diff --git a/CHANGELOG.md b/CHANGELOG.md index 51ead928c..b582165fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## v0.36.3 + +- Bugfixes for [#558](https://github.com/plugwise/plugwise-beta/issues/558) and [#559](https://github.com/plugwise/plugwise-beta/issues/559). + ## v0.36.2 - Improve support for Anna+Elga systems that do not support cooling (fix for [#547](https://github.com/plugwise/plugwise-beta/issues/547)). diff --git a/plugwise/__init__.py b/plugwise/__init__.py index 2b292fb30..e1d96e0de 100644 --- a/plugwise/__init__.py +++ b/plugwise/__init__.py @@ -871,20 +871,20 @@ async def set_gateway_mode(self, mode: str) -> None: if mode not in self._gw_allowed_modes: raise PlugwiseError("Plugwise: invalid gateway mode.") - time_1 = dt.datetime.now(dt.UTC) - away_time = time_1.isoformat(timespec="milliseconds") + "Z" - time_2 = str(dt.date.today() - dt.timedelta(1)) - vacation_time = time_2 + "T23:00:00.000Z" end_time = "2037-04-21T08:00:53.000Z" valid = "" if mode == "away": + time_1 = self._domain_objects.find("./gateway/time").text + away_time = dt.datetime.fromisoformat(time_1).astimezone(dt.UTC).isoformat(timespec="milliseconds").replace("+00:00", "Z") valid = ( f"{away_time}{end_time}" ) if mode == "vacation": + time_2 = str(dt.date.today() - dt.timedelta(1)) + vacation_time = time_2 + "T23:00:00.000Z" valid = f"{vacation_time}{end_time}" - uri = f"{APPLIANCES};type=gateway/gateway_mode_control" + uri = f"{APPLIANCES};id={self.gateway_id}/gateway_mode_control" data = f"{mode}{valid}" await self._request(uri, method="put", data=data) diff --git a/plugwise/helper.py b/plugwise/helper.py index 0f773bf2b..6e8a6bf8b 100644 --- a/plugwise/helper.py +++ b/plugwise/helper.py @@ -751,6 +751,7 @@ def _presets(self, loc_id: str) -> dict[str, list[float]]: return self._presets_legacy() if not (rule_ids := self._rule_ids_by_tag(tag_1, loc_id)): + rule_ids = None if not (rule_ids := self._rule_ids_by_name(tag_2, loc_id)): return presets # pragma: no cover @@ -767,35 +768,38 @@ def _presets(self, loc_id: str) -> dict[str, list[float]]: return presets - def _rule_ids_by_name(self, name: str, loc_id: str) -> dict[str, str]: + def _rule_ids_by_name(self, name: str, loc_id: str) -> dict[str, dict[str, str]]: """Helper-function for _presets(). Obtain the rule_id from the given name and and provide the location_id, when present. """ - schedule_ids: dict[str, str] = {} + schedule_ids: dict[str, dict[str, str]] = {} locator = f'./contexts/context/zone/location[@id="{loc_id}"]' for rule in self._domain_objects.findall(f'./rule[name="{name}"]'): + active = rule.find("active").text if rule.find(locator) is not None: - schedule_ids[rule.attrib["id"]] = loc_id + schedule_ids[rule.attrib["id"]] = {"location": loc_id, "name": name, "active": active} else: - schedule_ids[rule.attrib["id"]] = NONE + schedule_ids[rule.attrib["id"]] = {"location": NONE, "name": name, "active": active} return schedule_ids - def _rule_ids_by_tag(self, tag: str, loc_id: str) -> dict[str, str]: + def _rule_ids_by_tag(self, tag: str, loc_id: str) -> dict[str, dict[str, str]]: """Helper-function for _presets(), _schedules() and _last_active_schedule(). Obtain the rule_id from the given template_tag and provide the location_id, when present. """ - schedule_ids: dict[str, str] = {} + schedule_ids: dict[str, dict[str, str]] = {} locator1 = f'./template[@tag="{tag}"]' locator2 = f'./contexts/context/zone/location[@id="{loc_id}"]' for rule in self._domain_objects.findall("./rule"): if rule.find(locator1) is not None: + name = rule.find("name").text + active = rule.find("active").text if rule.find(locator2) is not None: - schedule_ids[rule.attrib["id"]] = loc_id + schedule_ids[rule.attrib["id"]] = {"location": loc_id, "name": name, "active": active} else: - schedule_ids[rule.attrib["id"]] = NONE + schedule_ids[rule.attrib["id"]] = {"location": NONE, "name": name, "active": active} return schedule_ids @@ -1478,7 +1482,7 @@ def _schedules(self, location: str) -> tuple[list[str], str]: NEW: when a location_id is present then the schedule is active. Valid for both Adam and non-legacy Anna. """ available: list[str] = [NONE] - rule_ids: dict[str, str] = {} + rule_ids: dict[str, dict[str, str]] = {} selected = NONE # Legacy Anna schedule, only one schedule allowed @@ -1495,15 +1499,16 @@ def _schedules(self, location: str) -> tuple[list[str], str]: return available, selected schedules: list[str] = [] - for rule_id, loc_id in rule_ids.items(): - name = self._domain_objects.find(f'./rule[@id="{rule_id}"]/name').text + for rule_id, data in rule_ids.items(): + active = data["active"] == "true" + name = data["name"] locator = f'./rule[@id="{rule_id}"]/directives' # Show an empty schedule as no schedule found if self._domain_objects.find(locator) is None: continue # pragma: no cover available.append(name) - if location == loc_id: + if location == data["location"] and active: selected = name self._last_active[location] = selected schedules.append(name) diff --git a/pyproject.toml b/pyproject.toml index 483206e0e..e4e245d86 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "plugwise" -version = "0.36.2" +version = "0.36.3" license = {file = "LICENSE"} description = "Plugwise Smile (Adam/Anna/P1) and Stretch module for Python 3." readme = "README.md"