Skip to content

Commit fa40d6d

Browse files
authored
Merge pull request #839 from plugwise/xml-get
Optimize 3
2 parents c005c19 + 1f956c7 commit fa40d6d

File tree

7 files changed

+68
-64
lines changed

7 files changed

+68
-64
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Ongoing
44

5-
- Code optimizations via PR [#837](https://github.com/plugwise/python-plugwise/pull/837), [#838](https://github.com/plugwise/python-plugwise/pull/838)
5+
- Code optimizations via PR [#837](https://github.com/plugwise/python-plugwise/pull/837), [#838](https://github.com/plugwise/python-plugwise/pull/838), [#839](https://github.com/plugwise/python-plugwise/pull/839)
66

77
## v1.11.0
88

plugwise/common.py

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -188,29 +188,28 @@ def _entity_switching_group(self, entity: GwEntityData) -> None:
188188
entity["switches"]["relay"] = counter != 0
189189
self._count += 1
190190

191-
def _get_groups(self) -> dict[str, GwEntityData]:
191+
def _get_groups(self) -> None:
192192
"""Helper-function for smile.py: get_all_gateway_entities().
193193
194194
Collect switching-, pumping- or report-group info.
195195
"""
196-
groups: dict[str, GwEntityData] = {}
197196
# P1 and Anna don't have groups
198197
if self.smile.type == "power" or self.check_name(ANNA):
199-
return groups
198+
return
200199

201200
for group in self._domain_objects.findall("./group"):
202201
members: list[str] = []
203-
group_id = group.attrib["id"]
202+
group_id = group.get("id")
204203
group_name = group.find("name").text
205204
group_type = group.find("type").text
206205
group_appliances = group.findall("appliances/appliance")
207206
for item in group_appliances:
208207
# Check if members are not orphaned - stretch
209-
if item.attrib["id"] in self.gw_entities:
210-
members.append(item.attrib["id"])
208+
if item.get("id") in self.gw_entities:
209+
members.append(item.get("id"))
211210

212-
if group_type in GROUP_TYPES and members:
213-
groups[group_id] = {
211+
if group_type in GROUP_TYPES and members and group_id:
212+
self.gw_entities[group_id] = {
214213
"dev_class": group_type,
215214
"model": "Group",
216215
"name": group_name,
@@ -219,8 +218,6 @@ def _get_groups(self) -> dict[str, GwEntityData]:
219218
}
220219
self._count += 5
221220

222-
return groups
223-
224221
def _get_lock_state(
225222
self, xml: etree.Element, data: GwEntityData, stretch_v2: bool = False
226223
) -> None:
@@ -266,7 +263,7 @@ def _get_module_data(
266263
if key is not None and key not in link_tag:
267264
continue
268265

269-
link_id = appl_search.attrib["id"]
266+
link_id = appl_search.get("id")
270267
loc = f".//services/{link_tag}[@id='{link_id}']...."
271268
# Not possible to walrus for some reason...
272269
# xml_2: self._modules for legacy, self._domain_objects for actual

plugwise/helper.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ def _get_appliances(self) -> None:
117117
for appliance in self._domain_objects.findall("./appliance"):
118118
appl = Munch()
119119
appl.available = None
120-
appl.entity_id = appliance.attrib["id"]
120+
appl.entity_id = appliance.get("id")
121121
appl.location = None
122122
appl.name = appliance.find("name").text
123123
appl.model = None
@@ -139,7 +139,7 @@ def _get_appliances(self) -> None:
139139
continue
140140

141141
if (appl_loc := appliance.find("location")) is not None:
142-
appl.location = appl_loc.attrib["id"]
142+
appl.location = appl_loc.get("id")
143143
# Set location to the _home_loc_id when the appliance-location is not found,
144144
# except for thermostat-devices without a location, they are not active
145145
elif appl.pwclass not in THERMOSTAT_CLASSES:
@@ -206,7 +206,7 @@ def _get_locations(self) -> None:
206206
loc = Munch()
207207
locations = self._domain_objects.findall("./location")
208208
for location in locations:
209-
loc.loc_id = location.attrib["id"]
209+
loc.loc_id = location.get("id")
210210
loc.name = location.find("name").text
211211
loc._type = location.find("type").text
212212
self._loc_data[loc.loc_id] = {
@@ -269,7 +269,7 @@ def _appliance_info_finder(self, appl: Munch, appliance: etree.Element) -> Munch
269269

270270
def _appl_gateway_info(self, appl: Munch, appliance: etree.Element) -> Munch:
271271
"""Helper-function for _appliance_info_finder()."""
272-
self._gateway_id = appliance.attrib["id"]
272+
self._gateway_id = appliance.get("id")
273273
appl.firmware = str(self.smile.version)
274274
appl.hardware = self.smile.hw_version
275275
appl.mac = self.smile.mac_address
@@ -319,7 +319,7 @@ def _get_appliances_with_offset_functionality(self) -> list[str]:
319319
'.//actuator_functionalities/offset_functionality[type="temperature_offset"]/offset/../../..'
320320
)
321321
for item in offset_appls:
322-
therm_list.append(item.attrib["id"])
322+
therm_list.append(item.get("id"))
323323

324324
return therm_list
325325

@@ -393,12 +393,12 @@ def _get_measurement_data(self, entity_id: str, entity: GwEntityData) -> None:
393393
def _collect_group_sensors(
394394
self,
395395
data: GwEntityData,
396-
entity_id: str,
396+
group_id: str,
397397
measurements: dict[str, UOM],
398398
) -> None:
399399
"""Collect group sensors."""
400400
if (
401-
group := self._domain_objects.find(f'./group[@id="{entity_id}"]')
401+
group := self._domain_objects.find(f'./group[@id="{group_id}"]')
402402
) is not None:
403403
for measurement, attrs in measurements.items():
404404
locator = f'.//logs/point_log[type="{measurement}"]/period/measurement'
@@ -502,7 +502,7 @@ def _get_plugwise_notifications(self) -> None:
502502
self._notifications = {}
503503
for notification in self._domain_objects.findall("./notification"):
504504
try:
505-
msg_id = notification.attrib["id"]
505+
msg_id = notification.get("id")
506506
msg_type = notification.find("type").text
507507
msg = notification.find("message").text
508508
self._notifications[msg_id] = {msg_type: msg}
@@ -903,7 +903,7 @@ def _presets(self, loc_id: str) -> dict[str, list[float]]:
903903
directives = self._domain_objects.find(f'rule[@id="{rule_id}"]/directives')
904904
for directive in directives:
905905
preset = directive.find("then").attrib
906-
presets[directive.attrib["preset"]] = [
906+
presets[directive.get("preset")] = [
907907
float(preset["heating_setpoint"]),
908908
float(preset["cooling_setpoint"]),
909909
]
@@ -920,13 +920,13 @@ def _rule_ids_by_name(self, name: str, loc_id: str) -> dict[str, dict[str, str]]
920920
for rule in self._domain_objects.findall(f'./rule[name="{name}"]'):
921921
active = rule.find("active").text
922922
if rule.find(locator) is not None:
923-
schedule_ids[rule.attrib["id"]] = {
923+
schedule_ids[rule.get("id")] = {
924924
"location": loc_id,
925925
"name": name,
926926
"active": active,
927927
}
928928
else:
929-
schedule_ids[rule.attrib["id"]] = {
929+
schedule_ids[rule.get("id")] = {
930930
"location": NONE,
931931
"name": name,
932932
"active": active,
@@ -947,13 +947,13 @@ def _rule_ids_by_tag(self, tag: str, loc_id: str) -> dict[str, dict[str, str]]:
947947
name = rule.find("name").text
948948
active = rule.find("active").text
949949
if rule.find(locator2) is not None:
950-
schedule_ids[rule.attrib["id"]] = {
950+
schedule_ids[rule.get("id")] = {
951951
"location": loc_id,
952952
"name": name,
953953
"active": active,
954954
}
955955
else:
956-
schedule_ids[rule.attrib["id"]] = {
956+
schedule_ids[rule.get("id")] = {
957957
"location": NONE,
958958
"name": name,
959959
"active": active,
@@ -1002,6 +1002,6 @@ def _thermostat_uri(self, loc_id: str) -> str:
10021002
Determine the location-set_temperature uri - from LOCATIONS.
10031003
"""
10041004
locator = f'./location[@id="{loc_id}"]/actuator_functionalities/thermostat_functionality'
1005-
thermostat_functionality_id = self._domain_objects.find(locator).attrib["id"]
1005+
thermostat_functionality_id = self._domain_objects.find(locator).get("id")
10061006

10071007
return f"{LOCATIONS};id={loc_id}/thermostat;id={thermostat_functionality_id}"

plugwise/legacy/helper.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ def _all_appliances(self) -> None:
107107
continue # pragma: no cover
108108

109109
appl.location = self._home_loc_id
110-
appl.entity_id = appliance.attrib["id"]
110+
appl.entity_id = appliance.get("id")
111111
appl.name = appliance.find("name").text
112112
# Extend device_class name when a Circle/Stealth is type heater_central -- Pw-Beta Issue #739
113113
if (
@@ -148,7 +148,7 @@ def _all_locations(self) -> None:
148148
return
149149

150150
for location in locations:
151-
loc.loc_id = location.attrib["id"]
151+
loc.loc_id = location.get("id")
152152
loc.name = location.find("name").text
153153
loc._type = location.find("type").text
154154
# Filter the valid single location for P1 legacy: services not empty
@@ -393,10 +393,14 @@ def _presets(self) -> dict[str, list[float]]:
393393
"""Helper-function for presets() - collect Presets for a legacy Anna."""
394394
presets: dict[str, list[float]] = {}
395395
for directive in self._domain_objects.findall("rule/directives/when/then"):
396-
if directive is not None and directive.get("icon") is not None:
396+
if (
397+
directive is not None
398+
and directive.get("icon") is not None
399+
and directive.get("temperature") is not None
400+
):
397401
# Ensure list of heating_setpoint, cooling_setpoint
398-
presets[directive.attrib["icon"]] = [
399-
float(directive.attrib["temperature"]),
402+
presets[directive.get("icon")] = [
403+
float(directive.get("temperature")),
400404
0,
401405
]
402406

@@ -411,7 +415,7 @@ def _schedules(self) -> tuple[list[str], str]:
411415
search = self._domain_objects
412416
if (result := search.find("./rule[name='Thermostat schedule']")) is not None:
413417
name = "Thermostat schedule"
414-
rule_id = result.attrib["id"]
418+
rule_id = result.get("id")
415419

416420
log_type = "schedule_state"
417421
locator = f"./appliance[type='thermostat']/logs/point_log[type='{log_type}']/period/measurement"
@@ -432,5 +436,5 @@ def _schedules(self) -> tuple[list[str], str]:
432436
def _thermostat_uri(self) -> str:
433437
"""Determine the location-set_temperature uri - from APPLIANCES."""
434438
locator = "./appliance[type='thermostat']"
435-
appliance_id = self._appliances.find(locator).attrib["id"]
439+
appliance_id = self._appliances.find(locator).get("id")
436440
return f"{APPLIANCES};id={appliance_id}/thermostat"

plugwise/legacy/smile.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,7 @@ def get_all_gateway_entities(self) -> None:
8282
Finally, collect the data and states for each entity.
8383
"""
8484
self._all_appliances()
85-
if group_data := self._get_groups():
86-
self.gw_entities.update(group_data)
87-
85+
self._get_groups()
8886
self._all_entity_data()
8987

9088
async def async_update(self) -> dict[str, GwEntityData]:
@@ -154,13 +152,17 @@ async def set_offset(self, dev_id: str, offset: float) -> None:
154152

155153
async def set_preset(self, _: str, preset: str) -> None:
156154
"""Set the given Preset on the relevant Thermostat - from DOMAIN_OBJECTS."""
157-
if (presets := self._presets()) is None:
155+
if not (presets := self._presets()):
158156
raise PlugwiseError("Plugwise: no presets available.") # pragma: no cover
159157
if preset not in list(presets):
160158
raise PlugwiseError("Plugwise: invalid preset.")
161159

162160
locator = f'rule/directives/when/then[@icon="{preset}"].../.../...'
163-
rule_id = self._domain_objects.find(locator).attrib["id"]
161+
if (rule := self._domain_objects.find(locator)) is None:
162+
raise PlugwiseError("Plugwise: no preset rule found.") # pragma: no cover
163+
if (rule_id := rule.get("id")) is None:
164+
raise PlugwiseError("Plugwise: no preset id found.") # pragma: no cover
165+
164166
data = f"<rules><rule id='{rule_id}'><active>true</active></rule></rules>"
165167
await self.call_request(RULES, method="put", data=data)
166168

@@ -192,7 +194,7 @@ async def set_schedule_state(
192194
schedule_rule_id: str | None = None
193195
for rule in self._domain_objects.findall("rule"):
194196
if rule.find("name").text == name:
195-
schedule_rule_id = rule.attrib["id"]
197+
schedule_rule_id = rule.get("id")
196198
break
197199

198200
if schedule_rule_id is None:
@@ -205,7 +207,7 @@ async def set_schedule_state(
205207
new_state = "true"
206208

207209
locator = f'.//*[@id="{schedule_rule_id}"]/template'
208-
template_id = self._domain_objects.find(locator).attrib["id"]
210+
template_id = self._domain_objects.find(locator).get("id")
209211

210212
data = (
211213
"<rules>"

plugwise/smile.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,7 @@ def get_all_gateway_entities(self) -> None:
113113
)
114114
self._scan_thermostats()
115115

116-
if group_data := self._get_groups():
117-
self.gw_entities.update(group_data)
118-
116+
self._get_groups()
119117
self._all_entity_data()
120118

121119
async def async_update(self) -> dict[str, GwEntityData]:
@@ -178,7 +176,7 @@ async def set_number(
178176
if th_func_list := self._domain_objects.findall(locator):
179177
for th_func in th_func_list:
180178
if th_func.find("type").text == key:
181-
thermostat_id = th_func.attrib["id"]
179+
thermostat_id = th_func.get("id")
182180

183181
if thermostat_id is None:
184182
raise PlugwiseError(f"Plugwise: cannot change setpoint, {key} not found.")
@@ -358,7 +356,7 @@ async def set_schedule_state(
358356
)
359357
if self.check_name(ANNA):
360358
locator = f'.//*[@id="{schedule_rule_id}"]/template'
361-
template_id = self._domain_objects.find(locator).attrib["id"]
359+
template_id = self._domain_objects.find(locator).get("id")
362360
template = f'<template id="{template_id}" />'
363361

364362
contexts = self.determine_contexts(loc_id, new_state, schedule_rule_id)
@@ -427,10 +425,10 @@ async def set_switch_state(
427425
# multiple types of e.g. toggle_functionality present
428426
if (sw_type := item.find("type")) is not None:
429427
if sw_type.text == switch.act_type:
430-
switch_id = item.attrib["id"]
428+
switch_id = item.get("id")
431429
break
432430
else: # actuators with a single item like relay_functionality
433-
switch_id = item.attrib["id"]
431+
switch_id = item.get("id")
434432

435433
uri = f"{APPLIANCES};id={appl_id}/{switch.device};id={switch_id}"
436434
if model == "relay":
@@ -456,7 +454,7 @@ async def _set_groupswitch_member_state(
456454
switched = 0
457455
for member in members:
458456
locator = f'appliance[@id="{member}"]/{switch.actuator}/{switch.func_type}'
459-
switch_id = self._domain_objects.find(locator).attrib["id"]
457+
switch_id = self._domain_objects.find(locator).get("id")
460458
uri = f"{APPLIANCES};id={member}/{switch.device};id={switch_id}"
461459
lock_blocked = self.gw_entities[member]["switches"].get("lock")
462460
# Assume Plugs under Plugwise control are not part of a group

plugwise/util.py

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -82,30 +82,33 @@ def check_heater_central(xml: etree.Element) -> str:
8282
for a system that has two heater_central appliances.
8383
"""
8484
locator = "./appliance[type='heater_central']"
85-
hc_count = 0
86-
hc_list: list[dict[str, bool]] = []
85+
heater_central_count = 0
86+
heater_central_list: list[dict[str, bool]] = []
8787
for heater_central in xml.findall(locator):
88-
hc_count += 1
89-
hc_id: str = heater_central.attrib["id"]
90-
has_actuators: bool = (
91-
heater_central.find("actuator_functionalities/") is not None
92-
)
88+
if (heater_central_id := heater_central.get("id")) is None:
89+
continue # pragma: no cover
90+
91+
if (heater_central_name := heater_central.find("name")) is None:
92+
continue # pragma: no cover
93+
94+
has_actuators = heater_central.find("actuator_functionalities/") is not None
9395
# Filter for Plug/Circle/Stealth heater_central -- Pw-Beta Issue #739
94-
if heater_central.find("name").text == "Central heating boiler":
95-
hc_list.append({hc_id: has_actuators})
96+
if heater_central_name.text == "Central heating boiler":
97+
heater_central_list.append({heater_central_id: has_actuators})
98+
heater_central_count += 1
9699

97-
if not hc_list:
100+
if not heater_central_list:
98101
return NONE # pragma: no cover
99102

100-
heater_central_id = list(hc_list[0].keys())[0]
101-
if hc_count > 1:
102-
for item in hc_list:
103-
hc_id, has_actuators = next(iter(item.items()))
103+
heater_id = list(heater_central_list[0].keys())[0]
104+
if heater_central_count > 1:
105+
for item in heater_central_list:
106+
heater_central_id, has_actuators = next(iter(item.items()))
104107
if has_actuators:
105-
heater_central_id = hc_id
108+
heater_id = heater_central_id
106109
break
107110

108-
return heater_central_id
111+
return heater_id
109112

110113

111114
def check_model(name: str | None, vendor_name: str | None) -> str | None:

0 commit comments

Comments
 (0)