Redesign dashboard zone card with live temps, AC status, and per-radiator state

Adds actual room-temperature capture for TRVs over MQTT and a background
Modbus poller for AC mode/fan/lock/room-temp, so the dashboard tile can show
real setpoint-vs-actual readings, an AC status block, and up to 3 radiator
icons per zone instead of just the setpoint.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-07-27 20:25:50 +00:00
parent ab14d4dfe1
commit 0929285651
9 changed files with 230 additions and 12 deletions

View file

@ -205,7 +205,7 @@ html, body, #root { height: 100%; margin: 0; font-size: 14px; }
}
/* ── Zone grid / cards ─────────────────────────────────────── */
.zone-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 12px; }
.zone-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 12px; }
.zone-card {
cursor: pointer;
transition: box-shadow .12s, transform .12s;
@ -218,9 +218,32 @@ html, body, #root { height: 100%; margin: 0; font-size: 14px; }
.zone-card.st-occupied { border-left-color: var(--st-occupied); }
.zone-card.st-cooling_down { border-left-color: var(--st-cooling-down); }
.zone-card-title { font-weight: 600; font-size: 14px; margin-bottom: 4px; display: flex; align-items: center; gap: 6px; justify-content: space-between; }
.zone-card-temp { font-size: 22px; font-weight: 700; margin: 6px 0 2px; }
.zone-card-temp { font-size: 20px; font-weight: 700; margin: 6px 0 2px; }
.zone-card-meta { font-size: 12px; color: var(--text-mid); display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
/* ── Zone card body: setpoint/radiators on the left, AC block on the right ─ */
.zone-card-body { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; margin-top: 4px; }
.zone-card-main { flex: 1; min-width: 0; }
.rad-row { display: flex; gap: 10px; margin-top: 8px; flex-wrap: wrap; }
.rad-icon { display: flex; align-items: center; gap: 3px; font-size: 10.5px; font-weight: 600; color: var(--text-mid); }
.rad-icon.heating { color: var(--st-occupied); }
.rad-icon.idle { color: var(--st-cooling-down); }
.ac-block { position: relative; display: flex; flex-direction: column; align-items: center; gap: 2px; padding-top: 4px; color: var(--text-dark); }
.ac-block.off { color: var(--text-mid); opacity: .55; }
.ac-lock { position: absolute; top: -10px; left: 50%; transform: translateX(-50%); color: var(--health-degraded); }
.ac-mode-row { display: flex; align-items: center; gap: 6px; }
.ac-temp { font-size: 10.5px; font-weight: 600; color: var(--text-mid); }
.fan-bar { display: flex; align-items: flex-end; gap: 2px; height: 16px; }
.fan-bar span { width: 3px; background: var(--card-border); border-radius: 1px; }
.fan-bar span:nth-child(1) { height: 25%; }
.fan-bar span:nth-child(2) { height: 50%; }
.fan-bar span:nth-child(3) { height: 75%; }
.fan-bar span:nth-child(4) { height: 100%; }
.fan-bar span.on { background: var(--app-primary); }
/* ── Badges ────────────────────────────────────────────────── */
.badge {
display: inline-flex;