Skip to content

Release v5.1.0#29

Merged
tis24dev merged 5 commits into
mainfrom
dev
Jun 22, 2026
Merged

Release v5.1.0#29
tis24dev merged 5 commits into
mainfrom
dev

Conversation

@tis24dev

@tis24dev tis24dev commented Jun 22, 2026

Copy link
Copy Markdown
Owner

Automated release PR for v5.1.0.

Summary by CodeRabbit

  • New Features

    • Added an “addhOn diagnostics” device with per-account debug controls.
    • Added debug switches (integration debug + MQTT realtime debug), plus Force refresh and Reset debug actions.
    • Added diagnostic sensors (debug status, log levels, appliances discovered, last refresh) and an update OK indicator.
  • Documentation

    • Updated the README with step-by-step debug log capture instructions and the new diagnostics device workflow.
    • Added dedicated documentation for the diagnostics device with dashboard examples and guidance.
  • Bug Fixes / Improvements

    • Refined diagnostics coverage reporting to reduce noise and improve attribution.

Greptile Summary

This PR introduces the "addhOn diagnostics" device — a synthetic per-account service device that surfaces the integration's debug controls (two persisted switches, two action buttons, five read-only sensors, one binary sensor) directly from a Home Assistant dashboard, without requiring the Options flow dialog. It also refactors the _coverage() diagnostic helper to partition unmapped attributes into signal, statistics, and meta/noise buckets.

  • New HonAccountEntity / HonAccountCoordinatorEntity base classes group all diagnostics-device entities and keep them distinct from appliance entities via the _addhon_account marker.
  • diagnostics.py coverage calculation now correctly carves out protocol envelope blobs, scalar debug/protocol noise, and program-definition slots into an _unmapped_meta bucket so the attributes_total denominator reflects only genuine telemetry and control candidates; tests pin both the denylists and the partition invariants.
  • Comprehensive test_debug_panel.py covers lifecycle, state sync, idempotency, and reset behavior with hand-rolled HA stubs consistent with the project's existing test style.

Confidence Score: 5/5

Safe to merge — all new entities follow established HA lifecycle patterns, state sync is covered by tests, and no existing appliance entity logic is touched.

The diagnostics device entities are well-isolated behind the _addhon_account marker, the entry-listener teardown is handled via async_on_remove, and the coordinator-always-available override is intentional and tested. The two carry-over style observations from previous reviews (a redundant state write in HonDebugSwitch._async_set and a dead-code seeding block with a misleading comment in HonLastRefreshSensor) are harmless and non-blocking.

No files require special attention.

Important Files Changed

Filename Overview
custom_components/addhon/base_entity.py Adds HonAccountEntity mixin and HonAccountCoordinatorEntity (always-available CoordinatorEntity subclass) for diagnostics-device entities; clean MRO and explicit init calls for each parent.
custom_components/addhon/switch.py Adds HonDebugSwitch (two per entry, persisted via entry.options); previously noted redundant async_write_ha_state() after async_update_entry is still present but non-blocking.
custom_components/addhon/sensor.py Adds five diagnostic sensors (debug status ENUM, two log-level strings, appliances count, last refresh timestamp); seeding block in HonLastRefreshSensor.async_added_to_hass() is dead code in production (previously noted) but harmless.
custom_components/addhon/button.py Adds HonForceRefreshButton (triggers coordinator refresh) and HonResetDebugButton (clears both toggles and resets logger levels); reset correctly fires entry-update listeners only when toggles were on.
custom_components/addhon/binary_sensor.py Adds HonUpdateOkBinarySensor (CONNECTIVITY device class, always available) to show whether the last coordinator refresh succeeded; correctly overrides available to stay visible on failed refreshes.
custom_components/addhon/diagnostics.py Coverage helper refactored to partition unmapped attrs/params into signal, statistics, and meta buckets; total denominator now excludes meta so coverage gap is meaningful; partition is provably lossless and disjoint via new tests.
tests/test_debug_panel.py New comprehensive test file covering all diagnostics entities: switch state sync, idempotency, entry-listener registration, sensor value mapping, seeding, coordinator-update propagation, and button press behavior.
custom_components/addhon/init.py Fetches integration version via async_get_integration for the diagnostics device sw_version field; failure is caught and logged at DEBUG, making it cosmetic-only.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    subgraph HA["Home Assistant"]
        OPT["Options Flow\n(Configure dialog)"]
        SVC["set_log_level service"]
        COORD["DataUpdateCoordinator"]
    end

    subgraph DEV["addhOn diagnostics device (per account)"]
        SW1["HonDebugSwitch\n(debug_logging)"]
        SW2["HonDebugSwitch\n(mqtt_realtime_debug)"]
        BTN1["HonForceRefreshButton\n(Refresh now)"]
        BTN2["HonResetDebugButton\n(Reset debug)"]
        SEN1["HonDebugStatusSensor\n(off/integration/mqtt/full)"]
        SEN2["HonLogLevelSensor\n(integration)"]
        SEN3["HonLogLevelSensor\n(mqtt)"]
        SEN4["HonAppliancesCountSensor"]
        SEN5["HonLastRefreshSensor"]
        BIN["HonUpdateOkBinarySensor"]
    end

    ENTRY["entry.options\n(CONF_ENABLE_DEBUG\nCONF_ENABLE_MQTT_DEBUG)"]
    LOGGERS["Python Loggers\n(custom_components.addhon\n+ mqtt transport)"]

    SW1 -->|async_update_entry| ENTRY
    SW2 -->|async_update_entry| ENTRY
    BTN2 -->|async_update_entry + reset levels| ENTRY
    BTN2 --> LOGGERS
    BTN1 -->|async_request_refresh| COORD
    OPT -->|async_update_entry| ENTRY

    ENTRY -->|add_update_listener fires| SW1
    ENTRY -->|add_update_listener fires| SW2
    ENTRY -->|add_update_listener fires| SEN1

    SVC --> LOGGERS
    LOGGERS -->|poll| SEN2
    LOGGERS -->|poll| SEN3

    COORD -->|_handle_coordinator_update| SEN4
    COORD -->|_handle_coordinator_update| SEN5
    COORD -->|last_update_success| BIN
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    subgraph HA["Home Assistant"]
        OPT["Options Flow\n(Configure dialog)"]
        SVC["set_log_level service"]
        COORD["DataUpdateCoordinator"]
    end

    subgraph DEV["addhOn diagnostics device (per account)"]
        SW1["HonDebugSwitch\n(debug_logging)"]
        SW2["HonDebugSwitch\n(mqtt_realtime_debug)"]
        BTN1["HonForceRefreshButton\n(Refresh now)"]
        BTN2["HonResetDebugButton\n(Reset debug)"]
        SEN1["HonDebugStatusSensor\n(off/integration/mqtt/full)"]
        SEN2["HonLogLevelSensor\n(integration)"]
        SEN3["HonLogLevelSensor\n(mqtt)"]
        SEN4["HonAppliancesCountSensor"]
        SEN5["HonLastRefreshSensor"]
        BIN["HonUpdateOkBinarySensor"]
    end

    ENTRY["entry.options\n(CONF_ENABLE_DEBUG\nCONF_ENABLE_MQTT_DEBUG)"]
    LOGGERS["Python Loggers\n(custom_components.addhon\n+ mqtt transport)"]

    SW1 -->|async_update_entry| ENTRY
    SW2 -->|async_update_entry| ENTRY
    BTN2 -->|async_update_entry + reset levels| ENTRY
    BTN2 --> LOGGERS
    BTN1 -->|async_request_refresh| COORD
    OPT -->|async_update_entry| ENTRY

    ENTRY -->|add_update_listener fires| SW1
    ENTRY -->|add_update_listener fires| SW2
    ENTRY -->|add_update_listener fires| SEN1

    SVC --> LOGGERS
    LOGGERS -->|poll| SEN2
    LOGGERS -->|poll| SEN3

    COORD -->|_handle_coordinator_update| SEN4
    COORD -->|_handle_coordinator_update| SEN5
    COORD -->|last_update_success| BIN
Loading

Comments Outside Diff (2)

  1. custom_components/addhon/sensor.py, line 495-503 (link)

    P2 Seeding logic is dead code in production and comment is inaccurate

    CoordinatorEntity.async_added_to_hass() already calls self._handle_coordinator_update() when coordinator.data is not None — and since async_setup_entry runs async_config_entry_first_refresh() before entities are registered, data is always non-None at this point. As a result, _attr_native_value is already populated (via HonLastRefreshSensor._handle_coordinator_update) by the time the seeding if block runs, so the condition is always False in normal operation. The comment claiming "the update only fires on subsequent cycles" contradicts how CoordinatorEntity.async_added_to_hass works.

    The seeding block is harmless (covers the theoretical data is None edge case) but the misleading comment could confuse future maintainers reviewing HA lifecycle behaviour here.

    Fix in Claude Code Fix in Cursor Fix in Codex

  2. custom_components/addhon/switch.py, line 615-628 (link)

    P2 Double state write after async_update_entry

    async_update_entry fires the entry update listener synchronously in HA, which triggers _async_entry_updated → async_write_ha_state(). The explicit self.async_write_ha_state() on line 628 then writes a second time within the same task. HA coalesces these, so there is no correctness issue, but it is redundant. The _async_entry_updated listener alone already covers this case.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

    Fix in Claude Code Fix in Cursor Fix in Codex

Reviews (2): Last reviewed commit: "test(switch): validate AC switch params ..." | Re-trigger Greptile

tis24dev and others added 3 commits June 22, 2026 11:42
Surface the integration's debug controls on a dedicated, per-config-entry
"addhOn diagnostica" service device instead of hiding them in Options ->
Configure and the developer-tools services. One set of entities per entry
(the loggers are process-global, so they are NOT per appliance):

- switch: Debug logging, MQTT realtime debug -- mirror entry.options (single
  source of truth), re-apply log levels live via the existing options update
  listener (no reload), and stay in sync with the Options flow / Reset button
  through an entry update listener.
- sensor: Debug status (enum off/integration/mqtt/full), Integration/MQTT log
  level (effective level, reflects runtime set_log_level overrides), Appliances
  discovered, Last refresh (timestamp, seeded on add, advanced on refresh).
- binary_sensor: Update OK (connectivity; stays available through a failed
  refresh so the OFF state is actually shown).
- button: Refresh now, Reset debug (clears runtime overrides + persists both
  toggles off).

Shared foundations in base_entity.py (account_device_info, HonAccountEntity,
HonAccountCoordinatorEntity); sw_version resolved once in __init__ via a lazy
async_get_integration. en/it translations at parity. New docs/debug-device.md
with core-card YAML, plus README + discovery/MQTT doc cross-links.

Tests: new tests/test_debug_panel.py (switch persistence/sync, sensor mappings,
last-refresh seed/advance, button reset) with a scoped lifecycle patch over the
bare shared HA stubs; existing platform tests filter the account entities out of
their appliance-level assertions.
…bug steps

The "addhOn diagnostica" service device carried a hardcoded Italian name, the
odd one out in an otherwise English-base / EN-IT-translated UI. Make it follow
the UI language like the entity names: drop the literal name for
translation_key="diagnostics" and add a "device" section to en.json
("addhOn diagnostics") and it.json ("addhOn diagnostica"). model has no
translation hook in HA, so it becomes English ("Diagnostics & debug").

Docs/README: the device name and its entity-id slug now depend on the HA
language; README uses the English name, docs/debug-device.md shows the English
slug (addhon_diagnostics_*) and notes the Italian one. README also gains a
concise step-by-step "Capture debug logs" block (enable -> reproduce ->
download full log -> reset).

Tests: extend the translation_key-literal check to recognize the top-level
"device" translation section (still required in both languages).
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6874cb4f-7c23-4917-9e4e-1da75c0f0ddb

📥 Commits

Reviewing files that changed from the base of the PR and between 8cc0ac2 and fce9bee.

⛔ Files ignored due to path filters (1)
  • tests/fixtures/ac_as35/settings_command_params.json is excluded by !tests/fixtures/**
📒 Files selected for processing (3)
  • custom_components/addhon/diagnostics.py
  • tests/test_diagnostics.py
  • tests/test_switch_params.py

📝 Walkthrough

Walkthrough

Introduces a synthetic per-account "addhOn diagnostics" Home Assistant service device grouping two debug config switches, five diagnostic sensors, a coordinator-health binary sensor, and two action buttons. Refines diagnostics coverage to partition meta/noise from telemetry signal. Adds fixture-based validation for AC switch parameters. New base entity classes (HonAccountEntity, HonAccountCoordinatorEntity) back all diagnostics entities. Integration version resolved at setup time. Full translations (EN/IT), documentation, README updates, manifest version bump, and comprehensive test coverage included.

Changes

addhOn diagnostics device

Layer / File(s) Summary
Account device base classes and version storage
custom_components/addhon/__init__.py, custom_components/addhon/base_entity.py
async_setup_entry resolves and stores integration_version via async_get_integration. base_entity.py gains account_device_info(), HonAccountEntity, and HonAccountCoordinatorEntity — the base types every new diagnostics entity inherits from.
Debug configuration switches
custom_components/addhon/switch.py
HonDebugSwitch (EntityCategory.CONFIG) reads/writes CONF_ENABLE_DEBUG and CONF_ENABLE_MQTT_DEBUG in entry.options via async_update_entry, registers an entry-update listener to stay synchronized. Two instances appended per config entry in async_setup_entry.
Diagnostic sensor classes
custom_components/addhon/sensor.py
Imports extended, entry_data refactor applied, and five diagnostic sensors registered per entry: HonDebugStatusSensor, HonLogLevelSensor (×2), HonAppliancesCountSensor, and HonLastRefreshSensor.
Action buttons and coordinator health sensor
custom_components/addhon/button.py, custom_components/addhon/binary_sensor.py
HonForceRefreshButton triggers coordinator.async_request_refresh. HonResetDebugButton resets log levels and persists options to False. HonUpdateOkBinarySensor reflects coordinator.last_update_success as a connectivity diagnostic.
Diagnostics coverage meta/noise classification
custom_components/addhon/diagnostics.py
Introduces _COVERAGE_META_ATTRS denylist and regex patterns for program-slot detection. Refactors _coverage() to partition unmapped attributes/parameters into three disjoint buckets: statistics, meta/noise, and signal-only telemetry. Denominators adjusted to exclude meta portions.
Translations, documentation, manifest, and README
custom_components/addhon/translations/en.json, custom_components/addhon/translations/it.json, docs/debug-device.md, README.md, custom_components/addhon/manifest.json
EN/IT translations add device.diagnostics and all new entity keys. docs/debug-device.md documents the device and provides dashboard card examples. README troubleshooting and options sections expanded. Version bumped to 5.1.0.
Test coverage for diagnostics device and refined diagnostics
tests/test_debug_panel.py, tests/test_diagnostics.py, tests/test_entity_availability.py, tests/test_entity_translation_keys.py, tests/test_number_setpoints.py, tests/test_program_select.py, tests/test_sensor_per_type.py, tests/test_tier2_sensors.py
test_debug_panel.py provides full coverage for switches, sensors, and buttons using fake HA objects and lifecycle instrumentation. Existing test modules add DeviceEntryType, EntityCategory, and SensorDeviceClass.TIMESTAMP stubs, wire device_registry onto helpers, and filter _addhon_account entities from appliance-scoped assertions.

AC switch parameter schema validation

Layer / File(s) Summary
Switch parameter fixture validation
tests/test_switch_params.py
Validates _AC_SWITCHES parameter mappings against real Haier AS35 captured schema fixtures. Asserts every configured switch param exists in the real schema, verifies fixture sanity, and pins the exact key -> param mapping with explicit tests.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~65 minutes

Possibly related PRs

  • tis24dev/addhOn#27: Both PRs modify custom_components/addhon/diagnostics.py — the main PR refines diagnostics coverage partitioning and meta-denominator logic while PR #27 rewrites the diagnostics payload/coverage computation pipeline, so they overlap directly in coverage/diagnostics code.

Poem

🐰 Hop hop, a new device appears,
Debug switches wriggling their ears!
A sensor counts appliances found,
A button resets with a single bound.
The logs reset, the timestamps glow—
This rabbit ships v5.1.0! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.70% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Release v5.1.0' directly corresponds to the primary change in this PR—a version bump and release of v5.1.0 with the diagnostics debug panel feature.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
custom_components/addhon/sensor.py (1)

965-1001: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

Consider using a tuple for immutable class attribute.

The static analyzer flags _attr_options as a mutable list. Since these options are never modified at runtime, a tuple would be more appropriate and silence the warning.

♻️ Suggested change
-    _attr_options = ["off", "integration", "mqtt", "full"]
+    _attr_options = ("off", "integration", "mqtt", "full")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@custom_components/addhon/sensor.py` around lines 965 - 1001, The
_attr_options class attribute in the HonDebugStatusSensor class is currently
defined as a mutable list, which triggers a static analyzer warning. Convert
this list to a tuple by replacing the square brackets with parentheses, since
these options are never modified at runtime and should be immutable. This will
silence the warning while maintaining the same functionality.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/debug-device.md`:
- Around line 72-73: The documentation file contains incorrect entity_id
references for the button entity. The actual entity_id generated by the
implementation is button.addhon_diagnostics_force_refresh (based on the
force_refresh translation key and object_id suffix), but the docs incorrectly
reference button.addhon_diagnostics_refresh_now which is the translated display
name, not the entity_id. Update all occurrences of
button.addhon_diagnostics_refresh_now to button.addhon_diagnostics_force_refresh
on lines 72, 101, and 107 in the docs/debug-device.md file to ensure the
dashboard examples work as copy/paste templates.

---

Nitpick comments:
In `@custom_components/addhon/sensor.py`:
- Around line 965-1001: The _attr_options class attribute in the
HonDebugStatusSensor class is currently defined as a mutable list, which
triggers a static analyzer warning. Convert this list to a tuple by replacing
the square brackets with parentheses, since these options are never modified at
runtime and should be immutable. This will silence the warning while maintaining
the same functionality.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e34a56bf-b886-4415-b610-a29fc1b76b58

📥 Commits

Reviewing files that changed from the base of the PR and between 392ef9b and 8cc0ac2.

📒 Files selected for processing (18)
  • README.md
  • custom_components/addhon/__init__.py
  • custom_components/addhon/base_entity.py
  • custom_components/addhon/binary_sensor.py
  • custom_components/addhon/button.py
  • custom_components/addhon/manifest.json
  • custom_components/addhon/sensor.py
  • custom_components/addhon/switch.py
  • custom_components/addhon/translations/en.json
  • custom_components/addhon/translations/it.json
  • docs/debug-device.md
  • tests/test_debug_panel.py
  • tests/test_entity_availability.py
  • tests/test_entity_translation_keys.py
  • tests/test_number_setpoints.py
  • tests/test_program_select.py
  • tests/test_sensor_per_type.py
  • tests/test_tier2_sensors.py

Comment thread docs/debug-device.md
Comment on lines +72 to +73
- entity: button.addhon_diagnostics_refresh_now
name: Refresh now

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "1) Inspect button implementation keys/object suffixes"
rg -n -C2 'class HonForceRefreshButton|_attr_translation_key|super\(.*force_refresh' custom_components/addhon/button.py

echo
echo "2) Find documented entity_ids using refresh_now vs force_refresh"
rg -n -C2 'addhon_diagnostics_(refresh_now|force_refresh)' docs/debug-device.md README.md

echo
echo "3) Check tests (if present) for expected button entity_id/object_id"
rg -n -C2 '(refresh_now|force_refresh)' tests

Repository: tis24dev/addhOn

Length of output: 3000


🏁 Script executed:

find . -type f \( -name "*.json" -o -name "*.yaml" -o -name "*.yml" \) | grep -i -E "(string|translation|locale|en\.json)" | head -20

Repository: tis24dev/addhOn

Length of output: 155


🏁 Script executed:

rg -n "Refresh now|refresh.?now" --type yaml --type json

Repository: tis24dev/addhOn

Length of output: 139


🏁 Script executed:

sed -n '630,650p' custom_components/addhon/translations/en.json

Repository: tis24dev/addhOn

Length of output: 502


Change entity_id from refresh_now to force_refresh in button entity references.

The implementation uses force_refresh as the translation key and object_id suffix, which generates the entity_id button.addhon_diagnostics_force_refresh. The docs incorrectly reference button.addhon_diagnostics_refresh_now (the translated display name, not the entity_id). Update lines 72, 101, and 107 to use the correct entity_id so the dashboard examples work as copy/paste templates.

Affected lines
  - entity: button.addhon_diagnostics_force_refresh
    name: Refresh now

Also applies to: 101-107

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/debug-device.md` around lines 72 - 73, The documentation file contains
incorrect entity_id references for the button entity. The actual entity_id
generated by the implementation is button.addhon_diagnostics_force_refresh
(based on the force_refresh translation key and object_id suffix), but the docs
incorrectly reference button.addhon_diagnostics_refresh_now which is the
translated display name, not the entity_id. Update all occurrences of
button.addhon_diagnostics_refresh_now to button.addhon_diagnostics_force_refresh
on lines 72, 101, and 107 in the docs/debug-device.md file to ensure the
dashboard examples work as copy/paste templates.

tis24dev added 2 commits June 22, 2026 13:04
…ta noise

A live test on 4 real appliances showed coverage.attributes_unmapped /
command_params_unmapped buried the mappable "what to map" signal under protocol
envelope blobs and debug plumbing (commandHistory, lastConnEvent, activity,
parameters, resultCode, transfer-rate scalars, program1..N slots, the command
selector and cloud endpoints).

Partition the unmapped sets so the maintainer reads pure signal first, nothing
dropped:
- attributes_unmapped        - mappable telemetry candidates (the gold);
- attributes_unmapped_statistics - statistics-container keys (unchanged);
- attributes_unmapped_meta   - envelope blobs (value-type dict/list, no list to
  maintain) + scalar debug/protocol denylist + program-slot regex;
- command_params_unmapped / command_params_unmapped_meta - same split.

The value-type rule (dict/list-valued bare key = envelope) needs no name list and
auto-catches future blobs; only the scalar residue (resultCode, debug/transfer-rate
flags, programStats and cloud/test plumbing) and program1..N use a small denylist.
Both denominators (attributes_total, command_params_total) now count mapped + signal
(excluding statistics + meta) so unmapped/total reads as a real coverage gap.

Validated against the live REF/AC/TD/WM dumps and a 3-round adversarial refuter pool:
no over-suppression (genuine warnings softWarn/detWarn and program code prCode kept
as signal, confirmed via the decompiled app), partition lossless/disjoint, denominators
non-negative and symmetric. Tests extended (32 in test_diagnostics, full suite green);
test stubs realigned to the platforms' current homeassistant.const/device_registry
imports.
The per-type entity tests check the entity `key` but not the `param` (the Haier
command-parameter name a switch reads/writes). A wrong `param` makes a
capability-gated switch silently never created on any device, and no key-based
test catches it - this was raised as a false-positive "echoStatus -> ecoStatus"
fix, but echoStatus is the genuine Haier name (verified live on a real AS35 and in
the decompiled hOn app; ecoStatus exists nowhere).

Add tests/test_switch_params.py:
- reality check: every _AC_SWITCHES.param must exist in a real AC's settings
  schema (fixture tests/fixtures/ac_as35/, param names captured from a live
  AS35PBPHRA-PRE diagnostics dump on 2026-06-22; names only, no values/identity);
- a drift-guard pin of the key->param mapping documenting echoStatus as correct;
- fixture-sanity + uniqueness guards.

Verified the test catches the regression: changing eco's param to a non-existent
`ecoStatus` fails both the reality and pin tests. Full suite green (414 passed).
@tis24dev tis24dev merged commit b0d8759 into main Jun 22, 2026
7 of 8 checks passed
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.

1 participant