Skip to content

Add the IDiagnostic interface, and trigger and system log subscriptions - #404

Closed
ptr727 wants to merge 1 commit into
loopj:mainfrom
ptr727:diagnostic-interface
Closed

ptr727 wants to merge 1 commit into
loopj:mainfrom
ptr727:diagnostic-interface

Conversation

@ptr727

@ptr727 ptr727 commented Oct 21, 2026

Copy link
Copy Markdown
Contributor

Why

When a button press doesn't do what was expected, or a module drops off its bus, the place to find out why is InFusion Diagnostics: its History view shows which object started which task, and its Log view shows the controller's warnings and module offline/online messages. Neither is reachable from aiovantage today, so an integration can't show what triggered a scene or alert when a module goes offline.

This adds the read-only side of the IDiagnostic ACI interface that those views use, plus live versions of both from the Host Command enhanced log.

How it is implemented

  • DiagnosticInterface (config client) wraps four read-only IDiagnostic methods:

    • get_event_log returns the trigger history: which object (button, timer, sensor, module) started which task, and how.
    • get_event_log_next returns one history entry by position.
    • get_sys_log returns the system log.
    • get_modules returns the modules answering on an enclosure's bus, with their status bytes and error counts.

    Each takes master=, like the other interfaces.

  • TriggerType and SysLogType enums name the trigger and log type codes. They live in their own module, so the event types don't depend on the config client. Both are exported from aiovantage.config_client.

  • EventStream.subscribe_triggers and subscribe_system_log subscribe to the EVENT and SYSTEM enhanced logs and pass each line to the callback as a TriggerReceived or SystemLogReceived. They are built on subscribe_enhanced_log, so peers, reference counting and resubscribing after a reconnect work as they already do.

  • Enhanced log lines carry no type tag, so every log type a client has enabled arrives on the same stream. Each parser matches only its own line shape:

    • a trigger is five integers;
    • a system log is a type number, a one-word source and a message;
    • object status is a VID followed by Interface.Method.

    The controller's enhanced log handler now skips lines that aren't object status. Without that, a trigger or system log line can match a managed object's VID, and a short line like 100 raises during unpacking and stops the event stream.

  • Examples: examples/config_client/dump_diagnostics.py and examples/command_client/monitor_triggers.py.

Protocol notes

Verified against an IC-II controller on 4.11 firmware:

  • GetEventLog and GetSysLog answer only when an empty <call/> element is sent. A bare <GetEventLog/> gets no reply.
  • An integer parameter has to be a <call>N</call> element.
  • GetEventLogNext(n) returns entry n with Position set to the next position, or -1 on the last entry, and an empty <return/> past the end. How many entries the controller keeps, and what it drops once full, isn't known, so the docstring says to check timestamps rather than rely on positions alone.
  • EVENT lines are <source> <destination> <event> <param1> <param2>. A press, a double press (param1 = 2) and a hold were captured live and matched the trigger history one to one.
  • A module losing a line feed raises trigger code 0xA004 from the module, with what looks like the feed number in param1. SYSTEM logs a warning plus Module Offline and Module Online. TriggerType.MODULE_ALERT is marked as observed rather than documented.
  • History timestamps are the controller's local time with no offset, so EventLogEntry keeps them as text and its timestamp property returns a naive datetime. The registered converter would otherwise mark them UTC.
  • Subscribing turns on ELENABLE <type> ON, which stays on after the client disconnects, the same as the existing enhanced log subscriptions.

How it was tested

  • New tests:
    • each IDiagnostic call, including empty replies, addressing another master, and unreadable fields;
    • trigger and system log parsing, including lines of the other shapes;
    • subscribing and unsubscribing with reference counting;
    • the status handler skipping non-status lines.
  • pytest, ruff check, ruff format --check and pyright pass.
  • Run against a live controller, including a deliberate breaker trip on one module, which showed up as the trigger, the warning and the offline/online pair above.

Home Assistant

A companion change to home-assistant-vantage builds on these APIs. It adds vantage_trigger and vantage_system_log events, trigger history and system log actions, and per-module connectivity sensors. It is ready, and can be previewed in ptr727/loopj-home-assistant-vantage#9. It will follow as focused PRs once an aiovantage release carrying this change is available to pin, since the integration can't take a git requirement.

🤖 Generated with Claude Code

Add DiagnosticInterface for the read-only IDiagnostic methods InFusion
Diagnostics uses for its History and Log views: the trigger history, the
system log, and the modules answering on an enclosure's bus. Add
EventStream.subscribe_triggers and subscribe_system_log for the live
EVENT and SYSTEM enhanced logs, and have the controllers' enhanced log
handler skip lines that are not object status.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The reviewed changes have no unresolved blocking issues and all approval assessments indicate readiness.

No open issues 🎉

What changed in this PR

Adds read-only diagnostic APIs and live trigger/system-log subscriptions to aiovantage, exposing controller history, system logs, module status, and enhanced log events.

Changes:

  • Adds DiagnosticInterface methods and models for event history, system logs, and module status.
  • Adds trigger and system-log enums, parsers, and live subscription support.
  • Filters non-status enhanced-log messages before object status handling.
  • Adds tests and usage examples for the new functionality.
File Description
tests/​controllers/​test_base.py Tests filtering non-status enhanced-log messages.
tests/​config_client/​test_diagnostic.py Tests diagnostic RPC serialization, parsing, addressing, and empty replies.
tests/​command_client/​test_events.py Tests log parsing, subscriptions, peers, reference counting, and filtering.
src/​aiovantage/​events.py Adds parsed trigger and system-log event models.
src/​aiovantage/​config_client.py Exports diagnostic interfaces, models, and log enums.
src/​aiovantage/​_log_types.py Defines trigger and system-log type enums.
src/​aiovantage/​_controllers/​base.py Filters non-object enhanced-log messages before status handling.
src/​aiovantage/​_config_client/​interfaces/​diagnostic.py Defines diagnostic RPC models and read-only interface methods.
src/​aiovantage/​_command_client/​events.py Implements live trigger and system-log subscriptions.
examples/​config_client/​dump_diagnostics.py Demonstrates reading diagnostic history, logs, and modules.
examples/​command_client/​monitor_triggers.py Demonstrates monitoring live triggers and system-log events.

Review effort: Lite

@loopj

loopj commented Oct 22, 2026

Copy link
Copy Markdown
Owner

Thanks @ptr727! Can you please split this into separate PRs for each of the functional changes

  • IDiagnostic interface
  • Trigger log
  • System log

These are three unrelated changes.

@ptr727

ptr727 commented Oct 22, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @loopj, split as asked into three PRs. Each one carries a single commit of its own:

#407 and #408 are stacked because they reuse the log type enums from #406, and the trigger and system log subscriptions touch the same files. Each PR's last commit is the one to review. Closing this one in favor of those.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants