Skip to content

refactor: handle incomplete Hive API state responses without error logs - #162

Merged
KJonline merged 3 commits into
devfrom
fix-heating-mode-keyerror
Oct 15, 2026
Merged

KJonline merged 3 commits into
devfrom
fix-heating-mode-keyerror

Conversation

@KJonline

Copy link
Copy Markdown
Contributor

Replace try/except KeyError blocks in heating/hotwater get_mode with early returns when state.mode is missing. Add _keep_missing_state to PollingMixin that carries over dropped state keys from the previous poll for up to MAX_STALE_STATE_POLLS (5) consecutive incomplete responses, logging a warning per poll listing affected products and missing keys, plus a debug log showing the keys that did arrive. After the threshold, accept

Replace try/except KeyError blocks in heating/hotwater get_mode with early
returns when state.mode is missing. Add _keep_missing_state to PollingMixin
that carries over dropped state keys from the previous poll for up to
MAX_STALE_STATE_POLLS (5) consecutive incomplete responses, logging a
warning per poll listing affected products and missing keys, plus a debug
log showing the keys that did arrive. After the threshold, accept
Comment thread src/session/polling.py
@claude

claude Bot commented Oct 10, 2026

Copy link
Copy Markdown

🤖 Claude Code Review

Verdict: Mostly sound, but the carry-over of "missing" state keys can show stale state in Home Assistant. Should fix before merge.

Bugs

  • _keep_missing_state (src/session/polling.py) carries over every state key absent from a response, with no allowlist. When Hive legitimately drops a key (e.g. boost after boost ends, colour keys after a light changes mode), the old value is reported for up to 5 polls. See the inline comment.

Other findings

  • Minor: _stale_state_polls entries for products that leave the response are never cleaned up.
  • Tests cover the new paths well (get_mode with no mode, the polling merge, the cap, the reset). There is no test for a key that is legitimately removed.

Home Assistant check: fetched climate.py. It reads self.device["status"]["boost"] == "ON" and HIVE_TO_HASS_STATE.get(self.device["status"]["mode"]). A stale boost therefore shows directly in the UI. A None mode from get_mode is handled by .get().

Not reviewed: the sync (pyhiveapi) generated package, which is built from this source.


Automated review by Claude Code · workflow run

@codecov

codecov Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.96%. Comparing base (8acdfc3) to head (1c1a94a).
⚠️ Report is 1 commits behind head on dev.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##              dev     #162   +/-   ##
=======================================
  Coverage   99.96%   99.96%           
=======================================
  Files          30       30           
  Lines        2576     2599   +23     
  Branches      297      306    +9     
=======================================
+ Hits         2575     2598   +23     
  Partials        1        1           
Flag Coverage Δ
unittests 99.96% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/devices/heating.py 100.00% <100.00%> (ø)
src/devices/hotwater.py 100.00% <100.00%> (ø)
src/session/__init__.py 100.00% <100.00%> (ø)
src/session/polling.py 99.40% <100.00%> (+0.13%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Keys Hive may legitimately omit (boost, the colour keys) were kept from
the previous poll for up to five polls, which could report stale state
such as boost ON. Carry over only mode, name, status and target, and
drop the per-product count for products that leave the response.

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

claude Bot commented Oct 10, 2026

Copy link
Copy Markdown

🤖 Claude Code Review

Verdict: Looks good. I found no blocking bugs, and the concerns from the earlier review are addressed.

Bugs: none found.

Other findings

  • Minor: a required key (e.g. target) that Hive drops on purpose is kept for up to 5 polls (MAX_STALE_STATE_POLLS) before the response is accepted. This is bounded and logged, so I'm treating it as acceptable.
  • Checked: the get_mode rewrite in heating.py and hotwater.py behaves as before for present keys. _get_product_state already catches KeyError and TypeError, so a missing product or state block returns None. Both get_mode methods now return None quietly instead of logging an error.
  • Checked: the earlier review's points are fixed. Only REQUIRED_STATE_KEYS are carried over, and _stale_state_polls entries are removed for products that leave the response. Tests cover both.
  • Tests: the new paths are covered (carry-over, cap, reset, optional keys, cleanup).

Home Assistant check: I fetched climate.py. It reads HIVE_TO_HASS_STATE.get(self.device["status"]["mode"]), so a None mode is handled. It also reads self.device["status"]["boost"] == "ON". boost is no longer carried over, so a stale boost can't appear.

Not reviewed: the generated sync pyhiveapi package.


Automated review by Claude Code · workflow run

@KJonline
KJonline merged commit 102cd55 into dev Oct 15, 2026
11 checks passed
@KJonline
KJonline deleted the fix-heating-mode-keyerror branch October 15, 2026 17:57
@claude

claude Bot commented Oct 15, 2026

Copy link
Copy Markdown

🤖 Claude Code Review

Verdict: Looks good. I found no blocking bugs.

Bugs: none found.

Other findings

  • Minor: a required key (target, mode, etc.) that Hive drops on purpose is kept for up to 5 polls (MAX_STALE_STATE_POLLS) before it is accepted as dropped. This is bounded and logged, so it is acceptable.
  • Checked: the get_mode rewrite in heating.py and hotwater.py behaves as before when the keys are present. A missing state or mode now returns None and logs at debug level instead of error.
  • Checked: _keep_missing_state only carries over REQUIRED_STATE_KEYS. It clears _stale_state_polls entries for products that leave the response. Tests cover the carry-over, the cap, the reset and the cleanup.

Home Assistant check: I fetched climate.py. It reads HIVE_TO_HASS_STATE.get(self.device["status"]["mode"]) and self.device["status"]["boost"] == "ON", and it refreshes through updateData and getClimate. A None mode is handled by .get(). boost is not carried over, so it can't go stale. No public API names or return shapes changed.

Not reviewed: the generated sync pyhiveapi package.


Automated review by Claude Code · workflow run

@KJonline
KJonline restored the fix-heating-mode-keyerror branch October 15, 2026 17:59
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