omni-pca-docs/src/content/docs/explanation/zone-unit-numbering.md
Ryan Malloy 9ea05c3b94 docs: add Hardware specs reference + Zone & unit numbering explanation
Two new pages distilled from HAI's official OmniPro II Installation
Manual 3-2 + Product Specifications datasheet (Quadomated mirror).

reference/hardware-specs.md
  Capacity ceilings (176 zones, 511 units, 8 areas, 64 thermostats,
  128 buttons, 1500 programs, 99 codes, 128 messages, etc.), digital
  communicator + network features, electrical specs with the per-output
  current caps and the 24-hour battery-standby derating numbers,
  physical dimensions, environmental ranges, listings, languages, and
  part-number lookup. The numbers here are the source of every cap in
  clsCapOMNI_PRO_II.cs and the upper bounds for the protocol's range
  fields, so anyone debugging "why does my panel NAK at index N" should
  start here.

explanation/zone-unit-numbering.md
  Appendix C of the install manual, transcribed and explained: how the
  panel maps physical hardware to its 1-176 zone and 1-511 unit
  address spaces. Documents the four overlapping families that share
  the unit number line -- X-10 (1-256, by house code), ALC bus
  (parallel address space within those slots), physical outputs
  (257-392), and panel flags (393-511) -- which is why the working
  panel reports units at index 257+ (sprinkler outputs on the first
  17A00 expansion enclosure) and 393+ (named flags) even though only
  a dozen lights are wired up.

  Closes a real debugging mystery from Phase 2/3 of the v1+UDP work:
  OmniClientV1's long-form RequestUnitStatus path (BE u16 start/end)
  exists specifically to address units > 255, which only happens
  because of this firmware-fixed address layout.

astro.config.mjs
  Slot both new pages into the existing Reference and Explanation
  sidebar groups.
2026-05-11 13:23:58 -06:00

5.7 KiB
Raw Blame History

title description
Zone & unit numbering How the Omni Pro II maps physical hardware to its 1-176 zone and 1-511 unit address space — and why your panel may report units in the 257+ range even with no 16th-house-code X-10 module installed.

A panel that looks like it has 8 zones and a dozen lights to a homeowner is actually addressing into a much larger fixed map of 176 zone slots and 511 unit slots. The mapping is part of the controller's firmware, not configurable. If you walk the panel with OmniClientV1.iter_names() and see units at index 257 or 393, this is why.

This page is a literal transcription of Appendix C of HAI's OmniPro II Installation Manual 3-2, p74 — distilled from the live mapping our firmware-2.12 panel actually reports.

Zones (1-176)

Every group of 16 zones is one physical board / enclosure.

Index range Source
1 16 Controller (onboard)
17 32 1st 10A06 hardwire expander board
33 48 2nd 10A06 hardwire expander board
49 64 1st 17A00 expansion enclosure
65 80 2nd 17A00 expansion enclosure
81 96 3rd 17A00 expansion enclosure
97 112 4th 17A00 expansion enclosure
113 128 5th 17A00 expansion enclosure
129 144 6th 17A00 expansion enclosure
145 160 7th 17A00 expansion enclosure
161 176 8th 17A00 expansion enclosure

The hardware cap is 176, regardless of how many your installer wired up. Slots without a physical sensor still respond to RequestZoneStatus — they just return status=0, loop=0 (or the analog-loop "no transponder" sentinel 0x80).

Units (1-511)

The unit address space mixes four protocol families — X-10, ALC, physical outputs, and "flags" — into one flat number line. Which one each block lands in is fixed by the firmware:

X-10 (1 256, by house code)

X-10 modules are addressed (house_code, unit_id) on the wire but Omni flattens that to a single integer: each consecutive house code gets the next 16 indices. The installer picks the starting house code "X" at setup time; the controller occupies X through X+15 (16 house codes).

Index range Source
1 16 X-10 house code X (start), modules 116
17 32 X-10 house code X+1, modules 116
33 48 X-10 house code X+2
49 64 X-10 house code X+3
65 80 X-10 house code X+4
81 96 X-10 house code X+5
97 112 X-10 house code X+6
113 128 X-10 house code X+7
129 144 X-10 house code X+8
145 160 X-10 house code X+9
161 176 X-10 house code X+10
177 192 X-10 house code X+11
193 208 X-10 house code X+12
209 224 X-10 house code X+13
225 240 X-10 house code X+14
241 256 X-10 house code X+15

ALC bus (parallel address space)

ALC ("Advanced Lighting Control") devices share the X-10 slots above, but only every other range within a 64-block module/branch:

Index range Source
1 31 ALC Module 1, Branch 1 (addresses 1-31)
33 63 ALC Module 1, Branch 2
65 95 ALC Module 1, Branch 3
97 127 ALC Module 1, Branch 4
129 159 ALC Module 2, Branch 1
161 191 ALC Module 2, Branch 2
193 223 ALC Module 2, Branch 3
225 255 ALC Module 2, Branch 4

ALC and X-10 numbering deliberately overlap: if you've wired an ALC device at module 1 / branch 1 / addr 5, it lives at unit index 5 — same slot the X-10 firmware would otherwise have for house-code-X module 5. You pick one or the other; the panel won't drive both into the same slot.

Physical outputs (257 392)

Real relay/voltage outputs on the controller and expansion enclosures:

Index range Source
257 272 Outputs 1-16, 1st 17A00 expansion enclosure
273 288 Outputs 1-16, 2nd 17A00
289 304 Outputs 1-16, 3rd 17A00
305 320 Outputs 1-16, 4th 17A00
321 336 Outputs 1-16, 5th 17A00
337 352 Outputs 1-16, 6th 17A00
353 368 Outputs 1-16, 7th 17A00
369 384 Outputs 1-16, 8th 17A00
385 392 Voltage outputs 1-8 on the controller itself

Flags (393 511)

The top 119 unit slots aren't hardware — they're flags: panel variables an installer can write Programming Lines against. Flags behave like units on the wire (you can turn_unit_on(400) to set flag 400), but no physical load moves.

Index range Source
393 511 Flags (panel variables)

Why this matters for omni-pca

  • OmniClientV1.iter_names() streams names for any defined slot in the full 1-511 range. If your .pca config defined sprinkler controllers as outputs 1-10 on the first 17A00, you'll see them as units 257-266 — even though only 8 "real" lights are wired up.
  • RequestUnitStatus has two payload forms. The short form's start and end are single bytes (max 255). The long form takes BE u16s (max 65535) — see clsOLMsgRequestUnitStatus.cs:18-31. Our v1 client picks the right form automatically based on the requested range.
  • Per-poll record cap. Firmware 2.12 caps a single RequestUnitStatus reply at ~62 records regardless of MessageLength headroom; querying a wider range NAKs. OmniClientV1Adapter chunks status polls into batches of 40 to stay well under that.

If you want to see the live mapping for your panel, run:

cd omni-pca
uv run python dev/probe_v1_client.py

— it dumps every defined name across all object types and lets you correlate user-facing labels with their underlying unit index.