plugwise 1.5.1a3__tar.gz → 1.5.2__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 (32) hide show
  1. {plugwise-1.5.1a3 → plugwise-1.5.2}/PKG-INFO +1 -1
  2. {plugwise-1.5.1a3 → plugwise-1.5.2}/plugwise/common.py +8 -10
  3. {plugwise-1.5.1a3 → plugwise-1.5.2}/plugwise/constants.py +26 -25
  4. {plugwise-1.5.1a3 → plugwise-1.5.2}/plugwise/helper.py +7 -32
  5. {plugwise-1.5.1a3 → plugwise-1.5.2}/plugwise/legacy/helper.py +3 -3
  6. {plugwise-1.5.1a3 → plugwise-1.5.2}/plugwise/util.py +2 -4
  7. {plugwise-1.5.1a3 → plugwise-1.5.2}/plugwise.egg-info/PKG-INFO +1 -1
  8. {plugwise-1.5.1a3 → plugwise-1.5.2}/pyproject.toml +1 -1
  9. {plugwise-1.5.1a3 → plugwise-1.5.2}/tests/test_adam.py +2 -1
  10. {plugwise-1.5.1a3 → plugwise-1.5.2}/LICENSE +0 -0
  11. {plugwise-1.5.1a3 → plugwise-1.5.2}/README.md +0 -0
  12. {plugwise-1.5.1a3 → plugwise-1.5.2}/plugwise/__init__.py +0 -0
  13. {plugwise-1.5.1a3 → plugwise-1.5.2}/plugwise/data.py +0 -0
  14. {plugwise-1.5.1a3 → plugwise-1.5.2}/plugwise/exceptions.py +0 -0
  15. {plugwise-1.5.1a3 → plugwise-1.5.2}/plugwise/legacy/data.py +0 -0
  16. {plugwise-1.5.1a3 → plugwise-1.5.2}/plugwise/legacy/smile.py +0 -0
  17. {plugwise-1.5.1a3 → plugwise-1.5.2}/plugwise/py.typed +0 -0
  18. {plugwise-1.5.1a3 → plugwise-1.5.2}/plugwise/smile.py +0 -0
  19. {plugwise-1.5.1a3 → plugwise-1.5.2}/plugwise.egg-info/SOURCES.txt +0 -0
  20. {plugwise-1.5.1a3 → plugwise-1.5.2}/plugwise.egg-info/dependency_links.txt +0 -0
  21. {plugwise-1.5.1a3 → plugwise-1.5.2}/plugwise.egg-info/requires.txt +0 -0
  22. {plugwise-1.5.1a3 → plugwise-1.5.2}/plugwise.egg-info/top_level.txt +0 -0
  23. {plugwise-1.5.1a3 → plugwise-1.5.2}/setup.cfg +0 -0
  24. {plugwise-1.5.1a3 → plugwise-1.5.2}/setup.py +0 -0
  25. {plugwise-1.5.1a3 → plugwise-1.5.2}/tests/test_anna.py +0 -0
  26. {plugwise-1.5.1a3 → plugwise-1.5.2}/tests/test_generic.py +0 -0
  27. {plugwise-1.5.1a3 → plugwise-1.5.2}/tests/test_init.py +0 -0
  28. {plugwise-1.5.1a3 → plugwise-1.5.2}/tests/test_legacy_anna.py +0 -0
  29. {plugwise-1.5.1a3 → plugwise-1.5.2}/tests/test_legacy_generic.py +0 -0
  30. {plugwise-1.5.1a3 → plugwise-1.5.2}/tests/test_legacy_p1.py +0 -0
  31. {plugwise-1.5.1a3 → plugwise-1.5.2}/tests/test_legacy_stretch.py +0 -0
  32. {plugwise-1.5.1a3 → plugwise-1.5.2}/tests/test_p1.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: plugwise
3
- Version: 1.5.1a3
3
+ Version: 1.5.2
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
@@ -73,13 +73,12 @@ class SmileCommon:
73
73
  appl.name = "OpenTherm"
74
74
  locator_1 = "./logs/point_log[type='flame_state']/boiler_state"
75
75
  locator_2 = "./services/boiler_state"
76
- mod_type = "boiler_state"
77
76
  # xml_1: appliance
78
77
  # xml_3: self._modules for legacy, self._domain_objects for actual
79
78
  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)
81
80
  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)
83
82
  appl.vendor_name = module_data["vendor_name"]
84
83
  appl.hardware = module_data["hardware_version"]
85
84
  appl.model_id = module_data["vendor_model"] if not legacy else None
@@ -94,15 +93,15 @@ class SmileCommon:
94
93
  def _appl_thermostat_info(self, appl: Munch, xml_1: etree, xml_2: etree = None) -> Munch:
95
94
  """Helper-function for _appliance_info_finder()."""
96
95
  locator = "./logs/point_log[type='thermostat']/thermostat"
97
- mod_type = "thermostat"
98
96
  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)
100
98
  appl.vendor_name = module_data["vendor_name"]
101
99
  appl.model = module_data["vendor_model"]
102
100
  if appl.model != "ThermoTouch": # model_id for Anna not present as stand-alone device
103
101
  appl.model_id = appl.model
104
102
  appl.model = check_model(appl.model, appl.vendor_name)
105
103
 
104
+ appl.available = module_data["reachable"]
106
105
  appl.hardware = module_data["hardware_version"]
107
106
  appl.firmware = module_data["firmware_version"]
108
107
  appl.zigbee_mac = module_data["zigbee_mac_address"]
@@ -192,6 +191,7 @@ class SmileCommon:
192
191
  self.gw_devices[appl.dev_id] = {"dev_class": appl.pwclass}
193
192
  self._count += 1
194
193
  for key, value in {
194
+ "available": appl.available,
195
195
  "firmware": appl.firmware,
196
196
  "hardware": appl.hardware,
197
197
  "location": appl.location,
@@ -278,7 +278,6 @@ class SmileCommon:
278
278
  self,
279
279
  xml_1: etree,
280
280
  locator: str,
281
- mod_type: str,
282
281
  xml_2: etree = None,
283
282
  legacy: bool = False,
284
283
  ) -> ModelData:
@@ -295,12 +294,11 @@ class SmileCommon:
295
294
  "vendor_model": None,
296
295
  "zigbee_mac_address": None,
297
296
  }
298
- # xml_1: appliance
297
+
299
298
  if (appl_search := xml_1.find(locator)) is not None:
299
+ link_tag = appl_search.tag
300
300
  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}']...."
304
302
  # Not possible to walrus for some reason...
305
303
  # xml_2: self._modules for legacy, self._domain_objects for actual
306
304
  search = return_valid(xml_2, self._domain_objects)
@@ -81,6 +81,7 @@ HW_MODELS: Final[dict[str, str]] = {
81
81
 
82
82
  MAX_SETPOINT: Final[float] = 30.0
83
83
  MIN_SETPOINT: Final[float] = 4.0
84
+ MODULE_LOCATOR: Final = "./logs/point_log/*[@id]"
84
85
  NONE: Final = "None"
85
86
  OFF: Final = "off"
86
87
 
@@ -123,7 +124,7 @@ P1_LEGACY_MEASUREMENTS: Final[dict[str, UOM]] = {
123
124
  # radiator_valve: 'uncorrected_temperature', 'temperature_offset'
124
125
 
125
126
  DEVICE_MEASUREMENTS: Final[dict[str, DATA | UOM]] = {
126
- "humidity": UOM(PERCENTAGE), # Specific for a Jip
127
+ "humidity": UOM(NONE), # Specific for a Jip
127
128
  "illuminance": UOM(UNIT_LUMEN), # Specific for an Anna
128
129
  "temperature": UOM(TEMP_CELSIUS), # HA Core thermostat current_temperature
129
130
  "thermostat": DATA("setpoint", TEMP_CELSIUS), # HA Core thermostat setpoint
@@ -425,44 +426,44 @@ class SmileBinarySensors(TypedDict, total=False):
425
426
  class SmileSensors(TypedDict, total=False):
426
427
  """Smile Sensors class."""
427
428
 
428
- battery: float
429
+ battery: int
429
430
  cooling_activation_outdoor_temperature: float
430
431
  cooling_deactivation_threshold: float
431
432
  dhw_temperature: float
432
433
  domestic_hot_water_setpoint: float
433
434
  temperature: float
434
- electricity_consumed: int
435
- electricity_consumed_interval:int
435
+ electricity_consumed: float
436
+ electricity_consumed_interval: float
436
437
  electricity_consumed_off_peak_cumulative: float
437
- electricity_consumed_off_peak_interval: int
438
- electricity_consumed_off_peak_point: int
438
+ electricity_consumed_off_peak_interval: float
439
+ electricity_consumed_off_peak_point: float
439
440
  electricity_consumed_peak_cumulative: float
440
- electricity_consumed_peak_interval: int
441
- electricity_consumed_peak_point: int
442
- electricity_consumed_point: int
443
- electricity_phase_one_consumed: int
444
- electricity_phase_two_consumed: int
445
- electricity_phase_three_consumed: int
446
- electricity_phase_one_produced: int
447
- electricity_phase_two_produced: int
448
- electricity_phase_three_produced: int
449
- electricity_produced: int
450
- electricity_produced_interval: int
441
+ electricity_consumed_peak_interval: float
442
+ electricity_consumed_peak_point: float
443
+ electricity_consumed_point: float
444
+ electricity_phase_one_consumed: float
445
+ electricity_phase_two_consumed: float
446
+ electricity_phase_three_consumed: float
447
+ electricity_phase_one_produced: float
448
+ electricity_phase_two_produced: float
449
+ electricity_phase_three_produced: float
450
+ electricity_produced: float
451
+ electricity_produced_interval: float
451
452
  electricity_produced_off_peak_cumulative: float
452
- electricity_produced_off_peak_interval: int
453
- electricity_produced_off_peak_point: int
453
+ electricity_produced_off_peak_interval: float
454
+ electricity_produced_off_peak_point: float
454
455
  electricity_produced_peak_cumulative: float
455
- electricity_produced_peak_interval: int
456
- electricity_produced_peak_point: int
457
- electricity_produced_point: int
456
+ electricity_produced_peak_interval: float
457
+ electricity_produced_peak_point: float
458
+ electricity_produced_point: float
458
459
  gas_consumed_cumulative: float
459
460
  gas_consumed_interval: float
460
461
  humidity: float
461
462
  illuminance: float
462
463
  intended_boiler_temperature: float
463
- modulation_level: float
464
+ modulation_level: int
464
465
  net_electricity_cumulative: float
465
- net_electricity_point: int
466
+ net_electricity_point: float
466
467
  outdoor_air_temperature: float
467
468
  outdoor_temperature: float
468
469
  return_temperature: float
@@ -470,7 +471,7 @@ class SmileSensors(TypedDict, total=False):
470
471
  setpoint_high: float
471
472
  setpoint_low: float
472
473
  temperature_difference: float
473
- valve_position: float
474
+ valve_position: int
474
475
  voltage_phase_one: float
475
476
  voltage_phase_two: float
476
477
  voltage_phase_three: float
@@ -24,6 +24,7 @@ from plugwise.constants import (
24
24
  LIMITS,
25
25
  LOCATIONS,
26
26
  LOGGER,
27
+ MODULE_LOCATOR,
27
28
  NONE,
28
29
  OFF,
29
30
  P1_MEASUREMENTS,
@@ -299,6 +300,7 @@ class SmileHelper(SmileCommon):
299
300
  if appl.pwclass in THERMOSTAT_CLASSES and appl.location is None:
300
301
  continue
301
302
 
303
+ appl.available = None
302
304
  appl.dev_id = appliance.attrib["id"]
303
305
  appl.name = appliance.find("name").text
304
306
  appl.model = None
@@ -356,9 +358,8 @@ class SmileHelper(SmileCommon):
356
358
  """Collect P1 DSMR SmartMeter info."""
357
359
  loc_id = next(iter(self.loc_data.keys()))
358
360
  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)
362
363
  if not module_data["contents"]:
363
364
  LOGGER.error("No module data found for SmartMeter") # pragma: no cover
364
365
  return None # pragma: no cover
@@ -396,13 +397,13 @@ class SmileHelper(SmileCommon):
396
397
  return appl
397
398
  case _ as s if s.endswith("_plug"):
398
399
  # 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)
402
402
  # A plug without module-data is orphaned/ no present
403
403
  if not module_data["contents"]:
404
404
  return Munch()
405
405
 
406
+ appl.available = module_data["reachable"]
406
407
  appl.firmware = module_data["firmware_version"]
407
408
  appl.hardware = module_data["hardware_version"]
408
409
  appl.model_id = module_data["vendor_model"]
@@ -515,9 +516,6 @@ class SmileHelper(SmileCommon):
515
516
  if appliance.find("type").text in ACTUATOR_CLASSES:
516
517
  self._get_actuator_functionalities(appliance, device, data)
517
518
 
518
- # Collect availability-status for wireless connected devices to Adam
519
- self._wireless_availability(appliance, data)
520
-
521
519
  if dev_id == self.gateway_id and self.smile(ADAM):
522
520
  self._get_regulation_mode(appliance, data)
523
521
  self._get_gateway_mode(appliance, data)
@@ -710,29 +708,6 @@ class SmileHelper(SmileCommon):
710
708
  act_item = cast(ActuatorType, item)
711
709
  data[act_item] = temp_dict
712
710
 
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
-
736
711
  def _get_regulation_mode(self, appliance: etree, data: DeviceData) -> None:
737
712
  """Helper-function for _get_measurement_data().
738
713
 
@@ -125,6 +125,7 @@ class SmileLegacyHelper(SmileCommon):
125
125
  appl.pwclass = "heater_central_plug"
126
126
 
127
127
  appl.model = appl.pwclass.replace("_", " ").title()
128
+ appl.available = None
128
129
  appl.model_id = None
129
130
  appl.firmware = None
130
131
  appl.hardware = None
@@ -230,9 +231,7 @@ class SmileLegacyHelper(SmileCommon):
230
231
  """
231
232
  if self.smile_type in ("power", "stretch"):
232
233
  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)
236
235
  appl.zigbee_mac = module_data["zigbee_mac_address"]
237
236
  # Filter appliance without zigbee_mac, it's an orphaned device
238
237
  if appl.zigbee_mac is None and self.smile_type != "power":
@@ -253,6 +252,7 @@ class SmileLegacyHelper(SmileCommon):
253
252
  def _p1_smartmeter_info_finder(self, appl: Munch) -> None:
254
253
  """Collect P1 DSMR Smartmeter info."""
255
254
  loc_id = next(iter(self.loc_data.keys()))
255
+ appl.available = None
256
256
  appl.dev_id = loc_id
257
257
  appl.location = loc_id
258
258
  appl.mac = None
@@ -115,7 +115,7 @@ def check_model(name: str | None, vendor_name: str | None) -> str | None:
115
115
  if name is not None and "lumi.plug" in name:
116
116
  return "Aqara Smart Plug"
117
117
 
118
- return name # pragma: no cover
118
+ return None
119
119
 
120
120
 
121
121
  def common_match_cases(
@@ -173,10 +173,8 @@ def format_measure(measure: str, unit: str) -> float | int:
173
173
  result = float(f"{round(float_measure, 1):.1f}")
174
174
  elif abs(float_measure) < 10:
175
175
  result = float(f"{round(float_measure, 2):.2f}")
176
- elif abs(float_measure) >= 10 and abs(float_measure) < 100:
176
+ elif abs(float_measure) >= 10:
177
177
  result = float(f"{round(float_measure, 1):.1f}")
178
- elif abs(float_measure) >= 100:
179
- result = int(round(float_measure))
180
178
 
181
179
  return result
182
180
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: plugwise
3
- Version: 1.5.1a3
3
+ Version: 1.5.2
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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "plugwise"
7
- version = "1.5.1a3"
7
+ version = "1.5.2"
8
8
  license = {file = "LICENSE"}
9
9
  description = "Plugwise Smile (Adam/Anna/P1) and Stretch module for Python 3."
10
10
  readme = "README.md"
@@ -36,10 +36,11 @@ class TestPlugwiseAdam(TestPlugwise): # pylint: disable=attribute-defined-outsi
36
36
  assert smile.gateway_id == "da224107914542988a88561b4452b0f6"
37
37
  assert smile._last_active["f2bf9048bef64cc5b6d5110154e33c81"] == "Weekschema"
38
38
  assert smile._last_active["f871b8c4d63549319221e294e4f88074"] == "Badkamer"
39
- assert self.device_items == 157
39
+ assert self.device_items == 165
40
40
  assert self.device_list == [
41
41
  "da224107914542988a88561b4452b0f6",
42
42
  "056ee145a816487eaa69243c3280f8bf",
43
+ "10016900610d4c7481df78c89606ef22",
43
44
  "67d73d0bd469422db25a618a5fb8eeb0",
44
45
  "e2f4322d57924fa090fbbc48b3a140dc",
45
46
  "29542b2b6a6a4169acecc15c72a599b8",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes