pyisyox.runtime package¶
Runtime objects that wrap pyisyox.client.LoadResult data.
Node— wraps aNodeRecordplus the resolvedNodeDefplus a back-reference to theIoXClient, with an editor-codec-validatedNode.send_command().EventDispatcherandparse_event_frame()— decode/rest/subscribeevent frames and overlay property updates onto the same node registry.
- class DeviceLinkerAction(*values)[source]¶
Bases:
StrEnumAction codes on
SystemEventControl.DEVICE_LINKER(_20) frames — Cookbook §8.5.22 (udievnts.xsd).- STATUS¶
Linking status update —
<eventInfo>carries device-linker info.
- CLEARED¶
The device-linking list was cleared. No payload.
- class DeviceWriteAction(*values)[source]¶
Bases:
StrEnumDevice-write sub-codes that ride through on
_7(SystemEventControl.PROGRESS) frames — PyISY 3.x surfaced these asNodeChangeAction.DEVICE_WRITING/DEVICE_MEMORY.Unlike the other action enums, these are control-value sub-codes (they have the
_prefix and arrive in the<control>slot), not<action>values — the dispatcher doesn’t route them; they pass through as plain control events.<eventInfo>child tags per code are inDEVICE_WRITE_PROGRESS_EVENT_INFO_TAGS.- PROGRESS¶
Device-writing progress message —
<eventInfo>carries<message>.
- MEMORY¶
Raw Insteon memory write —
<eventInfo>carries<memory>/<cmd1>/<cmd2>/<value>.hacs-udi-iox’s backlight entities subscribe to this to catch memory-write echoes.
- class Event(seqnum, timestamp, control, action, node_address, formatted_action='', formatted_name='', uom='', precision=None, event_info='')[source]¶
Bases:
objectOne parsed event frame.
- Variables:
seqnum (int) – Event sequence number from the eisy. Monotonic per connection; resets on reconnect.
timestamp (str) – ISO 8601 timestamp string from the frame (preserved verbatim — consumer parses if needed).
control (str) – Property id (
"ST","GV1", …) or system code ("_5","_28", …).action (str) – Raw value as reported (string form preserves the controller’s precision representation).
node_address (str) – Wire address of the affected node, or empty string for system events.
formatted_action (str) – Human-readable display value (e.g.
"0.6839 US gallons"). Empty when the controller didn’t supply one (system events typically don’t).formatted_name (str) – Display name of the property (e.g.
"Current"). Empty when not provided.uom (str) – Unit-of-measure id from
<action uom="...">.precision (int | None) – Decimal precision from
<action prec="...">, orNoneif absent. (Wire keys it as"prec"; Python attribute spells it out.)event_info (str) – Inner
<eventInfo>XML preserved verbatim. Empty string when the frame had no<eventInfo>element or when its content was empty. Consumers that need the structured payload (e.g. variable change frames carrying<var type="..." id="...">, or controller logs in CDATA) parse this themselves — the IoX wire schema differs across system control codes and pyisyox stays neutral.
- Parameters:
- class EventDispatcher(nodes, programs=None, variables=None, groups=None)[source]¶
Bases:
objectRoutes parsed
Eventinstances into a node registry + listener callbacks.The dispatcher is intentionally not coupled to the WebSocket transport —
feed()accepts a raw frame and does the parse + route + emit dance. The actual WS read loop lives inpyisyox.runtime.ws; tests can drive the dispatcher directly with synthetic frames.- Parameters:
nodes (dict[str, NodeRecord])
programs (dict[str, ProgramRecord] | None)
variables (dict[str, dict[str, VariableRecord]] | None)
groups (dict[str, GroupRecord] | None)
- update_groups(groups)[source]¶
(Re)build the member→groups reverse index from a group registry.
Called from
__init__and again bypyisyox.controller.Controller.refresh()—refresh()replacesLoadResult.groupswith a fresh dict (unlikenodes, which is mutated in place), so the index has to be rebuilt or scene-membership changes from a reload lifecycle event would be missed (new members never re-emit; removed members still would).- Parameters:
groups (dict[str, GroupRecord])
- Return type:
None
- add_program_status_listener(callback)[source]¶
Register
callbackto fire on every program-status frame (<control>_1</control>action"0").The dispatcher updates the matching
pyisyox.client.ProgramRecordin place before firing, so consumers readingprogram.statusfrom the callback see the new value.- Returns:
An unsubscribe function.
- Parameters:
callback (Callable[[ProgramStatusEvent], None])
- Return type:
Callable[[], None]
- add_variable_table_change_listener(callback)[source]¶
Register
callbackto fire on every variable-table-change frame (<control>_1</control>action"9").Fired when a variable is added, removed, or has its precision changed on the controller. The dispatcher itself does not re-fetch the variable table — the listener is the seam where consumers wire in a focused re-fetch (e.g. by calling
Controller.refresh()) so the registry mirrors the new metadata. SeeVariableTableChangeEventfor the payload.- Returns:
An unsubscribe function.
- Parameters:
callback (Callable[[VariableTableChangeEvent], None])
- Return type:
Callable[[], None]
- add_lifecycle_listener(callback)[source]¶
Register
callbackto fire on every parsedNodeLifecycleEvent(<control>_3</control>frames).Use this to drive reload UX: HA Core typically registers a Repair issue when it sees a lifecycle event with
requires_reload=True, prompting the user to reload the integration when convenient. The dispatcher does not update the node registry on lifecycle events — consumers decide whether to callpyisyox.controller.Controller.refresh()or live with a stale view until manual reload.- Returns:
An unsubscribe function.
- Parameters:
callback (Callable[[NodeLifecycleEvent], None])
- Return type:
Callable[[], None]
- feed(raw_frame)[source]¶
Parse one frame, apply the property update, fan out to listeners.
Returns the parsed
Eventfor callers that want to peek (e.g. for sequence-number tracking), orNonewhen the frame couldn’t be parsed (malformed XML, non-event envelope, keep-alive null). Never raises on bad input — a single bad frame must not crash the read loop.
- class Folder(record)[source]¶
Bases:
objectUser-facing handle for one folder in the node tree.
- Parameters:
record (FolderRecord)
- class Group(record, profile, client, nodes=None)[source]¶
Bases:
objectUser-facing handle for one group / scene in the controller.
- Parameters:
record (GroupRecord)
profile (Profile)
client (IoXClient)
nodes (dict[str, NodeRecord] | None)
- classmethod from_record(record, profile, client, nodes=None)[source]¶
Construct a Group from a parsed record.
Pass
nodes(the controller’sloaded.nodesdict) to enable thegroup_all_onderived property. Without it the group is purely command-issuing.- Parameters:
record (GroupRecord)
profile (Profile)
client (IoXClient)
nodes (dict[str, NodeRecord] | None)
- Return type:
- property address: str¶
Group address — usually a 5-digit integer string or
"ADR####"for special groups like~zAuto DR.
- property nodedef_id: str¶
Scene-class label (
"InsteonDimmer"etc.). Not a real profile nodedef — see module docstring.
- property member_addresses: tuple[str, ...]¶
Addresses of the nodes that belong to this group.
Sourced from the
<members>element in/rest/nodesXML. Order matches the controller’s declaration order. Includes both controllers and responders; usecontroller_addressesfor the controller subset.
- property controller_addresses: tuple[str, ...]¶
Subset of
member_addressesthat the controller flags as scene controllers (<link type="16">).Empty when the group has no explicit controller (e.g. virtual scenes / SmartLinc-style automation groups).
- property has_state_target: bool¶
Whether the scene maintains any member on/off state.
Truewhen link targets resolved and at least one member has anon/offintent. A resolved scene with only fire-only / config links (cmdBL/BEEP/…, or empty) →False: it has no steady state, so a consumer should model it as a momentary button, not a switch. When targets are unresolved we can’t tell, so assumeTrue(the safe default — keep it a stateful scene).
- property has_dimmable_members: bool¶
True iff any member node is a dimmable load.
Nodedef-derived via
pyisyox.runtime.Node.is_dimmable, so it’s robust and — unlikehas_state_target— does not depend on/api/groupslink resolution (works on older firmware too). Consumers pair it withhas_state_targetto pick the scene’s HA platform: no state target → button; else dimmable members → on/off light (preserving light semantics + the group/more-info framework, noswitch_as_x); else → switch. Scenes have no settable brightness — fade/brt/dim are separate manual commands — so “light” here is on/off only.Returns
Falsewithout a node-registry reference. Members missing from the registry are skipped (defensive). Memoised on first access (oneNode+find_nodedefper member) — the result is static for this record, so repeated reads (e.g.to_dict) don’t rebuild it.
- property group_all_on: bool¶
True iff every on-target member currently reports an “on” state.
Computed on access from the controller’s node registry. Stateless members — motion sensors, RemoteLincs, binary-alarm devices, see
_STATELESS_NODEDEF_IDS— are excluded; theirSTisn’t a persistent state.When
/api/groupslink targets resolved, the aggregate is over the scene’s on-target members only (see_on_set()) — so a radio-style keypad scene (one button on-target, the rest driven off) tracks correctly instead of being structurally never-all-on. Otherwise it falls back to the legacy all-member behaviour. ReturnsFalsewhen the group has no node-registry reference, the (on-target / member) set is empty, a member is missing from the registry, or any counted member’sSTis missing or zero.Cheap:
O(N), computed on read — the underlyingSTvalues mutate in place via the WS dispatcher, so each access reflects the latest state.
- property group_any_on: bool¶
True iff at least one on-target member currently reports “on”.
Companion to
group_all_on; this is the aggregation HA scene-switch consumers want for theiris_on. When/api/groupslink targets resolved it considers only the scene’s on-target members (see_on_set()), so a scene reads on iff a member it actually drives on is on — not merely because some always-lit keypad button is non-zero. Otherwise it falls back to the legacy “any stateful member non-zero” behaviour (whatpyisy.Group.statusdid). Stateless members and members not in the registry are skipped.Returns
Falsewith no node-registry reference, an empty (on-target / member) set, or when every counted member’sSTis missing or zero. Cheap:O(N), computed on read.
- async send_command(command_id, *params)[source]¶
Send a command to every member of this group.
Wire shape:
GET /rest/nodes/{group_addr}/cmd/{command_id}[/{p1}...]. The controller broadcasts to each member; results aren’t returned per-member.Unlike
Node.send_command(), parameters are not validated through the editor codec — group nodedefs aren’t profile-resolvable. Pass already-encoded integers; consumers are responsible for sanity checks (e.g. clamp on-level to 0-100). Common usage:await group.send_command("DON")— turn the scene on to its programmed levelawait group.send_command("DON", 75)— explicit on-levelawait group.send_command("DOF")await group.send_command("DFON")/"DFOF"— fastawait group.send_command("BRT")/"DIM"— manual brighten/dim step
- async rename(name)[source]¶
Rename this group / scene.
Wire shape:
POST /api/nodes/{address}with{"name": "<str>", "nodeType": "group"}. ThenodeTypefield is required by the server even though the address already disambiguates — without it the call is rejected.- Parameters:
name (str)
- Return type:
None
- class InternetAccessStatus(*values)[source]¶
Bases:
StrEnumAction codes on
SystemEventControl.INTERNET_ACCESS(_6) frames — Cookbook §8.5.8.- DISABLED¶
- ENABLED¶
Enabled —
<eventInfo>is the external URL.
- FAILED¶
- class NetworkResource(record, client)[source]¶
Bases:
objectUser-facing handle for one networking module resource.
- Parameters:
record (NetworkResourceRecord)
client (IoXClient)
- async run()[source]¶
Fire this network resource.
Wire shape:
GET /rest/networking/resources/{id}. The controller acknowledges receipt only — the response doesn’t carry the result of the underlying HTTP / TCP / UDP fire, and there’s no progress event on the WebSocket. Treat this as fire-and-forget.- Return type:
None
- class Node(record, nodedef, profile, client)[source]¶
Bases:
objectUser-facing handle around one node from a
LoadResult.Construct via
Node.from_record()rather than the bare constructor so the editor resolver and nodedef are wired automatically from the parsedProfile.- Parameters:
record (NodeRecord)
nodedef (NodeDef | None)
profile (Profile)
client (IoXClient)
- classmethod from_record(record, profile, client)[source]¶
Resolve the nodedef for
recordand construct a Node.- Parameters:
record (NodeRecord)
profile (Profile)
client (IoXClient)
- Return type:
- property type: str¶
IoX type triple, e.g.
"1.65.69.0"for KeypadLinc dimmer.Plugin nodes carry a placeholder (Flume reports
"1.2.3.4"); consumers should not rely on it for plugin classification — usenodedefinstead.
- property parent_address: str | None¶
Tree-hierarchy parent (containing folder).
Noneat root.Distinct from
primary_address:<parent>is the folder,<pnode>is the device primary for multi-button hardware.
- property primary_address: str | None¶
Device primary for sub-button nodes (from
<pnode>).Sub-buttons of multi-button devices (KeypadLinc, RemoteLinc, FanLinc) carry the primary’s address.
Nonefor primaries — soprimary_address is not Nonereads as “sub-node” andprimary_address or addressas the device-grouping address.
- property properties: dict[str, NodePropertyValue]¶
Live property values, keyed by property id (e.g.
"ST").Each value is UOM-normalised to its nodedef editor’s canonical unit — e.g. an Insteon dimmer reporting
OLas a UOM-100 0-255 byte is surfaced as the UOM-51 0-100% theI_OLeditor (and the/cmdwrite surface) uses. Values already matching the editor pass through unchanged.
- property status: NodePropertyValue | None¶
Shortcut for
properties[PROP_STATUS]— the node’s primary status reading ("ST"), UOM-normalised the same waypropertiesis.Returns
Nonewhen the node hasn’t reported ST yet (common for write-only Insteon controllers and plugin nodes that don’t advertise ST). Consumers that want a scalar should readnode.status.value(a string) and parse it themselves; the property keeps the structured shape so callers can also reach.uom,.formatted, etc.
- property flag: int¶
Raw node-flag bitfield from the controller’s node table.
Bit meanings live in
pyisyox.constants.NodeFlag(NEW,IN_ERR,DEVICE_ROOT, …). Usehas_flag()for individual bit checks rather than reading this directly. Returns0when the controller didn’t carry a value for this node — treat0as “no bits set” rather than “unknown”.
- has_flag(flag)[source]¶
Return
Trueif every bit inflagis set on this node.flagmay be OR’d; combined values must have every bit set.
- property protocol: Protocol¶
Transport-protocol classification from
family_id.Returns
NODE_SERVERfor any non-core family id (PG3 plugin nodes report a slot id here),UNKNOWNfor recognised but unmapped core families. Classifies transport, not device class — useis_thermostatetc. for capability.
- property is_lock: bool¶
True for door/deadbolt locks.
Two tells: nodedef accepts
SECMD(Z-Wave / Insteon I2CS), or nodedef id contains"Lock"(IoX 6+DoorLockvariants that drive viaDON/DOF).
- property is_fan: bool¶
True for multi-speed fan controllers (nodedef id contains
"Fan").Fan nodes are a subset of dimmable (
FanLincMotoracceptsDONwith a{0, 25, 75, 100}subset), so platform classification should checkis_fanbeforeis_dimmable.
- property is_dimmable: bool¶
True if the node has a multilevel
STstate and accepts a parameterizedDON.Three conditions must all hold for a real dimmer:
STeditor reports a multilevel range (not a binary{0, 100}subset). Relay nodedefs acceptDONwith an ignored level param, soDON’s editor alone is unreliable —STis the source of truth for “can the node hold a non-binary level”.The nodedef accepts
DON. Some Insteon nodedefs (RemoteLinc2_ADV scene buttons, IMETER_SOLO meters) carry a multilevelSTeditor — meaningful for the device’s own bookkeeping — but only acceptWDU/QUERY, so they can’t actually be commanded on. Without this checkis_dimmablereturns True for them and consumers route them onto the LIGHT platform where DON-based turn_on silently fails.The accepted
DONdeclares at least one parameter (the on-level). HA’s light platform sets brightness withDON <level>; a parameterlessDONcannot take one, so the node is on/off-only even with a multilevelST(some node-server nodedefs set level via a separateSETST/SETOLcommand instead — issue #64 / Virtual#11). Real Insteon/Z-Wave dimmers declareDONwith an optional on-level param, so they still qualify.
- property is_battery_node: bool¶
True if the node reports
BATLVLbut noST.Battery-powered Insteon sensors (motion, leak, open/close) match this — they have no on/off primary state.
- property zwave_props: ZWaveProperties | None¶
Parsed
ZWavePropertiesfor Z-Wave / Z-Matter nodes;Nonefor Insteon and other families.
- async send_command(command_id, *params)[source]¶
Send a command, with editor-codec parameter validation.
Each parameter is sent as
/{value}/{uom}using the UOM its editor declares (the eisy web-UI convention —/cmd/DON/75/51). Parameters whose editor carries no real unit (UOM"0"or unset) are sent bare.When the node has no resolved nodedef (dynamically provisioned Z-Wave/Z-Matter nodes whose
UZW*defs aren’t in/rest/profiles), params pass through verbatim (numeric → int, no UOM) so the node stays controllable without validation.
- async set_climate_mode(mode)[source]¶
Set HVAC mode. Accepts enum names (
"Heat","Cool","Auto","Program Auto", …) or raw ints. The editor forCLIMDenforces subset membership (e.g. excludes"Fan Only"on devices that don’t support it).
- async set_climate_setpoint_heat(val)[source]¶
Set the heat setpoint. The codec scales by
prec(or doubles for legacy UOM-101 half-degree editors).- Parameters:
val (float)
- Return type:
None
- async set_climate_setpoint_cool(val)[source]¶
Set the cool setpoint.
- Parameters:
val (float)
- Return type:
None
- async set_fan_mode(mode)[source]¶
Set fan mode. Accepts enum names (
"Auto","On","Auto High", …) or raw ints.
- async set_on_level(val)[source]¶
Set the remembered on-level via
OL(0-100 percent).- Parameters:
val (int)
- Return type:
None
- async set_ramp_rate(val)[source]¶
Set the device’s ramp rate.
Insteon: 0-31 index into the IoX ramp-rate table. Z-Wave: seconds. The editor enforces the per-device range.
- Parameters:
val (int)
- Return type:
None
- async set_backlight(val)[source]¶
Set keypad/switch backlight intensity.
Two encodings driven by the BL editor’s UOM: UOM 100 → 0-100%, UOM 25 → integer index (or enum-name string the codec resolves).
- async start_manual_dimming()[source]¶
Begin manual dimming (legacy Insteon
BMAN).The IoX docs prefer the
FADE_*family for new code.- Return type:
None
- async rename(name)[source]¶
Rename this node. The controller emits a
_3lifecycle frame withaction="NN"on success.- Parameters:
name (str)
- Return type:
None
- async get_zwave_parameter(number)[source]¶
Request parameter
number; return{parameter, size, value}.Family id picks the wire prefix (
"4"→/rest/zwave/...,"12"→/rest/zmatter/zwave/...). RaisesNodeCommandErroron non-Z-Wave nodes or controller failure;ISYResponseParseErroron malformed bodies.
- async set_zwave_parameter(number, value, size)[source]¶
Write parameter
number(size 1/2/4 bytes) on this Z-Wave node.The post-write report arrives asynchronously on the WS stream. Raises
NodeCommandErroron rejection so failures aren’t silent.
- async set_zwave_lock_code(user_num, code)[source]¶
Program a Z-Wave lock’s user-code slot. Raises
NodeCommandErroron a failed envelope.
- exception NodeCommandError[source]¶
Bases:
ExceptionRaised when a command can’t be sent — unknown command id, missing parameter, validation failure, or no nodedef resolved for this node.
Defined here (not in
node.py) to keep the module dependency one-way:node.pyimports from_commands.py, never the reverse.
- class NodeLifecycleAction(*values)[source]¶
Bases:
StrEnumVerbs the eisy emits via
<control>_3</control>events — ISY994 Developer Cookbook §8.5.5 (“Node Changed/Updated”). PyISY 3.x keeps the same mapping.<eventInfo>child tags per verb are inNODE_LIFECYCLE_EVENT_INFO_TAGS.ENcarries anenabledboolean in<eventInfo>— there’s no separate “disabled” verb; the same code handles both transitions.- NODE_ADDED¶
Node added.
<eventInfo>carries<nodeName>plus a<nodeType>that is itself the full<node>element — seeNodeLifecycleEvent.node_xml.
- NODE_REMOVED¶
Node removed (device deleted from the controller).
- NODE_RENAMED¶
Node renamed (display name changed).
- NODE_MOVED¶
Node moved into a Scene.
- LINK_CHANGED¶
Link changed (within a scene). Not supported by the controller — kept for documentation; never observed.
- NODE_REMOVED_FROM_GROUP¶
Node removed from a Scene.
- PARENT_CHANGED¶
Parent (primary node) changed.
- NODE_ENABLED¶
Node enabled/disabled — direction is in
eventInfo.enabled.
- POWER_INFO_CHANGED¶
Power-info changed —
<eventInfo>carries<deviceClass>/<wattage>/<dcPeriod>.
- DEVICE_ID_CHANGED¶
Device ID changed. Not implemented by the controller — kept for documentation.
- DEVICE_PROPERTY_CHANGED¶
Device property changed — UPB only.
- PENDING_DEVICE_OP¶
Pending device operation queued, awaiting commit. On Insteon a write (e.g. changing backlight level) surfaces
WHfirst, thenPROGRAMMING_DEVICE(WD) while the value is written; a property-update event arrives separately once it lands.
- PROGRAMMING_DEVICE¶
The controller is carrying out a programming/write operation on this node (follows
PENDING_DEVICE_OP). Cookbook name: “Programming Device”. Not a completion signal — watch the subsequent property-update event for the new value.
- NODE_REVISED¶
Node revised — drastically changed (UPB-style); the consumer should discard cached info for the node and rebuild it.
<eventInfo>carries the full<node>structure.
- NODE_TYPE_INFO_CHANGED¶
Supported-type info changed — the node’s nodedef assignment was reassigned (e.g. a node server’s
changeNode, or a device driver detecting new capabilities). The primary signal that a cached nodedef → entity mapping is stale. Not fired for/rest/profilesdefinition updates or moves, or at startup migration — those rewrite the profile DB without notifying.
- ALL_NODES_ADDED¶
All nodes for a single device have been added (bulk). Fired after an include / re-pair so consumers can coalesce a single refresh per device instead of per child node.
- LINK_UPDATED¶
Scene link updated — a link’s properties (on-level / ramp rate) changed for an existing scene member.
- DISCOVERING_NODES¶
Discovering nodes (linking in progress). No node.
- NODE_DISCOVERY_COMPLETE¶
Node discovery complete. No node.
- NODE_ERROR¶
Node communication error (device unreachable).
- NODE_ERROR_CLEARED¶
A previously-reported node communication error was cleared (cookbook: “Clear Node Error / Comm. Errors Cleared”) — the companion to
NODE_ERROR.
- FOLDER_ADDED¶
Folder added.
- FOLDER_REMOVED¶
Folder removed.
- FOLDER_RENAMED¶
Folder renamed —
<eventInfo>carries<newName>.
- GROUP_ADDED¶
Scene (group) added —
<eventInfo>carries<groupName>/<groupType>.
- GROUP_REMOVED¶
Scene (group) removed.
- GROUP_RENAMED¶
Scene (group) renamed —
<eventInfo>carries<newName>.
- NET_RENAMED¶
A networking-module resource was renamed (
node= the new name). Doesn’t affect the node registry.
- class NodeLifecycleEvent(action, node_address, raw_action, seqnum, node_xml=None, enabled=None)[source]¶
Bases:
objectA high-level summary of a
<control>_3</control>lifecycle frame.Emitted alongside the raw
Eventwhenever the dispatcher sees one of the actions inNodeLifecycleAction. Consumers subscribe viapyisyox.controller.Controller.add_node_lifecycle_listener()to drive their own reload UX (HA Core’s Repair issue, etc.).- Variables:
action (pyisyox.runtime.events.NodeLifecycleAction | str) – The lifecycle verb (typed enum). Unknown verbs come through as a plain string via
raw_action.node_address (str) – Wire address of the affected node. Empty string only for system-wide signals (none observed yet).
raw_action (str) – The string action value verbatim, in case a new verb appears that isn’t yet in
NodeLifecycleAction.node_xml (str | None) – For
NDactions, the inner<node>element text from<eventInfo>.Nonefor verbs that don’t include the full element. Consumers wanting the parsed shape can pass this toparse_lifecycle_node_xml().enabled (bool | None) – For
EN(NODE_ENABLED) actions, the new enabled/disabled state from<eventInfo><enabled>— the same value already written back toNode.enabled.Nonefor every other verb (and forENframes that omit the flag).
- Parameters:
- action: NodeLifecycleAction | str¶
- property requires_reload: bool¶
True for verbs that invalidate the cached node/group/folder registry.
Reload-worthy:
ND/NR/NN(node added/removed/renamed — the registry’s set or display names are stale),EN(enabled/disabled — the entity’s property shape may change),RV(revised — discard and rebuild this node),NI(supported-type info changed — the node’s nodedef assignment was reassigned, so the cached nodedef→entity mapping is stale; per UDI’s notification taxonomy this is the primary signal for profile-related node changes),AA(all-nodes-added bulk signal after a device include),RG(removed from scene — membership changed),SC(node-discovery complete — new nodes may have appeared), and the folder/scene tree verbsFD/FR/FN/GD/GR/GN(thegroups/foldersregistries are stale).Softer signals — informational, don’t trigger reload UX:
MV(added to scene),CL(link changed — not supported),LU(scene link’s on-level/ramp updated — property change, not shape change),PC(parent changed),PI(power info),DI(device id — not implemented),DP(UPB property),WH(pending op),WD(programming device — a property-update event follows),SN(discovering nodes — wait forSC),CE/NE(comm error/cleared — no shape change),WR(a networking resource was renamed — doesn’t touch nodes).
- class Program(record, client)[source]¶
Bases:
_ProgramBaseUser-facing handle for one program.
- Parameters:
record (ProgramRecord)
client (IoXClient)
- property enabled: bool | None¶
Falsewhen the program is disabled.Noneif the wire payload omitted the field (defensive — every captured program carries it).
- property running: str | None¶
Raw runtime-state field as the controller reported it.
Two wire shapes: REST
/api/programsemits a human label ("idle"/"running then"/"running else"); the WS event stream emits the cookbook<s>byte (two ASCII hex digits). Userun_state/eval_statefor a firmware-agnostic typed view.
- property run_state: ProgramRunState | None¶
Typed run-clause state — one of
IDLE/THEN/ELSE.Nonewhen the program errored (ProgramEvalState.NOT_LOADED) or the controller hasn’t reported a running field yet.
- property eval_state: ProgramEvalState | None¶
Typed if-clause evaluation state — disambiguates the three “not really True/False” cases that
statuscollapses.Nonefrom REST loads (which only carry the run label) and when the controller hasn’t reported a running field yet.
- property last_run_time: datetime | None¶
Tz-aware
datetimeof the program’s last run start, orNoneif it has never run.REST
/api/programsemits the timestamp as ISO 8601 UTC ("2026-05-10T14:49:53.000Z"); we parse on read so the wrapper hands consumers a realdatetimerather than the wire string. The raw form remains accessible viaself._record.last_run_timefor diagnostics / round-trip.
- property last_finish_time: datetime | None¶
Tz-aware
datetimeof the program’s last run completion, orNone.
- property next_scheduled_run_time: datetime | None¶
Tz-aware
datetimeof the next scheduled run, orNonefor manual-only programs.
- async run_then()[source]¶
Run the program’s
thenclause.Wire:
GET /rest/programs/{id}/runThen.- Return type:
None
- async run_if()[source]¶
Re-evaluate the program’s
ifcondition (without running the matching clause’s actions).- Return type:
None
- class ProgramCommand(*values)[source]¶
Bases:
StrEnumVerbs accepted by
GET /rest/programs/{id}/{command}.Members are the camelCase wire strings the eisy expects; consumers building HA-style snake-case service schemas can use the member names (
ProgramCommand.RUN_THEN.name == "RUN_THEN") or pull the wire string via.value/ direct comparison (StrEnummembers compare equal to their underlying string).Folders only support
RUN,STOP,ENABLE, andDISABLE—Program-only verbs raise server-side on a folder target.- RUN¶
Run the program (or every program under a folder). For programs, evaluates the if-clause and runs the matching branch.
- RUN_THEN¶
Run the program’s
thenclause directly.
- RUN_ELSE¶
Run the program’s
elseclause directly.
- RUN_IF¶
Re-evaluate the program’s
ifcondition without running the matching clause’s actions.
- STOP¶
Abort an executing program / folder.
- ENABLE¶
Enable the program / folder for evaluation.
- DISABLE¶
Disable the program / folder (status freezes).
- ENABLE_RUN_AT_STARTUP¶
Mark the program as auto-run on controller boot.
- DISABLE_RUN_AT_STARTUP¶
Clear the auto-run-on-boot flag.
- class ProgramEvalState(*values)[source]¶
Bases:
IntEnumHigh-nibble of the
<s>byte on a program-status frame.Cookbook §8.5.3: the program’s last if-clause evaluation result. The
status: boolfield onProgramStatusEventderives from the same source (the<on/>/<off/>element) but this enum disambiguates the three “not really True/False” cases that the bool collapses.Note
NOT_LOADEDis the cookbook’s literal label, but in practice the controller emits0xF0when the program failed to compile or hit a runtime error — not (only) when it hasn’t been loaded yet. Treat this as the program-error sentinel; seeProgramRunStatefor whyrun_stateisNonein this case.- UNKNOWN¶
- TRUE¶
- FALSE¶
- NOT_LOADED¶
- class ProgramFolder(record, client)[source]¶
Bases:
_ProgramBaseOrganisational container for programs.
Folders share the program command surface but only
run/stop/enable/disableare documented to apply. The eisy aggregates child status intostatusserver-side.- Parameters:
record (ProgramRecord)
client (IoXClient)
- class ProgramRunState(*values)[source]¶
Bases:
IntEnumLow-nibble of the
<s>byte on a program-status frame.Cookbook §8.5.3: exactly one of three run-clause states per frame, ORed with a
ProgramEvalState(high nibble) in the byte. Absent (Noneon the event) when the high nibble isProgramEvalState.NOT_LOADED— the program errored so there’s no clause currently running.- IDLE¶
- THEN¶
- ELSE¶
- class ProgramStatusEvent(address, status, running, seqnum, run_state=None, eval_state=None, enabled=None, run_at_startup=None)[source]¶
Bases:
objectA program toggled true/false on the controller.
Emitted by
EventDispatcherwhenever a<control>_1</control>frame with<action>0</action>arrives carrying a program id in its<eventInfo>. The matchingpyisyox.client.ProgramRecordis mutated in place before listeners fire, so consumers readingprogram.statusfrom a callback see the updated value.- Variables:
address (str) – Program id (4-character hex, zero-padded to match
/api/programs).status (bool) –
Truewhen the cookbook<s>byte’s eval state isProgramEvalState.TRUE(the if-clause matched on the most recent evaluation);FalseforProgramEvalState.FALSE. ForProgramEvalState.UNKNOWN/ProgramEvalState.NOT_LOADED(and frames with no<s>byte) the dispatcher carries forward the priorrecord.statusso a transient unknown doesn’t flip the entity. Wire-shape note: the<on/>/<off/>elements that ride along on the same frame are the enabled flag, not the status — seeenabled.running (int | None) – Raw
<s>byte the eisy sent, orNoneif absent. Cookbook §8.5.3: the byte is a bitwise OR of aProgramRunState(low nibble) and aProgramEvalState(high nibble); userun_state/eval_statefor the typed view.run_state (pyisyox.runtime.events.ProgramRunState | None) – Decoded low nibble —
IDLE/THEN/ELSE, orNonewhen the program isn’t loaded (eval_state == NOT_LOADED) or the wire byte was absent / unrecognised.eval_state (pyisyox.runtime.events.ProgramEvalState | None) – Decoded high nibble —
UNKNOWN/TRUE/FALSE/NOT_LOADED, orNonewhen the wire byte was absent / unrecognised. Disambiguates the three “not really True/False” cases thatstatus: boolcollapses.NOT_LOADEDis the cookbook label for what is in practice the program-errored sentinel — seeProgramEvalState.enabled (bool | None) – New
enabledstate when the frame carried an<on/>/<off/>element —Truefor<on/>,Falsefor<off/>.Nonewhen the frame omitted both (some “ran”-only frames carry only<r>/<f>/<s>— see cookbook §8.5.3). The matching record’spyisyox.client.ProgramRecord.enabledis updated in-place before listeners fire when this is non-None.run_at_startup (bool | None) – New
run_at_startupstate when the frame carried an<rr/>(True) or<nr/>(False) element.Nonewhen the frame omitted both. Mirror of the enabled-flag pattern; the record’spyisyox.client.ProgramRecord.run_at_startupis updated in-place before listeners fire.
- Parameters:
address (str)
status (bool)
running (int | None)
seqnum (int)
run_state (ProgramRunState | None)
eval_state (ProgramEvalState | None)
enabled (bool | None)
run_at_startup (bool | None)
- run_state: ProgramRunState | None¶
- eval_state: ProgramEvalState | None¶
- class ProgressAction(*values)[source]¶
Bases:
StrEnumAction codes on
SystemEventControl.PROGRESS(_7) frames — Cookbook §8.5.9.<eventInfo>is free-text progress detail.- UPDATE¶
Generic progress update.
- DEVICE_ADDER_INFO¶
Device-adder info (UPB only).
- DEVICE_ADDER_WARN¶
Device-adder warning (UPB only).
- DEVICE_ADDER_ERROR¶
Device-adder error (UPB only).
- class SecuritySystemAction(*values)[source]¶
Bases:
StrEnumAction codes on
SystemEventControl.SECURITY_SYSTEM(_8) frames — Cookbook §8.5.10.nodeand<eventInfo>are null.- DISCONNECTED¶
- CONNECTED¶
- DISARMED¶
- ARMED_AWAY¶
- ARMED_STAY¶
- ARMED_STAY_INSTANT¶
- ARMED_NIGHT¶
- ARMED_NIGHT_INSTANT¶
- ARMED_VACATION¶
- class SystemConfigAction(*values)[source]¶
Bases:
StrEnumAction codes on
SystemEventControl.SYSTEM_CONFIG(_4) frames — Cookbook §8.5.6.- TIME_CHANGED¶
- TIME_CONFIG_CHANGED¶
- NTP_SETTINGS_UPDATED¶
- NOTIFICATIONS_SETTINGS_UPDATED¶
- NTP_COMM_ERROR¶
- BATCH_MODE_UPDATED¶
Batch mode toggled —
<eventInfo><status>is"1"/"0".
- BATTERY_WRITE_MODE_UPDATED¶
Battery-powered-write mode toggled —
<eventInfo><status>is"1"/"0".
- class SystemEditorAction(*values)[source]¶
Bases:
StrEnumAction codes on
SystemEventControl.SYSTEM_EDITOR(_24) frames. The<node>slot carries the editor name (e.g._sys_notify_short).- EDITOR_CHANGED¶
A system editor’s contents changed.
- class SystemEventControl(*values)[source]¶
Bases:
StrEnumIoX WebSocket “system” control codes (underscore-prefixed).
Property updates use the property id (
"ST","GV1", …) with a populatednode_address. System events use one of these underscore-prefixed codes with an emptynode_address.Codes
_0-_23are the full ISY-994 set from the ISY994 Developer Cookbook §8.5;_24-_28are IoX-6 additions (system editors, the modern Z-Wave / ZigBee / Matter drivers, system upgrade) not in that document — tracked from UDI’s internalUDEvents.htaxonomy. Newer IoX firmware may emit further codes; those aren’t enumerated, andlabel()passes them through verbatim so logs still identify them.- HEARTBEAT¶
Periodic heartbeat.
<action>is the duration in seconds until the next expected heartbeat (use it to detect a stalled stream). No<eventInfo>.
- TRIGGER¶
Trigger events — program status, variable change/init, schedule change, key/info-string pushes, “get status” refresh signal.
<action>discriminates; seeTriggerAction.
- DRIVER_SPECIFIC¶
Driver-specific events — payload depends on the underlying protocol driver. Not modelled.
- NODE_LIFECYCLE¶
Node / scene / folder lifecycle — add / remove / rename / enable / revise / comm-error / etc.
<action>carries the verb; seeNodeLifecycleActionandNODE_LIFECYCLE_EVENT_INFO_TAGS.
- SYSTEM_CONFIG¶
System configuration updated — time / NTP / notifications / batch-mode / battery-write-mode.
<action>0-6; seeSystemConfigAction.
- SYSTEM_STATUS¶
Controller-side busy/idle/safe-mode status.
<action>0-3; seepyisyox.constants.SystemStatus.
- INTERNET_ACCESS¶
Internet-access status — disabled / enabled (
<eventInfo>= external URL) / failed. SeeInternetAccessStatus.
- PROGRESS¶
Progress report during long-running operations (device programming, restore, device-adder).
<action>1 / 2.1 / 2.2 / 2.3; seeProgressAction. The_7A/_7Mdevice-write sub-codes also ride through on this control — seeDeviceWriteAction.
- SECURITY_SYSTEM¶
Security-system event — connected / disconnected / armed-* / disarmed. See
SecuritySystemAction.
- SYSTEM_ALERT¶
System alert event — “not implemented and should be ignored” per the cookbook.
- OPENADR¶
OpenADR / Flex-Your-Power events — ISY994 Z-Series demand-response.
- CLIMATE¶
Climate / weather events — required the ISY994 WeatherBug module; not present on eisy.
- AMI_SEP¶
AMI/SEP energy events — ISY994 only (see the Energy Management Developer’s Manual).
- ENERGY_MONITORING¶
External energy-monitoring (Brultech) — ISY994 only; on later firmware these are folded into node events instead.
- UPB_LINKER¶
UPB linker events — UPB-enabled units only.
- UPB_DEVICE_ADDER¶
UPB device-adder state — UPB-enabled units only.
- UPB_DEVICE_STATUS¶
UPB device-status events — UPB-enabled units only.
- GAS_METER¶
Gas-meter events — ISY994 only.
- ZIGBEE¶
Legacy ZigBee events — ISY994-era driver. See
ZIGBEE_UYB(_27) for the IoX-6+ ZigBee driver used on eisy.
- ELK¶
ELK alarm-panel events — requires the ELK module (see the ELK Integration Developer’s Manual).
- DEVICE_LINKER¶
Device-linker events —
<action>1 (status) / 2 (cleared). SeeDeviceLinkerAction.
- ZWAVE¶
Legacy Z-Wave integration events — ISY994-era driver. See
ZMATTER_ZWAVE(_25) for the IoX-6+ ZMatter Z-Wave driver used on eisy.
- BILLING¶
Billing events — ISY994 ZS-series only.
- PORTAL¶
Portal events — portal socket-connection / account-registration status when a portal module is installed.
- SYSTEM_EDITOR¶
System editor changed — fired when a “system editor” (e.g.
_sys_notify_short) is updated.<node>carries the editor name.<action>isSystemEditorAction. IoX-6 addition.
- ZMATTER_ZWAVE¶
ZMatter Z-Wave events — IoX-6+ Z-Wave driver on eisy hardware.
<action>is dotted ("{category}.{type}"); category numbers are system-status (1), discovery (2), general-status (3), general-error (4), S2 (5), OTA (6), backup/restore (7), device- interview (8), button-detect (9), logger (10). Sub-action details aren’t modelled — the dotted string passes through verbatim. Distinct fromZWAVE(_21, ISY994-era driver).
- SYSTEM_UPGRADE¶
System-upgrade lifecycle —
<action>isSystemUpgradeAction(active / inactive / available / reboot-required). IoX-6 addition.
- ZIGBEE_UYB¶
ZigBee events — IoX-6+ ZigBee driver on eisy hardware. Same dotted
"{category}.{type}"action shape asZMATTER_ZWAVE(minus the logger sub-category). Distinct fromZIGBEE(_18, ISY994-era driver).
- MATTER_STATUS¶
Matter network status — IoX-6+ Matter driver.
<action>is dotted; active sub-categories are 1 (system status), 2 (discovery), 3 (RX/TX), 8 (device interview). Not in the ISY994 cookbook.Note:
_28is also reserved in UDI’s source for Profile change events (actions 1-8 — profile/editor/nodedef/linkdef updated/deleted) — but no firmware path fires those today (placeholders since Dec 2024 per UDI). Don’t subscribe expecting them.
- class SystemUpgradeAction(*values)[source]¶
Bases:
StrEnumAction codes on
SystemEventControl.SYSTEM_UPGRADE(_26) frames — IoX-6 firmware-upgrade lifecycle.- ACTIVE¶
Upgrade in progress.
- INACTIVE¶
Upgrade not active (post-completion or idle).
- AVAILABLE¶
A new upgrade is available to install.
- REBOOT_REQUIRED¶
Upgrade applied; reboot required to take effect.
- class TriggerAction(*values)[source]¶
Bases:
StrEnumAction codes carried in
SystemEventControl.TRIGGER(_1) frames — ISY994 Developer Cookbook §8.5.3.<action>discriminates what the frame is; pyisyox only routes onPROGRAM_STATUS/VARIABLE_VALUE/VARIABLE_INIT.- PROGRAM_STATUS¶
Program status changed — handled by
_apply_program_status.<eventInfo>carries the program<id>, enabled/run-at-reboot flags, last run/finish times, and a bitwise<s>status.
- GET_STATUS¶
“Get status” — the controller is telling subscribers to re-poll everything (e.g. after a config change). No payload.
- KEY_CHANGED¶
A key changed.
nodecarries the key.
- INFO_STRING¶
An info string.
nodecarries the key;<eventInfo>is the text.
- IR_LEARN_MODE¶
IR learn mode toggled. No payload.
- SCHEDULE¶
A schedule’s status changed.
nodecarries the key.
- VARIABLE_VALUE¶
Variable value changed — handled by
_apply_variable_change.<eventInfo>carries<var type id><val><ts>.
- VARIABLE_INIT¶
Variable init (restore-on-startup) value changed — same handler / payload shape as
VARIABLE_VALUE, applied toinit.
- KEY¶
The current subscription key, sent once right after a new subscription is established.
<eventInfo>is the key.
- VARIABLE_TABLE_CHANGED¶
Variable table structurally changed — fires when a variable is added or removed, or when its precision is changed (a metadata change that the per-value
VARIABLE_VALUE/VARIABLE_INITframes don’t cover).<eventInfo>carries<var><type>N</type><id>0</id></var>(id=0 is the wildcard sentinel — “this whole type’s table changed”). The right response is to re-fetch/api/variables/{type}for the affected type so the registry mirrors the controller’s metadata (precision in particular — the wirevalfrom the per-value frames is raw, and a stale precision will mis-render the value). The dispatcher recognises it and firesEventDispatcher.add_variable_table_change_listener()callbacks; the dispatcher itself does not re-fetch.
- class Variable(record, client)[source]¶
Bases:
objectUser-facing handle for one controller variable.
- Parameters:
record (VariableRecord)
client (IoXClient)
- classmethod from_record(record, client)[source]¶
Construct a
Variablefrom a parsed record.- Parameters:
record (VariableRecord)
client (IoXClient)
- Return type:
- property value: int | float¶
Current value (wire field
val).Reads reflect the latest write — mutations via
set_value()update the underlying record in place after a successful POST.Type is
int | float: most variables read back asintfrom the wire (/api/variables/{type}parses"val"as int), but a controller may surfacefloaton a fresh write that posted a non-integer (the modernPOST /api/variables/{type}/{id}endpoint accepts floats and the wrapper stores whatever was sent on success).
- property ts: str¶
Last-change timestamp as the controller emits it.
ISO 8601 UTC string when present,
""when the controller doesn’t stamp the entry (e.g. freshly created variables before the first change).
- async set_value(value)[source]¶
Set the current value of this variable.
Wire shape:
POST /api/variables/{type}/{id}with body{"value": <number>}. The modern endpoint accepts bothintandfloat— for aprecision > 0variable, send the displayed float (e.g.51.5) and the controller applies the* 10**precisionscale on store. Sending aninton the same variable means the controller stores it verbatim (no scale applied), which produces a mismatch between consumer-displayed and controller-internal values — so callers driving displayed-unit UIs should send floats.Strings are tolerated for legacy callers (parsed as float if they contain a decimal point, else int).
Updates the underlying record on success so subsequent reads of
valuereflect the new state without waiting for a WS frame.- Parameters:
value (float)
- Return type:
None
- async set_init(init)[source]¶
Set the init / restore-on-startup value.
Wire shape:
POST /api/variables/{type}/{id}with{"init": <number>}. Same int-or-float semantics asset_value().- Parameters:
init (float)
- Return type:
None
- async rename(name)[source]¶
Rename this variable on the controller.
Wire shape:
POST /api/variables/{type}/{id}with{"name": "<str>"}.- Parameters:
name (str)
- Return type:
None
- async set_precision(prec)[source]¶
Set decimal precision (
displayed = raw / 10**precision).Wire shape:
POST /api/variables/{type}/{id}with{"prec": <int>}.A precision change fires
_1/9(VARIABLE_TABLE_CHANGED) on the WebSocket — not the per-value6/7frames — so consumers that only listen on value/init updates won’t see the new precision until they refresh. Thepyisyox.Controllerauto-refreshes the affected type on this event when its dispatcher is wired.- Parameters:
prec (int)
- Return type:
None
- async delete()[source]¶
Delete this variable on the controller.
Wire shape:
DELETE /api/variables/{type}/{id}. Fires aVARIABLE_TABLE_CHANGEDframe so an auto-refresh listener can drop the entry from the registry; the wrapper itself becomes inert (subsequent mutations would 404 — the wrapper carries no flag for this; consumers should drop their reference).- Return type:
None
- class VariableTableChangeEvent(type_id, seqnum)[source]¶
Bases:
objectA
_1/ action"9"system event — variable table changed.The eisy fires this when a variable is added, removed, or has its precision changed (a structural / metadata change that the per-value
TriggerAction.VARIABLE_VALUE/VARIABLE_INITframes don’t carry).<eventInfo>payload:<var><type>N</type><id>0</id></var>
id=0is the wildcard sentinel — “this whole type’s table changed”, not a specific variable. Consumers should re-fetch/api/variables/{type_id}to pick up the new metadata (precision in particular — the per-value frames carry rawvaland a stale precision will mis-render every variable of this type until the registry is refreshed).
- class WebSocketEventStream(client, dispatcher, path='/rest/subscribe')[source]¶
Bases:
objectBackground reader that feeds frames into an
EventDispatcher.Lifecycle:
start()schedules the read task and returns immediately.The task connects, dispatches frames, reconnects on transport errors, and pumps
EventStreamStatusnotifications to any registered status listener. On each connect it holdsSYNCING(notCONNECTED) until the controller’s initial status replay drains, so consumers don’t treat the replay as live events.stop()cancels the task and closes any active WS.
The class deliberately keeps its surface narrow — the consumer is expected to be the top-level
ISYglue object that owns both theIoXClientand the dispatcher.- Parameters:
client (IoXClient)
dispatcher (EventDispatcher)
path (str)
- property status: EventStreamStatus¶
Most-recent stream status.
Updated on every transition (initialise / connect / reconnect / disconnect / lost). Defaults to
EventStreamStatus.NOT_STARTEDbeforestart(). Useful for system-health pages that want a single readable status string without subscribing to every notification.
- property connected: bool¶
Truewhile the stream is in theCONNECTEDstate.Convenience over comparing
statusdirectly. Note thatconnectedflippingFalsedoesn’t mean the reader has given up — it may be reconnecting, or inEventStreamStatus.SYNCING(socket open but the controller’s initial status replay hasn’t drained yet — intentionally not “connected” so event consumers don’t treat the replay as live changes).
- property last_event_at: datetime | None¶
UTC timestamp of the most recent text frame, or
Noneif no frame has been received this lifetime.The eisy emits a heartbeat
<control>_0</control>frame every 30 seconds even when nothing else changes, so a stalelast_event_at(more than ~60 s ago) is a reasonable signal that the connection is broken even when the WS handshake hasn’t returned an error yet.
- add_status_listener(callback)[source]¶
Register a callback for stream-status changes.
- Returns:
An unsubscribe function.
- Parameters:
callback (Callable[[EventStreamStatus], None])
- Return type:
Callable[[], None]
- describe_system_event(control, action)[source]¶
Render a
<control>/<action>pair from a system event frame as a friendly"<control_label> = <action_label>"string.Resolves both halves to their enum names where one applies:
"_5"/"0"→"system_status = not_busy""_1"/"0"→"trigger = program_status""_3"/"WH"→"node_lifecycle = pending_device_op""_4"/"5"→"system_config = batch_mode_updated""_8"/"AW"→"security_system = armed_away""_20"/"2"→"device_linker = cleared""_0"/"90"→"heartbeat = 90"(action = seconds to the next heartbeat; not enumerated)"_28"/"1.3"→"matter_status = 1.3"(no enum)"_26"/"2"→"system_upgrade = inactive""_24"/"1"→"system_editor = editor_changed""_99"/"x"→"_99 = x"(control we don’t recognise — both halves pass through verbatim)
Intended for the debug logging consumers do over raw event frames (so a line reads
system_status = busyinstead ofsystem_status = 1); not part of any dispatch path. Property- update frames (non-underscore control) aren’t system events — this just echoes them back unchanged if you pass one.
- parse_event_frame(raw)[source]¶
Decode a single WebSocket frame to an
Event.Accepts either:
Raw XML —
<?xml...?><Event...>...</Event>(legacy/rest/subscribe).JSON envelope —
{"type": "event", "data": "<xml>"}(modern/api/events/subscribe). Othertypevalues (e.g."spolisy"PG3 service status) returnNone— they’re not property updates and the dispatcher ignores them.
Returns
Nonefor keep-alive nulls, malformed XML, or non-event JSON envelopes. Does not raise on parse failures so a single bad frame can’t crash the read loop.
Submodules¶
- pyisyox.runtime.events module
SystemEventControlSystemEventControl.HEARTBEATSystemEventControl.TRIGGERSystemEventControl.DRIVER_SPECIFICSystemEventControl.NODE_LIFECYCLESystemEventControl.SYSTEM_CONFIGSystemEventControl.SYSTEM_STATUSSystemEventControl.INTERNET_ACCESSSystemEventControl.PROGRESSSystemEventControl.SECURITY_SYSTEMSystemEventControl.SYSTEM_ALERTSystemEventControl.OPENADRSystemEventControl.CLIMATESystemEventControl.AMI_SEPSystemEventControl.ENERGY_MONITORINGSystemEventControl.UPB_LINKERSystemEventControl.UPB_DEVICE_ADDERSystemEventControl.UPB_DEVICE_STATUSSystemEventControl.GAS_METERSystemEventControl.ZIGBEESystemEventControl.ELKSystemEventControl.DEVICE_LINKERSystemEventControl.ZWAVESystemEventControl.BILLINGSystemEventControl.PORTALSystemEventControl.SYSTEM_EDITORSystemEventControl.ZMATTER_ZWAVESystemEventControl.SYSTEM_UPGRADESystemEventControl.ZIGBEE_UYBSystemEventControl.MATTER_STATUSSystemEventControl.label()
TriggerActionProgressActionSystemConfigActionSystemConfigAction.TIME_CHANGEDSystemConfigAction.TIME_CONFIG_CHANGEDSystemConfigAction.NTP_SETTINGS_UPDATEDSystemConfigAction.NOTIFICATIONS_SETTINGS_UPDATEDSystemConfigAction.NTP_COMM_ERRORSystemConfigAction.BATCH_MODE_UPDATEDSystemConfigAction.BATTERY_WRITE_MODE_UPDATEDSystemConfigAction.label()
InternetAccessStatusSecuritySystemActionSecuritySystemAction.DISCONNECTEDSecuritySystemAction.CONNECTEDSecuritySystemAction.DISARMEDSecuritySystemAction.ARMED_AWAYSecuritySystemAction.ARMED_STAYSecuritySystemAction.ARMED_STAY_INSTANTSecuritySystemAction.ARMED_NIGHTSecuritySystemAction.ARMED_NIGHT_INSTANTSecuritySystemAction.ARMED_VACATIONSecuritySystemAction.label()
DeviceLinkerActionSystemUpgradeActionSystemEditorActionDeviceWriteActionNodeLifecycleActionNodeLifecycleAction.NODE_ADDEDNodeLifecycleAction.NODE_REMOVEDNodeLifecycleAction.NODE_RENAMEDNodeLifecycleAction.NODE_MOVEDNodeLifecycleAction.LINK_CHANGEDNodeLifecycleAction.NODE_REMOVED_FROM_GROUPNodeLifecycleAction.PARENT_CHANGEDNodeLifecycleAction.NODE_ENABLEDNodeLifecycleAction.POWER_INFO_CHANGEDNodeLifecycleAction.DEVICE_ID_CHANGEDNodeLifecycleAction.DEVICE_PROPERTY_CHANGEDNodeLifecycleAction.PENDING_DEVICE_OPNodeLifecycleAction.PROGRAMMING_DEVICENodeLifecycleAction.NODE_REVISEDNodeLifecycleAction.NODE_TYPE_INFO_CHANGEDNodeLifecycleAction.ALL_NODES_ADDEDNodeLifecycleAction.LINK_UPDATEDNodeLifecycleAction.DISCOVERING_NODESNodeLifecycleAction.NODE_DISCOVERY_COMPLETENodeLifecycleAction.NODE_ERRORNodeLifecycleAction.NODE_ERROR_CLEAREDNodeLifecycleAction.FOLDER_ADDEDNodeLifecycleAction.FOLDER_REMOVEDNodeLifecycleAction.FOLDER_RENAMEDNodeLifecycleAction.GROUP_ADDEDNodeLifecycleAction.GROUP_REMOVEDNodeLifecycleAction.GROUP_RENAMEDNodeLifecycleAction.NET_RENAMEDNodeLifecycleAction.label()
NODE_LIFECYCLE_EVENT_INFO_TAGSDEVICE_WRITE_PROGRESS_EVENT_INFO_TAGSdescribe_system_event()NodeLifecycleEventEventparse_event_frame()ProgramRunStateProgramEvalStateProgramStatusEventVariableTableChangeEventEventDispatcher
- pyisyox.runtime.folder module
- pyisyox.runtime.group module
GroupGroup.from_record()Group.addressGroup.nameGroup.nodedef_idGroup.family_idGroup.instance_idGroup.parent_addressGroup.member_addressesGroup.controller_addressesGroup.has_state_targetGroup.has_dimmable_membersGroup.group_all_onGroup.group_any_onGroup.send_command()Group.rename()Group.to_dict()
- pyisyox.runtime.network_resource module
- pyisyox.runtime.node module
NodeNode.from_record()Node.addressNode.nameNode.nodedef_idNode.family_idNode.instance_idNode.typeNode.parent_addressNode.primary_addressNode.enabledNode.propertiesNode.statusNode.nodedefNode.flagNode.has_flag()Node.protocolNode.is_thermostatNode.is_lockNode.is_fanNode.is_dimmableNode.is_battery_nodeNode.zwave_propsNode.send_command()Node.set_climate_mode()Node.set_climate_setpoint_heat()Node.set_climate_setpoint_cool()Node.set_fan_mode()Node.secure_lock()Node.secure_unlock()Node.set_on_level()Node.set_ramp_rate()Node.set_backlight()Node.start_manual_dimming()Node.stop_manual_dimming()Node.rename()Node.to_dict()Node.get_zwave_parameter()Node.set_zwave_parameter()Node.set_zwave_lock_code()Node.delete_zwave_lock_code()Node.set_enabled()
NodeCommandError
- pyisyox.runtime.program module
- pyisyox.runtime.variable module
- pyisyox.runtime.ws module