From 8c96375cb183bd4a25125fd3d5f5abe1841669a2 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Tue, 24 Feb 2026 14:02:02 +0100 Subject: [PATCH 1/9] Implement Core PR #163713 --- custom_components/plugwise/climate.py | 103 ++++++++++++------ tests/components/plugwise/test_climate.py | 125 +++++++++++++++++++--- 2 files changed, 177 insertions(+), 51 deletions(-) diff --git a/custom_components/plugwise/climate.py b/custom_components/plugwise/climate.py index a362170ee..95328ec5b 100644 --- a/custom_components/plugwise/climate.py +++ b/custom_components/plugwise/climate.py @@ -2,7 +2,7 @@ from __future__ import annotations -from dataclasses import dataclass +from dataclasses import asdict, dataclass from typing import Any from homeassistant.components.climate import ( @@ -108,10 +108,7 @@ def as_dict(self) -> dict[str, Any]: @classmethod def from_dict(cls, restored: dict[str, Any]) -> PlugwiseClimateExtraStoredData: """Initialize a stored data object from a dict.""" - return cls( - last_active_schedule=restored.get("last_active_schedule"), - previous_action_mode=restored.get("previous_action_mode"), - ) + return asdict(self) class PlugwiseClimateEntity(PlugwiseEntity, ClimateEntity, RestoreEntity): @@ -124,7 +121,7 @@ class PlugwiseClimateEntity(PlugwiseEntity, ClimateEntity, RestoreEntity): _enable_turn_on_off_backwards_compatibility = False _last_active_schedule: str | None = None - _previous_action_mode: str | None = HVACAction.HEATING.value # Upstream + _previous_action_mode: str | None = HVACAction.HEATING.value async def async_added_to_hass(self) -> None: """Run when entity about to be added.""" @@ -135,7 +132,9 @@ async def async_added_to_hass(self) -> None: extra_data.as_dict() ) self._last_active_schedule = plugwise_extra_data.last_active_schedule - self._previous_action_mode = plugwise_extra_data.previous_action_mode + self._previous_action_mode = ( + plugwise_extra_data.previous_action_mode or HVACAction.HEATING.value + ) def __init__( self, @@ -241,11 +240,10 @@ def hvac_modes(self) -> list[HVACMode]: if self.coordinator.api.cooling_present: if REGULATION_MODES in self._gateway_data: - selected = self._gateway_data.get(SELECT_REGULATION_MODE) - if selected == HVACAction.COOLING.value: - hvac_modes.append(HVACMode.COOL) - if selected == HVACAction.HEATING.value: + if "heating" in self._gateway_data[REGULATION_MODES]: hvac_modes.append(HVACMode.HEAT) + if "cooling" in self._gateway_data[REGULATION_MODES]: + hvac_modes.append(HVACMode.COOL) else: hvac_modes.append(HVACMode.HEAT_COOL) else: @@ -294,39 +292,76 @@ async def async_set_temperature(self, **kwargs: Any) -> None: await self.coordinator.api.set_temperature(self._location, data) + def _regulation_mode_for_hvac(self, hvac_mode: HVACMode) -> str | None: + """Return the API regulation value for a manual HVAC mode, or None.""" + if hvac_mode == HVACMode.HEAT: + return HVACAction.HEATING.value + if hvac_mode == HVACMode.COOL: + return HVACAction.COOLING.value + return None + @plugwise_command async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None: - """Set the hvac mode.""" + """Set the HVAC mode (off, heat, cool, heat_cool, or auto/schedule).""" if hvac_mode == self.hvac_mode: return + api = self.coordinator.api + current_schedule = self.device.get("select_schedule") + + # OFF: single API call if hvac_mode == HVACMode.OFF: - await self.coordinator.api.set_regulation_mode(hvac_mode.value) - else: - current = self.device.get("select_schedule") - desired = current - # Capture the last valid schedule - if desired and desired != "off": - self._last_active_schedule = desired - elif desired == "off": - desired = self._last_active_schedule - - # Enabling HVACMode.AUTO requires a previously set schedule for saving and restoring - if hvac_mode == HVACMode.AUTO and not desired: - raise HomeAssistantError( - translation_domain=DOMAIN, - translation_key=ERROR_NO_SCHEDULE, - ) + await api.set_regulation_mode(hvac_mode.value) + return - await self.coordinator.api.set_schedule_state( - self._location, - STATE_ON if hvac_mode == HVACMode.AUTO else STATE_OFF, - desired, + # Manual mode (heat/cool/heat_cool) without a schedule: set regulation only + if ( + current_schedule is None + and hvac_mode != HVACMode.AUTO + and ( + regulation := self._regulation_mode_for_hvac(hvac_mode) + or self._previous_action_mode ) - if self.hvac_mode == HVACMode.OFF and self._previous_action_mode: - await self.coordinator.api.set_regulation_mode( + ): + await api.set_regulation_mode(regulation) + return + + # Manual mode: ensure regulation and turn off schedule when needed + if hvac_mode in (HVACMode.HEAT, HVACMode.COOL, HVACMode.HEAT_COOL): + if ( + regulation := self._regulation_mode_for_hvac(hvac_mode) or ( self._previous_action_mode + if self.hvac_mode in (HVACMode.HEAT_COOL, HVACMode.OFF) + else None + ) + ): + await api.set_regulation_mode(regulation) + + if ( + self.hvac_mode == HVACMode.OFF and current_schedule not in (None, "off") + ) or (self.hvac_mode == HVACMode.AUTO and current_schedule is not None): + await api.set_schedule_state( + self._location, STATE_OFF, current_schedule ) + return + + # AUTO: restore schedule and regulation + desired_schedule = current_schedule + if desired_schedule and desired_schedule != "off": + self._last_active_schedule = desired_schedule + elif desired_schedule == "off": + desired_schedule = self._last_active_schedule + + if not desired_schedule: + raise HomeAssistantError( + translation_domain=DOMAIN, + translation_key=ERROR_NO_SCHEDULE, + ) + + if self._previous_action_mode: + if self.hvac_mode == HVACMode.OFF: + await api.set_regulation_mode(self._previous_action_mode) + await api.set_schedule_state(self._location, STATE_ON, desired_schedule) @plugwise_command async def async_set_preset_mode(self, preset_mode: str) -> None: diff --git a/tests/components/plugwise/test_climate.py b/tests/components/plugwise/test_climate.py index 9a348bc67..56af94292 100644 --- a/tests/components/plugwise/test_climate.py +++ b/tests/components/plugwise/test_climate.py @@ -167,7 +167,7 @@ async def test_adam_restore_state_climate( State("climate.bathroom", "heat"), PlugwiseClimateExtraStoredData( last_active_schedule="Badkamer", - previous_action_mode=None, + previous_action_mode="heating", ).as_dict(), ), ], @@ -207,7 +207,6 @@ async def test_adam_restore_state_climate( {ATTR_ENTITY_ID: "climate.living_room", ATTR_HVAC_MODE: HVACMode.HEAT}, blocking=True, ) - # Verify set_schedule_state was called with the restored schedule mock_smile_adam_heat_cool.set_regulation_mode.assert_called_with( "heating", ) @@ -222,7 +221,7 @@ async def test_adam_restore_state_climate( assert (state := hass.states.get("climate.bathroom")) assert state.state == "heat" - # Verify restoration is used when setting a schedule + # Verify restoration is used when setting the schedule, schedule == "off" await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_HVAC_MODE, @@ -233,7 +232,27 @@ async def test_adam_restore_state_climate( mock_smile_adam_heat_cool.set_schedule_state.assert_called_with( "f871b8c4d63549319221e294e4f88074", STATE_ON, "Badkamer" ) + assert mock_smile_adam_heat_cool.set_schedule_state.call_count == 1 + data = mock_smile_adam_heat_cool.async_update.return_value + data["f871b8c4d63549319221e294e4f88074"]["climate_mode"] = "heat" + data["f871b8c4d63549319221e294e4f88074"]["select_schedule"] = "Badkamer" + with patch(HA_PLUGWISE_SMILE_ASYNC_UPDATE, return_value=data): + freezer.tick(timedelta(minutes=1)) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + assert (state := hass.states.get("climate.bathroom")) + assert state.state == "heat" + + # Verify the active schedule is used + await hass.services.async_call( + CLIMATE_DOMAIN, + SERVICE_SET_HVAC_MODE, + {ATTR_ENTITY_ID: "climate.bathroom", ATTR_HVAC_MODE: HVACMode.AUTO}, + blocking=True, + ) + assert mock_smile_adam_heat_cool.set_schedule_state.call_count == 2 @pytest.mark.parametrize("chosen_env", ["m_adam_heating"], indirect=True) @pytest.mark.parametrize("cooling_present", [False], indirect=True) @@ -255,10 +274,33 @@ async def test_adam_2_climate_snapshot( async def test_adam_3_climate_entity_attributes( hass: HomeAssistant, mock_smile_adam_heat_cool: MagicMock, - init_integration: MockConfigEntry, + mock_config_entry: MockConfigEntry, freezer: FrozenDateTimeFactory, ) -> None: """Test creation of adam climate device environment.""" + mock_restore_cache_with_extra_data( + hass, + [ + ( + State("climate.living_room", "heat"), + PlugwiseClimateExtraStoredData( + last_active_schedule="Weekschema", + previous_action_mode="heating", + ).as_dict(), + ), + ( + State("climate.bathroom", "heat"), + PlugwiseClimateExtraStoredData( + last_active_schedule="Badkamer", + previous_action_mode="heating", + ).as_dict(), + ), + ], + ) + mock_config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + state = hass.states.get("climate.living_room") assert state assert state.state == HVACMode.COOL @@ -266,8 +308,10 @@ async def test_adam_3_climate_entity_attributes( assert state.attributes[ATTR_HVAC_MODES] == [ HVACMode.OFF, HVACMode.AUTO, + HVACMode.HEAT, HVACMode.COOL, ] + data = mock_smile_adam_heat_cool.async_update.return_value data["da224107914542988a88561b4452b0f6"]["select_regulation_mode"] = "heating" data["f2bf9048bef64cc5b6d5110154e33c81"]["climate_mode"] = "heat" @@ -283,11 +327,6 @@ async def test_adam_3_climate_entity_attributes( assert state assert state.state == HVACMode.HEAT assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.HEATING - assert state.attributes[ATTR_HVAC_MODES] == [ - HVACMode.OFF, - HVACMode.AUTO, - HVACMode.HEAT, - ] data = mock_smile_adam_heat_cool.async_update.return_value data["da224107914542988a88561b4452b0f6"]["select_regulation_mode"] = "cooling" @@ -304,12 +343,64 @@ async def test_adam_3_climate_entity_attributes( assert state assert state.state == HVACMode.COOL assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.COOLING - assert state.attributes[ATTR_HVAC_MODES] == [ - HVACMode.OFF, - HVACMode.AUTO, - HVACMode.COOL, - ] + data = mock_smile_adam_heat_cool.async_update.return_value + data["da224107914542988a88561b4452b0f6"]["select_regulation_mode"] = "off" + data["f2bf9048bef64cc5b6d5110154e33c81"]["climate_mode"] = "off" + data["f2bf9048bef64cc5b6d5110154e33c81"]["control_state"] = HVACAction.OFF + data["056ee145a816487eaa69243c3280f8bf"]["binary_sensors"]["cooling_state"] = True + data["056ee145a816487eaa69243c3280f8bf"]["binary_sensors"]["heating_state"] = False + with patch(HA_PLUGWISE_SMILE_ASYNC_UPDATE, return_value=data): + freezer.tick(timedelta(minutes=1)) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + assert (state := hass.states.get("climate.living_room")) + assert state.state == "off" + assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.OFF + + # Test setting regulation_mode to cooling, from off, ignoring the restored previous_action_mode + await hass.services.async_call( + CLIMATE_DOMAIN, + SERVICE_SET_HVAC_MODE, + {ATTR_ENTITY_ID: "climate.living_room", ATTR_HVAC_MODE: HVACMode.COOL}, + blocking=True, + ) + # Verify set_regulation_mode was called with the user-selected HVACMode + mock_smile_adam_heat_cool.set_regulation_mode.assert_called_with( + "cooling", + ) + + data = mock_smile_adam_heat_cool.async_update.return_value + data["da224107914542988a88561b4452b0f6"]["select_regulation_mode"] = "off" + data["f871b8c4d63549319221e294e4f88074"]["climate_mode"] = "off" + data["f871b8c4d63549319221e294e4f88074"]["control_state"] = HVACAction.OFF + data["056ee145a816487eaa69243c3280f8bf"]["binary_sensors"]["cooling_state"] = True + data["056ee145a816487eaa69243c3280f8bf"]["binary_sensors"]["heating_state"] = False + with patch(HA_PLUGWISE_SMILE_ASYNC_UPDATE, return_value=data): + freezer.tick(timedelta(minutes=1)) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + assert (state := hass.states.get("climate.bathroom")) + assert state.state == "off" + assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.OFF + + # Test setting to AUTO, from OFF + await hass.services.async_call( + CLIMATE_DOMAIN, + SERVICE_SET_HVAC_MODE, + {ATTR_ENTITY_ID: "climate.bathroom", ATTR_HVAC_MODE: HVACMode.AUTO}, + blocking=True, + ) + # Verify set_regulation_mode was called with the user-selected HVACMode + mock_smile_adam_heat_cool.set_regulation_mode.assert_called_with( + "cooling", + ) + # And set_schedule_state was called with the restored last_active_schedule + mock_smile_adam_heat_cool.set_schedule_state.assert_called_with( + "f871b8c4d63549319221e294e4f88074", STATE_ON, "Badkamer", + ) async def test_adam_climate_off_mode_change( hass: HomeAssistant, @@ -329,7 +420,7 @@ async def test_adam_climate_off_mode_change( }, blocking=True, ) - assert mock_smile_adam_jip.set_schedule_state.call_count == 1 + assert mock_smile_adam_jip.set_schedule_state.call_count == 0 assert mock_smile_adam_jip.set_regulation_mode.call_count == 1 mock_smile_adam_jip.set_regulation_mode.assert_called_with("heating") @@ -345,7 +436,7 @@ async def test_adam_climate_off_mode_change( }, blocking=True, ) - assert mock_smile_adam_jip.set_schedule_state.call_count == 1 + assert mock_smile_adam_jip.set_schedule_state.call_count == 0 assert mock_smile_adam_jip.set_regulation_mode.call_count == 2 mock_smile_adam_jip.set_regulation_mode.assert_called_with("off") @@ -361,7 +452,7 @@ async def test_adam_climate_off_mode_change( }, blocking=True, ) - assert mock_smile_adam_jip.set_schedule_state.call_count == 1 + assert mock_smile_adam_jip.set_schedule_state.call_count == 0 assert mock_smile_adam_jip.set_regulation_mode.call_count == 2 From 4363d3ac13b2971e37265511a7fc4f683aadef40 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Tue, 24 Feb 2026 17:48:13 +0100 Subject: [PATCH 2/9] Fix wrong update --- custom_components/plugwise/climate.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/custom_components/plugwise/climate.py b/custom_components/plugwise/climate.py index 95328ec5b..c12c557d6 100644 --- a/custom_components/plugwise/climate.py +++ b/custom_components/plugwise/climate.py @@ -100,15 +100,15 @@ class PlugwiseClimateExtraStoredData(ExtraStoredData): def as_dict(self) -> dict[str, Any]: """Return a dict representation of the text data.""" - return { - "last_active_schedule": self.last_active_schedule, - "previous_action_mode": self.previous_action_mode, - } + return asdict(self) @classmethod def from_dict(cls, restored: dict[str, Any]) -> PlugwiseClimateExtraStoredData: """Initialize a stored data object from a dict.""" - return asdict(self) + return cls( + last_active_schedule=restored.get("last_active_schedule"), + previous_action_mode=restored.get("previous_action_mode"), + ) class PlugwiseClimateEntity(PlugwiseEntity, ClimateEntity, RestoreEntity): From c57496e332ba10db357a371c0d4cb2d585f2711d Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Tue, 24 Feb 2026 18:03:50 +0100 Subject: [PATCH 3/9] Optimize --- custom_components/plugwise/climate.py | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/custom_components/plugwise/climate.py b/custom_components/plugwise/climate.py index c12c557d6..079ac99e0 100644 --- a/custom_components/plugwise/climate.py +++ b/custom_components/plugwise/climate.py @@ -144,7 +144,8 @@ def __init__( """Set up the Plugwise API.""" super().__init__(coordinator, device_id) - gateway_id: str = coordinator.api.gateway_id + self._api = coordinator.api + gateway_id: str = self._api.gateway_id self._gateway_data = coordinator.data[gateway_id] self._location = device_id if (location := self.device.get(LOCATION)) is not None: @@ -161,8 +162,8 @@ def __init__( # Determine supported features self._attr_supported_features = ClimateEntityFeature.TARGET_TEMPERATURE if ( - self.coordinator.api.cooling_present - and coordinator.api.smile.name != "Adam" + self._api.cooling_present + and self._api.smile.name != "Adam" ): self._attr_supported_features = ( ClimateEntityFeature.TARGET_TEMPERATURE_RANGE @@ -238,7 +239,7 @@ def hvac_modes(self) -> list[HVACMode]: if self.device.get(AVAILABLE_SCHEDULES, []): hvac_modes.append(HVACMode.AUTO) - if self.coordinator.api.cooling_present: + if self._api.cooling_present: if REGULATION_MODES in self._gateway_data: if "heating" in self._gateway_data[REGULATION_MODES]: hvac_modes.append(HVACMode.HEAT) @@ -290,7 +291,7 @@ async def async_set_temperature(self, **kwargs: Any) -> None: if mode := kwargs.get(ATTR_HVAC_MODE): await self.async_set_hvac_mode(mode) - await self.coordinator.api.set_temperature(self._location, data) + await self._api.set_temperature(self._location, data) def _regulation_mode_for_hvac(self, hvac_mode: HVACMode) -> str | None: """Return the API regulation value for a manual HVAC mode, or None.""" @@ -306,12 +307,10 @@ async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None: if hvac_mode == self.hvac_mode: return - api = self.coordinator.api current_schedule = self.device.get("select_schedule") - # OFF: single API call if hvac_mode == HVACMode.OFF: - await api.set_regulation_mode(hvac_mode.value) + await self._api.set_regulation_mode(hvac_mode.value) return # Manual mode (heat/cool/heat_cool) without a schedule: set regulation only @@ -323,7 +322,7 @@ async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None: or self._previous_action_mode ) ): - await api.set_regulation_mode(regulation) + await self._api.set_regulation_mode(regulation) return # Manual mode: ensure regulation and turn off schedule when needed @@ -335,12 +334,12 @@ async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None: else None ) ): - await api.set_regulation_mode(regulation) + await self._api.set_regulation_mode(regulation) if ( self.hvac_mode == HVACMode.OFF and current_schedule not in (None, "off") ) or (self.hvac_mode == HVACMode.AUTO and current_schedule is not None): - await api.set_schedule_state( + await self._api.set_schedule_state( self._location, STATE_OFF, current_schedule ) return @@ -360,10 +359,10 @@ async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None: if self._previous_action_mode: if self.hvac_mode == HVACMode.OFF: - await api.set_regulation_mode(self._previous_action_mode) - await api.set_schedule_state(self._location, STATE_ON, desired_schedule) + await self._api.set_regulation_mode(self._previous_action_mode) + await self._api.set_schedule_state(self._location, STATE_ON, desired_schedule) @plugwise_command async def async_set_preset_mode(self, preset_mode: str) -> None: """Set the preset mode.""" - await self.coordinator.api.set_preset(self._location, preset_mode) + await self._api.set_preset(self._location, preset_mode) From 03080c6d943f877b782dd5b7dededaec36018260 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Tue, 24 Feb 2026 18:06:55 +0100 Subject: [PATCH 4/9] Prettied translation file --- .../plugwise/translations/en.json | 672 +++++++++--------- 1 file changed, 336 insertions(+), 336 deletions(-) diff --git a/custom_components/plugwise/translations/en.json b/custom_components/plugwise/translations/en.json index 6c0ff827d..057c5fe14 100644 --- a/custom_components/plugwise/translations/en.json +++ b/custom_components/plugwise/translations/en.json @@ -1,347 +1,347 @@ { - "config": { - "abort": { - "already_configured": "This device is already configured", - "anna_with_adam": "Both Anna and Adam detected. Add your Adam instead of your Anna", - "not_the_same_smile": "The configured Smile ID does not match the Smile ID on the requested IP address.", - "reconfigure_successful": "Reconfiguration successful" - }, - "error": { - "cannot_connect": "Failed to connect", - "invalid_auth": "Authentication failed", - "invalid_setup": "Add your Adam instead of your Anna, see the documentation", - "network_down": "Plugwise Zigbee network is down", - "network_timeout": "Network communication timeout", - "response_error": "Invalid XML data, or error indication received from the Plugwise Adam/Smile/Stretch", - "stick_init": "Initialization of Plugwise USB-stick failed", - "unknown": "Unknown error!", - "unsupported": "Device with unsupported firmware" - }, - "step": { - "reconfigure": { - "data": { - "host": "IP-address", - "port": "Port number" + "config": { + "abort": { + "already_configured": "This device is already configured", + "anna_with_adam": "Both Anna and Adam detected. Add your Adam instead of your Anna", + "not_the_same_smile": "The configured Smile ID does not match the Smile ID on the requested IP address.", + "reconfigure_successful": "Reconfiguration successful" }, - "description": "Update configuration for {title}." - }, - "user": { - "data": { - "host": "IP-address", - "password": "ID", - "port": "Port number", - "username": "Username" + "error": { + "cannot_connect": "Failed to connect", + "invalid_auth": "Authentication failed", + "invalid_setup": "Add your Adam instead of your Anna, see the documentation", + "network_down": "Plugwise Zigbee network is down", + "network_timeout": "Network communication timeout", + "response_error": "Invalid XML data, or error indication received from the Plugwise Adam/Smile/Stretch", + "stick_init": "Initialization of Plugwise USB-stick failed", + "unknown": "Unknown error!", + "unsupported": "Device with unsupported firmware" }, - "description": "Enter your Plugwise device: (setup can take up to 90s)", - "title": "Set up Plugwise Adam/Smile/Stretch" - } - } - }, - "entity": { - "binary_sensor": { - "compressor_state": { - "name": "Compressor state" - }, - "cooling_enabled": { - "name": "Cooling enabled" - }, - "cooling_state": { - "name": "Cooling" - }, - "dhw_state": { - "name": "DHW state" - }, - "flame_state": { - "name": "Flame state" - }, - "heating_state": { - "name": "Heating" - }, - "low_battery": { - "name": "Battery status" - }, - "plugwise_notification": { - "name": "Plugwise notification" - }, - "secondary_boiler_state": { - "name": "Secondary boiler state" - } - }, - "button": { - "reboot": { - "name": "Reboot" - } - }, - "climate": { - "plugwise": { - "state_attributes": { - "preset_mode": { - "state": { - "asleep": "Night", - "away": "Away", - "home": "Home", - "no_frost": "Anti-frost", - "vacation": "Vacation" + "step": { + "reconfigure": { + "data": { + "host": "IP-address", + "port": "Port number" + }, + "description": "Update configuration for {title}." + }, + "user": { + "data": { + "host": "IP-address", + "password": "ID", + "port": "Port number", + "username": "Username" + }, + "description": "Enter your Plugwise device: (setup can take up to 90s)", + "title": "Set up Plugwise Adam/Smile/Stretch" } - } } - } - }, - "number": { - "max_dhw_temperature": { - "name": "Domestic hot water setpoint" - }, - "maximum_boiler_temperature": { - "name": "Maximum boiler temperature setpoint" - }, - "temperature_offset": { - "name": "Temperature offset" - } }, - "select": { - "select_dhw_mode": { - "name": "DHW mode", - "state": { - "auto": "Auto", - "boost": "Boost", - "comfort": "Comfort", - "off": "Off" - } - }, - "select_gateway_mode": { - "name": "Gateway mode", - "state": { - "away": "Pause", - "full": "Normal", - "vacation": "Vacation" - } - }, - "select_regulation_mode": { - "name": "Regulation mode", - "state": { - "bleeding_cold": "Bleeding cold", - "bleeding_hot": "Bleeding hot", - "cooling": "Cooling", - "heating": "Heating", - "off": "Off" - } - }, - "select_schedule": { - "name": "Thermostat schedule", - "state": { - "off": "Off" - } - }, - "select_zone_profile": { - "name": "Zone profile", - "state": { - "active": "Active", - "off": "Off", - "passive": "Passive" + "entity": { + "binary_sensor": { + "compressor_state": { + "name": "Compressor state" + }, + "cooling_enabled": { + "name": "Cooling enabled" + }, + "cooling_state": { + "name": "Cooling" + }, + "dhw_state": { + "name": "DHW state" + }, + "flame_state": { + "name": "Flame state" + }, + "heating_state": { + "name": "Heating" + }, + "low_battery": { + "name": "Battery status" + }, + "plugwise_notification": { + "name": "Plugwise notification" + }, + "secondary_boiler_state": { + "name": "Secondary boiler state" + } + }, + "button": { + "reboot": { + "name": "Reboot" + } + }, + "climate": { + "plugwise": { + "state_attributes": { + "preset_mode": { + "state": { + "asleep": "Night", + "away": "Away", + "home": "Home", + "no_frost": "Anti-frost", + "vacation": "Vacation" + } + } + } + } + }, + "number": { + "max_dhw_temperature": { + "name": "Domestic hot water setpoint" + }, + "maximum_boiler_temperature": { + "name": "Maximum boiler temperature setpoint" + }, + "temperature_offset": { + "name": "Temperature offset" + } + }, + "select": { + "select_dhw_mode": { + "name": "DHW mode", + "state": { + "auto": "Auto", + "boost": "Boost", + "comfort": "Comfort", + "off": "Off" + } + }, + "select_gateway_mode": { + "name": "Gateway mode", + "state": { + "away": "Pause", + "full": "Normal", + "vacation": "Vacation" + } + }, + "select_regulation_mode": { + "name": "Regulation mode", + "state": { + "bleeding_cold": "Bleeding cold", + "bleeding_hot": "Bleeding hot", + "cooling": "Cooling", + "heating": "Heating", + "off": "Off" + } + }, + "select_schedule": { + "name": "Thermostat schedule", + "state": { + "off": "Off" + } + }, + "select_zone_profile": { + "name": "Zone profile", + "state": { + "active": "Active", + "off": "Off", + "passive": "Passive" + } + } + }, + "sensor": { + "cooling_setpoint": { + "name": "Cooling setpoint" + }, + "dhw_temperature": { + "name": "DHW temperature" + }, + "domestic_hot_water_setpoint": { + "name": "DHW setpoint" + }, + "electricity_consumed": { + "name": "Electricity consumed" + }, + "electricity_consumed_interval": { + "name": "Electricity consumed interval" + }, + "electricity_consumed_off_peak_cumulative": { + "name": "Electricity consumed off-peak cumulative" + }, + "electricity_consumed_off_peak_interval": { + "name": "Electricity consumed off-peak interval" + }, + "electricity_consumed_off_peak_point": { + "name": "Electricity consumed off-peak point" + }, + "electricity_consumed_peak_cumulative": { + "name": "Electricity consumed peak cumulative" + }, + "electricity_consumed_peak_interval": { + "name": "Electricity consumed peak interval" + }, + "electricity_consumed_peak_point": { + "name": "Electricity consumed peak point" + }, + "electricity_consumed_point": { + "name": "Electricity consumed point" + }, + "electricity_phase_one_consumed": { + "name": "Electricity phase one consumed" + }, + "electricity_phase_one_produced": { + "name": "Electricity phase one produced" + }, + "electricity_phase_three_consumed": { + "name": "Electricity phase three consumed" + }, + "electricity_phase_three_produced": { + "name": "Electricity phase three produced" + }, + "electricity_phase_two_consumed": { + "name": "Electricity phase two consumed" + }, + "electricity_phase_two_produced": { + "name": "Electricity phase two produced" + }, + "electricity_produced": { + "name": "Electricity produced" + }, + "electricity_produced_interval": { + "name": "Electricity produced interval" + }, + "electricity_produced_off_peak_cumulative": { + "name": "Electricity produced off-peak cumulative" + }, + "electricity_produced_off_peak_interval": { + "name": "Electricity produced off-peak interval" + }, + "electricity_produced_off_peak_point": { + "name": "Electricity produced off-peak point" + }, + "electricity_produced_peak_cumulative": { + "name": "Electricity produced peak cumulative" + }, + "electricity_produced_peak_interval": { + "name": "Electricity produced peak interval" + }, + "electricity_produced_peak_point": { + "name": "Electricity produced peak point" + }, + "electricity_produced_point": { + "name": "Electricity produced point" + }, + "gas_consumed_cumulative": { + "name": "Gas consumed cumulative" + }, + "gas_consumed_interval": { + "name": "Gas consumed interval" + }, + "heating_setpoint": { + "name": "Heating setpoint" + }, + "intended_boiler_temperature": { + "name": "Intended boiler temperature" + }, + "maximum_boiler_temperature": { + "name": "Maximum boiler temperature setpoint" + }, + "modulation_level": { + "name": "Modulation level" + }, + "net_electricity_cumulative": { + "name": "Net electricity cumulative" + }, + "net_electricity_point": { + "name": "Net electricity point" + }, + "outdoor_air_temperature": { + "name": "Outdoor air temperature" + }, + "outdoor_temperature": { + "name": "Outdoor temperature" + }, + "return_temperature": { + "name": "Return temperature" + }, + "setpoint": { + "name": "Setpoint" + }, + "temperature_difference": { + "name": "Temperature difference" + }, + "valve_position": { + "name": "Valve position" + }, + "voltage_phase_one": { + "name": "Voltage phase one" + }, + "voltage_phase_three": { + "name": "Voltage phase three" + }, + "voltage_phase_two": { + "name": "Voltage phase two" + }, + "water_pressure": { + "name": "Water pressure" + }, + "water_temperature": { + "name": "Water temperature" + } + }, + "switch": { + "cooling_ena_switch": { + "name": "Cooling" + }, + "dhw_cm_switch": { + "name": "DHW comfort mode" + }, + "lock": { + "name": "Lock" + }, + "relay": { + "name": "Relay" + } } - } - }, - "sensor": { - "cooling_setpoint": { - "name": "Cooling setpoint" - }, - "dhw_temperature": { - "name": "DHW temperature" - }, - "domestic_hot_water_setpoint": { - "name": "DHW setpoint" - }, - "electricity_consumed": { - "name": "Electricity consumed" - }, - "electricity_consumed_interval": { - "name": "Electricity consumed interval" - }, - "electricity_consumed_off_peak_cumulative": { - "name": "Electricity consumed off-peak cumulative" - }, - "electricity_consumed_off_peak_interval": { - "name": "Electricity consumed off-peak interval" - }, - "electricity_consumed_off_peak_point": { - "name": "Electricity consumed off-peak point" - }, - "electricity_consumed_peak_cumulative": { - "name": "Electricity consumed peak cumulative" - }, - "electricity_consumed_peak_interval": { - "name": "Electricity consumed peak interval" - }, - "electricity_consumed_peak_point": { - "name": "Electricity consumed peak point" - }, - "electricity_consumed_point": { - "name": "Electricity consumed point" - }, - "electricity_phase_one_consumed": { - "name": "Electricity phase one consumed" - }, - "electricity_phase_one_produced": { - "name": "Electricity phase one produced" - }, - "electricity_phase_three_consumed": { - "name": "Electricity phase three consumed" - }, - "electricity_phase_three_produced": { - "name": "Electricity phase three produced" - }, - "electricity_phase_two_consumed": { - "name": "Electricity phase two consumed" - }, - "electricity_phase_two_produced": { - "name": "Electricity phase two produced" - }, - "electricity_produced": { - "name": "Electricity produced" - }, - "electricity_produced_interval": { - "name": "Electricity produced interval" - }, - "electricity_produced_off_peak_cumulative": { - "name": "Electricity produced off-peak cumulative" - }, - "electricity_produced_off_peak_interval": { - "name": "Electricity produced off-peak interval" - }, - "electricity_produced_off_peak_point": { - "name": "Electricity produced off-peak point" - }, - "electricity_produced_peak_cumulative": { - "name": "Electricity produced peak cumulative" - }, - "electricity_produced_peak_interval": { - "name": "Electricity produced peak interval" - }, - "electricity_produced_peak_point": { - "name": "Electricity produced peak point" - }, - "electricity_produced_point": { - "name": "Electricity produced point" - }, - "gas_consumed_cumulative": { - "name": "Gas consumed cumulative" - }, - "gas_consumed_interval": { - "name": "Gas consumed interval" - }, - "heating_setpoint": { - "name": "Heating setpoint" - }, - "intended_boiler_temperature": { - "name": "Intended boiler temperature" - }, - "maximum_boiler_temperature": { - "name": "Maximum boiler temperature setpoint" - }, - "modulation_level": { - "name": "Modulation level" - }, - "net_electricity_cumulative": { - "name": "Net electricity cumulative" - }, - "net_electricity_point": { - "name": "Net electricity point" - }, - "outdoor_air_temperature": { - "name": "Outdoor air temperature" - }, - "outdoor_temperature": { - "name": "Outdoor temperature" - }, - "return_temperature": { - "name": "Return temperature" - }, - "setpoint": { - "name": "Setpoint" - }, - "temperature_difference": { - "name": "Temperature difference" - }, - "valve_position": { - "name": "Valve position" - }, - "voltage_phase_one": { - "name": "Voltage phase one" - }, - "voltage_phase_three": { - "name": "Voltage phase three" - }, - "voltage_phase_two": { - "name": "Voltage phase two" - }, - "water_pressure": { - "name": "Water pressure" - }, - "water_temperature": { - "name": "Water temperature" - } - }, - "switch": { - "cooling_ena_switch": { - "name": "Cooling" - }, - "dhw_cm_switch": { - "name": "DHW comfort mode" - }, - "lock": { - "name": "Lock" - }, - "relay": { - "name": "Relay" - } - } - }, - "exceptions": { - "authentication_failed": { - "message": "Invalid authentication" - }, - "data_incomplete_or_missing": { - "message": "Data incomplete or missing." - }, - "error_communicating_with_api": { - "message": "Error communicating with API: {error}." }, - "failed_to_connect": { - "message": "Failed to connect" - }, - "invalid_setup": { - "message": "Add your Adam instead of your Anna, see the documentation" - }, - "response_error": { - "message": "Invalid XML data, or error indication received from the Plugwise Adam/Smile/Stretch" + "exceptions": { + "authentication_failed": { + "message": "Invalid authentication" + }, + "data_incomplete_or_missing": { + "message": "Data incomplete or missing." + }, + "error_communicating_with_api": { + "message": "Error communicating with API: {error}." + }, + "failed_to_connect": { + "message": "Failed to connect" + }, + "invalid_setup": { + "message": "Add your Adam instead of your Anna, see the documentation" + }, + "response_error": { + "message": "Invalid XML data, or error indication received from the Plugwise Adam/Smile/Stretch" + }, + "set_schedule_first": { + "message": "Failed setting HVACMode, set a schedule first." + }, + "unsupported_firmware": { + "message": "Device with unsupported firmware" + } }, - "set_schedule_first": { - "message": "Failed setting HVACMode, set a schedule first." + "options": { + "step": { + "init": { + "data": { + "cooling_on": "Anna: cooling-mode is on", + "refresh_interval": "Frontend refresh-time (1.5 - 5 seconds) *) beta-only option", + "scan_interval": "Scan Interval (seconds) *) beta-only option" + }, + "description": "Adjust Smile/Stretch Options" + }, + "none": { + "description": "This Integration does not provide any Options", + "title": "No Options available" + } + } }, - "unsupported_firmware": { - "message": "Device with unsupported firmware" - } - }, - "options": { - "step": { - "init": { - "data": { - "cooling_on": "Anna: cooling-mode is on", - "refresh_interval": "Frontend refresh-time (1.5 - 5 seconds) *) beta-only option", - "scan_interval": "Scan Interval (seconds) *) beta-only option" - }, - "description": "Adjust Smile/Stretch Options" - }, - "none": { - "description": "This Integration does not provide any Options", - "title": "No Options available" - } - } - }, - "services": { - "delete_notification": { - "description": "Deletes a Plugwise Notification", - "name": "Delete Plugwise notification" + "services": { + "delete_notification": { + "description": "Deletes a Plugwise Notification", + "name": "Delete Plugwise notification" + } } - } -} +} \ No newline at end of file From 7e3016b30df5636ff334e715d352a774fe7a2d8d Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Tue, 24 Feb 2026 18:08:47 +0100 Subject: [PATCH 5/9] Update CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d1a53499..83c5440f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ Versions from 0.40 and up +## v0.63.1 + +- Implement Core PR [#163713](https://github.com/home-assistant/core/pull/163713) via PR [#1024](https://github.com/plugwise/plugwise-beta/pull/1024) + ## v0.63.0 - Remove climate home-kit emulation option via PR [#1023](https://github.com/plugwise/plugwise-beta/pull/1023) From 705b28a0ef3bb92a67798a6dfaf827263d659a9b Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Tue, 24 Feb 2026 18:11:45 +0100 Subject: [PATCH 6/9] Set to v0.63.1 release version --- custom_components/plugwise/manifest.json | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/plugwise/manifest.json b/custom_components/plugwise/manifest.json index 825e0d762..3d5bb03fc 100644 --- a/custom_components/plugwise/manifest.json +++ b/custom_components/plugwise/manifest.json @@ -8,6 +8,6 @@ "iot_class": "local_polling", "loggers": ["plugwise"], "requirements": ["plugwise==1.11.2"], - "version": "0.63.0", + "version": "0.63.1", "zeroconf": ["_plugwise._tcp.local."] } diff --git a/pyproject.toml b/pyproject.toml index 5be9f8167..801e2daf4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "plugwise-beta" -version = "0.63.0" +version = "0.63.1" description = "Plugwise beta custom-component" readme = "README.md" requires-python = ">=3.13" From 58b6a0f76b23b85e69b060addfb927aa7208d73c Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Tue, 24 Feb 2026 18:46:20 +0100 Subject: [PATCH 7/9] Reduce complexity --- custom_components/plugwise/climate.py | 38 ++++++++++++++++----------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/custom_components/plugwise/climate.py b/custom_components/plugwise/climate.py index 079ac99e0..71bcf4cbd 100644 --- a/custom_components/plugwise/climate.py +++ b/custom_components/plugwise/climate.py @@ -327,21 +327,7 @@ async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None: # Manual mode: ensure regulation and turn off schedule when needed if hvac_mode in (HVACMode.HEAT, HVACMode.COOL, HVACMode.HEAT_COOL): - if ( - regulation := self._regulation_mode_for_hvac(hvac_mode) or ( - self._previous_action_mode - if self.hvac_mode in (HVACMode.HEAT_COOL, HVACMode.OFF) - else None - ) - ): - await self._api.set_regulation_mode(regulation) - - if ( - self.hvac_mode == HVACMode.OFF and current_schedule not in (None, "off") - ) or (self.hvac_mode == HVACMode.AUTO and current_schedule is not None): - await self._api.set_schedule_state( - self._location, STATE_OFF, current_schedule - ) + await self._set_manual_hvac_mode(hvac_mode, current_schedule) return # AUTO: restore schedule and regulation @@ -357,10 +343,30 @@ async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None: translation_key=ERROR_NO_SCHEDULE, ) + await self._set_auto_hvac_mode(desired_schedule) + + async def _set_manual_hvac_mode(self, mode: HVACMode, schedule: str | None) -> None: + """Execute relevant api-functions based on the requested manual and present mode.""" + if ( + regulation := self._regulation_mode_for_hvac(mode) or ( + self._previous_action_mode + if self.hvac_mode in (HVACMode.HEAT_COOL, HVACMode.OFF) + else None + ) + ): + await self._api.set_regulation_mode(regulation) + + if ( + self.hvac_mode == HVACMode.OFF and schedule not in (None, "off") + ) or (self.hvac_mode == HVACMode.AUTO and schedule is not None): + await self._api.set_schedule_state(self._location, STATE_OFF, schedule) + + async def _set_auto_hvac_mode(self, schedule: str) -> None: + """Execute relevant api-functions based on the requested auto and present mode.""" if self._previous_action_mode: if self.hvac_mode == HVACMode.OFF: await self._api.set_regulation_mode(self._previous_action_mode) - await self._api.set_schedule_state(self._location, STATE_ON, desired_schedule) + await self._api.set_schedule_state(self._location, STATE_ON, schedule) @plugwise_command async def async_set_preset_mode(self, preset_mode: str) -> None: From ac8803d7841b84c23047eded7ffeb5505b4a0491 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Tue, 24 Feb 2026 18:59:32 +0100 Subject: [PATCH 8/9] en.json: add empty line at end-of-file --- custom_components/plugwise/translations/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/plugwise/translations/en.json b/custom_components/plugwise/translations/en.json index 057c5fe14..aae4b6ea1 100644 --- a/custom_components/plugwise/translations/en.json +++ b/custom_components/plugwise/translations/en.json @@ -344,4 +344,4 @@ "name": "Delete Plugwise notification" } } -} \ No newline at end of file +} From 50bf59262a1420807e3827540013f89331195b6f Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Tue, 24 Feb 2026 19:14:47 +0100 Subject: [PATCH 9/9] Fix json formatting --- .../plugwise/translations/en.json | 670 +++++++++--------- 1 file changed, 335 insertions(+), 335 deletions(-) diff --git a/custom_components/plugwise/translations/en.json b/custom_components/plugwise/translations/en.json index aae4b6ea1..6c0ff827d 100644 --- a/custom_components/plugwise/translations/en.json +++ b/custom_components/plugwise/translations/en.json @@ -1,347 +1,347 @@ { - "config": { - "abort": { - "already_configured": "This device is already configured", - "anna_with_adam": "Both Anna and Adam detected. Add your Adam instead of your Anna", - "not_the_same_smile": "The configured Smile ID does not match the Smile ID on the requested IP address.", - "reconfigure_successful": "Reconfiguration successful" - }, - "error": { - "cannot_connect": "Failed to connect", - "invalid_auth": "Authentication failed", - "invalid_setup": "Add your Adam instead of your Anna, see the documentation", - "network_down": "Plugwise Zigbee network is down", - "network_timeout": "Network communication timeout", - "response_error": "Invalid XML data, or error indication received from the Plugwise Adam/Smile/Stretch", - "stick_init": "Initialization of Plugwise USB-stick failed", - "unknown": "Unknown error!", - "unsupported": "Device with unsupported firmware" - }, - "step": { - "reconfigure": { - "data": { - "host": "IP-address", - "port": "Port number" - }, - "description": "Update configuration for {title}." - }, - "user": { - "data": { - "host": "IP-address", - "password": "ID", - "port": "Port number", - "username": "Username" - }, - "description": "Enter your Plugwise device: (setup can take up to 90s)", - "title": "Set up Plugwise Adam/Smile/Stretch" - } - } + "config": { + "abort": { + "already_configured": "This device is already configured", + "anna_with_adam": "Both Anna and Adam detected. Add your Adam instead of your Anna", + "not_the_same_smile": "The configured Smile ID does not match the Smile ID on the requested IP address.", + "reconfigure_successful": "Reconfiguration successful" }, - "entity": { - "binary_sensor": { - "compressor_state": { - "name": "Compressor state" - }, - "cooling_enabled": { - "name": "Cooling enabled" - }, - "cooling_state": { - "name": "Cooling" - }, - "dhw_state": { - "name": "DHW state" - }, - "flame_state": { - "name": "Flame state" - }, - "heating_state": { - "name": "Heating" - }, - "low_battery": { - "name": "Battery status" - }, - "plugwise_notification": { - "name": "Plugwise notification" - }, - "secondary_boiler_state": { - "name": "Secondary boiler state" - } - }, - "button": { - "reboot": { - "name": "Reboot" - } - }, - "climate": { - "plugwise": { - "state_attributes": { - "preset_mode": { - "state": { - "asleep": "Night", - "away": "Away", - "home": "Home", - "no_frost": "Anti-frost", - "vacation": "Vacation" - } - } - } - } - }, - "number": { - "max_dhw_temperature": { - "name": "Domestic hot water setpoint" - }, - "maximum_boiler_temperature": { - "name": "Maximum boiler temperature setpoint" - }, - "temperature_offset": { - "name": "Temperature offset" - } - }, - "select": { - "select_dhw_mode": { - "name": "DHW mode", - "state": { - "auto": "Auto", - "boost": "Boost", - "comfort": "Comfort", - "off": "Off" - } - }, - "select_gateway_mode": { - "name": "Gateway mode", - "state": { - "away": "Pause", - "full": "Normal", - "vacation": "Vacation" - } - }, - "select_regulation_mode": { - "name": "Regulation mode", - "state": { - "bleeding_cold": "Bleeding cold", - "bleeding_hot": "Bleeding hot", - "cooling": "Cooling", - "heating": "Heating", - "off": "Off" - } - }, - "select_schedule": { - "name": "Thermostat schedule", - "state": { - "off": "Off" - } - }, - "select_zone_profile": { - "name": "Zone profile", - "state": { - "active": "Active", - "off": "Off", - "passive": "Passive" - } - } - }, - "sensor": { - "cooling_setpoint": { - "name": "Cooling setpoint" - }, - "dhw_temperature": { - "name": "DHW temperature" - }, - "domestic_hot_water_setpoint": { - "name": "DHW setpoint" - }, - "electricity_consumed": { - "name": "Electricity consumed" - }, - "electricity_consumed_interval": { - "name": "Electricity consumed interval" - }, - "electricity_consumed_off_peak_cumulative": { - "name": "Electricity consumed off-peak cumulative" - }, - "electricity_consumed_off_peak_interval": { - "name": "Electricity consumed off-peak interval" - }, - "electricity_consumed_off_peak_point": { - "name": "Electricity consumed off-peak point" - }, - "electricity_consumed_peak_cumulative": { - "name": "Electricity consumed peak cumulative" - }, - "electricity_consumed_peak_interval": { - "name": "Electricity consumed peak interval" - }, - "electricity_consumed_peak_point": { - "name": "Electricity consumed peak point" - }, - "electricity_consumed_point": { - "name": "Electricity consumed point" - }, - "electricity_phase_one_consumed": { - "name": "Electricity phase one consumed" - }, - "electricity_phase_one_produced": { - "name": "Electricity phase one produced" - }, - "electricity_phase_three_consumed": { - "name": "Electricity phase three consumed" - }, - "electricity_phase_three_produced": { - "name": "Electricity phase three produced" - }, - "electricity_phase_two_consumed": { - "name": "Electricity phase two consumed" - }, - "electricity_phase_two_produced": { - "name": "Electricity phase two produced" - }, - "electricity_produced": { - "name": "Electricity produced" - }, - "electricity_produced_interval": { - "name": "Electricity produced interval" - }, - "electricity_produced_off_peak_cumulative": { - "name": "Electricity produced off-peak cumulative" - }, - "electricity_produced_off_peak_interval": { - "name": "Electricity produced off-peak interval" - }, - "electricity_produced_off_peak_point": { - "name": "Electricity produced off-peak point" - }, - "electricity_produced_peak_cumulative": { - "name": "Electricity produced peak cumulative" - }, - "electricity_produced_peak_interval": { - "name": "Electricity produced peak interval" - }, - "electricity_produced_peak_point": { - "name": "Electricity produced peak point" - }, - "electricity_produced_point": { - "name": "Electricity produced point" - }, - "gas_consumed_cumulative": { - "name": "Gas consumed cumulative" - }, - "gas_consumed_interval": { - "name": "Gas consumed interval" - }, - "heating_setpoint": { - "name": "Heating setpoint" - }, - "intended_boiler_temperature": { - "name": "Intended boiler temperature" - }, - "maximum_boiler_temperature": { - "name": "Maximum boiler temperature setpoint" - }, - "modulation_level": { - "name": "Modulation level" - }, - "net_electricity_cumulative": { - "name": "Net electricity cumulative" - }, - "net_electricity_point": { - "name": "Net electricity point" - }, - "outdoor_air_temperature": { - "name": "Outdoor air temperature" - }, - "outdoor_temperature": { - "name": "Outdoor temperature" - }, - "return_temperature": { - "name": "Return temperature" - }, - "setpoint": { - "name": "Setpoint" - }, - "temperature_difference": { - "name": "Temperature difference" - }, - "valve_position": { - "name": "Valve position" - }, - "voltage_phase_one": { - "name": "Voltage phase one" - }, - "voltage_phase_three": { - "name": "Voltage phase three" - }, - "voltage_phase_two": { - "name": "Voltage phase two" - }, - "water_pressure": { - "name": "Water pressure" - }, - "water_temperature": { - "name": "Water temperature" - } - }, - "switch": { - "cooling_ena_switch": { - "name": "Cooling" - }, - "dhw_cm_switch": { - "name": "DHW comfort mode" - }, - "lock": { - "name": "Lock" - }, - "relay": { - "name": "Relay" - } - } + "error": { + "cannot_connect": "Failed to connect", + "invalid_auth": "Authentication failed", + "invalid_setup": "Add your Adam instead of your Anna, see the documentation", + "network_down": "Plugwise Zigbee network is down", + "network_timeout": "Network communication timeout", + "response_error": "Invalid XML data, or error indication received from the Plugwise Adam/Smile/Stretch", + "stick_init": "Initialization of Plugwise USB-stick failed", + "unknown": "Unknown error!", + "unsupported": "Device with unsupported firmware" }, - "exceptions": { - "authentication_failed": { - "message": "Invalid authentication" - }, - "data_incomplete_or_missing": { - "message": "Data incomplete or missing." - }, - "error_communicating_with_api": { - "message": "Error communicating with API: {error}." - }, - "failed_to_connect": { - "message": "Failed to connect" - }, - "invalid_setup": { - "message": "Add your Adam instead of your Anna, see the documentation" + "step": { + "reconfigure": { + "data": { + "host": "IP-address", + "port": "Port number" }, - "response_error": { - "message": "Invalid XML data, or error indication received from the Plugwise Adam/Smile/Stretch" + "description": "Update configuration for {title}." + }, + "user": { + "data": { + "host": "IP-address", + "password": "ID", + "port": "Port number", + "username": "Username" }, - "set_schedule_first": { - "message": "Failed setting HVACMode, set a schedule first." - }, - "unsupported_firmware": { - "message": "Device with unsupported firmware" - } + "description": "Enter your Plugwise device: (setup can take up to 90s)", + "title": "Set up Plugwise Adam/Smile/Stretch" + } + } + }, + "entity": { + "binary_sensor": { + "compressor_state": { + "name": "Compressor state" + }, + "cooling_enabled": { + "name": "Cooling enabled" + }, + "cooling_state": { + "name": "Cooling" + }, + "dhw_state": { + "name": "DHW state" + }, + "flame_state": { + "name": "Flame state" + }, + "heating_state": { + "name": "Heating" + }, + "low_battery": { + "name": "Battery status" + }, + "plugwise_notification": { + "name": "Plugwise notification" + }, + "secondary_boiler_state": { + "name": "Secondary boiler state" + } }, - "options": { - "step": { - "init": { - "data": { - "cooling_on": "Anna: cooling-mode is on", - "refresh_interval": "Frontend refresh-time (1.5 - 5 seconds) *) beta-only option", - "scan_interval": "Scan Interval (seconds) *) beta-only option" - }, - "description": "Adjust Smile/Stretch Options" - }, - "none": { - "description": "This Integration does not provide any Options", - "title": "No Options available" + "button": { + "reboot": { + "name": "Reboot" + } + }, + "climate": { + "plugwise": { + "state_attributes": { + "preset_mode": { + "state": { + "asleep": "Night", + "away": "Away", + "home": "Home", + "no_frost": "Anti-frost", + "vacation": "Vacation" } + } } + } + }, + "number": { + "max_dhw_temperature": { + "name": "Domestic hot water setpoint" + }, + "maximum_boiler_temperature": { + "name": "Maximum boiler temperature setpoint" + }, + "temperature_offset": { + "name": "Temperature offset" + } }, - "services": { - "delete_notification": { - "description": "Deletes a Plugwise Notification", - "name": "Delete Plugwise notification" + "select": { + "select_dhw_mode": { + "name": "DHW mode", + "state": { + "auto": "Auto", + "boost": "Boost", + "comfort": "Comfort", + "off": "Off" + } + }, + "select_gateway_mode": { + "name": "Gateway mode", + "state": { + "away": "Pause", + "full": "Normal", + "vacation": "Vacation" } + }, + "select_regulation_mode": { + "name": "Regulation mode", + "state": { + "bleeding_cold": "Bleeding cold", + "bleeding_hot": "Bleeding hot", + "cooling": "Cooling", + "heating": "Heating", + "off": "Off" + } + }, + "select_schedule": { + "name": "Thermostat schedule", + "state": { + "off": "Off" + } + }, + "select_zone_profile": { + "name": "Zone profile", + "state": { + "active": "Active", + "off": "Off", + "passive": "Passive" + } + } + }, + "sensor": { + "cooling_setpoint": { + "name": "Cooling setpoint" + }, + "dhw_temperature": { + "name": "DHW temperature" + }, + "domestic_hot_water_setpoint": { + "name": "DHW setpoint" + }, + "electricity_consumed": { + "name": "Electricity consumed" + }, + "electricity_consumed_interval": { + "name": "Electricity consumed interval" + }, + "electricity_consumed_off_peak_cumulative": { + "name": "Electricity consumed off-peak cumulative" + }, + "electricity_consumed_off_peak_interval": { + "name": "Electricity consumed off-peak interval" + }, + "electricity_consumed_off_peak_point": { + "name": "Electricity consumed off-peak point" + }, + "electricity_consumed_peak_cumulative": { + "name": "Electricity consumed peak cumulative" + }, + "electricity_consumed_peak_interval": { + "name": "Electricity consumed peak interval" + }, + "electricity_consumed_peak_point": { + "name": "Electricity consumed peak point" + }, + "electricity_consumed_point": { + "name": "Electricity consumed point" + }, + "electricity_phase_one_consumed": { + "name": "Electricity phase one consumed" + }, + "electricity_phase_one_produced": { + "name": "Electricity phase one produced" + }, + "electricity_phase_three_consumed": { + "name": "Electricity phase three consumed" + }, + "electricity_phase_three_produced": { + "name": "Electricity phase three produced" + }, + "electricity_phase_two_consumed": { + "name": "Electricity phase two consumed" + }, + "electricity_phase_two_produced": { + "name": "Electricity phase two produced" + }, + "electricity_produced": { + "name": "Electricity produced" + }, + "electricity_produced_interval": { + "name": "Electricity produced interval" + }, + "electricity_produced_off_peak_cumulative": { + "name": "Electricity produced off-peak cumulative" + }, + "electricity_produced_off_peak_interval": { + "name": "Electricity produced off-peak interval" + }, + "electricity_produced_off_peak_point": { + "name": "Electricity produced off-peak point" + }, + "electricity_produced_peak_cumulative": { + "name": "Electricity produced peak cumulative" + }, + "electricity_produced_peak_interval": { + "name": "Electricity produced peak interval" + }, + "electricity_produced_peak_point": { + "name": "Electricity produced peak point" + }, + "electricity_produced_point": { + "name": "Electricity produced point" + }, + "gas_consumed_cumulative": { + "name": "Gas consumed cumulative" + }, + "gas_consumed_interval": { + "name": "Gas consumed interval" + }, + "heating_setpoint": { + "name": "Heating setpoint" + }, + "intended_boiler_temperature": { + "name": "Intended boiler temperature" + }, + "maximum_boiler_temperature": { + "name": "Maximum boiler temperature setpoint" + }, + "modulation_level": { + "name": "Modulation level" + }, + "net_electricity_cumulative": { + "name": "Net electricity cumulative" + }, + "net_electricity_point": { + "name": "Net electricity point" + }, + "outdoor_air_temperature": { + "name": "Outdoor air temperature" + }, + "outdoor_temperature": { + "name": "Outdoor temperature" + }, + "return_temperature": { + "name": "Return temperature" + }, + "setpoint": { + "name": "Setpoint" + }, + "temperature_difference": { + "name": "Temperature difference" + }, + "valve_position": { + "name": "Valve position" + }, + "voltage_phase_one": { + "name": "Voltage phase one" + }, + "voltage_phase_three": { + "name": "Voltage phase three" + }, + "voltage_phase_two": { + "name": "Voltage phase two" + }, + "water_pressure": { + "name": "Water pressure" + }, + "water_temperature": { + "name": "Water temperature" + } + }, + "switch": { + "cooling_ena_switch": { + "name": "Cooling" + }, + "dhw_cm_switch": { + "name": "DHW comfort mode" + }, + "lock": { + "name": "Lock" + }, + "relay": { + "name": "Relay" + } + } + }, + "exceptions": { + "authentication_failed": { + "message": "Invalid authentication" + }, + "data_incomplete_or_missing": { + "message": "Data incomplete or missing." + }, + "error_communicating_with_api": { + "message": "Error communicating with API: {error}." + }, + "failed_to_connect": { + "message": "Failed to connect" + }, + "invalid_setup": { + "message": "Add your Adam instead of your Anna, see the documentation" + }, + "response_error": { + "message": "Invalid XML data, or error indication received from the Plugwise Adam/Smile/Stretch" + }, + "set_schedule_first": { + "message": "Failed setting HVACMode, set a schedule first." + }, + "unsupported_firmware": { + "message": "Device with unsupported firmware" + } + }, + "options": { + "step": { + "init": { + "data": { + "cooling_on": "Anna: cooling-mode is on", + "refresh_interval": "Frontend refresh-time (1.5 - 5 seconds) *) beta-only option", + "scan_interval": "Scan Interval (seconds) *) beta-only option" + }, + "description": "Adjust Smile/Stretch Options" + }, + "none": { + "description": "This Integration does not provide any Options", + "title": "No Options available" + } + } + }, + "services": { + "delete_notification": { + "description": "Deletes a Plugwise Notification", + "name": "Delete Plugwise notification" } + } }