import Head from 'next/head'; import { useEffect, useMemo, useState } from 'react'; interface ApiStatus { message: string; docs: string; } interface MqttMessage { topic: string; payload: string; receivedAt: string; } declare global { interface Window { Paho?: { Client: new (...args: any[]) => any; }; } } export default function Home() { const [status, setStatus] = useState(null); const [error, setError] = useState(null); const [messages, setMessages] = useState([]); const [connected, setConnected] = useState(false); const clientId = useMemo(() => `ulhub-web-${Math.random().toString(16).slice(2)}`, []); useEffect(() => { fetch('/api/status') .then((res) => res.json()) .then(setStatus) .catch((err) => setError(err.message)); }, []); useEffect(() => { const script = document.createElement('script'); script.src = 'https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.min.js'; script.async = true; console.log('Appending Paho script to page:', script.src); script.onerror = () => { console.error('Failed to load Paho MQTT script from CDN'); setError('Failed to load MQTT client script'); }; script.onload = () => { console.log('Paho script loaded', !!window.Paho); console.log('Paho global:', window.Paho); // connect to same-origin via nginx proxy at /mqtt so browsers use wss on HTTPS const scheme = window.location.protocol === 'https:' ? 'wss' : 'ws'; const uri = `${scheme}://${window.location.host}/mqtt`; console.log('Connecting Paho client to', uri); let client: any; try { if (window.Paho && typeof (window.Paho as any).Client === 'function') { client = new (window.Paho as any).Client(uri, clientId); } else if (window.Paho && (window.Paho as any).MQTT && typeof (window.Paho as any).MQTT.Client === 'function') { // Paho.MQTT.Client(host, port, path, clientId) const url = new URL(uri); const host = url.hostname; const port = url.port ? Number(url.port) : (url.protocol === 'wss:' ? 443 : 80); const path = url.pathname + (url.search || ''); client = new (window.Paho as any).MQTT.Client(host, port, path, clientId); } else { console.error('Paho client constructor not found', window.Paho); setError('MQTT client not available in browser'); return; } } catch (e) { console.error('Failed to instantiate Paho client', e); setError(String(e)); return; } client.onConnectionLost = (responseObject: { errorCode: number; errorMessage: string }) => { console.warn('Paho connection lost', responseObject); setConnected(false); setError(responseObject.errorMessage || 'MQTT connection lost'); }; client.onMessageArrived = (message: { topic: string; payloadString: string }) => { setMessages((prev) => [ { topic: message.topic, payload: message.payloadString, receivedAt: new Date().toLocaleTimeString(), }, ...prev, ].slice(0, 10)); }; const connectOptions: any = { onSuccess: () => { console.log('Paho connected'); setConnected(true); setError(null); client.subscribe('devices/#'); }, onFailure: (err: { errorMessage: string }) => { console.error('Paho connect failure', err); setConnected(false); setError(err.errorMessage || 'Unable to connect to MQTT broker'); }, }; // force secure websocket when page is served over HTTPS connectOptions.useSSL = window.location.protocol === 'https:'; console.log('Paho connect options:', connectOptions); client.connect(connectOptions); return () => { client.disconnect(); }; }; document.body.appendChild(script); return () => { document.body.removeChild(script); }; }, [clientId]); return ( <> UlHub

UlHub

React + Next.js frontend with NestJS backend and live MQTT WebSocket data.

API Status

{error &&

{error}

} {status ? (

{status.message}

{status.docs}

) : (

Loading status...

)}

MQTT WebSocket

Status: {connected ? 'Connected' : 'Connecting...'}

    {messages.map((msg, index) => (
  • {msg.topic} {msg.receivedAt}
    {msg.payload}
  • ))}
); }