--- title: Home Assistant entity catalogue description: One device per panel plus typed entities for every named object — alarm panels, lights, binary sensors, climates, sensors, buttons, switches, and a typed event relay. --- The integration creates one HA device per Omni panel. Every named object on the controller (zones, units, areas, thermostats, buttons) is materialised as one or more typed entities below. Discovery happens once at first 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. | Platform | Entity | Per | |---|---|---| | `alarm_control_panel` | Area arm/disarm with code | discovered area | | `binary_sensor` | Zone open/tripped | binary zone | | `binary_sensor` | Zone bypassed (diagnostic) | binary zone | | `binary_sensor` | AC power, backup battery, system trouble | panel | | `button` | Panel button macro | discovered button | | `climate` | Thermostat (heat/cool/auto, fan, hold) | discovered thermostat | | `event` | Typed push event relay | panel | | `light` | Unit on/off + brightness | discovered unit | | `sensor` | Analog zone (temp/humidity/power) | analog zone | | `sensor` | Thermostat current temp / humidity / outdoor temp | thermostat | | `sensor` | Panel model + firmware, last event class | panel | | `switch` | Zone bypass toggle | binary zone | ## `alarm_control_panel` One per discovered area (`OmniAreaAlarmPanel`). Surfaces the area's current `SecurityMode` translated into HA's `AlarmControlPanelState` enum: - `OFF` → `disarmed` - `DAY` → `armed_home` - `NIGHT` → `armed_night` - `AWAY` → `armed_away` - `VACATION` → `armed_vacation` - `DAY_INSTANT` → `armed_custom_bypass` - `ARMING_*` (security modes 9..14) → `arming` - entry-timer running → `pending` - `alarms != 0` → `triggered` Supported features: `ARM_HOME`, `ARM_NIGHT`, `ARM_AWAY`, `ARM_VACATION`, `ARM_CUSTOM_BYPASS`. Code validation is enforced server-side: the user's PIN is sent through `ExecuteSecurityCommand` (opcode 74). Wrong code raises an HA `ServiceValidationError`. Attributes: `area_index`, `mode_name`, `entry_timer_secs`, `exit_timer_secs`, `alarm_active`, `alarm_bitfield`. ## `binary_sensor` Three flavours. **Per binary zone — open/tripped (`OmniZoneBinarySensor`).** `device_class` is derived from the zone's `ZoneType`: | ZoneType | HA `BinarySensorDeviceClass` | |----------|------------------------------| | ENTRY_EXIT, PERIMETER, NIGHT_INTERIOR, AWAY_INTERIOR, *_DELAY, LATCHING_* | `door` / `window` (opening) | | FIRE, FIRE_EMERGENCY, FIRE_TAMPER | `smoke` | | GAS | `gas` | | WATER | `moisture` | | FREEZE | `cold` | | TAMPER, LATCHING_TAMPER | `tamper` | | TROUBLE | `problem` | | temperature/humidity types | (handled by `sensor` instead) | State: `on` when the zone is open / not-secure / tripped. Attributes: `zone_index`, `zone_type`, `area`, `current_state`, `latched_state`, `arming_state`, `is_in_alarm`, `is_trouble`. **Per binary zone — bypass diagnostic (`OmniZoneBypassBinarySensor`).** `entity_category = DIAGNOSTIC`, on iff the zone is currently bypassed (user or auto-bypass). **Per panel — system trouble triplet.** Three diagnostic sensors per panel: - `binary_sensor.{name}_ac_power` — on iff AC is OK (inverted from `AcLost`) - `binary_sensor.{name}_backup_battery` — on iff battery OK - `binary_sensor.{name}_system_trouble` — on iff any current trouble These mirror the typed events `AcLost`/`AcRestored`, `BatteryLow`/ `BatteryRestored`, and `DcmTrouble`/`DcmOk`. ## `button` One `OmniButton` per discovered panel button macro. Pressing the HA button dispatches a `Command.EXECUTE_BUTTON` (parameter2 = button index). No state. This is the only entity for "scenes" — Omni "scenes" are user-named button macros, so adding a parallel `scene` platform would just double-count. ## `climate` One `OmniClimate` per discovered thermostat. Maps the panel's `HvacMode` + `FanMode` + `HoldMode` triple onto HA's `HVACMode`, fan modes, and preset modes. Setpoints are translated through the `omni_temp_to_*` helpers so HA can display whatever unit the user prefers. Supported features: `TARGET_TEMPERATURE` (single setpoint), or `TARGET_TEMPERATURE_RANGE` when in `HEAT_COOL`/auto mode. Fan: `auto`, `on`, `cycle`. Preset: `none`, `hold`, `vacation`. Attributes: `thermostat_index`, `humidity_percent`, `outdoor_temperature_*`, `humidify_setpoint_raw`, `dehumidify_setpoint_raw`, `horc_status` (1=heating active, 2=cooling active). ## `event` One `OmniPanelEvent` per panel. Surfaces the typed push-event stream as a single HA `event` entity with `event_types`: ```text zone_state_changed unit_state_changed arming_changed alarm_activated alarm_cleared ac_lost ac_restored battery_low battery_restored user_macro_button phone_line_dead phone_line_restored ``` Plus an `unknown` catch-all for the 14 less-common SystemEvent subclasses. Each event carries the originating dataclass's fields in `event_data` (zone index, area, alarm type, etc.), plus a `raw_word` for debugging. Automations key on `platform: state` filtered by `attributes.event_type`. See [HA services → automation example](/reference/ha-services/) for a worked snippet. ## `light` One `OmniLight` per discovered unit. Dimmer state is a single byte that encodes a lot: | State byte | Meaning | |------------|---------| | 0 | Off | | 1 | On (relay; no level info — exposed as 100% brightness) | | 2..13 | Scene A..L (state - 63 → ASCII) | | 17..25 | Dim 1..9 (state - 16) | | 26 | Blink | | 33..41 | Brighten 1..9 (state - 32) | | 100..200 | Brightness 0..100% (state - 100) | Non-dimmable relays silently ignore brightness. Conversion is done in pure helpers (`omni_state_to_ha_brightness`, `ha_brightness_to_omni_percent`) unit-tested without HA in the venv. Attributes: `unit_index`, `time_remaining_secs` (panel-side timer for auto-off; 0 = indefinite). ## `sensor` Three flavours. **Per analog zone.** Zones with `ZoneType` in {TEMPERATURE, OUTDOOR_TEMP, HUMIDITY, TEMP_ALARM, ENERGY_SAVER, FREEZE} get a `sensor` entity instead of (or in addition to) a binary sensor. Unit is inferred from the zone type — temperature in `°F`/`°C`, humidity as `%`, power-related as `W`. **Per thermostat.** Three sub-sensors per thermostat: - `sensor.{name}_temperature` — current measured temp - `sensor.{name}_humidity` — humidity percent - `sensor.{name}_outdoor_temperature` — outdoor temp (if reported) **Per panel.** Two info sensors: - `sensor.{name}_panel_model` — model name + firmware version (state) - `sensor.{name}_last_event` — class name of the most recent SystemEvent (`ZoneStateChanged`, `ArmingChanged`, etc.) with the raw word as an attribute ## `switch` One `OmniZoneBypassSwitch` per binary zone, `entity_category = CONFIG`. Toggling the switch dispatches `Command.BYPASS_ZONE` / `Command.RESTORE_ZONE`. State mirrors the bypass diagnostic binary sensor above. ## What gets discovered Only objects with a name set on the panel are discovered — that's the panel's own definition of "this slot is in use". To populate names, use PC Access's "Names" page (or any other Omni programmer). On a fresh factory-default panel you'll see zero entities; configure object names first, then reload the integration. ## Where to look in source | Class | File | |-------|------| | `OmniAreaAlarmPanel` | `custom_components/omni_pca/alarm_control_panel.py` | | `OmniZoneBinarySensor`, `OmniZoneBypassBinarySensor` | `binary_sensor.py` | | `OmniButton` | `button.py` | | `OmniClimate` | `climate.py` | | `OmniPanelEvent` | `event.py` | | `OmniLight` | `light.py` | | sensor classes | `sensor.py` | | `OmniZoneBypassSwitch` | `switch.py` | All of them sit on top of `OmniDataUpdateCoordinator` (`coordinator.py`), which keeps a long-lived `OmniClient`, runs one-time discovery on first refresh, and patches state in-place from the typed event stream.