PyPlumIO 0.5.21__py3-none-any.whl → 0.5.23__py3-none-any.whl

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 (37) hide show
  1. {PyPlumIO-0.5.21.dist-info → PyPlumIO-0.5.23.dist-info}/METADATA +12 -10
  2. PyPlumIO-0.5.23.dist-info/RECORD +60 -0
  3. {PyPlumIO-0.5.21.dist-info → PyPlumIO-0.5.23.dist-info}/WHEEL +1 -1
  4. pyplumio/__init__.py +2 -2
  5. pyplumio/_version.py +2 -2
  6. pyplumio/connection.py +3 -12
  7. pyplumio/devices/__init__.py +16 -16
  8. pyplumio/devices/ecomax.py +126 -126
  9. pyplumio/devices/mixer.py +50 -44
  10. pyplumio/devices/thermostat.py +36 -35
  11. pyplumio/exceptions.py +9 -9
  12. pyplumio/filters.py +56 -37
  13. pyplumio/frames/__init__.py +6 -6
  14. pyplumio/frames/messages.py +4 -6
  15. pyplumio/helpers/data_types.py +8 -7
  16. pyplumio/helpers/event_manager.py +53 -33
  17. pyplumio/helpers/parameter.py +138 -52
  18. pyplumio/helpers/task_manager.py +7 -2
  19. pyplumio/helpers/timeout.py +0 -3
  20. pyplumio/helpers/uid.py +2 -2
  21. pyplumio/protocol.py +35 -28
  22. pyplumio/stream.py +2 -2
  23. pyplumio/structures/alerts.py +40 -31
  24. pyplumio/structures/ecomax_parameters.py +493 -282
  25. pyplumio/structures/frame_versions.py +5 -6
  26. pyplumio/structures/lambda_sensor.py +6 -6
  27. pyplumio/structures/mixer_parameters.py +136 -71
  28. pyplumio/structures/network_info.py +2 -3
  29. pyplumio/structures/product_info.py +0 -4
  30. pyplumio/structures/program_version.py +24 -17
  31. pyplumio/structures/schedules.py +35 -15
  32. pyplumio/structures/thermostat_parameters.py +82 -50
  33. pyplumio/utils.py +12 -7
  34. PyPlumIO-0.5.21.dist-info/RECORD +0 -61
  35. pyplumio/helpers/typing.py +0 -29
  36. {PyPlumIO-0.5.21.dist-info → PyPlumIO-0.5.23.dist-info}/LICENSE +0 -0
  37. {PyPlumIO-0.5.21.dist-info → PyPlumIO-0.5.23.dist-info}/top_level.txt +0 -0
@@ -3,10 +3,11 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  from collections.abc import Generator
6
+ from contextlib import suppress
6
7
  from dataclasses import dataclass
7
8
  from datetime import datetime
8
9
  from functools import lru_cache
9
- from typing import Any, Final
10
+ from typing import Any, Final, Literal, NamedTuple
10
11
 
11
12
  from pyplumio.const import AlertType
12
13
  from pyplumio.helpers.data_types import UnsignedInt
@@ -19,27 +20,40 @@ ATTR_TOTAL_ALERTS: Final = "total_alerts"
19
20
  MAX_UINT32: Final = 4294967295
20
21
 
21
22
 
22
- @lru_cache(maxsize=10)
23
- def _convert_to_datetime(seconds: int) -> datetime:
24
- """Convert timestamp to a datetime object."""
25
-
26
- def _seconds_to_datetime_args(seconds: int) -> Generator[Any, None, None]:
27
- """Convert seconds to a kwargs for a datetime class."""
28
- intervals: tuple[tuple[str, int, int], ...] = (
29
- ("year", 32140800, 2000), # 60sec * 60min * 24h * 31d * 12m
30
- ("month", 2678400, 1), # 60sec * 60min * 24h * 31d
31
- ("day", 86400, 1), # 60sec * 60min * 24h
32
- ("hour", 3600, 0), # 60sec * 60min
33
- ("minute", 60, 0),
34
- ("second", 1, 0),
35
- )
23
+ class DateTimeInterval(NamedTuple):
24
+ """Represents an alert time interval."""
25
+
26
+ name: Literal["year", "month", "day", "hour", "minute", "second"]
27
+ seconds: int
28
+ offset: int = 0
29
+
36
30
 
37
- for name, count, offset in intervals:
38
- value = seconds // count
39
- seconds -= value * count
31
+ DATETIME_INTERVALS: tuple[DateTimeInterval, ...] = (
32
+ DateTimeInterval("year", seconds=60 * 60 * 24 * 31 * 12, offset=2000),
33
+ DateTimeInterval("month", seconds=60 * 60 * 24 * 31, offset=1),
34
+ DateTimeInterval("day", seconds=60 * 60 * 24, offset=1),
35
+ DateTimeInterval("hour", seconds=60 * 60),
36
+ DateTimeInterval("minute", seconds=60),
37
+ DateTimeInterval("second", seconds=1),
38
+ )
39
+
40
+
41
+ @lru_cache(maxsize=10)
42
+ def _seconds_to_datetime(timestamp: int) -> datetime:
43
+ """Convert timestamp to a datetime object.
44
+
45
+ The ecoMAX controller stores alert time as a special timestamp value
46
+ in seconds counted from Jan 1st, 2000.
47
+ """
48
+
49
+ def _datetime_kwargs(timestamp: int) -> Generator[Any, None, None]:
50
+ """Yield a tuple, that represents a single datetime kwarg."""
51
+ for name, seconds, offset in DATETIME_INTERVALS:
52
+ value = timestamp // seconds
53
+ timestamp -= value * seconds
40
54
  yield name, (value + offset)
41
55
 
42
- return datetime(**dict(_seconds_to_datetime_args(seconds)))
56
+ return datetime(**dict(_datetime_kwargs(timestamp)))
43
57
 
44
58
 
45
59
  @dataclass
@@ -62,24 +76,20 @@ class AlertsStructure(StructureDecoder):
62
76
 
63
77
  def _unpack_alert(self, message: bytearray) -> Alert:
64
78
  """Unpack an alert."""
65
- try:
66
- code = message[self._offset]
67
- code = AlertType(code)
68
- except ValueError:
69
- pass
70
-
79
+ code = message[self._offset]
71
80
  self._offset += 1
72
81
  from_seconds = UnsignedInt.from_bytes(message, self._offset)
73
82
  self._offset += from_seconds.size
74
83
  to_seconds = UnsignedInt.from_bytes(message, self._offset)
75
84
  self._offset += to_seconds.size
76
-
77
- from_dt = _convert_to_datetime(from_seconds.value)
85
+ from_dt = _seconds_to_datetime(from_seconds.value)
78
86
  to_dt = (
79
87
  None
80
88
  if to_seconds.value == MAX_UINT32
81
- else _convert_to_datetime(to_seconds.value)
89
+ else _seconds_to_datetime(to_seconds.value)
82
90
  )
91
+ with suppress(ValueError):
92
+ code = AlertType(code)
83
93
 
84
94
  return Alert(code, from_dt, to_dt)
85
95
 
@@ -90,12 +100,11 @@ class AlertsStructure(StructureDecoder):
90
100
  total_alerts = message[offset + 0]
91
101
  start = message[offset + 1]
92
102
  end = message[offset + 2]
93
-
103
+ self._offset = offset + 3
94
104
  if end == 0:
95
105
  # No alerts found.
96
- return ensure_dict(data, {ATTR_TOTAL_ALERTS: total_alerts}), offset + 3
106
+ return ensure_dict(data, {ATTR_TOTAL_ALERTS: total_alerts}), self._offset
97
107
 
98
- self._offset = offset + 3
99
108
  return (
100
109
  ensure_dict(
101
110
  data,