From f7be0f7b184b63f661657f9b705ac816215080a0 Mon Sep 17 00:00:00 2001 From: Ryan Malloy Date: Sun, 10 May 2026 18:18:44 -0600 Subject: [PATCH] Homepage redesign: lead with the HA integration, then the library MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous homepage opened with prose ('What it is') and listed three generic 'where to start' cards. New version is more concrete: - Hero block with three call-to-action buttons (Add to HA, Decode .pca, Source on Gitea) using Starlight's hero frontmatter - '## In Home Assistant' section opens with what users actually get, followed by a 2x2 grid of clickable HA screenshots (integrations list, integration page, device controls, dev-tools states) — each thumbnail links to the relevant detail page with a short caption - '## In Python' section: 15-line OmniClient + events() example so the library shape is immediately legible, plus four bullets highlighting opcode coverage / typed dataclasses / mock controller / async-first - '## Two non-public protocol quirks' kept verbatim — still the headline RE finding - '## Read the in-depth content' replaces the three generic cards with six specific ones routing to install how-to, dev-stack tutorial, protocol reference, quirks explainer, file format, and journey Build clean, 23 pages. Local container rebuilt + recreated. The new sections render: In Home Assistant, In Python, Two non-public protocol quirks, Read the in-depth content. --- src/content/docs/index.mdx | 148 +++++++++++++++++++++++++++++-------- 1 file changed, 119 insertions(+), 29 deletions(-) diff --git a/src/content/docs/index.mdx b/src/content/docs/index.mdx index 3c2302a..2eafcf5 100644 --- a/src/content/docs/index.mdx +++ b/src/content/docs/index.mdx @@ -2,69 +2,159 @@ title: HAI Omni Pro II — omni-pca description: Reverse-engineered Python library and Home Assistant integration for HAI/Leviton Omni Pro II home automation panels. template: doc +hero: + tagline: | + Async Python library and a drop-in Home Assistant integration for the + HAI/Leviton Omni-Link II protocol — clean-room reverse-engineered from + PC Access 3.17, complete with two non-public crypto quirks no other + public client implements. + actions: + - text: Add to Home Assistant + link: /how-to/install-in-home-assistant/ + icon: right-arrow + variant: primary + - text: Decode your .pca file + link: /tutorials/decrypt-your-pca/ + icon: external + variant: secondary + - text: Source on Gitea + link: https://git.supported.systems/warehack.ing/omni-pca + icon: external + variant: minimal --- import { Card, CardGrid, LinkCard } from '@astrojs/starlight/components'; import { Image } from 'astro:assets'; + import wordmark from '../../assets/manual/omnipro-ii-wordmark.png'; +import shotIntegrations from '../../assets/screenshots/02-integrations-list.png'; +import shotConfig from '../../assets/screenshots/03-omni-pca-config.png'; +import shotDevice from '../../assets/screenshots/04-panel-device.png'; +import shotStates from '../../assets/screenshots/06-developer-states.png'; OmniPro II Automation -## What it is +## In Home Assistant -`omni-pca` is an async Python library and a matching Home Assistant custom -component for HAI / Leviton **Omni Pro II**, **Omni IIe**, **Omni LTe**, and -**Lumina** panels. It speaks Omni-Link II straight to the controller over TCP, -opens an encrypted session, and surfaces the panel's typed object model — zones, -units, areas, thermostats, buttons, programs, codes, messages — plus the -unsolicited push-event stream the panel emits on state changes. +One device per panel. Typed entities for every named object the controller +knows about — alarm areas, lights and outputs, binary zones with bypass, +thermostats with HVAC modes, programs and panel-button macros, plus a +single `event` entity that relays the panel's typed push-event stream +into HA automations. Push updates arrive within one TCP round-trip; a +30-second poll backstops anything that didn't push. -The protocol layer was built from a clean-room decompilation of HAI's PC Access -3.17. Every opcode, byte layout, and crypto step is cited back to the source -line in the decompiled C# (`clsOmniLinkConnection.cs`, `clsHAC.cs`, etc.). +
+ + HA Devices and Services dashboard with HAI/Leviton Omni Panel listed alongside built-in integrations +
Discoverable in the integrations list →
+
+ + omni_pca integration page showing Custom integration, version 2026.5.10, 1 device with 38 entities +
Entity catalogue · 8 platforms →
+
+ + Omni Pro II device page in HA with lights, areas, thermostats, and panel buttons all live +
Per-device controls grid →
+
+ + HA Developer Tools showing alarm_control_panel.omni_pro_ii_main with full attribute payload +
Real entity state from the panel →
+
+
+ +## In Python + +The library underneath is intentionally async-first and typed end-to-end: + +```python +import asyncio +from omni_pca import OmniClient + +async def main() -> None: + async with OmniClient( + host="192.168.1.9", + port=4369, + controller_key=bytes.fromhex("6ba7b4e9b4656de3cd7edd4c650cdb09"), + ) as panel: + info = await panel.get_system_information() + print(info.model_name, info.firmware_version) + + async for event in panel.events(): + print(event) # ZoneStateChanged, ArmingChanged, AlarmActivated, … + +asyncio.run(main()) +``` + +What you get from the library: + +- **Full opcode coverage** — 104 v1 + 83 v2 message types, byte-exact to the + decompiled C# enums. +- **21 typed status/properties dataclasses**, 26 typed `SystemEvent` + subclasses, no untyped bytes leaking past the framing layer. +- **Stateful mock controller** for offline development. The same `MockPanel` + class powers the integration tests and the docker dev stack. +- **Async-first** — `OmniClient` is an async context manager, `events()` is + an async iterator, no callback soup. ## Two non-public protocol quirks The wire protocol — as actually implemented in PC Access 3.17 — has two -non-public quirks that public Omni-Link clients miss. Without them the panel -will accept your TCP connection, complete the unencrypted handshake, and then +quirks that public Omni-Link clients miss. Without them the panel will +accept your TCP connection, complete the unencrypted handshake, and then silently drop you on the first encrypted message: 1. **Session key XOR mix.** The AES-128 session key is *not* the panel's - `ControllerKey` directly. Bytes `[11..16)` of the ControllerKey are XORed - with a 5-byte `SessionID` nonce that the controller sends in - `ControllerAckNewSession`. Bytes `[0..11)` are the ControllerKey verbatim. -2. **Per-block XOR pre-whitening before AES.** Before each 16-byte block is - AES-encrypted, its first two bytes are XORed with the packet's 16-bit - sequence number (high byte first). The same mask is applied to *every* - block of the packet. Decrypt reverses it. + `ControllerKey` directly. Bytes `[11..16)` of the ControllerKey are + XORed with a 5-byte `SessionID` nonce that the controller sends in + `ControllerAckNewSession`. Bytes `[0..11)` are the ControllerKey + verbatim. +2. **Per-block XOR pre-whitening before AES.** Before each 16-byte block + is AES-encrypted, its first two bytes are XORed with the packet's + 16-bit sequence number (high byte first). The same mask is applied + to *every* block of the packet. Decrypt reverses it. Both are unambiguous in the decompiled C# (`clsOmniLinkConnection.cs:1886-1892` and `:396-401`). Neither appears in `jomnilinkII`, `pyomnilink`, or any -third-party Omni-Link writeup we found. See [the quirks -explainer](/explanation/quirks/) for the full story. +third-party Omni-Link writeup we found. See +[the quirks explainer](/explanation/quirks/) for why they exist and the +full visual breakdown. -## Where to start +## Read the in-depth content + + +