diff --git a/CHANGELOG.md b/CHANGELOG.md index f8c540c4b..d711eab69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## v1.1.0 + +- New Feature: add a battery_state binary_sensor for battery-powered devices and block the related battery-low notifications. + ## v1.0.0 - First formal release to v1.0.0! diff --git a/fixtures/adam_heatpump_cooling/all_data.json b/fixtures/adam_heatpump_cooling/all_data.json index 17be405a5..f77f34504 100644 --- a/fixtures/adam_heatpump_cooling/all_data.json +++ b/fixtures/adam_heatpump_cooling/all_data.json @@ -47,6 +47,9 @@ "Weekend", "off" ], + "binary_sensors": { + "battery_state": false + }, "control_state": "off", "dev_class": "zone_thermostat", "firmware": "2016-10-10T02:00:00+02:00", @@ -521,6 +524,9 @@ "Weekend", "off" ], + "binary_sensors": { + "battery_state": false + }, "control_state": "off", "dev_class": "zone_thermostat", "firmware": "2016-10-10T02:00:00+02:00", @@ -632,7 +638,7 @@ "cooling_present": true, "gateway_id": "7d97fc3117784cfdafe347bcedcbbbcb", "heater_id": "0ca13e8176204ca7bf6f09de59f81c83", - "item_count": 415, + "item_count": 417, "notifications": {}, "reboot": true, "smile_name": "Adam" diff --git a/fixtures/adam_jip/all_data.json b/fixtures/adam_jip/all_data.json index 922b3ddc5..c33e9fdc1 100644 --- a/fixtures/adam_jip/all_data.json +++ b/fixtures/adam_jip/all_data.json @@ -3,6 +3,9 @@ "1346fbd8498d4dbcab7e18d51b771f3d": { "active_preset": "no_frost", "available": true, + "binary_sensors": { + "battery_state": false + }, "control_state": "off", "dev_class": "zone_thermostat", "firmware": "2016-10-27T02:00:00+02:00", @@ -97,6 +100,9 @@ "6f3e9d7084214c21b9dfa46f6eeb8700": { "active_preset": "home", "available": true, + "binary_sensors": { + "battery_state": false + }, "control_state": "off", "dev_class": "zone_thermostat", "firmware": "2016-10-27T02:00:00+02:00", @@ -152,6 +158,9 @@ "a6abc6a129ee499c88a4d420cc413b47": { "active_preset": "home", "available": true, + "binary_sensors": { + "battery_state": false + }, "control_state": "off", "dev_class": "zone_thermostat", "firmware": "2016-10-27T02:00:00+02:00", @@ -263,6 +272,9 @@ "f61f1a2535f54f52ad006a3d18e459ca": { "active_preset": "home", "available": true, + "binary_sensors": { + "battery_state": false + }, "control_state": "off", "dev_class": "zone_thermometer", "firmware": "2020-09-01T02:00:00+02:00", @@ -298,7 +310,7 @@ "cooling_present": false, "gateway_id": "b5c2386c6f6342669e50fe49dd05b188", "heater_id": "e4684553153b44afbef2200885f379dc", - "item_count": 213, + "item_count": 217, "notifications": {}, "reboot": true, "smile_name": "Adam" diff --git a/fixtures/adam_multiple_devices_per_zone/all_data.json b/fixtures/adam_multiple_devices_per_zone/all_data.json index 9c17df507..cbc006143 100644 --- a/fixtures/adam_multiple_devices_per_zone/all_data.json +++ b/fixtures/adam_multiple_devices_per_zone/all_data.json @@ -82,6 +82,9 @@ }, "680423ff840043738f42cc7f1ff97a36": { "available": true, + "binary_sensors": { + "battery_state": false + }, "dev_class": "thermo_sensor", "firmware": "2019-03-27T01:00:00+01:00", "hardware": "1", @@ -115,6 +118,9 @@ "CV Jessie", "off" ], + "binary_sensors": { + "battery_state": false + }, "dev_class": "zone_thermostat", "firmware": "2016-10-27T02:00:00+02:00", "hardware": "255", @@ -199,6 +205,9 @@ }, "a2c3583e0a6349358998b760cea82d2a": { "available": true, + "binary_sensors": { + "battery_state": false + }, "dev_class": "thermo_sensor", "firmware": "2019-03-27T01:00:00+01:00", "hardware": "1", @@ -255,6 +264,9 @@ "CV Jessie", "off" ], + "binary_sensors": { + "battery_state": false + }, "dev_class": "zone_thermostat", "firmware": "2016-08-02T02:00:00+02:00", "hardware": "255", @@ -306,6 +318,9 @@ }, "d3da73bde12a47d5a6b8f9dad971f2ec": { "available": true, + "binary_sensors": { + "battery_state": false + }, "dev_class": "thermo_sensor", "firmware": "2019-03-27T01:00:00+01:00", "hardware": "1", @@ -339,6 +354,9 @@ "CV Jessie", "off" ], + "binary_sensors": { + "battery_state": false + }, "dev_class": "zone_thermostat", "firmware": "2016-10-27T02:00:00+02:00", "hardware": "255", @@ -379,6 +397,9 @@ "CV Jessie", "off" ], + "binary_sensors": { + "battery_state": false + }, "dev_class": "thermostatic_radiator_valve", "firmware": "2019-03-27T01:00:00+01:00", "hardware": "1", @@ -421,6 +442,9 @@ "CV Jessie", "off" ], + "binary_sensors": { + "battery_state": false + }, "dev_class": "zone_thermostat", "firmware": "2016-10-27T02:00:00+02:00", "hardware": "255", @@ -473,7 +497,7 @@ "cooling_present": false, "gateway_id": "fe799307f1624099878210aa0b9f1475", "heater_id": "90986d591dcd426cae3ec3e8111ff730", - "item_count": 315, + "item_count": 323, "notifications": { "af82e4ccf9c548528166d38e560662a4": { "warning": "Node Plug (with MAC address 000D6F000D13CB01, in room 'n.a.') has been unreachable since 23:03 2020-01-18. Please check the connection and restart the device." diff --git a/fixtures/adam_plus_anna_new/all_data.json b/fixtures/adam_plus_anna_new/all_data.json index 438084e68..c69356300 100644 --- a/fixtures/adam_plus_anna_new/all_data.json +++ b/fixtures/adam_plus_anna_new/all_data.json @@ -27,6 +27,9 @@ }, "1772a4ea304041adb83f357b751341ff": { "available": true, + "binary_sensors": { + "battery_state": false + }, "dev_class": "thermo_sensor", "firmware": "2020-11-04T01:00:00+01:00", "hardware": "1", @@ -184,6 +187,9 @@ "Weekschema", "off" ], + "binary_sensors": { + "battery_state": true + }, "control_state": "preheating", "dev_class": "zone_thermostat", "firmware": "2016-10-10T02:00:00+02:00", @@ -195,7 +201,7 @@ "preset_modes": ["no_frost", "asleep", "vacation", "home", "away"], "select_schedule": "Badkamer", "sensors": { - "battery": 38, + "battery": 14, "setpoint": 18.0, "temperature": 16.5 }, @@ -231,7 +237,7 @@ "cooling_present": false, "gateway_id": "da224107914542988a88561b4452b0f6", "heater_id": "056ee145a816487eaa69243c3280f8bf", - "item_count": 147, + "item_count": 149, "notifications": {}, "reboot": true, "smile_name": "Adam" diff --git a/fixtures/adam_zone_per_device/all_data.json b/fixtures/adam_zone_per_device/all_data.json index 119e098fe..5a86937be 100644 --- a/fixtures/adam_zone_per_device/all_data.json +++ b/fixtures/adam_zone_per_device/all_data.json @@ -82,6 +82,9 @@ }, "680423ff840043738f42cc7f1ff97a36": { "available": true, + "binary_sensors": { + "battery_state": false + }, "dev_class": "thermo_sensor", "firmware": "2019-03-27T01:00:00+01:00", "hardware": "1", @@ -115,6 +118,9 @@ "CV Jessie", "off" ], + "binary_sensors": { + "battery_state": false + }, "dev_class": "zone_thermostat", "firmware": "2016-10-27T02:00:00+02:00", "hardware": "255", @@ -199,6 +205,9 @@ }, "a2c3583e0a6349358998b760cea82d2a": { "available": true, + "binary_sensors": { + "battery_state": false + }, "dev_class": "thermo_sensor", "firmware": "2019-03-27T01:00:00+01:00", "hardware": "1", @@ -255,6 +264,9 @@ "CV Jessie", "off" ], + "binary_sensors": { + "battery_state": false + }, "dev_class": "zone_thermostat", "firmware": "2016-08-02T02:00:00+02:00", "hardware": "255", @@ -306,6 +318,9 @@ }, "d3da73bde12a47d5a6b8f9dad971f2ec": { "available": true, + "binary_sensors": { + "battery_state": false + }, "dev_class": "thermo_sensor", "firmware": "2019-03-27T01:00:00+01:00", "hardware": "1", @@ -339,6 +354,9 @@ "CV Jessie", "off" ], + "binary_sensors": { + "battery_state": false + }, "dev_class": "zone_thermostat", "firmware": "2016-10-27T02:00:00+02:00", "hardware": "255", @@ -379,6 +397,9 @@ "CV Jessie", "off" ], + "binary_sensors": { + "battery_state": false + }, "dev_class": "thermostatic_radiator_valve", "firmware": "2019-03-27T01:00:00+01:00", "hardware": "1", @@ -421,6 +442,9 @@ "CV Jessie", "off" ], + "binary_sensors": { + "battery_state": false + }, "dev_class": "zone_thermostat", "firmware": "2016-10-27T02:00:00+02:00", "hardware": "255", @@ -473,7 +497,7 @@ "cooling_present": false, "gateway_id": "fe799307f1624099878210aa0b9f1475", "heater_id": "90986d591dcd426cae3ec3e8111ff730", - "item_count": 315, + "item_count": 323, "notifications": { "af82e4ccf9c548528166d38e560662a4": { "warning": "Node Plug (with MAC address 000D6F000D13CB01, in room 'n.a.') has been unreachable since 23:03 2020-01-18. Please check the connection and restart the device." diff --git a/fixtures/m_adam_cooling/all_data.json b/fixtures/m_adam_cooling/all_data.json index 759d0094d..2806e0cba 100644 --- a/fixtures/m_adam_cooling/all_data.json +++ b/fixtures/m_adam_cooling/all_data.json @@ -28,6 +28,9 @@ }, "1772a4ea304041adb83f357b751341ff": { "available": true, + "binary_sensors": { + "battery_state": false + }, "dev_class": "thermo_sensor", "firmware": "2020-11-04T01:00:00+01:00", "hardware": "1", @@ -116,6 +119,9 @@ "Weekschema", "off" ], + "binary_sensors": { + "battery_state": true + }, "control_state": "preheating", "dev_class": "zone_thermostat", "firmware": "2016-10-10T02:00:00+02:00", @@ -127,7 +133,7 @@ "preset_modes": ["no_frost", "asleep", "vacation", "home", "away"], "select_schedule": "Badkamer", "sensors": { - "battery": 38, + "battery": 14, "setpoint": 23.5, "temperature": 23.9 }, @@ -163,7 +169,7 @@ "cooling_present": true, "gateway_id": "da224107914542988a88561b4452b0f6", "heater_id": "056ee145a816487eaa69243c3280f8bf", - "item_count": 147, + "item_count": 149, "notifications": {}, "reboot": true, "smile_name": "Adam" diff --git a/fixtures/m_adam_heating/all_data.json b/fixtures/m_adam_heating/all_data.json index e2c23df42..447d7bd2d 100644 --- a/fixtures/m_adam_heating/all_data.json +++ b/fixtures/m_adam_heating/all_data.json @@ -33,6 +33,9 @@ }, "1772a4ea304041adb83f357b751341ff": { "available": true, + "binary_sensors": { + "battery_state": false + }, "dev_class": "thermo_sensor", "firmware": "2020-11-04T01:00:00+01:00", "hardware": "1", @@ -115,6 +118,9 @@ "Weekschema", "off" ], + "binary_sensors": { + "battery_state": true + }, "control_state": "off", "dev_class": "zone_thermostat", "firmware": "2016-10-10T02:00:00+02:00", @@ -126,7 +132,7 @@ "preset_modes": ["no_frost", "asleep", "vacation", "home", "away"], "select_schedule": "Badkamer", "sensors": { - "battery": 38, + "battery": 14, "setpoint": 15.0, "temperature": 17.9 }, @@ -162,7 +168,7 @@ "cooling_present": false, "gateway_id": "da224107914542988a88561b4452b0f6", "heater_id": "056ee145a816487eaa69243c3280f8bf", - "item_count": 147, + "item_count": 149, "notifications": {}, "reboot": true, "smile_name": "Adam" diff --git a/fixtures/m_adam_jip/all_data.json b/fixtures/m_adam_jip/all_data.json index 7888d7778..86508c55e 100644 --- a/fixtures/m_adam_jip/all_data.json +++ b/fixtures/m_adam_jip/all_data.json @@ -3,6 +3,9 @@ "1346fbd8498d4dbcab7e18d51b771f3d": { "active_preset": "no_frost", "available": true, + "binary_sensors": { + "battery_state": false + }, "control_state": "off", "dev_class": "zone_thermostat", "firmware": "2016-10-27T02:00:00+02:00", @@ -97,6 +100,9 @@ "6f3e9d7084214c21b9dfa46f6eeb8700": { "active_preset": "home", "available": true, + "binary_sensors": { + "battery_state": false + }, "control_state": "off", "dev_class": "zone_thermostat", "firmware": "2016-10-27T02:00:00+02:00", @@ -152,6 +158,9 @@ "a6abc6a129ee499c88a4d420cc413b47": { "active_preset": "home", "available": true, + "binary_sensors": { + "battery_state": false + }, "control_state": "off", "dev_class": "zone_thermostat", "firmware": "2016-10-27T02:00:00+02:00", @@ -263,6 +272,9 @@ "f61f1a2535f54f52ad006a3d18e459ca": { "active_preset": "home", "available": true, + "binary_sensors": { + "battery_state": false + }, "control_state": "off", "dev_class": "zone_thermometer", "firmware": "2020-09-01T02:00:00+02:00", @@ -298,7 +310,7 @@ "cooling_present": false, "gateway_id": "b5c2386c6f6342669e50fe49dd05b188", "heater_id": "e4684553153b44afbef2200885f379dc", - "item_count": 213, + "item_count": 217, "notifications": {}, "reboot": true, "smile_name": "Adam" diff --git a/fixtures/m_adam_multiple_devices_per_zone/all_data.json b/fixtures/m_adam_multiple_devices_per_zone/all_data.json index c88773abe..b788b43da 100644 --- a/fixtures/m_adam_multiple_devices_per_zone/all_data.json +++ b/fixtures/m_adam_multiple_devices_per_zone/all_data.json @@ -82,6 +82,9 @@ }, "680423ff840043738f42cc7f1ff97a36": { "available": true, + "binary_sensors": { + "battery_state": false + }, "dev_class": "thermo_sensor", "firmware": "2019-03-27T01:00:00+01:00", "hardware": "1", @@ -115,6 +118,9 @@ "CV Jessie", "off" ], + "binary_sensors": { + "battery_state": false + }, "dev_class": "zone_thermostat", "firmware": "2016-10-27T02:00:00+02:00", "hardware": "255", @@ -199,6 +205,9 @@ }, "a2c3583e0a6349358998b760cea82d2a": { "available": true, + "binary_sensors": { + "battery_state": false + }, "dev_class": "thermo_sensor", "firmware": "2019-03-27T01:00:00+01:00", "hardware": "1", @@ -255,6 +264,9 @@ "CV Jessie", "off" ], + "binary_sensors": { + "battery_state": false + }, "dev_class": "zone_thermostat", "firmware": "2016-08-02T02:00:00+02:00", "hardware": "255", @@ -306,6 +318,9 @@ }, "d3da73bde12a47d5a6b8f9dad971f2ec": { "available": true, + "binary_sensors": { + "battery_state": false + }, "dev_class": "thermo_sensor", "firmware": "2019-03-27T01:00:00+01:00", "hardware": "1", @@ -339,6 +354,9 @@ "CV Jessie", "off" ], + "binary_sensors": { + "battery_state": false + }, "dev_class": "zone_thermostat", "firmware": "2016-10-27T02:00:00+02:00", "hardware": "255", @@ -371,6 +389,9 @@ "e7693eb9582644e5b865dba8d4447cf1": { "active_preset": "no_frost", "available": true, + "binary_sensors": { + "battery_state": false + }, "dev_class": "thermostatic_radiator_valve", "firmware": "2019-03-27T01:00:00+01:00", "hardware": "1", @@ -412,6 +433,9 @@ "CV Jessie", "off" ], + "binary_sensors": { + "battery_state": false + }, "dev_class": "zone_thermostat", "firmware": "2016-10-27T02:00:00+02:00", "hardware": "255", @@ -464,7 +488,7 @@ "cooling_present": false, "gateway_id": "fe799307f1624099878210aa0b9f1475", "heater_id": "90986d591dcd426cae3ec3e8111ff730", - "item_count": 315, + "item_count": 323, "notifications": { "af82e4ccf9c548528166d38e560662a4": { "warning": "Node Plug (with MAC address 000D6F000D13CB01, in room 'n.a.') has been unreachable since 23:03 2020-01-18. Please check the connection and restart the device." diff --git a/plugwise/constants.py b/plugwise/constants.py index 677766796..ffe9378b3 100644 --- a/plugwise/constants.py +++ b/plugwise/constants.py @@ -258,6 +258,7 @@ ] BinarySensorType = Literal[ + "battery_state", "compressor_state", "cooling_enabled", "cooling_state", @@ -409,6 +410,7 @@ class ModelData(TypedDict): class SmileBinarySensors(TypedDict, total=False): """Smile Binary Sensors class.""" + battery_state: bool compressor_state: bool cooling_enabled: bool cooling_state: bool diff --git a/plugwise/data.py b/plugwise/data.py index e1d46caee..603a6988d 100644 --- a/plugwise/data.py +++ b/plugwise/data.py @@ -4,6 +4,8 @@ """ from __future__ import annotations +import re + from plugwise.constants import ( ADAM, ANNA, @@ -52,13 +54,49 @@ def _update_gw_devices(self) -> None: Collect data for each device and add to self.gw_devices. """ + mac_list: list[str] = [] for device_id, device in self.gw_devices.items(): data = self._get_device_data(device_id) - self._add_or_update_notifications(device_id, device, data) + if device_id == self.gateway_id: + mac_list = self._detect_low_batteries() + self._add_or_update_notifications(device_id, device, data) + device.update(data) + + is_battery_low = ( + mac_list + and "battery_state" in device["binary_sensors"] + and device["zigbee_mac_address"] in mac_list + and ( + (device["dev_class"] in ("thermo_sensor", "thermostatic_radiator_valve") and device["sensors"]["battery"] < 30) + or (device["dev_class"] in ("zone_thermometer", "zone_thermostat") and device["sensors"]["battery"] < 15) + ) + ) + if is_battery_low: + device["binary_sensors"]["battery_state"] = True + self._update_for_cooling(device) + remove_empty_platform_dicts(device) + def _detect_low_batteries(self) -> list[str]: + """Helper-function updating the battery_state binary_sensor status from a Battery-is-low message.""" + mac_address_list: list[str] = [] + mac_pattern = re.compile(r"(?:[0-9A-F]{2}){8}") + matches = ["Battery", "below"] + if self._notifications: + for msg_id, notification in list(self._notifications.items()): + mac_address: str | None = None + message: str | None = notification.get("message") + if message is not None and all(x in message for x in matches) and (mac_addresses := mac_pattern.findall(message)): + mac_address = mac_addresses[0] # re.findall() outputs a list + + if mac_address is not None: + self._notifications.pop(msg_id) + mac_address_list.append(mac_address) + + return mac_address_list + def _add_or_update_notifications( self, device_id: str, device: DeviceData, data: DeviceData ) -> None: diff --git a/plugwise/smile.py b/plugwise/smile.py index 21f31a237..1b9824508 100644 --- a/plugwise/smile.py +++ b/plugwise/smile.py @@ -129,7 +129,6 @@ def get_all_devices(self) -> None: async def async_update(self) -> PlugwiseData: """Perform an incremental update for updating the various device states.""" - # Perform a full update at day-change self.gw_data: GatewayData = {} self.gw_devices: dict[str, DeviceData] = {} try: diff --git a/plugwise/util.py b/plugwise/util.py index 0aba3d2d8..a818d6d03 100644 --- a/plugwise/util.py +++ b/plugwise/util.py @@ -138,6 +138,9 @@ def common_match_cases( sp_key = cast(SpecialType, measurement) data[sp_key] = value + if "battery" in data["sensors"]: + data["binary_sensors"]["battery_state"] = False + def escape_illegal_xml_characters(xmldata: str) -> str: """Replace illegal &-characters.""" diff --git a/pyproject.toml b/pyproject.toml index f7010951e..43d584380 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "plugwise" -version = "1.0.0" +version = "1.1.0a0" license = {file = "LICENSE"} description = "Plugwise Smile (Adam/Anna/P1) and Stretch module for Python 3." readme = "README.md" diff --git a/tests/data/adam/adam_plus_anna_new.json b/tests/data/adam/adam_plus_anna_new.json index 911e787b4..55d2a9028 100644 --- a/tests/data/adam/adam_plus_anna_new.json +++ b/tests/data/adam/adam_plus_anna_new.json @@ -70,10 +70,13 @@ "name": "Lisa Badkamer", "zigbee_mac_address": "000D6F000C869B61", "vendor": "Plugwise", + "binary_sensors": { + "battery_state": true + }, "sensors": { "temperature": 16.5, "setpoint": 18, - "battery": 38 + "battery": 14 }, "temperature_offset": { "lower_bound": -2, @@ -178,6 +181,9 @@ "name": "Tom Badkamer", "zigbee_mac_address": "000D6F000C8FF5EE", "vendor": "Plugwise", + "binary_sensors": { + "battery_state": false + }, "sensors": { "temperature": 17.6, "setpoint": 18, diff --git a/tests/data/adam/adam_plus_anna_new_UPDATED_DATA.json b/tests/data/adam/adam_plus_anna_new_UPDATED_DATA.json index e357757de..044192bac 100644 --- a/tests/data/adam/adam_plus_anna_new_UPDATED_DATA.json +++ b/tests/data/adam/adam_plus_anna_new_UPDATED_DATA.json @@ -27,6 +27,9 @@ "available": false }, "e2f4322d57924fa090fbbc48b3a140dc": { + "binary_sensors": { + "battery_state": false + }, "mode": "off" }, "da224107914542988a88561b4452b0f6": { diff --git a/tests/test_adam.py b/tests/test_adam.py index 0a97cb10f..34e2f57c0 100644 --- a/tests/test_adam.py +++ b/tests/test_adam.py @@ -14,7 +14,155 @@ class TestPlugwiseAdam(TestPlugwise): # pylint: disable=attribute-defined-outside-init - """Tests for Adam standalone, i.e. not combined with Anna or Jip.""" + """Tests for Adam.""" + + @pytest.mark.asyncio + async def test_connect_adam_plus_anna_new(self): + """Test extended Adam (firmware 3.8) with Anna and a switch-group setup.""" + self.smile_setup = "adam_plus_anna_new" + + testdata = self.load_testdata(SMILE_TYPE, self.smile_setup) + server, smile, client = await self.connect_wrapper() + assert smile.smile_hostname == "smile000000" + + self.validate_test_basics( + _LOGGER, + smile, + smile_type=None, + smile_version="3.7.8", + ) + + await self.device_test(smile, "2023-12-17 00:00:01", testdata) + assert smile.gateway_id == "da224107914542988a88561b4452b0f6" + assert smile._last_active["f2bf9048bef64cc5b6d5110154e33c81"] == "Weekschema" + assert smile._last_active["f871b8c4d63549319221e294e4f88074"] == "Badkamer" + assert self.device_items == 149 + assert self.device_list == [ + "da224107914542988a88561b4452b0f6", + "056ee145a816487eaa69243c3280f8bf", + "67d73d0bd469422db25a618a5fb8eeb0", + "e2f4322d57924fa090fbbc48b3a140dc", + "29542b2b6a6a4169acecc15c72a599b8", + "ad4838d7d35c4d6ea796ee12ae5aedf8", + "1772a4ea304041adb83f357b751341ff", + "854f8a9b0e7e425db97f1f110e1ce4b3", + "2568cc4b9c1e401495d4741a5f89bee1", + "e8ef2a01ed3b4139a53bf749204fe6b4", + ] + + result = await self.tinker_thermostat( + smile, + "f2bf9048bef64cc5b6d5110154e33c81", + good_schedules=["Weekschema", "Badkamer", "Test"], + ) + assert result + + # Special test-case for turning a schedule off based on only the location id. + await smile.set_schedule_state("f2bf9048bef64cc5b6d5110154e33c81", "off") + + # Special test-case for turning a schedule off for a location via the option "off". + await smile.set_schedule_state("f2bf9048bef64cc5b6d5110154e33c81", "on", "off") + + # bad schedule-state test + result = await self.tinker_thermostat_schedule( + smile, + "f2bf9048bef64cc5b6d5110154e33c81", + "bad", + good_schedules=["Badkamer"], + single=True, + ) + assert result + + smile._schedule_old_states["f2bf9048bef64cc5b6d5110154e33c81"][ + "Badkamer" + ] = "off" + result_1 = await self.tinker_thermostat_schedule( + smile, + "f2bf9048bef64cc5b6d5110154e33c81", + "on", + good_schedules=["Badkamer"], + single=True, + ) + result_2 = await self.tinker_thermostat_schedule( + smile, + "f2bf9048bef64cc5b6d5110154e33c81", + "on", + good_schedules=["Badkamer"], + single=True, + ) + assert result_1 and result_2 + + switch_change = await self.tinker_switch( + smile, + "e8ef2a01ed3b4139a53bf749204fe6b4", + ["2568cc4b9c1e401495d4741a5f89bee1", "29542b2b6a6a4169acecc15c72a599b8"], + ) + assert switch_change + switch_change = await self.tinker_switch( + smile, "056ee145a816487eaa69243c3280f8bf", model="dhw_cm_switch" + ) + assert switch_change + switch_change = await self.tinker_switch( + smile, "854f8a9b0e7e425db97f1f110e1ce4b3", model="lock" + ) + assert switch_change + switch_change = await self.tinker_switch( + smile, "2568cc4b9c1e401495d4741a5f89bee1" + ) + assert not switch_change + + tinkered = await self.tinker_gateway_mode(smile) + assert not tinkered + + tinkered = await self.tinker_regulation_mode(smile) + assert not tinkered + + tinkered = await self.tinker_max_boiler_temp(smile) + assert not tinkered + + # Now change some data and change directory reading xml from + # emulating reading newer dataset after an update_interval + testdata_updated = self.load_testdata( + SMILE_TYPE, f"{self.smile_setup}_UPDATED_DATA" + ) + self.smile_setup = "updated/adam_plus_anna_new" + await self.device_test( + smile, "2022-01-16 00:00:01", testdata_updated, initialize=False + ) + + # Simulate receiving no xml-data after a requesting a reboot of the gateway + self.smile_setup = "reboot/adam_plus_anna_new" + try: + await self.device_test(smile, initialize=False) + except pw_exceptions.PlugwiseError: + _LOGGER.debug("Receiving no data after a reboot is properly handled") + + # Simulate receiving xml-data with + self.smile_setup = "error/adam_plus_anna_new" + try: + await self.device_test(smile, initialize=False) + except pw_exceptions.ResponseError: + _LOGGER.debug("Receiving error-data from the Gateway") + + await smile.close_connection() + await self.disconnect(server, client) + + self.smile_setup = "adam_plus_anna_new" + testdata = self.load_testdata(SMILE_TYPE, self.smile_setup) + server, smile, client = await self.connect_wrapper(raise_timeout=True) + await self.device_test(smile, "2023-12-17 00:00:01", testdata, skip_testing=True) + + tinkered = await self.tinker_max_boiler_temp(smile, unhappy=True) + assert tinkered + + tinkered = await self.tinker_gateway_mode(smile, unhappy=True) + assert tinkered + + tinkered = await self.tinker_regulation_mode(smile, unhappy=True) + assert tinkered + + await smile.close_connection() + await self.disconnect(server, client) @pytest.mark.asyncio async def test_connect_adam_zone_per_device(self): @@ -38,7 +186,7 @@ async def test_connect_adam_zone_per_device(self): assert smile._last_active["82fa13f017d240daa0d0ea1775420f24"] == CV_JESSIE assert smile._last_active["08963fec7c53423ca5680aa4cb502c63"] == BADKAMER_SCHEMA assert smile._last_active["446ac08dd04d4eff8ac57489757b7314"] == BADKAMER_SCHEMA - assert self.device_items == 315 + assert self.device_items == 323 assert "af82e4ccf9c548528166d38e560662a4" in self.notifications await smile.delete_notification() @@ -116,7 +264,7 @@ async def test_connect_adam_multiple_devices_per_zone(self): assert smile._last_active["82fa13f017d240daa0d0ea1775420f24"] == CV_JESSIE assert smile._last_active["08963fec7c53423ca5680aa4cb502c63"] == BADKAMER_SCHEMA assert smile._last_active["446ac08dd04d4eff8ac57489757b7314"] == BADKAMER_SCHEMA - assert self.device_items == 315 + assert self.device_items == 323 assert "af82e4ccf9c548528166d38e560662a4" in self.notifications @@ -154,7 +302,7 @@ async def test_adam_heatpump_cooling(self): assert smile._last_active["a562019b0b1f47a4bde8ebe3dbe3e8a9"] == WERKDAG_SCHEMA assert smile._last_active["8cf650a4c10c44819e426bed406aec34"] == WERKDAG_SCHEMA assert smile._last_active["5cc21042f87f4b4c94ccb5537c47a53f"] == WERKDAG_SCHEMA - assert self.device_items == 415 + assert self.device_items == 417 await smile.close_connection() await self.disconnect(server, client) @@ -230,154 +378,6 @@ async def test_connect_adam_plus_anna(self): await smile.close_connection() await self.disconnect(server, client) - @pytest.mark.asyncio - async def test_connect_adam_plus_anna_new(self): - """Test extended Adam (firmware 3.8) with Anna and a switch-group setup.""" - self.smile_setup = "adam_plus_anna_new" - - testdata = self.load_testdata(SMILE_TYPE, self.smile_setup) - server, smile, client = await self.connect_wrapper() - assert smile.smile_hostname == "smile000000" - - self.validate_test_basics( - _LOGGER, - smile, - smile_type=None, - smile_version="3.7.8", - ) - - await self.device_test(smile, "2023-12-17 00:00:01", testdata) - assert smile.gateway_id == "da224107914542988a88561b4452b0f6" - assert smile._last_active["f2bf9048bef64cc5b6d5110154e33c81"] == "Weekschema" - assert smile._last_active["f871b8c4d63549319221e294e4f88074"] == "Badkamer" - assert self.device_items == 147 - assert self.device_list == [ - "da224107914542988a88561b4452b0f6", - "056ee145a816487eaa69243c3280f8bf", - "67d73d0bd469422db25a618a5fb8eeb0", - "e2f4322d57924fa090fbbc48b3a140dc", - "29542b2b6a6a4169acecc15c72a599b8", - "ad4838d7d35c4d6ea796ee12ae5aedf8", - "1772a4ea304041adb83f357b751341ff", - "854f8a9b0e7e425db97f1f110e1ce4b3", - "2568cc4b9c1e401495d4741a5f89bee1", - "e8ef2a01ed3b4139a53bf749204fe6b4", - ] - - result = await self.tinker_thermostat( - smile, - "f2bf9048bef64cc5b6d5110154e33c81", - good_schedules=["Weekschema", "Badkamer", "Test"], - ) - assert result - - # Special test-case for turning a schedule off based on only the location id. - await smile.set_schedule_state("f2bf9048bef64cc5b6d5110154e33c81", "off") - - # Special test-case for turning a schedule off for a location via the option "off". - await smile.set_schedule_state("f2bf9048bef64cc5b6d5110154e33c81", "on", "off") - - # bad schedule-state test - result = await self.tinker_thermostat_schedule( - smile, - "f2bf9048bef64cc5b6d5110154e33c81", - "bad", - good_schedules=["Badkamer"], - single=True, - ) - assert result - - smile._schedule_old_states["f2bf9048bef64cc5b6d5110154e33c81"][ - "Badkamer" - ] = "off" - result_1 = await self.tinker_thermostat_schedule( - smile, - "f2bf9048bef64cc5b6d5110154e33c81", - "on", - good_schedules=["Badkamer"], - single=True, - ) - result_2 = await self.tinker_thermostat_schedule( - smile, - "f2bf9048bef64cc5b6d5110154e33c81", - "on", - good_schedules=["Badkamer"], - single=True, - ) - assert result_1 and result_2 - - switch_change = await self.tinker_switch( - smile, - "e8ef2a01ed3b4139a53bf749204fe6b4", - ["2568cc4b9c1e401495d4741a5f89bee1", "29542b2b6a6a4169acecc15c72a599b8"], - ) - assert switch_change - switch_change = await self.tinker_switch( - smile, "056ee145a816487eaa69243c3280f8bf", model="dhw_cm_switch" - ) - assert switch_change - switch_change = await self.tinker_switch( - smile, "854f8a9b0e7e425db97f1f110e1ce4b3", model="lock" - ) - assert switch_change - switch_change = await self.tinker_switch( - smile, "2568cc4b9c1e401495d4741a5f89bee1" - ) - assert not switch_change - - tinkered = await self.tinker_gateway_mode(smile) - assert not tinkered - - tinkered = await self.tinker_regulation_mode(smile) - assert not tinkered - - tinkered = await self.tinker_max_boiler_temp(smile) - assert not tinkered - - # Now change some data and change directory reading xml from - # emulating reading newer dataset after an update_interval - testdata_updated = self.load_testdata( - SMILE_TYPE, f"{self.smile_setup}_UPDATED_DATA" - ) - self.smile_setup = "updated/adam_plus_anna_new" - await self.device_test( - smile, "2022-01-16 00:00:01", testdata_updated, initialize=False - ) - - # Simulate receiving no xml-data after a requesting a reboot of the gateway - self.smile_setup = "reboot/adam_plus_anna_new" - try: - await self.device_test(smile, initialize=False) - except pw_exceptions.PlugwiseError: - _LOGGER.debug("Receiving no data after a reboot is properly handled") - - # Simulate receiving xml-data with - self.smile_setup = "error/adam_plus_anna_new" - try: - await self.device_test(smile, initialize=False) - except pw_exceptions.ResponseError: - _LOGGER.debug("Receiving error-data from the Gateway") - - await smile.close_connection() - await self.disconnect(server, client) - - self.smile_setup = "adam_plus_anna_new" - testdata = self.load_testdata(SMILE_TYPE, self.smile_setup) - server, smile, client = await self.connect_wrapper(raise_timeout=True) - await self.device_test(smile, "2023-12-17 00:00:01", testdata, skip_testing=True) - - tinkered = await self.tinker_max_boiler_temp(smile, unhappy=True) - assert tinkered - - tinkered = await self.tinker_gateway_mode(smile, unhappy=True) - assert tinkered - - tinkered = await self.tinker_regulation_mode(smile, unhappy=True) - assert tinkered - - await smile.close_connection() - await self.disconnect(server, client) - @pytest.mark.asyncio async def test_adam_plus_jip(self): """Test Adam with Jip setup.""" @@ -392,7 +392,7 @@ async def test_adam_plus_jip(self): assert smile._last_active["06aecb3d00354375924f50c47af36bd2"] is None assert smile._last_active["d27aede973b54be484f6842d1b2802ad"] is None assert smile._last_active["13228dab8ce04617af318a2888b3c548"] is None - assert self.device_items == 213 + assert self.device_items == 217 # Negative test result = await self.tinker_thermostat( diff --git a/userdata/adam_plus_anna_new/core.domain_objects.xml b/userdata/adam_plus_anna_new/core.domain_objects.xml index 67a2e1626..574c7f7d7 100644 --- a/userdata/adam_plus_anna_new/core.domain_objects.xml +++ b/userdata/adam_plus_anna_new/core.domain_objects.xml @@ -137,7 +137,7 @@ - 0.38 + 0.14 @@ -1834,6 +1834,18 @@ + + message + local + Battery of Lisa is low. + Battery of Lisa (with MAC address 000D6F000C869B61, in room 'Bathroom') is below 30%. + + + + 2021-12-07T22:05:22.690+02:00 + 2021-12-07T22:05:22.774+02:00 + + Plugwise 160-01