Added Radio.ID and refactored the Stats interface
Some checks failed
Run tests / test (1.25) (push) Failing after 1m0s
Run tests / test (stable) (push) Failing after 1m0s

This commit is contained in:
2026-03-17 08:33:06 +01:00
parent 8ec85821e4
commit 27e2da1943
15 changed files with 2045 additions and 22 deletions

View File

@@ -32,8 +32,8 @@ func NewCompanion(conn io.ReadWriteCloser) (*Node, error) {
}, nil
}
func NewRepeater(conn io.ReadWriteCloser, hasSNR bool) (*Node, error) {
driver := newRepeaterDriver(conn, hasSNR)
func NewRepeater(conn io.ReadWriteCloser) (*Node, error) {
driver := newRepeaterDriver(conn)
if err := driver.Setup(); err != nil {
return nil, err
@@ -60,7 +60,7 @@ func (dev *Node) Info() *radio.Info {
return dev.driver.Info()
}
func (dev *Node) Stats() map[string]any {
func (dev *Node) Stats() <-chan map[string]any {
return dev.driver.Stats()
}
@@ -78,7 +78,7 @@ type nodeDriver interface {
Setup() error
Packets() <-chan *Packet
Stats() map[string]any
Stats() <-chan map[string]any
}
type nodeTracer interface {

View File

@@ -47,7 +47,7 @@ type companionDriver struct {
info companionInfo
traceTag uint32
traceAuthCode uint32
stats map[string]any
stats chan map[string]any
}
type companionDriverWaiting struct {
@@ -131,6 +131,7 @@ func newCompanionDriver(conn io.ReadWriteCloser) *companionDriver {
conn: conn,
waiting: make(chan *companionDriverWaiting, 16),
traceTag: rand.Uint32(),
stats: make(chan map[string]any, 2),
//traceAuthCode: rand.Uint32(),
}
}
@@ -144,7 +145,7 @@ func (drv *companionDriver) Setup() (err error) {
if err = drv.sendAppStart(); err != nil {
return
}
if err = drv.sendDeviceInfo(); err != nil {
if err = drv.getDeviceInfo(); err != nil {
return
}
return
@@ -209,7 +210,7 @@ func (drv *companionDriver) Info() *radio.Info {
}
}
func (drv *companionDriver) Stats() map[string]any {
func (drv *companionDriver) Stats() <-chan map[string]any {
return drv.stats
}
@@ -397,7 +398,7 @@ func (drv *companionDriver) sendAppStart() (err error) {
return
}
func (drv *companionDriver) sendDeviceInfo() (err error) {
func (drv *companionDriver) getDeviceInfo() (err error) {
var (
args = []byte{0x03}
data []byte
@@ -425,6 +426,11 @@ func (drv *companionDriver) sendDeviceInfo() (err error) {
return
}
func (drv *companionDriver) getPublicKey() (err error) {
// TODO
return err
}
func (drv *companionDriver) poll() {
for {
frame, err := drv.readFrame()

View File

@@ -3,6 +3,7 @@ package meshcore
import (
"bufio"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"math"
@@ -23,7 +24,7 @@ type repeaterDriver struct {
lastFrame []byte
lastFrameAt time.Time
info repeaterInfo
stats map[string]any
stats chan map[string]any
err error
}
@@ -78,7 +79,7 @@ type repeaterInfo struct {
Type NodeType
Power byte // in dBm
MaxPower byte // in dBm
PublicKey [32]byte
PublicKey string
Latitude float64
Longitude float64
HasMultiACKs bool
@@ -98,15 +99,20 @@ type repeaterInfo struct {
Manufacturer string
}
func newRepeaterDriver(conn io.ReadWriteCloser, hasSNR bool) *repeaterDriver {
func newRepeaterDriver(conn io.ReadWriteCloser) *repeaterDriver {
return &repeaterDriver{
conn: conn,
waiting: make(chan *repeaterDriverWaiting, 16),
hasSNR: hasSNR,
stats: make(map[string]any),
stats: make(chan map[string]any, 2),
}
}
func newRepeaterDriverWithSNRPatch(conn io.ReadWriteCloser) *repeaterDriver {
driver := newRepeaterDriver(conn)
driver.hasSNR = true
return driver
}
func (drv *repeaterDriver) Close() error {
return drv.conn.Close()
}
@@ -150,6 +156,7 @@ func (drv *repeaterDriver) Info() *radio.Info {
}
return &radio.Info{
ID: drv.info.PublicKey,
Name: drv.info.Name,
Manufacturer: manufacturer,
Device: device,
@@ -179,7 +186,7 @@ func (drv *repeaterDriver) RawPackets() <-chan *protocol.Packet {
return drv.rawPackets
}
func (drv *repeaterDriver) Stats() map[string]any {
func (drv *repeaterDriver) Stats() <-chan map[string]any {
return drv.stats
}
@@ -193,6 +200,11 @@ func (drv *repeaterDriver) queryDeviceInfo() (err error) {
return
}
// Fetch public key
if drv.info.PublicKey, err = drv.writeCommand("get", "public.key"); err != nil {
return
}
var line string
// Fetch frequency, bandwidth and LoRa settings
@@ -412,24 +424,26 @@ func (drv *repeaterDriver) poll() {
}
func (drv *repeaterDriver) pollStats() {
ticker := time.NewTicker(time.Minute)
ticker := time.NewTicker(time.Second * 10)
defer ticker.Stop()
for {
stats := make(map[string]any)
neighbors, err := drv.getNeighbors()
if err != nil {
Logger.Warnf("meshcore: failed to get neighbors: %v", err)
} else {
drv.stats["neighbors"] = neighbors
stats["neighbors"] = neighbors
}
response, err := drv.writeCommand("stats")
response, err := drv.writeCommand("stats-core")
if err != nil {
Logger.Warnf("meshcore: failed to get stats: %v", err)
return
}
stats := make(map[string]any)
neighborStats := make(map[string]any)
for _, line := range strings.Split(response, "\n") {
parts := strings.SplitN(line, "=", 2)
if len(parts) != 2 {
@@ -439,15 +453,53 @@ func (drv *repeaterDriver) pollStats() {
value := parts[1]
if i, err := strconv.Atoi(value); err == nil {
stats[key] = i
neighborStats[key] = i
} else if f, err := strconv.ParseFloat(value, 64); err == nil {
stats[key] = f
neighborStats[key] = f
} else {
stats[key] = value
neighborStats[key] = value
}
}
drv.stats = stats
var (
coreStats = make(map[string]any)
radioStats = make(map[string]any)
packetStats = make(map[string]any)
)
if response, err := drv.writeCommand("stats-core"); err == nil {
if err = json.Unmarshal([]byte(response), &coreStats); err != nil {
Logger.Warnf("meshcore: failed to decode core stats: %v", err)
}
} else {
Logger.Warnf("meshcore: failed to get core stats: %v", err)
}
if response, err := drv.writeCommand("stats-radio"); err == nil {
if err = json.Unmarshal([]byte(response), &radioStats); err != nil {
Logger.Warnf("meshcore: failed to decode radio stats: %v", err)
}
} else {
Logger.Warnf("meshcore: failed to get radio stats: %v", err)
}
if response, err := drv.writeCommand("stats-packets"); err == nil {
if err = json.Unmarshal([]byte(response), &packetStats); err != nil {
Logger.Warnf("meshcore: failed to decode packet stats: %v", err)
}
} else {
Logger.Warnf("meshcore: failed to get packet stats: %v", err)
}
stats["neighbors"] = neighborStats
stats["core"] = coreStats
stats["radio"] = radioStats
stats["packets"] = packetStats
select {
case drv.stats <- stats:
default:
Logger.Warn("meshcore: stats channel full, dropping stats")
}
<-ticker.C
}