mirror of
https://github.com/pyMC-dev/pyMC_Repeater.git
synced 2026-08-07 09:23:06 +02:00
MeshCoreToMqttJwtPusher initialization and packet publishing with node name and radio configuration
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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}")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user