Device ${device.id}/>
<${Button} title="Forget this device" onclick=${onforget}/>
/>
<${LedControlPanel} device=${device} rpc=${rpc} connected=${connected} />
<${FirmwareUpdatePanel} device=${device} rpc=${rpc} connected=${connected} />
/>
/>`;
}
const App = function() {
const sigDevices = useSignal([]);
const sigCurrentDevID = useSignal(localStorage.getItem('currentDevID') || '');
const sigUrl = useSignal(localStorage.getItem('url') || DefaultUrl);
const sigTopic = useSignal(localStorage.getItem('topic') || DefaultTopic);
const sigError = useSignal(null);
const sigLoading = useSignal(true);
const sigConnected = useSignal(false);
const responseHandlers = useRef({});
const getDeviceByID = (deviceID) => sigDevices.value.find(d => d.id === deviceID);
function addResponseHandler(correlationId, handler) {
responseHandlers[correlationId] = handler;
}
function removeResponseHandler(correlationId) {
delete responseHandlers[correlationId];
}
const onRefresh = () => window.location.reload();
const initConn = () => {
MqttClient = mqtt.connect(sigUrl.value, {connectTimeout: 5000, reconnectPeriod: 0});
MqttClient.on('connect', () => {
//console.log('Connected to the broker');
sigLoading.value = false;
sigError.value = null; // Reset error state upon successful connection
sigConnected.value = true;
const statusTopic = sigTopic.value + '/+/status'
const txTopic = sigTopic.value + '/+/tx'
const subscribe = (topic) => {
MqttClient.subscribe(topic, (err) => {
if (err) {
console.error('Error subscribing to topic:', err);
setError('Error subscribing to topic');
} else {
//console.log('Successfully subscribed to ', topic);
}
});
};
subscribe(statusTopic);
subscribe(txTopic);
});
MqttClient.on('message', (topic, message) => {
console.log(`Received message from ${topic}: ${message.toString()}`);
if (message.length == 0) return;
let response;
try {
response = JSON.parse(message.toString());
} catch (err) {
console.error(err);
return;
}
if (topic.endsWith('/status')) {
if (!response.params) {
console.error('Invalid response');
return;
}
let device = Object.assign(response.params, {topic: topic, id: topic.split('/')[1]});
device.online = response.params.status === 'online';
const devices = sigDevices.value.filter(d => d.id !== device.id);
devices.push(device);
devices.sort((a, b) => a.online && !b.online ? -1
:!a.online && b.online ? 1
: a.id < b.id ? -1 : 1);
sigDevices.value = devices;
} else if (topic.endsWith('/tx')) {
if (!response.id) {
console.error('Invalid response');
return;
}
const handler = responseHandlers[response.id];
if (handler) {
handler(response);
removeResponseHandler(response.id);
}
}
});
MqttClient.on('error', (err) => {
console.error('Connection error:', err);
sigError.value = 'Connection cannot be established.';
});
MqttClient.on('close', () => {
if (!sigConnected.value) {
console.error('Failed to connect to the broker.');
sigError.value = 'Connection cannot be established.';
sigLoading.value = false;
}
});
};
useEffect(() => initConn(), []);
const handlePublish = (methodName, parameters, timeout = 5000) => {
return new Promise((resolve, reject) => {
const randomIdGenerator = function(length) {
return Math.random().toString(36).substring(2, length + 2);
};
const randomID = randomIdGenerator(40);
const timeoutID = setTimeout(() => {
removeResponseHandler(randomID);
reject(new Error('Request timed out'));
}, timeout);
addResponseHandler(randomID, (messageData) => {
clearTimeout(timeoutID);
resolve(messageData);
});
if (sigCurrentDevID.value) {
const rxTopic = sigTopic.value + `/${sigCurrentDevID.value}/rx`;
const rpcPayload = {method: methodName, id: randomID};
if (parameters) {
rpcPayload.params = parameters;
}
console.log(`Sending message to ${rxTopic}: ${JSON.stringify(rpcPayload)}`);
MqttClient.publish(rxTopic, JSON.stringify(rpcPayload));
}
});
};
const onDeviceClick = (deviceID) => {
const device = getDeviceByID(deviceID);
if (device) {
sigCurrentDevID.value = device.id;
localStorage.setItem('currentDevID', device.id);
}
};
if (sigError.value) {
return html`
<${Header} sigTopic=${sigTopic} sigUrl=${sigUrl} />
Connection Error
Unable to connect to the MQTT broker.
<${Button} title="Retry" onclick=${onRefresh} class="absolute top-4 right-4" />
`;
}
return html`
<${Header} sigTopic=${sigTopic} sigUrl=${sigUrl} connected=${sigConnected.value} />
<${Sidebar} devices=${sigDevices.value} onclick=${onDeviceClick} />
/>
<${DeviceDashboard}
device=${getDeviceByID(sigCurrentDevID.value)} connected=${sigConnected.value}
rpc=${handlePublish} />
/>
<${Help} />
/>
/>`;
};
window.onload = () => render(h(App), document.body);