Skip to content

Commit 65aa686

Browse files
authored
Merge pull request #226 from plugwise/setpoint_high_low
# v0.25.0: Improve compatibility with HA Core climate platform
2 parents 6273ca9 + ff42779 commit 65aa686

File tree

6 files changed

+593
-52
lines changed

6 files changed

+593
-52
lines changed

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Changelog
22

3-
# v0.24.2: Better Core compatibility (change mode cool to heat_cool)
3+
# v0.25.0: Improve compatibility with HA Core climate platform
4+
- Change mode cool to heat_cool
5+
- Add setpoint_high/setpoint_low to output
46

57
# v0.24.1: Bugfix: fix root-cause of https://github.com/home-assistant/core/issues/79708
68

plugwise/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Plugwise module."""
22

3-
__version__ = "0.24.2"
3+
__version__ = "0.25.0"
44

55
from plugwise.smile import Smile
66
from plugwise.stick import Stick

plugwise/constants.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,8 @@
397397
"upper_bound",
398398
"resolution",
399399
)
400+
MAX_SETPOINT: Final[float] = 40.0
401+
MIN_SETPOINT: Final[float] = 0.0
400402
SPECIAL_FORMAT: Final[tuple[str, ...]] = (ENERGY_KILO_WATT_HOUR, VOLUME_CUBIC_METERS)
401403
SWITCH_GROUP_TYPES: Final[tuple[str, ...]] = ("switching", "report")
402404
ZONE_THERMOSTATS: Final[tuple[str, ...]] = (
@@ -564,6 +566,8 @@
564566
"outdoor_temperature",
565567
"return_temperature",
566568
"setpoint",
569+
"setpoint_high",
570+
"setpoint_low",
567571
"temperature_difference",
568572
"valve_position",
569573
"water_pressure",
@@ -666,6 +670,8 @@ class SmileSensors(TypedDict, total=False):
666670
outdoor_temperature: float
667671
return_temperature: float
668672
setpoint: float
673+
setpoint_high: float
674+
setpoint_low: float
669675
temperature_difference: float
670676
valve_position: float
671677
water_pressure: float
@@ -695,6 +701,8 @@ class ActuatorData(TypedDict, total=False):
695701

696702
lower_bound: float
697703
setpoint: float
704+
setpoint_high: float
705+
setpoint_low: float
698706
resolution: float
699707
upper_bound: float
700708

plugwise/helper.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -949,6 +949,8 @@ def _get_appliance_data(self, d_id: str) -> DeviceData:
949949
):
950950
if data.get("c_heating_state") and not data.get("heating_state"):
951951
data["heating_state"] = True
952+
if self._cooling_present:
953+
self._cooling_active = True
952954

953955
data.pop("c_heating_state")
954956

@@ -958,21 +960,17 @@ def _get_appliance_data(self, d_id: str) -> DeviceData:
958960

959961
if d_id == self._heater_id:
960962
# Adam
961-
if self._cooling_enabled:
962-
data["cooling_enabled"] = self._cooling_enabled
963963
if self.smile_name == "Smile Anna":
964964
# Use elga_status_code or cooling_enabled to set _cooling_enabled to True
965965
if self._cooling_present:
966966
# Elga:
967967
if "elga_status_code" in data:
968968
self._cooling_enabled = data["elga_status_code"] in [8, 9]
969-
data["cooling_enabled"] = self._cooling_enabled
970969
self._cooling_active = data["elga_status_code"] == 8
971970
data.pop("elga_status_code", None)
972971
# Loria/Thermastate: look at cooling_state, not at cooling_enabled, not available on R32!
973972
elif "cooling_ena_switch" in data:
974973
self._cooling_enabled = data["cooling_ena_switch"]
975-
data["cooling_enabled"] = self._cooling_enabled
976974
self._cooling_active = data["cooling_state"]
977975

978976
# Don't show cooling_state when no cooling present

plugwise/smile.py

Lines changed: 65 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
DOMAIN_OBJECTS,
2222
LOCATIONS,
2323
LOGGER,
24+
MAX_SETPOINT,
25+
MIN_SETPOINT,
2426
MODULES,
2527
NOTIFICATIONS,
2628
RULES,
@@ -29,6 +31,7 @@
2931
SWITCH_GROUP_TYPES,
3032
SYSTEM,
3133
ZONE_THERMOSTATS,
34+
ActuatorData,
3235
ApplianceData,
3336
DeviceData,
3437
GatewayData,
@@ -51,25 +54,59 @@ class SmileData(SmileHelper):
5154
def update_for_cooling(self, devices: dict[str, DeviceData]) -> None:
5255
"""Helper-function for adding/updating various cooling-related values."""
5356
for _, device in devices.items():
54-
# For Anna + cooling, modify cooling_state based on provided info by Plugwise
55-
if self.smile_name == "Smile Anna":
56-
if device["dev_class"] == "heater_central" and self._cooling_present:
57-
device["binary_sensors"]["cooling_state"] = False
58-
if self._cooling_active:
59-
device["binary_sensors"]["cooling_state"] = True
57+
# For Anna or Adama + cooling, modify cooling_state based on provided info by Plugwise
58+
if device["dev_class"] == "heater_central" and self._cooling_present:
59+
device["binary_sensors"]["cooling_state"] = False
60+
if self._cooling_active:
61+
device["binary_sensors"]["cooling_state"] = True
6062

6163
# For Adam + on/off cooling, modify heating_state and cooling_state
6264
# based on provided info by Plugwise
6365
if (
6466
self.smile_name == "Adam"
6567
and device["dev_class"] == "heater_central"
6668
and self._on_off_device
67-
and self._cooling_enabled
69+
and self._cooling_active
6870
and device["binary_sensors"]["heating_state"]
6971
):
7072
device["binary_sensors"]["cooling_state"] = True
7173
device["binary_sensors"]["heating_state"] = False
7274

75+
# Add setpoint_low and setpoint_high when cooling is enabled
76+
if device["dev_class"] not in ZONE_THERMOSTATS:
77+
continue
78+
79+
if self._cooling_present:
80+
# Replace setpoint with setpoint_high/_low
81+
thermostat = device["thermostat"]
82+
sensors = device["sensors"]
83+
max_setpoint = MAX_SETPOINT
84+
min_setpoint = MIN_SETPOINT
85+
if self._sched_setpoints is not None:
86+
max_setpoint = self._sched_setpoints[1]
87+
min_setpoint = self._sched_setpoints[0]
88+
89+
temp_dict: ActuatorData = {
90+
"setpoint": thermostat["setpoint"],
91+
"setpoint_low": thermostat["setpoint"],
92+
"setpoint_high": max_setpoint,
93+
}
94+
if self._cooling_active:
95+
temp_dict = {
96+
"setpoint": thermostat["setpoint"],
97+
"setpoint_low": min_setpoint,
98+
"setpoint_high": thermostat["setpoint"],
99+
}
100+
# Keep setpoint in sensors, remove when appropriate
101+
# if "setpoint" in sensors:
102+
# sensors.pop("setpoint")
103+
sensors["setpoint_low"] = temp_dict["setpoint_low"]
104+
sensors["setpoint_high"] = temp_dict["setpoint_high"]
105+
# Keep setpoint in output, remove when appropriate
106+
# thermostat.pop("setpoint")
107+
temp_dict.update(thermostat)
108+
device["thermostat"] = temp_dict
109+
73110
def _all_device_data(self) -> None:
74111
"""Helper-function for get_all_devices().
75112
Collect initial data for each device and add to self.gw_data and self.gw_devices.
@@ -674,11 +711,29 @@ async def set_preset(self, loc_id: str, preset: str) -> None:
674711

675712
await self._request(uri, method="put", data=data)
676713

677-
async def set_temperature(self, loc_id: str, temperature: float) -> None:
714+
async def set_temperature(self, loc_id: str, items: dict[str, float]) -> None:
678715
"""Set the given Temperature on the relevant Thermostat."""
679-
temp = str(temperature)
716+
setpoint: float | None = None
717+
if "setpoint" in items:
718+
setpoint = items["setpoint"]
719+
if self._cooling_present:
720+
if "setpoint_low" in items:
721+
setpoint = items["setpoint_low"]
722+
if self._cooling_active:
723+
if "setpoint_high" in items:
724+
setpoint = items["setpoint_high"]
725+
726+
if setpoint is None:
727+
raise PlugwiseError(
728+
"Plugwise: failed setting temperature: no valid input provided"
729+
) # pragma: no cover"
730+
731+
temperature = str(setpoint)
680732
uri = self._thermostat_uri(loc_id)
681-
data = f"<thermostat_functionality><setpoint>{temp}</setpoint></thermostat_functionality>"
733+
data = (
734+
"<thermostat_functionality><setpoint>"
735+
f"{temperature}</setpoint></thermostat_functionality>"
736+
)
682737

683738
await self._request(uri, method="put", data=data)
684739

0 commit comments

Comments
 (0)