1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
package main
import (
"context"
"encoding/base64"
"encoding/binary"
"fmt"
"os"
"os/signal"
"time"
"github.com/charmbracelet/log"
"github.com/meshnet-gophers/meshtastic-go"
pb "github.com/meshnet-gophers/meshtastic-go/meshtastic"
flag "github.com/spf13/pflag"
"golang.org/x/crypto/curve25519"
)
func main() {
var args struct {
DbDir string
LogsDir string
ConfigPath string
Interface string
Relentless bool
}
flag.StringVarP(&args.DbDir, "dbdir", "", "./data/", "The path to the database directory")
flag.StringVarP(&args.LogsDir, "logsdir", "", "./logs/", "The path to the logs directory")
flag.StringVarP(&args.ConfigPath, "config", "c", "./config.json", "The path to the config.json")
flag.StringVarP(&args.Interface, "interface", "i", "kava", "Mesh interface (kava, mqtt)")
flag.BoolVarP(&args.Relentless, "relentless", "r", false, "Relentless reconnect to modem")
flag.Parse()
log.SetLevel(log.DebugLevel)
cfg, err := ReadConfig(args.ConfigPath)
if err != nil {
log.Fatal(err)
}
pbChannels := make([]*pb.ChannelSettings, len(cfg.Channels))
for i, channel := range cfg.Channels {
var pbChannelSettings = pb.ChannelSettings{
Name: channel.Name,
Psk: channel.PSK,
}
pbChannels[i] = &pbChannelSettings
}
var nodeID meshtastic.NodeID
if len(cfg.NodeID) == 4 {
nodeID = meshtastic.NodeID(binary.BigEndian.Uint32(cfg.NodeID))
} else if len(cfg.NodeID) == 0 {
nodeID, err = meshtastic.RandomNodeID()
if err != nil {
log.Fatal(err)
}
}
log.Print("Config:")
log.Print(" Database", "directory", args.DbDir)
log.Print(" Logs", "directory", args.LogsDir)
log.Print(" Node", "id", nodeID, "short", cfg.ShortName, "name", cfg.Name)
nodeConfig := NodeConfig{
DatabaseDir: args.DbDir,
LogsDir: args.LogsDir,
NodeID: nodeID,
LongName: cfg.Name,
ShortName: cfg.ShortName,
DefaultHops: cfg.DefaultHops,
MaxHops: cfg.MaxHops,
Channels: &pb.ChannelSet{Settings: pbChannels},
BroadcastNodeInfoInterval: time.Duration(cfg.NodeBroadcastInterval * float64(time.Second)),
BroadcastPositionInterval: time.Duration(cfg.Position.BroadcastInterval * float64(time.Second)),
// Position paramters
PositionLatitudeI: int32(cfg.Position.Latitude * 1.e7),
PositionLongitudeI: int32(cfg.Position.Longitude * 1.e7),
PositionAltitude: int32(cfg.Position.Altitude),
// Device Metrics
DeviceMetricsBroadcastInterval: time.Duration(cfg.DeviceMetrics.BroadcastInterval * float64(time.Second)),
DeviceMetricsUPSAddress: cfg.DeviceMetrics.UPSAddress,
TCPListenAddr: "0.0.0.0:4403",
}
if len(cfg.X25519Key) == 32 {
nodeConfig.X25519SecretKey = cfg.X25519Key
nodeConfig.X25519PublicKey, err = curve25519.X25519(nodeConfig.X25519SecretKey, curve25519.Basepoint)
if err != nil {
log.Fatal(err)
}
log.Print(" X25519PublicKey", "base64", base64.StdEncoding.EncodeToString(nodeConfig.X25519PublicKey), "hex", fmt.Sprintf("%x", nodeConfig.X25519PublicKey))
} else if len(cfg.X25519Key) != 0 {
log.Fatal("invalid x25519 key")
}
if args.Relentless {
log.Warn("Starting Node in 'relentless' mode...")
} else {
log.Info("Starting Node...")
}
n, err := NewNode(nodeConfig)
if err != nil {
log.Fatal(err)
}
defer n.Close()
ctx, _ := signal.NotifyContext(context.Background(), os.Interrupt)
for {
var iface MeshIf
switch args.Interface {
case "kava":
iface = NewKavaConn(cfg.KavaModem.Address, 10*time.Second, n.cfg.Channels)
case "mqtt":
iface = NewMqttIf(cfg.MqttIf.Address, cfg.MqttIf.Username, cfg.MqttIf.Password, cfg.MqttIf.Root, cfg.MqttIf.ClientID, meshtastic.NodeID(nodeID), n.cfg.Channels)
default:
log.Fatal("invalid argument", "interface", args.Interface)
}
if err := n.Run(ctx, iface); err != nil {
log.Error("!! Node.Run()", "err", err)
}
if err := ctx.Err(); err != nil {
log.Error("!! Caught interrupt!")
break
}
if !args.Relentless {
break
}
log.Warn("Reconnecting in 30 seconds...")
ticker := time.NewTicker(30 * time.Second)
select {
case <-ctx.Done():
return
case <-ticker.C:
}
}
}
|