Skip to content

Zone & unit numbering

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.

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

Index rangeSource
1 – 16Controller (onboard)
17 – 321st 10A06 hardwire expander board
33 – 482nd 10A06 hardwire expander board
49 – 641st 17A00 expansion enclosure
65 – 802nd 17A00 expansion enclosure
81 – 963rd 17A00 expansion enclosure
97 – 1124th 17A00 expansion enclosure
113 – 1285th 17A00 expansion enclosure
129 – 1446th 17A00 expansion enclosure
145 – 1607th 17A00 expansion enclosure
161 – 1768th 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).

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

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

Index rangeSource
1 – 31ALC Module 1, Branch 1 (addresses 1-31)
33 – 63ALC Module 1, Branch 2
65 – 95ALC Module 1, Branch 3
97 – 127ALC Module 1, Branch 4
129 – 159ALC Module 2, Branch 1
161 – 191ALC Module 2, Branch 2
193 – 223ALC Module 2, Branch 3
225 – 255ALC 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.

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

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

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 rangeSource
393 – 511Flags (panel variables)
  • 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:

Terminal window
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.