python-broadlink 1.0.0__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.
- broadlink/__init__.py +342 -0
- broadlink/alarm.py +43 -0
- broadlink/climate.py +474 -0
- broadlink/const.py +5 -0
- broadlink/cover.py +182 -0
- broadlink/device.py +470 -0
- broadlink/exceptions.py +161 -0
- broadlink/helpers.py +43 -0
- broadlink/hub.py +98 -0
- broadlink/light.py +200 -0
- broadlink/protocol.py +50 -0
- broadlink/remote.py +521 -0
- broadlink/sensor.py +90 -0
- broadlink/switch.py +472 -0
- python_broadlink-1.0.0.dist-info/METADATA +360 -0
- python_broadlink-1.0.0.dist-info/RECORD +19 -0
- python_broadlink-1.0.0.dist-info/WHEEL +5 -0
- python_broadlink-1.0.0.dist-info/licenses/LICENSE +22 -0
- python_broadlink-1.0.0.dist-info/top_level.txt +1 -0
broadlink/switch.py
ADDED
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
"""Support for switches."""
|
|
2
|
+
import json
|
|
3
|
+
import struct
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from . import exceptions as e
|
|
7
|
+
from .device import Device
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class sp1(Device):
|
|
11
|
+
"""Controls a Broadlink SP1."""
|
|
12
|
+
|
|
13
|
+
TYPE = "SP1"
|
|
14
|
+
|
|
15
|
+
async def set_power(self, pwr: bool) -> None:
|
|
16
|
+
"""Set the power state of the device."""
|
|
17
|
+
packet = bytearray(4)
|
|
18
|
+
packet[0] = bool(pwr)
|
|
19
|
+
response = await self.send_packet(0x66, packet)
|
|
20
|
+
e.check_error(response[0x22:0x24])
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class sp2(Device):
|
|
24
|
+
"""Controls a Broadlink SP2."""
|
|
25
|
+
|
|
26
|
+
TYPE = "SP2"
|
|
27
|
+
|
|
28
|
+
async def set_power(self, pwr: bool) -> None:
|
|
29
|
+
"""Set the power state of the device."""
|
|
30
|
+
packet = bytearray(16)
|
|
31
|
+
packet[0] = 2
|
|
32
|
+
packet[4] = bool(pwr)
|
|
33
|
+
response = await self.send_packet(0x6A, packet)
|
|
34
|
+
e.check_error(response[0x22:0x24])
|
|
35
|
+
|
|
36
|
+
async def check_power(self) -> bool:
|
|
37
|
+
"""Return the power state of the device."""
|
|
38
|
+
packet = bytearray(16)
|
|
39
|
+
packet[0] = 1
|
|
40
|
+
response = await self.send_packet(0x6A, packet)
|
|
41
|
+
e.check_error(response[0x22:0x24])
|
|
42
|
+
payload = self.decrypt(response[0x38:])
|
|
43
|
+
return bool(payload[0x4])
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class sp2s(sp2):
|
|
47
|
+
"""Controls a Broadlink SP2S."""
|
|
48
|
+
|
|
49
|
+
TYPE = "SP2S"
|
|
50
|
+
|
|
51
|
+
async def get_energy(self) -> float:
|
|
52
|
+
"""Return the power consumption in W."""
|
|
53
|
+
packet = bytearray(16)
|
|
54
|
+
packet[0] = 4
|
|
55
|
+
response = await self.send_packet(0x6A, packet)
|
|
56
|
+
e.check_error(response[0x22:0x24])
|
|
57
|
+
payload = self.decrypt(response[0x38:])
|
|
58
|
+
return int.from_bytes(payload[0x4:0x7], "little") / 1000
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class sp3(Device):
|
|
62
|
+
"""Controls a Broadlink SP3."""
|
|
63
|
+
|
|
64
|
+
TYPE = "SP3"
|
|
65
|
+
|
|
66
|
+
async def set_power(self, pwr: bool) -> None:
|
|
67
|
+
"""Set the power state of the device."""
|
|
68
|
+
packet = bytearray(16)
|
|
69
|
+
packet[0] = 2
|
|
70
|
+
packet[4] = await self.check_nightlight() << 1 | bool(pwr)
|
|
71
|
+
response = await self.send_packet(0x6A, packet)
|
|
72
|
+
e.check_error(response[0x22:0x24])
|
|
73
|
+
|
|
74
|
+
async def set_nightlight(self, ntlight: bool) -> None:
|
|
75
|
+
"""Set the night light state of the device."""
|
|
76
|
+
packet = bytearray(16)
|
|
77
|
+
packet[0] = 2
|
|
78
|
+
packet[4] = bool(ntlight) << 1 | await self.check_power()
|
|
79
|
+
response = await self.send_packet(0x6A, packet)
|
|
80
|
+
e.check_error(response[0x22:0x24])
|
|
81
|
+
|
|
82
|
+
async def check_power(self) -> bool:
|
|
83
|
+
"""Return the power state of the device."""
|
|
84
|
+
packet = bytearray(16)
|
|
85
|
+
packet[0] = 1
|
|
86
|
+
response = await self.send_packet(0x6A, packet)
|
|
87
|
+
e.check_error(response[0x22:0x24])
|
|
88
|
+
payload = self.decrypt(response[0x38:])
|
|
89
|
+
return bool(payload[0x4] & 1)
|
|
90
|
+
|
|
91
|
+
async def check_nightlight(self) -> bool:
|
|
92
|
+
"""Return the state of the night light."""
|
|
93
|
+
packet = bytearray(16)
|
|
94
|
+
packet[0] = 1
|
|
95
|
+
response = await self.send_packet(0x6A, packet)
|
|
96
|
+
e.check_error(response[0x22:0x24])
|
|
97
|
+
payload = self.decrypt(response[0x38:])
|
|
98
|
+
return bool(payload[0x4] & 2)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class sp3s(sp2):
|
|
102
|
+
"""Controls a Broadlink SP3S."""
|
|
103
|
+
|
|
104
|
+
TYPE = "SP3S"
|
|
105
|
+
|
|
106
|
+
async def get_energy(self) -> float:
|
|
107
|
+
"""Return the power consumption in W."""
|
|
108
|
+
packet = bytearray([8, 0, 254, 1, 5, 1, 0, 0, 0, 45])
|
|
109
|
+
response = await self.send_packet(0x6A, packet)
|
|
110
|
+
e.check_error(response[0x22:0x24])
|
|
111
|
+
payload = self.decrypt(response[0x38:])
|
|
112
|
+
energy = payload[0x7:0x4:-1].hex()
|
|
113
|
+
return int(energy) / 100
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class sp4(Device):
|
|
117
|
+
"""Controls a Broadlink SP4."""
|
|
118
|
+
|
|
119
|
+
TYPE = "SP4"
|
|
120
|
+
|
|
121
|
+
async def set_power(self, pwr: bool) -> None:
|
|
122
|
+
"""Set the power state of the device."""
|
|
123
|
+
await self.set_state(pwr=pwr)
|
|
124
|
+
|
|
125
|
+
async def set_nightlight(self, ntlight: bool) -> None:
|
|
126
|
+
"""Set the night light state of the device."""
|
|
127
|
+
await self.set_state(ntlight=ntlight)
|
|
128
|
+
|
|
129
|
+
async def set_state(
|
|
130
|
+
self,
|
|
131
|
+
pwr: Optional[bool] = None,
|
|
132
|
+
ntlight: Optional[bool] = None,
|
|
133
|
+
indicator: Optional[bool] = None,
|
|
134
|
+
ntlbrightness: Optional[int] = None,
|
|
135
|
+
maxworktime: Optional[int] = None,
|
|
136
|
+
childlock: Optional[bool] = None,
|
|
137
|
+
) -> dict:
|
|
138
|
+
"""Set state of device."""
|
|
139
|
+
state = {}
|
|
140
|
+
if pwr is not None:
|
|
141
|
+
state["pwr"] = int(bool(pwr))
|
|
142
|
+
if ntlight is not None:
|
|
143
|
+
state["ntlight"] = int(bool(ntlight))
|
|
144
|
+
if indicator is not None:
|
|
145
|
+
state["indicator"] = int(bool(indicator))
|
|
146
|
+
if ntlbrightness is not None:
|
|
147
|
+
state["ntlbrightness"] = ntlbrightness
|
|
148
|
+
if maxworktime is not None:
|
|
149
|
+
state["maxworktime"] = maxworktime
|
|
150
|
+
if childlock is not None:
|
|
151
|
+
state["childlock"] = int(bool(childlock))
|
|
152
|
+
|
|
153
|
+
packet = self._encode(2, state)
|
|
154
|
+
response = await self.send_packet(0x6A, packet)
|
|
155
|
+
return self._decode(response)
|
|
156
|
+
|
|
157
|
+
async def check_power(self) -> bool:
|
|
158
|
+
"""Return the power state of the device."""
|
|
159
|
+
state = await self.get_state()
|
|
160
|
+
return bool(state["pwr"])
|
|
161
|
+
|
|
162
|
+
async def check_nightlight(self) -> bool:
|
|
163
|
+
"""Return the state of the night light."""
|
|
164
|
+
state = await self.get_state()
|
|
165
|
+
return bool(state["ntlight"])
|
|
166
|
+
|
|
167
|
+
async def get_state(self) -> dict:
|
|
168
|
+
"""Get full state of device."""
|
|
169
|
+
packet = self._encode(1, {})
|
|
170
|
+
response = await self.send_packet(0x6A, packet)
|
|
171
|
+
return self._decode(response)
|
|
172
|
+
|
|
173
|
+
def _encode(self, flag: int, state: dict) -> bytes:
|
|
174
|
+
"""Encode a message."""
|
|
175
|
+
packet = bytearray(12)
|
|
176
|
+
data = json.dumps(state, separators=(",", ":")).encode()
|
|
177
|
+
struct.pack_into(
|
|
178
|
+
"<HHHBBI", packet, 0, 0xA5A5, 0x5A5A, 0x0000, flag, 0x0B, len(data)
|
|
179
|
+
)
|
|
180
|
+
packet.extend(data)
|
|
181
|
+
checksum = sum(packet, 0xBEAF) & 0xFFFF
|
|
182
|
+
packet[0x04:0x06] = checksum.to_bytes(2, "little")
|
|
183
|
+
return packet
|
|
184
|
+
|
|
185
|
+
def _decode(self, response: bytes) -> dict:
|
|
186
|
+
"""Decode a message."""
|
|
187
|
+
e.check_error(response[0x22:0x24])
|
|
188
|
+
payload = self.decrypt(response[0x38:])
|
|
189
|
+
js_len = struct.unpack_from("<I", payload, 0x08)[0]
|
|
190
|
+
state = json.loads(payload[0x0C:0x0C+js_len])
|
|
191
|
+
return state
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
class sp4b(sp4):
|
|
195
|
+
"""Controls a Broadlink SP4 (type B)."""
|
|
196
|
+
|
|
197
|
+
TYPE = "SP4B"
|
|
198
|
+
|
|
199
|
+
async def get_state(self) -> dict:
|
|
200
|
+
"""Get full state of device."""
|
|
201
|
+
state = await super().get_state()
|
|
202
|
+
|
|
203
|
+
# Convert sensor data to float. Remove keys if sensors are not supported.
|
|
204
|
+
sensor_attrs = ["current", "volt", "power", "totalconsum", "overload"]
|
|
205
|
+
for attr in sensor_attrs:
|
|
206
|
+
value = state.pop(attr, -1)
|
|
207
|
+
if value != -1:
|
|
208
|
+
state[attr] = value / 1000
|
|
209
|
+
return state
|
|
210
|
+
|
|
211
|
+
def _encode(self, flag: int, state: dict) -> bytes:
|
|
212
|
+
"""Encode a message."""
|
|
213
|
+
packet = bytearray(14)
|
|
214
|
+
data = json.dumps(state, separators=(",", ":")).encode()
|
|
215
|
+
length = 12 + len(data)
|
|
216
|
+
struct.pack_into(
|
|
217
|
+
"<HHHHBBI",
|
|
218
|
+
packet,
|
|
219
|
+
0,
|
|
220
|
+
length,
|
|
221
|
+
0xA5A5,
|
|
222
|
+
0x5A5A,
|
|
223
|
+
0x0000,
|
|
224
|
+
flag,
|
|
225
|
+
0x0B,
|
|
226
|
+
len(data),
|
|
227
|
+
)
|
|
228
|
+
packet.extend(data)
|
|
229
|
+
checksum = sum(packet[0x02:], 0xBEAF) & 0xFFFF
|
|
230
|
+
packet[0x06:0x08] = checksum.to_bytes(2, "little")
|
|
231
|
+
return packet
|
|
232
|
+
|
|
233
|
+
def _decode(self, response: bytes) -> dict:
|
|
234
|
+
"""Decode a message."""
|
|
235
|
+
e.check_error(response[0x22:0x24])
|
|
236
|
+
payload = self.decrypt(response[0x38:])
|
|
237
|
+
js_len = struct.unpack_from("<I", payload, 0xA)[0]
|
|
238
|
+
state = json.loads(payload[0x0E:0x0E+js_len])
|
|
239
|
+
return state
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
class bg1(Device):
|
|
243
|
+
"""Controls a BG Electrical smart outlet."""
|
|
244
|
+
|
|
245
|
+
TYPE = "BG1"
|
|
246
|
+
|
|
247
|
+
async def get_state(self) -> dict:
|
|
248
|
+
"""Return the power state of the device.
|
|
249
|
+
|
|
250
|
+
Example: `{"pwr":1,"pwr1":1,"pwr2":0,"maxworktime":60,"maxworktime1":60,"maxworktime2":0,"idcbrightness":50}`
|
|
251
|
+
"""
|
|
252
|
+
packet = self._encode(1, {})
|
|
253
|
+
response = await self.send_packet(0x6A, packet)
|
|
254
|
+
e.check_error(response[0x22:0x24])
|
|
255
|
+
return self._decode(response)
|
|
256
|
+
|
|
257
|
+
async def set_state(
|
|
258
|
+
self,
|
|
259
|
+
pwr: Optional[bool] = None,
|
|
260
|
+
pwr1: Optional[bool] = None,
|
|
261
|
+
pwr2: Optional[bool] = None,
|
|
262
|
+
maxworktime: Optional[int] = None,
|
|
263
|
+
maxworktime1: Optional[int] = None,
|
|
264
|
+
maxworktime2: Optional[int] = None,
|
|
265
|
+
idcbrightness: Optional[int] = None,
|
|
266
|
+
) -> dict:
|
|
267
|
+
"""Set the power state of the device."""
|
|
268
|
+
state = {}
|
|
269
|
+
if pwr is not None:
|
|
270
|
+
state["pwr"] = int(bool(pwr))
|
|
271
|
+
if pwr1 is not None:
|
|
272
|
+
state["pwr1"] = int(bool(pwr1))
|
|
273
|
+
if pwr2 is not None:
|
|
274
|
+
state["pwr2"] = int(bool(pwr2))
|
|
275
|
+
if maxworktime is not None:
|
|
276
|
+
state["maxworktime"] = maxworktime
|
|
277
|
+
if maxworktime1 is not None:
|
|
278
|
+
state["maxworktime1"] = maxworktime1
|
|
279
|
+
if maxworktime2 is not None:
|
|
280
|
+
state["maxworktime2"] = maxworktime2
|
|
281
|
+
if idcbrightness is not None:
|
|
282
|
+
state["idcbrightness"] = idcbrightness
|
|
283
|
+
|
|
284
|
+
packet = self._encode(2, state)
|
|
285
|
+
response = await self.send_packet(0x6A, packet)
|
|
286
|
+
e.check_error(response[0x22:0x24])
|
|
287
|
+
return self._decode(response)
|
|
288
|
+
|
|
289
|
+
def _encode(self, flag: int, state: dict) -> bytes:
|
|
290
|
+
"""Encode a message."""
|
|
291
|
+
packet = bytearray(14)
|
|
292
|
+
data = json.dumps(state).encode()
|
|
293
|
+
length = 12 + len(data)
|
|
294
|
+
struct.pack_into(
|
|
295
|
+
"<HHHHBBI",
|
|
296
|
+
packet,
|
|
297
|
+
0,
|
|
298
|
+
length,
|
|
299
|
+
0xA5A5,
|
|
300
|
+
0x5A5A,
|
|
301
|
+
0x0000,
|
|
302
|
+
flag,
|
|
303
|
+
0x0B,
|
|
304
|
+
len(data),
|
|
305
|
+
)
|
|
306
|
+
packet.extend(data)
|
|
307
|
+
checksum = sum(packet[0x2:], 0xBEAF) & 0xFFFF
|
|
308
|
+
packet[0x06:0x08] = checksum.to_bytes(2, "little")
|
|
309
|
+
return packet
|
|
310
|
+
|
|
311
|
+
def _decode(self, response: bytes) -> dict:
|
|
312
|
+
"""Decode a message."""
|
|
313
|
+
payload = self.decrypt(response[0x38:])
|
|
314
|
+
js_len = struct.unpack_from("<I", payload, 0x0A)[0]
|
|
315
|
+
state = json.loads(payload[0x0E:0x0E+js_len])
|
|
316
|
+
return state
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
class ehc31(bg1):
|
|
320
|
+
"""Controls a BG Electrical smart extension lead."""
|
|
321
|
+
|
|
322
|
+
TYPE = "EHC31"
|
|
323
|
+
|
|
324
|
+
async def set_state(
|
|
325
|
+
self,
|
|
326
|
+
pwr: Optional[bool] = None,
|
|
327
|
+
pwr1: Optional[bool] = None,
|
|
328
|
+
pwr2: Optional[bool] = None,
|
|
329
|
+
pwr3: Optional[bool] = None,
|
|
330
|
+
maxworktime1: Optional[int] = None,
|
|
331
|
+
maxworktime2: Optional[int] = None,
|
|
332
|
+
maxworktime3: Optional[int] = None,
|
|
333
|
+
idcbrightness: Optional[int] = None,
|
|
334
|
+
childlock: Optional[bool] = None,
|
|
335
|
+
childlock1: Optional[bool] = None,
|
|
336
|
+
childlock2: Optional[bool] = None,
|
|
337
|
+
childlock3: Optional[bool] = None,
|
|
338
|
+
childlock4: Optional[bool] = None,
|
|
339
|
+
) -> dict:
|
|
340
|
+
"""Set the power state of the device."""
|
|
341
|
+
state = {}
|
|
342
|
+
if pwr is not None:
|
|
343
|
+
state["pwr"] = int(bool(pwr))
|
|
344
|
+
if pwr1 is not None:
|
|
345
|
+
state["pwr1"] = int(bool(pwr1))
|
|
346
|
+
if pwr2 is not None:
|
|
347
|
+
state["pwr2"] = int(bool(pwr2))
|
|
348
|
+
if pwr3 is not None:
|
|
349
|
+
state["pwr3"] = int(bool(pwr3))
|
|
350
|
+
if maxworktime1 is not None:
|
|
351
|
+
state["maxworktime1"] = maxworktime1
|
|
352
|
+
if maxworktime2 is not None:
|
|
353
|
+
state["maxworktime2"] = maxworktime2
|
|
354
|
+
if maxworktime3 is not None:
|
|
355
|
+
state["maxworktime3"] = maxworktime3
|
|
356
|
+
if idcbrightness is not None:
|
|
357
|
+
state["idcbrightness"] = idcbrightness
|
|
358
|
+
if childlock is not None:
|
|
359
|
+
state["childlock"] = int(bool(childlock))
|
|
360
|
+
if childlock1 is not None:
|
|
361
|
+
state["childlock1"] = int(bool(childlock1))
|
|
362
|
+
if childlock2 is not None:
|
|
363
|
+
state["childlock2"] = int(bool(childlock2))
|
|
364
|
+
if childlock3 is not None:
|
|
365
|
+
state["childlock3"] = int(bool(childlock3))
|
|
366
|
+
if childlock4 is not None:
|
|
367
|
+
state["childlock4"] = int(bool(childlock4))
|
|
368
|
+
|
|
369
|
+
packet = self._encode(2, state)
|
|
370
|
+
response = await self.send_packet(0x6A, packet)
|
|
371
|
+
e.check_error(response[0x22:0x24])
|
|
372
|
+
return self._decode(response)
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
class mp1(Device):
|
|
376
|
+
"""Controls a Broadlink MP1."""
|
|
377
|
+
|
|
378
|
+
TYPE = "MP1"
|
|
379
|
+
|
|
380
|
+
async def set_power_mask(self, sid_mask: int, pwr: bool) -> None:
|
|
381
|
+
"""Set the power state of the device."""
|
|
382
|
+
packet = bytearray(16)
|
|
383
|
+
packet[0x00] = 0x0D
|
|
384
|
+
packet[0x02] = 0xA5
|
|
385
|
+
packet[0x03] = 0xA5
|
|
386
|
+
packet[0x04] = 0x5A
|
|
387
|
+
packet[0x05] = 0x5A
|
|
388
|
+
packet[0x06] = 0xB2 + ((sid_mask << 1) if pwr else sid_mask)
|
|
389
|
+
packet[0x07] = 0xC0
|
|
390
|
+
packet[0x08] = 0x02
|
|
391
|
+
packet[0x0A] = 0x03
|
|
392
|
+
packet[0x0D] = sid_mask
|
|
393
|
+
packet[0x0E] = sid_mask if pwr else 0
|
|
394
|
+
|
|
395
|
+
response = await self.send_packet(0x6A, packet)
|
|
396
|
+
e.check_error(response[0x22:0x24])
|
|
397
|
+
|
|
398
|
+
async def set_power(self, sid: int, pwr: bool) -> None:
|
|
399
|
+
"""Set the power state of the device."""
|
|
400
|
+
sid_mask = 0x01 << (sid - 1)
|
|
401
|
+
await self.set_power_mask(sid_mask, pwr)
|
|
402
|
+
|
|
403
|
+
async def check_power_raw(self) -> int:
|
|
404
|
+
"""Return the power state of the device in raw format."""
|
|
405
|
+
packet = bytearray(16)
|
|
406
|
+
packet[0x00] = 0x0A
|
|
407
|
+
packet[0x02] = 0xA5
|
|
408
|
+
packet[0x03] = 0xA5
|
|
409
|
+
packet[0x04] = 0x5A
|
|
410
|
+
packet[0x05] = 0x5A
|
|
411
|
+
packet[0x06] = 0xAE
|
|
412
|
+
packet[0x07] = 0xC0
|
|
413
|
+
packet[0x08] = 0x01
|
|
414
|
+
|
|
415
|
+
response = await self.send_packet(0x6A, packet)
|
|
416
|
+
e.check_error(response[0x22:0x24])
|
|
417
|
+
payload = self.decrypt(response[0x38:])
|
|
418
|
+
return payload[0x0E]
|
|
419
|
+
|
|
420
|
+
async def check_power(self) -> dict:
|
|
421
|
+
"""Return the power state of the device."""
|
|
422
|
+
data = await self.check_power_raw()
|
|
423
|
+
return {
|
|
424
|
+
"s1": bool(data & 1),
|
|
425
|
+
"s2": bool(data & 2),
|
|
426
|
+
"s3": bool(data & 4),
|
|
427
|
+
"s4": bool(data & 8),
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
class mp1s(mp1):
|
|
432
|
+
"""Controls a Broadlink MP1S."""
|
|
433
|
+
|
|
434
|
+
TYPE = "MP1S"
|
|
435
|
+
|
|
436
|
+
async def get_state(self) -> dict:
|
|
437
|
+
"""Return the power state of the device.
|
|
438
|
+
|
|
439
|
+
voltage in V.
|
|
440
|
+
current in A.
|
|
441
|
+
power in W.
|
|
442
|
+
power consumption in kW·h.
|
|
443
|
+
"""
|
|
444
|
+
packet = bytearray(16)
|
|
445
|
+
packet[0x00] = 0x0E
|
|
446
|
+
packet[0x02] = 0xA5
|
|
447
|
+
packet[0x03] = 0xA5
|
|
448
|
+
packet[0x04] = 0x5A
|
|
449
|
+
packet[0x05] = 0x5A
|
|
450
|
+
packet[0x06] = 0xB2
|
|
451
|
+
packet[0x07] = 0xC0
|
|
452
|
+
packet[0x08] = 0x01
|
|
453
|
+
packet[0x0A] = 0x04
|
|
454
|
+
|
|
455
|
+
response = await self.send_packet(0x6A, packet)
|
|
456
|
+
e.check_error(response[0x22:0x24])
|
|
457
|
+
payload = self.decrypt(response[0x38:])
|
|
458
|
+
payload_str = payload.hex()[4:-6]
|
|
459
|
+
|
|
460
|
+
def get_value(start, end, factors):
|
|
461
|
+
value = sum(
|
|
462
|
+
int(payload_str[i-2:i]) * factor
|
|
463
|
+
for i, factor in zip(range(start, end, -2), factors)
|
|
464
|
+
)
|
|
465
|
+
return value
|
|
466
|
+
|
|
467
|
+
return {
|
|
468
|
+
"volt": get_value(34, 30, [10, 0.1]),
|
|
469
|
+
"current": get_value(40, 34, [1, 0.01, 0.0001]),
|
|
470
|
+
"power": get_value(46, 40, [100, 1, 0.01]),
|
|
471
|
+
"totalconsum": get_value(54, 46, [10000, 100, 1, 0.01]),
|
|
472
|
+
}
|