Replaces the read-only "conditions present but not editable" banner
with a real editor for the cond / cond2 u16 fields on TIMED / EVENT /
YEARLY programs.
Compact-form conditions split into five families per
clsText.GetConditionalText (clsText.cs:2224-2274):
none — cond = 0 (no inline condition)
misc — family 0x00, low nibble = enuMiscConditional
(NONE / NEVER / LIGHT / DARK / PHONE_* / AC_POWER_* /
BATTERY_* / ENERGY_COST_*)
zone — family 0x04, low byte = zone, bit 0x0200 = NOT_READY
unit — family 0x08, low 9 bits = unit, bit 0x0200 = ON
time — family 0x0C, low byte = time-clock #, bit 0x0200 = enabled
sec — family >= 0x10, bits 8-11 = area, bits 12-14 = security mode
types.ts gains decodeCondition / encodeCondition + the
MISC_CONDITIONALS / SECURITY_MODE_NAMES enums. Round-trip is exact:
decode(encode(c)) === c for every supported family.
UI: two condition slots per editor (matching the two u16 fields on
the wire). Each slot has a family-picker dropdown that swaps the
sub-fields (zone picker + secure/not-ready, unit picker + on/off,
area picker + security mode, time-clock # + enabled/disabled, misc
condition picker, or "none"). Picking a family seeds sensible defaults
(NEVER for misc, first zone secure, first unit ON, area 1 disarmed,
time clock 1 enabled).
Object pickers reuse the same _bucketWithPreserve helper introduced
for the action editor, so out-of-range zone/unit/area refs in inline
conditions keep their original value with a "preserve" label.
Live smoke test against the real panel: slot #1's actual condition
"AND IF Time clock 4 is disabled" now decodes into the editor as
Family=Time clock / # = 4 / Is = disabled — exactly the on-disk state.
Frontend bundle: 63 KB minified (up from 56 KB with the new editor
section + cond helpers).
Omni Programs side panel — frontend
Lit/TypeScript source for the HA side panel registered by
websocket.py:async_register_side_panel. The build output
(../www/panel.js) is committed so end-users don't need Node installed.
Edit / rebuild
cd custom_components/omni_pca/frontend
npm install # one-time
npm run build # one-shot — drops a fresh ../www/panel.js
npm run watch # rebuild on change (use during HA dev)
The build script (build.mjs) bundles the entry point + Lit + all
imports into a single ESM file at ../www/panel.js. Source maps are
inlined in --watch mode and stripped in production builds. Output is
~34 KB minified.
Layout
| File | Purpose |
|---|---|
src/omni-panel-programs.ts |
The custom-element entry point. Defines <omni-panel-programs> (matching the panel_custom registration). |
src/token-renderer.ts |
Token stream → Lit TemplateResult. Each TokenKind gets distinctive styling; REF tokens become buttons that dispatch a click. |
src/types.ts |
TS interfaces mirroring the Phase-B websocket wire shapes. Short keys (k/t/ek/ei/s) match websocket.py:_tokens_to_json. |
Wire contract
The panel calls three websocket commands (all defined in
../websocket.py):
omni_pca/programs/list— paginated, filterable summaries.omni_pca/programs/get— full structured-English detail for one slot.omni_pca/programs/fire— sendsCommand.EXECUTE_PROGRAMover the wire.
The frontend doesn't subscribe to push events; live-state badges
refresh on a low-frequency poll (REFRESH_MS = 5000). That's a
deliberate scope choice — switching to per-entity event subscription
is a follow-up if the polling overhead becomes visible on huge installs.