Fix connection timeout: use REST API for initial state load, increase WS timeout to 60s

Large HA instances with many entities cause get_states to exceed the 12s
WebSocket timeout. Now loads all states via /api/states HTTP endpoint first
(much more reliable for large payloads), with WebSocket get_states as fallback.
Also bumped WS send timeout from 12s to 60s for slow HA responses.
This commit is contained in:
2026-05-15 16:11:44 +10:00
parent 4bdb228a8c
commit 76b67d3470
+18 -5
View File
@@ -248,17 +248,30 @@ function dispatch(msg) {
function send(msg) { function send(msg) {
return new Promise((res, rej) => { return new Promise((res, rej) => {
const id = wsId++; msg.id = id; pending[id] = { res, rej }; const id = wsId++; msg.id = id; pending[id] = { res, rej };
setTimeout(() => { if (pending[id]) { delete pending[id]; rej(new Error('timeout')); } }, 12000); setTimeout(() => { if (pending[id]) { delete pending[id]; rej(new Error('timeout')); } }, 60000);
ws.send(JSON.stringify(msg)); ws.send(JSON.stringify(msg));
}); });
} }
async function onAuth() { async function onAuth() {
setBadge('connected'); setBadge('connected');
const r = await send({ type: 'get_states' }); // Use REST API for initial state load — handles large HA instances better
r.result.forEach(s => { states[s.entity_id] = s; }); // than WebSocket get_states which can timeout with hundreds of entities
await send({ type: 'subscribe_events', event_type: 'state_changed' }); try {
parseCfg(states[CFG_ENTITY]?.state); render(); const resp = await fetch(`${prefs.url}/api/states`, {
headers: { Authorization: `Bearer ${prefs.token}` }
});
if (resp.ok) { const all = await resp.json(); all.forEach(s => { states[s.entity_id] = s; }); }
} catch(e) {
try { const r = await send({ type: 'get_states' }); r.result.forEach(s => { states[s.entity_id] = s; }); }
catch(e2) { console.warn('Could not load initial states:', e2); }
}
try { await send({ type: 'subscribe_events', event_type: 'state_changed' }); }
catch(e) { console.warn('Could not subscribe to events:', e); }
parseCfg(states[CFG_ENTITY]?.state);
render();
} }
function onStateChange({ entity_id, new_state }) { function onStateChange({ entity_id, new_state }) {
states[entity_id] = new_state; states[entity_id] = new_state;
if (entity_id === CFG_ENTITY) { parseCfg(new_state?.state); schedRender(); return; } if (entity_id === CFG_ENTITY) { parseCfg(new_state?.state); schedRender(); return; }