Skip to content

Commit 79b64b0

Browse files
authored
Merge pull request #156 from plugwise/optimizing
Continued improvement
2 parents bb344df + d8814d2 commit 79b64b0

File tree

3 files changed

+74
-91
lines changed

3 files changed

+74
-91
lines changed

plugwise/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Plugwise module."""
22

3-
__version__ = "0.16.7a4"
3+
__version__ = "0.16.7a6"
44

55
from plugwise.smile import Smile
66
from plugwise.stick import Stick

plugwise/helper.py

Lines changed: 53 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,10 @@ def update_helper(
7373
if d_item == "plugwise_notification":
7474
devs[d_id][e_type][d_item] = notifs != {}
7575

76-
if key != d_item:
77-
continue
78-
for item in devs[d_id][e_type]:
79-
if key != item:
80-
continue
81-
devs[d_id][e_type][item] = data[key]
76+
if d_item == key:
77+
for item in devs[d_id][e_type]:
78+
if item == key:
79+
devs[d_id][e_type][item] = data[key]
8280

8381

8482
def check_model(name: str, v_name: str) -> str:
@@ -121,23 +119,22 @@ def schemas_schedule_temp(schedules: dict[str, Any], name: str) -> float | None:
121119
for i in range(length):
122120
j = (i + 1) % (length - 1)
123121
now = dt.datetime.now().time()
124-
if (
125-
schema_list[i][0] == dt.datetime.now().weekday()
126-
or schema_list[j][0] == dt.datetime.now().weekday()
122+
today = dt.datetime.now().weekday()
123+
if today in [schema_list[i][0], schema_list[j][0]] and in_between(
124+
now, schema_list[i][1], schema_list[j][1]
127125
):
128-
if in_between(now, schema_list[i][1], schema_list[j][1]):
129-
return schema_list[i][2]
126+
return schema_list[i][2]
130127

131128

132129
def types_finder(data: etree) -> set:
133130
"""Detect types within locations from logs."""
134131
types = set()
135132
for measure, attrs in HOME_MEASUREMENTS.items():
136-
locator = f".//logs/point_log[type='{measure}']"
133+
locator = f"./logs/point_log[type='{measure}']"
137134
if (log := data.find(locator)) is None:
138135
continue
139136

140-
p_locator = ".//electricity_point_meter"
137+
p_locator = "./electricity_point_meter"
141138
if (p_log := log.find(p_locator)) is not None and p_log.get("id"):
142139
types.add(attrs.get(ATTR_TYPE))
143140

@@ -376,7 +373,7 @@ def _all_locations(self) -> None:
376373
loc.name = location.find("name").text
377374
loc.id = location.attrib["id"]
378375
# Filter the valid single location for P1 legacy: services not empty
379-
locator = ".//services"
376+
locator = "./services"
380377
if (
381378
self._smile_legacy
382379
and self.smile_type == "power"
@@ -388,7 +385,7 @@ def _all_locations(self) -> None:
388385
loc.members = set()
389386

390387
# Group of appliances
391-
locator = ".//appliances/appliance"
388+
locator = "./appliances/appliance"
392389
if (locs := location.findall(locator)) is not None:
393390
for member in locs:
394391
loc.members.add(member.attrib["id"])
@@ -429,10 +426,10 @@ def _get_module_data(
429426
model_data["hardware_version"] = module.find("hardware_version").text
430427
model_data["firmware_version"] = module.find("firmware_version").text
431428
# Adam
432-
if found := module.find(".//protocols/zig_bee_node"):
429+
if found := module.find("./protocols/zig_bee_node"):
433430
model_data["zigbee_mac_address"] = found.find("mac_address").text
434431
# Stretches
435-
if found := module.find(".//protocols/network_router"):
432+
if found := module.find("./protocols/network_router"):
436433
model_data["zigbee_mac_address"] = found.find("mac_address").text
437434

438435
return model_data
@@ -442,7 +439,7 @@ def _energy_device_info_finder(self, appliance: etree, appl: Munch) -> Munch:
442439
Collect energy device info (Circle, Plug, Stealth): firmware, model and vendor name.
443440
"""
444441
if self._stretch_v2 or self._stretch_v3:
445-
locator = ".//services/electricity_point_meter"
442+
locator = "./services/electricity_point_meter"
446443
mod_type = "electricity_point_meter"
447444
module_data = self._get_module_data(appliance, locator, mod_type)
448445
if not module_data["contents"]:
@@ -460,7 +457,7 @@ def _energy_device_info_finder(self, appliance: etree, appl: Munch) -> Munch:
460457
return appl
461458

462459
if self.smile_type != "stretch" and "plug" in appl.types:
463-
locator = ".//logs/point_log/electricity_point_meter"
460+
locator = "./logs/point_log/electricity_point_meter"
464461
mod_type = "electricity_point_meter"
465462
module_data = self._get_module_data(appliance, locator, mod_type)
466463
appl.v_name = module_data["vendor_name"]
@@ -490,8 +487,7 @@ def _appliance_info_finder(self, appliance: etree, appl: Munch) -> Munch:
490487
mode_list: list[str] = []
491488
locator = "./actuator_functionalities/regulation_mode_control_functionality"
492489
if (search := appliance.find(locator)) is not None:
493-
if search.find("mode") is not None:
494-
self.cooling_active = search.find("mode").text == "cooling"
490+
self.cooling_active = search.find("mode").text == "cooling"
495491
if search.find("allowed_modes") is not None:
496492
for mode in search.find("allowed_modes"):
497493
mode_list.append(mode.text)
@@ -500,7 +496,7 @@ def _appliance_info_finder(self, appliance: etree, appl: Munch) -> Munch:
500496
return appl
501497

502498
if appl.pwclass in THERMOSTAT_CLASSES:
503-
locator = ".//logs/point_log[type='thermostat']/thermostat"
499+
locator = "./logs/point_log[type='thermostat']/thermostat"
504500
mod_type = "thermostat"
505501
module_data = self._get_module_data(appliance, locator, mod_type)
506502
appl.v_name = module_data["vendor_name"]
@@ -526,8 +522,8 @@ def _appliance_info_finder(self, appliance: etree, appl: Munch) -> Munch:
526522

527523
self._heater_id = appliance.attrib["id"]
528524
appl.name = "OpenTherm"
529-
locator1 = ".//logs/point_log[type='flame_state']/boiler_state"
530-
locator2 = ".//services/boiler_state"
525+
locator1 = "./logs/point_log[type='flame_state']/boiler_state"
526+
locator2 = "./services/boiler_state"
531527
mod_type = "boiler_state"
532528
module_data = self._get_module_data(appliance, locator1, mod_type)
533529
if not module_data["contents"]:
@@ -565,10 +561,10 @@ def _appliance_types_finder(self, appliance: etree, appl: Munch) -> Munch:
565561
appl.types = self._loc_data[self._home_location].get("types")
566562

567563
# Determine appliance_type from functionality
568-
relay_func = appliance.find(".//actuator_functionalities/relay_functionality")
569-
relay_act = appliance.find(".//actuators/relay")
564+
relay_func = appliance.find("./actuator_functionalities/relay_functionality")
565+
relay_act = appliance.find("./actuators/relay")
570566
thermo_func = appliance.find(
571-
".//actuator_functionalities/thermostat_functionality"
567+
"./actuator_functionalities/thermostat_functionality"
572568
)
573569
if relay_func is not None or relay_act is not None:
574570
appl.types.add("plug")
@@ -706,7 +702,7 @@ def _control_state(self, loc_id: str) -> str | None:
706702
"""
707703
locator = f'location[@id="{loc_id}"]'
708704
if (location := self._domain_objects.find(locator)) is not None:
709-
locator = './/actuator_functionalities/thermostat_functionality[type="thermostat"]/control_state'
705+
locator = './actuator_functionalities/thermostat_functionality[type="thermostat"]/control_state'
710706
if (ctrl_state := location.find(locator)) is not None:
711707
return ctrl_state.text
712708

@@ -764,8 +760,8 @@ def _rule_ids_by_name(self, name: str, loc_id: str) -> dict[str]:
764760
Obtain the rule_id from the given name and and provide the location_id, when present.
765761
"""
766762
schema_ids: dict[str] = {}
767-
locator = f'.//contexts/context/zone/location[@id="{loc_id}"]'
768-
for rule in self._domain_objects.findall(f'.//rule[name="{name}"]'):
763+
locator = f'./contexts/context/zone/location[@id="{loc_id}"]'
764+
for rule in self._domain_objects.findall(f'./rule[name="{name}"]'):
769765
if rule.find(locator) is not None:
770766
schema_ids[rule.attrib["id"]] = loc_id
771767
else:
@@ -778,9 +774,9 @@ def _rule_ids_by_tag(self, tag: str, loc_id: str) -> dict[str]:
778774
Obtain the rule_id from the given template_tag and provide the location_id, when present.
779775
"""
780776
schema_ids: dict[str] = {}
781-
locator1 = f'.//template[@tag="{tag}"]'
782-
locator2 = f'.//contexts/context/zone/location[@id="{loc_id}"]'
783-
for rule in self._domain_objects.findall(".//rule"):
777+
locator1 = f'./template[@tag="{tag}"]'
778+
locator2 = f'./contexts/context/zone/location[@id="{loc_id}"]'
779+
for rule in self._domain_objects.findall("./rule"):
784780
if rule.find(locator1) is not None:
785781
if rule.find(locator2) is not None:
786782
schema_ids[rule.attrib["id"]] = loc_id
@@ -861,7 +857,7 @@ def _get_appliance_data(self, d_id: str) -> dict[str, Any]:
861857
}.items()
862858

863859
if (
864-
appliance := self._appliances.find(f'.//appliance[@id="{d_id}"]')
860+
appliance := self._appliances.find(f'./appliance[@id="{d_id}"]')
865861
) is not None:
866862
data = self._appliance_measurements(appliance, data, measurements)
867863
data.update(self._get_lock_state(appliance))
@@ -965,7 +961,7 @@ def _thermostat_uri_legacy(self) -> str:
965961
"""Helper-function for _thermostat_uri().
966962
Determine the location-set_temperature uri - from APPLIANCES.
967963
"""
968-
locator = ".//appliance[type='thermostat']"
964+
locator = "./appliance[type='thermostat']"
969965
appliance_id = self._appliances.find(locator).attrib["id"]
970966

971967
return f"{APPLIANCES};id={appliance_id}/thermostat"
@@ -976,7 +972,7 @@ def _thermostat_uri(self, loc_id: str) -> str:
976972
if self._smile_legacy:
977973
return self._thermostat_uri_legacy()
978974

979-
locator = f'location[@id="{loc_id}"]/actuator_functionalities/thermostat_functionality'
975+
locator = f'./location[@id="{loc_id}"]/actuator_functionalities/thermostat_functionality'
980976
thermostat_functionality_id = self._locations.find(locator).attrib["id"]
981977

982978
return f"{LOCATIONS};id={loc_id}/thermostat;id={thermostat_functionality_id}"
@@ -990,27 +986,15 @@ def _group_switches(self) -> dict[str]:
990986
if self.smile_type == "power" or self.smile_name == "Anna":
991987
return switch_groups
992988

993-
search = self._domain_objects
994-
995-
appliances = search.findall("./appliance")
996-
groups = search.findall("./group")
997-
998-
for group in groups:
989+
for group in self._domain_objects.findall("./group"):
999990
group_appl: dict[str] = {}
1000991
members: list[str] = []
1001992
group_id = group.attrib["id"]
1002993
group_name = group.find("name").text
1003994
group_type = group.find("type").text
1004-
if self.smile_type == "stretch":
1005-
group_appliance: etree | None = group.findall("appliances/appliance")
1006-
for dummy in group_appliance:
1007-
members.append(dummy.attrib["id"])
1008-
else:
1009-
for appliance in appliances:
1010-
if (appl_group := appliance.find("./groups/group")) is not None:
1011-
appl_id: str = appliance.attrib["id"]
1012-
if appl_group.attrib["id"] == group_id:
1013-
members.append(appl_id)
995+
group_appliances = group.findall("appliances/appliance")
996+
for item in group_appliances:
997+
members.append(item.attrib["id"])
1014998

1015999
if group_type in SWITCH_GROUP_TYPES:
10161000
group_appl[group_id] = {
@@ -1035,8 +1019,8 @@ def _heating_valves(self) -> int | None:
10351019
"""
10361020
loc_found = 0
10371021
open_valve_count = 0
1038-
for appliance in self._appliances.findall(".//appliance"):
1039-
locator = './/logs/point_log[type="valve_position"]/period/measurement'
1022+
for appliance in self._appliances.findall("./appliance"):
1023+
locator = './logs/point_log[type="valve_position"]/period/measurement'
10401024
if (appl_loc := appliance.find(locator)) is not None:
10411025
loc_found += 1
10421026
if float(appl_loc.text) > 0.0:
@@ -1058,7 +1042,7 @@ def _power_data_peak_value(self, loc: str) -> Munch:
10581042
return loc
10591043

10601044
loc.locator = (
1061-
f'.//{loc.log_type}[type="{loc.measurement}"]/period/measurement'
1045+
f'./{loc.log_type}[type="{loc.measurement}"]/period/measurement'
10621046
)
10631047

10641048
# Locator not found
@@ -1098,13 +1082,13 @@ def _power_data_from_location(self, loc_id: str) -> dict[str, Any] | None:
10981082
if self._smile_legacy:
10991083
t_string = "tariff_indicator"
11001084

1101-
loc.logs = search.find(f'.//location[@id="{loc_id}"]/logs')
1085+
loc.logs = search.find(f'./location[@id="{loc_id}"]/logs')
11021086
# meter_string = ".//{}[type='{}']/"
11031087
for loc.measurement, loc.attrs in HOME_MEASUREMENTS.items():
11041088
for loc.log_type in log_list:
11051089
for loc.peak_select in peak_list:
11061090
loc.locator = (
1107-
f'.//{loc.log_type}[type="{loc.measurement}"]/period/'
1091+
f'./{loc.log_type}[type="{loc.measurement}"]/period/'
11081092
f'measurement[@{t_string}="{loc.peak_select}"]'
11091093
)
11101094
loc = self._power_data_peak_value(loc)
@@ -1123,11 +1107,11 @@ def _preset(self, loc_id: str) -> str | None:
11231107
Collect the active preset based on Location ID.
11241108
"""
11251109
if not self._smile_legacy:
1126-
locator = f'.//location[@id="{loc_id}"]/preset'
1110+
locator = f'./location[@id="{loc_id}"]/preset'
11271111
if (preset := self._domain_objects.find(locator)) is not None:
11281112
return preset.text
11291113

1130-
locator = "rule[active='true']/directives/when/then"
1114+
locator = "./rule[active='true']/directives/when/then"
11311115
if (
11321116
active_rule := self._domain_objects.find(locator)
11331117
) is None or "icon" not in active_rule.keys():
@@ -1144,13 +1128,13 @@ def _schemas_legacy(
11441128
schemas: dict[str] = {}
11451129

11461130
search = self._domain_objects
1147-
for schema in search.findall(".//rule"):
1131+
for schema in search.findall("./rule"):
11481132
if rule_name := schema.find("name").text:
11491133
if "preset" not in rule_name:
11501134
name = rule_name
11511135

11521136
log_type = "schedule_state"
1153-
locator = f"appliance[type='thermostat']/logs/point_log[type='{log_type}']/period/measurement"
1137+
locator = f"./appliance[type='thermostat']/logs/point_log[type='{log_type}']/period/measurement"
11541138
active = False
11551139
if (result := search.find(locator)) is not None:
11561140
active = result.text == "on"
@@ -1189,9 +1173,9 @@ def _schemas(self, location: str) -> tuple[str, ...]:
11891173

11901174
schedules: dict[str, Any] = {}
11911175
for rule_id, loc_id in rule_ids.items():
1192-
name = self._domain_objects.find(f'rule[@id="{rule_id}"]/name').text
1176+
name = self._domain_objects.find(f'./rule[@id="{rule_id}"]/name').text
11931177
schedule: dict[str, float] = {}
1194-
locator = f'rule[@id="{rule_id}"]/directives'
1178+
locator = f'./rule[@id="{rule_id}"]/directives'
11951179
directives = self._domain_objects.find(locator)
11961180
for directive in directives:
11971181
entry = directive.find("then").attrib
@@ -1234,9 +1218,11 @@ def _last_used_schedule(self, loc_id: str, rule_ids: dict[str]) -> str | None:
12341218
schemas: dict[str] | None = {}
12351219

12361220
for rule_id in rule_ids:
1237-
schema_name = self._domain_objects.find(f'rule[@id="{rule_id}"]/name').text
1221+
schema_name = self._domain_objects.find(
1222+
f'./rule[@id="{rule_id}"]/name'
1223+
).text
12381224
schema_date = self._domain_objects.find(
1239-
f'rule[@id="{rule_id}"]/modified_date'
1225+
f'./rule[@id="{rule_id}"]/modified_date'
12401226
).text
12411227
schema_time = parse(schema_date)
12421228
schemas[schema_name] = (schema_time - epoch).total_seconds()
@@ -1252,10 +1238,7 @@ def _object_value(self, obj_id: str, measurement: str) -> float | int | bool | N
12521238
"""
12531239
val: float | int | None = None
12541240
search = self._domain_objects
1255-
locator = (
1256-
f'.//location[@id="{obj_id}"]/logs/point_log'
1257-
f'[type="{measurement}"]/period/measurement'
1258-
)
1241+
locator = f'./location[@id="{obj_id}"]/logs/point_log[type="{measurement}"]/period/measurement'
12591242
if (found := search.find(locator)) is not None:
12601243
val = format_measure(found.text, None)
12611244
return val
@@ -1274,7 +1257,7 @@ def _get_lock_state(self, xml: str) -> dict[str, Any]:
12741257
func_type = "relay"
12751258
appl_class = xml.find("type").text
12761259
if appl_class not in ["central_heating_pump", "valve_actuator"]:
1277-
locator = f".//{actuator}/{func_type}/lock"
1260+
locator = f"./{actuator}/{func_type}/lock"
12781261
if (found := xml.find(locator)) is not None:
12791262
data["lock"] = format_measure(found.text, None)
12801263

0 commit comments

Comments
 (0)