Sprinkle pca-re/docs/manuals/ citations into the four files that map hardest to user-visible panel behavior, so a reader chasing "why is this byte 0x03 here" lands on the right manual chapter directly from the source. models.SecurityMode Per-value comments summarising what each arming mode means at the keypad (entry/exit delays, which zones it arms, when to use it). Points at the Owner's Manual SECURITY_SYSTEM_OPERATION chapter where these semantics are spelled out for end users. models.ZoneType Class docstring now points at the Installation Manual SETUP ZONES table where each numeric byte value is named -- the byte values and short names we chose match that table one-for-one, so a reader can cross-walk the v1 ZoneStatus byte to "PERIMETER" / "AWAY INT" / etc. by row. events.py Module docstring adds Cross-references to APPENDIX A (Contact ID reporting format) and APPENDIX B (digital communicator code sheet) in the Installation Manual -- the central-station codes a panel transmits for each AlarmKind correspond directly to those tables. commands.py Module docstring points at the Owner's Manual CONTROL, Scene Commands, and SECURITY SYSTEM OPERATION chapters so the reader can tie each enuUnitCommand byte to the user-facing keypad path that triggers it. No code changes; all 387 tests still pass.
225 lines
11 KiB
Python
225 lines
11 KiB
Python
"""Command (opcode 20) and ExecuteSecurityCommand (opcode 74) primitives.
|
|
|
|
This module pins down the exact byte values the panel expects in the
|
|
*first byte* of a Command (opcode 20) payload, plus the failure-mode
|
|
exception used by the typed methods on :class:`omni_pca.client.OmniClient`.
|
|
|
|
Naming note: there is no standalone ``enuCommand`` enum in HAI_Shared —
|
|
the C# code uses :class:`enuUnitCommand` (file
|
|
``decompiled/project/HAI_Shared/enuUnitCommand.cs``) for *every* Command
|
|
opcode regardless of object type, even though the name suggests it's
|
|
unit-only. We mirror that single enum here under the cleaner name
|
|
:class:`Command`. Every member cites the line in ``enuUnitCommand.cs``
|
|
where its byte value is defined.
|
|
|
|
The rich Command (opcode 20) wire format (from
|
|
``clsOL2MsgCommand.cs:5-57``) is:
|
|
|
|
payload[0] = command byte (this enum)
|
|
payload[1] = parameter1 (single byte, e.g. brightness, mode value)
|
|
payload[2] = parameter2 high byte (BE u16)
|
|
payload[3] = parameter2 low byte
|
|
|
|
Parameter2 is almost always the **object number** (unit#, zone#,
|
|
thermostat#, message#, button#, scene#). Parameter1 carries whatever the
|
|
specific command needs (level, mode, set-point, etc.) — see the per-
|
|
member doc-comments below for the mapping.
|
|
|
|
The ExecuteSecurityCommand (opcode 74) wire format (from
|
|
``clsOL2MsgExecuteSecurityCommand.cs:5-90``) is:
|
|
|
|
payload[0] = area number (1-based)
|
|
payload[1] = security mode byte (enuSecurityMode, raw 0-7)
|
|
payload[2] = code digit 1 (thousands place, 0-9)
|
|
payload[3] = code digit 2 (hundreds place, 0-9)
|
|
payload[4] = code digit 3 (tens place, 0-9)
|
|
payload[5] = code digit 4 (ones place, 0-9)
|
|
|
|
The reply (ExecuteSecurityCommandResponse, opcode 75) carries a single
|
|
status byte at ``payload[0]`` whose values are listed in
|
|
``enuSecurityCommnadResponse.cs`` — :class:`SecurityCommandResponse`
|
|
mirrors that enum.
|
|
|
|
Cross-references (HAI OmniPro II Owner's Manual):
|
|
Chapter "CONTROL" (pca-re/docs/owner_manual/05_CONTROL/) documents
|
|
the user-facing keypad keys that map to these commands —
|
|
e.g. UNIT_ON/OFF + UNIT_LEVEL are what a homeowner triggers via
|
|
the "Control → 1 (Unit)" menu, SHOW_MESSAGE_WITH_BEEP is
|
|
invoked from "Control → Message → Show".
|
|
Chapter "Scene Commands" (06_Scene_Commands/) covers
|
|
COMPOSE_SCENE and the per-room scene-recall path.
|
|
Chapter "SECURITY SYSTEM OPERATION" (03_SECURITY_SYSTEM_OPERATION/)
|
|
documents what each SecurityMode byte (0-6) means at the user
|
|
level — the arming menu, entry/exit-delay semantics, and which
|
|
zones each mode arms.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from enum import IntEnum
|
|
|
|
from .connection import ProtocolError
|
|
|
|
|
|
class Command(IntEnum):
|
|
"""OMNI command codes used as ``payload[0]`` of a Command (opcode 20).
|
|
|
|
Every member's value is sourced from
|
|
``decompiled/project/HAI_Shared/enuUnitCommand.cs``; the trailing
|
|
line-number reference points to the exact definition.
|
|
"""
|
|
|
|
# ---- unit / lighting ------------------------------------------------
|
|
UNIT_OFF = 0 # enuUnitCommand.Off, line 5
|
|
UNIT_ON = 1 # enuUnitCommand.On, line 6
|
|
ALL_OFF = 2 # enuUnitCommand.AllOff, line 7 (alias: All=2 line 8)
|
|
ALL_ON = 3 # enuUnitCommand.AllOn, line 9
|
|
BYPASS_ZONE = 4 # enuUnitCommand.Bypass, line 10
|
|
RESTORE_ZONE = 5 # enuUnitCommand.Restore, line 11
|
|
RESTORE_ALL_ZONES = 6 # enuUnitCommand.RestoreAll, line 12
|
|
EXECUTE_BUTTON = 7 # enuUnitCommand.Button, line 13
|
|
ENERGY = 8 # enuUnitCommand.Energy, line 14
|
|
UNIT_LEVEL = 9 # enuUnitCommand.Level, line 15 (param1 = 0..100 %)
|
|
UNIT_DECREMENT_COUNTER = 10 # enuUnitCommand.Dec, line 16
|
|
UNIT_INCREMENT_COUNTER = 11 # enuUnitCommand.Inc, line 17
|
|
UNIT_SET_COUNTER = 12 # enuUnitCommand.Set, line 18
|
|
UNIT_RAMP = 13 # enuUnitCommand.Ramp, line 19
|
|
COMPOSE_SCENE = 14 # enuUnitCommand.Compose, line 20
|
|
UPB_STATUS_REQUEST = 15 # enuUnitCommand.UPBStatus, line 21
|
|
DIM_STEP = 16 # enuUnitCommand.Dim, line 22 (param1 = step)
|
|
DIM_1 = 17 # enuUnitCommand.Dim1, line 23
|
|
DIM_2 = 18 # enuUnitCommand.Dim2, line 24
|
|
DIM_3 = 19 # enuUnitCommand.Dim3, line 25
|
|
DIM_4 = 20 # enuUnitCommand.Dim4, line 26
|
|
DIM_5 = 21 # enuUnitCommand.Dim5, line 27
|
|
DIM_6 = 22 # enuUnitCommand.Dim6, line 28
|
|
DIM_7 = 23 # enuUnitCommand.Dim7, line 29
|
|
DIM_8 = 24 # enuUnitCommand.Dim8, line 30
|
|
DIM_9 = 25 # enuUnitCommand.Dim9, line 31
|
|
UPB_BLINK = 26 # enuUnitCommand.UPBBlink, line 32
|
|
UPB_BLINK_OFF = 27 # enuUnitCommand.UPBBlinkOff, line 33
|
|
UPB_LINK_OFF = 28 # enuUnitCommand.UPBLinkOff, line 34
|
|
UPB_LINK_ON = 29 # enuUnitCommand.UPBLinkOn, line 35
|
|
UPB_LINK_SET = 30 # enuUnitCommand.UPBLinkSet, line 36
|
|
UPB_LINK_FADE_STOP = 31 # enuUnitCommand.UPBLinkFadeStop, line 37
|
|
BRIGHT_STEP = 32 # enuUnitCommand.Bright, line 38 (param1 = step)
|
|
BRIGHT_1 = 33 # enuUnitCommand.Bright1, line 39
|
|
BRIGHT_2 = 34 # enuUnitCommand.Bright2, line 40
|
|
BRIGHT_3 = 35 # enuUnitCommand.Bright3, line 41
|
|
BRIGHT_4 = 36 # enuUnitCommand.Bright4, line 42
|
|
BRIGHT_5 = 37 # enuUnitCommand.Bright5, line 43
|
|
BRIGHT_6 = 38 # enuUnitCommand.Bright6, line 44
|
|
BRIGHT_7 = 39 # enuUnitCommand.Bright7, line 45
|
|
BRIGHT_8 = 40 # enuUnitCommand.Bright8, line 46
|
|
BRIGHT_9 = 41 # enuUnitCommand.Bright9, line 47
|
|
CENTRALITE_SCENE_OFF = 42 # enuUnitCommand.CentraLiteSceneOff, line 48
|
|
CENTRALITE_SCENE_ON = 43 # enuUnitCommand.CentraLiteSceneOn, line 49
|
|
UPB_LED_OFF = 44 # enuUnitCommand.UPBLEDOff, line 50
|
|
UPB_LED_ON = 45 # enuUnitCommand.UPBLEDOn, line 51
|
|
RADIO_RA_PHANTOM_OFF = 46 # enuUnitCommand.RadioRAPhantomOff, line 52
|
|
RADIO_RA_PHANTOM_ON = 47 # enuUnitCommand.RadioRAPhantomOn, line 53
|
|
|
|
# ---- security (alternative path; preferred path is opcode 74) ------
|
|
# When sent through a Command (opcode 20), parameter1 carries the user
|
|
# code index (1-based) and parameter2 carries the area number. The
|
|
# panel honours these only if the code is enabled for the area.
|
|
SECURITY_OFF = 48 # enuUnitCommand.SecurityOff, line 55 (alias Security=48 line 54)
|
|
SECURITY_DAY = 49 # enuUnitCommand.SecurityDay, line 56
|
|
SECURITY_NIGHT = 50 # enuUnitCommand.SecurityNight, line 57
|
|
SECURITY_AWAY = 51 # enuUnitCommand.SecurityAway, line 58
|
|
SECURITY_VACATION = 52 # enuUnitCommand.SecurityVac, line 59
|
|
SECURITY_DAY_INSTANT = 53 # enuUnitCommand.SecurityDyi, line 60
|
|
SECURITY_NIGHT_DELAYED = 54 # enuUnitCommand.SecurityNtd, line 61
|
|
SECURITY_ANY_CHANGE = 55 # enuUnitCommand.SecurityAny, line 62
|
|
SECURITY_ARMING_DAY = 57 # enuUnitCommand.SecurityArmingDay, line 63
|
|
SECURITY_ARMING_NIGHT = 58 # enuUnitCommand.SecurityArmingNight, line 64
|
|
SECURITY_ARMING_AWAY = 59 # enuUnitCommand.SecurityArmingAway, line 65
|
|
SECURITY_ARMING_VACATION = 60 # enuUnitCommand.SecurityArmingVacation, line 66
|
|
SECURITY_ARMING_DAY_INSTANT = 61 # enuUnitCommand.SecurityArmingDayInst, line 67
|
|
SECURITY_ARMING_NIGHT_DELAYED = 62 # enuUnitCommand.SecurityArmingNightDelay, line 68
|
|
|
|
# ---- energy (HMS) --------------------------------------------------
|
|
ENERGY_OFF = 64 # enuUnitCommand.Eof, line 69
|
|
ENERGY_ON = 65 # enuUnitCommand.Eon, line 70
|
|
|
|
# ---- thermostat ---------------------------------------------------
|
|
SET_THERMOSTAT_HEAT_SETPOINT = 66 # enuUnitCommand.SetLowSetPt, line 71
|
|
SET_THERMOSTAT_COOL_SETPOINT = 67 # enuUnitCommand.SetHighSetPt, line 72
|
|
SET_THERMOSTAT_SYSTEM_MODE = 68 # enuUnitCommand.Mode, line 73
|
|
SET_THERMOSTAT_FAN_MODE = 69 # enuUnitCommand.Fan, line 74
|
|
SET_THERMOSTAT_HOLD_MODE = 70 # enuUnitCommand.Hold, line 75
|
|
THERMOSTAT_INC_DEC_LO = 71 # enuUnitCommand.IncDecLo, line 76
|
|
THERMOSTAT_INC_DEC_HI = 72 # enuUnitCommand.IncDecHi, line 77
|
|
SET_THERMOSTAT_HUMIDIFY_SETPOINT = 73 # enuUnitCommand.SetHumidifySetPt, line 78
|
|
SET_THERMOSTAT_DEHUMIDIFY_SETPOINT = 74 # enuUnitCommand.SetDeHumidifySetPt, line 79
|
|
|
|
# ---- panel display messages ---------------------------------------
|
|
SHOW_MESSAGE_WITH_BEEP = 80 # enuUnitCommand.ShowMsgWBeep, line 81 (alias FirstMsgCmd=80 line 80)
|
|
LOG_MESSAGE = 81 # enuUnitCommand.LogMsg, line 82
|
|
CLEAR_MESSAGE = 82 # enuUnitCommand.ClearMsg, line 83
|
|
SAY_MESSAGE = 83 # enuUnitCommand.SayMsg, line 84
|
|
PHONE_MESSAGE = 84 # enuUnitCommand.PhoneMsg, line 85
|
|
SEND_MESSAGE = 85 # enuUnitCommand.SendMsg, line 86
|
|
SHOW_MESSAGE_NO_BEEP = 86 # enuUnitCommand.ShowMsgNoBeep, line 87
|
|
EMAIL_MESSAGE = 87 # enuUnitCommand.EMailMsg, line 88 (alias LastMsgCmd=87 line 89)
|
|
|
|
# ---- scenes / misc -----------------------------------------------
|
|
SCENE_OFF = 96 # enuUnitCommand.SceneOff, line 90
|
|
SCENE_ON = 97 # enuUnitCommand.SceneOn, line 91
|
|
SCENE_SET = 98 # enuUnitCommand.SceneSet, line 92
|
|
TOGGLE = 99 # enuUnitCommand.Toggle, line 93
|
|
SHOW_VIDEO = 100 # enuUnitCommand.ShowVideo, line 94
|
|
TIMED_LEVEL = 101 # enuUnitCommand.TimedLevel, line 95
|
|
CONSOLE_BEEP = 102 # enuUnitCommand.ConsoleBeep, line 96
|
|
BEEP = 103 # enuUnitCommand.Beep, line 97
|
|
EXECUTE_PROGRAM = 104 # enuUnitCommand.UserSetting, line 98
|
|
LOCK = 105 # enuUnitCommand.Lock, line 99
|
|
UNLOCK = 106 # enuUnitCommand.Unlock, line 100
|
|
LUTRON_HOMEWORKS_KEYPAD = 107 # enuUnitCommand.LutronHomeWorksKeypadButtonPress, line 101
|
|
CLIPSAL_C_BUS_SCENE = 108 # enuUnitCommand.Clipsal_C_Bus_Scene, line 102
|
|
RADIO_RA2_PHANTOM = 109 # enuUnitCommand.RadioRA2Phantom, line 103
|
|
STOP = 110 # enuUnitCommand.Stop, line 104
|
|
|
|
# ---- audio --------------------------------------------------------
|
|
AUDIO_ZONE = 112 # enuUnitCommand.AudioZone, line 105
|
|
AUDIO_VOLUME = 113 # enuUnitCommand.AudioVolume, line 106
|
|
AUDIO_SOURCE = 114 # enuUnitCommand.AudioSource, line 107
|
|
AUDIO_KEY_PRESS = 115 # enuUnitCommand.AudioKeyPress, line 108
|
|
|
|
|
|
class SecurityCommandResponse(IntEnum):
|
|
"""Status byte returned in an ExecuteSecurityCommandResponse (opcode 75).
|
|
|
|
Source: ``decompiled/project/HAI_Shared/enuSecurityCommnadResponse.cs``
|
|
(typo in the C# enum name preserved here for grep parity).
|
|
"""
|
|
|
|
SUCCESS = 0 # line 5
|
|
INVALID_CODE = 1 # line 6
|
|
INVALID_SECURITY_MODE = 2 # line 7
|
|
INVALID_AREA = 3 # line 8
|
|
ZONES_NOT_READY = 4 # line 9
|
|
INSTALLER_RESTORE_NEEDED = 5 # line 10
|
|
CODE_LOCKED_OUT = 6 # line 11
|
|
INVALID = 0xFF # line 12
|
|
|
|
|
|
class CommandFailedError(ProtocolError):
|
|
"""A command opcode was Nak'd by the panel, or returned a structured
|
|
failure code (e.g. the Security command response carries one of the
|
|
:class:`SecurityCommandResponse` values).
|
|
|
|
The ``failure_code`` attribute is set when the panel returned an
|
|
ExecuteSecurityCommandResponse with a non-zero status byte; it's
|
|
``None`` for plain Nak replies that carry no further detail.
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
message: str,
|
|
*,
|
|
failure_code: int | None = None,
|
|
) -> None:
|
|
super().__init__(message)
|
|
self.failure_code = failure_code
|