Compare commits

...

3 commits

3 changed files with 46 additions and 5 deletions

View file

@ -101,6 +101,20 @@ func handleMessage(from uint32, topic string, portNum generated.PortNum, payload
} }
Nodes[from].UpdateDeviceMetrics(batteryLevel, voltage, chUtil, airUtilTx, uptime) Nodes[from].UpdateDeviceMetrics(batteryLevel, voltage, chUtil, airUtilTx, uptime)
NodesMutex.Unlock() NodesMutex.Unlock()
} else if envMetrics := telemetry.GetEnvironmentMetrics(); envMetrics != nil {
temperature := envMetrics.GetTemperature()
relativeHumidity := envMetrics.GetRelativeHumidity()
barometricPressure := envMetrics.GetBarometricPressure()
log.Printf(
"[msg] %v (%v) %s: EnvironmentMetrics{temperature: %vC; humidity: %v%%; pressure: %vhPA}",
from, topic, portNum, temperature, relativeHumidity, barometricPressure,
)
NodesMutex.Lock()
if Nodes[from] == nil {
Nodes[from] = meshtastic.NewNode(topic)
}
Nodes[from].UpdateEnvironmentMetrics(temperature, relativeHumidity, barometricPressure)
NodesMutex.Unlock()
} }
case generated.PortNum_NEIGHBORINFO_APP: case generated.PortNum_NEIGHBORINFO_APP:
var neighborInfo generated.NeighborInfo var neighborInfo generated.NeighborInfo

View file

@ -42,6 +42,11 @@ type Node struct {
AirUtilTx float32 `json:"airUtilTx,omitempty"` AirUtilTx float32 `json:"airUtilTx,omitempty"`
Uptime uint32 `json:"uptime,omitempty"` Uptime uint32 `json:"uptime,omitempty"`
LastDeviceMetrics int64 `json:"lastDeviceMetrics,omitempty"` LastDeviceMetrics int64 `json:"lastDeviceMetrics,omitempty"`
// EnvironmentMetrics
Temperature float32 `json:"temperature,omitempty"`
RelativeHumidity float32 `json:"relativeHumidity,omitempty"`
BarometricPressure float32 `json:"barometricPressure,omitempty"`
LastEnvironmentMetrics int64 `json:"lastEnvironmentMetrics,omitempty"`
// NeighborInfo // NeighborInfo
Neighbors map[uint32]*NeighborInfo `json:"neighbors,omitempty"` Neighbors map[uint32]*NeighborInfo `json:"neighbors,omitempty"`
// key=mqtt topic, value=first seen/last position update // key=mqtt topic, value=first seen/last position update
@ -63,6 +68,13 @@ func (node *Node) ClearDeviceMetrics() {
node.LastDeviceMetrics = 0 node.LastDeviceMetrics = 0
} }
func (node *Node) ClearEnvironmentMetrics() {
node.Temperature = 0
node.RelativeHumidity = 0
node.BarometricPressure = 0
node.LastEnvironmentMetrics = 0
}
func (node *Node) ClearMapReportData() { func (node *Node) ClearMapReportData() {
node.FwVersion = "" node.FwVersion = ""
node.Region = "" node.Region = ""
@ -85,7 +97,7 @@ func (node *Node) IsValid() bool {
return true return true
} }
func (node *Node) Prune(seenByTtl, neighborTtl, deviceMetricsTtl, mapReportTtl int64) { func (node *Node) Prune(seenByTtl, neighborTtl, metricsTtl, mapReportTtl int64) {
now := time.Now().Unix() now := time.Now().Unix()
// SeenBy // SeenBy
for topic, lastSeen := range node.SeenBy { for topic, lastSeen := range node.SeenBy {
@ -121,9 +133,13 @@ func (node *Node) Prune(seenByTtl, neighborTtl, deviceMetricsTtl, mapReportTtl i
delete(node.Neighbors, toDelete) delete(node.Neighbors, toDelete)
} }
// DeviceMetrics // DeviceMetrics
if node.LastDeviceMetrics > 0 && node.LastDeviceMetrics+deviceMetricsTtl < now { if node.LastDeviceMetrics > 0 && node.LastDeviceMetrics+metricsTtl < now {
node.ClearDeviceMetrics() node.ClearDeviceMetrics()
} }
// EnvironmentMetrics
if node.LastEnvironmentMetrics > 0 && node.LastEnvironmentMetrics+metricsTtl < now {
node.ClearEnvironmentMetrics()
}
// MapReport // MapReport
if node.LastMapReport > 0 && node.LastMapReport+mapReportTtl < now { if node.LastMapReport > 0 && node.LastMapReport+mapReportTtl < now {
node.ClearMapReportData() node.ClearMapReportData()
@ -139,6 +155,13 @@ func (node *Node) UpdateDeviceMetrics(batteryLevel uint32, voltage, chUtil, airU
node.LastDeviceMetrics = time.Now().Unix() node.LastDeviceMetrics = time.Now().Unix()
} }
func (node *Node) UpdateEnvironmentMetrics(temperature, relativeHumidity, barometricPressure float32) {
node.Temperature = temperature
node.RelativeHumidity = relativeHumidity
node.BarometricPressure = barometricPressure
node.LastEnvironmentMetrics = time.Now().Unix()
}
func (node *Node) UpdateMapReport(fwVersion, region, modemPreset string, hasDefaultCh bool, onlineLocalNodes uint32) { func (node *Node) UpdateMapReport(fwVersion, region, modemPreset string, hasDefaultCh bool, onlineLocalNodes uint32) {
node.FwVersion = fwVersion node.FwVersion = fwVersion
node.Region = region node.Region = region
@ -178,9 +201,9 @@ func (node *Node) UpdateUser(longName, shortName, hwModel, role string) {
type NodeDB map[uint32]*Node type NodeDB map[uint32]*Node
func (db NodeDB) Prune(seenByTtl, neighborTtl, deviceMetricsTtl, mapReportTtl int64) { func (db NodeDB) Prune(seenByTtl, neighborTtl, metricsTtl, mapReportTtl int64) {
for nodeNum, node := range db { for nodeNum, node := range db {
node.Prune(seenByTtl, neighborTtl, deviceMetricsTtl, mapReportTtl) node.Prune(seenByTtl, neighborTtl, metricsTtl, mapReportTtl)
if len(node.SeenBy) == 0 { if len(node.SeenBy) == 0 {
delete(db, nodeNum) delete(db, nodeNum)
} }

View file

@ -211,6 +211,7 @@
fwVersion, region, modemPreset, hasDefaultCh, onlineLocalNodes, fwVersion, region, modemPreset, hasDefaultCh, onlineLocalNodes,
latitude, longitude, altitude, precision, latitude, longitude, altitude, precision,
batteryLevel, voltage, chUtil, airUtilTx, uptime, batteryLevel, voltage, chUtil, airUtilTx, uptime,
temperature, relativeHumidity, barometricPressure,
neighbors, seenBy neighbors, seenBy
} = node } = node
const id = `!${Number(nodeNum).toString(16)}` const id = `!${Number(nodeNum).toString(16)}`
@ -234,11 +235,14 @@
${region ? `<tr><th>Region</th><td>${html(region)}</td></tr>` : ''} ${region ? `<tr><th>Region</th><td>${html(region)}</td></tr>` : ''}
${modemPreset ? `<tr><th>Modem preset</th><td>${html(modemPreset)}</td></tr>` : ''} ${modemPreset ? `<tr><th>Modem preset</th><td>${html(modemPreset)}</td></tr>` : ''}
${hasDefaultCh ? `<tr><th>Has default channel</th><td>True</td></tr>` : ''} ${hasDefaultCh ? `<tr><th>Has default channel</th><td>True</td></tr>` : ''}
${onlineLocalNodes ? `<tr><th>Online local nodes</th><td>${onlineLocalNodes}</td></tr>` : ''}
${batteryLevel ? `<tr><th>Power</th><td>${batteryLevel > 100 ? 'Plugged in' : `${batteryLevel}%`}${voltage ? ` (${voltage.toFixed(2)}V)` : ''}</td></tr>` : ''} ${batteryLevel ? `<tr><th>Power</th><td>${batteryLevel > 100 ? 'Plugged in' : `${batteryLevel}%`}${voltage ? ` (${voltage.toFixed(2)}V)` : ''}</td></tr>` : ''}
${chUtil ? `<tr><th>ChUtil</th><td>${chUtil.toFixed(2)}%</td></tr>` : ''} ${chUtil ? `<tr><th>ChUtil</th><td>${chUtil.toFixed(2)}%</td></tr>` : ''}
${airUtilTx ? `<tr><th>AirUtilTX</th><td>${airUtilTx.toFixed(2)}%</td></tr>` : ''} ${airUtilTx ? `<tr><th>AirUtilTX</th><td>${airUtilTx.toFixed(2)}%</td></tr>` : ''}
${uptime ? `<tr><th>Uptime</th><td>${duration(uptime)}</td></tr>` : ''} ${uptime ? `<tr><th>Uptime</th><td>${duration(uptime)}</td></tr>` : ''}
${onlineLocalNodes ? `<tr><th>Online local nodes</th><td>${onlineLocalNodes}</td></tr>` : ''} ${temperature ? `<tr><th>Temperature</th><td>${temperature.toFixed(1)}&#8451; / ${(temperature * 1.8 + 32).toFixed(1)}&#8457;</td></tr>` : ''}
${relativeHumidity ? `<tr><th>Relative Humidity</th><td>${Math.round(relativeHumidity)}%</td></tr>` : ''}
${barometricPressure ? `<tr><th>Barometric Pressure</th><td>${Math.round(barometricPressure)} hPa</td></tr>` : ''}
${altitude ? `<tr><th>Altitude</th><td>${altitude.toLocaleString()} m above MSL</td></tr>` : ''} ${altitude ? `<tr><th>Altitude</th><td>${altitude.toLocaleString()} m above MSL</td></tr>` : ''}
${precision && precisionMargins[precision-1] ? ${precision && precisionMargins[precision-1] ?
`<tr><th>Location precision</th><td>&#177; ${precisionMargins[precision-1].toLocaleString()} m (orange circle)</td></tr>` : '' `<tr><th>Location precision</th><td>&#177; ${precisionMargins[precision-1].toLocaleString()} m (orange circle)</td></tr>` : ''