Skip to content

run_program_command sends decimal program/folder id to /rest/programs/{id}/..., but that endpoint requires the legacy 4-char hex id #193

Description

@shbatm

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")

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions