|
- """mqtt_parser.py
-
- Parser del topic/payload MQTT in formato publish_out/<gateway> 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>
- 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
|