Skip to content

Release v2.3 — Critical fixes & improvements - #1

Merged
telard-pixel merged 3 commits into
mainfrom
dev
Jun 12, 2026
Merged

Release v2.3 — Critical fixes & improvements#1
telard-pixel merged 3 commits into
mainfrom
dev

Conversation

@telard-pixel

Copy link
Copy Markdown
Collaborator

Critical Fixes

  • Removed duplicate run_command_sync() in hon_client.py

Major Fixes

  • Simplified HVACMode enum handling
  • Used constants from const.py for consistency
  • Fixed fallback target_temperature (now returns None)

Minor Fixes

  • Fixed program 0 (Cotton) selection in select.py

Testing

  • 3 devices loaded correctly (AC, Washer, Dryer)
  • All commands working
  • 0 errors in extended logs

Requirements

  • Home Assistant ≥ 2024.1
  • pyhOn ≥ 0.17.5

tis24dev added 3 commits June 12, 2026 22:58
- clean up HonClient lifecycle failures and setup/unload cancellation paths

- route command entities through their owning config-entry client

- fail closed on missing sessions, appliance-list failures, partial updates, auth/reauth failures, and typed timeouts

- classify auth vs retryable server errors in config flow, setup, and coordinator refresh

- surface select/switch/climate command failures as HomeAssistantError

- validate and roll back climate settings parameter assignment before sending

- force post-command refresh through direct coordinator refresh and fail on stored refresh errors

- add focused unittest coverage with Home Assistant stubs
- add explicit start/stop button entities for physical program actions

- remove the misleading start/stop power switch

- only expose program select for safe non-start program commands

- stop using washer-only static program labels for dryer-capable selects

- cover button platform forwarding, routing, and no-startProgram select regressions
@telard-pixel
telard-pixel merged commit aaa1cf8 into main Jun 12, 2026
tis24dev added a commit that referenced this pull request Jun 23, 2026
…t refresh

Audit findings #1 (HIGH) and #14, plus the concurrent-refresh race.

_check_headers refreshed the OAuth token before EVERY request whenever a
refresh_token was present (#1): with several appliances and the asyncio.gather
in load_commands, that is dozens of POST /services/oauth2/token per coordinator
cycle (token is valid 8h), risking cloud rate-limit/block. A single 401 also
cascaded into 3 refreshes (#14: pre-refresh + loop0 + recursion).

Refresh only when there is no usable in-RAM token (first request / restart with a
persisted refresh_token) or the token is near expiry; the 401 recovery in
_intercept is unchanged, and since refresh() resets _expires the recursive
_check_headers no longer fires a second time. An asyncio.Lock (on the connection,
not the create()-replaced HonAuth) with a re-check collapses a concurrent burst
into a single refresh, so a rotating IdP cannot invalidate the shared token
mid-flight.

Tests: no pre-refresh when fresh (#1), single refresh on 401 (#14), refresh on
expires-soon, restart-with-token refreshes not logins, concurrent burst -> 1
refresh (lock).
tis24dev added a commit that referenced this pull request Jun 23, 2026
…t refresh

Audit findings #1 (HIGH) and #14, plus the concurrent-refresh race.

_check_headers refreshed the OAuth token before EVERY request whenever a
refresh_token was present (#1): with several appliances and the asyncio.gather
in load_commands, that is dozens of POST /services/oauth2/token per coordinator
cycle (token is valid 8h), risking cloud rate-limit/block. A single 401 also
cascaded into 3 refreshes (#14: pre-refresh + loop0 + recursion).

Refresh only when there is no usable in-RAM token (first request / restart with a
persisted refresh_token) or the token is near expiry; the 401 recovery in
_intercept is unchanged, and since refresh() resets _expires the recursive
_check_headers no longer fires a second time. An asyncio.Lock (on the connection,
not the create()-replaced HonAuth) with a re-check collapses a concurrent burst
into a single refresh, so a rotating IdP cannot invalidate the shared token
mid-flight.

Tests: no pre-refresh when fresh (#1), single refresh on 401 (#14), refresh on
expires-soon, restart-with-token refreshes not logins, concurrent burst -> 1
refresh (lock).
tis24dev added a commit that referenced this pull request Jun 23, 2026
…t refresh

Audit findings #1 (HIGH) and #14, plus the concurrent-refresh race.

_check_headers refreshed the OAuth token before EVERY request whenever a
refresh_token was present (#1): with several appliances and the asyncio.gather
in load_commands, that is dozens of POST /services/oauth2/token per coordinator
cycle (token is valid 8h), risking cloud rate-limit/block. A single 401 also
cascaded into 3 refreshes (#14: pre-refresh + loop0 + recursion).

Refresh only when there is no usable in-RAM token (first request / restart with a
persisted refresh_token) or the token is near expiry; the 401 recovery in
_intercept is unchanged, and since refresh() resets _expires the recursive
_check_headers no longer fires a second time. An asyncio.Lock (on the connection,
not the create()-replaced HonAuth) with a re-check collapses a concurrent burst
into a single refresh, so a rotating IdP cannot invalidate the shared token
mid-flight.

Tests: no pre-refresh when fresh (#1), single refresh on 401 (#14), refresh on
expires-soon, restart-with-token refreshes not logins, concurrent burst -> 1
refresh (lock).
tis24dev added a commit that referenced this pull request Jun 25, 2026
#2, #5)

- _persist_refresh_token: update the config entry only when the live refresh
  token actually rotated (at setup and on each coordinator poll), so a rotated
  token survives a restart instead of replaying a stale one (#2).
- HonClient: re-seed the stored refresh token after setup, after MFA verify, and
  after each poll, so a mid-life rotation is not lost on the next refresh (#1, #5).
- tests: change-guarded persist (AST-checked call sites), mid-life rotation
  seed-sync, and the reauth re-seed handoff.
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.

2 participants