Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## v1.14.1

- Improve manual fixtures script, reorder set_schedule_state() arguments for better compatibility with set_dhw_mode(), via PR[#897](https://github.com/plugwise/python-plugwise/pull/897)

## v1.14.0

- Include both old and new entities for a step-wise introduction of water_heaters in HA via PR [#895](https://github.com/plugwise/python-plugwise/pull/895):
Expand Down
2 changes: 1 addition & 1 deletion fixtures/m_adam_cooling/data.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"select_dhw_mode": "eco",
"sensors": {
"intended_boiler_temperature": 17.5,
"water_temperature": 43.0
"water_temperature": 19.0
},
"switches": {
"dhw_cm_switch": false
Expand Down
4 changes: 2 additions & 2 deletions fixtures/m_anna_heatpump_cooling/data.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,13 @@
"model": "Generic heater/cooler",
"name": "OpenTherm",
"sensors": {
"dhw_temperature": 46.3,
"dhw_temperature": 41.5,
"intended_boiler_temperature": 0.0,
"modulation_level": 40,
"outdoor_air_temperature": 28.0,
"return_temperature": 23.8,
"water_pressure": 1.57,
"water_temperature": 29.1
"water_temperature": 22.7
},
"switches": {
"dhw_cm_switch": false
Expand Down
4 changes: 2 additions & 2 deletions fixtures/m_anna_heatpump_idle/data.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,13 @@
"model": "Generic heater/cooler",
"name": "OpenTherm",
"sensors": {
"dhw_temperature": 46.3,
"dhw_temperature": 41.5,
"intended_boiler_temperature": 18.0,
"modulation_level": 0,
"outdoor_air_temperature": 28.2,
"return_temperature": 22.0,
"water_pressure": 1.57,
"water_temperature": 29.1
"water_temperature": 22.7
},
"switches": {
"dhw_cm_switch": false
Expand Down
17 changes: 12 additions & 5 deletions plugwise/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ async def set_select(
) -> None:
"""Set the selected option for the applicable Select."""
try:
await self._smile_api.set_select(key, loc_id, option, state)
await self._smile_api.set_select(key, loc_id, option, state=state)
except ConnectionFailedError as exc:
raise ConnectionFailedError(
f"Failed to set select option '{option}': {str(exc)}"
Expand All @@ -371,12 +371,12 @@ async def set_select(
async def set_schedule_state(
self,
loc_id: str,
state: str | None,
name: str | None = None,
state: str | None = None,
) -> None:
"""Activate/deactivate the Schedule, with the given name, on the relevant Thermostat."""
try:
await self._smile_api.set_schedule_state(loc_id, state, name)
await self._smile_api.set_schedule_state(loc_id, name=name, state=state)
except ConnectionFailedError as exc: # pragma no cover
raise ConnectionFailedError(
f"Failed to set schedule state: {str(exc)}"
Expand Down Expand Up @@ -462,12 +462,19 @@ async def set_regulation_mode(self, mode: str) -> None:
) from exc # pragma no cover

async def set_dhw_mode(
self, key: str, location: str, length: int, mode: str
self,
key: str,
location: str,
mode: str,
length: int,
) -> None:
"""Set the domestic hot water heating regulation mode."""
try: # pragma no cover
await self._smile_api.set_dhw_mode(
key, location, length, mode
key,
location,
mode,
length,
) # pragma: no cover
except ConnectionFailedError as exc: # pragma no cover
raise ConnectionFailedError(
Expand Down
19 changes: 15 additions & 4 deletions plugwise/legacy/smile.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,11 @@ async def reboot_gateway(self) -> None:
"""Set-function placeholder for legacy devices."""

async def set_dhw_mode(
self, key: str, location: str, length: int, mode: str
self,
key: str,
location: str,
mode: str,
length: int,
) -> None:
"""Set-function placeholder for legacy devices."""

Expand Down Expand Up @@ -170,14 +174,21 @@ async def set_regulation_mode(self, mode: str) -> None:
"""Set-function placeholder for legacy devices."""

async def set_select(
self, key: str, loc_id: str, option: str, state: str | None
self,
_: str,
loc_id: str,
option: str,
state: str | None = None,
) -> None:
"""Set the thermostat schedule option."""
# schedule name corresponds to select option
await self.set_schedule_state("dummy", state, option)
await self.set_schedule_state("loc_id", option, state=state)

async def set_schedule_state(
self, _: str, state: str | None, name: str | None
self,
_: str,
name: str | None = None,
state: str | None = None,
) -> None:
"""Activate/deactivate the Schedule.

Expand Down
31 changes: 17 additions & 14 deletions plugwise/smile.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,11 @@ async def set_preset(self, loc_id: str, preset: str) -> None:
await self.call_request(uri, method="put", data=data)

async def set_select(
self, key: str, appl_or_loc_id: str, option: str, state: str | None
self,
key: str,
appl_or_loc_id: str,
option: str,
state: str | None = None,
) -> None:
"""Set a dhw/gateway/regulation mode or the thermostat schedule option."""
match key:
Expand All @@ -247,13 +251,13 @@ async def set_select(
case "select_schedule":
# The schedule name corresponds to the select option
# Location id is passed
await self.set_schedule_state(appl_or_loc_id, state, option)
await self.set_schedule_state(appl_or_loc_id, option, state=state)
case "select_zone_profile":
# Location id is passed
await self.set_zone_profile(appl_or_loc_id, option)

async def set_dhw_mode(
self, key: str, appl_id: str, length: int, mode: str
self, key: str, appl_id: str, mode: str, length: int
) -> None:
"""Set the domestic hot water mode.

Expand All @@ -266,7 +270,7 @@ async def set_dhw_mode(

match length:
case 2:
await self.set_select(key, appl_id, mode, None)
await self.set_select(key, appl_id, mode)
case _:
data = (
"<domestic_hot_water_mode_control_functionality>"
Expand Down Expand Up @@ -342,28 +346,27 @@ async def set_zone_profile(self, loc_id: str, profile: str) -> None:
await self.call_request(uri, method="post", data=data)

async def set_schedule_state(
self,
loc_id: str,
new_state: str | None,
name: str | None,
self, loc_id: str, name: str | None = None, state: str | None = None
) -> None:
"""Activate/deactivate the Schedule, with the given name, on the relevant Thermostat.

Determined from - DOMAIN_OBJECTS.
Used in HA Core to set the hvac_mode: in practice switch between schedule on - off.
"""
# Input checking
if new_state not in (STATE_OFF, STATE_ON):
if state is None:
state = STATE_ON
elif state not in (STATE_OFF, STATE_ON):
raise PlugwiseError("Plugwise: invalid schedule state.")

# Translate selection of Off-schedule-option to disabling the active schedule
if name == OFF:
new_state = STATE_OFF
state = STATE_OFF

# Handle no schedule-name / schedule-off requested: find the active schedule
if name is None or name == OFF:
_, name = self._schedules(loc_id)
if name == OFF: # no active schedule found, nothing to do
if name in (NONE, OFF): # no active schedule found, nothing to do
return

schedule_rule = self._rule_ids_by_name(name, loc_id)
Expand All @@ -372,7 +375,7 @@ async def set_schedule_state(
raise PlugwiseError("Plugwise: no schedule with this name available.")

# If no state change is requested, do nothing
if new_state == self._schedule_old_states[loc_id][name]:
if state == self._schedule_old_states[loc_id][name]:
return

schedule_rule_id: str = next(iter(schedule_rule))
Expand All @@ -384,7 +387,7 @@ async def set_schedule_state(
template_id = self._domain_objects.find(locator).get("id")
template = f'<template id="{template_id}" />'

contexts = self.determine_contexts(loc_id, new_state, schedule_rule_id)
contexts = self.determine_contexts(loc_id, state, schedule_rule_id)
data = (
"<rules>"
f"<rule id='{schedule_rule_id}'>"
Expand All @@ -396,7 +399,7 @@ async def set_schedule_state(
)
uri = f"{RULES};id={schedule_rule_id}"
await self.call_request(uri, method="put", data=data)
self._schedule_old_states[loc_id][name] = new_state
self._schedule_old_states[loc_id][name] = state

def determine_contexts(self, loc_id: str, state: str, sched_id: str) -> str:
"""Helper-function for set_schedule_state()."""
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "plugwise"
version = "1.14.0"
version = "1.14.1"
license = "MIT"
description = "Plugwise Smile (Adam/Anna/P1) and Stretch module for Python 3."
readme = "README.md"
Expand Down
9 changes: 9 additions & 0 deletions scripts/manual_fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ def json_writer(manual_name: str, output: dict) -> None:
m_adam_cooling["056ee145a816487eaa69243c3280f8bf"]["sensors"][
"intended_boiler_temperature"
] = 17.5
m_adam_cooling["056ee145a816487eaa69243c3280f8bf"]["sensors"][
"water_temperature"
] = 19.0

json_writer("m_adam_cooling", m_adam_cooling)

Expand Down Expand Up @@ -252,6 +255,9 @@ def json_writer(manual_name: str, output: dict) -> None:

m_anna_heatpump_cooling["1cbf783bb11e4a7c8a6843dee3a86927"]["maximum_boiler_temperature"]["current"] = 22.7
m_anna_heatpump_cooling["1cbf783bb11e4a7c8a6843dee3a86927"]["max_dhw_temperature"]["current"] = 41.5
m_anna_heatpump_cooling["1cbf783bb11e4a7c8a6843dee3a86927"]["sensors"][
"dhw_temperature"
] = 41.5
m_anna_heatpump_cooling["1cbf783bb11e4a7c8a6843dee3a86927"]["sensors"][
"intended_boiler_temperature"
] = 0.0
Expand All @@ -264,6 +270,9 @@ def json_writer(manual_name: str, output: dict) -> None:
m_anna_heatpump_cooling["1cbf783bb11e4a7c8a6843dee3a86927"]["sensors"][
"outdoor_air_temperature"
] = 28.0
m_anna_heatpump_cooling["1cbf783bb11e4a7c8a6843dee3a86927"]["sensors"][
"water_temperature"
] = 22.7

# Go for 015a
m_anna_heatpump_cooling["015ae9ea3f964e668e490fa39da3870b"]["sensors"][
Expand Down
10 changes: 8 additions & 2 deletions tests/test_adam.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,16 @@ async def test_connect_adam_plus_anna_new(self):
assert result

# Special test-case for turning a schedule off based on only the location id.
await api.set_schedule_state("f2bf9048bef64cc5b6d5110154e33c81", "off")
await api.set_schedule_state("f2bf9048bef64cc5b6d5110154e33c81", None, "off")

# Special test-case for turning a schedule off for a location via the option "off".
await api.set_schedule_state("f2bf9048bef64cc5b6d5110154e33c81", "on", "off")
await api.set_schedule_state("f2bf9048bef64cc5b6d5110154e33c81", "off", "on")

# Special test-case for setting a schedule to an invalid state.
with pytest.raises(pw_exceptions.PlugwiseError):
await api.set_schedule_state(
"f2bf9048bef64cc5b6d5110154e33c81", "Weekschema", "eco"
)

# bad schedule-state test
result = await self.tinker_thermostat_schedule(
Expand Down
4 changes: 2 additions & 2 deletions tests/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,7 @@ async def tinker_thermostat_schedule(
new_schedule = new_schedule[1:]
_LOGGER.info("- Adjusting schedule to %s", f"{new_schedule}{warning}")
try:
await api.set_select("select_schedule", loc_id, new_schedule, state)
await api.set_select("select_schedule", loc_id, new_schedule)
tinker_schedule_passed = True
_LOGGER.info(" + working as intended")
except pw_exceptions.PlugwiseError:
Expand Down Expand Up @@ -860,7 +860,7 @@ async def tinker_dhw_mode(api, appliance, key, length, unhappy=False):
mode = mode[1:]
_LOGGER.info("%s", f"- Adjusting dhw mode to {mode}{warning}")
try:
await api.set_dhw_mode(key, appliance, length, mode)
await api.set_dhw_mode(key, appliance, mode, length)
_LOGGER.info(" + tinker_dhw_mode worked as intended")
tinker_dhw_mode_passed = True
except pw_exceptions.PlugwiseError:
Expand Down