PyPlumIO 0.6.1__py3-none-any.whl → 0.6.2__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.
- pyplumio/__init__.py +3 -1
- pyplumio/_version.py +2 -2
- pyplumio/const.py +0 -5
- pyplumio/data_types.py +2 -2
- pyplumio/devices/__init__.py +23 -5
- pyplumio/devices/ecomax.py +30 -53
- pyplumio/devices/ecoster.py +2 -3
- pyplumio/filters.py +199 -136
- pyplumio/frames/__init__.py +101 -15
- pyplumio/frames/messages.py +8 -65
- pyplumio/frames/requests.py +38 -38
- pyplumio/frames/responses.py +30 -86
- pyplumio/helpers/async_cache.py +13 -8
- pyplumio/helpers/event_manager.py +24 -18
- pyplumio/helpers/factory.py +0 -3
- pyplumio/parameters/__init__.py +38 -35
- pyplumio/protocol.py +14 -8
- pyplumio/structures/alerts.py +2 -2
- pyplumio/structures/ecomax_parameters.py +1 -1
- pyplumio/structures/frame_versions.py +3 -2
- pyplumio/structures/mixer_parameters.py +5 -3
- pyplumio/structures/network_info.py +1 -0
- pyplumio/structures/product_info.py +1 -1
- pyplumio/structures/program_version.py +2 -2
- pyplumio/structures/schedules.py +8 -40
- pyplumio/structures/sensor_data.py +498 -0
- pyplumio/structures/thermostat_parameters.py +7 -4
- pyplumio/utils.py +41 -4
- {pyplumio-0.6.1.dist-info → pyplumio-0.6.2.dist-info}/METADATA +4 -4
- pyplumio-0.6.2.dist-info/RECORD +50 -0
- pyplumio/structures/boiler_load.py +0 -32
- pyplumio/structures/boiler_power.py +0 -33
- pyplumio/structures/fan_power.py +0 -33
- pyplumio/structures/fuel_consumption.py +0 -36
- pyplumio/structures/fuel_level.py +0 -39
- pyplumio/structures/lambda_sensor.py +0 -57
- pyplumio/structures/mixer_sensors.py +0 -80
- pyplumio/structures/modules.py +0 -102
- pyplumio/structures/output_flags.py +0 -47
- pyplumio/structures/outputs.py +0 -88
- pyplumio/structures/pending_alerts.py +0 -28
- pyplumio/structures/statuses.py +0 -52
- pyplumio/structures/temperatures.py +0 -94
- pyplumio/structures/thermostat_sensors.py +0 -106
- pyplumio-0.6.1.dist-info/RECORD +0 -63
- {pyplumio-0.6.1.dist-info → pyplumio-0.6.2.dist-info}/WHEEL +0 -0
- {pyplumio-0.6.1.dist-info → pyplumio-0.6.2.dist-info}/licenses/LICENSE +0 -0
- {pyplumio-0.6.1.dist-info → pyplumio-0.6.2.dist-info}/top_level.txt +0 -0
@@ -1,32 +0,0 @@
|
|
1
|
-
"""Contains a boiler load structure decoder."""
|
2
|
-
|
3
|
-
from __future__ import annotations
|
4
|
-
|
5
|
-
from typing import Any, Final
|
6
|
-
|
7
|
-
from pyplumio.const import BYTE_UNDEFINED
|
8
|
-
from pyplumio.structures import StructureDecoder
|
9
|
-
from pyplumio.utils import ensure_dict
|
10
|
-
|
11
|
-
ATTR_BOILER_LOAD: Final = "boiler_load"
|
12
|
-
|
13
|
-
|
14
|
-
class BoilerLoadStructure(StructureDecoder):
|
15
|
-
"""Represents a boiler load sensor data structure."""
|
16
|
-
|
17
|
-
__slots__ = ()
|
18
|
-
|
19
|
-
def decode(
|
20
|
-
self, message: bytearray, offset: int = 0, data: dict[str, Any] | None = None
|
21
|
-
) -> tuple[dict[str, Any], int]:
|
22
|
-
"""Decode bytes and return message data and offset."""
|
23
|
-
boiler_load = message[offset]
|
24
|
-
offset += 1
|
25
|
-
|
26
|
-
if boiler_load == BYTE_UNDEFINED:
|
27
|
-
return ensure_dict(data), offset
|
28
|
-
|
29
|
-
return (ensure_dict(data, {ATTR_BOILER_LOAD: boiler_load}), offset)
|
30
|
-
|
31
|
-
|
32
|
-
__all__ = ["ATTR_BOILER_LOAD", "BoilerLoadStructure"]
|
@@ -1,33 +0,0 @@
|
|
1
|
-
"""Contains a boiler power structure decoder."""
|
2
|
-
|
3
|
-
from __future__ import annotations
|
4
|
-
|
5
|
-
import math
|
6
|
-
from typing import Any, Final
|
7
|
-
|
8
|
-
from pyplumio.data_types import Float
|
9
|
-
from pyplumio.structures import StructureDecoder
|
10
|
-
from pyplumio.utils import ensure_dict
|
11
|
-
|
12
|
-
ATTR_BOILER_POWER: Final = "boiler_power"
|
13
|
-
|
14
|
-
|
15
|
-
class BoilerPowerStructure(StructureDecoder):
|
16
|
-
"""Represents a boiler power sensor data structure."""
|
17
|
-
|
18
|
-
__slots__ = ()
|
19
|
-
|
20
|
-
def decode(
|
21
|
-
self, message: bytearray, offset: int = 0, data: dict[str, Any] | None = None
|
22
|
-
) -> tuple[dict[str, Any], int]:
|
23
|
-
"""Decode bytes and return message data and offset."""
|
24
|
-
boiler_power = Float.from_bytes(message, offset)
|
25
|
-
offset += boiler_power.size
|
26
|
-
|
27
|
-
if math.isnan(boiler_power.value):
|
28
|
-
return ensure_dict(data), offset
|
29
|
-
|
30
|
-
return ensure_dict(data, {ATTR_BOILER_POWER: boiler_power.value}), offset
|
31
|
-
|
32
|
-
|
33
|
-
__all__ = ["ATTR_BOILER_POWER", "BoilerPowerStructure"]
|
pyplumio/structures/fan_power.py
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
"""Contains a fan power structure decoder."""
|
2
|
-
|
3
|
-
from __future__ import annotations
|
4
|
-
|
5
|
-
import math
|
6
|
-
from typing import Any, Final
|
7
|
-
|
8
|
-
from pyplumio.data_types import Float
|
9
|
-
from pyplumio.structures import StructureDecoder
|
10
|
-
from pyplumio.utils import ensure_dict
|
11
|
-
|
12
|
-
ATTR_FAN_POWER: Final = "fan_power"
|
13
|
-
|
14
|
-
|
15
|
-
class FanPowerStructure(StructureDecoder):
|
16
|
-
"""Represents a fan power sensor data structure."""
|
17
|
-
|
18
|
-
__slots__ = ()
|
19
|
-
|
20
|
-
def decode(
|
21
|
-
self, message: bytearray, offset: int = 0, data: dict[str, Any] | None = None
|
22
|
-
) -> tuple[dict[str, Any], int]:
|
23
|
-
"""Decode bytes and return message data and offset."""
|
24
|
-
fan_power = Float.from_bytes(message, offset)
|
25
|
-
offset += fan_power.size
|
26
|
-
|
27
|
-
if math.isnan(fan_power.value):
|
28
|
-
return ensure_dict(data), offset
|
29
|
-
|
30
|
-
return ensure_dict(data, {ATTR_FAN_POWER: fan_power.value}), offset
|
31
|
-
|
32
|
-
|
33
|
-
__all__ = ["ATTR_FAN_POWER", "FanPowerStructure"]
|
@@ -1,36 +0,0 @@
|
|
1
|
-
"""Contains fuel consumption structure decoder."""
|
2
|
-
|
3
|
-
from __future__ import annotations
|
4
|
-
|
5
|
-
import math
|
6
|
-
from typing import Any, Final
|
7
|
-
|
8
|
-
from pyplumio.data_types import Float
|
9
|
-
from pyplumio.structures import StructureDecoder
|
10
|
-
from pyplumio.utils import ensure_dict
|
11
|
-
|
12
|
-
ATTR_FUEL_CONSUMPTION: Final = "fuel_consumption"
|
13
|
-
|
14
|
-
|
15
|
-
class FuelConsumptionStructure(StructureDecoder):
|
16
|
-
"""Represents a fuel consumption sensor data structure."""
|
17
|
-
|
18
|
-
__slots__ = ()
|
19
|
-
|
20
|
-
def decode(
|
21
|
-
self, message: bytearray, offset: int = 0, data: dict[str, Any] | None = None
|
22
|
-
) -> tuple[dict[str, Any], int]:
|
23
|
-
"""Decode bytes and return message data and offset."""
|
24
|
-
fuel_consumption = Float.from_bytes(message, offset)
|
25
|
-
offset += fuel_consumption.size
|
26
|
-
|
27
|
-
if math.isnan(fuel_consumption.value):
|
28
|
-
return ensure_dict(data), offset
|
29
|
-
|
30
|
-
return (
|
31
|
-
ensure_dict(data, {ATTR_FUEL_CONSUMPTION: fuel_consumption.value}),
|
32
|
-
offset,
|
33
|
-
)
|
34
|
-
|
35
|
-
|
36
|
-
__all__ = ["ATTR_FUEL_CONSUMPTION", "FuelConsumptionStructure"]
|
@@ -1,39 +0,0 @@
|
|
1
|
-
"""Contains a fuel level structure decoder."""
|
2
|
-
|
3
|
-
from __future__ import annotations
|
4
|
-
|
5
|
-
from typing import Any, Final
|
6
|
-
|
7
|
-
from pyplumio.const import BYTE_UNDEFINED
|
8
|
-
from pyplumio.structures import StructureDecoder
|
9
|
-
from pyplumio.utils import ensure_dict
|
10
|
-
|
11
|
-
ATTR_FUEL_LEVEL: Final = "fuel_level"
|
12
|
-
|
13
|
-
FUEL_LEVEL_OFFSET: Final = 101
|
14
|
-
|
15
|
-
|
16
|
-
class FuelLevelStructure(StructureDecoder):
|
17
|
-
"""Represents a fuel level sensor data structure."""
|
18
|
-
|
19
|
-
__slots__ = ()
|
20
|
-
|
21
|
-
def decode(
|
22
|
-
self, message: bytearray, offset: int = 0, data: dict[str, Any] | None = None
|
23
|
-
) -> tuple[dict[str, Any], int]:
|
24
|
-
"""Decode bytes and return message data and offset."""
|
25
|
-
fuel_level = message[offset]
|
26
|
-
offset += 1
|
27
|
-
|
28
|
-
if fuel_level == BYTE_UNDEFINED:
|
29
|
-
return ensure_dict(data), offset
|
30
|
-
|
31
|
-
if fuel_level >= FUEL_LEVEL_OFFSET:
|
32
|
-
# Observed on at least ecoMAX 860P6-O.
|
33
|
-
# See: https://github.com/denpamusic/PyPlumIO/issues/19
|
34
|
-
fuel_level -= FUEL_LEVEL_OFFSET
|
35
|
-
|
36
|
-
return (ensure_dict(data, {ATTR_FUEL_LEVEL: fuel_level}), offset)
|
37
|
-
|
38
|
-
|
39
|
-
__all__ = ["ATTR_FUEL_LEVEL", "FuelLevelStructure"]
|
@@ -1,57 +0,0 @@
|
|
1
|
-
"""Contains a lambda sensor structure decoder."""
|
2
|
-
|
3
|
-
from __future__ import annotations
|
4
|
-
|
5
|
-
from contextlib import suppress
|
6
|
-
from typing import Any, Final
|
7
|
-
|
8
|
-
from pyplumio.const import BYTE_UNDEFINED, LambdaState
|
9
|
-
from pyplumio.data_types import UnsignedShort
|
10
|
-
from pyplumio.structures import StructureDecoder
|
11
|
-
from pyplumio.utils import ensure_dict
|
12
|
-
|
13
|
-
ATTR_LAMBDA_STATE: Final = "lambda_state"
|
14
|
-
ATTR_LAMBDA_TARGET: Final = "lambda_target"
|
15
|
-
ATTR_LAMBDA_LEVEL: Final = "lambda_level"
|
16
|
-
|
17
|
-
|
18
|
-
class LambdaSensorStructure(StructureDecoder):
|
19
|
-
"""Represents a lambda sensor data structure."""
|
20
|
-
|
21
|
-
__slots__ = ()
|
22
|
-
|
23
|
-
def decode(
|
24
|
-
self, message: bytearray, offset: int = 0, data: dict[str, Any] | None = None
|
25
|
-
) -> tuple[dict[str, Any], int]:
|
26
|
-
"""Decode bytes and return message data and offset."""
|
27
|
-
lambda_state = message[offset]
|
28
|
-
offset += 1
|
29
|
-
if lambda_state == BYTE_UNDEFINED:
|
30
|
-
return ensure_dict(data), offset
|
31
|
-
|
32
|
-
lambda_target = message[offset]
|
33
|
-
offset += 1
|
34
|
-
level = UnsignedShort.from_bytes(message, offset)
|
35
|
-
offset += level.size
|
36
|
-
with suppress(ValueError):
|
37
|
-
lambda_state = LambdaState(lambda_state)
|
38
|
-
|
39
|
-
return (
|
40
|
-
ensure_dict(
|
41
|
-
data,
|
42
|
-
{
|
43
|
-
ATTR_LAMBDA_STATE: lambda_state,
|
44
|
-
ATTR_LAMBDA_TARGET: lambda_target,
|
45
|
-
ATTR_LAMBDA_LEVEL: level.value / 10,
|
46
|
-
},
|
47
|
-
),
|
48
|
-
offset,
|
49
|
-
)
|
50
|
-
|
51
|
-
|
52
|
-
__all__ = [
|
53
|
-
"ATTR_LAMBDA_STATE",
|
54
|
-
"ATTR_LAMBDA_TARGET",
|
55
|
-
"ATTR_LAMBDA_LEVEL",
|
56
|
-
"LambdaSensorStructure",
|
57
|
-
]
|
@@ -1,80 +0,0 @@
|
|
1
|
-
"""Contains a mixer sensors structure decoder."""
|
2
|
-
|
3
|
-
from __future__ import annotations
|
4
|
-
|
5
|
-
from collections.abc import Generator
|
6
|
-
import math
|
7
|
-
from typing import Any, Final
|
8
|
-
|
9
|
-
from pyplumio.const import ATTR_CURRENT_TEMP, ATTR_TARGET_TEMP
|
10
|
-
from pyplumio.data_types import Float
|
11
|
-
from pyplumio.structures import StructureDecoder
|
12
|
-
from pyplumio.utils import ensure_dict
|
13
|
-
|
14
|
-
ATTR_PUMP: Final = "pump"
|
15
|
-
ATTR_MIXERS_AVAILABLE: Final = "mixers_available"
|
16
|
-
ATTR_MIXERS_CONNECTED: Final = "mixers_connected"
|
17
|
-
ATTR_MIXER_SENSORS: Final = "mixer_sensors"
|
18
|
-
|
19
|
-
MIXER_SENSOR_SIZE: Final = 8
|
20
|
-
|
21
|
-
|
22
|
-
class MixerSensorsStructure(StructureDecoder):
|
23
|
-
"""Represents a mixer sensors data structure."""
|
24
|
-
|
25
|
-
__slots__ = ("_offset",)
|
26
|
-
|
27
|
-
_offset: int
|
28
|
-
|
29
|
-
def _unpack_mixer_sensors(self, message: bytearray) -> dict[str, Any] | None:
|
30
|
-
"""Unpack sensors for a mixer."""
|
31
|
-
offset = self._offset
|
32
|
-
current_temp = Float.from_bytes(message, offset)
|
33
|
-
try:
|
34
|
-
return (
|
35
|
-
{
|
36
|
-
ATTR_CURRENT_TEMP: current_temp.value,
|
37
|
-
ATTR_TARGET_TEMP: message[offset + 4],
|
38
|
-
ATTR_PUMP: bool(message[offset + 6] & 0x01),
|
39
|
-
}
|
40
|
-
if not math.isnan(current_temp.value)
|
41
|
-
else None
|
42
|
-
)
|
43
|
-
finally:
|
44
|
-
self._offset = offset + MIXER_SENSOR_SIZE
|
45
|
-
|
46
|
-
def _mixer_sensors(
|
47
|
-
self, message: bytearray, mixers: int
|
48
|
-
) -> Generator[tuple[int, dict[str, Any]], None, None]:
|
49
|
-
"""Get sensors for a mixer."""
|
50
|
-
for index in range(mixers):
|
51
|
-
if sensors := self._unpack_mixer_sensors(message):
|
52
|
-
yield (index, sensors)
|
53
|
-
|
54
|
-
def decode(
|
55
|
-
self, message: bytearray, offset: int = 0, data: dict[str, Any] | None = None
|
56
|
-
) -> tuple[dict[str, Any], int]:
|
57
|
-
"""Decode bytes and return message data and offset."""
|
58
|
-
mixers = message[offset]
|
59
|
-
self._offset = offset + 1
|
60
|
-
mixer_sensors = dict(self._mixer_sensors(message, mixers))
|
61
|
-
return (
|
62
|
-
ensure_dict(
|
63
|
-
data,
|
64
|
-
{
|
65
|
-
ATTR_MIXER_SENSORS: mixer_sensors,
|
66
|
-
ATTR_MIXERS_AVAILABLE: mixers,
|
67
|
-
ATTR_MIXERS_CONNECTED: len(mixer_sensors),
|
68
|
-
},
|
69
|
-
),
|
70
|
-
self._offset,
|
71
|
-
)
|
72
|
-
|
73
|
-
|
74
|
-
__all__ = [
|
75
|
-
"ATTR_PUMP",
|
76
|
-
"ATTR_MIXERS_AVAILABLE",
|
77
|
-
"ATTR_MIXERS_CONNECTED",
|
78
|
-
"ATTR_MIXER_SENSORS",
|
79
|
-
"MixerSensorsStructure",
|
80
|
-
]
|
pyplumio/structures/modules.py
DELETED
@@ -1,102 +0,0 @@
|
|
1
|
-
"""Contains a modules structure decoder."""
|
2
|
-
|
3
|
-
from __future__ import annotations
|
4
|
-
|
5
|
-
from dataclasses import dataclass
|
6
|
-
import struct
|
7
|
-
from typing import Any, Final
|
8
|
-
|
9
|
-
from pyplumio.const import BYTE_UNDEFINED
|
10
|
-
from pyplumio.structures import StructureDecoder
|
11
|
-
from pyplumio.utils import ensure_dict
|
12
|
-
|
13
|
-
ATTR_MODULES: Final = "modules"
|
14
|
-
ATTR_MODULE_A: Final = "module_a"
|
15
|
-
ATTR_MODULE_B: Final = "module_b"
|
16
|
-
ATTR_MODULE_C: Final = "module_c"
|
17
|
-
ATTR_ECOLAMBDA: Final = "ecolambda"
|
18
|
-
ATTR_ECOSTER: Final = "ecoster"
|
19
|
-
ATTR_PANEL: Final = "panel"
|
20
|
-
MODULES: tuple[str, ...] = (
|
21
|
-
ATTR_MODULE_A,
|
22
|
-
ATTR_MODULE_B,
|
23
|
-
ATTR_MODULE_C,
|
24
|
-
ATTR_ECOLAMBDA,
|
25
|
-
ATTR_ECOSTER,
|
26
|
-
ATTR_PANEL,
|
27
|
-
)
|
28
|
-
|
29
|
-
struct_version = struct.Struct("<BBB")
|
30
|
-
struct_vendor = struct.Struct("<BB")
|
31
|
-
|
32
|
-
|
33
|
-
@dataclass(slots=True)
|
34
|
-
class ConnectedModules:
|
35
|
-
"""Represents a firmware version info for connected module."""
|
36
|
-
|
37
|
-
module_a: str | None = None
|
38
|
-
module_b: str | None = None
|
39
|
-
module_c: str | None = None
|
40
|
-
ecolambda: str | None = None
|
41
|
-
ecoster: str | None = None
|
42
|
-
panel: str | None = None
|
43
|
-
|
44
|
-
|
45
|
-
class ModulesStructure(StructureDecoder):
|
46
|
-
"""Represents a modules data structure."""
|
47
|
-
|
48
|
-
__slots__ = ("_offset",)
|
49
|
-
|
50
|
-
_offset: int
|
51
|
-
|
52
|
-
def _unpack_module_version(self, module: str, message: bytearray) -> str | None:
|
53
|
-
"""Unpack a module version."""
|
54
|
-
if message[self._offset] == BYTE_UNDEFINED:
|
55
|
-
self._offset += 1
|
56
|
-
return None
|
57
|
-
|
58
|
-
offset = self._offset
|
59
|
-
version_data = struct_version.unpack_from(message, offset)
|
60
|
-
version = ".".join(str(i) for i in version_data)
|
61
|
-
offset += struct_version.size
|
62
|
-
if module == ATTR_MODULE_A:
|
63
|
-
vendor_code, vendor_version = struct_vendor.unpack_from(message, offset)
|
64
|
-
version += f".{chr(vendor_code) + str(vendor_version)}"
|
65
|
-
offset += struct_vendor.size
|
66
|
-
|
67
|
-
self._offset = offset
|
68
|
-
return version
|
69
|
-
|
70
|
-
def decode(
|
71
|
-
self, message: bytearray, offset: int = 0, data: dict[str, Any] | None = None
|
72
|
-
) -> tuple[dict[str, Any], int]:
|
73
|
-
"""Decode bytes and return message data and offset."""
|
74
|
-
self._offset = offset
|
75
|
-
return (
|
76
|
-
ensure_dict(
|
77
|
-
data,
|
78
|
-
{
|
79
|
-
ATTR_MODULES: ConnectedModules(
|
80
|
-
**{
|
81
|
-
module: self._unpack_module_version(module, message)
|
82
|
-
for module in MODULES
|
83
|
-
}
|
84
|
-
)
|
85
|
-
},
|
86
|
-
),
|
87
|
-
self._offset,
|
88
|
-
)
|
89
|
-
|
90
|
-
|
91
|
-
__all__ = [
|
92
|
-
"ATTR_MODULES",
|
93
|
-
"ATTR_MODULE_A",
|
94
|
-
"ATTR_MODULE_B",
|
95
|
-
"ATTR_MODULE_C",
|
96
|
-
"ATTR_ECOLAMBDA",
|
97
|
-
"ATTR_ECOSTER",
|
98
|
-
"ATTR_PANEL",
|
99
|
-
"MODULES",
|
100
|
-
"ConnectedModules",
|
101
|
-
"ModulesStructure",
|
102
|
-
]
|
@@ -1,47 +0,0 @@
|
|
1
|
-
"""Contains an output flags structure decoder."""
|
2
|
-
|
3
|
-
from __future__ import annotations
|
4
|
-
|
5
|
-
from typing import Any, Final
|
6
|
-
|
7
|
-
from pyplumio.data_types import UnsignedInt
|
8
|
-
from pyplumio.structures import StructureDecoder
|
9
|
-
from pyplumio.utils import ensure_dict
|
10
|
-
|
11
|
-
ATTR_HEATING_PUMP_FLAG: Final = "heating_pump_flag"
|
12
|
-
ATTR_WATER_HEATER_PUMP_FLAG: Final = "water_heater_pump_flag"
|
13
|
-
ATTR_CIRCULATION_PUMP_FLAG: Final = "circulation_pump_flag"
|
14
|
-
ATTR_SOLAR_PUMP_FLAG: Final = "solar_pump_flag"
|
15
|
-
|
16
|
-
|
17
|
-
class OutputFlagsStructure(StructureDecoder):
|
18
|
-
"""Represents an output flags structure."""
|
19
|
-
|
20
|
-
__slots__ = ()
|
21
|
-
|
22
|
-
def decode(
|
23
|
-
self, message: bytearray, offset: int = 0, data: dict[str, Any] | None = None
|
24
|
-
) -> tuple[dict[str, Any], int]:
|
25
|
-
"""Decode bytes and return message data and offset."""
|
26
|
-
output_flags = UnsignedInt.from_bytes(message, offset)
|
27
|
-
return (
|
28
|
-
ensure_dict(
|
29
|
-
data,
|
30
|
-
{
|
31
|
-
ATTR_HEATING_PUMP_FLAG: bool(output_flags.value & 0x04),
|
32
|
-
ATTR_WATER_HEATER_PUMP_FLAG: bool(output_flags.value & 0x08),
|
33
|
-
ATTR_CIRCULATION_PUMP_FLAG: bool(output_flags.value & 0x10),
|
34
|
-
ATTR_SOLAR_PUMP_FLAG: bool(output_flags.value & 0x800),
|
35
|
-
},
|
36
|
-
),
|
37
|
-
offset + output_flags.size,
|
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
|
-
]
|
pyplumio/structures/outputs.py
DELETED
@@ -1,88 +0,0 @@
|
|
1
|
-
"""Contains an outputs structure decoder."""
|
2
|
-
|
3
|
-
from __future__ import annotations
|
4
|
-
|
5
|
-
from typing import Any, Final
|
6
|
-
|
7
|
-
from pyplumio.data_types import UnsignedInt
|
8
|
-
from pyplumio.structures import StructureDecoder
|
9
|
-
from pyplumio.utils import ensure_dict
|
10
|
-
|
11
|
-
ATTR_FAN: Final = "fan"
|
12
|
-
ATTR_FEEDER: Final = "feeder"
|
13
|
-
ATTR_HEATING_PUMP: Final = "heating_pump"
|
14
|
-
ATTR_WATER_HEATER_PUMP: Final = "water_heater_pump"
|
15
|
-
ATTR_CIRCULATION_PUMP: Final = "circulation_pump"
|
16
|
-
ATTR_LIGHTER: Final = "lighter"
|
17
|
-
ATTR_ALARM: Final = "alarm"
|
18
|
-
ATTR_OUTER_BOILER: Final = "outer_boiler"
|
19
|
-
ATTR_FAN2_EXHAUST: Final = "fan2_exhaust"
|
20
|
-
ATTR_FEEDER2: Final = "feeder2"
|
21
|
-
ATTR_OUTER_FEEDER: Final = "outer_feeder"
|
22
|
-
ATTR_SOLAR_PUMP: Final = "solar_pump"
|
23
|
-
ATTR_FIREPLACE_PUMP: Final = "fireplace_pump"
|
24
|
-
ATTR_GCZ_CONTACT: Final = "gcz_contact"
|
25
|
-
ATTR_BLOW_FAN1: Final = "blow_fan1"
|
26
|
-
ATTR_BLOW_FAN2: Final = "blow_fan2"
|
27
|
-
|
28
|
-
OUTPUTS: tuple[str, ...] = (
|
29
|
-
ATTR_FAN,
|
30
|
-
ATTR_FEEDER,
|
31
|
-
ATTR_HEATING_PUMP,
|
32
|
-
ATTR_WATER_HEATER_PUMP,
|
33
|
-
ATTR_CIRCULATION_PUMP,
|
34
|
-
ATTR_LIGHTER,
|
35
|
-
ATTR_ALARM,
|
36
|
-
ATTR_OUTER_BOILER,
|
37
|
-
ATTR_FAN2_EXHAUST,
|
38
|
-
ATTR_FEEDER2,
|
39
|
-
ATTR_OUTER_FEEDER,
|
40
|
-
ATTR_SOLAR_PUMP,
|
41
|
-
ATTR_FIREPLACE_PUMP,
|
42
|
-
ATTR_GCZ_CONTACT,
|
43
|
-
ATTR_BLOW_FAN1,
|
44
|
-
ATTR_BLOW_FAN2,
|
45
|
-
)
|
46
|
-
|
47
|
-
|
48
|
-
class OutputsStructure(StructureDecoder):
|
49
|
-
"""Represents an outputs data structure."""
|
50
|
-
|
51
|
-
__slots__ = ()
|
52
|
-
|
53
|
-
def decode(
|
54
|
-
self, message: bytearray, offset: int = 0, data: dict[str, Any] | None = None
|
55
|
-
) -> tuple[dict[str, Any], int]:
|
56
|
-
"""Decode bytes and return message data and offset."""
|
57
|
-
outputs = UnsignedInt.from_bytes(message, offset)
|
58
|
-
return (
|
59
|
-
ensure_dict(
|
60
|
-
data,
|
61
|
-
{
|
62
|
-
output: bool(outputs.value & 2**index)
|
63
|
-
for index, output in enumerate(OUTPUTS)
|
64
|
-
},
|
65
|
-
),
|
66
|
-
offset + outputs.size,
|
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
|
-
]
|
@@ -1,28 +0,0 @@
|
|
1
|
-
"""Contains a pending alerts structure decoder."""
|
2
|
-
|
3
|
-
from __future__ import annotations
|
4
|
-
|
5
|
-
from typing import Any, Final
|
6
|
-
|
7
|
-
from pyplumio.structures import StructureDecoder
|
8
|
-
from pyplumio.utils import ensure_dict
|
9
|
-
|
10
|
-
ATTR_PENDING_ALERTS: Final = "pending_alerts"
|
11
|
-
|
12
|
-
|
13
|
-
class PendingAlertsStructure(StructureDecoder):
|
14
|
-
"""Represents a pending alerts structure."""
|
15
|
-
|
16
|
-
__slots__ = ()
|
17
|
-
|
18
|
-
def decode(
|
19
|
-
self, message: bytearray, offset: int = 0, data: dict[str, Any] | None = None
|
20
|
-
) -> tuple[dict[str, Any], int]:
|
21
|
-
"""Decode bytes and return message data and offset."""
|
22
|
-
alerts_number = message[offset]
|
23
|
-
return ensure_dict(data, {ATTR_PENDING_ALERTS: alerts_number}), (
|
24
|
-
offset + alerts_number + 1
|
25
|
-
)
|
26
|
-
|
27
|
-
|
28
|
-
__all__ = ["ATTR_PENDING_ALERTS", "PendingAlertsStructure"]
|
pyplumio/structures/statuses.py
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
"""Contains a statuses structure decoder."""
|
2
|
-
|
3
|
-
from __future__ import annotations
|
4
|
-
|
5
|
-
from typing import Any, Final
|
6
|
-
|
7
|
-
from pyplumio.structures import StructureDecoder
|
8
|
-
from pyplumio.utils import ensure_dict
|
9
|
-
|
10
|
-
ATTR_HEATING_TARGET: Final = "heating_target"
|
11
|
-
ATTR_HEATING_STATUS: Final = "heating_status"
|
12
|
-
ATTR_WATER_HEATER_TARGET: Final = "water_heater_target"
|
13
|
-
ATTR_WATER_HEATER_STATUS: Final = "water_heater_status"
|
14
|
-
|
15
|
-
STATUSES: tuple[str, ...] = (
|
16
|
-
ATTR_HEATING_TARGET,
|
17
|
-
ATTR_HEATING_STATUS,
|
18
|
-
ATTR_WATER_HEATER_TARGET,
|
19
|
-
ATTR_WATER_HEATER_STATUS,
|
20
|
-
)
|
21
|
-
|
22
|
-
STATUSES_SIZE: Final = 4
|
23
|
-
|
24
|
-
|
25
|
-
class StatusesStructure(StructureDecoder):
|
26
|
-
"""Represents a statuses data structure."""
|
27
|
-
|
28
|
-
__slots__ = ()
|
29
|
-
|
30
|
-
def decode(
|
31
|
-
self, message: bytearray, offset: int = 0, data: dict[str, Any] | None = None
|
32
|
-
) -> tuple[dict[str, Any], int]:
|
33
|
-
"""Decode bytes and return message data and offset."""
|
34
|
-
return (
|
35
|
-
ensure_dict(
|
36
|
-
data,
|
37
|
-
{
|
38
|
-
status: message[offset + index]
|
39
|
-
for index, status in enumerate(STATUSES)
|
40
|
-
},
|
41
|
-
),
|
42
|
-
offset + STATUSES_SIZE,
|
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
|
-
]
|