PyPlumIO 0.5.18__py3-none-any.whl → 0.5.20__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-0.5.18.dist-info → PyPlumIO-0.5.20.dist-info}/METADATA +8 -8
- PyPlumIO-0.5.20.dist-info/RECORD +61 -0
- pyplumio/__init__.py +1 -0
- pyplumio/__main__.py +1 -0
- pyplumio/_version.py +2 -2
- pyplumio/connection.py +2 -4
- pyplumio/const.py +1 -0
- pyplumio/devices/__init__.py +31 -22
- pyplumio/devices/ecomax.py +3 -11
- pyplumio/devices/ecoster.py +1 -0
- pyplumio/devices/mixer.py +1 -0
- pyplumio/devices/thermostat.py +1 -0
- pyplumio/exceptions.py +1 -0
- pyplumio/filters.py +8 -10
- pyplumio/frames/__init__.py +35 -28
- pyplumio/frames/messages.py +1 -0
- pyplumio/frames/requests.py +1 -0
- pyplumio/frames/responses.py +1 -0
- pyplumio/helpers/data_types.py +1 -0
- pyplumio/helpers/event_manager.py +1 -5
- pyplumio/helpers/factory.py +10 -3
- pyplumio/helpers/parameter.py +1 -0
- pyplumio/helpers/schedule.py +11 -7
- pyplumio/helpers/task_manager.py +1 -0
- pyplumio/helpers/timeout.py +7 -20
- pyplumio/helpers/typing.py +1 -0
- pyplumio/helpers/uid.py +1 -0
- pyplumio/protocol.py +63 -81
- pyplumio/stream.py +41 -38
- pyplumio/structures/__init__.py +1 -0
- pyplumio/structures/alerts.py +1 -0
- pyplumio/structures/boiler_load.py +1 -0
- pyplumio/structures/boiler_power.py +1 -0
- pyplumio/structures/ecomax_parameters.py +8 -8
- pyplumio/structures/fan_power.py +1 -0
- pyplumio/structures/frame_versions.py +1 -0
- pyplumio/structures/fuel_consumption.py +1 -0
- pyplumio/structures/fuel_level.py +1 -0
- pyplumio/structures/lambda_sensor.py +1 -0
- pyplumio/structures/mixer_parameters.py +11 -13
- pyplumio/structures/mixer_sensors.py +1 -0
- pyplumio/structures/modules.py +1 -0
- pyplumio/structures/network_info.py +1 -0
- pyplumio/structures/output_flags.py +1 -0
- pyplumio/structures/outputs.py +1 -0
- pyplumio/structures/pending_alerts.py +1 -0
- pyplumio/structures/product_info.py +1 -0
- pyplumio/structures/program_version.py +3 -2
- pyplumio/structures/regulator_data.py +3 -4
- pyplumio/structures/regulator_data_schema.py +1 -0
- pyplumio/structures/schedules.py +14 -11
- pyplumio/structures/statuses.py +1 -0
- pyplumio/structures/temperatures.py +1 -0
- pyplumio/structures/thermostat_parameters.py +17 -22
- pyplumio/structures/thermostat_sensors.py +1 -0
- pyplumio/utils.py +1 -0
- PyPlumIO-0.5.18.dist-info/RECORD +0 -61
- {PyPlumIO-0.5.18.dist-info → PyPlumIO-0.5.20.dist-info}/LICENSE +0 -0
- {PyPlumIO-0.5.18.dist-info → PyPlumIO-0.5.20.dist-info}/WHEEL +0 -0
- {PyPlumIO-0.5.18.dist-info → PyPlumIO-0.5.20.dist-info}/top_level.txt +0 -0
pyplumio/helpers/task_manager.py
CHANGED
pyplumio/helpers/timeout.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
"""Contains a timeout decorator."""
|
2
|
+
|
2
3
|
from __future__ import annotations
|
3
4
|
|
4
5
|
import asyncio
|
@@ -16,30 +17,16 @@ _LOGGER = logging.getLogger(__name__)
|
|
16
17
|
|
17
18
|
|
18
19
|
def timeout(
|
19
|
-
seconds: int,
|
20
|
-
) -> Callable[[Callable[P, Awaitable[T]]], Callable[P, Coroutine[Any, Any, T
|
21
|
-
"""Decorate a timeout for the awaitable.
|
22
|
-
|
23
|
-
Return None on exception if raise_exception parameter is set to false.
|
24
|
-
"""
|
20
|
+
seconds: int,
|
21
|
+
) -> Callable[[Callable[P, Awaitable[T]]], Callable[P, Coroutine[Any, Any, T]]]:
|
22
|
+
"""Decorate a timeout for the awaitable."""
|
25
23
|
|
26
24
|
def decorator(
|
27
25
|
func: Callable[P, Awaitable[T]],
|
28
|
-
) -> Callable[P, Coroutine[Any, Any, T
|
26
|
+
) -> Callable[P, Coroutine[Any, Any, T]]:
|
29
27
|
@wraps(func)
|
30
|
-
async def wrapper(*args: P.args, **kwargs: P.kwargs) -> T
|
31
|
-
|
32
|
-
return await asyncio.wait_for(func(*args, **kwargs), timeout=seconds)
|
33
|
-
except asyncio.TimeoutError:
|
34
|
-
if raise_exception:
|
35
|
-
raise
|
36
|
-
|
37
|
-
_LOGGER.warning(
|
38
|
-
"Function '%s' timed out after %i seconds",
|
39
|
-
func.__name__,
|
40
|
-
seconds,
|
41
|
-
)
|
42
|
-
return None
|
28
|
+
async def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
|
29
|
+
return await asyncio.wait_for(func(*args, **kwargs), timeout=seconds)
|
43
30
|
|
44
31
|
return wrapper
|
45
32
|
|
pyplumio/helpers/typing.py
CHANGED
pyplumio/helpers/uid.py
CHANGED
pyplumio/protocol.py
CHANGED
@@ -1,24 +1,19 @@
|
|
1
1
|
"""Contains protocol representation."""
|
2
|
+
|
2
3
|
from __future__ import annotations
|
3
4
|
|
4
5
|
from abc import ABC, abstractmethod
|
5
6
|
import asyncio
|
6
7
|
from collections.abc import Awaitable, Callable
|
8
|
+
from dataclasses import dataclass
|
7
9
|
import logging
|
8
|
-
from typing import cast
|
9
10
|
|
10
11
|
from pyplumio.const import ATTR_CONNECTED, DeviceType
|
11
|
-
from pyplumio.devices import AddressableDevice
|
12
|
-
from pyplumio.exceptions import
|
13
|
-
FrameDataError,
|
14
|
-
FrameError,
|
15
|
-
ReadError,
|
16
|
-
UnknownDeviceError,
|
17
|
-
)
|
12
|
+
from pyplumio.devices import AddressableDevice
|
13
|
+
from pyplumio.exceptions import FrameError, ReadError, UnknownDeviceError
|
18
14
|
from pyplumio.frames import Frame
|
19
15
|
from pyplumio.frames.requests import StartMasterRequest
|
20
16
|
from pyplumio.helpers.event_manager import EventManager
|
21
|
-
from pyplumio.helpers.factory import create_instance
|
22
17
|
from pyplumio.stream import FrameReader, FrameWriter
|
23
18
|
from pyplumio.structures.network_info import (
|
24
19
|
EthernetParameters,
|
@@ -101,49 +96,56 @@ class DummyProtocol(Protocol):
|
|
101
96
|
await self.close_writer()
|
102
97
|
|
103
98
|
|
99
|
+
@dataclass
|
100
|
+
class Queues:
|
101
|
+
"""Represents asyncio queues."""
|
102
|
+
|
103
|
+
__slots__ = ("read", "write")
|
104
|
+
|
105
|
+
read: asyncio.Queue
|
106
|
+
write: asyncio.Queue
|
107
|
+
|
108
|
+
async def join(self) -> None:
|
109
|
+
"""Wait for queues to finish."""
|
110
|
+
for queue in (self.read, self.write):
|
111
|
+
await queue.join()
|
112
|
+
|
113
|
+
|
104
114
|
class AsyncProtocol(Protocol, EventManager):
|
105
115
|
"""Represents an async protocol.
|
106
116
|
|
107
117
|
This protocol implements producer-consumers pattern using
|
108
118
|
asyncio queues.
|
109
119
|
|
110
|
-
The frame producer tries to read frames from write queue
|
111
|
-
available,
|
120
|
+
The frame producer tries to read frames from the write queue.
|
121
|
+
If any is available, it sends them to the device via frame writer.
|
112
122
|
|
113
|
-
It reads stream via frame reader
|
114
|
-
|
123
|
+
It then reads stream via frame reader and puts received frame
|
124
|
+
into the read queue.
|
115
125
|
|
116
|
-
Frame consumers
|
117
|
-
|
126
|
+
Frame consumers read frames from the read queue, create device
|
127
|
+
entry, if needed, and send frame to the entry for the processing.
|
118
128
|
"""
|
119
129
|
|
130
|
+
consumers_count: int
|
120
131
|
data: dict[str, AddressableDevice]
|
121
|
-
consumers_number: int
|
122
132
|
_network: NetworkInfo
|
123
|
-
_queues:
|
133
|
+
_queues: Queues
|
124
134
|
|
125
135
|
def __init__(
|
126
136
|
self,
|
127
137
|
ethernet_parameters: EthernetParameters | None = None,
|
128
138
|
wireless_parameters: WirelessParameters | None = None,
|
129
|
-
|
139
|
+
consumers_count: int = 3,
|
130
140
|
) -> None:
|
131
141
|
"""Initialize a new async protocol."""
|
132
142
|
super().__init__()
|
133
|
-
self.
|
143
|
+
self.consumers_count = consumers_count
|
134
144
|
self._network = NetworkInfo(
|
135
|
-
eth=(
|
136
|
-
|
137
|
-
if ethernet_parameters is None
|
138
|
-
else ethernet_parameters
|
139
|
-
),
|
140
|
-
wlan=(
|
141
|
-
WirelessParameters(status=False)
|
142
|
-
if wireless_parameters is None
|
143
|
-
else wireless_parameters
|
144
|
-
),
|
145
|
+
eth=ethernet_parameters or EthernetParameters(status=False),
|
146
|
+
wlan=wireless_parameters or WirelessParameters(status=False),
|
145
147
|
)
|
146
|
-
self._queues = (asyncio.Queue(), asyncio.Queue())
|
148
|
+
self._queues = Queues(read=asyncio.Queue(), write=asyncio.Queue())
|
147
149
|
|
148
150
|
def connection_established(
|
149
151
|
self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter
|
@@ -151,11 +153,12 @@ class AsyncProtocol(Protocol, EventManager):
|
|
151
153
|
"""Start frame producer and consumers."""
|
152
154
|
self.reader = FrameReader(reader)
|
153
155
|
self.writer = FrameWriter(writer)
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
156
|
+
self._queues.write.put_nowait(StartMasterRequest(recipient=DeviceType.ECOMAX))
|
157
|
+
self.create_task(
|
158
|
+
self.frame_producer(self._queues, reader=self.reader, writer=self.writer)
|
159
|
+
)
|
160
|
+
for _ in range(self.consumers_count):
|
161
|
+
self.create_task(self.frame_consumer(self._queues.read))
|
159
162
|
|
160
163
|
for device in self.data.values():
|
161
164
|
device.dispatch_nowait(ATTR_CONNECTED, True)
|
@@ -178,8 +181,9 @@ class AsyncProtocol(Protocol, EventManager):
|
|
178
181
|
|
179
182
|
async def shutdown(self) -> None:
|
180
183
|
"""Shutdown protocol tasks."""
|
181
|
-
await
|
182
|
-
|
184
|
+
await self._queues.join()
|
185
|
+
self.cancel_tasks()
|
186
|
+
await self.wait_until_done()
|
183
187
|
for device in self.data.values():
|
184
188
|
await device.shutdown()
|
185
189
|
|
@@ -188,68 +192,46 @@ class AsyncProtocol(Protocol, EventManager):
|
|
188
192
|
await self.close_writer()
|
189
193
|
|
190
194
|
async def frame_producer(
|
191
|
-
self,
|
195
|
+
self, queues: Queues, reader: FrameReader, writer: FrameWriter
|
192
196
|
) -> None:
|
193
197
|
"""Handle frame reads and writes."""
|
194
198
|
await self.connected.wait()
|
195
|
-
reader = cast(FrameReader, self.reader)
|
196
|
-
writer = cast(FrameWriter, self.writer)
|
197
199
|
while self.connected.is_set():
|
198
200
|
try:
|
199
|
-
if
|
200
|
-
await writer.write(await
|
201
|
-
|
201
|
+
if not queues.write.empty():
|
202
|
+
await writer.write(await queues.write.get())
|
203
|
+
queues.write.task_done()
|
202
204
|
|
203
205
|
if (response := await reader.read()) is not None:
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
read_queue.put_nowait((device, response))
|
208
|
-
|
209
|
-
except FrameDataError as e:
|
210
|
-
_LOGGER.warning("Incorrect payload: %s", e)
|
211
|
-
except ReadError as e:
|
212
|
-
_LOGGER.debug("Read error: %s", e)
|
213
|
-
except UnknownDeviceError as e:
|
214
|
-
_LOGGER.debug("Unknown device: %s", e)
|
215
|
-
except FrameError as e:
|
206
|
+
queues.read.put_nowait(response)
|
207
|
+
|
208
|
+
except (ReadError, UnknownDeviceError, FrameError) as e:
|
216
209
|
_LOGGER.debug("Can't process received frame: %s", e)
|
217
210
|
except (OSError, asyncio.TimeoutError):
|
218
211
|
self.create_task(self.connection_lost())
|
219
212
|
break
|
220
|
-
except Exception
|
221
|
-
_LOGGER.exception(
|
213
|
+
except Exception:
|
214
|
+
_LOGGER.exception("Unexpected exception")
|
222
215
|
|
223
|
-
async def frame_consumer(self,
|
216
|
+
async def frame_consumer(self, queue: asyncio.Queue) -> None:
|
224
217
|
"""Handle frame processing."""
|
225
218
|
await self.connected.wait()
|
226
219
|
while self.connected.is_set():
|
227
|
-
|
228
|
-
|
229
|
-
)
|
220
|
+
frame: Frame = await queue.get()
|
221
|
+
device = await self.get_device_entry(frame.sender)
|
230
222
|
device.handle_frame(frame)
|
231
|
-
|
223
|
+
queue.task_done()
|
232
224
|
|
233
225
|
async def get_device_entry(self, device_type: DeviceType) -> AddressableDevice:
|
234
|
-
"""Set up device entry."""
|
235
|
-
|
226
|
+
"""Set up or return a device entry."""
|
227
|
+
name = device_type.name.lower()
|
236
228
|
if name not in self.data:
|
237
|
-
|
229
|
+
device = await AddressableDevice.create(
|
230
|
+
device_type, queue=self._queues.write, network=self._network
|
231
|
+
)
|
232
|
+
device.dispatch_nowait(ATTR_CONNECTED, True)
|
233
|
+
self.create_task(device.async_setup())
|
234
|
+
self.set_event(name)
|
235
|
+
self.data[name] = device
|
238
236
|
|
239
237
|
return self.data[name]
|
240
|
-
|
241
|
-
async def _create_device_entry(self, name: str, handler: str) -> AddressableDevice:
|
242
|
-
"""Create device entry."""
|
243
|
-
write_queue = self.queues[1]
|
244
|
-
device: AddressableDevice = await create_instance(
|
245
|
-
handler, queue=write_queue, network=self._network
|
246
|
-
)
|
247
|
-
device.dispatch_nowait(ATTR_CONNECTED, True)
|
248
|
-
self.create_task(device.async_setup())
|
249
|
-
self.set_event(name)
|
250
|
-
return device
|
251
|
-
|
252
|
-
@property
|
253
|
-
def queues(self) -> tuple[asyncio.Queue, asyncio.Queue]:
|
254
|
-
"""Return the protocol queues."""
|
255
|
-
return self._queues
|
pyplumio/stream.py
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
"""Contains a frame reader and writer classes."""
|
2
|
+
|
2
3
|
from __future__ import annotations
|
3
4
|
|
4
5
|
import asyncio
|
5
6
|
from asyncio import IncompleteReadError, StreamReader, StreamWriter
|
6
7
|
import logging
|
7
|
-
from typing import Final
|
8
|
+
from typing import Final, NamedTuple
|
8
9
|
|
9
10
|
from pyplumio.const import DeviceType
|
10
|
-
from pyplumio.
|
11
|
-
from pyplumio.
|
12
|
-
from pyplumio.
|
11
|
+
from pyplumio.devices import is_known_device_type
|
12
|
+
from pyplumio.exceptions import ChecksumError, ReadError, UnknownDeviceError
|
13
|
+
from pyplumio.frames import FRAME_START, Frame, bcc, struct_header
|
13
14
|
from pyplumio.helpers.timeout import timeout
|
14
15
|
|
15
16
|
READER_TIMEOUT: Final = 10
|
@@ -53,6 +54,18 @@ class FrameWriter:
|
|
53
54
|
await self._writer.wait_closed()
|
54
55
|
|
55
56
|
|
57
|
+
class Header(NamedTuple):
|
58
|
+
"""Represents a frame header."""
|
59
|
+
|
60
|
+
bytes: bytes
|
61
|
+
frame_start: int
|
62
|
+
frame_length: int
|
63
|
+
recipient: int
|
64
|
+
sender: int
|
65
|
+
econet_type: int
|
66
|
+
econet_version: int
|
67
|
+
|
68
|
+
|
56
69
|
class FrameReader:
|
57
70
|
"""Represents a frame reader."""
|
58
71
|
|
@@ -64,11 +77,11 @@ class FrameReader:
|
|
64
77
|
"""Initialize a new frame reader."""
|
65
78
|
self._reader = reader
|
66
79
|
|
67
|
-
async def _read_header(self) ->
|
80
|
+
async def _read_header(self) -> Header:
|
68
81
|
"""Locate and read a frame header.
|
69
82
|
|
70
83
|
Raise pyplumio.ReadError if header size is too small and
|
71
|
-
OSError
|
84
|
+
OSError if serial connection is broken.
|
72
85
|
"""
|
73
86
|
while buffer := await self._reader.read(1):
|
74
87
|
if FRAME_START not in buffer:
|
@@ -78,23 +91,7 @@ class FrameReader:
|
|
78
91
|
if len(buffer) < struct_header.size:
|
79
92
|
raise ReadError(f"Header can't be less than {struct_header.size} bytes")
|
80
93
|
|
81
|
-
|
82
|
-
_,
|
83
|
-
length,
|
84
|
-
recipient,
|
85
|
-
sender,
|
86
|
-
sender_type,
|
87
|
-
econet_version,
|
88
|
-
] = struct_header.unpack_from(buffer)
|
89
|
-
|
90
|
-
return (
|
91
|
-
buffer,
|
92
|
-
length,
|
93
|
-
recipient,
|
94
|
-
sender,
|
95
|
-
sender_type,
|
96
|
-
econet_version,
|
97
|
-
)
|
94
|
+
return Header(buffer, *struct_header.unpack_from(buffer))
|
98
95
|
|
99
96
|
raise OSError("Serial connection broken")
|
100
97
|
|
@@ -107,38 +104,44 @@ class FrameReader:
|
|
107
104
|
checksum.
|
108
105
|
"""
|
109
106
|
(
|
110
|
-
|
111
|
-
|
107
|
+
header_bytes,
|
108
|
+
_,
|
109
|
+
frame_length,
|
112
110
|
recipient,
|
113
111
|
sender,
|
114
|
-
|
112
|
+
econet_type,
|
115
113
|
econet_version,
|
116
114
|
) = await self._read_header()
|
117
115
|
|
118
116
|
if recipient not in (DeviceType.ECONET, DeviceType.ALL):
|
119
117
|
return None
|
120
118
|
|
121
|
-
if
|
122
|
-
raise
|
119
|
+
if not is_known_device_type(sender):
|
120
|
+
raise UnknownDeviceError(f"Unknown sender type ({sender})")
|
121
|
+
|
122
|
+
if frame_length > MAX_FRAME_LENGTH or frame_length < MIN_FRAME_LENGTH:
|
123
|
+
raise ReadError(f"Unexpected frame length ({frame_length})")
|
123
124
|
|
124
125
|
try:
|
125
|
-
payload = await self._reader.readexactly(
|
126
|
+
payload = await self._reader.readexactly(frame_length - struct_header.size)
|
126
127
|
except IncompleteReadError as e:
|
127
128
|
raise ReadError(
|
128
129
|
"Got an incomplete frame while trying to read "
|
129
|
-
+ f"'{
|
130
|
+
+ f"'{frame_length - struct_header.size}' bytes"
|
130
131
|
) from e
|
131
132
|
|
132
|
-
if
|
133
|
-
raise ChecksumError(
|
133
|
+
if (checksum := bcc(header_bytes + payload[:-2])) and checksum != payload[-2]:
|
134
|
+
raise ChecksumError(
|
135
|
+
f"Incorrect frame checksum ({checksum} != {payload[-2]})"
|
136
|
+
)
|
134
137
|
|
135
|
-
frame
|
136
|
-
|
137
|
-
recipient=recipient,
|
138
|
-
|
139
|
-
|
140
|
-
sender_type=sender_type,
|
138
|
+
frame = await Frame.create(
|
139
|
+
frame_type=payload[0],
|
140
|
+
recipient=DeviceType(recipient),
|
141
|
+
sender=DeviceType(sender),
|
142
|
+
econet_type=econet_type,
|
141
143
|
econet_version=econet_version,
|
144
|
+
message=payload[1:-2],
|
142
145
|
)
|
143
146
|
_LOGGER.debug("Received frame: %s", frame)
|
144
147
|
|
pyplumio/structures/__init__.py
CHANGED
pyplumio/structures/alerts.py
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
"""Contains regulator parameter structure decoder."""
|
2
|
+
|
2
3
|
from __future__ import annotations
|
3
4
|
|
4
5
|
from collections.abc import Generator
|
5
6
|
from dataclasses import dataclass
|
6
|
-
from typing import Any, Final
|
7
|
+
from typing import Any, Final
|
7
8
|
|
8
9
|
from pyplumio.const import (
|
9
10
|
ATTR_INDEX,
|
@@ -11,12 +12,12 @@ from pyplumio.const import (
|
|
11
12
|
ATTR_SIZE,
|
12
13
|
ATTR_VALUE,
|
13
14
|
PERCENTAGE,
|
15
|
+
FrameType,
|
14
16
|
ProductType,
|
15
17
|
UnitOfMeasurement,
|
16
18
|
)
|
17
19
|
from pyplumio.devices import AddressableDevice
|
18
20
|
from pyplumio.frames import Request
|
19
|
-
from pyplumio.helpers.factory import create_instance
|
20
21
|
from pyplumio.helpers.parameter import (
|
21
22
|
BinaryParameter,
|
22
23
|
BinaryParameterDescription,
|
@@ -47,10 +48,10 @@ class EcomaxParameter(Parameter):
|
|
47
48
|
async def create_request(self) -> Request:
|
48
49
|
"""Create a request to change the parameter."""
|
49
50
|
if self.description.name == ATTR_ECOMAX_CONTROL:
|
50
|
-
|
51
|
+
frame_type = FrameType.REQUEST_ECOMAX_CONTROL
|
51
52
|
data = {ATTR_VALUE: self.values.value}
|
52
53
|
elif self.description.name == ATTR_THERMOSTAT_PROFILE:
|
53
|
-
|
54
|
+
frame_type = FrameType.REQUEST_SET_THERMOSTAT_PARAMETER
|
54
55
|
data = {
|
55
56
|
ATTR_INDEX: self._index,
|
56
57
|
ATTR_VALUE: self.values.value,
|
@@ -58,15 +59,14 @@ class EcomaxParameter(Parameter):
|
|
58
59
|
ATTR_SIZE: 1,
|
59
60
|
}
|
60
61
|
else:
|
61
|
-
|
62
|
+
frame_type = FrameType.REQUEST_SET_ECOMAX_PARAMETER
|
62
63
|
data = {
|
63
64
|
ATTR_INDEX: self._index,
|
64
65
|
ATTR_VALUE: self.values.value,
|
65
66
|
}
|
66
67
|
|
67
|
-
return
|
68
|
-
|
69
|
-
await create_instance(cls, recipient=self.device.address, data=data),
|
68
|
+
return await Request.create(
|
69
|
+
frame_type, recipient=self.device.address, data=data
|
70
70
|
)
|
71
71
|
|
72
72
|
async def set(self, value: ParameterValueType, retries: int = 5) -> bool:
|
pyplumio/structures/fan_power.py
CHANGED
@@ -1,19 +1,20 @@
|
|
1
1
|
"""Contains a mixer parameter structure decoder."""
|
2
|
+
|
2
3
|
from __future__ import annotations
|
3
4
|
|
4
5
|
from collections.abc import Generator
|
5
6
|
from dataclasses import dataclass
|
6
|
-
from typing import TYPE_CHECKING, Any, Final
|
7
|
+
from typing import TYPE_CHECKING, Any, Final
|
7
8
|
|
8
9
|
from pyplumio.const import (
|
9
10
|
ATTR_DEVICE_INDEX,
|
10
11
|
ATTR_INDEX,
|
11
12
|
ATTR_VALUE,
|
13
|
+
FrameType,
|
12
14
|
ProductType,
|
13
15
|
UnitOfMeasurement,
|
14
16
|
)
|
15
17
|
from pyplumio.frames import Request
|
16
|
-
from pyplumio.helpers.factory import create_instance
|
17
18
|
from pyplumio.helpers.parameter import (
|
18
19
|
BinaryParameter,
|
19
20
|
BinaryParameterDescription,
|
@@ -44,17 +45,14 @@ class MixerParameter(Parameter):
|
|
44
45
|
|
45
46
|
async def create_request(self) -> Request:
|
46
47
|
"""Create a request to change the parameter."""
|
47
|
-
return
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
ATTR_DEVICE_INDEX: self.device.index,
|
56
|
-
},
|
57
|
-
),
|
48
|
+
return await Request.create(
|
49
|
+
FrameType.REQUEST_SET_MIXER_PARAMETER,
|
50
|
+
recipient=self.device.parent.address,
|
51
|
+
data={
|
52
|
+
ATTR_INDEX: self._index,
|
53
|
+
ATTR_VALUE: self.values.value,
|
54
|
+
ATTR_DEVICE_INDEX: self.device.index,
|
55
|
+
},
|
58
56
|
)
|
59
57
|
|
60
58
|
async def set(self, value: ParameterValueType, retries: int = 5) -> bool:
|
pyplumio/structures/modules.py
CHANGED
pyplumio/structures/outputs.py
CHANGED