Mercurial > code > home > repos > light-bridge
view src/main.ts @ 23:7d9a056e29fe
esp rgbw output; cleanup
author | drewp@bigasterisk.com |
---|---|
date | Mon, 29 Jan 2024 23:41:27 -0800 |
parents | 178e020289c1 |
children |
line wrap: on
line source
import { LitElement, TemplateResult, css, html } from "lit"; import { customElement, state } from "lit/decorators.js"; interface Light { name: string; address: { url?: string; label: string }; requestingColor: string; requestingDeviceColor: object; emittingColor: string; online: boolean; latencyMs: number; } @customElement("lb-page") export class LbPage extends LitElement { static styles = [ css` :host { display: flex; flex-direction: column; height: 100vh; } table { border-collapse: collapse; } td, th { border: 1px solid #aaa; text-align: center; } .color { display: inline-block; width: 30px; height: 30px; border-radius: 50%; margin: 3px; vertical-align: middle; } .col-group-1 { background: #e0ecf4; } .col-group-2 { background: #e0f3db; } .col-group-3 { background: #fee8c8; } @media (max-width: 1200px) { .opt { display: none; } } `, ]; // bug https://github.com/lit/lit/issues/4305 @((state as any)()) lights: Light[] = []; @((state as any)()) lightByName: Map<string, Light> = new Map(); @((state as any)()) reportTime: Date = new Date(0); connectedCallback(): void { super.connectedCallback(); const es = new EventSource("api/table"); es.onmessage = (ev) => { console.log("got table update"); const body = JSON.parse(ev.data); this.lights = body.lights.map((wrappedLight: any) => wrappedLight.light as Light); this.rebuildLightByName(); this.reportTime = new Date(body.now * 1000); }; } private rebuildLightByName() { this.lightByName = new Map(); this.lights.forEach((light: any) => { this.lightByName.set(light.name, light); }); } render() { return html` <h1>Light-bridge</h1> <table> ${this.renderLightHeaders()} ${this.lights.map(this.renderLightRow.bind(this))} </table> <p>Updated ${this.reportTime.toLocaleString("sv")}</p> <p> <a href="metrics">metrics</a> | <a href="https://bigasterisk.com/code/light-bridge/files/tip/">code</a> | <a href="api/graph">graph</a> </p> <bigast-loginbar></bigast-loginbar> `; } renderLightHeaders() { return html`<tr> <th class="col-group-1">light</th> <th class="col-group-1">address</th> <th class="col-group-2">requested color</th> <th class="col-group-2 opt">requested device color</th> <th class="col-group-3">emitting color</th> <th class="col-group-3 opt">online</th> <th class="col-group-3 opt">latency</th> </tr>`; } renderLightRow(d: Light) { return html` <tr> <td class="col-group-1">${d.name}</td> <td class="col-group-1"><code>${this.renderLinked(d.address)}</code></td> <td class="col-group-2"> <code>${d.requestingColor}</code> <input type="color" @input=${this.onRequestingColor.bind(this, d.name, null)} .value="${d.requestingColor}" /> <button @click=${this.onRequestingColor.bind(this, d.name, "#000000")}>off</button> <button @click=${this.onRequestingColor.bind(this, d.name, "#ffffff")}>full</button> </td> <td class="col-group-2 opt"><code>${JSON.stringify(d.requestingDeviceColor)}</code></td> <td class="col-group-3">${d.emittingColor} <span class="color" style="background: ${d.emittingColor}"></span></td> <td class="col-group-3 opt">${d.online ? "✔" : ""}</td> <td class="col-group-3 opt">${d.latencyMs} ms</td> </tr> `; } private renderLinked(link: { url?: string; label: string }): TemplateResult { var addr = html`${link.label}`; if (link.url) { addr = html`<a href="${link.url}">${addr}</a>`; } return addr; } async onRequestingColor(lightName: string, preset: string | null, ev: InputEvent) { const currentRequest = this.lightByName.get(lightName)!.requestingColor; const value = preset || (ev.target as HTMLInputElement).value; console.log("LbPage ~ onRequestingColor ~ value === currentRequest:", value, currentRequest); if (value === currentRequest) { return; } const url = new URL("api/output", location as any); url.searchParams.append("light", lightName); fetch(url, { method: "PUT", body: value }); // todo: only run one fetch at a time, per light // sometime after this, the SSE table will send us back the change we made (probably) } }