Skip to content

feat: add wintermode switch entity (fixes #331)#332

Merged
geertmeersman merged 2 commits into
mainfrom
dev-current
Sep 10, 2025
Merged

feat: add wintermode switch entity (fixes #331)#332
geertmeersman merged 2 commits into
mainfrom
dev-current

Conversation

@geertmeersman

@geertmeersman geertmeersman commented Sep 10, 2025

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Added a Winter Mode switch to the Robonect integration for REST-enabled setups. The toggle persists across restarts, displays a snowflake icon, includes attribution and last-synced details in its attributes, and appears alongside other Robonect switches.
  • Documentation

    • Added UI translations/labels for the Winter Mode switch in English, German, French, and Dutch.

@coderabbitai

coderabbitai Bot commented Sep 10, 2025

Copy link
Copy Markdown

Walkthrough

Adds a REST-configurable Robonect Winter Mode switch class and registers it when REST is enabled; updates translations for English, German, French, and Dutch to include Winter Mode labels.

Changes

Cohort / File(s) Summary
Switch implementation
custom_components/robonect/switch.py
Introduces RobonectConfigSwitch, registers a REST-based Winter Mode config switch (key ".winter_mode") when REST is enabled, persists state in the config entry, exposes last_synced and category attributes, and updates REST switches registration/logging.
Translations (EN/DE/FR)
custom_components/robonect/translations/en.json, custom_components/robonect/translations/de.json, custom_components/robonect/translations/fr.json
Adds entity.switch.winter_mode translation entries: EN "Winter mode", DE "Wintermodus", FR "Mode hiver".
Translations (NL)
custom_components/robonect/translations/nl.json
Adds winter_mode translation under entity.binary_sensor with name "Wintermodus" (placement differs from other locales).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant HA as Home Assistant
  participant Switch as RobonectConfigSwitch
  participant Entry as ConfigEntry

  rect rgb(238,247,255)
    note right of HA: Setup (REST enabled)
    HA->>Switch: Register Winter Mode (".winter_mode")
    Switch->>Entry: Read config entry.data[CONF_WINTER_MODE]
    Switch-->>HA: initial state
  end

  rect rgb(243,255,240)
    User->>HA: Toggle Winter Mode
    HA->>Switch: async_turn_on / async_turn_off
    Switch->>Entry: Update entry.data[CONF_WINTER_MODE]=True/False
    Entry-->>Switch: confirm update
    Switch-->>HA: State changed (is_on)
  end

  rect rgb(255,247,230)
    HA->>Switch: Query attributes
    Switch-->>HA: extra_state_attributes (last_synced, category)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Pre-merge checks (3 passed)

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly conveys the primary change of introducing a winter mode switch entity, aligns with the conventional “feat:” prefix, and references the related issue #331. It clearly matches the core of the changeset—adding a new Winter Mode switch—without unnecessary detail or noise, making it easy for reviewers to understand the intent at a glance.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

Poem

A twitch of whiskers, a toggle bright,
I hop and set the Winter Mode right.
Configs saved beneath my paw,
Translations hum—bonjour, hallo, ja!
Mower naps while snowflakes glow. 🐇❄️

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dev-current

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.

@github-actions github-actions Bot added feat A new feature minor A change requiring a minor version bump labels Sep 10, 2025

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (5)
custom_components/robonect/switch.py (5)

85-99: Broaden entities list type to include the new config switch

You append RobonectConfigSwitch to a list typed as list[RobonectRestSwitch]. Loosen the annotation to avoid type/lint warnings.

Apply:

-        entities: list[RobonectRestSwitch] = []
+        entities: list[SwitchEntity] = []

100-100: Nit: log message says “sensors” but this is the switch platform

Minor wording fix for clarity.

-        _LOGGER.debug("Creating REST sensors")
+        _LOGGER.debug("Creating REST switches")

396-401: Remove redundant RestoreEntity in MRO

RobonectEntity already derives from RestoreEntity. Duplicating it is unnecessary.

-class RobonectConfigSwitch(RobonectEntity, SwitchEntity, RestoreEntity):
+class RobonectConfigSwitch(RobonectEntity, SwitchEntity):

424-439: Switch state isn’t refreshed after toggling

After async_update_entry, the UI may not reflect the new state until another update. Refresh the entity state immediately.

     async def async_turn_on(self, **kwargs: Any) -> None:
         """Turn the switch on."""
         if self.is_on is True:
             return
         if self.entity_description.key == f".{CONF_WINTER_MODE}":
             new_data = {**self.entry.data, CONF_WINTER_MODE: True}
             self.hass.config_entries.async_update_entry(self.entry, data=new_data)
+            self.update_ha_state()

     async def async_turn_off(self, **kwargs: Any) -> None:
         """Turn the switch off."""
         if self.is_on is False:
             return
         if self.entity_description.key == f".{CONF_WINTER_MODE}":
             new_data = {**self.entry.data, CONF_WINTER_MODE: False}
             self.hass.config_entries.async_update_entry(self.entry, data=new_data)
+            self.update_ha_state()

91-96: Optional: align category with semantics

Category is set to "NONE" and exposed in attributes. Consider "config" for clearer telemetry and uniqueness that reads better in UIs. No functional impact.

-                    category="NONE",
+                    category="config",
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 64735e6 and 9f9a06d.

📒 Files selected for processing (5)
  • custom_components/robonect/switch.py (3 hunks)
  • custom_components/robonect/translations/de.json (1 hunks)
  • custom_components/robonect/translations/en.json (1 hunks)
  • custom_components/robonect/translations/fr.json (1 hunks)
  • custom_components/robonect/translations/nl.json (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
custom_components/robonect/switch.py (4)
custom_components/robonect/definitions.py (1)
  • RobonectSwitchEntityDescription (22-30)
custom_components/robonect/entity.py (1)
  • RobonectEntity (34-128)
custom_components/robonect/binary_sensor.py (3)
  • is_on (139-141)
  • is_on (205-208)
  • extra_state_attributes (230-233)
custom_components/robonect/sensor.py (3)
  • extra_state_attributes (259-264)
  • extra_state_attributes (343-346)
  • extra_state_attributes (382-384)
🔇 Additional comments (5)
custom_components/robonect/translations/en.json (1)

769-772: LGTM: adds switch label for Winter mode

Label matches the entity key and other locales. No issues.

custom_components/robonect/translations/de.json (1)

769-772: LGTM: German switch label added

"Wintermodus" aligns with other locales.

custom_components/robonect/translations/fr.json (1)

769-772: LGTM: French switch label added

"Mode hiver" consistent across UI.

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

769-772: LGTM: Dutch switch label added

"Wintermodus" consistent with other languages.

custom_components/robonect/switch.py (1)

420-431: Defaults and migrations for CONF_WINTER_MODE are correctly implemented
New entries require explicit winter_mode input in the config flow, and existing entries are migrated with winter_mode=False (version <4) in init.py.

Comment thread custom_components/robonect/switch.py
@github-actions github-actions Bot added the fix A bug fix label Sep 10, 2025

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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)
custom_components/robonect/switch.py (1)

417-423: Good fix: safe access to CONF_WINTER_MODE

Using .get(..., False) prevents KeyError on older entries. Thanks for addressing the earlier concern.

🧹 Nitpick comments (3)
custom_components/robonect/switch.py (3)

86-99: Fix entities list type: allow RobonectConfigSwitch

entities is annotated as list[RobonectRestSwitch] but now also contains RobonectConfigSwitch; adjust the type to avoid mypy/static typing issues.

-        entities: list[RobonectRestSwitch] = []
+        entities: list[SwitchEntity] = []

100-100: Nit: make the log reflect both switch types

This block now adds a config switch as well; tweak the message for clarity.

-        _LOGGER.debug("Creating REST switches")
+        _LOGGER.debug("Creating config and REST switches")

396-401: Unify attribution via a constant

Other entities use constants (e.g., ATTRIBUTION_REST/MQTT). Consider adding ATTRIBUTION_CONFIG in const.py and importing it here instead of a magic string for consistency.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9f9a06d and ef6587d.

📒 Files selected for processing (1)
  • custom_components/robonect/switch.py (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
custom_components/robonect/switch.py (3)
custom_components/robonect/definitions.py (1)
  • RobonectSwitchEntityDescription (22-30)
custom_components/robonect/entity.py (2)
  • RobonectEntity (34-128)
  • update_ha_state (125-128)
custom_components/robonect/binary_sensor.py (2)
  • is_on (139-141)
  • is_on (205-208)
🔇 Additional comments (2)
custom_components/robonect/switch.py (2)

24-24: LGTM: winter-mode constant import

Importing CONF_WINTER_MODE here is correct and needed for the new switch.


394-395: No-op change

Only whitespace/newlines here; nothing to review.

Comment on lines +424 to +441
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the switch on."""
if self.is_on is True:
return
if self.entity_description.key == f".{CONF_WINTER_MODE}":
new_data = {**self.entry.data, CONF_WINTER_MODE: True}
self.hass.config_entries.async_update_entry(self.entry, data=new_data)
self.update_ha_state()

async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the switch off."""
if self.is_on is False:
return
if self.entity_description.key == f".{CONF_WINTER_MODE}":
new_data = {**self.entry.data, CONF_WINTER_MODE: False}
self.hass.config_entries.async_update_entry(self.entry, data=new_data)
self.update_ha_state()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify state propagation to dependent entities

Toggling this switch updates entry.data and this entity’s state, but the winter_mode binary_sensor (reads entry.data directly) may not auto-refresh. Ensure it reacts immediately (dispatcher, update listener, or explicit refresh).

Run to locate other uses and confirm update flow:

If it doesn’t auto-update, I can propose a minimal dispatcher-based update to keep the binary_sensor in sync when the switch toggles.


🏁 Script executed:

#!/bin/bash
# Find all references to CONF_WINTER_MODE and nearby state handling.
rg -nC3 '\bCONF_WINTER_MODE\b' custom_components/robonect

# Inspect binary sensor update hooks that might react to config entry changes.
rg -nC3 'binary_sensor|async_added_to_hass|dispatcher|update_entry' custom_components/robonect

Length of output: 20618


Propagate winter_mode changes to the binary_sensor via dispatcher
In custom_components/robonect/switch.py (lines 428–431, 437–440), after calling async_update_entry and update_ha_state, emit a signal (e.g. async_dispatcher_send(self.hass, SIGNAL_WINTER_MODE_UPDATED)). In custom_components/robonect/binary_sensor.py’s async_added_to_hass, subscribe to that signal and call self.async_write_ha_state() in the callback. This ensures the winter_mode binary_sensor (which reads entry.data) refreshes immediately when the switch toggles.

@geertmeersman geertmeersman merged commit e9c5f96 into main Sep 10, 2025
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat A new feature fix A bug fix minor A change requiring a minor version bump

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant