Ryan Malloy f6a09592f1 Live demo: HA in docker discovers + drives mock panel, screenshots captured
dev/screenshot.py — end-to-end automated demo:
  * onboards HA via /api/onboarding (user creation + auth_code flow)
  * subsequent runs log in via /auth/login_flow with saved credentials
  * adds the omni_pca config entry via /api/config/config_entries/flow
  * uses HA's template REST endpoint to discover the panel device_id
  * launches a headless chromium via playwright with prefetched auth tokens
  * captures 6 deep-linked screenshots:
      01-overview.png            — Lovelace
      02-integrations-list.png   — HAI/Leviton sitting next to HA's built-ins
      03-omni-pca-config.png     — '1 device · 38 entities', custom integration
      04-panel-device.png        — Omni Pro II device page with full controls
      05-entities-omni.png       — config_entry filtered entities table
      06-developer-states.png    — alarm_control_panel.omni_pro_ii_main with
                                   raw_mode_name=OFF, code_arm_required=true,
                                   etc. proving real entity state from mock

dev/docker-compose.yml — mock-panel command rewritten:
  * Mounts only src/ and run_mock_panel.py (read-only) instead of the full
    project so uv doesn't try to recreate the host's .venv on a RO mount
  * Installs cryptography via uv pip install --system
  * PYTHONPATH set to /tmp/mock/src so omni_pca imports work without a
    package install

dev/artifacts/screenshots/2026-05-10/ — six PNGs from the run.

.gitignore — adds dist/ for build artifacts.

Confirmed end-to-end: HA discovered the integration via mDNS hint
(showed up in the onboarding wizard's compatible-devices step), the
config flow connected to the mock over host.docker.internal:14369,
materialized 38 entities across 8 platforms (alarm_control_panel,
binary_sensor, button, climate, event, light, sensor, switch), and
displayed everything in the device + entity registries with friendly
names and attributes intact. The integration name hash is 38 entities
because the mock seeds 5 zones (binary + bypass) + 4 units + 2 areas +
2 thermostats + 3 buttons + 3 system-level binary sensors + 2 system
sensors + 6 thermostat sensors + 1 event entity = 38 (matches HA UI).
2026-05-10 16:17:33 -06:00
2026-05-10 12:46:26 -06:00

omni-pca

Async Python client for HAI/Leviton Omni-Link II home automation panels — Omni Pro II, Omni IIe, Omni LTe, Lumina.

Includes a Home Assistant custom component (custom_components/omni_pca/).

Status

Alpha. Built from a full reverse-engineering of HAI's PC Access 3.17 (the Windows installer/programmer app). The protocol layer captures two non-public quirks that public Omni-Link clients miss:

  1. Session key is not the ControllerKey. Last 5 bytes are XORed with a controller-supplied SessionID nonce.
  2. Per-block XOR pre-whitening before AES. First two bytes of every 16-byte block are XORed with the packet's sequence number.

See docs/PROTOCOL.md for the full byte-level spec.

Quick start (library)

uv add omni-pca
import asyncio
from omni_pca import OmniClient

async def main():
    async with OmniClient(
        host="192.168.1.9",
        port=4369,
        controller_key=bytes.fromhex("6ba7b4e9b4656de3cd7edd4c650cdb09"),
    ) as panel:
        info = await panel.get_system_info()
        print(info.model_name, info.firmware_version)

asyncio.run(main())

Quick start (Home Assistant)

Copy custom_components/omni_pca/ into your HA config/custom_components/, restart HA, then add the integration via Settings → Devices & Services. You'll need:

  • Panel IP / hostname
  • TCP port (default 4369)
  • ControllerKey as 32 hex chars

Get the ControllerKey from your .pca file using the included parser:

uvx --from omni-pca omni-pca decode-pca path/to/Your.pca --field controller_key

The integration creates one HA device per panel plus typed entities for every named object on the controller: alarm_control_panel for areas, light for units, binary_sensor/switch for zones (state + bypass), climate for thermostats, sensor for analog zones and panel telemetry, button for panel macros, and event for the typed push-notification stream. See custom_components/omni_pca/README.md for the entity table and service list.

Without a panel — mock controller

For testing, the library ships a minimal Omni controller emulator:

from omni_pca.mock_panel import MockPanel

async with MockPanel(controller_key=...).serve(port=14369):
    # connect a real OmniClient to localhost:14369 — works end-to-end
    ...

Versioning

Date-based (CalVer): YYYY.M.D. Bumped on backwards-incompatible changes.

Acknowledgments

This client is independent and not affiliated with Leviton or HAI. Protocol details derived from clean-room analysis of the publicly-distributed PC Access installer.

Description
Async Python library and Home Assistant integration for HAI/Leviton Omni Pro II / Omni IIe / Omni LTe / Lumina panels. Reverse-engineered from PC Access 3.17.
Readme MIT 1.4 MiB
2026-05-10 23:49:48 +00:00
Languages
Python 99.8%
Makefile 0.2%