Skip to content

Add safer HA program selection helpers for hOn dishwasher and oven devices. - #317

Open
astrinh0 wants to merge 2 commits into
gvigroux:masterfrom
astrinh0:jveloso-addprograms
Open

Add safer HA program selection helpers for hOn dishwasher and oven devices.#317
astrinh0 wants to merge 2 commits into
gvigroux:masterfrom
astrinh0:jveloso-addprograms

Conversation

@astrinh0

@astrinh0 astrinh0 commented May 27, 2026

Copy link
Copy Markdown
Contributor

Summary

Add safer Home Assistant program selection helpers for hOn dishwasher and oven devices.

Changes

  • Enable select and number program helpers for startProgram.
  • Add startProgram helper entities only for:
    • Dishwasher appliance type 9
    • Oven appliance type 4
  • Expose program selection and program options from hOn command metadata.
  • Keep helper entity changes local only.
  • Keep appliance start behind the existing explicit hon.start_program service.
  • Prevent stale cached program values from overriding a newly selected program.
  • Ensure multi-program commands always include program in the final payload.
  • Prevent program from being added to ancillary parameters.
  • Avoid duplicate number entities for startProgram range parameters.
  • Limit the program-details button to dishwasher/oven devices with startProgram.

Safety

No new start button is added.

The new select and number entities only prepare the local startProgram command state. They do not start an appliance and do not send settings to hOn by themselves.

Tested

  • Simulated dishwasher model XI 6B0S3FSB

    • Select program
    • Reselect another program
    • Select the first program again
    • Set options
    • Confirm no command is sent by entity changes
  • Simulated oven model H6 ID46G3YTB

    • Select program
    • Reselect another program
    • Select the first program again
    • Set tempSel, prTime, and preheatStatus
    • Confirm no command is sent by entity changes
  • Simulated final startProgram payload creation for both models.

  • Verified program is sent in parameters, not ancillaryParameters.

  • Verified final dishwasher payload:

    • commandName: startProgram
    • applianceType: DW
    • parameters: delayTime, extraDry, program
    • ancillaryParameters: empty
  • Verified final oven payload:

    • commandName: startProgram
    • applianceType: OV
    • parameters: tempSel, prTime, preheatStatus, program
    • ancillaryParameters: empty
  • Verified no accidental send() / settings_command() calls remain in the new select, number, or program-details button paths.

  • Ran syntax checks for changed Home Assistant files that local Python can parse.

Limitations

Real hOn cloud acceptance still needs validation in a live Home Assistant environment with the actual appliances connected.

@astrinh0 astrinh0 changed the title feat: update code Add safer Home Assistant program selection helpers for hOn dishwasher and oven devices. May 27, 2026
@astrinh0 astrinh0 changed the title Add safer Home Assistant program selection helpers for hOn dishwasher and oven devices. Add safer HA program selection helpers for hOn dishwasher and oven devices. May 27, 2026
foXaCe added a commit to foXaCe/hon that referenced this pull request Aug 8, 2026
…mName, password-change error, program helpers

Adapt interesting upstream (gvigroux/hon) PRs to the refactored fork:
- gvigroux#336: appliances without a command set (e.g. TVs) handled gracefully (debug log, no error)
- gvigroux#335: optional 'series' field in load_commands (no KeyError)
- gvigroux#332: add programName to startProgram commands for WM/WD
- gvigroux#318: detect ChangePassword redirect -> HonPasswordChangeRequiredError, actionable config flow error (password_change_required) in user/reauth/reconfigure + translations
- gvigroux#317: limit 'Get programs details' button to oven/dishwasher (PROGRAM_HELPER_APPLIANCE_TYPES) + don't propagate 'program' parameter in start_command
- Ignored gvigroux#341 (induction hob) and gvigroux#342 (pt-PT) per decision
- 3 new tests (password change, missing series, button OV/DW), 410 total
foXaCe added a commit to foXaCe/hon that referenced this pull request Aug 8, 2026
* chore: overhaul state file

* docs: overhaul state (phase 0/0.5/1 done)

* refactor: architecture & coordinator

- New typed coordinator HonBaseCoordinator (DataUpdateCoordinator[HonDevice]) with _async_setup one-shot (commands+statistics), UpdateFailed, async_set
- Modern config entry lifecycle: entry.runtime_data, ConfigEntryAuthFailed (translatable), ConfigEntryNotReady, async_on_unload, add_update_listener
- Typed exceptions (HonAuthenticationError/HonConnectionError/HonRateLimitError)
- OptionsFlow with configurable update_interval (30-3600s)
- Cleaned reauth + reconfigure flows (removed dead commented code, modern selectors)
- All platforms migrated from hass.data[DOMAIN] to entry.runtime_data

* docs: overhaul state (phase 2 done)

* refactor: modular structure

- Split monoliths into api/ (client, exceptions, models) and devices/ (base, per-platform entity classes)
- Platforms reduced to async_setup_entry importing from devices/
- Added helpers.py (snake_case, get_key, minutes_until)
- Deduplicated HonBaseEntity (device_info/attributes shared, no more 3x copy)
- Implemented 3 orphan service handlers (turn_off_oven/washingmachine/purifier)
- Removed dead code (async_get_device_ids duplicate, commented blocks, TODO orphans)
- Fixed translation_key bug in HonBaseChildLockStatus
- Fixed get_setting log spam (warning -> debug)
- Replaced deprecated CONCENTRATION_* constants with UnitOfDensity/UnitOfRatio

* docs: overhaul state (phase 3 done)

* fix: api client robustness

- Shared aiohttp session via async_get_clientsession (drop ssl=False private session)
- ClientTimeout(total=30) on every request
- Exponential backoff retry on 429/5xx/ClientError/Timeout (2^n up to 8s)
- Automatic token refresh on 401 with re-entrancy guard (no infinite loop)
- HonRateLimitError for HTTP 429
- Responses closed properly (async with), return parsed JSON
- Eliminated _LOGGER f-strings (lazy %s logging), removed setup log spam
- Fixed non-existent async_get_state call in washing machine service (connectivity via coordinator)
- datetime.utcnow() -> datetime.now(UTC)

* docs: overhaul state (phase 4 done)

* feat: modernize entities

- has_entity_name=True everywhere (HA prefixes device name)
- Unified unique_id format {entry.unique_id}_{mac}_{key} via coordinator.unique_id_prefix
- ConfigEntry VERSION 1->2 + async_migrate_entry: prefix existing unique ids with {email}_ (54 UID stable, verified)
- Activate number & select platforms (were dead code); merged duplicate entity creation, fixed missing .send() on start_command, fixed native_unit_of_measurement typo, fixed HonSelect MRO (HonDevice, SelectEntity) -> (HonBaseEntity, SelectEntity)
- update_sensor matches new prefixed unique_id format

* docs: overhaul state (phase 5 done)

* fix: config flow & fr translations

- Create strings.json (single source of truth, 1329 keys, parity strict with en/fr)
- Full French translations (was 5% coverage) with vouvoiement, strict key parity verified
- Clean dirty en.json data (lockStatuslockStatus, newline keys, test/ending states, broken config error)
- Add entity.binary_sensor.lockstatus + exceptions.auth_failed translations
- Clean services.yaml: typos (Botton->Bottom, ºC->°C), inconsistent defaults (30°->30, 400 rpm->400, 15 min->15), simplify huge send_custom_request default
- Align all 28 YAML services with handlers
- hassfest: 0 invalid integrations

* docs: overhaul state (phase 6 done)

* chore: typing + docstrings + hassfest

- from __future__ import annotations on all 30 files
- mypy --strict: 0 errors (fixed async_get_options_flow to new 2026.8 @staticmethod @callback pattern)
- 237 docstrings added across 22 files
- Switch available log spam: warning -> debug
- manifest.json: add loggers
- hassfest: 0 invalid integrations

* docs: overhaul state (phase 7 done)

* test: exhaustive test suite, coverage >= 90%

- 402 tests, 96% coverage (100% on all critical modules)
- tests/: conftest, config_flow (20), init (9), coordinator (13), client (38), helpers (11), parameter (25), device (44), command (11), services (7), devices/* (sensor, binary_sensor, switch, number, select, button, climate, water_heater)
- Fixed 2 real bugs found by tests:
  * HonOptionsFlowHandler overwrote read-only config_entry (options flow crashed on HA >= 2026.7)
  * HonDevice.set wrote into a recreated dict (value never persisted)
- ruff check+format green on code and tests, mypy strict green
- pre-commit mypy: run on whole package (pass_filenames=false) to avoid namespace collision

* docs: overhaul state (phase 8 done)

* chore: final validation, changelog, architecture

- Remove .overhaul-state.md (overhaul complete)
- CHANGELOG.md updated with all phases
- ARCHITECTURE.md rewritten for the modular structure
- Parallelize appliance context loading at setup (6.91s vs 8.93s baseline, faster boot)
- Remove duplicate load_commands/load_statistics calls (already in coordinator _async_setup)

* feat: localize entities (FR) + config flow & options translations + diagnostics

- Entity names moved from hard-coded English _attr_name to translation_key (HA resolves FR/EN): 100 keys added (sensor, binary_sensor, switch, button), strict parity strings/en/fr (1432 keys)
- Fixed invalid auto translation keys (start_time, statistics_programs_counter, water_hardness, haier_detergent_weight...)
- Config flow + options flow fully translated to French
- Added diagnostics.py (entry/appliances/coordinators/devices/entities snapshot, async_redact_data)
- Fixed options flow 500 error (async_get_options_flow passed config_entry to constructor that takes none)
- Tests updated to assert translation_key; added test_diagnostics; 404 tests, 96% coverage
- hassfest green, mypy strict green, unique_id stability preserved (71/71)

* feat: system health, README/docs update

- system_health.py: cloud reachability, appliance count, coordinator update status
- Tests for system health (406 tests total, 96% coverage)
- README: document options flow and reauth
- CHANGELOG: record system health + translations

* feat: localize button notifications + mode/phase/error entity names

- Button notifications (programs/settings details) in French, program titles translated via entity translations (program: value kept raw for the service call)
- Add missing 'name' to mode/phase/error/program translations (were state-only, entities showed no name)
- Fix fr.json using English names for wash_program_phase/washingmachine_error
- Add test asserting French notification text + translated title
- hassfest green, 407 tests, parity strict (1449 keys)

* perf: cut config entry setup time ~2.5x

- Remove redundant per-platform refreshes at setup: sensor (1x), switch (9x), climate (re-first-refresh after __init__ already refreshed)
- Parallelize load_commands + load_statistics in coordinator _async_setup
- Config entry setup: ~3.5-4s vs 8.93s baseline (measured on HA dev, 2 appliances)
- authorize (~2.1s, 3 dependent CIAM calls) is the remaining dominant cost
- Update test_sensor_platform (no longer awaits per-appliance refresh)
- 407 tests green, mypy/ruff green, 71 entities stable

* fix: audit findings — branding, min HA version, parallel updates, docs

- Add brand/ assets (icon 256/512, logo) for Bronze 'brands' rule (local bundle, modern 2026.3 method)
- Fix hacs.json + README min HA version 2024.1 -> 2026.7 (code uses UnitOfDensity/UnitOfRatio from 2026.7)
- Add PARALLEL_UPDATES to all platforms (0 for read-only with coordinator, 1 for action platforms) — Silver 'parallel-updates'
- README: add Removal, Data updates, Use cases, Examples, Known limitations sections — Gold docs rules
- Audit against Quality Scale of 2026-08-09, HA 2026.8

* fix: sanitize sensitive payload logging (CodeQL)

- CodeQL: 2 high-severity alerts logging full command payloads (mac, parameters) in debug
- Sanitize all payload logs in api/client.py: log mac/type/command/resultCode only, never full payloads or appliance lists
- Sanitize appliance list log in __init__.py (MAC addresses only)

* feat: adapt upstream PRs — empty command set, optional series, programName, password-change error, program helpers

Adapt interesting upstream (gvigroux/hon) PRs to the refactored fork:
- gvigroux#336: appliances without a command set (e.g. TVs) handled gracefully (debug log, no error)
- gvigroux#335: optional 'series' field in load_commands (no KeyError)
- gvigroux#332: add programName to startProgram commands for WM/WD
- gvigroux#318: detect ChangePassword redirect -> HonPasswordChangeRequiredError, actionable config flow error (password_change_required) in user/reauth/reconfigure + translations
- gvigroux#317: limit 'Get programs details' button to oven/dishwasher (PROGRAM_HELPER_APPLIANCE_TYPES) + don't propagate 'program' parameter in start_command
- Ignored gvigroux#341 (induction hob) and gvigroux#342 (pt-PT) per decision
- 3 new tests (password change, missing series, button OV/DW), 410 total

* fix: remove MAC identifiers from logs (CodeQL)

- CodeQL flags MAC addresses and appliance identifiers as sensitive data even in debug logs
- Replace identifier-bearing logs with counts/result codes only (appliances loaded N, resultCode, command type)
- No MAC/email/serial identifiers logged anywhere anymore
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