Ryan Malloy 7b4052624c Docs: extend JOURNEY through the HA + harness + demo arc; add CHANGELOG
docs/JOURNEY.md — replaced the placeholder 'What's next' section with
seven new chronological entries covering everything that happened after
the panel-search comedy:

  - HA rebuild Phase A: poll-vs-push decision, pure-function helpers
    extraction, 61 unit tests with no HA imports
  - HA Phase B: the six new entity platforms, the Omni state-byte
    overload, security-mode-to-alarm-state mapping, the scene-platform
    skip decision
  - HA Phase C: services + diagnostics + repairs flow
  - 'wait, did we mock enough?' — catching the missing Thermostat
    (6) and Button (3) RequestProperties handlers BEFORE the HA
    harness ever touched the mock
  - HA test harness rough patches: requires-python conflict, pytest_socket
    fight, the CONF_ENTRY_ID-doesn't-exist-in-HA find, teardown hang
    fixed by converting configured_panel into a generator
  - Docker dev stack: mounting only src/ to dodge the read-only-venv
    problem with uv
  - Automated onboarding + screenshots: the auth_code OAuth dance, the
    template-endpoint device-id trick, playwright auto-injection of
    hassTokens, the discovery-during-onboarding nice surprise

Plus appended five new entries to 'Things worth remembering':
  - Pure functions are the cheapest thing in test suites
  - Mocking the entire protocol counterpart catches whole categories
  - pytest_socket + real network can coexist
  - The 'build without a real device' loop is unreasonably effective
  - (existing entries kept verbatim)

Final length: ~6800 words, 27 dated sections plus the lessons list.

CHANGELOG.md — new file. Single 2026.5.10 entry under Keep-a-Changelog-
ish format, broken into seven sections matching the project layers:
Protocol layer (RE findings), Library, Home Assistant integration,
Tests, Developer tooling, Documentation, Known gaps. Cites the source
line numbers for the two non-public protocol quirks. Lists every
public module + every entity platform. Linked to git tag template at
the bottom (release not pushed yet).

Tests still 351 + 1 skip. No code changed.
2026-05-10 16:29:41 -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%