diff --git a/CHANGELOG.md b/CHANGELOG.md index c10039a93..1dccd7aab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Changelog -## v.1.7.1 +## v1.7.2 + +- Bugfix for Plugwise-beta issue [833](https://github.com/plugwise/plugwise-beta/issues/833) solving relay- and lock-switches not switching for the Stretch. + +## v1.7.1 - Avoid None-init for smile_version [#699](https://github.com/plugwise/python-plugwise/pull/699) - Replace string.split() by string.partition() [#702](https://github.com/plugwise/python-plugwise/pull/702) diff --git a/plugwise/__init__.py b/plugwise/__init__.py index 407fcd8b0..d2160663f 100644 --- a/plugwise/__init__.py +++ b/plugwise/__init__.py @@ -296,7 +296,7 @@ async def _smile_detect_legacy( ): system = await self._request(SYSTEM) self.smile_version = parse(system.find("./gateway/firmware").text) - return_model = system.find("./gateway/product").text + return_model = str(system.find("./gateway/product").text) self.smile_hostname = system.find("./gateway/hostname").text # If wlan0 contains data it's active, so eth0 should be checked last for network in ("wlan0", "eth0"): @@ -307,7 +307,7 @@ async def _smile_detect_legacy( elif dsmrmain is not None: status = await self._request(STATUS) self.smile_version = parse(status.find("./system/version").text) - return_model = status.find("./system/product").text + return_model = str(status.find("./system/product").text) self.smile_hostname = status.find("./network/hostname").text self.smile_mac_address = status.find("./network/mac_address").text else: # pragma: no cover diff --git a/plugwise/legacy/smile.py b/plugwise/legacy/smile.py index 5d63b3255..c74dcddcb 100644 --- a/plugwise/legacy/smile.py +++ b/plugwise/legacy/smile.py @@ -231,21 +231,50 @@ async def set_schedule_state( async def set_switch_state( self, appl_id: str, members: list[str] | None, model: str, state: str ) -> None: - """Set the given State of the relevant Switch.""" + """Set the given state of the relevant switch. + + For individual switches, sets the state directly. + For group switches, sets the state for each member in the group separately. + For switch-locks, sets the lock state using a different data format. + """ switch = Munch() switch.actuator = "actuator_functionalities" switch.func_type = "relay_functionality" if self._stretch_v2: switch.actuator = "actuators" switch.func_type = "relay" - switch.func = "state" + # Handle switch-lock + if model == "lock": + state = "false" if state == "off" else "true" + appliance = self._appliances.find(f'appliance[@id="{appl_id}"]') + appl_name = appliance.find("name").text + appl_type = appliance.find("type").text + data = f''' + + + + + + <{switch.actuator}> + <{switch.func_type}> + {state} + + + + '''.strip() + await self.call_request(APPLIANCES, method="post", data=data) + return + + # Handle group of switches + data = f"<{switch.func_type}>{state}" if members is not None: - return await self._set_groupswitch_member_state(members, state, switch) - - data = f"<{switch.func_type}><{switch.func}>{state}" - uri = f"{APPLIANCES};id={appl_id}/{switch.func_type}" + return await self._set_groupswitch_member_state( + data, members, state, switch + ) + # Handle individual relay switches + uri = f"{APPLIANCES};id={appl_id}/relay" if model == "relay": locator = ( f'appliance[@id="{appl_id}"]/{switch.actuator}/{switch.func_type}/lock' @@ -257,16 +286,14 @@ async def set_switch_state( await self.call_request(uri, method="put", data=data) async def _set_groupswitch_member_state( - self, members: list[str], state: str, switch: Munch + self, data: str, members: list[str], state: str, switch: Munch ) -> None: """Helper-function for set_switch_state(). - Set the given State of the relevant Switch within a group of members. + Set the given State of the relevant Switch (relay) within a group of members. """ for member in members: - uri = f"{APPLIANCES};id={member}/{switch.func_type}" - data = f"<{switch.func_type}><{switch.func}>{state}" - + uri = f"{APPLIANCES};id={member}/relay" await self.call_request(uri, method="put", data=data) async def set_temperature(self, _: str, items: dict[str, float]) -> None: diff --git a/pyproject.toml b/pyproject.toml index ae85c0b23..c5c33be97 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "plugwise" -version = "1.7.1" +version = "1.7.2" license = {file = "LICENSE"} description = "Plugwise Smile (Adam/Anna/P1) and Stretch module for Python 3." readme = "README.md" diff --git a/tests/test_init.py b/tests/test_init.py index 028e33c11..b585125ab 100644 --- a/tests/test_init.py +++ b/tests/test_init.py @@ -167,8 +167,10 @@ async def setup_legacy_app( "PUT", CORE_APPLIANCES_TAIL, self.smile_http_accept ) else: + app.router.add_route("POST", CORE_APPLIANCES_TAIL, self.smile_http_ok) app.router.add_route("PUT", CORE_APPLIANCES_TAIL, self.smile_http_ok) else: + app.router.add_route("POST", CORE_APPLIANCES_TAIL, self.smile_timeout) app.router.add_route("PUT", CORE_LOCATIONS_TAIL, self.smile_timeout) app.router.add_route("PUT", CORE_RULES_TAIL, self.smile_timeout) app.router.add_route("PUT", CORE_APPLIANCES_TAIL, self.smile_timeout) diff --git a/tests/test_legacy_stretch.py b/tests/test_legacy_stretch.py index f5056dee6..021cc385b 100644 --- a/tests/test_legacy_stretch.py +++ b/tests/test_legacy_stretch.py @@ -74,6 +74,10 @@ async def test_connect_stretch_v23(self): smile, "2587a7fcdd7e482dab03fda256076b4b" ) assert switch_change + switch_change = await self.tinker_switch( + smile, "2587a7fcdd7e482dab03fda256076b4b", model="lock" + ) + assert switch_change switch_change = await self.tinker_switch( smile, "f7b145c8492f4dd7a4de760456fdef3e",