PyPlumIO 0.5.42__py3-none-any.whl → 0.5.43__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 (60) hide show
  1. pyplumio/__init__.py +3 -2
  2. pyplumio/_version.py +2 -2
  3. pyplumio/connection.py +14 -14
  4. pyplumio/const.py +7 -0
  5. pyplumio/devices/__init__.py +32 -19
  6. pyplumio/devices/ecomax.py +112 -128
  7. pyplumio/devices/ecoster.py +5 -0
  8. pyplumio/devices/mixer.py +21 -31
  9. pyplumio/devices/thermostat.py +19 -29
  10. pyplumio/filters.py +166 -147
  11. pyplumio/frames/__init__.py +20 -8
  12. pyplumio/frames/messages.py +3 -0
  13. pyplumio/frames/requests.py +21 -0
  14. pyplumio/frames/responses.py +18 -0
  15. pyplumio/helpers/data_types.py +23 -21
  16. pyplumio/helpers/event_manager.py +40 -3
  17. pyplumio/helpers/factory.py +5 -2
  18. pyplumio/helpers/schedule.py +8 -5
  19. pyplumio/helpers/task_manager.py +3 -0
  20. pyplumio/helpers/timeout.py +8 -8
  21. pyplumio/helpers/uid.py +8 -5
  22. pyplumio/{helpers/parameter.py → parameters/__init__.py} +98 -4
  23. pyplumio/parameters/ecomax.py +868 -0
  24. pyplumio/parameters/mixer.py +245 -0
  25. pyplumio/parameters/thermostat.py +197 -0
  26. pyplumio/protocol.py +6 -3
  27. pyplumio/stream.py +3 -0
  28. pyplumio/structures/__init__.py +3 -0
  29. pyplumio/structures/alerts.py +8 -5
  30. pyplumio/structures/boiler_load.py +3 -0
  31. pyplumio/structures/boiler_power.py +3 -0
  32. pyplumio/structures/ecomax_parameters.py +6 -800
  33. pyplumio/structures/fan_power.py +3 -0
  34. pyplumio/structures/frame_versions.py +3 -0
  35. pyplumio/structures/fuel_consumption.py +3 -0
  36. pyplumio/structures/fuel_level.py +3 -0
  37. pyplumio/structures/lambda_sensor.py +8 -0
  38. pyplumio/structures/mixer_parameters.py +8 -230
  39. pyplumio/structures/mixer_sensors.py +9 -0
  40. pyplumio/structures/modules.py +14 -0
  41. pyplumio/structures/network_info.py +11 -0
  42. pyplumio/structures/output_flags.py +9 -0
  43. pyplumio/structures/outputs.py +21 -0
  44. pyplumio/structures/pending_alerts.py +3 -0
  45. pyplumio/structures/product_info.py +5 -2
  46. pyplumio/structures/program_version.py +3 -0
  47. pyplumio/structures/regulator_data.py +4 -1
  48. pyplumio/structures/regulator_data_schema.py +3 -0
  49. pyplumio/structures/schedules.py +18 -1
  50. pyplumio/structures/statuses.py +9 -0
  51. pyplumio/structures/temperatures.py +22 -0
  52. pyplumio/structures/thermostat_parameters.py +13 -177
  53. pyplumio/structures/thermostat_sensors.py +9 -0
  54. pyplumio/utils.py +14 -12
  55. {pyplumio-0.5.42.dist-info → pyplumio-0.5.43.dist-info}/METADATA +30 -17
  56. pyplumio-0.5.43.dist-info/RECORD +63 -0
  57. {pyplumio-0.5.42.dist-info → pyplumio-0.5.43.dist-info}/WHEEL +1 -1
  58. pyplumio-0.5.42.dist-info/RECORD +0 -60
  59. {pyplumio-0.5.42.dist-info → pyplumio-0.5.43.dist-info}/licenses/LICENSE +0 -0
  60. {pyplumio-0.5.42.dist-info → pyplumio-0.5.43.dist-info}/top_level.txt +0 -0
@@ -28,3 +28,6 @@ class FanPowerStructure(StructureDecoder):
28
28
  return ensure_dict(data), offset
29
29
 
30
30
  return ensure_dict(data, {ATTR_FAN_POWER: fan_power.value}), offset
31
+
32
+
33
+ __all__ = ["ATTR_FAN_POWER", "FanPowerStructure"]
@@ -48,3 +48,6 @@ class FrameVersionsStructure(StructureDecoder):
48
48
  ),
49
49
  self._offset,
50
50
  )
51
+
52
+
53
+ __all__ = ["ATTR_FRAME_VERSIONS", "FrameVersionsStructure"]
@@ -31,3 +31,6 @@ class FuelConsumptionStructure(StructureDecoder):
31
31
  ensure_dict(data, {ATTR_FUEL_CONSUMPTION: fuel_consumption.value}),
32
32
  offset,
33
33
  )
34
+
35
+
36
+ __all__ = ["ATTR_FUEL_CONSUMPTION", "FuelConsumptionStructure"]
@@ -34,3 +34,6 @@ class FuelLevelStructure(StructureDecoder):
34
34
  fuel_level -= FUEL_LEVEL_OFFSET
35
35
 
36
36
  return (ensure_dict(data, {ATTR_FUEL_LEVEL: fuel_level}), offset)
37
+
38
+
39
+ __all__ = ["ATTR_FUEL_LEVEL", "FuelLevelStructure"]
@@ -50,3 +50,11 @@ class LambdaSensorStructure(StructureDecoder):
50
50
  ),
51
51
  offset,
52
52
  )
53
+
54
+
55
+ __all__ = [
56
+ "ATTR_LAMBDA_STATE",
57
+ "ATTR_LAMBDA_TARGET",
58
+ "ATTR_LAMBDA_LEVEL",
59
+ "LambdaSensorStructure",
60
+ ]
@@ -3,245 +3,17 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  from collections.abc import Generator
6
- from dataclasses import dataclass
7
- from typing import TYPE_CHECKING, Any, Final
6
+ from typing import Any, Final
8
7
 
9
- from dataslots import dataslots
10
-
11
- from pyplumio.const import (
12
- ATTR_DEVICE_INDEX,
13
- ATTR_INDEX,
14
- ATTR_VALUE,
15
- FrameType,
16
- ProductType,
17
- UnitOfMeasurement,
18
- )
19
- from pyplumio.frames import Request
20
- from pyplumio.helpers.parameter import (
21
- Number,
22
- NumberDescription,
23
- NumericType,
24
- Parameter,
25
- ParameterDescription,
26
- ParameterValues,
27
- Switch,
28
- SwitchDescription,
29
- unpack_parameter,
30
- )
8
+ from pyplumio.parameters import ParameterValues, unpack_parameter
31
9
  from pyplumio.structures import StructureDecoder
32
10
  from pyplumio.utils import ensure_dict
33
11
 
34
- if TYPE_CHECKING:
35
- from pyplumio.devices.mixer import Mixer
36
-
37
12
  ATTR_MIXER_PARAMETERS: Final = "mixer_parameters"
38
13
 
39
14
  MIXER_PARAMETER_SIZE: Final = 3
40
15
 
41
16
 
42
- @dataclass
43
- class MixerParameterDescription(ParameterDescription):
44
- """Represents a mixer parameter description."""
45
-
46
- __slots__ = ()
47
-
48
-
49
- class MixerParameter(Parameter):
50
- """Represent a mixer parameter."""
51
-
52
- __slots__ = ()
53
-
54
- device: Mixer
55
- description: MixerParameterDescription
56
-
57
- async def create_request(self) -> Request:
58
- """Create a request to change the parameter."""
59
- return await Request.create(
60
- FrameType.REQUEST_SET_MIXER_PARAMETER,
61
- recipient=self.device.parent.address,
62
- data={
63
- ATTR_INDEX: self._index,
64
- ATTR_VALUE: self.values.value,
65
- ATTR_DEVICE_INDEX: self.device.index,
66
- },
67
- )
68
-
69
-
70
- @dataslots
71
- @dataclass
72
- class MixerNumberDescription(MixerParameterDescription, NumberDescription):
73
- """Represent a mixer number description."""
74
-
75
- offset: int = 0
76
-
77
-
78
- class MixerNumber(MixerParameter, Number):
79
- """Represents a mixer number."""
80
-
81
- __slots__ = ()
82
-
83
- description: MixerNumberDescription
84
-
85
- def _pack_value(self, value: NumericType) -> int:
86
- """Pack the parameter value."""
87
- return super()._pack_value(value + self.description.offset)
88
-
89
- def _unpack_value(self, value: int) -> NumericType:
90
- """Unpack the parameter value."""
91
- return super()._unpack_value(value - self.description.offset)
92
-
93
-
94
- @dataslots
95
- @dataclass
96
- class MixerSwitchDescription(MixerParameterDescription, SwitchDescription):
97
- """Represents a mixer switch description."""
98
-
99
-
100
- class MixerSwitch(MixerParameter, Switch):
101
- """Represents a mixer switch."""
102
-
103
- __slots__ = ()
104
-
105
- description: MixerSwitchDescription
106
-
107
-
108
- MIXER_PARAMETERS: dict[ProductType, tuple[MixerParameterDescription, ...]] = {
109
- ProductType.ECOMAX_P: (
110
- MixerNumberDescription(
111
- name="mixer_target_temp",
112
- unit_of_measurement=UnitOfMeasurement.CELSIUS,
113
- ),
114
- MixerNumberDescription(
115
- name="min_target_temp",
116
- unit_of_measurement=UnitOfMeasurement.CELSIUS,
117
- ),
118
- MixerNumberDescription(
119
- name="max_target_temp",
120
- unit_of_measurement=UnitOfMeasurement.CELSIUS,
121
- ),
122
- MixerNumberDescription(
123
- name="thermostat_decrease_target_temp",
124
- unit_of_measurement=UnitOfMeasurement.CELSIUS,
125
- ),
126
- MixerSwitchDescription(
127
- name="weather_control",
128
- ),
129
- MixerNumberDescription(
130
- name="heating_curve",
131
- step=0.1,
132
- ),
133
- MixerNumberDescription(
134
- name="heating_curve_shift",
135
- offset=20,
136
- unit_of_measurement=UnitOfMeasurement.CELSIUS,
137
- ),
138
- MixerNumberDescription(
139
- name="weather_factor",
140
- ),
141
- MixerNumberDescription(
142
- name="work_mode",
143
- ),
144
- MixerNumberDescription(
145
- name="mixer_input_dead_zone",
146
- step=0.1,
147
- unit_of_measurement=UnitOfMeasurement.CELSIUS,
148
- ),
149
- MixerSwitchDescription(
150
- name="thermostat_operation",
151
- ),
152
- MixerNumberDescription(
153
- name="thermostat_mode",
154
- ),
155
- MixerSwitchDescription(
156
- name="disable_pump_on_thermostat",
157
- ),
158
- MixerSwitchDescription(
159
- name="summer_work",
160
- ),
161
- ),
162
- ProductType.ECOMAX_I: (
163
- MixerNumberDescription(
164
- name="work_mode",
165
- ),
166
- MixerNumberDescription(
167
- name="circuit_target_temp",
168
- unit_of_measurement=UnitOfMeasurement.CELSIUS,
169
- ),
170
- MixerNumberDescription(
171
- name="day_target_temp",
172
- unit_of_measurement=UnitOfMeasurement.CELSIUS,
173
- ),
174
- MixerNumberDescription(
175
- name="night_target_temp",
176
- unit_of_measurement=UnitOfMeasurement.CELSIUS,
177
- ),
178
- MixerNumberDescription(
179
- name="min_target_temp",
180
- unit_of_measurement=UnitOfMeasurement.CELSIUS,
181
- ),
182
- MixerNumberDescription(
183
- name="max_target_temp",
184
- unit_of_measurement=UnitOfMeasurement.CELSIUS,
185
- ),
186
- MixerSwitchDescription(
187
- name="summer_work",
188
- ),
189
- MixerSwitchDescription(
190
- name="weather_control",
191
- ),
192
- MixerNumberDescription(
193
- name="enable_circuit",
194
- ),
195
- MixerNumberDescription(
196
- name="constant_water_preset_temp",
197
- unit_of_measurement=UnitOfMeasurement.CELSIUS,
198
- ),
199
- MixerNumberDescription(
200
- name="thermostat_decrease_temp",
201
- unit_of_measurement=UnitOfMeasurement.CELSIUS,
202
- ),
203
- MixerNumberDescription(
204
- name="thermostat_correction",
205
- unit_of_measurement=UnitOfMeasurement.CELSIUS,
206
- ),
207
- MixerSwitchDescription(
208
- name="thermostat_pump_lock",
209
- ),
210
- MixerNumberDescription(
211
- name="valve_opening_time",
212
- unit_of_measurement=UnitOfMeasurement.SECONDS,
213
- ),
214
- MixerNumberDescription(
215
- name="mixer_input_dead_zone",
216
- step=0.1,
217
- unit_of_measurement=UnitOfMeasurement.CELSIUS,
218
- ),
219
- MixerNumberDescription(
220
- name="proportional_range",
221
- ),
222
- MixerNumberDescription(
223
- name="integration_time_constant",
224
- ),
225
- MixerNumberDescription(
226
- name="heating_curve",
227
- step=0.1,
228
- ),
229
- MixerNumberDescription(
230
- name="heating_curve_shift",
231
- offset=20,
232
- unit_of_measurement=UnitOfMeasurement.CELSIUS,
233
- ),
234
- MixerNumberDescription(
235
- name="thermostat_mode",
236
- ),
237
- MixerNumberDescription(
238
- name="decreasing_constant_water_temp",
239
- unit_of_measurement=UnitOfMeasurement.CELSIUS,
240
- ),
241
- ),
242
- }
243
-
244
-
245
17
  class MixerParametersStructure(StructureDecoder):
246
18
  """Represents a mixer parameters data structure."""
247
19
 
@@ -286,3 +58,9 @@ class MixerParametersStructure(StructureDecoder):
286
58
  ),
287
59
  self._offset,
288
60
  )
61
+
62
+
63
+ __all__ = [
64
+ "ATTR_MIXER_PARAMETERS",
65
+ "MixerParametersStructure",
66
+ ]
@@ -69,3 +69,12 @@ class MixerSensorsStructure(StructureDecoder):
69
69
  ),
70
70
  self._offset,
71
71
  )
72
+
73
+
74
+ __all__ = [
75
+ "ATTR_PUMP",
76
+ "ATTR_MIXERS_AVAILABLE",
77
+ "ATTR_MIXERS_CONNECTED",
78
+ "ATTR_MIXER_SENSORS",
79
+ "MixerSensorsStructure",
80
+ ]
@@ -89,3 +89,17 @@ class ModulesStructure(StructureDecoder):
89
89
  ),
90
90
  self._offset,
91
91
  )
92
+
93
+
94
+ __all__ = [
95
+ "ATTR_MODULES",
96
+ "ATTR_MODULE_A",
97
+ "ATTR_MODULE_B",
98
+ "ATTR_MODULE_C",
99
+ "ATTR_ECOLAMBDA",
100
+ "ATTR_ECOSTER",
101
+ "ATTR_PANEL",
102
+ "MODULES",
103
+ "ConnectedModules",
104
+ "ModulesStructure",
105
+ ]
@@ -114,3 +114,14 @@ class NetworkInfoStructure(Structure):
114
114
  ),
115
115
  offset + NETWORK_INFO_SIZE,
116
116
  )
117
+
118
+
119
+ __all__ = [
120
+ "EthernetParameters",
121
+ "WirelessParameters",
122
+ "NetworkInfo",
123
+ "NetworkInfoStructure",
124
+ "ATTR_NETWORK",
125
+ "DEFAULT_IP",
126
+ "DEFAULT_NETMASK",
127
+ ]
@@ -36,3 +36,12 @@ class OutputFlagsStructure(StructureDecoder):
36
36
  ),
37
37
  offset + output_flags.size,
38
38
  )
39
+
40
+
41
+ __all__ = [
42
+ "ATTR_HEATING_PUMP_FLAG",
43
+ "ATTR_WATER_HEATER_PUMP_FLAG",
44
+ "ATTR_CIRCULATION_PUMP_FLAG",
45
+ "ATTR_SOLAR_PUMP_FLAG",
46
+ "OutputFlagsStructure",
47
+ ]
@@ -65,3 +65,24 @@ class OutputsStructure(StructureDecoder):
65
65
  ),
66
66
  offset + outputs.size,
67
67
  )
68
+
69
+
70
+ __all__ = [
71
+ "ATTR_FAN",
72
+ "ATTR_FEEDER",
73
+ "ATTR_HEATING_PUMP",
74
+ "ATTR_WATER_HEATER_PUMP",
75
+ "ATTR_CIRCULATION_PUMP",
76
+ "ATTR_LIGHTER",
77
+ "ATTR_ALARM",
78
+ "ATTR_OUTER_BOILER",
79
+ "ATTR_FAN2_EXHAUST",
80
+ "ATTR_FEEDER2",
81
+ "ATTR_OUTER_FEEDER",
82
+ "ATTR_SOLAR_PUMP",
83
+ "ATTR_FIREPLACE_PUMP",
84
+ "ATTR_GCZ_CONTACT",
85
+ "ATTR_BLOW_FAN1",
86
+ "ATTR_BLOW_FAN2",
87
+ "OutputsStructure",
88
+ ]
@@ -23,3 +23,6 @@ class PendingAlertsStructure(StructureDecoder):
23
23
  return ensure_dict(data, {ATTR_PENDING_ALERTS: alerts_number}), (
24
24
  offset + alerts_number + 1
25
25
  )
26
+
27
+
28
+ __all__ = ["ATTR_PENDING_ALERTS", "PendingAlertsStructure"]
@@ -20,7 +20,7 @@ ATTR_PRODUCT: Final = "product"
20
20
  @cache
21
21
  def format_model_name(model_name: str) -> str:
22
22
  """Format a device model name."""
23
- if m := re.match(r"^([A-Z]+)\s{0,}([0-9]{3,})(.+)$", model_name, re.IGNORECASE):
23
+ if m := re.match(r"^([A-Z]+)\s*(\d{3,})(.+)$", model_name, re.IGNORECASE):
24
24
  model_device, model_number, model_suffix = m.groups()
25
25
  model_device = "ecoMAX" if model_device == "EM" else model_device
26
26
  return f"{model_device} {model_number}{model_suffix}"
@@ -28,7 +28,7 @@ def format_model_name(model_name: str) -> str:
28
28
  return model_name
29
29
 
30
30
 
31
- @dataclass
31
+ @dataclass(frozen=True)
32
32
  class ProductInfo:
33
33
  """Represents a product info provided by an UID response."""
34
34
 
@@ -78,3 +78,6 @@ class ProductInfoStructure(StructureDecoder):
78
78
  ),
79
79
  offset,
80
80
  )
81
+
82
+
83
+ __all__ = ["ATTR_PRODUCT", "ProductInfo", "ProductInfoStructure"]
@@ -84,3 +84,6 @@ class ProgramVersionStructure(Structure):
84
84
  ),
85
85
  offset + VERSION_INFO_SIZE,
86
86
  )
87
+
88
+
89
+ __all__ = ["ATTR_VERSION", "VersionInfo", "ProgramVersionStructure"]
@@ -45,7 +45,7 @@ class RegulatorDataStructure(StructureDecoder):
45
45
  """Decode bytes and return message data and offset."""
46
46
  data = ensure_dict(data)
47
47
  offset += 2
48
- regdata_version = f"{message[offset+1]}.{message[offset]}"
48
+ regdata_version = f"{message[offset + 1]}.{message[offset]}"
49
49
  if regdata_version != REGDATA_VERSION:
50
50
  return data, offset
51
51
 
@@ -63,3 +63,6 @@ class RegulatorDataStructure(StructureDecoder):
63
63
  }
64
64
 
65
65
  return data, self._offset
66
+
67
+
68
+ __all__ = ["ATTR_REGDATA", "REGDATA_VERSION", "RegulatorDataStructure"]
@@ -45,3 +45,6 @@ class RegulatorDataSchemaStructure(StructureDecoder):
45
45
  ),
46
46
  self._offset,
47
47
  )
48
+
49
+
50
+ __all__ = ["ATTR_REGDATA_SCHEMA", "RegulatorDataSchemaStructure"]
@@ -19,7 +19,7 @@ from pyplumio.const import (
19
19
  from pyplumio.devices import Device, PhysicalDevice
20
20
  from pyplumio.exceptions import FrameDataError
21
21
  from pyplumio.frames import Request
22
- from pyplumio.helpers.parameter import (
22
+ from pyplumio.parameters import (
23
23
  Number,
24
24
  NumberDescription,
25
25
  Parameter,
@@ -238,3 +238,20 @@ class SchedulesStructure(Structure):
238
238
  ),
239
239
  self._offset,
240
240
  )
241
+
242
+
243
+ __all__ = [
244
+ "ATTR_SCHEDULES",
245
+ "ATTR_SCHEDULE_PARAMETERS",
246
+ "ATTR_SCHEDULE_SWITCH",
247
+ "ATTR_SCHEDULE_PARAMETER",
248
+ "ScheduleParameterDescription",
249
+ "ScheduleParameter",
250
+ "ScheduleNumberDescription",
251
+ "ScheduleNumber",
252
+ "ScheduleSwitchDescription",
253
+ "ScheduleSwitch",
254
+ "SCHEDULE_PARAMETERS",
255
+ "collect_schedule_data",
256
+ "SchedulesStructure",
257
+ ]
@@ -41,3 +41,12 @@ class StatusesStructure(StructureDecoder):
41
41
  ),
42
42
  offset + STATUSES_SIZE,
43
43
  )
44
+
45
+
46
+ __all__ = [
47
+ "ATTR_HEATING_TARGET",
48
+ "ATTR_HEATING_STATUS",
49
+ "ATTR_WATER_HEATER_TARGET",
50
+ "ATTR_WATER_HEATER_STATUS",
51
+ "StatusesStructure",
52
+ ]
@@ -70,3 +70,25 @@ class TemperaturesStructure(StructureDecoder):
70
70
  data[TEMPERATURES[index]] = temp.value
71
71
 
72
72
  return data, offset
73
+
74
+
75
+ __all__ = [
76
+ "ATTR_HEATING_TEMP",
77
+ "ATTR_FEEDER_TEMP",
78
+ "ATTR_WATER_HEATER_TEMP",
79
+ "ATTR_OUTSIDE_TEMP",
80
+ "ATTR_RETURN_TEMP",
81
+ "ATTR_EXHAUST_TEMP",
82
+ "ATTR_OPTICAL_TEMP",
83
+ "ATTR_UPPER_BUFFER_TEMP",
84
+ "ATTR_LOWER_BUFFER_TEMP",
85
+ "ATTR_UPPER_SOLAR_TEMP",
86
+ "ATTR_LOWER_SOLAR_TEMP",
87
+ "ATTR_FIREPLACE_TEMP",
88
+ "ATTR_TOTAL_GAIN",
89
+ "ATTR_HYDRAULIC_COUPLER_TEMP",
90
+ "ATTR_EXCHANGER_TEMP",
91
+ "ATTR_AIR_IN_TEMP",
92
+ "ATTR_AIR_OUT_TEMP",
93
+ "TemperaturesStructure",
94
+ ]