"""mqtt_parser.py Parser del topic/payload MQTT in formato publish_out/ con payload JSON list. Esempio payload: [ {"timestamp":"...","type":"Gateway","mac":"AC233FC1DD3C","nums":9}, {"timestamp":"...","mac":"C3000057B9F4","rssi":-56,"rawData":"..."}, ... ] Restituisce eventi normalizzati (gateway_mac_compact, beacon_mac_compact, rssi, timestamp_iso). """ from __future__ import annotations import json from typing import List, Optional, Tuple from .normalize import mac_to_compact MqttEvent = Tuple[str, str, float, Optional[str]] # (gw_compact, beacon_compact, rssi, ts_iso) def parse_publish_out(topic: str, payload: bytes) -> List[MqttEvent]: try: obj = json.loads(payload.decode("utf-8", errors="strict")) except Exception: return [] if not isinstance(obj, list) or not obj: return [] # Gateway MAC: preferisci il primo elemento "type: Gateway" se presente, altrimenti usa il topic. gw_compact: str = "" first = obj[0] if isinstance(first, dict) and str(first.get("type", "")).lower() == "gateway" and "mac" in first: gw_compact = mac_to_compact(first.get("mac")) if not gw_compact: # topic: publish_out/ gw_compact = mac_to_compact(topic.split("/")[-1]) out: List[MqttEvent] = [] for item in obj: if not isinstance(item, dict): continue if str(item.get("type", "")).lower() == "gateway": continue mac = item.get("mac") rssi = item.get("rssi") if mac is None or rssi is None: continue b_compact = mac_to_compact(mac) if len(b_compact) != 12: continue try: rssi_f = float(rssi) except Exception: continue ts = item.get("timestamp") out.append((gw_compact, b_compact, rssi_f, ts if isinstance(ts, str) else None)) return out