MeshCoreToMqttJwtPusher initialization and packet publishing with node name and radio configuration

This commit is contained in:
Lloyd
2025-11-18 23:36:10 +00:00
parent 8ef2d3997d
commit 007182deb1
2 changed files with 85 additions and 18 deletions
+39 -15
View File
@@ -63,12 +63,14 @@ class MeshCoreToMqttJwtPusher:
public_key: str,
iata_code: str,
broker_index: int = 0,
topic_prefix: str = "pymc-repeater",
topic_prefix: str = "meshcore",
jwt_expiry_minutes: int = 10,
use_tls: bool = True,
status_interval: int = 60, # Heartbeat interval in seconds
model: str = "PyMC-Repeater",
firmware_version: str = "0.0.0",
app_version: str = "0.0.0",
node_name: str = None,
radio_config: str = None,
):
if broker_index >= len(LETSMESH_BROKERS):
@@ -83,7 +85,9 @@ class MeshCoreToMqttJwtPusher:
self.use_tls = use_tls
self.status_interval = status_interval
self.model = model
self.firmware_version = firmware_version
self.app_version = app_version
self.node_name = node_name or "PyMC-Repeater"
self.radio_config = radio_config or "915.0,125.0,7,5"
self._status_task = None
self._running = False
self._packet_stats = {
@@ -150,7 +154,11 @@ class MeshCoreToMqttJwtPusher:
logging.info(f"Connected to {self.broker['name']}")
self._running = True
# Publish initial status on connect
self.publish_status(state="online")
self.publish_status(
state="online",
origin=self.node_name,
radio_config=self.radio_config
)
else:
logging.error(f"Failed with code {rc}")
@@ -194,7 +202,11 @@ class MeshCoreToMqttJwtPusher:
def disconnect(self):
self._running = False
# Publish offline status before disconnecting
self.publish_status(state="offline")
self.publish_status(
state="offline",
origin=self.node_name,
radio_config=self.radio_config
)
import time
time.sleep(0.5) # Give time for the message to be sent
@@ -207,7 +219,11 @@ class MeshCoreToMqttJwtPusher:
import time
while self._running:
try:
self.publish_status(state="online")
self.publish_status(
state="online",
origin=self.node_name,
radio_config=self.radio_config
)
time.sleep(self.status_interval)
except Exception as e:
logging.error(f"Status heartbeat error: {e}")
@@ -238,7 +254,8 @@ class MeshCoreToMqttJwtPusher:
self._packet_stats["packets_sent"] += 1
return self.publish_packet(pkt, subtopic, retain)
def publish_status(self, state: str = "online", location: dict = None, extra_stats: dict = None):
def publish_status(self, state: str = "online", location: dict = None, extra_stats: dict = None,
origin: str = None, radio_config: str = None):
"""
Publish device status/heartbeat message
@@ -246,21 +263,28 @@ class MeshCoreToMqttJwtPusher:
state: Device state (online/offline)
location: Optional dict with latitude/longitude
extra_stats: Optional additional statistics to include
origin: Node name/description
radio_config: Radio configuration string (freq,bw,sf,cr)
"""
uptime = (datetime.now(UTC) - self._packet_stats["start_time"]).total_seconds()
uptime_secs = int((datetime.now(UTC) - self._packet_stats["start_time"]).total_seconds())
status = {
"origin_id": self.public_key,
"status": state,
"timestamp": datetime.now(UTC).isoformat(),
"state": state,
"origin": origin or "PyMC-Repeater",
"origin_id": self.public_key,
"model": self.model,
"firmware_version": self.app_version,
"radio": radio_config or "0.0,0.0,0,0",
"client_version": f"pyMC_repeater_{self.app_version}",
"stats": {
"uptime": int(uptime),
"uptime_secs": uptime_secs,
"packets_sent": self._packet_stats["packets_sent"],
"packets_received": self._packet_stats["packets_received"],
"errors": 0,
"queue_len": 0,
**(extra_stats or {})
},
"model": self.model,
"firmware_version": self.firmware_version
}
}
if location:
@@ -331,7 +355,7 @@ if __name__ == "__main__":
broker_index=0,
status_interval=30 if mode == "live" else 0, # 30s heartbeat in live mode
model="PyMC-Gateway",
firmware_version="1.0.0"
app_version="1.0.0"
)
pusher.connect()
+46 -3
View File
@@ -1,6 +1,7 @@
import json
import logging
import time
from datetime import datetime
from pathlib import Path
from typing import Optional, Dict, Any
@@ -42,6 +43,15 @@ class StorageCollector:
private_key_hex = identity_key.hex()
public_key_hex = local_identity.get_public_key().hex()
# Get node name and radio config from config
node_name = self.config.get("repeater", {}).get("node_name", "PyMC-Repeater")
radio_config = self.config.get("radio", {})
radio_freq = radio_config.get("frequency", 915.0)
radio_bw = radio_config.get("bandwidth", 125.0)
radio_sf = radio_config.get("spreading_factor", 7)
radio_cr = radio_config.get("coding_rate", 5)
radio_config_str = f"{radio_freq},{radio_bw},{radio_sf},{radio_cr}"
self.letsmesh_handler = MeshCoreToMqttJwtPusher(
private_key=private_key_hex,
public_key=public_key_hex,
@@ -49,7 +59,9 @@ class StorageCollector:
broker_index=letsmesh_config.get("broker_index", 0),
status_interval=letsmesh_config.get("status_interval", 60),
model=letsmesh_config.get("model", "PyMC-Repeater"),
firmware_version=__version__
app_version=__version__,
node_name=node_name,
radio_config=radio_config_str
)
self.letsmesh_handler.connect()
logger.info(f"LetsMesh handler initialized (v{__version__}) with public key: {public_key_hex[:16]}...")
@@ -69,9 +81,40 @@ class StorageCollector:
# Publish to LetsMesh if enabled
if self.letsmesh_handler:
try:
# Publish raw packet data if available
# Format packet data for LetsMesh publish_packet
if "raw_packet" in packet_record and packet_record["raw_packet"]:
self.letsmesh_handler.publish_raw_data(packet_record["raw_packet"])
# Extract timestamp and format date/time
timestamp = packet_record.get("timestamp", time.time())
dt = datetime.fromtimestamp(timestamp)
# Get node name from config
node_name = self.config.get("repeater", {}).get("node_name", "Unknown")
# Format route type (1=Flood->F, 2=Direct->D, etc)
route_map = {1: "F", 2: "D"}
route = route_map.get(packet_record.get("route", 0), str(packet_record.get("route", 0)))
letsmesh_packet = {
"origin": node_name,
"origin_id": self.letsmesh_handler.public_key,
"timestamp": dt.isoformat(),
"type": "PACKET",
"direction": "rx",
"time": dt.strftime("%H:%M:%S"),
"date": dt.strftime("%-d/%-m/%Y"),
"len": str(len(packet_record["raw_packet"]) // 2), # Raw packet length in bytes
"packet_type": str(packet_record.get("type", 0)),
"route": route,
"payload_len": str(packet_record.get("payload_length", 0)),
"raw": packet_record["raw_packet"],
"SNR": str(packet_record.get("snr", 0)),
"RSSI": str(packet_record.get("rssi", 0)),
"score": str(int(packet_record.get("score", 0) * 1000)), # Convert to integer score
"duration": "0", # Not available in our packet record
"hash": packet_record.get("packet_hash", "")
}
self.letsmesh_handler.publish_packet(letsmesh_packet)
except Exception as e:
logger.error(f"Failed to publish packet to LetsMesh: {e}")