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 <noreply@anthropic.com>
This commit is contained in:
2026-09-21 18:20:15 +03:00
co-authored by Claude Sonnet 5
parent eaf92f1581
commit 1ce0137ba9
+61 -2
View File
@@ -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