Skip to content

More 0138-related improvements#425

Merged
bouwew merged 17 commits intomainfrom
pw-0138-2
Mar 11, 2026
Merged

More 0138-related improvements#425
bouwew merged 17 commits intomainfrom
pw-0138-2

Conversation

@bouwew
Copy link
Contributor

@bouwew bouwew commented Mar 10, 2026

Summary by CodeRabbit

  • Bug Fixes

    • Improved relay state initialization with enhanced response handling and error detection for more reliable state synchronization.
  • Chores

    • Version bumped to 0.47.6.

@coderabbitai
Copy link

coderabbitai bot commented Mar 10, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR extends the CircleRelayInitStateRequest messaging system to support dual reply identifiers (0139 and 0100). The PlugwiseRequest framework now handles multiple possible responses, and the Circle node class is updated to interpret both CircleRelayInitStateResponse and NodeAckResponse types with improved error handling.

Changes

Cohort / File(s) Summary
Dual Reply Identifier Support
plugwise_usb/messages/requests.py
Added _reply_identifier_2 attribute to PlugwiseRequest; updated subscribe_to_response to combine and filter multiple reply identifiers; modified CircleRelayInitStateRequest to use identifiers 0139 and 0100 with widened return type to accept both CircleRelayInitStateResponse and NodeAckResponse.
Response Type Changes
plugwise_usb/messages/responses.py
Modified POWER_LOG_INTERVAL_ACCEPTED enum member from plain bytes to tuple format; minor formatting adjustments to related enum entries.
Node-Level Message Handling
plugwise_usb/nodes/circle.py
Updated imports for CircleRelayInitStateResponse and NodeAckResponseType; refactored _relay_init_get to initialize requests within try/except and return boolean state based on response type; updated _relay_init_set to handle MessageError, with explicit response type checks and state-update logic.
Version & Documentation
CHANGELOG.md, pyproject.toml
Version bumped from 0.47.5 to 0.47.6 with changelog entry for PR 425 improvements.

Sequence Diagram

sequenceDiagram
    participant Circle as Circle Node
    participant Request as CircleRelayInitStateRequest
    participant Framework as PlugwiseRequest<br/>(subscribe_to_response)
    participant Response as Response Handler

    Circle->>Request: _relay_init_get()
    Request->>Request: create with _reply_identifier(0139)<br/>+ _reply_identifier_2(0100)
    Request->>Framework: subscribe_to_response(combined_ids)
    Framework->>Framework: filter + combine identifiers<br/>(0139, 0100)
    Framework->>Response: wait for response matching<br/>0139 OR 0100
    
    alt Receives 0139 (CircleRelayInitStateResponse)
        Response->>Circle: return CircleRelayInitStateResponse
        Circle->>Circle: extract + return boolean state
    else Receives 0100 (NodeAckResponse)
        Response->>Circle: return NodeAckResponse
        Circle->>Circle: handle as acknowledgment
    else No response
        Response->>Circle: return None
        Circle->>Circle: return None or raise error
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Add missing response-types #422: Extends message response type definitions (POWER_LOG_INTERVAL_ACCEPTED, Node ack/fail types) that form the foundation for this PR's dual-response handling.
  • Fix 0138 AckResponse #424: Previously modified CircleRelayInitStateRequest to expect only NodeAckResponse (0100); this PR extends it to also handle CircleRelayInitStateResponse (0139) with dual reply support.

Suggested reviewers

  • dirixmjm
  • ArnoutD
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title '0138-related improvements' is vague and uses non-descriptive terminology without clearly conveying the specific changes made to the codebase. Use a more descriptive title that explains the specific technical change, such as 'Add dual reply handling for CircleRelayInitStateRequest' or 'Support multiple response types for 0138 message handling'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch pw-0138-2

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 requested review from ArnoutD and dirixmjm March 10, 2026 11:48
@codecov
Copy link

codecov bot commented Mar 10, 2026

Codecov Report

❌ Patch coverage is 52.77778% with 17 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.76%. Comparing base (8170aaa) to head (62fdd9b).
⚠️ Report is 18 commits behind head on main.

Files with missing lines Patch % Lines
plugwise_usb/nodes/circle.py 37.03% 17 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #425      +/-   ##
==========================================
- Coverage   82.01%   81.76%   -0.25%     
==========================================
  Files          36       36              
  Lines        8177     8195      +18     
==========================================
- Hits         6706     6701       -5     
- Misses       1471     1494      +23     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@plugwise_usb/connection/__init__.py`:
- Around line 235-238: The except clause uses Python 2 syntax "except NodeError,
StickError" which fails under Python 3; update the exception handling in the
method that calls self._queue.submit to catch both exceptions by parenthesizing
them (i.e., use except (NodeError, StickError):) and keep the existing return
None behavior so the call returns None on either NodeError or StickError.

In `@plugwise_usb/messages/requests.py`:
- Around line 176-180: The tuple of reply identifiers passed to
node_subscription_fn currently includes None when there's only a single reply
(it uses (self._reply_identifier, self._reply_identifier_2)), which violates
subscribe_to_node_responses()'s expected type; change the call site where
self._unsubscribe_node_response is assigned so you filter out None values before
constructing the tuple (e.g., build a sequence from self._reply_identifier and
self._reply_identifier_2 and only pass a tuple of actual bytes, or pass None if
empty) so node_subscription_fn(process_node_response, self._mac,
<filtered-reply-identifiers>, self._seq_id) always receives either None or a
tuple[bytes, ...].

In `@plugwise_usb/nodes/circle.py`:
- Around line 1154-1163: The success branch handling
CircleRelayInitStateResponse currently continues execution and triggers the
unexpected-response warning and return, causing initialize() to see a failure;
after awaiting self._relay_init_update_state(response.relay.value == 1) (or
instead of falling through) return immediately (or else put the warning/return
in an else block) so that the parsed relay-init state is returned on success and
initialize() sees a successful read.
- Around line 1176-1189: The code treats the set reply as a state payload and
reads response.relay which doesn't exist on NodeAckResponse; update the logic in
the CircleRelayInitStateRequest handling to first guard the union typed response
(ensure response is a NodeAckResponse) before inspecting node_ack_type, and in
the DEFAULT_ACK branch use the originally requested state value (the request's
state parameter) to call self._relay_init_update_state(...) instead of reading
response.relay; keep the existing None check and DEFAULT_FAIL handling but avoid
accessing attributes that only exist on a different response type.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 98e277e3-c242-4f63-8d4c-f8aea2c83daa

📥 Commits

Reviewing files that changed from the base of the PR and between 8170aaa and af69c46.

📒 Files selected for processing (4)
  • plugwise_usb/connection/__init__.py
  • plugwise_usb/messages/requests.py
  • plugwise_usb/messages/responses.py
  • plugwise_usb/nodes/circle.py

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
plugwise_usb/nodes/circle.py (2)

1158-1162: ⚠️ Potential issue | 🔴 Critical

Return the parsed relay-init state on the success path.

This branch still falls through to None, so initialize() treats a successful relay-init read as failure and aborts initialization for RELAY_INIT nodes.

🐛 Proposed fix
         if isinstance(response, CircleRelayInitStateResponse):
+            state = response.relay.value == 1
             _LOGGER.debug("Successful get of relay init state for %s", self._mac_in_str)
-            await self._relay_init_update_state(response.relay.value == 1)
+            await self._relay_init_update_state(state)
+            return state
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugwise_usb/nodes/circle.py` around lines 1158 - 1162, The success branch
for handling CircleRelayInitStateResponse currently returns None and so
initialize() thinks the read failed; modify the CircleRelayInitStateResponse
branch to return the parsed boolean state (response.relay.value == 1) after
awaiting _relay_init_update_state so callers get a truthy success value; update
the block that logs "Successful get of relay init state for %s" (using
self._mac_in_str) to await self._relay_init_update_state(response.relay.value ==
1) and then return that boolean instead of falling through to None, ensuring
initialize() recognizes successful reads for RELAY_INIT nodes.

1185-1192: ⚠️ Potential issue | 🔴 Critical

Narrow the union before reading ack fields, and persist the requested state on success.

CircleRelayInitStateRequest.send() now returns CircleRelayInitStateResponse | NodeAckResponse | None, but this code immediately reads node_ack_type and then response.relay. On the happy-path ack response, response.relay does not exist, so the state update can crash with AttributeError.

🐛 Proposed fix
-        if response.node_ack_type == NodeAckResponseType.DEFAULT_FAIL:
+        if not isinstance(response, NodeAckResponse):
+            _LOGGER.warning(
+                "Unexpected response type %s for %s",
+                response.__class__.__name__,
+                self._mac_in_str,
+            )
+            return None
+
+        if response.node_ack_type == NodeAckResponseType.DEFAULT_FAIL:
             _LOGGER.warning("Failed to set relay init state for %s", self._mac_in_str)
             return None

         if response.node_ack_type == NodeAckResponseType.DEFAULT_ACK:
             _LOGGER.debug("Successful set relay init state for %s", self._mac_in_str)
-            await self._relay_init_update_state(response.relay.value == 1)
+            await self._relay_init_update_state(state)

Add the missing import at the top of the file as well:

-from ..messages.responses import NodeAckResponseType, NodeInfoResponse, NodeResponseType
+from ..messages.responses import (
+    NodeAckResponse,
+    NodeAckResponseType,
+    NodeInfoResponse,
+    NodeResponseType,
+)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugwise_usb/nodes/circle.py` around lines 1185 - 1192, The code assumes
response has both node_ack_type and relay but send() can return
CircleRelayInitStateResponse | NodeAckResponse | None; first check for None and
then narrow the union with an isinstance/type check: handle
CircleRelayInitStateResponse by reading response.relay and calling await
self._relay_init_update_state(response.relay.value == 1); handle NodeAckResponse
separately (check node_ack_type for DEFAULT_FAIL/DEFAULT_ACK) and on DEFAULT_ACK
persist the requested state (from the original CircleRelayInitStateRequest
instance or parameter used to send()) by calling await
self._relay_init_update_state(requested_state) instead of accessing
response.relay; ensure imports include CircleRelayInitStateResponse and
NodeAckResponse for the type checks.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@plugwise_usb/nodes/circle.py`:
- Around line 1145-1150: The except block around constructing
CircleRelayInitStateRequest is catching MessageError and re-raising NodeError
without chaining; update the handler to raise the NodeError using "from err" so
the original MessageError traceback is preserved (e.g., change the except block
that currently raises NodeError(f"{self._mac_in_str} error: {err}") to raise
NodeError(...) from err); apply the same change for the similar handler at the
CircleRelayInitStateRequest-related code around the 1172–1177 section to satisfy
Ruff B904.

---

Duplicate comments:
In `@plugwise_usb/nodes/circle.py`:
- Around line 1158-1162: The success branch for handling
CircleRelayInitStateResponse currently returns None and so initialize() thinks
the read failed; modify the CircleRelayInitStateResponse branch to return the
parsed boolean state (response.relay.value == 1) after awaiting
_relay_init_update_state so callers get a truthy success value; update the block
that logs "Successful get of relay init state for %s" (using self._mac_in_str)
to await self._relay_init_update_state(response.relay.value == 1) and then
return that boolean instead of falling through to None, ensuring initialize()
recognizes successful reads for RELAY_INIT nodes.
- Around line 1185-1192: The code assumes response has both node_ack_type and
relay but send() can return CircleRelayInitStateResponse | NodeAckResponse |
None; first check for None and then narrow the union with an isinstance/type
check: handle CircleRelayInitStateResponse by reading response.relay and calling
await self._relay_init_update_state(response.relay.value == 1); handle
NodeAckResponse separately (check node_ack_type for DEFAULT_FAIL/DEFAULT_ACK)
and on DEFAULT_ACK persist the requested state (from the original
CircleRelayInitStateRequest instance or parameter used to send()) by calling
await self._relay_init_update_state(requested_state) instead of accessing
response.relay; ensure imports include CircleRelayInitStateResponse and
NodeAckResponse for the type checks.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: da52215c-13be-4785-8493-8c07097b3c2b

📥 Commits

Reviewing files that changed from the base of the PR and between af69c46 and 475d957.

📒 Files selected for processing (2)
  • plugwise_usb/messages/requests.py
  • plugwise_usb/nodes/circle.py

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@plugwise_usb/messages/requests.py`:
- Around line 1523-1524: The docstring references a non-existent response type
name; replace the incorrect CircleInitRelayStateResponse with the actual class
name CircleRelayInitStateResponse in the docstring so it matches the
imported/returned type (search for the docstring block containing "Response
message    : NodeAckResponse for set" and update the second line to use
CircleRelayInitStateResponse).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: be18fdec-5521-47bc-8013-51055c237429

📥 Commits

Reviewing files that changed from the base of the PR and between 475d957 and 2e47f19.

📒 Files selected for processing (1)
  • plugwise_usb/messages/requests.py

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
plugwise_usb/nodes/circle.py (1)

1145-1150: ⚠️ Potential issue | 🟠 Major

Chain the wrapped NodeError from the caught MessageError.

Line 1150 and Line 1177 still raise without from err, so Ruff B904 keeps failing and the original traceback is lost.

♻️ Proposed fix
         except MessageError as err:
-            raise NodeError(f"{self._mac_in_str} error: {err}")
+            raise NodeError(f"{self._mac_in_str} error: {err}") from err

Apply the same change in both handlers.

#!/bin/bash
# Verify both handlers still omit exception chaining.
sed -n '1145,1150p' plugwise_usb/nodes/circle.py
echo '---'
sed -n '1172,1177p' plugwise_usb/nodes/circle.py
# Expected: each raise statement ends with `from err`.

Also applies to: 1172-1177

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugwise_usb/nodes/circle.py` around lines 1145 - 1150, The except blocks
catching MessageError when constructing the CircleRelayInitStateRequest (and the
second similar handler later) raise a new NodeError but drop the original
traceback; modify both except clauses to re-raise NodeError using exception
chaining (raise NodeError(f"{self._mac_in_str} error: {err}") from err) so the
original MessageError is preserved in the traceback and Ruff B904 is satisfied.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@plugwise_usb/nodes/circle.py`:
- Around line 1145-1150: The except blocks catching MessageError when
constructing the CircleRelayInitStateRequest (and the second similar handler
later) raise a new NodeError but drop the original traceback; modify both except
clauses to re-raise NodeError using exception chaining (raise
NodeError(f"{self._mac_in_str} error: {err}") from err) so the original
MessageError is preserved in the traceback and Ruff B904 is satisfied.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e1fda077-106a-4c40-83a3-b72188db6d18

📥 Commits

Reviewing files that changed from the base of the PR and between 2e47f19 and 0444e17.

📒 Files selected for processing (1)
  • plugwise_usb/nodes/circle.py

Comment on lines +1179 to +1191
if (response := await request.send()) is None:
_LOGGER.warning(
"No response from %s to configure relay init setting", self._mac_in_str
)
return None

if response.node_ack_type == NodeAckResponseType.DEFAULT_FAIL:
_LOGGER.warning("Failed to set relay init state for %s", self._mac_in_str)
return None

if response.node_ack_type == NodeAckResponseType.DEFAULT_ACK:
_LOGGER.debug("Successful set relay init state for %s", self._mac_in_str)
await self._relay_init_update_state(state)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Propagate relay-init write failures instead of returning stale cached state.

On Line 1179 and Line 1185, this helper only logs and returns. If _relay_config.init_state was already populated, set_relay_init() will return that stale value and relay_init_on() / relay_init_off() will appear to succeed even though the write failed. Any non-default ack also falls through silently.

🐛 Proposed fix
         if (response := await request.send()) is None:
             _LOGGER.warning(
                 "No response from %s to configure relay init setting", self._mac_in_str
             )
-            return None
+            raise NodeError(
+                f"No response from {self._mac_in_str} to configure relay init setting"
+            )

         if response.node_ack_type == NodeAckResponseType.DEFAULT_FAIL:
             _LOGGER.warning("Failed to set relay init state for %s", self._mac_in_str)
-            return None
+            raise NodeError(f"Failed to set relay init state for {self._mac_in_str}")

         if response.node_ack_type == NodeAckResponseType.DEFAULT_ACK:
             _LOGGER.debug("Successful set relay init state for %s", self._mac_in_str)
             await self._relay_init_update_state(state)
+            return
+
+        raise NodeError(
+            f"Unexpected ack {response.node_ack_type!r} for relay init set on {self._mac_in_str}"
+        )

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
plugwise_usb/nodes/circle.py (1)

1179-1191: ⚠️ Potential issue | 🟡 Minor

Silent failure may return stale cached state to callers.

When _relay_init_set fails (no response or DEFAULT_FAIL), it logs a warning and returns None. However, the caller set_relay_init() then returns self._relay_config.init_state, which may contain a stale value from a previous successful write.

For example:

  1. Previous successful write set init_state=False
  2. User calls relay_init_on()_relay_init_set(True) fails silently
  3. set_relay_init() returns False (stale) without raising an error

If the current behavior is intentional to avoid excessive error propagation, consider at minimum returning a success/failure indicator or documenting this behavior.

🐛 Possible fix to propagate failures
         if (response := await request.send()) is None:
             _LOGGER.warning(
                 "No response from %s to configure relay init setting", self._mac_in_str
             )
-            return None
+            raise NodeError(
+                f"No response from {self._mac_in_str} to configure relay init setting"
+            )

         if response.node_ack_type == NodeAckResponseType.DEFAULT_FAIL:
             _LOGGER.warning("Failed to set relay init state for %s", self._mac_in_str)
-            return None
+            raise NodeError(f"Failed to set relay init state for {self._mac_in_str}")

         if response.node_ack_type == NodeAckResponseType.DEFAULT_ACK:
             _LOGGER.debug("Successful set relay init state for %s", self._mac_in_str)
             await self._relay_init_update_state(state)
+            return
+
+        raise NodeError(
+            f"Unexpected ack {response.node_ack_type!r} for relay init set on {self._mac_in_str}"
+        )

Based on learnings: "bouwew prefers not to add excessive validation decorators or protective error handling" - if the current behavior is by design, this can be deferred.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugwise_usb/nodes/circle.py` around lines 1179 - 1191, The _relay_init_set
currently returns None on failure which lets callers like set_relay_init()
incorrectly return a stale self._relay_config.init_state; change _relay_init_set
(the function handling request.send(), response.node_ack_type checks and calling
_relay_init_update_state) to return an explicit boolean: return False when
response is None or response.node_ack_type == NodeAckResponseType.DEFAULT_FAIL,
and return True after a successful _relay_init_update_state call (i.e., when
NodeAckResponseType.DEFAULT_ACK); also update set_relay_init() to
propagate/return that boolean result so callers can detect failure instead of
reading stale _relay_config.init_state.
🧹 Nitpick comments (1)
plugwise_usb/nodes/circle.py (1)

45-45: Import CircleRelayInitStateResponse from its source module.

CircleRelayInitStateResponse is defined in ..messages.responses, not ..messages.requests. While this works because requests.py imports it, importing from the actual source module is clearer and more maintainable.

♻️ Suggested change
 from ..messages.requests import (
     CircleClockGetRequest,
     CircleClockSetRequest,
     CircleEnergyLogsRequest,
     CircleMeasureIntervalRequest,
     CirclePowerUsageRequest,
     CircleRelayInitStateRequest,
-    CircleRelayInitStateResponse,
     CircleRelaySwitchRequest,
     EnergyCalibrationRequest,
     NodeInfoRequest,
 )
-from ..messages.responses import NodeAckResponseType, NodeInfoResponse, NodeResponseType
+from ..messages.responses import (
+    CircleRelayInitStateResponse,
+    NodeAckResponseType,
+    NodeInfoResponse,
+    NodeResponseType,
+)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugwise_usb/nodes/circle.py` at line 45, The import in
plugwise_usb/nodes/circle.py currently pulls CircleRelayInitStateResponse from
..messages.requests but its canonical definition lives in ..messages.responses;
change the import to import CircleRelayInitStateResponse directly from
..messages.responses (update the import list that includes
CircleRelayInitStateResponse) so the module references the source of truth and
avoids relying on transitive imports from requests.py.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@plugwise_usb/nodes/circle.py`:
- Around line 1179-1191: The _relay_init_set currently returns None on failure
which lets callers like set_relay_init() incorrectly return a stale
self._relay_config.init_state; change _relay_init_set (the function handling
request.send(), response.node_ack_type checks and calling
_relay_init_update_state) to return an explicit boolean: return False when
response is None or response.node_ack_type == NodeAckResponseType.DEFAULT_FAIL,
and return True after a successful _relay_init_update_state call (i.e., when
NodeAckResponseType.DEFAULT_ACK); also update set_relay_init() to
propagate/return that boolean result so callers can detect failure instead of
reading stale _relay_config.init_state.

---

Nitpick comments:
In `@plugwise_usb/nodes/circle.py`:
- Line 45: The import in plugwise_usb/nodes/circle.py currently pulls
CircleRelayInitStateResponse from ..messages.requests but its canonical
definition lives in ..messages.responses; change the import to import
CircleRelayInitStateResponse directly from ..messages.responses (update the
import list that includes CircleRelayInitStateResponse) so the module references
the source of truth and avoids relying on transitive imports from requests.py.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5454df7e-2d80-4ce8-9125-11eea697f382

📥 Commits

Reviewing files that changed from the base of the PR and between 0444e17 and 2d4361c.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • plugwise_usb/messages/requests.py
  • plugwise_usb/nodes/circle.py
  • pyproject.toml
✅ Files skipped from review due to trivial changes (2)
  • CHANGELOG.md
  • pyproject.toml

@sonarqubecloud
Copy link

@bouwew bouwew marked this pull request as ready for review March 11, 2026 07:29
@bouwew bouwew requested a review from a team as a code owner March 11, 2026 07:29
@bouwew bouwew merged commit f5c968b into main Mar 11, 2026
13 of 17 checks passed
@bouwew bouwew deleted the pw-0138-2 branch March 11, 2026 07:29
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