From 509e5db088c83da33f6a9b42a6b03d1b6111dcfb Mon Sep 17 00:00:00 2001 From: Philipp Date: Tue, 16 Jul 2024 23:08:34 +0200 Subject: [PATCH] Added missing BANK_HOLIDAY to domestic hot water on VRC700 controllers, Added ZoneDesiredRoomTemperatureSetpointHeatingSensor & ZoneDesiredRoomTemperatureSetpointCoolingSensor, Temperature controls now update heating or cooling targets depending on which mode is active --- custom_components/mypyllant/climate.py | 90 ++++++++++++++++------- custom_components/mypyllant/manifest.json | 4 +- custom_components/mypyllant/sensor.py | 60 ++++++++++----- dev-requirements.txt | 2 +- 4 files changed, 107 insertions(+), 49 deletions(-) diff --git a/custom_components/mypyllant/climate.py b/custom_components/mypyllant/climate.py index ba5e591..e938b6d 100644 --- a/custom_components/mypyllant/climate.py +++ b/custom_components/mypyllant/climate.py @@ -745,49 +745,83 @@ async def async_set_temperature(self, **kwargs: Any) -> None: target_temp_low = kwargs.get(ATTR_TARGET_TEMP_LOW) target_temp_high = kwargs.get(ATTR_TARGET_TEMP_HIGH) - if target_temp_low is not None and target_temp_high is not None: - _LOGGER.debug("Setting target temperature range on %s", self.zone.name) - if target_temp_low != self.zone.desired_room_temperature_setpoint_heating: - await self.set_quick_veto(temperature=target_temp_low) + if temperature is not None and ( + target_temp_low is not None or target_temp_high is not None + ): + raise ValueError( + "Can't set temperature and target_temp_low/target_temp_high at the same time" + ) + + if temperature: + # If only one temperature is passed in, set it on the active operating type + if self.zone.active_operating_type == ZoneOperatingType.HEATING: + target_temp_low = temperature + elif self.zone.cooling: + target_temp_high = temperature + else: + _LOGGER.warning("Can't determine operation type on %s", self.zone.name) + + if target_temp_low is not None: + # Heating temperature if ( - self.zone.cooling - and self.zone.cooling.operation_mode_cooling == ZoneOperatingMode.MANUAL + self.zone.heating.operation_mode_heating == ZoneOperatingMode.MANUAL + and target_temp_low != self.zone.heating.manual_mode_setpoint_heating ): - if target_temp_high != self.zone.cooling.manual_mode_setpoint_cooling: - await self.set_manual_mode_setpoint( - temperature=target_temp_high, - setpoint_type="cooling", - ) - elif ( - self.zone.cooling - and self.zone.cooling.operation_mode_cooling - == ZoneOperatingMode.TIME_CONTROLLED - ): - if target_temp_high != self.zone.cooling.setpoint_cooling: - await self.set_time_controlled_cooling_setpoint( - temperature=target_temp_high - ) - elif temperature is not None: - if self.zone.heating.operation_mode_heating == ZoneOperatingMode.MANUAL: - await self.set_manual_mode_setpoint(temperature=temperature) + _LOGGER.debug( + "Setting heating manual temperature on %s to %s", + self.zone.name, + target_temp_high, + ) + await self.set_manual_mode_setpoint(temperature=target_temp_low) else: if self.time_program_overwrite and not self.preset_mode == PRESET_BOOST: _LOGGER.debug( - "Setting time program temperature in %s to %s", + "Setting heating time program temperature in %s to %s", self.zone.name, - temperature, + target_temp_low, ) await self.coordinator.api.set_time_program_temperature( self.zone, "heating", - temperature=temperature, + temperature=target_temp_low, ) await self.coordinator.async_request_refresh_delayed() else: _LOGGER.debug( - "Setting quick veto on %s to %s", self.zone.name, temperature + "Setting quick veto on %s to %s", + self.zone.name, + target_temp_low, ) - await self.set_quick_veto(temperature=temperature) + await self.set_quick_veto(temperature=target_temp_low) + + if target_temp_high is not None and self.zone.cooling: + # Cooling temperature + if ( + self.zone.cooling.operation_mode_cooling == ZoneOperatingMode.MANUAL + and target_temp_high != self.zone.cooling.manual_mode_setpoint_cooling + ): + _LOGGER.debug( + "Setting cooling manual temperature on %s to %s", + self.zone.name, + target_temp_high, + ) + await self.set_manual_mode_setpoint( + temperature=target_temp_high, + setpoint_type="cooling", + ) + elif ( + self.zone.cooling.operation_mode_cooling + == ZoneOperatingMode.TIME_CONTROLLED + and target_temp_high != self.zone.cooling.setpoint_cooling + ): + _LOGGER.debug( + "Setting cooling time controlled temperature on %s to %s", + self.zone.name, + target_temp_high, + ) + await self.set_time_controlled_cooling_setpoint( + temperature=target_temp_high + ) @property def preset_modes(self) -> list[str]: diff --git a/custom_components/mypyllant/manifest.json b/custom_components/mypyllant/manifest.json index 03da413..fad9968 100644 --- a/custom_components/mypyllant/manifest.json +++ b/custom_components/mypyllant/manifest.json @@ -10,7 +10,7 @@ "iot_class": "cloud_polling", "issue_tracker": "https://github.com/signalkraft/mypyllant-component/issues", "requirements": [ - "myPyllant==0.8.23" + "myPyllant==0.8.25" ], - "version": "v0.8.11" + "version": "v0.8.12" } diff --git a/custom_components/mypyllant/sensor.py b/custom_components/mypyllant/sensor.py index d57a7bc..eeda1db 100644 --- a/custom_components/mypyllant/sensor.py +++ b/custom_components/mypyllant/sensor.py @@ -123,6 +123,16 @@ async def create_system_sensors( index, zone_index, system_coordinator ) ) + sensors.append( + lambda: ZoneDesiredRoomTemperatureSetpointHeatingSensor( + index, zone_index, system_coordinator + ) + ) + sensors.append( + lambda: ZoneDesiredRoomTemperatureSetpointCoolingSensor( + index, zone_index, system_coordinator + ) + ) if zone.current_room_temperature is not None: sensors.append( lambda: ZoneCurrentRoomTemperatureSensor( @@ -460,29 +470,43 @@ def name(self): @property def native_value(self): - if self.zone.desired_room_temperature_setpoint: - return self.zone.desired_room_temperature_setpoint - elif self.zone.desired_room_temperature_setpoint_heating: - return self.zone.desired_room_temperature_setpoint_heating - elif self.zone.desired_room_temperature_setpoint_cooling: - return self.zone.desired_room_temperature_setpoint_cooling - else: - if self.zone.is_eco_mode: - return self.zone.heating.set_back_temperature - return self.zone.desired_room_temperature_setpoint + return self.zone.desired_room_temperature_setpoint @property - def extra_state_attributes(self) -> Mapping[str, Any] | None: - return { - "desired_room_temperature_setpoint_heating": self.zone.desired_room_temperature_setpoint_heating, - "desired_room_temperature_setpoint_cooling": self.zone.desired_room_temperature_setpoint_cooling, - "desired_room_temperature_setpoint": self.zone.desired_room_temperature_setpoint, - "is_eco_mode": self.zone.is_eco_mode, - } + def unique_id(self) -> str: + return f"{DOMAIN}_{self.id_infix}_desired_temperature" + + +class ZoneDesiredRoomTemperatureSetpointHeatingSensor( + ZoneDesiredRoomTemperatureSetpointSensor +): + @property + def name(self): + return f"{self.name_prefix} Desired Heating Temperature" + + @property + def native_value(self): + return self.zone.desired_room_temperature_setpoint_heating @property def unique_id(self) -> str: - return f"{DOMAIN}_{self.id_infix}_desired_temperature" + return f"{DOMAIN}_{self.id_infix}_desired_heating_temperature" + + +class ZoneDesiredRoomTemperatureSetpointCoolingSensor( + ZoneDesiredRoomTemperatureSetpointSensor +): + @property + def name(self): + return f"{self.name_prefix} Desired Cooling Temperature" + + @property + def native_value(self): + return self.zone.desired_room_temperature_setpoint_cooling + + @property + def unique_id(self) -> str: + return f"{DOMAIN}_{self.id_infix}_desired_cooling_temperature" class ZoneCurrentRoomTemperatureSensor(ZoneCoordinatorEntity, SensorEntity): diff --git a/dev-requirements.txt b/dev-requirements.txt index 4089182..1e78c2e 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -11,7 +11,7 @@ types-PyYAML~=6.0.12.20240311 # Need specific versions pytest-homeassistant-custom-component==0.13.142 -myPyllant==0.8.23 +myPyllant==0.8.25 # Versions handled by pytest-homeassistant-custom-component freezegun