Summary
Program/folder commands (run, runThen, runElse, runIf, stop, enable, disable,
enableRunAtStartup, disableRunAtStartup) 404 against current IoX firmware
because Client.run_program_command() sends a decimal program id where the
legacy REST endpoint expects the classic 4-character hex id.
Symptom
Toggling an HA.switch-folder program switch (Program.run_then()/run_else())
started 404ing:
GET https://<eisy>/rest/programs/149/runElse -> 404
Manually hitting /rest/programs/0095/runElse (hex form of 149) succeeds.
Root cause
The program/folder registry is built from GET /api/programs (JSON), whose
id field is a plain decimal integer:
{"id": 149, "name": "actions", "folder": false, "parentId": 6, ...}
parse_api_programs() in client.py sets ProgramRecord.address = str(entry["id"])
directly (decimal), even though Program.address's docstring claims "4-character
hex string." That decimal address flows unchanged through Program.run() /
run_then() / run_else() / stop() / enable() / disable() / etc. into
Client.run_program_command(), which formats it straight into:
GET /rest/programs/{program_id}/{command}
But GET /rest/programs (the XML listing for that same endpoint family) uses
4-character hex ids:
<program id="0095" parentId="0006" ...><name>actions</name>...
So every program/folder verb pyisyox issues sends a decimal id to an endpoint
that current IoX firmware rejects with 404.
Why now
The decimal(JSON)/hex(legacy-REST) split isn't new -- both captures above are
from the same firmware snapshot. What appears to have changed is that IoX now
enforces (404s) rather than tolerating a decimal id on /rest/programs/{id}/...
Can't confirm the firmware-side history from the client, but the client-side
mechanism is 100% reproducible regardless of which side changed.
Proposed fix
Convert at the one chokepoint all program commands funnel through
(Client.run_program_command), rather than changing ProgramRecord.address
(used for registry keys / entity unique_ids -- shouldn't move):
--- a/pyisyox/client.py
+++ b/pyisyox/client.py
@@ async def run_program_command(self, program_id: str, command: str) -> str:
IoX 6 keeps this legacy path; no /api/programs/{id}/...
equivalent has been observed. The controller acknowledges
receipt only — status changes flow back over the WebSocket.
+
-
``program_id`` normally arrives as the decimal string
-
``/api/programs`` reports (``ProgramRecord.address``), but
-
this endpoint is addressed with the legacy 4-character hex
-
id (e.g. ``"0095"``) -- recent IoX firmware 404s on decimal.
-
Purely-numeric input is upconverted; anything else (already
-
hex) passes through unchanged.
"""
-
return await self._get_text(PROGRAM_COMMAND_PATH.format(program_id=program_id, command=command))
-
wire_id = f"{int(program_id):04X}" if program_id.isdigit() else program_id
-
return await self._get_text(PROGRAM_COMMAND_PATH.format(program_id=wire_id, command=command))
Verification
Hot-patched exactly this change into a running install (pyisyox 6.0.0b9)
against a live eisy on current IoX 6 firmware:
- switch.turn_on -> runThen -> hex URL -> 200, entity state verified "on"
- switch.turn_off -> runElse -> hex URL -> 200, entity state verified "off"
Both previously 404'd with the decimal id.
Environment
- pyisyox 6.0.0b9
- eisy / IoX 6 (recently updated via package update)
- Repro program: id 149 (hex 0095), name "actions", under folder 6
("Main Bedroom Keypad Backlights") under folder 5 ("HA.switch")
Summary
Program/folder commands (run, runThen, runElse, runIf, stop, enable, disable,
enableRunAtStartup, disableRunAtStartup) 404 against current IoX firmware
because Client.run_program_command() sends a decimal program id where the
legacy REST endpoint expects the classic 4-character hex id.
Symptom
Toggling an HA.switch-folder program switch (Program.run_then()/run_else())
started 404ing:
Manually hitting /rest/programs/0095/runElse (hex form of 149) succeeds.
Root cause
The program/folder registry is built from GET /api/programs (JSON), whose
idfield is a plain decimal integer:parse_api_programs() in client.py sets ProgramRecord.address = str(entry["id"])
directly (decimal), even though Program.address's docstring claims "4-character
hex string." That decimal address flows unchanged through Program.run() /
run_then() / run_else() / stop() / enable() / disable() / etc. into
Client.run_program_command(), which formats it straight into:
But GET /rest/programs (the XML listing for that same endpoint family) uses
4-character hex ids:
So every program/folder verb pyisyox issues sends a decimal id to an endpoint
that current IoX firmware rejects with 404.
Why now
The decimal(JSON)/hex(legacy-REST) split isn't new -- both captures above are
from the same firmware snapshot. What appears to have changed is that IoX now
enforces (404s) rather than tolerating a decimal id on /rest/programs/{id}/...
Can't confirm the firmware-side history from the client, but the client-side
mechanism is 100% reproducible regardless of which side changed.
Proposed fix
Convert at the one chokepoint all program commands funnel through
(Client.run_program_command), rather than changing ProgramRecord.address
(used for registry keys / entity unique_ids -- shouldn't move):
--- a/pyisyox/client.py
+++ b/pyisyox/client.py
@@ async def run_program_command(self, program_id: str, command: str) -> str:
IoX 6 keeps this legacy path; no
/api/programs/{id}/...equivalent has been observed. The controller acknowledges
receipt only — status changes flow back over the WebSocket.
+
Verification
Hot-patched exactly this change into a running install (pyisyox 6.0.0b9)
against a live eisy on current IoX 6 firmware:
Both previously 404'd with the decimal id.
Environment
("Main Bedroom Keypad Backlights") under folder 5 ("HA.switch")