mirror of
https://github.com/rstrouse/ESPSomfy-RTS.git
synced 2026-10-31 13:52:15 +01:00
feat: web UI on socket protocol 2 (step 2b)
The UI talks to the device over the one socket at /ws: the sync fills the shade model, its events redraw the lists, and every read, command, edit, setting, scan and reboot is an op. Only /loginContext, /login and the file transfers stay on HTTP, so a page load opens no other connection. - The 8080 socket, editJSON/requestResult and the /controller, /rooms, /shades, /groups, /room, /shade, /group, settings and command routes are no longer used by the UI. - An edit's callback gets the item once its event is in (ProtoClient waitFor); busy edits and saves are sent again. - The token is kept in sessionStorage. When /ws is refused and /loginContext says a login is needed, the client stops retrying and the login panel opens. Backup and uploads send the token. - A banner shows when the device speaks another protocol version. - Removed dead code: the /pairShade call and its unused /unpairShade twin, loadLogin, login.html (broken, linked from nowhere), Secure Config Only's checkbox (protocol 2 has two modes) and the HTTP helpers nothing uses. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
4415beb4f7
commit
0df740df6a
6 changed files with 570 additions and 944 deletions
|
|
@ -68,7 +68,27 @@ class ProtoClient {
|
|||
// unless a listener calls close(), as the UI does once /loginContext says
|
||||
// a login is needed (docs/SECURITY_PLAN.md).
|
||||
on(name, cb) { (this.listeners[name] = this.listeners[name] || []).push(cb); }
|
||||
emit(name, d) { for (const cb of this.listeners[name] || []) cb(d); }
|
||||
off(name, cb) { this.listeners[name] = (this.listeners[name] || []).filter((x) => x !== cb); }
|
||||
emit(name, d) { for (const cb of (this.listeners[name] || []).slice()) cb(d); }
|
||||
// The next event of that name that match(d) accepts, or null after ms.
|
||||
// An edit's events follow its reply, so this is how a caller gets the
|
||||
// item the edit left: the model has it by then.
|
||||
waitFor(name, match, ms) {
|
||||
return new Promise((resolve) => {
|
||||
let timer = null;
|
||||
const cb = (d) => {
|
||||
if (match && !match(d)) return;
|
||||
this.off(name, cb);
|
||||
this.clearTimeout(timer);
|
||||
resolve(d);
|
||||
};
|
||||
this.on(name, cb);
|
||||
timer = this.setTimeout(() => {
|
||||
this.off(name, cb);
|
||||
resolve(null);
|
||||
}, ms);
|
||||
});
|
||||
}
|
||||
|
||||
connect() {
|
||||
if (!this.stopped && (this.ws || this.reconnectTimer)) return;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue