Migrate from jomnilinkII or pyomnilink
If you’ve been using jomnilinkII
(Java) or pyomnilink
(Python) and want to switch to omni-pca, here’s what changes and why.
What stays the same
Section titled “What stays the same”- Your panel hardware and firmware — no changes needed.
- The ControllerKey —
omni-pcauses the same persistent 32-hex key your existing client uses. Pull it the same way (PC Access UI,.pcafile, keypad). - Network details — same IP, same port (4369 by default).
- The user codes / area mode semantics / zone numbering — these are panel-side, identical across all clients.
What changes
Section titled “What changes”The two non-public protocol quirks
Section titled “The two non-public protocol quirks”This is the headline. Per the quirks explainer, PC Access does two things that no other public Omni-Link client we checked implements:
- Session key XOR mix. The AES-128 key for the session is not
the persistent ControllerKey. It’s
ControllerKey[0:11] || (ControllerKey[11:16] XOR SessionID[0:5]). - Per-block XOR pre-whitening. The first two bytes of every 16-byte AES block are XORed with the packet’s sequence number before encryption.
If your existing client is currently working against your panel, then one of these is true:
- The panel firmware is configured to allow unencrypted sessions
(
ProtocolVersion=V1over a serial-or-modem path), and the existing client is using that path. - Your panel is older firmware that didn’t ship the quirks (we don’t have a confirmed cutoff version, but pre-3.0 likely doesn’t have them).
- The existing client does implement the quirks but didn’t document them in source — possible but we haven’t found one.
omni-pca always uses the quirks, so it works against modern firmware
out of the box. If your panel is older and rejects connections, file
an issue — we can add a protocol_quirks=False option.
API surface
Section titled “API surface”The shape is different. omni-pca is async; the others are sync (or
event-loop-based with a different idiom).
# pyomnilinkfrom omnilink2 import OmniLink2omni = OmniLink2('192.168.1.9', 4369, 'CONTROLLER_KEY_HEX')omni.connect()info = omni.system_information()print(info)omni.close()
# omni-pcaimport asynciofrom omni_pca import OmniClient
async def main(): async with OmniClient(host='192.168.1.9', port=4369, controller_key=bytes.fromhex('CONTROLLER_KEY_HEX')) as panel: info = await panel.get_system_information() print(info)
asyncio.run(main())Method names mostly translate directly:
pyomnilink / jomnilinkII | omni-pca |
|---|---|
system_information() | get_system_information() |
system_status() | get_system_status() |
object_properties(type, idx) | get_object_properties(ObjectType.X, idx) |
extended_status(type, start, end) | get_extended_status(ObjectType.X, start, end) |
command(cmd, p1, p2) | execute_command(Command.X, p1, p2) |
unit_on(idx) | turn_unit_on(idx) |
subscribe_unsolicited(cb) | async for ev in panel.events(): ... |
All omni-pca methods are typed and return parsed dataclasses, not raw
byte tuples.
Event handling
Section titled “Event handling”pyomnilink and jomnilinkII typically use a callback model: register
a function, get raw events. omni-pca exposes events as a typed async
iterator with 26 parsed subclasses:
async for event in panel.events(): match event: case ZoneStateChanged(zone_index=idx, new_state=state): ... case ArmingChanged(area_index=idx, new_mode=mode): ... case AlarmActivated(area_index=idx, alarm_type=kind): ...Subclassing pattern matching catches everything and lets the type checker yell when you handle an event with the wrong field name.
Home Assistant
Section titled “Home Assistant”If you’re using HA, swap the integration:
- Remove the existing Omni integration from Settings → Devices & Services.
- Drop in
custom_components/omni_pca/— see the quickstart. - Add the new integration; entity IDs will change (the new naming
convention is
<platform>.omni_pro_ii_<object_name>).
If you have automations referring to the old entity IDs, search-and- replace; the matching of zones/units/areas to underlying panel objects is otherwise identical.
What you lose
Section titled “What you lose”- Battle-tested years of production use —
omni-pcais fresh code (released 2026-05-10). The protocol layer has 351 unit + integration tests against a faithful mock, but the wider OSS world hasn’t kicked the tyres yet. - Some opcode coverage —
omni-pcav1.0 doesn’t have a path for Programs discovery yet. Most other features are covered.
What you gain
Section titled “What you gain”- Async + typed API — better Python ergonomics, mypy-friendly.
- Two protocol quirks correctly implemented — works against firmware that rejects naive AES-ECB clients.
- Faithful mock panel — develop and test without touching real hardware.
- Modern HA integration — config flow, discovery, push events, diagnostics, services. No YAML configuration.
- Full byte-level documentation — see protocol reference, file format, and the JOURNEY for how it was derived.
Found a bug?
Section titled “Found a bug?”If you’ve migrated and something works in jomnilinkII / pyomnilink
that doesn’t in omni-pca, that’s an opcode we haven’t reverse-
engineered yet (or implemented in a model). Open an issue with:
- Panel model + firmware version
- The specific
pyomnilink/jomnilinkIIcall you were making - Any captured packets if you have them
The protocol decompilation is exhaustive — if PC Access does something, we can implement it.