Implement heartbeat
This commit is contained in:
@@ -54,6 +54,14 @@ def on_message(client, userdata, msg):
|
|||||||
if MAIN_LOOP:
|
if MAIN_LOOP:
|
||||||
asyncio.run_coroutine_threadsafe(handle_message(msg), MAIN_LOOP)
|
asyncio.run_coroutine_threadsafe(handle_message(msg), MAIN_LOOP)
|
||||||
|
|
||||||
|
async def update_last_seen(node_id):
|
||||||
|
"""Generic helper to update the timestamp on any contact."""
|
||||||
|
try:
|
||||||
|
doc_ref = db.collection("nodes").document(node_id)
|
||||||
|
await async_firestore(doc_ref.set, {"last_seen": datetime.utcnow()}, merge=True)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Failed to update heartbeat for {node_id}: {e}")
|
||||||
|
|
||||||
async def handle_message(msg):
|
async def handle_message(msg):
|
||||||
topic_parts = msg.topic.split('/')
|
topic_parts = msg.topic.split('/')
|
||||||
if len(topic_parts) < 3: return
|
if len(topic_parts) < 3: return
|
||||||
@@ -65,37 +73,46 @@ async def handle_message(msg):
|
|||||||
payload = json.loads(msg.payload.decode())
|
payload = json.loads(msg.payload.decode())
|
||||||
timestamp = datetime.utcnow()
|
timestamp = datetime.utcnow()
|
||||||
|
|
||||||
|
# 1. ALWAYS update last_seen if we hear from the node
|
||||||
|
await update_last_seen(node_id)
|
||||||
|
|
||||||
if event_type == "checkin":
|
if event_type == "checkin":
|
||||||
print(f"Processing checkin for {node_id}...")
|
# This now receives the periodic heartbeat
|
||||||
|
print(f"Heartbeat/Checkin from {node_id}")
|
||||||
data = {
|
data = {
|
||||||
"node_id": node_id,
|
"node_id": node_id,
|
||||||
"last_seen": timestamp,
|
"last_seen": timestamp,
|
||||||
"status": payload.get("status", "online"),
|
"status": payload.get("status", "online"),
|
||||||
"active_system": payload.get("active_system"),
|
"active_system": payload.get("active_system"),
|
||||||
"available_systems": payload.get("available_systems", []),
|
"available_systems": payload.get("available_systems", []),
|
||||||
"config": payload,
|
|
||||||
"radio_state": "active" if payload.get("is_listening") else "idle"
|
"radio_state": "active" if payload.get("is_listening") else "idle"
|
||||||
}
|
}
|
||||||
doc_ref = db.collection("nodes").document(node_id)
|
doc_ref = db.collection("nodes").document(node_id)
|
||||||
print(f"Writing to Firestore: {doc_ref.path} in DB {FIRESTORE_DB_ID}")
|
|
||||||
await async_firestore(doc_ref.set, data, merge=True)
|
await async_firestore(doc_ref.set, data, merge=True)
|
||||||
print(f"Successfully updated checkin for {node_id}")
|
|
||||||
ACTIVE_NODES_CACHE[node_id] = data
|
ACTIVE_NODES_CACHE[node_id] = data
|
||||||
|
|
||||||
elif event_type == "status":
|
elif event_type == "status":
|
||||||
print(f"Processing status update for {node_id}...")
|
# Handle explicit Offline messages (LWT or clean shutdown)
|
||||||
|
print(f"Status update for {node_id}: {payload.get('status')}")
|
||||||
status = payload.get("status")
|
status = payload.get("status")
|
||||||
|
|
||||||
|
data = {"status": status, "last_seen": timestamp}
|
||||||
|
|
||||||
|
# If offline, maybe clear active system?
|
||||||
|
if status == "offline":
|
||||||
|
data["radio_state"] = "unknown"
|
||||||
|
|
||||||
doc_ref = db.collection("nodes").document(node_id)
|
doc_ref = db.collection("nodes").document(node_id)
|
||||||
print(f"Writing to Firestore: {doc_ref.path} in DB {FIRESTORE_DB_ID}")
|
await async_firestore(doc_ref.set, data, merge=True)
|
||||||
await async_firestore(doc_ref.set, {"status": status, "last_seen": timestamp}, merge=True)
|
|
||||||
print(f"Successfully updated status for {node_id}")
|
|
||||||
if node_id in ACTIVE_NODES_CACHE:
|
if node_id in ACTIVE_NODES_CACHE:
|
||||||
ACTIVE_NODES_CACHE[node_id]["status"] = status
|
ACTIVE_NODES_CACHE[node_id].update(data)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error processing MQTT message from {node_id}: {e}")
|
print(f"Error processing MQTT message from {node_id}: {e}")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
# MQTT Setup
|
# MQTT Setup
|
||||||
mqtt_client = mqtt.Client(client_id=C2_ID)
|
mqtt_client = mqtt.Client(client_id=C2_ID)
|
||||||
mqtt_client.on_connect = on_connect
|
mqtt_client.on_connect = on_connect
|
||||||
|
|||||||
Reference in New Issue
Block a user