Skip to content

Commit a41bdb2

Browse files
authored
Merge pull request #651 from plugwise/zigbee-valve
Bugfix for Adam: improve recognition of unknown zigbee devices
2 parents af09f6c + e706c47 commit a41bdb2

File tree

13 files changed

+115
-53
lines changed

13 files changed

+115
-53
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## v1.5.2
4+
5+
- Bugfix for Adam: improve recognition of unknown zigbee devices.
6+
37
## v1.5.1
48

59
- Fix typing and rounding of P1 and thermostat sensors, energy-device-related code improvements.

fixtures/adam_plus_anna_new/all_data.json

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,18 @@
2525
"dhw_cm_switch": false
2626
}
2727
},
28+
"10016900610d4c7481df78c89606ef22": {
29+
"available": true,
30+
"dev_class": "valve_actuator_plug",
31+
"location": "d9786723dbcf4f19b5c629a54629f9c7",
32+
"model_id": "TS0011",
33+
"name": "Aanvoer water afsluiter (nous lz3)",
34+
"switches": {
35+
"relay": false
36+
},
37+
"vendor": "_TZ3000_abjodzas",
38+
"zigbee_mac_address": "A4C13862AF9917B1"
39+
},
2840
"1772a4ea304041adb83f357b751341ff": {
2941
"available": true,
3042
"binary_sensors": {
@@ -266,7 +278,7 @@
266278
"cooling_present": false,
267279
"gateway_id": "da224107914542988a88561b4452b0f6",
268280
"heater_id": "056ee145a816487eaa69243c3280f8bf",
269-
"item_count": 157,
281+
"item_count": 165,
270282
"notifications": {},
271283
"reboot": true,
272284
"smile_name": "Adam"

fixtures/m_adam_cooling/all_data.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@
189189
"cooling_present": true,
190190
"gateway_id": "da224107914542988a88561b4452b0f6",
191191
"heater_id": "056ee145a816487eaa69243c3280f8bf",
192-
"item_count": 157,
192+
"item_count": 89,
193193
"notifications": {},
194194
"reboot": true,
195195
"smile_name": "Adam"

fixtures/m_adam_heating/all_data.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@
193193
"cooling_present": false,
194194
"gateway_id": "da224107914542988a88561b4452b0f6",
195195
"heater_id": "056ee145a816487eaa69243c3280f8bf",
196-
"item_count": 157,
196+
"item_count": 89,
197197
"notifications": {},
198198
"reboot": true,
199199
"smile_name": "Adam"

plugwise/common.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,12 @@ def _appl_heater_central_info(
7373
appl.name = "OpenTherm"
7474
locator_1 = "./logs/point_log[type='flame_state']/boiler_state"
7575
locator_2 = "./services/boiler_state"
76-
mod_type = "boiler_state"
7776
# xml_1: appliance
7877
# xml_3: self._modules for legacy, self._domain_objects for actual
7978
xml_3 = return_valid(xml_3, self._domain_objects)
80-
module_data = self._get_module_data(xml_1, locator_1, mod_type, xml_3)
79+
module_data = self._get_module_data(xml_1, locator_1, xml_3)
8180
if not module_data["contents"]:
82-
module_data = self._get_module_data(xml_1, locator_2, mod_type, xml_3)
81+
module_data = self._get_module_data(xml_1, locator_2, xml_3)
8382
appl.vendor_name = module_data["vendor_name"]
8483
appl.hardware = module_data["hardware_version"]
8584
appl.model_id = module_data["vendor_model"] if not legacy else None
@@ -94,15 +93,15 @@ def _appl_heater_central_info(
9493
def _appl_thermostat_info(self, appl: Munch, xml_1: etree, xml_2: etree = None) -> Munch:
9594
"""Helper-function for _appliance_info_finder()."""
9695
locator = "./logs/point_log[type='thermostat']/thermostat"
97-
mod_type = "thermostat"
9896
xml_2 = return_valid(xml_2, self._domain_objects)
99-
module_data = self._get_module_data(xml_1, locator, mod_type, xml_2)
97+
module_data = self._get_module_data(xml_1, locator, xml_2)
10098
appl.vendor_name = module_data["vendor_name"]
10199
appl.model = module_data["vendor_model"]
102100
if appl.model != "ThermoTouch": # model_id for Anna not present as stand-alone device
103101
appl.model_id = appl.model
104102
appl.model = check_model(appl.model, appl.vendor_name)
105103

104+
appl.available = module_data["reachable"]
106105
appl.hardware = module_data["hardware_version"]
107106
appl.firmware = module_data["firmware_version"]
108107
appl.zigbee_mac = module_data["zigbee_mac_address"]
@@ -192,6 +191,7 @@ def _create_gw_devices(self, appl: Munch) -> None:
192191
self.gw_devices[appl.dev_id] = {"dev_class": appl.pwclass}
193192
self._count += 1
194193
for key, value in {
194+
"available": appl.available,
195195
"firmware": appl.firmware,
196196
"hardware": appl.hardware,
197197
"location": appl.location,
@@ -278,7 +278,6 @@ def _get_module_data(
278278
self,
279279
xml_1: etree,
280280
locator: str,
281-
mod_type: str,
282281
xml_2: etree = None,
283282
legacy: bool = False,
284283
) -> ModelData:
@@ -295,12 +294,11 @@ def _get_module_data(
295294
"vendor_model": None,
296295
"zigbee_mac_address": None,
297296
}
298-
# xml_1: appliance
297+
299298
if (appl_search := xml_1.find(locator)) is not None:
299+
link_tag = appl_search.tag
300300
link_id = appl_search.attrib["id"]
301-
loc = f".//services/{mod_type}[@id='{link_id}']...."
302-
if legacy:
303-
loc = f".//{mod_type}[@id='{link_id}']...."
301+
loc = f".//services/{link_tag}[@id='{link_id}']...."
304302
# Not possible to walrus for some reason...
305303
# xml_2: self._modules for legacy, self._domain_objects for actual
306304
search = return_valid(xml_2, self._domain_objects)

plugwise/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181

8282
MAX_SETPOINT: Final[float] = 30.0
8383
MIN_SETPOINT: Final[float] = 4.0
84+
MODULE_LOCATOR: Final = "./logs/point_log/*[@id]"
8485
NONE: Final = "None"
8586
OFF: Final = "off"
8687

plugwise/helper.py

Lines changed: 7 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
LIMITS,
2525
LOCATIONS,
2626
LOGGER,
27+
MODULE_LOCATOR,
2728
NONE,
2829
OFF,
2930
P1_MEASUREMENTS,
@@ -299,6 +300,7 @@ def _all_appliances(self) -> None:
299300
if appl.pwclass in THERMOSTAT_CLASSES and appl.location is None:
300301
continue
301302

303+
appl.available = None
302304
appl.dev_id = appliance.attrib["id"]
303305
appl.name = appliance.find("name").text
304306
appl.model = None
@@ -356,9 +358,8 @@ def _p1_smartmeter_info_finder(self, appl: Munch) -> None:
356358
"""Collect P1 DSMR SmartMeter info."""
357359
loc_id = next(iter(self.loc_data.keys()))
358360
location = self._domain_objects.find(f'./location[@id="{loc_id}"]')
359-
locator = "./logs/point_log/electricity_point_meter"
360-
mod_type = "electricity_point_meter"
361-
module_data = self._get_module_data(location, locator, mod_type)
361+
locator = MODULE_LOCATOR
362+
module_data = self._get_module_data(location, locator)
362363
if not module_data["contents"]:
363364
LOGGER.error("No module data found for SmartMeter") # pragma: no cover
364365
return None # pragma: no cover
@@ -396,13 +397,13 @@ def _appliance_info_finder(self, appl: Munch, appliance: etree) -> Munch:
396397
return appl
397398
case _ as s if s.endswith("_plug"):
398399
# Collect info from plug-types (Plug, Aqara Smart Plug)
399-
locator = "./logs/interval_log/electricity_interval_meter"
400-
mod_type = "electricity_interval_meter"
401-
module_data = self._get_module_data(appliance, locator, mod_type)
400+
locator = MODULE_LOCATOR
401+
module_data = self._get_module_data(appliance, locator)
402402
# A plug without module-data is orphaned/ no present
403403
if not module_data["contents"]:
404404
return Munch()
405405

406+
appl.available = module_data["reachable"]
406407
appl.firmware = module_data["firmware_version"]
407408
appl.hardware = module_data["hardware_version"]
408409
appl.model_id = module_data["vendor_model"]
@@ -515,9 +516,6 @@ def _get_measurement_data(self, dev_id: str) -> DeviceData:
515516
if appliance.find("type").text in ACTUATOR_CLASSES:
516517
self._get_actuator_functionalities(appliance, device, data)
517518

518-
# Collect availability-status for wireless connected devices to Adam
519-
self._wireless_availability(appliance, data)
520-
521519
if dev_id == self.gateway_id and self.smile(ADAM):
522520
self._get_regulation_mode(appliance, data)
523521
self._get_gateway_mode(appliance, data)
@@ -710,29 +708,6 @@ def _get_actuator_functionalities(
710708
act_item = cast(ActuatorType, item)
711709
data[act_item] = temp_dict
712710

713-
def _wireless_availability(self, appliance: etree, data: DeviceData) -> None:
714-
"""Helper-function for _get_measurement_data().
715-
716-
Collect the availability-status for wireless connected devices.
717-
"""
718-
if self.smile(ADAM):
719-
# Try collecting for a Plug
720-
locator = "./logs/interval_log/electricity_interval_meter"
721-
mod_type = "electricity_interval_meter"
722-
module_data = self._get_module_data(appliance, locator, mod_type)
723-
if not module_data["contents"]:
724-
# Try collecting for a wireless thermostat
725-
locator = "./logs/point_log[type='thermostat']/thermostat"
726-
mod_type = "thermostat"
727-
module_data = self._get_module_data(appliance, locator, mod_type)
728-
if not module_data["contents"]:
729-
LOGGER.error("No module data found for Plug or wireless thermostat") # pragma: no cover
730-
return None # pragma: no cover
731-
732-
if module_data["reachable"] is not None:
733-
data["available"] = module_data["reachable"]
734-
self._count += 1
735-
736711
def _get_regulation_mode(self, appliance: etree, data: DeviceData) -> None:
737712
"""Helper-function for _get_measurement_data().
738713

plugwise/legacy/helper.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ def _all_appliances(self) -> None:
125125
appl.pwclass = "heater_central_plug"
126126

127127
appl.model = appl.pwclass.replace("_", " ").title()
128+
appl.available = None
128129
appl.model_id = None
129130
appl.firmware = None
130131
appl.hardware = None
@@ -230,9 +231,7 @@ def _energy_device_info_finder(self, appliance: etree, appl: Munch) -> Munch:
230231
"""
231232
if self.smile_type in ("power", "stretch"):
232233
locator = "./services/electricity_point_meter"
233-
mod_type = "electricity_point_meter"
234-
235-
module_data = self._get_module_data(appliance, locator, mod_type, self._modules, legacy=True)
234+
module_data = self._get_module_data(appliance, locator, self._modules, legacy=True)
236235
appl.zigbee_mac = module_data["zigbee_mac_address"]
237236
# Filter appliance without zigbee_mac, it's an orphaned device
238237
if appl.zigbee_mac is None and self.smile_type != "power":
@@ -253,6 +252,7 @@ def _energy_device_info_finder(self, appliance: etree, appl: Munch) -> Munch:
253252
def _p1_smartmeter_info_finder(self, appl: Munch) -> None:
254253
"""Collect P1 DSMR Smartmeter info."""
255254
loc_id = next(iter(self.loc_data.keys()))
255+
appl.available = None
256256
appl.dev_id = loc_id
257257
appl.location = loc_id
258258
appl.mac = None

plugwise/util.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ def check_model(name: str | None, vendor_name: str | None) -> str | None:
115115
if name is not None and "lumi.plug" in name:
116116
return "Aqara Smart Plug"
117117

118-
return name # pragma: no cover
118+
return None
119119

120120

121121
def common_match_cases(

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "plugwise"
7-
version = "1.5.1"
7+
version = "1.5.2"
88
license = {file = "LICENSE"}
99
description = "Plugwise Smile (Adam/Anna/P1) and Stretch module for Python 3."
1010
readme = "README.md"

0 commit comments

Comments
 (0)