plugwise 1.7.2__tar.gz → 1.7.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. {plugwise-1.7.2 → plugwise-1.7.3}/PKG-INFO +4 -3
  2. {plugwise-1.7.2 → plugwise-1.7.3}/README.md +3 -2
  3. {plugwise-1.7.2 → plugwise-1.7.3}/plugwise/__init__.py +12 -19
  4. {plugwise-1.7.2 → plugwise-1.7.3}/plugwise/common.py +19 -9
  5. {plugwise-1.7.2 → plugwise-1.7.3}/plugwise/constants.py +0 -11
  6. {plugwise-1.7.2 → plugwise-1.7.3}/plugwise/data.py +10 -21
  7. {plugwise-1.7.2 → plugwise-1.7.3}/plugwise/helper.py +29 -18
  8. {plugwise-1.7.2 → plugwise-1.7.3}/plugwise/legacy/data.py +2 -12
  9. {plugwise-1.7.2 → plugwise-1.7.3}/plugwise/legacy/helper.py +28 -15
  10. {plugwise-1.7.2 → plugwise-1.7.3}/plugwise/legacy/smile.py +36 -31
  11. {plugwise-1.7.2 → plugwise-1.7.3}/plugwise/smile.py +71 -40
  12. {plugwise-1.7.2 → plugwise-1.7.3}/plugwise/smilecomm.py +4 -2
  13. {plugwise-1.7.2 → plugwise-1.7.3}/plugwise/util.py +26 -35
  14. {plugwise-1.7.2 → plugwise-1.7.3}/plugwise.egg-info/PKG-INFO +4 -3
  15. {plugwise-1.7.2 → plugwise-1.7.3}/pyproject.toml +1 -8
  16. {plugwise-1.7.2 → plugwise-1.7.3}/LICENSE +0 -0
  17. {plugwise-1.7.2 → plugwise-1.7.3}/plugwise/exceptions.py +0 -0
  18. {plugwise-1.7.2 → plugwise-1.7.3}/plugwise/py.typed +0 -0
  19. {plugwise-1.7.2 → plugwise-1.7.3}/plugwise.egg-info/SOURCES.txt +0 -0
  20. {plugwise-1.7.2 → plugwise-1.7.3}/plugwise.egg-info/dependency_links.txt +0 -0
  21. {plugwise-1.7.2 → plugwise-1.7.3}/plugwise.egg-info/requires.txt +0 -0
  22. {plugwise-1.7.2 → plugwise-1.7.3}/plugwise.egg-info/top_level.txt +0 -0
  23. {plugwise-1.7.2 → plugwise-1.7.3}/setup.cfg +0 -0
  24. {plugwise-1.7.2 → plugwise-1.7.3}/setup.py +0 -0
  25. {plugwise-1.7.2 → plugwise-1.7.3}/tests/test_adam.py +0 -0
  26. {plugwise-1.7.2 → plugwise-1.7.3}/tests/test_anna.py +0 -0
  27. {plugwise-1.7.2 → plugwise-1.7.3}/tests/test_generic.py +0 -0
  28. {plugwise-1.7.2 → plugwise-1.7.3}/tests/test_init.py +0 -0
  29. {plugwise-1.7.2 → plugwise-1.7.3}/tests/test_legacy_anna.py +0 -0
  30. {plugwise-1.7.2 → plugwise-1.7.3}/tests/test_legacy_generic.py +0 -0
  31. {plugwise-1.7.2 → plugwise-1.7.3}/tests/test_legacy_p1.py +0 -0
  32. {plugwise-1.7.2 → plugwise-1.7.3}/tests/test_legacy_stretch.py +0 -0
  33. {plugwise-1.7.2 → plugwise-1.7.3}/tests/test_p1.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: plugwise
3
- Version: 1.7.2
3
+ Version: 1.7.3
4
4
  Summary: Plugwise Smile (Adam/Anna/P1) and Stretch module for Python 3.
5
5
  Home-page: https://github.com/plugwise/python-plugwise
6
6
  Author: Plugwise device owners
@@ -48,12 +48,13 @@ Requires-Dist: python-dateutil
48
48
 
49
49
  # Plugwise python module
50
50
 
51
- This module is the backend for the [`plugwise` component](https://github.com/home-assistant/core/tree/dev/homeassistant/components/plugwise) in Home Assistant Core (which we maintain as co-code owners).
51
+ This module is the backend for the [`plugwise` component](https://github.com/home-assistant/core/tree/dev/homeassistant/components/plugwise) in Home Assistant Core (which we maintain as code owners).
52
52
 
53
- This module supports `Smile`s (and `Stretch`), i.e. the networked plugwise devices. For the USB (or Stick-standalone version) please refer to upcoming [`plugwise-usb` component](https://github.com/plugwise/plugwise_usb-beta).
53
+ This module supports Hubs such as `Adam`, `Smile`s for Anna and P1 and `Stretch`, i.e. the networked plugwise devices. For the USB (or Stick-standalone version) please refer to upcoming [`plugwise-usb` component](https://github.com/plugwise/plugwise_usb-beta).
54
54
 
55
55
  Our main usage for this module is supporting [Home Assistant](https://www.home-assistant.io) / [home-assistant](http://github.com/home-assistant/core/)
56
56
 
57
+ ![Static Badge](https://img.shields.io/badge/Plugwise_Discord-Join_now-purple?style=social&logo=discord&link=https%3A%2F%2Fdiscord.gg%2FmFVhF8Ar6A)
57
58
  [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/plugwise)
58
59
  [![CodeRabbit.ai is Awesome](https://img.shields.io/badge/AI-orange?label=CodeRabbit&color=orange&link=https%3A%2F%2Fcoderabbit.ai)](https://coderabbit.ai)
59
60
  [![renovate maintained](https://img.shields.io/badge/maintained%20with-renovate-blue?logo=renovatebot)](https://github.com/plugwise/python-plugwise/issues/291)
@@ -1,11 +1,12 @@
1
1
  # Plugwise python module
2
2
 
3
- This module is the backend for the [`plugwise` component](https://github.com/home-assistant/core/tree/dev/homeassistant/components/plugwise) in Home Assistant Core (which we maintain as co-code owners).
3
+ This module is the backend for the [`plugwise` component](https://github.com/home-assistant/core/tree/dev/homeassistant/components/plugwise) in Home Assistant Core (which we maintain as code owners).
4
4
 
5
- This module supports `Smile`s (and `Stretch`), i.e. the networked plugwise devices. For the USB (or Stick-standalone version) please refer to upcoming [`plugwise-usb` component](https://github.com/plugwise/plugwise_usb-beta).
5
+ This module supports Hubs such as `Adam`, `Smile`s for Anna and P1 and `Stretch`, i.e. the networked plugwise devices. For the USB (or Stick-standalone version) please refer to upcoming [`plugwise-usb` component](https://github.com/plugwise/plugwise_usb-beta).
6
6
 
7
7
  Our main usage for this module is supporting [Home Assistant](https://www.home-assistant.io) / [home-assistant](http://github.com/home-assistant/core/)
8
8
 
9
+ ![Static Badge](https://img.shields.io/badge/Plugwise_Discord-Join_now-purple?style=social&logo=discord&link=https%3A%2F%2Fdiscord.gg%2FmFVhF8Ar6A)
9
10
  [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/plugwise)
10
11
  [![CodeRabbit.ai is Awesome](https://img.shields.io/badge/AI-orange?label=CodeRabbit&color=orange&link=https%3A%2F%2Fcoderabbit.ai)](https://coderabbit.ai)
11
12
  [![renovate maintained](https://img.shields.io/badge/maintained%20with-renovate-blue?logo=renovatebot)](https://github.com/plugwise/python-plugwise/issues/291)
@@ -18,7 +18,6 @@ from plugwise.constants import (
18
18
  STATUS,
19
19
  SYSTEM,
20
20
  GwEntityData,
21
- SmileProps,
22
21
  ThermoLoc,
23
22
  )
24
23
  from plugwise.exceptions import (
@@ -69,7 +68,6 @@ class Smile(SmileComm):
69
68
  self._opentherm_device = False
70
69
  self._schedule_old_states: dict[str, dict[str, str]] = {}
71
70
  self._smile_api: SmileAPI | SmileLegacyAPI
72
- self._smile_props: SmileProps = {}
73
71
  self._stretch_v2 = False
74
72
  self._target_smile: str = NONE
75
73
  self.smile_hostname: str = NONE
@@ -86,26 +84,22 @@ class Smile(SmileComm):
86
84
  @property
87
85
  def cooling_present(self) -> bool:
88
86
  """Return the cooling capability."""
89
- if "cooling_present" in self._smile_props:
90
- return self._smile_props["cooling_present"]
91
- return False
87
+ return self._smile_api.cooling_present
92
88
 
93
89
  @property
94
90
  def gateway_id(self) -> str:
95
91
  """Return the gateway-id."""
96
- return self._smile_props["gateway_id"]
92
+ return self._smile_api.gateway_id
97
93
 
98
94
  @property
99
95
  def heater_id(self) -> str:
100
96
  """Return the heater-id."""
101
- if "heater_id" in self._smile_props:
102
- return self._smile_props["heater_id"]
103
- return NONE
97
+ return self._smile_api.heater_id
104
98
 
105
99
  @property
106
100
  def item_count(self) -> int:
107
101
  """Return the item-count."""
108
- return self._smile_props["item_count"]
102
+ return self._smile_api.item_count
109
103
 
110
104
  @property
111
105
  def reboot(self) -> bool:
@@ -162,7 +156,6 @@ class Smile(SmileComm):
162
156
  self._opentherm_device,
163
157
  self._request,
164
158
  self._schedule_old_states,
165
- self._smile_props,
166
159
  self.smile_hostname,
167
160
  self.smile_hw_version,
168
161
  self.smile_mac_address,
@@ -179,7 +172,6 @@ class Smile(SmileComm):
179
172
  self._on_off_device,
180
173
  self._opentherm_device,
181
174
  self._request,
182
- self._smile_props,
183
175
  self._stretch_v2,
184
176
  self._target_smile,
185
177
  self.smile_hostname,
@@ -198,7 +190,9 @@ class Smile(SmileComm):
198
190
 
199
191
  return self.smile_version
200
192
 
201
- async def _smile_detect(self, result: etree, dsmrmain: etree) -> None:
193
+ async def _smile_detect(
194
+ self, result: etree.Element, dsmrmain: etree.Element
195
+ ) -> None:
202
196
  """Helper-function for connect().
203
197
 
204
198
  Detect which type of Plugwise Gateway is being connected.
@@ -256,10 +250,8 @@ class Smile(SmileComm):
256
250
  # For Adam, Anna, determine the system capabilities:
257
251
  # Find the connected heating/cooling device (heater_central),
258
252
  # e.g. heat-pump or gas-fired heater
259
- onoff_boiler: etree = result.find("./module/protocols/onoff_boiler")
260
- open_therm_boiler: etree = result.find(
261
- "./module/protocols/open_therm_boiler"
262
- )
253
+ onoff_boiler = result.find("./module/protocols/onoff_boiler")
254
+ open_therm_boiler = result.find("./module/protocols/open_therm_boiler")
263
255
  self._on_off_device = onoff_boiler is not None
264
256
  self._opentherm_device = open_therm_boiler is not None
265
257
 
@@ -272,7 +264,7 @@ class Smile(SmileComm):
272
264
  self._elga = True
273
265
 
274
266
  async def _smile_detect_legacy(
275
- self, result: etree, dsmrmain: etree, model: str
267
+ self, result: etree.Element, dsmrmain: etree.Element, model: str
276
268
  ) -> str:
277
269
  """Helper-function for _smile_detect().
278
270
 
@@ -298,11 +290,12 @@ class Smile(SmileComm):
298
290
  self.smile_version = parse(system.find("./gateway/firmware").text)
299
291
  return_model = str(system.find("./gateway/product").text)
300
292
  self.smile_hostname = system.find("./gateway/hostname").text
301
- # If wlan0 contains data it's active, so eth0 should be checked last
293
+ # If wlan0 contains data it's active, eth0 should be checked last as is preferred
302
294
  for network in ("wlan0", "eth0"):
303
295
  locator = f"./{network}/mac"
304
296
  if (net_locator := system.find(locator)) is not None:
305
297
  self.smile_mac_address = net_locator.text
298
+
306
299
  # P1 legacy:
307
300
  elif dsmrmain is not None:
308
301
  status = await self._request(STATUS)
@@ -27,7 +27,9 @@ from defusedxml import ElementTree as etree
27
27
  from munch import Munch
28
28
 
29
29
 
30
- def get_zigbee_data(module: etree, module_data: ModuleData, legacy: bool) -> None:
30
+ def get_zigbee_data(
31
+ module: etree.Element, module_data: ModuleData, legacy: bool
32
+ ) -> None:
31
33
  """Helper-function for _get_module_data()."""
32
34
  if legacy:
33
35
  # Stretches
@@ -49,13 +51,18 @@ class SmileCommon:
49
51
  """Init."""
50
52
  self._cooling_present: bool
51
53
  self._count: int
52
- self._domain_objects: etree
54
+ self._domain_objects: etree.Element
53
55
  self._heater_id: str = NONE
54
56
  self._on_off_device: bool
55
57
  self.gw_entities: dict[str, GwEntityData] = {}
56
58
  self.smile_name: str
57
59
  self.smile_type: str
58
60
 
61
+ @property
62
+ def heater_id(self) -> str:
63
+ """Return the heater-id."""
64
+ return self._heater_id
65
+
59
66
  def smile(self, name: str) -> bool:
60
67
  """Helper-function checking the smile-name."""
61
68
  return self.smile_name == name
@@ -63,10 +70,10 @@ class SmileCommon:
63
70
  def _appl_heater_central_info(
64
71
  self,
65
72
  appl: Munch,
66
- xml_1: etree,
73
+ xml_1: etree.Element,
67
74
  legacy: bool,
68
- xml_2: etree = None,
69
- xml_3: etree = None,
75
+ xml_2: etree.Element = None,
76
+ xml_3: etree.Element = None,
70
77
  ) -> Munch:
71
78
  """Helper-function for _appliance_info_finder()."""
72
79
  # Find the valid heater_central
@@ -74,6 +81,9 @@ class SmileCommon:
74
81
  xml_2 = return_valid(xml_2, self._domain_objects)
75
82
  self._heater_id = check_heater_central(xml_2)
76
83
 
84
+ if self._heater_id == NONE:
85
+ return Munch() # pragma: no cover
86
+
77
87
  # Info for On-Off device
78
88
  if self._on_off_device:
79
89
  appl.name = "OnOff" # pragma: no cover
@@ -101,7 +111,7 @@ class SmileCommon:
101
111
  return appl
102
112
 
103
113
  def _appl_thermostat_info(
104
- self, appl: Munch, xml_1: etree, xml_2: etree = None
114
+ self, appl: Munch, xml_1: etree.Element, xml_2: etree.Element = None
105
115
  ) -> Munch:
106
116
  """Helper-function for _appliance_info_finder()."""
107
117
  locator = "./logs/point_log[type='thermostat']/thermostat"
@@ -190,7 +200,7 @@ class SmileCommon:
190
200
  return switch_groups
191
201
 
192
202
  def _get_lock_state(
193
- self, xml: etree, data: GwEntityData, stretch_v2: bool = False
203
+ self, xml: etree.Element, data: GwEntityData, stretch_v2: bool = False
194
204
  ) -> None:
195
205
  """Helper-function for _get_measurement_data().
196
206
 
@@ -209,9 +219,9 @@ class SmileCommon:
209
219
 
210
220
  def _get_module_data(
211
221
  self,
212
- xml_1: etree,
222
+ xml_1: etree.Element,
213
223
  locator: str,
214
- xml_2: etree = None,
224
+ xml_2: etree.Element = None,
215
225
  legacy: bool = False,
216
226
  ) -> ModuleData:
217
227
  """Helper-function for _energy_device_info_finder() and _appliance_info_finder().
@@ -393,17 +393,6 @@ ZONE_THERMOSTATS: Final[tuple[str, ...]] = (
393
393
  )
394
394
 
395
395
 
396
- class SmileProps(TypedDict, total=False):
397
- """The SmileProps Data class."""
398
-
399
- cooling_present: bool
400
- gateway_id: str
401
- heater_id: str
402
- item_count: int
403
- reboot: bool
404
- smile_name: str
405
-
406
-
407
396
  class ModuleData(TypedDict):
408
397
  """The Module data class."""
409
398
 
@@ -16,7 +16,6 @@ from plugwise.constants import (
16
16
  OFF,
17
17
  ActuatorData,
18
18
  GwEntityData,
19
- SmileProps,
20
19
  )
21
20
  from plugwise.helper import SmileHelper
22
21
  from plugwise.util import remove_empty_platform_dicts
@@ -27,28 +26,19 @@ class SmileData(SmileHelper):
27
26
 
28
27
  def __init__(self) -> None:
29
28
  """Init."""
30
- self._smile_props: SmileProps
29
+ super().__init__()
31
30
  self._zones: dict[str, GwEntityData] = {}
32
- SmileHelper.__init__(self)
33
31
 
34
32
  def _all_entity_data(self) -> None:
35
33
  """Helper-function for get_all_gateway_entities().
36
34
 
37
- Collect data for each entity and add to self._smile_props and self.gw_entities.
35
+ Collect data for each entity and add to self.gw_entities.
38
36
  """
39
37
  self._update_gw_entities()
40
38
  if self.smile(ADAM):
41
39
  self._update_zones()
42
40
  self.gw_entities.update(self._zones)
43
41
 
44
- self._smile_props["gateway_id"] = self._gateway_id
45
- self._smile_props["item_count"] = self._count
46
- self._smile_props["reboot"] = True
47
- self._smile_props["smile_name"] = self.smile_name
48
- if self._is_thermostat:
49
- self._smile_props["heater_id"] = self._heater_id
50
- self._smile_props["cooling_present"] = self._cooling_present
51
-
52
42
  def _update_zones(self) -> None:
53
43
  """Helper-function for _all_entity_data() and async_update().
54
44
 
@@ -228,6 +218,7 @@ class SmileData(SmileHelper):
228
218
  for msg in item.values():
229
219
  if message in msg:
230
220
  data["available"] = False
221
+ break
231
222
 
232
223
  def _get_adam_data(self, entity: GwEntityData, data: GwEntityData) -> None:
233
224
  """Helper-function for _get_entity_data().
@@ -329,16 +320,14 @@ class SmileData(SmileHelper):
329
320
 
330
321
  Also, replace NONE by OFF when none of the schedules are active.
331
322
  """
332
- loc_schedule_states: dict[str, str] = {}
333
- for schedule in schedules:
334
- loc_schedule_states[schedule] = "off"
335
- if schedule == selected and data["climate_mode"] == "auto":
336
- loc_schedule_states[schedule] = "on"
337
- self._schedule_old_states[location] = loc_schedule_states
338
-
339
323
  all_off = True
340
- for state in self._schedule_old_states[location].values():
341
- if state == "on":
324
+ self._schedule_old_states[location] = {}
325
+ for schedule in schedules:
326
+ active: bool = schedule == selected and data["climate_mode"] == "auto"
327
+ self._schedule_old_states[location][schedule] = "off"
328
+ if active:
329
+ self._schedule_old_states[location][schedule] = "on"
342
330
  all_off = False
331
+
343
332
  if all_off:
344
333
  data["select_schedule"] = OFF
@@ -59,7 +59,9 @@ from munch import Munch
59
59
  from packaging import version
60
60
 
61
61
 
62
- def search_actuator_functionalities(appliance: etree, actuator: str) -> etree | None:
62
+ def search_actuator_functionalities(
63
+ appliance: etree.Element, actuator: str
64
+ ) -> etree.Element | None:
63
65
  """Helper-function for finding the relevant actuator xml-structure."""
64
66
  locator = f"./actuator_functionalities/{actuator}"
65
67
  if (search := appliance.find(locator)) is not None:
@@ -73,6 +75,7 @@ class SmileHelper(SmileCommon):
73
75
 
74
76
  def __init__(self) -> None:
75
77
  """Set the constructor for this class."""
78
+ super().__init__()
76
79
  self._endpoint: str
77
80
  self._elga: bool
78
81
  self._is_thermostat: bool
@@ -87,7 +90,16 @@ class SmileHelper(SmileCommon):
87
90
  self.smile_model: str
88
91
  self.smile_model_id: str | None
89
92
  self.smile_version: version.Version
90
- SmileCommon.__init__(self)
93
+
94
+ @property
95
+ def gateway_id(self) -> str:
96
+ """Return the gateway-id."""
97
+ return self._gateway_id
98
+
99
+ @property
100
+ def item_count(self) -> int:
101
+ """Return the item-count."""
102
+ return self._count
91
103
 
92
104
  def _all_appliances(self) -> None:
93
105
  """Collect all appliances with relevant info.
@@ -195,6 +207,7 @@ class SmileHelper(SmileCommon):
195
207
  other_entities = self.gw_entities
196
208
  priority_entities = {entity_id: priority_entity}
197
209
  self.gw_entities = {**priority_entities, **other_entities}
210
+ break
198
211
 
199
212
  def _all_locations(self) -> None:
200
213
  """Collect all locations."""
@@ -212,7 +225,7 @@ class SmileHelper(SmileCommon):
212
225
  f"./location[@id='{loc.loc_id}']"
213
226
  )
214
227
 
215
- def _appliance_info_finder(self, appl: Munch, appliance: etree) -> Munch:
228
+ def _appliance_info_finder(self, appl: Munch, appliance: etree.Element) -> Munch:
216
229
  """Collect info for all appliances found."""
217
230
  match appl.pwclass:
218
231
  case "gateway":
@@ -230,7 +243,7 @@ class SmileHelper(SmileCommon):
230
243
  appliance, "domestic_hot_water_mode_control_functionality"
231
244
  )
232
245
  # Skip orphaned heater_central (Core Issue #104433)
233
- if appl.entity_id != self._heater_id:
246
+ if appl.entity_id != self.heater_id:
234
247
  return Munch()
235
248
  return appl
236
249
  case _ as s if s.endswith("_plug"):
@@ -250,9 +263,9 @@ class SmileHelper(SmileCommon):
250
263
  appl.zigbee_mac = module_data["zigbee_mac_address"]
251
264
  return appl
252
265
  case _: # pragma: no cover
253
- return appl
266
+ return Munch()
254
267
 
255
- def _appl_gateway_info(self, appl: Munch, appliance: etree) -> Munch:
268
+ def _appl_gateway_info(self, appl: Munch, appliance: etree.Element) -> Munch:
256
269
  """Helper-function for _appliance_info_finder()."""
257
270
  self._gateway_id = appliance.attrib["id"]
258
271
  appl.firmware = str(self.smile_version)
@@ -285,7 +298,7 @@ class SmileHelper(SmileCommon):
285
298
  return appl
286
299
 
287
300
  def _get_appl_actuator_modes(
288
- self, appliance: etree, actuator_type: str
301
+ self, appliance: etree.Element, actuator_type: str
289
302
  ) -> list[str]:
290
303
  """Get allowed modes for the given actuator type."""
291
304
  mode_list: list[str] = []
@@ -341,7 +354,7 @@ class SmileHelper(SmileCommon):
341
354
 
342
355
  # Get non-P1 data from APPLIANCES
343
356
  measurements = DEVICE_MEASUREMENTS
344
- if self._is_thermostat and entity_id == self._heater_id:
357
+ if self._is_thermostat and entity_id == self.heater_id:
345
358
  measurements = HEATER_CENTRAL_MEASUREMENTS
346
359
  # Show the allowed dhw_modes (Loria only)
347
360
  if self._dhw_allowed_modes:
@@ -397,7 +410,7 @@ class SmileHelper(SmileCommon):
397
410
 
398
411
  def _appliance_measurements(
399
412
  self,
400
- appliance: etree,
413
+ appliance: etree.Element,
401
414
  data: GwEntityData,
402
415
  measurements: dict[str, DATA | UOM],
403
416
  ) -> None:
@@ -429,7 +442,7 @@ class SmileHelper(SmileCommon):
429
442
  self._count = count_data_items(self._count, data)
430
443
 
431
444
  def _get_toggle_state(
432
- self, xml: etree, toggle: str, name: ToggleNameType, data: GwEntityData
445
+ self, xml: etree.Element, toggle: str, name: ToggleNameType, data: GwEntityData
433
446
  ) -> None:
434
447
  """Helper-function for _get_measurement_data().
435
448
 
@@ -458,7 +471,7 @@ class SmileHelper(SmileCommon):
458
471
  )
459
472
 
460
473
  def _get_actuator_functionalities(
461
- self, xml: etree, entity: GwEntityData, data: GwEntityData
474
+ self, xml: etree.Element, entity: GwEntityData, data: GwEntityData
462
475
  ) -> None:
463
476
  """Get and process the actuator_functionalities details for an entity.
464
477
 
@@ -520,7 +533,7 @@ class SmileHelper(SmileCommon):
520
533
  data[act_item] = temp_dict
521
534
 
522
535
  def _get_actuator_mode(
523
- self, appliance: etree, entity_id: str, key: str
536
+ self, appliance: etree.Element, entity_id: str, key: str
524
537
  ) -> str | None:
525
538
  """Helper-function for _get_regulation_mode and _get_gateway_mode.
526
539
 
@@ -535,7 +548,7 @@ class SmileHelper(SmileCommon):
535
548
  return None
536
549
 
537
550
  def _get_regulation_mode(
538
- self, appliance: etree, entity_id: str, data: GwEntityData
551
+ self, appliance: etree.Element, entity_id: str, data: GwEntityData
539
552
  ) -> None:
540
553
  """Helper-function for _get_measurement_data().
541
554
 
@@ -551,7 +564,7 @@ class SmileHelper(SmileCommon):
551
564
  self._cooling_enabled = mode == "cooling"
552
565
 
553
566
  def _get_gateway_mode(
554
- self, appliance: etree, entity_id: str, data: GwEntityData
567
+ self, appliance: etree.Element, entity_id: str, data: GwEntityData
555
568
  ) -> None:
556
569
  """Helper-function for _get_measurement_data().
557
570
 
@@ -616,7 +629,7 @@ class SmileHelper(SmileCommon):
616
629
 
617
630
  Support added for Techneco Elga and Thercon Loria/Thermastage.
618
631
  """
619
- if entity_id != self._heater_id:
632
+ if entity_id != self.heater_id:
620
633
  return
621
634
 
622
635
  if "elga_status_code" in data:
@@ -837,9 +850,7 @@ class SmileHelper(SmileCommon):
837
850
  return presets # pragma: no cover
838
851
 
839
852
  for rule_id in rule_ids:
840
- directives: etree = self._domain_objects.find(
841
- f'rule[@id="{rule_id}"]/directives'
842
- )
853
+ directives = self._domain_objects.find(f'rule[@id="{rule_id}"]/directives')
843
854
  for directive in directives:
844
855
  preset = directive.find("then").attrib
845
856
  presets[directive.attrib["preset"]] = [
@@ -7,7 +7,7 @@ from __future__ import annotations
7
7
 
8
8
  # Dict as class
9
9
  # Version detection
10
- from plugwise.constants import NONE, OFF, GwEntityData, SmileProps
10
+ from plugwise.constants import NONE, OFF, GwEntityData
11
11
  from plugwise.legacy.helper import SmileLegacyHelper
12
12
  from plugwise.util import remove_empty_platform_dicts
13
13
 
@@ -15,22 +15,12 @@ from plugwise.util import remove_empty_platform_dicts
15
15
  class SmileLegacyData(SmileLegacyHelper):
16
16
  """The Plugwise Smile main class."""
17
17
 
18
- def __init__(self) -> None:
19
- """Init."""
20
- self._smile_props: SmileProps
21
- SmileLegacyHelper.__init__(self)
22
-
23
18
  def _all_entity_data(self) -> None:
24
19
  """Helper-function for get_all_gateway_entities().
25
20
 
26
- Collect data for each entity and add to self._smile_props and self.gw_entities.
21
+ Collect data for each entity and add to self.gw_entities.
27
22
  """
28
23
  self._update_gw_entities()
29
- self._smile_props["gateway_id"] = self.gateway_id
30
- self._smile_props["item_count"] = self._count
31
- self._smile_props["smile_name"] = self.smile_name
32
- if self._is_thermostat:
33
- self._smile_props["heater_id"] = self._heater_id
34
24
 
35
25
  def _update_gw_entities(self) -> None:
36
26
  """Helper-function for _all_entity_data() and async_update().
@@ -23,6 +23,7 @@ from plugwise.constants import (
23
23
  NONE,
24
24
  OFF,
25
25
  P1_LEGACY_MEASUREMENTS,
26
+ PRIORITY_DEVICE_CLASSES,
26
27
  TEMP_CELSIUS,
27
28
  THERMOSTAT_CLASSES,
28
29
  UOM,
@@ -49,7 +50,7 @@ from munch import Munch
49
50
  from packaging.version import Version
50
51
 
51
52
 
52
- def etree_to_dict(element: etree) -> dict[str, str]:
53
+ def etree_to_dict(element: etree.Element) -> dict[str, str]:
53
54
  """Helper-function translating xml Element to dict."""
54
55
  node: dict[str, str] = {}
55
56
  if element is not None:
@@ -63,18 +64,29 @@ class SmileLegacyHelper(SmileCommon):
63
64
 
64
65
  def __init__(self) -> None:
65
66
  """Set the constructor for this class."""
66
- self._appliances: etree
67
+ super().__init__()
68
+ self._appliances: etree.Element
69
+ self._gateway_id: str = NONE
67
70
  self._is_thermostat: bool
68
71
  self._loc_data: dict[str, ThermoLoc]
69
- self._locations: etree
70
- self._modules: etree
72
+ self._locations: etree.Element
73
+ self._modules: etree.Element
71
74
  self._stretch_v2: bool
72
75
  self.gw_entities: dict[str, GwEntityData] = {}
73
76
  self.smile_mac_address: str | None
74
77
  self.smile_model: str
75
78
  self.smile_version: Version
76
79
  self.smile_zigbee_mac_address: str | None
77
- SmileCommon.__init__(self)
80
+
81
+ @property
82
+ def gateway_id(self) -> str:
83
+ """Return the gateway-id."""
84
+ return self._gateway_id
85
+
86
+ @property
87
+ def item_count(self) -> int:
88
+ """Return the item-count."""
89
+ return self._count
78
90
 
79
91
  def _all_appliances(self) -> None:
80
92
  """Collect all appliances with relevant info."""
@@ -124,13 +136,13 @@ class SmileLegacyHelper(SmileCommon):
124
136
  continue
125
137
 
126
138
  # Skip orphaned heater_central (Core Issue #104433)
127
- if appl.pwclass == "heater_central" and appl.entity_id != self._heater_id:
139
+ if appl.pwclass == "heater_central" and appl.entity_id != self.heater_id:
128
140
  continue # pragma: no cover
129
141
 
130
142
  self._create_gw_entities(appl)
131
143
 
132
144
  # Place the gateway and optional heater_central devices as 1st and 2nd
133
- for dev_class in ("heater_central", "gateway"):
145
+ for dev_class in PRIORITY_DEVICE_CLASSES:
134
146
  for entity_id, entity in dict(self.gw_entities).items():
135
147
  if entity["dev_class"] == dev_class:
136
148
  tmp_entity = entity
@@ -138,6 +150,7 @@ class SmileLegacyHelper(SmileCommon):
138
150
  cleared_dict = self.gw_entities
139
151
  add_to_front = {entity_id: tmp_entity}
140
152
  self.gw_entities = {**add_to_front, **cleared_dict}
153
+ break
141
154
 
142
155
  def _all_locations(self) -> None:
143
156
  """Collect all locations."""
@@ -171,11 +184,11 @@ class SmileLegacyHelper(SmileCommon):
171
184
 
172
185
  Use the home_location or FAKE_APPL as entity id.
173
186
  """
174
- self.gateway_id = self._home_loc_id
187
+ self._gateway_id = self._home_loc_id
175
188
  if self.smile_type == "power":
176
- self.gateway_id = FAKE_APPL
189
+ self._gateway_id = FAKE_APPL
177
190
 
178
- self.gw_entities[self.gateway_id] = {"dev_class": "gateway"}
191
+ self.gw_entities[self._gateway_id] = {"dev_class": "gateway"}
179
192
  self._count += 1
180
193
  for key, value in {
181
194
  "firmware": str(self.smile_version),
@@ -188,7 +201,7 @@ class SmileLegacyHelper(SmileCommon):
188
201
  }.items():
189
202
  if value is not None:
190
203
  gw_key = cast(ApplianceType, key)
191
- self.gw_entities[self.gateway_id][gw_key] = value
204
+ self.gw_entities[self._gateway_id][gw_key] = value
192
205
  self._count += 1
193
206
 
194
207
  def _appliance_info_finder(self, appliance: etree, appl: Munch) -> Munch:
@@ -266,7 +279,7 @@ class SmileLegacyHelper(SmileCommon):
266
279
  return data
267
280
 
268
281
  measurements = DEVICE_MEASUREMENTS
269
- if self._is_thermostat and entity_id == self._heater_id:
282
+ if self._is_thermostat and entity_id == self.heater_id:
270
283
  measurements = HEATER_CENTRAL_MEASUREMENTS
271
284
 
272
285
  if (
@@ -280,7 +293,7 @@ class SmileLegacyHelper(SmileCommon):
280
293
 
281
294
  # Anna: the Smile outdoor_temperature is present in the Home location
282
295
  # For some Anna's LOCATIONS is empty, falling back to domain_objects!
283
- if self._is_thermostat and entity_id == self.gateway_id:
296
+ if self._is_thermostat and entity_id == self._gateway_id:
284
297
  locator = f"./location[@id='{self._home_loc_id}']/logs/point_log[type='outdoor_temperature']/period/measurement"
285
298
  if (found := self._domain_objects.find(locator)) is not None:
286
299
  value = format_measure(found.text, NONE)
@@ -316,7 +329,7 @@ class SmileLegacyHelper(SmileCommon):
316
329
 
317
330
  def _appliance_measurements(
318
331
  self,
319
- appliance: etree,
332
+ appliance: etree.Element,
320
333
  data: GwEntityData,
321
334
  measurements: dict[str, DATA | UOM],
322
335
  ) -> None:
@@ -345,7 +358,7 @@ class SmileLegacyHelper(SmileCommon):
345
358
  self._count = count_data_items(self._count, data)
346
359
 
347
360
  def _get_actuator_functionalities(
348
- self, xml: etree, entity: GwEntityData, data: GwEntityData
361
+ self, xml: etree.Element, entity: GwEntityData, data: GwEntityData
349
362
  ) -> None:
350
363
  """Helper-function for _get_measurement_data()."""
351
364
  for item in ACTIVE_ACTUATORS: