OmniClientV1Adapter (src/omni_pca/v1/adapter.py)
V2-shape facade over OmniClientV1. Exposes the OmniClient surface the
HA coordinator was written against — get_system_information,
list_*_names, get_object_properties (synthesized from streamed names),
get_extended_status (chunked, routed to v1 typed status opcodes),
get_object_status(AREA, ...) (derived from SystemStatus.area_alarms),
events() (EventStream on v1 SystemEvents opcode 35), plus all the
write-method shims.
Chunks unit/zone/thermostat/aux polls per-type because firmware 2.12
NAKs Request*Status with >~62 records in one shot (verified live).
Falls back to "Area 1".."Area 8" when the UploadNames stream returns
zero areas — common on panels where the installer didn't name them.
custom_components/omni_pca/coordinator.py
_ensure_connected picks OmniClientV1Adapter for transport=udp. New
_walk_properties_v1 replaces the v2 RequestProperties walk with a
name-stream + synthesized-Properties pass.
custom_components/omni_pca/config_flow.py
_probe routes to OmniClientV1Adapter for transport=udp instead of
trying to drive v2 OmniClient over UDP (which silently dropped after
handshake, per the earlier diagnosis).
src/omni_pca/events.py
parse_events / _ensure_system_events / EventStream now take an
expected_opcode arg (default v2 SystemEvents=55, v1 callers pass 35).
Word format is byte-identical between v1 and v2, so the typed-event
decoder is unchanged.
src/omni_pca/v1/client.py
_range_status supports the long-form RequestUnitStatus (BE u16
start/end) so panels with unit indices > 255 (sprinklers, flags) work.
Verified end-to-end against firmware 2.12 panel at 192.168.1.9:
config entries:
state=loaded Omni Pro II (host.docker.internal) (mock)
state=loaded Omni Pro II (192.168.1.9) (real, v1+UDP)
real-panel entities created in HA: 96 (30 binary_sensor, 26 light,
15 switch, 13 button, 9 sensor, 3 climate)
cross-check: light.omni_pro_ii_front_porch_2 = on (matches live
probe: unit #2 'FRONT PORCH' state=0x01 brightness=100)
dev/probe_v1_coordinator.py
Coordinator-shaped end-to-end smoke test against the real panel
without HA — drives the full discovery + poll cycle through the
adapter. Useful for regression-checking the v1 wire path.
dev/add_real_panel.py
Programmatically adds the real-panel config entry to the dev HA
stack via the REST config-flow endpoints. Idempotent.
53 lines
1.5 KiB
Python
53 lines
1.5 KiB
Python
"""V1 (legacy) Omni-Link protocol over UDP.
|
|
|
|
The v2 path in :mod:`omni_pca` (TCP, OmniLink2Message, StartChar 0x21,
|
|
parameterised RequestProperties / RequestExtendedStatus) is what most
|
|
modern firmware speaks. This subpackage exists because some panels are
|
|
configured at the network module to listen on **UDP only**, in which case
|
|
PC Access falls back to the v1 wire protocol (typed RequestZoneStatus,
|
|
RequestUnitStatus, etc., StartChar 0x5A, OmniLinkMessage outer = 0x10).
|
|
|
|
Reference: clsOmniLinkConnection.cs:353-360 (ConnectionProtocol() returns
|
|
V1 for Modem/UDP/Serial, V2 only for TCP).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from .adapter import OmniClientV1Adapter
|
|
from .client import OmniClientV1, OmniNakError, OmniProtocolError
|
|
from .connection import (
|
|
HandshakeError,
|
|
InvalidEncryptionKeyError,
|
|
OmniConnectionV1,
|
|
RequestTimeoutError,
|
|
)
|
|
from .messages import (
|
|
NameRecord,
|
|
NameType,
|
|
parse_v1_aux_status,
|
|
parse_v1_namedata,
|
|
parse_v1_system_status,
|
|
parse_v1_thermostat_status,
|
|
parse_v1_unit_status,
|
|
parse_v1_zone_status,
|
|
)
|
|
|
|
__all__ = [
|
|
"HandshakeError",
|
|
"InvalidEncryptionKeyError",
|
|
"NameRecord",
|
|
"NameType",
|
|
"OmniClientV1",
|
|
"OmniClientV1Adapter",
|
|
"OmniConnectionV1",
|
|
"OmniNakError",
|
|
"OmniProtocolError",
|
|
"RequestTimeoutError",
|
|
"parse_v1_aux_status",
|
|
"parse_v1_namedata",
|
|
"parse_v1_system_status",
|
|
"parse_v1_thermostat_status",
|
|
"parse_v1_unit_status",
|
|
"parse_v1_zone_status",
|
|
]
|