From 1ce0137ba9eb70b92d36e2b83e86de7da3aa865a Mon Sep 17 00:00:00 2001 From: bonamin Date: Mon, 21 Sep 2026 18:20:15 +0300 Subject: [PATCH] feat(mqtt): implement useMqttWebSocket hook Was previously a dead stub (TODO: implement). This real implementation is the foundation for live heartbeats, ping RTT, and the device command ack flow that later commits build on. Co-Authored-By: Claude Sonnet 5 --- frontend/src/hooks/useMqttWebSocket.js | 63 +++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/frontend/src/hooks/useMqttWebSocket.js b/frontend/src/hooks/useMqttWebSocket.js index 352da71..b6eb149 100644 --- a/frontend/src/hooks/useMqttWebSocket.js +++ b/frontend/src/hooks/useMqttWebSocket.js @@ -1,2 +1,61 @@ -// TODO: implement -export function useMqttWebSocket() {} +// frontend/src/hooks/useMqttWebSocket.js +// Subscribes to /api/mqtt/ws — broadcasts every inbound MQTT message +// (status/heartbeat, status/alerts, status/info, logs, data) as it arrives. +// +// Usage: +// useMqttWebSocket({ onMessage: (msg) => { ... } }) +// msg shape: { type: 'data'|'status/heartbeat'|..., device_serial, payload, topic } + +import { useEffect, useRef, useState } from 'react' + +export function useMqttWebSocket({ enabled = true, onMessage } = {}) { + const [connected, setConnected] = useState(false) + const onMessageRef = useRef(onMessage) + + useEffect(() => { + onMessageRef.current = onMessage + }, [onMessage]) + + useEffect(() => { + if (!enabled) return + + let ws = null + let reconnectTimer = null + let stopped = false + + const connect = () => { + const token = localStorage.getItem('access_token') + if (!token) return + + const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:' + ws = new WebSocket(`${protocol}//${window.location.host}/api/mqtt/ws?token=${token}`) + + ws.onopen = () => setConnected(true) + ws.onclose = () => { + setConnected(false) + if (!stopped) reconnectTimer = setTimeout(connect, 5000) + } + ws.onerror = () => {} + ws.onmessage = (event) => { + try { + const data = JSON.parse(event.data) + onMessageRef.current?.(data) + } catch { + // ignore invalid JSON + } + } + } + + connect() + + return () => { + stopped = true + clearTimeout(reconnectTimer) + ws?.close() + } + }, [enabled]) + + return { connected } +} + +export default useMqttWebSocket