Skip to content

Conversation

@dirixmjm
Copy link
Contributor

@dirixmjm dirixmjm commented Sep 3, 2025

Summary by CodeRabbit

  • New Features

    • Adds Sense hysteresis support: switches to enable humidity/temperature control and choose direction.
    • Adds number controls for humidity/temperature upper and lower bounds (supports decimal values).
    • Adds status sensors for humidity/temperature hysteresis and a config-changed indicator.
  • Chores

    • Updates dependency to plugwise-usb 0.45.0; integration version bumped.
    • Adds English and Dutch labels for all new entities.
  • Documentation

    • Reworked changelog: new v0.56.0 (2025-09-03) and inserted v0.55.12/v0.55.11 entries; removed “Ongoing”.

@coderabbitai
Copy link

coderabbitai bot commented Sep 3, 2025

Walkthrough

Adds Sense hysteresis support: new binary sensors, switches, and numeric bounds; refactors number entities to use typed key-based access; updates translations; bumps integration and dependency versions; and updates changelog and project version metadata.

Changes

Cohort / File(s) Summary
Docs & Versioning
CHANGELOG.md, pyproject.toml, custom_components/plugwise_usb/manifest.json
Adds v0.56.0 changelog entry; removes “Ongoing” top section; bumps project version to 0.55.13 (pyproject); updates integration version to 0.56.0 and requirement to plugwise-usb==0.45.0 (manifest).
Binary Sensors (Sense / Hysteresis)
custom_components/plugwise_usb/binary_sensor.py
Adds three binary sensor descriptions: sense_config_dirty (SENSE_HYSTERESIS, diagnostic safety), humidity_hysteresis_state (SENSE), and temperature_hysteresis_state (SENSE).
Switches (Sense / Hysteresis)
custom_components/plugwise_usb/switch.py
Adds four switch descriptions for SENSE_HYSTERESIS: humidity_enabled, humidity_direction, temperature_enabled, temperature_direction, wired to async setter functions and api attributes.
Numbers Refactor & Hysteresis Bounds
custom_components/plugwise_usb/number.py
Replaces api_attribute with key-based access and adds async_number_type (default "int"); updates coordinator read path and set path (casts to int/float); adds four new number entities for hysteresis bounds (humidity/temperature upper/lower, float, step 0.1).
Translations / Strings
custom_components/plugwise_usb/strings.json, .../translations/en.json, .../translations/nl.json
Adds EN and NL translation entries for new binary sensors, switches, and numbers (sense hysteresis labels and names).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant HA as Home Assistant
  participant Ent as Plugwise Entities
  participant Coord as Coordinator
  participant Lib as plugwise-usb 0.45.0
  participant Dev as Device

  rect rgb(235,245,255)
  note right of HA: Setup
  HA->>Ent: Create entities for SENSE / SENSE_HYSTERESIS
  Ent->>Coord: Subscribe for updates
  Coord->>Lib: Poll / request data
  Lib->>Dev: Read state
  Dev-->>Lib: Hysteresis/config/state
  Lib-->>Coord: Data snapshot
  Coord-->>Ent: Update using entity_description.key
  end

  rect rgb(240,255,240)
  note right of U: Control (set)
  U->>Ent: Set number / toggle switch
  Ent->>Ent: Cast value (int/float) per async_number_type
  Ent->>Lib: Call async_* setter (hysteresis fn)
  Lib->>Dev: Apply configuration
  Dev-->>Lib: Ack/new state
  Lib-->>Coord: Updated snapshot
  Coord-->>Ent: Refresh state
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

enhancement, dependencies

Suggested reviewers

  • bouwew
  • ArnoutD

Poem

A rabbit taps its paw on keys,
New hysteresis bounds and ease.
Sensors watch, switches learn to flip,
Numbers drift with every dip.
Translations hop — v0.56 takes flight. 🐇✨


📜 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 0c3bc9c and ae2d7f4.

📒 Files selected for processing (1)
  • custom_components/plugwise_usb/number.py (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • custom_components/plugwise_usb/number.py
⏰ 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: Setup for HA-core (release/master)
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch mdi_sense

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 @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai 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:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai 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 @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai 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
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.

Please see my comments

bouwew: bump minor version number
@dirixmjm dirixmjm marked this pull request as ready for review September 3, 2025 10:34
@dirixmjm dirixmjm requested a review from a team as a code owner September 3, 2025 10:34
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 (9)
pyproject.toml (1)

3-3: Align project version with the feature release (0.56.0).

Manifest and changelog indicate 0.56.0; keep versions consistent to avoid packaging/HACS confusion. This also reflects the prior reviewer’s note.

-version = "0.55.13"
+version = "0.56.0"
CHANGELOG.md (1)

3-7: v0.56.0 entry and backend link — good.

Thanks for adding the 0.45.0 link; addresses the earlier request.

custom_components/plugwise_usb/translations/nl.json (1)

135-146: Shorten and standardize switch names.

Current labels are wordy. Shorter names read better in UI and align with the previous “Shorten” feedback.

-      "sense_humidity_enabled": {
-        "name": "Zet schakelen op luchtvochtigheid hysterese aan"
-      },
-      "sense_humidity_direction": {
-        "name": "Schakel bij stijgende of dalende luchtvochtigheid"
-      },
-      "sense_temperature_enabled": {
-        "name": "Zet schakelen op temperatuur hysterese aan"
-      },
-      "sense_temperature_direction": {
-        "name": "Schakel bij stijgende of dalende temperatuur"
-      }
+      "sense_humidity_enabled": {
+        "name": "Schakelen op luchtvochtigheid (hysterese)"
+      },
+      "sense_humidity_direction": {
+        "name": "Schakelrichting luchtvochtigheid"
+      },
+      "sense_temperature_enabled": {
+        "name": "Schakelen op temperatuur (hysterese)"
+      },
+      "sense_temperature_direction": {
+        "name": "Schakelrichting temperatuur"
+      }
custom_components/plugwise_usb/number.py (2)

50-51: Fix indentation: stray tab before mode="box".

HA/Black prefer 4-space indents; tabs may fail linting.

Apply:

-	mode="box",
+        mode="box",

84-85: Fix indentation: stray tab before mode="box".

Same issue as above.

-	mode="box",
+        mode="box",
custom_components/plugwise_usb/translations/en.json (3)

57-66: Shorten and standardize binary_sensor names (sentence case).

Keeps UI concise and consistent.

-      "sense_config_dirty": {
-        "name": "Sense hysteresis config changed"
-      },
-      "humidity_hysteresis_state": {
-        "name": "Humidity Status"
-      },
-      "temperature_hysteresis_state": {
-        "name": "Temperature Status"
-      }
+      "sense_config_dirty": {
+        "name": "Sense config changed"
+      },
+      "humidity_hysteresis_state": {
+        "name": "Humidity status"
+      },
+      "temperature_hysteresis_state": {
+        "name": "Temperature status"
+      }

134-146: Shorten switch names for readability.

Names should be compact; intent remains clear.

-      "sense_humidity_enabled": {
-        "name": "Enable humidity switching on hysteresis"
-      },
-      "sense_humidity_direction": {
-        "name": "Switch on increasing or decreasing humidity"
-      },
-      "sense_temperature_enabled": {
-        "name": "Enable temperature switching on hysteresis"
-      },
-      "sense_temperature_direction": {
-        "name": "Switch on increasing or decreasing temperature"
-      }
+      "sense_humidity_enabled": {
+        "name": "Humidity hysteresis"
+      },
+      "sense_humidity_direction": {
+        "name": "Humidity direction"
+      },
+      "sense_temperature_enabled": {
+        "name": "Temperature hysteresis"
+      },
+      "sense_temperature_direction": {
+        "name": "Temperature direction"
+      }

163-175: Shorten number names; align with unit display.

Avoid “value” suffix; UI already shows units.

-      "sense_humidity_upper_bound": {
-        "name": "Humidity upper boundary value"
-      },
-      "sense_humidity_lower_bound": {
-        "name": "Humidity lower boundary value"
-      },
-      "sense_temperature_upper_bound": {
-        "name": "Temperature upper boundary value"
-      },
-      "sense_temperature_lower_bound": {
-        "name": "Temperature lower boundary value"
-      }
+      "sense_humidity_upper_bound": {
+        "name": "Humidity upper bound"
+      },
+      "sense_humidity_lower_bound": {
+        "name": "Humidity lower bound"
+      },
+      "sense_temperature_upper_bound": {
+        "name": "Temperature upper bound"
+      },
+      "sense_temperature_lower_bound": {
+        "name": "Temperature lower bound"
+      }
custom_components/plugwise_usb/strings.json (1)

134-146: Shorten switch labels; keep them scannable.

  • Shorten “Enable … switching on hysteresis”.
  • Shorten “Switch on increasing or decreasing …” per prior review.
-      "sense_humidity_enabled": {
-        "name": "Enable humidity switching on hysteresis"
-      },
+      "sense_humidity_enabled": {
+        "name": "Enable humidity hysteresis"
+      },
-      "sense_humidity_direction": {
-        "name": "Switch on increasing or decreasing humidity"
-      },
+      "sense_humidity_direction": {
+        "name": "Switch on humidity increase/decrease"
+      },
-      "sense_temperature_enabled": {
-        "name": "Enable temperature switching on hysteresis"
-      },
+      "sense_temperature_enabled": {
+        "name": "Enable temperature hysteresis"
+      },
-      "sense_temperature_direction": {
-        "name": "Switch on increasing or decreasing temperature"
-      }
+      "sense_temperature_direction": {
+        "name": "Switch on temperature increase/decrease"
+      }
🧹 Nitpick comments (8)
custom_components/plugwise_usb/translations/nl.json (2)

57-66: Clarify hysteresis status entity names.

Consider explicitly mentioning “hysterese” in the status labels for clarity.

-      "humidity_hysteresis_state": {
-        "name": "Status Luchtvochtigheid"
-      },
-      "temperature_hysteresis_state": {
-        "name": "Status Temperatuur"
-      }
+      "humidity_hysteresis_state": {
+        "name": "Hysterese-status luchtvochtigheid"
+      },
+      "temperature_hysteresis_state": {
+        "name": "Hysterese-status temperatuur"
+      }

164-175: Prefer “bovengrens/ondergrens” over “hoge/lage schakelpunt”.

These are more concise and idiomatic for set bounds.

-      "sense_humidity_upper_bound": {
-        "name": "Hoge schakelpunt luchtvochtigheid"
-      },
-      "sense_humidity_lower_bound": {
-        "name": "Lage schakelpunt luchtvochtigheid"
-      },
-      "sense_temperature_upper_bound": {
-        "name": "Hoge schakelpunt temperatuur"
-      },
-      "sense_temperature_lower_bound": {
-        "name": "Lage schakelpunt temperatuur"
-      }
+      "sense_humidity_upper_bound": {
+        "name": "Bovengrens luchtvochtigheid"
+      },
+      "sense_humidity_lower_bound": {
+        "name": "Ondergrens luchtvochtigheid"
+      },
+      "sense_temperature_upper_bound": {
+        "name": "Bovengrens temperatuur"
+      },
+      "sense_temperature_lower_bound": {
+        "name": "Ondergrens temperatuur"
+      }
custom_components/plugwise_usb/switch.py (2)

73-104: Hysteresis switches added — LGTM; consider a Select for “direction”.

The four switches map cleanly to SENSE_HYSTERESIS. Optional: represent “direction” as a Select with values [rising, falling] for clearer UX; keep as switch if the API is strictly boolean.


73-104: Defensive read on coordinator data to avoid AttributeError.

If backend/data shape drifts, getattr without a default can break updates. Consider a safe fallback (not in this hunk; shown for context).

# In _handle_coordinator_update(), prefer a safe default
self._attr_is_on = bool(
    getattr(data, self.entity_description.api_attribute, False)
)
custom_components/plugwise_usb/number.py (2)

229-231: Guard against missing coordinator attributes to avoid AttributeError.

Use a default in getattr and skip state write if absent.

-        self._attr_native_value = getattr(
-            self.coordinator.data[self.entity_description.node_feature],
-            self.entity_description.key,
-        )
+        value = getattr(
+            self.coordinator.data[self.entity_description.node_feature],
+            self.entity_description.key,
+            None,
+        )
+        if value is None:
+            _LOGGER.debug(
+                "Key %s not present in %s data for %s",
+                self.entity_description.key,
+                self.entity_description.node_feature,
+                self._node_info.mac,
+            )
+            return
+        self._attr_native_value = value

236-240: Optional: normalize to step before sending.

To avoid float drift, consider rounding to native_step when async_number_type=="float".

-        if self.entity_description.async_number_type == "float":
-            await self.async_number_fn(float(value))
+        if self.entity_description.async_number_type == "float":
+            step = getattr(self.entity_description, "native_step", None)
+            v = float(value if step is None else round(value / step) * step)
+            await self.async_number_fn(v)
custom_components/plugwise_usb/strings.json (2)

57-66: Tighten naming and casing for clarity/consistency.

  • Prefer sentence case for “Status”.
-      "humidity_hysteresis_state": {
-        "name": "Humidity Status"
-      },
+      "humidity_hysteresis_state": {
+        "name": "Humidity status"
+      },
-      "temperature_hysteresis_state": {
-        "name": "Temperature Status"
-      }
+      "temperature_hysteresis_state": {
+        "name": "Temperature status"
+      }

163-175: Use “threshold” instead of “boundary value”.

Shorter and more familiar to users configuring hysteresis.

-      "sense_humidity_upper_bound": {
-        "name": "Humidity upper boundary value"
-      },
+      "sense_humidity_upper_bound": {
+        "name": "Humidity upper threshold"
+      },
-      "sense_humidity_lower_bound": {
-        "name": "Humidity lower boundary value"
-      },
+      "sense_humidity_lower_bound": {
+        "name": "Humidity lower threshold"
+      },
-      "sense_temperature_upper_bound": {
-        "name": "Temperature upper boundary value"
-      },
+      "sense_temperature_upper_bound": {
+        "name": "Temperature upper threshold"
+      },
-      "sense_temperature_lower_bound": {
-        "name": "Temperature lower boundary value"
-      }
+      "sense_temperature_lower_bound": {
+        "name": "Temperature lower threshold"
+      }
📜 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 d824384 and 0c3bc9c.

📒 Files selected for processing (9)
  • CHANGELOG.md (1 hunks)
  • custom_components/plugwise_usb/binary_sensor.py (1 hunks)
  • custom_components/plugwise_usb/manifest.json (1 hunks)
  • custom_components/plugwise_usb/number.py (5 hunks)
  • custom_components/plugwise_usb/strings.json (3 hunks)
  • custom_components/plugwise_usb/switch.py (1 hunks)
  • custom_components/plugwise_usb/translations/en.json (3 hunks)
  • custom_components/plugwise_usb/translations/nl.json (3 hunks)
  • pyproject.toml (1 hunks)
🔇 Additional comments (8)
custom_components/plugwise_usb/manifest.json (1)

12-13: Approve bump to plugwise-usb 0.45.0 and integration 0.56.0

Verified that plugwise-usb 0.45.0 exports NodeFeature.SENSE_HYSTERESIS and provides the async setters set_hysteresis_humidity_enabled/direction and set_hysteresis_temperature_enabled/direction.

CHANGELOG.md (2)

8-9: v0.55.12 section — OK.


13-16: v0.55.11 section — OK.

custom_components/plugwise_usb/binary_sensor.py (3)

64-72: Sense config-dirty binary sensor: looks correct and consistent.

NodeFeature and attributes align with the new SENSE_HYSTERESIS feature. No blocking concerns.


74-78: Confirm value type and feature source for humidity_hysteresis_state.

Please verify that:

  • The coordinator data under NodeFeature.SENSE exposes attribute humidity_hysteresis_state.
  • The attribute is strictly boolean (required by BinarySensor).

80-84: Confirm value type and feature source for temperature_hysteresis_state.

Same as for humidity: ensure attribute exists under NodeFeature.SENSE and is boolean.

custom_components/plugwise_usb/number.py (2)

36-37: Good addition: explicit numeric type handling.

async_number_type provides clear float/int casting and avoids API ambiguity.


97-148: Bounds sanity: are min/max ranges correct?

  • Humidity lower bound min=1 excludes 0%; intentional?
  • Temperature lower bound min=1 excludes <=0 °C; intended for hardware limits?

If 0 (or negatives) are valid, please relax native_min_value accordingly.

@sonarqubecloud
Copy link

sonarqubecloud bot commented Sep 3, 2025

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.

Well done!

@dirixmjm dirixmjm merged commit ba6ff0a into main Sep 3, 2025
12 checks passed
@bouwew bouwew deleted the mdi_sense branch September 3, 2025 12:13
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