Skip to content

Conversation

@dirixmjm
Copy link
Contributor

@dirixmjm dirixmjm commented Aug 28, 2025

Some NodeFeatures are not carrying any data, however they are used to generate entities such as buttons in HA. If polling requests data for these features, no data should be returned, and no exception generated.

Summary by CodeRabbit

  • Bug Fixes

    • Avoid crashes by skipping absent device feature values and guarding against missing keys.
    • Replaced exception-based failures with non-intrusive debug logging when feature data is not returned.
    • Fixes applied across device types (switches, sensors, circles, scans, SED).
  • Stability

    • More resilient state aggregation during polling; availability still reported when some features are absent.
  • Chores

    • Package version bumped to 0.44.13 and changelog updated for the release.

@coderabbitai
Copy link

coderabbitai bot commented Aug 28, 2025

Walkthrough

This PR makes get_state more defensive across multiple node classes by skipping assignments when the superclass result lacks a feature key and changes PlugwiseBaseNode.get_state to log-and-skip unsupported features instead of raising. It also updates the changelog for release v0.44.13 and bumps the project version to 0.44.13.

Changes

Cohort / File(s) Summary
Base node default handling
plugwise_usb/nodes/node.py
PlugwiseBaseNode.get_state no longer raises NodeError for unsupported features; it logs a debug message and skips the feature, allowing state aggregation to continue.
Guarded default assignment in node subclasses
plugwise_usb/nodes/circle.py, plugwise_usb/nodes/scan.py, plugwise_usb/nodes/sed.py, plugwise_usb/nodes/sense.py, plugwise_usb/nodes/switch.py
In each subclass get_state, the default branch now checks if feature in state_result before assigning from super().get_state((feature,)), preventing KeyError when the super call omits the feature. Explicit feature cases (ENERGY, RELAY, MOTION, SENSE, SWITCH) and final AVAILABLE insertion remain unchanged. circle.py adds a # noqa: PLR0912 directive.
Changelog update
CHANGELOG.md
Adds release header ## v0.44.13 - 2025-08-29, adds PR note about allowing get_state requests for non-data NodeFeatures, and removes the previous ongoing entry.
Metadata bump
pyproject.toml
Project version bumped from 0.44.13a0 to 0.44.13. No other functional changes.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant C as Caller
  participant N as Node Subclass
  participant B as BaseNode
  participant A as Adapter

  Note over C,N: Request states for one or more features
  C->>N: get_state(features)

  loop per feature
    N->>B: super().get_state((feature,))
    B->>A: fetch/collect raw state
    A-->>B: { ... } or {}
    alt Base returned contains feature
      B-->>N: {feature: value}
      N->>N: assign states[feature] = value
    else Base returned missing feature
      B-->>N: {} (logs debug for unsupported/missing)
      N->>N: skip assignment
    end
  end

  opt ensure AVAILABLE
    N->>N: add NodeFeature.AVAILABLE if absent
  end

  N-->>C: aggregated states dict
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • brefra
  • ArnoutD
  • bouwew

Poem

I nibble keys and tidy state,
Skip the gaps and leave no strait.
A quiet log where data's thin,
I stitch the fields that do come in.
Version hopped — the release is great! 🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 80f00e5 and da4d303.

📒 Files selected for processing (2)
  • CHANGELOG.md (1 hunks)
  • pyproject.toml (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • pyproject.toml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Ruff check and force
✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch mdi_nodefeature

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbit in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbit in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbit gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbit read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbit help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbit ignore or @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbit summary or @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbit or @coderabbitai title anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
plugwise_usb/nodes/circle.py (1)

1246-1246: Fix Ruff PLR0912 on get_state

The function exceeds the allowed branch count (GitHub Actions failure). Either refactor or add a targeted noqa to unblock CI.

Minimal unblock diff:

-    async def get_state(self, features: tuple[NodeFeature]) -> dict[NodeFeature, Any]:
+    async def get_state(self, features: tuple[NodeFeature]) -> dict[NodeFeature, Any]:  # noqa: PLR0912

Longer-term, consider extracting feature-handling cases into small helpers to reduce branching.

🧹 Nitpick comments (1)
plugwise_usb/nodes/scan.py (1)

510-512: Docstring nit: pluralize “feature”.

The function accepts a tuple of features.

Apply:

-        """Update latest state for given feature."""
+        """Update latest state for given features."""
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f9ea8f7 and 008a029.

📒 Files selected for processing (6)
  • plugwise_usb/nodes/circle.py (1 hunks)
  • plugwise_usb/nodes/node.py (1 hunks)
  • plugwise_usb/nodes/scan.py (1 hunks)
  • plugwise_usb/nodes/sed.py (1 hunks)
  • plugwise_usb/nodes/sense.py (1 hunks)
  • plugwise_usb/nodes/switch.py (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-06-19T06:38:04.702Z
Learnt from: bouwew
PR: plugwise/python-plugwise-usb#255
File: plugwise_usb/nodes/circle.py:477-482
Timestamp: 2025-06-19T06:38:04.702Z
Learning: In plugwise_usb/nodes/circle.py, the timestamp comparison `prev_address_timestamp - self._last_collected_energy_timestamp` in the `get_missing_energy_logs` method is intentional. The code iterates backwards through time-ordered energy log addresses, where `prev_address_timestamp` contains the more recent timestamp from the previous iteration, and this subtraction correctly calculates the time gap to determine when to stop collecting outdated data.

Applied to files:

  • plugwise_usb/nodes/circle.py
📚 Learning: 2025-08-07T17:50:29.188Z
Learnt from: bouwew
PR: plugwise/python-plugwise-usb#302
File: plugwise_usb/nodes/scan.py:132-142
Timestamp: 2025-08-07T17:50:29.188Z
Learning: In the plugwise_usb codebase, the `_load_defaults` method in node classes (scan.py, switch.py, sense.py) is only called once during node initialization, not during runtime. Therefore, flags like `_sed_node_info_update_task_scheduled` don't need to be reset at the start of `_load_defaults` as there's no risk of stale state from previous loads.

Applied to files:

  • plugwise_usb/nodes/node.py
  • plugwise_usb/nodes/scan.py
  • plugwise_usb/nodes/sense.py
🧬 Code graph analysis (2)
plugwise_usb/nodes/circle.py (1)
plugwise_usb/nodes/helpers/cache.py (1)
  • states (23-25)
plugwise_usb/nodes/scan.py (1)
plugwise_usb/nodes/helpers/cache.py (1)
  • states (23-25)
🪛 GitHub Actions: Latest commit
plugwise_usb/nodes/circle.py

[error] 1246-1246: Command: 'ruff check plugwise_usb/ tests/' failed: PLR0912 Too many branches (13 > 12).

plugwise_usb/nodes/node.py

[error] 638-638: Command: 'ruff check plugwise_usb/ tests/' reported G003 Logging statement uses +.

🔇 Additional comments (6)
plugwise_usb/nodes/switch.py (1)

156-159: Guarding superclass result prevents KeyError — good change

The membership check before indexing state_result is correct and aligns with the new base-class behavior.

plugwise_usb/nodes/sed.py (1)

649-652: Defensive access of state_result looks good

The added membership check avoids errors when a requested feature intentionally returns no data.

plugwise_usb/nodes/circle.py (1)

1296-1299: Safe access pattern adopted — approved

Guarding against missing keys from super().get_state() is correct and consistent across nodes.

plugwise_usb/nodes/sense.py (1)

167-170: Membership check avoids KeyError — approved

Matches the new “non-data feature returns nothing” contract from the base class.

plugwise_usb/nodes/scan.py (2)

531-534: Good guard to avoid KeyError for non-data features.

Conditionally assigning only when feature is present in state_result prevents KeyError and aligns with the PR objective to return no data (instead of raising) for non-data features.


519-524: Ignore inconsistent behavior alert: all get_state implementations—including the base class—still raise NodeError for unsupported features, and subclasses mirror that behavior.

Likely an incorrect or invalid review comment.

@codecov
Copy link

codecov bot commented Aug 28, 2025

Codecov Report

❌ Patch coverage is 75.00000% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.47%. Comparing base (f9ea8f7) to head (da4d303).
⚠️ Report is 9 commits behind head on main.

Files with missing lines Patch % Lines
plugwise_usb/nodes/sense.py 0.00% 2 Missing ⚠️
plugwise_usb/nodes/node.py 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #328      +/-   ##
==========================================
- Coverage   80.56%   80.47%   -0.10%     
==========================================
  Files          36       36              
  Lines        7559     7564       +5     
==========================================
- Hits         6090     6087       -3     
- Misses       1469     1477       +8     

☔ 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.

@dirixmjm dirixmjm marked this pull request as ready for review August 28, 2025 14:08
@dirixmjm dirixmjm requested a review from a team as a code owner August 28, 2025 14:08
Copy link
Contributor

@bouwew bouwew left a comment

Choose a reason for hiding this comment

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

It's working! Thanks @dirixmjm

@sonarqubecloud
Copy link

@dirixmjm dirixmjm merged commit b7176ce into main Aug 29, 2025
25 of 28 checks passed
@dirixmjm dirixmjm deleted the mdi_nodefeature branch August 29, 2025 11:10
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.

3 participants