Files
bellsystems-cp/backend/mqtt/logger.py

102 lines
3.3 KiB
Python

import logging
from mqtt import database as db
logger = logging.getLogger("mqtt.logger")
LEVEL_MAP = {
"🟢 INFO": "INFO",
"🟡 WARN": "WARN",
"🔴 EROR": "ERROR",
"INFO": "INFO",
"WARN": "WARN",
"ERROR": "ERROR",
"EROR": "ERROR",
}
async def handle_message(serial: str, topic_type: str, payload: dict):
try:
if topic_type == "status/heartbeat":
await _handle_heartbeat(serial, payload)
elif topic_type == "status/alerts":
await _handle_alerts(serial, payload)
elif topic_type == "status/info":
await _handle_info(serial, payload)
elif topic_type == "logs":
await _handle_log(serial, payload)
elif topic_type == "data":
await _handle_data_response(serial, payload)
else:
logger.debug(f"Unhandled topic type: {topic_type} for {serial}")
except Exception as e:
logger.error(f"Error handling {topic_type} for {serial}: {e}")
async def _handle_heartbeat(serial: str, payload: dict):
# Store silently — do not log as a visible event.
# The console surfaces an alert only when the device goes silent (no heartbeat for 90s).
inner = payload.get("payload", {})
await db.insert_heartbeat(
device_serial=serial,
device_id=inner.get("device_id", ""),
firmware_version=inner.get("firmware_version", ""),
ip_address=inner.get("ip_address", ""),
gateway=inner.get("gateway", ""),
uptime_ms=inner.get("uptime_ms", 0),
uptime_display=inner.get("timestamp", ""),
)
async def _handle_log(serial: str, payload: dict):
raw_level = payload.get("level", "INFO")
level = LEVEL_MAP.get(raw_level, "INFO")
message = payload.get("message", "")
device_timestamp = payload.get("timestamp")
await db.insert_log(
device_serial=serial,
level=level,
message=message,
device_timestamp=device_timestamp,
)
async def _handle_alerts(serial: str, payload: dict):
subsystem = payload.get("subsystem", "")
state = payload.get("state", "")
if not subsystem or not state:
logger.warning(f"Malformed alert payload from {serial}: {payload}")
return
if state == "CLEARED":
await db.delete_alert(serial, subsystem)
else:
await db.upsert_alert(serial, subsystem, state, payload.get("msg"))
async def _handle_info(serial: str, payload: dict):
event_type = payload.get("type", "")
data = payload.get("payload", {})
if event_type == "playback_started":
logger.debug(f"{serial}: playback started — melody_uid={data.get('melody_uid')}")
elif event_type == "playback_stopped":
logger.debug(f"{serial}: playback stopped")
else:
logger.debug(f"{serial}: info event '{event_type}'")
async def _handle_data_response(serial: str, payload: dict):
status = payload.get("status", "")
pending = await db.get_pending_command(serial)
if pending:
cmd_status = "success" if status == "SUCCESS" else "error"
await db.update_command_response(
command_id=pending["id"],
status=cmd_status,
response_payload=payload,
)
else:
logger.debug(f"Received data response for {serial} with no pending command")