File size: 2,677 Bytes
95c00ee
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fa7bc29
95c00ee
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fa7bc29
 
1bd74e9
95c00ee
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import asyncio
from fastapi import APIRouter, WebSocket, WebSocketDisconnect

from backend.services.canonical_telemetry_service import latest_points
from backend.services.hvac_safety_contract import is_demo_source
from backend.services.logging_service import log_event
from backend.services.platform_bms_service import platform_snapshot

ws_router = APIRouter()


@ws_router.websocket("/ws/telemetry")
async def telemetry_websocket(websocket: WebSocket):
    await websocket.accept()
    try:
        while True:
            snap = platform_snapshot()
            points = latest_points(limit=400)
            events = []
            for p in points:
                src = p.get("source")
                pid = str(p.get("point_id") or "")
                equipment = p.get("equipment_id") or p.get("asset_id")
                point_name = pid.split(".", 1)[1] if "." in pid else pid
                live = (
                    snap.get("bmsConnected")
                    and (not is_demo_source(src))
                    and p.get("quality") == "GOOD"
                    and p.get("classified") == "LIVE"
                )
                events.append(
                    {
                        "equipment_id": equipment,
                        "point": point_name,
                        "point_id": pid,
                        "value": p.get("value"),
                        "unit": p.get("unit"),
                        "timestamp": p.get("timestamp"),
                        "quality": p.get("quality"),
                        "source": src,
                        "building_id": p.get("building_id"),
                        "live": live,
                    }
                )
            bms = dict(snap.get("bms") or {})
            if "lastError" not in bms:
                bms["lastError"] = bms.get("last_error")
            await websocket.send_json(
                {
                    "bms": bms,
                    "telemetry": snap.get("telemetry"),
                    "safeMode": snap.get("safeMode"),
                    "controlEnabled": bool(snap.get("controlEnabled")),
                    "controlLabel": snap.get("controlLabel") or "WRITE DISABLED",
                    "plantMode": snap.get("plantMode"),
                    "events": events,
                    "count": len(events),
                }
            )
            await asyncio.sleep(5.0)
    except WebSocketDisconnect:
        return
    except Exception as e:
        log_event("ERROR", "websocket", "TELEMETRY_STREAM", extra={"error": type(e).__name__})
        try:
            await websocket.close()
        except Exception:
            pass
        return