docs: Edit-programs-in-HA how-to + side-panel reference + MDX fixes

New how-to walks through the Omni Programs side panel end-to-end:
list view, filters, the detail panel, compact-form editing, the
clausal chain editor, structured-AND with Arg2-as-object, known
limits, and the websocket commands the panel speaks. Five
embedded screenshots from a real .pca fixture.

reference/ha-entities.md picks up a short callout near the top so
readers browsing entity docs don't miss the side panel.

program-format.mdx had three pre-existing unescaped '<' characters
('firmware <3.0' and '(family << 8)' inside a table) that were
breaking the MDX build. Replaced with 'before 3.0' and escaped
operators.
This commit is contained in:
Ryan Malloy 2026-05-17 13:06:30 -06:00
parent 7bbe1b4372
commit de02f10be7
8 changed files with 216 additions and 3 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 KiB

View File

@ -0,0 +1,206 @@
---
title: Edit panel programs from Home Assistant
description: Browse, search, clone, and edit the panel's built-in automation programs from a Home Assistant side panel — no PC Access required.
sidebar:
order: 5
---
import { Image } from 'astro:assets';
import shotList from '../../../assets/screenshots/programs-list.png';
import shotDetail from '../../../assets/screenshots/programs-detail.png';
import shotCompact from '../../../assets/screenshots/programs-editor-compact.png';
import shotChain from '../../../assets/screenshots/programs-editor-chain.png';
import shotStructured from '../../../assets/screenshots/programs-editor-structured.png';
The integration registers a side-panel item called **Omni Programs**
that lets you view and edit the panel's built-in automation programs
without opening PC Access. These are the **panel-side** programs that
run on the Omni controller itself (so they survive HA outages), as
opposed to HA automations which run inside HA.
Open Home Assistant in your browser. **Omni Programs** appears in the
left sidebar alongside Overview, Map, Energy, etc.
<Image src={shotList} alt="Omni Programs side panel showing a list of panel programs with WHEN/THEN summaries, trigger-type badges, and a search box" style="border: 1px solid color-mix(in srgb, currentColor 25%, transparent); border-radius: 6px; margin: 1rem 0;" />
## Browsing & filtering
The header shows the total program count (`330 programs` on the panel
this screenshot was taken against). Each row is one program — for
multi-record clausal chains the row shows the **head** slot and
collapses the chain into a single summary line.
- **Search** — typing into the search box filters by any visible text
in the summary (program names, object names, command labels).
- **Trigger-type chips** — `TIMED` / `EVENT` / `YEARLY` / `WHEN` / `AT`
/ `EVERY` / `REMARK`. Click to toggle each filter; combinations are
OR'd. The right-edge badge on each row tells you the trigger type
and condition count.
- **References filter** — programs referencing a specific object
(zone, unit, area, button, thermostat) can be filtered from the HA
entity page: open any zone/unit/etc. entity, scroll to *Related*,
and click the program count to jump into the side panel pre-filtered
to that object.
The list updates in real time as the panel pushes program changes —
no manual refresh needed.
## The detail panel
Click any row to open the detail panel on the right.
<Image src={shotDetail} alt="Detail panel for slot 1 showing structured-English breakdown 'WHEN OPEN BIG GAR is pressed AND IF Time clock 4 is disabled THEN Turn ON Unit 33025' and four action buttons: Fire now, Edit, Clone, Clear" style="border: 1px solid color-mix(in srgb, currentColor 25%, transparent); border-radius: 6px; margin: 1rem 0;" />
The structured-English breakdown is the same renderer that produces
the row summary, but expanded — one clause per line, conditions in
context.
Four actions:
- **Fire now** — executes the program's THEN action immediately,
bypassing any conditions or schedule. Equivalent to PC Access's
"Test" button.
- **Edit** — opens the inline editor (see below).
- **Clone…** — duplicates the program into a different slot. Prompts
for the target slot number; refuses to overwrite a non-empty slot.
- **Clear** — wipes the slot to all zeros (`FREE`). Confirmation
required; this is sent to the panel as `DownloadProgram` with a
zero body, matching PC Access's "Delete" behaviour.
## Editing a compact-form program
Compact-form programs (`TIMED`, `EVENT`, `YEARLY`, `REMARK`) fit
entirely in one 14-byte record — the editor lays them out as a single
form with trigger fields up top, the action in the middle, and up to
two inline AND-IF conditions at the bottom.
<Image src={shotCompact} alt="Compact-form program editor for an EVENT-triggered program showing Category (Button press), Button (#1 OPEN BIG GAR), Action (Turn ON unit #33025), and an inline AND-IF on Time clock 4 disabled" style="border: 1px solid color-mix(in srgb, currentColor 25%, transparent); border-radius: 6px; margin: 1rem 0;" />
The form adapts to the trigger type:
- **TIMED** — hour / minute (or sunrise/sunset offset) + days-of-week
bitmask.
- **EVENT** — a category dropdown (Button press / Zone state change /
Unit state change / Fixed event), then category-specific sub-fields.
For example, *Button press* shows a button picker; *Zone state
change* shows zone + becomes-state.
- **YEARLY** — month + day-of-month picker.
- **REMARK** — read-only in this release (see [known
limits](#known-limits) below).
The action section is a command picker plus a parameter input whose
shape follows the command. *Turn ON unit* shows a unit picker; *Arm
area Night* shows an area picker; *Execute button* shows a button
picker.
The two inline AND-IF slots each get a Family dropdown (Zone / Unit /
Time clock / Misc / Area in security mode) and per-family sub-fields.
Hit **Save** to write the program back to the panel via
`DownloadProgram`. The integration validates the form server-side
before sending: bad ranges produce a structured error, not a corrupt
program.
## Editing a multi-record chain
Programs with `prog_type` ≥ 5 (`WHEN` / `AT` / `EVERY`) are
**clausal chains** — one record per visual line, occupying sequential
slots in the program table. The editor presents the whole chain as
one logical unit even though it's stored across multiple slots.
<Image src={shotChain} alt="Chain editor for a WHEN program showing the trigger header (Zone state change / FRONT_DOOR / not ready), a Conditions section with one AND IF row (Unit state / LIVING_LAMP / ON), and an Actions section with a THEN row (Turn ON unit / #2 KITCHEN_OVERHEAD)" style="border: 1px solid color-mix(in srgb, currentColor 25%, transparent); border-radius: 6px; margin: 1rem 0;" />
The editor has three sections:
- **Trigger header** (top) — the `WHEN` / `AT` / `EVERY` record.
- **Conditions** — zero or more `AND IF` / `OR IF` rows. Use the
`+ AND IF` button to add a row to the current group, or `+ OR IF` to
start a new alternative group. Each row has an `×` button to remove
it.
- **Actions** — one or more `THEN` rows. Use `+ THEN` to add another
action; chains can fire multiple actions in sequence.
**Anti-trample** — when you Save, the editor writes only the slots
needed for the current chain layout. If you remove a condition or
action, the slots it used to occupy are explicitly cleared so no
half-stale records linger on the panel.
## Structured-AND conditions
Most AND IF rows use the **Traditional** form (family + instance +
operand — "Zone 5 is SECURE", "Unit 12 is ON", etc). But the panel
also supports **Structured** AND records that compare a typed field
against either a constant or another typed field:
> AND IF Thermostat 1 Current temperature **>** Thermostat 2 Current temperature
The editor renders these as a dedicated form with operator picker
and per-arg type pickers:
<Image src={shotStructured} alt="Structured-AND editor showing Arg1 (Thermostat #1 LIVING_ROOM Current temperature), Operator (>), and Arg2 (Thermostat #2 MASTER_BEDROOM Current temperature) — both sides are typed references rather than constants" style="border: 1px solid color-mix(in srgb, currentColor 25%, transparent); border-radius: 6px; margin: 1rem 0;" />
**Arg1** can be any of: Zone, Unit, Thermostat, Area, Time/Date.
Each type has its own field selector — for Thermostat that's
*Current temperature / Heat setpoint / Cool setpoint / System mode /
Humidity / …*; for Zone it's *Loop reading / Current state / …*.
**Operator** is one of: `==`, `!=`, `<`, `>`, `is odd`, `is even`,
`is multiple of`, `in (bitmask)`, `not in (bitmask)`. The unary
operators (`is odd` / `is even`) hide the Arg2 controls entirely.
**Arg2** can be:
- **Constant** (default for new structured rows) — a 0..65535 value.
Used for "TEMP > 70", "Zone.CurrentState == 1", etc.
- **A typed reference** — Zone / Unit / Thermostat / Area / TimeDate
with its own field selector. This is how you author cross-object
comparisons like "Thermostat 1 temp > Thermostat 2 temp" or
"Zone 1 reading > Zone 2 reading".
Switching Arg2 from Constant to a reference type re-populates the
form with the appropriate picker; switching back preserves the
numeric value.
For the wire format behind all this, see the
[Program record format reference](/reference/program-format/#structured-op-and-records-op--0).
## Known limits
The editor covers the common cases but a few program shapes are
deliberately presented read-only — they're preserved verbatim on
Save, you just can't reshape them in the form:
- **REMARK programs** — read-only. The `remark_id` → text lookup
table layout is documented but the editor doesn't expose it yet.
- **Exotic Arg1/Arg2 types** on structured-AND — `UserSetting`,
`Auxiliary`, `Audio`, `AccessControl`, `Message`, `System`. These
show as a read-only banner with an `×` remove button.
- **Non-zero `CompConst`** on structured-AND — rarely used; preserved
but not exposed as a form control.
- **Multi-panel installs** — the side panel currently shows the
first configured panel. If you have multiple Omni panels, the
other panels' programs aren't accessible from the side panel yet.
## Where the data lives
The side panel is a Lit web component (`<omni-panel-programs>`)
registered via Home Assistant's `panel_custom` integration. It talks
to the integration's websocket API directly — there's no separate
state machine, no caching, no debouncing. Each user action becomes
one websocket round-trip:
| Action | Websocket command |
|---|---|
| List view + filters | `omni_pca/programs/list` |
| Open detail panel | `omni_pca/programs/get` |
| Fire now | `omni_pca/programs/fire` |
| Save (compact) | `omni_pca/programs/write` |
| Save (chain) | `omni_pca/programs/write_chain` |
| Clone… | `omni_pca/programs/clone` |
| Clear | `omni_pca/programs/clear` |
All seven commands validate input server-side and produce structured
errors (no opaque tracebacks) on bad input. The websocket layer's
own tests cover the contract — see `tests/ha_integration/
test_program_websocket.py` in the source tree if you want to extend
the API surface.

View File

@ -10,6 +10,13 @@ refresh; live state propagates over the panel's unsolicited push channel
within one TCP round-trip, with a 30-second poll backstopping anything that
didn't push.
In addition to the entity catalogue below, the integration registers an
**Omni Programs** sidebar item — a dedicated UI for browsing, editing,
cloning, and firing the panel's built-in automation programs (the
panel-side rules that run on the controller itself, distinct from HA
automations). See the [edit-programs-in-ha
how-to](/how-to/edit-programs-in-ha/) for the walkthrough.
| Platform | Entity | Per |
|---|---|---|
| `alarm_control_panel` | Area arm/disarm with code | discovered area |

View File

@ -347,7 +347,7 @@ The block fits in **one** 14-byte record. `prog_type` is `TIMED`,
- For `EVENT`, the event identifier replaces the calendar
month/day at bytes 9-10 (see [the EVENT `Evt` u16 section](#also-for-event-bytes-910-are-an-event-identifier-not-a-date)).
This is how 100% of records in any panel running firmware <3.0 are
This is how 100% of records in any panel running firmware before 3.0 are
encoded. It is also how PC Access encodes any block that fits the
constraints, even on firmware ≥3.0 — see the simplification rules
in `frmAutomationEditBlock.cs:589 SimplifyLines`.
@ -398,7 +398,7 @@ The firmware gate is `Features.Add(MultiLinePrograms, 196608u)` in
`clsCapOMNI_PRO_II.cs:290` (the 24-bit value packs as
`major*65536 + minor*256 + revision` → 3.0.0).
When MultiLinePrograms is OFF (firmware <3.0):
When MultiLinePrograms is OFF (firmware before 3.0):
- PC Access's `Or` toolbar button and "Add Comment Block" menu item
are disabled.
@ -420,7 +420,7 @@ load on a real 2.16A panel.
| Byte(s) | Field | Notes |
| --- | --- | --- |
| 0 | `prog_type` | = 5 |
| 9-10 (BE u16) | event-id | `(family << 8) | instance` — same encoding as compact-form `EVENT`'s bytes 9-10 in wire form. **No** Mon/Day file-form swap. |
| 9-10 (BE u16) | event-id | `(family \<\< 8) \| instance` — same encoding as compact-form `EVENT`'s bytes 9-10 in wire form. **No** Mon/Day file-form swap. |
| 1-8, 11-13 | zeros | (action lives in a separate `THEN` record) |
#### `AT` (ProgType=6) — single-occurrence time trigger