python-aidot 0.3.53__tar.gz → 0.3.54b2__tar.gz
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.
- {python_aidot-0.3.53 → python_aidot-0.3.54b2}/PKG-INFO +1 -1
- {python_aidot-0.3.53 → python_aidot-0.3.54b2}/aidot/client.py +6 -0
- {python_aidot-0.3.53 → python_aidot-0.3.54b2}/aidot/const.py +3 -0
- {python_aidot-0.3.53 → python_aidot-0.3.54b2}/aidot/device_client.py +35 -23
- {python_aidot-0.3.53 → python_aidot-0.3.54b2}/aidot/discover.py +2 -2
- {python_aidot-0.3.53 → python_aidot-0.3.54b2}/python_aidot.egg-info/PKG-INFO +1 -1
- {python_aidot-0.3.53 → python_aidot-0.3.54b2}/setup.py +1 -1
- {python_aidot-0.3.53 → python_aidot-0.3.54b2}/LICENSE +0 -0
- {python_aidot-0.3.53 → python_aidot-0.3.54b2}/README.md +0 -0
- {python_aidot-0.3.53 → python_aidot-0.3.54b2}/aidot/__init__.py +0 -0
- {python_aidot-0.3.53 → python_aidot-0.3.54b2}/aidot/aes_utils.py +0 -0
- {python_aidot-0.3.53 → python_aidot-0.3.54b2}/aidot/exceptions.py +0 -0
- {python_aidot-0.3.53 → python_aidot-0.3.54b2}/aidot/login_const.py +0 -0
- {python_aidot-0.3.53 → python_aidot-0.3.54b2}/python_aidot.egg-info/SOURCES.txt +0 -0
- {python_aidot-0.3.53 → python_aidot-0.3.54b2}/python_aidot.egg-info/dependency_links.txt +0 -0
- {python_aidot-0.3.53 → python_aidot-0.3.54b2}/python_aidot.egg-info/requires.txt +0 -0
- {python_aidot-0.3.53 → python_aidot-0.3.54b2}/python_aidot.egg-info/top_level.txt +0 -0
- {python_aidot-0.3.53 → python_aidot-0.3.54b2}/setup.cfg +0 -0
|
@@ -90,6 +90,12 @@ class AidotClient:
|
|
|
90
90
|
self._base_url = API_URL_TEMPLATE.format(region=self._region)
|
|
91
91
|
break
|
|
92
92
|
if token is not None:
|
|
93
|
+
# ✅ 兼容性处理: v1.0.8 数据结构迁移到 v1.1.3
|
|
94
|
+
# 旧版本: config_entry.data[CONF_LOGIN_INFO]
|
|
95
|
+
# 新版本: config_entry.data
|
|
96
|
+
if token.get(CONF_ID) is None and token.get(CONF_LOGIN_INFO) is not None:
|
|
97
|
+
token = token.get(CONF_LOGIN_INFO)
|
|
98
|
+
|
|
93
99
|
self.login_info = token.copy()
|
|
94
100
|
self.username = token[CONF_USERNAME]
|
|
95
101
|
self.password = token[CONF_PASSWORD]
|
|
@@ -188,6 +188,7 @@ CONF_IS_DEFAULT = "isDefault"
|
|
|
188
188
|
CONF_TYPE = "type"
|
|
189
189
|
CONF_MODEL_ID = "modelId"
|
|
190
190
|
CONF_MAC = "mac"
|
|
191
|
+
CONF_LOGIN_INFO = "loginInfo"
|
|
191
192
|
CONF_AES_KEY = "aesKey"
|
|
192
193
|
CONF_MODEL_ID = "modelId"
|
|
193
194
|
CONF_HARDWARE_VERSION = "hardwareVersion"
|
|
@@ -207,6 +208,8 @@ CONF_RGBW = "RGBW"
|
|
|
207
208
|
CONF_CCT = "CCT"
|
|
208
209
|
CONF_ACK = "ack"
|
|
209
210
|
CONF_IS_OWNER = "isOwner"
|
|
211
|
+
CONF_GET_DEV_ATTR_REQ = "getDevAttrReq"
|
|
212
|
+
CONF_SET_DEV_ATTR_REQ = "setDevAttrReq"
|
|
210
213
|
|
|
211
214
|
|
|
212
215
|
class Identity(StrEnum):
|
|
@@ -35,6 +35,8 @@ from .const import (
|
|
|
35
35
|
CONF_SERVICE_MODULES,
|
|
36
36
|
CONF_ACK,
|
|
37
37
|
CONF_CODE,
|
|
38
|
+
CONF_GET_DEV_ATTR_REQ,
|
|
39
|
+
CONF_SET_DEV_ATTR_REQ,
|
|
38
40
|
Identity,
|
|
39
41
|
)
|
|
40
42
|
|
|
@@ -44,10 +46,10 @@ _LOGGER = logging.getLogger(__name__)
|
|
|
44
46
|
class DeviceStatusData:
|
|
45
47
|
online: bool = False
|
|
46
48
|
on: bool = False
|
|
47
|
-
rgdb: int =
|
|
48
|
-
rgbw: tuple[int, int, int, int] =
|
|
49
|
-
cct: int =
|
|
50
|
-
dimming: int =
|
|
49
|
+
rgdb: int = 0xFF000000
|
|
50
|
+
rgbw: tuple[int, int, int, int] = (255, 0, 0, 0)
|
|
51
|
+
cct: int = 2700
|
|
52
|
+
dimming: int = 100
|
|
51
53
|
|
|
52
54
|
def update(self, attr: dict[str, Any]) -> None:
|
|
53
55
|
if attr is None:
|
|
@@ -57,7 +59,13 @@ class DeviceStatusData:
|
|
|
57
59
|
if attr.get(CONF_DIMMING) is not None:
|
|
58
60
|
self.dimming = int(attr.get(CONF_DIMMING) * 255 / 100)
|
|
59
61
|
if attr.get(CONF_RGBW) is not None:
|
|
60
|
-
|
|
62
|
+
rgbw_value = attr.get(CONF_RGBW)
|
|
63
|
+
# If RGBW is 0, set default red color (255, 0, 0, 0)
|
|
64
|
+
if rgbw_value == 0:
|
|
65
|
+
self.rgdb = 0xFF000000 # Red in int: 4278190080
|
|
66
|
+
else:
|
|
67
|
+
self.rgdb = rgbw_value
|
|
68
|
+
|
|
61
69
|
rgbw = ctypes.c_uint32(self.rgdb).value
|
|
62
70
|
r = (rgbw >> 24) & 0xFF
|
|
63
71
|
g = (rgbw >> 16) & 0xFF
|
|
@@ -114,6 +122,9 @@ class DeviceClient(object):
|
|
|
114
122
|
_ping_timer: Any = None
|
|
115
123
|
writer: Any = None
|
|
116
124
|
reader: Any = None
|
|
125
|
+
syncProperties = [CONF_ON_OFF, CONF_DIMMING, CONF_RGBW, CONF_CCT]
|
|
126
|
+
heart_time = 10
|
|
127
|
+
# syncProperties = []
|
|
117
128
|
_TAG: str = "DeviceClient"
|
|
118
129
|
@property
|
|
119
130
|
def connect_and_login(self) -> bool:
|
|
@@ -139,7 +150,10 @@ class DeviceClient(object):
|
|
|
139
150
|
self.password = device.get(CONF_PASSWORD)
|
|
140
151
|
self.device_id = device.get(CONF_ID)
|
|
141
152
|
self._simpleVersion = device.get("simpleVersion")
|
|
142
|
-
self._TAG = f"{self.device_id}"
|
|
153
|
+
self._TAG = f"{self.device_id}"
|
|
154
|
+
# if self.info.model_id == 'lk.WIFI-RGBWLight-D0006':
|
|
155
|
+
# self.syncProperties = [CONF_ON_OFF, CONF_DIMMING, CONF_RGBW, CONF_CCT]
|
|
156
|
+
|
|
143
157
|
_LOGGER.warning(f"{self._TAG}:{device}")
|
|
144
158
|
|
|
145
159
|
async def connect(self, ip_address) -> None:
|
|
@@ -227,6 +241,7 @@ class DeviceClient(object):
|
|
|
227
241
|
|
|
228
242
|
self.ascNumber = json_data[CONF_PAYLOAD][CONF_ASCNUMBER] + 1
|
|
229
243
|
self.status.online = True
|
|
244
|
+
self._notify_status_update()
|
|
230
245
|
self._receive_task = asyncio.create_task(
|
|
231
246
|
self.receive_data(),
|
|
232
247
|
name=f"aidot_receive_{self.device_id}"
|
|
@@ -238,7 +253,7 @@ class DeviceClient(object):
|
|
|
238
253
|
self._reconnect_handle = None
|
|
239
254
|
self._schedule_ping()
|
|
240
255
|
_LOGGER.warning(f"{self._TAG}:connect success: {self._ip_address}")
|
|
241
|
-
await self.send_action(
|
|
256
|
+
await self.send_action(self.syncProperties, CONF_GET_DEV_ATTR_REQ)
|
|
242
257
|
except (BrokenPipeError, ConnectionResetError, Exception) as e:
|
|
243
258
|
_LOGGER.error(f"{self.device_id} login read status error {e}")
|
|
244
259
|
|
|
@@ -281,12 +296,15 @@ class DeviceClient(object):
|
|
|
281
296
|
def _schedule_ping(self):
|
|
282
297
|
loop = asyncio.get_running_loop()
|
|
283
298
|
loop.create_task(self.send_ping_action())
|
|
284
|
-
self._ping_timer = loop.call_later(
|
|
299
|
+
self._ping_timer = loop.call_later(self.heart_time, self._schedule_ping)
|
|
285
300
|
|
|
286
301
|
async def send_dev_attr(self, dev_attr) -> None:
|
|
287
302
|
if not self._connect_and_login:
|
|
288
303
|
raise ConnectionError('Device offline')
|
|
289
|
-
|
|
304
|
+
if not self.status.on and not CONF_ON_OFF in dev_attr:
|
|
305
|
+
self.status.on = True
|
|
306
|
+
attr[CONF_ON_OFF] = 1
|
|
307
|
+
await self.send_action(dev_attr, CONF_SET_DEV_ATTR_REQ)
|
|
290
308
|
|
|
291
309
|
async def async_turn_off(self) -> None:
|
|
292
310
|
await self.send_dev_attr({CONF_ON_OFF: 0})
|
|
@@ -309,9 +327,6 @@ class DeviceClient(object):
|
|
|
309
327
|
current_timestamp_milliseconds = int(time.time() * 1000)
|
|
310
328
|
self.seq_num += 1
|
|
311
329
|
seq = "ha93" + str(self.seq_num).zfill(5)
|
|
312
|
-
if not self.status.on and not CONF_ON_OFF in attr:
|
|
313
|
-
self.status.on = True
|
|
314
|
-
attr[CONF_ON_OFF] = 1
|
|
315
330
|
|
|
316
331
|
if self._simpleVersion is not None:
|
|
317
332
|
action = {
|
|
@@ -320,7 +335,7 @@ class DeviceClient(object):
|
|
|
320
335
|
"clientId": "ha-" + self.user_id,
|
|
321
336
|
"srcAddr": "0." + self.user_id,
|
|
322
337
|
"seq": "" + seq,
|
|
323
|
-
|
|
338
|
+
CONF_PAYLOAD: {
|
|
324
339
|
"devId": self.device_id,
|
|
325
340
|
"parentId": self.device_id,
|
|
326
341
|
"userId": self.user_id,
|
|
@@ -338,14 +353,14 @@ class DeviceClient(object):
|
|
|
338
353
|
"service": "device",
|
|
339
354
|
"seq": "" + seq,
|
|
340
355
|
"srcAddr": "0." + self.user_id,
|
|
341
|
-
|
|
356
|
+
CONF_PAYLOAD: {
|
|
342
357
|
"attr": attr,
|
|
343
358
|
"ascNumber": self.ascNumber,
|
|
344
359
|
},
|
|
345
360
|
"tst": current_timestamp_milliseconds,
|
|
346
361
|
"deviceId": self.device_id,
|
|
347
362
|
}
|
|
348
|
-
|
|
363
|
+
_LOGGER.warning(f"{self.device_id} send_action {action}")
|
|
349
364
|
try:
|
|
350
365
|
self.writer.write(self.get_send_packet(json.dumps(action).encode(), 1))
|
|
351
366
|
await self.writer.drain()
|
|
@@ -362,10 +377,10 @@ class DeviceClient(object):
|
|
|
362
377
|
"service": "test",
|
|
363
378
|
"method": "pingreq",
|
|
364
379
|
"seq": "123456",
|
|
365
|
-
"srcAddr": "
|
|
380
|
+
"srcAddr": "123456",
|
|
366
381
|
CONF_PAYLOAD: {},
|
|
367
382
|
}
|
|
368
|
-
_LOGGER.
|
|
383
|
+
_LOGGER.warning(f"{self.device_id} send_ping_action {ping}")
|
|
369
384
|
try:
|
|
370
385
|
if self.ping_count >= 3:
|
|
371
386
|
_LOGGER.error(
|
|
@@ -375,9 +390,10 @@ class DeviceClient(object):
|
|
|
375
390
|
return -1
|
|
376
391
|
if self._connect_and_login is False:
|
|
377
392
|
return -1
|
|
378
|
-
self.writer.write(self.get_send_packet(json.dumps(ping).encode(), 2))
|
|
379
|
-
await self.writer.drain()
|
|
393
|
+
# self.writer.write(self.get_send_packet(json.dumps(ping).encode(), 2))
|
|
394
|
+
# await self.writer.drain()
|
|
380
395
|
self.ping_count += 1
|
|
396
|
+
await self.send_action(self.syncProperties, CONF_GET_DEV_ATTR_REQ)
|
|
381
397
|
return 1
|
|
382
398
|
except Exception as e:
|
|
383
399
|
_LOGGER.error(f"{self.device_id} ping error {e}")
|
|
@@ -423,9 +439,5 @@ class DeviceClient(object):
|
|
|
423
439
|
"""延迟重连"""
|
|
424
440
|
_LOGGER.info(f"{self.device_id} _schedule_reconnect")
|
|
425
441
|
loop = asyncio.get_running_loop()
|
|
426
|
-
# self._reconnect_handle = loop.call_later(
|
|
427
|
-
# 10, # 10秒后重连
|
|
428
|
-
# lambda: asyncio.create_task(self.async_login())
|
|
429
|
-
# )
|
|
430
442
|
self._reconnect_handle = loop.call_later(60, self._schedule_reconnect)
|
|
431
443
|
self._login_task = asyncio.create_task(self.async_login())
|
|
@@ -12,7 +12,7 @@ from .exceptions import AidotOSError
|
|
|
12
12
|
_LOGGER = logging.getLogger(__name__)
|
|
13
13
|
# _DISCOVER_TIME = 15
|
|
14
14
|
|
|
15
|
-
_DISCOVER_FAST =
|
|
15
|
+
_DISCOVER_FAST = 6 # 启动时快速发现
|
|
16
16
|
_DISCOVER_SLOW = 120 # 稳定后慢速维持
|
|
17
17
|
|
|
18
18
|
class BroadcastProtocol:
|
|
@@ -111,7 +111,7 @@ class Discover:
|
|
|
111
111
|
|
|
112
112
|
def start_repeat_broadcast(self) -> None:
|
|
113
113
|
self._is_close = False
|
|
114
|
-
self._fast_discover_count =
|
|
114
|
+
self._fast_discover_count = 5 # 前5次快速
|
|
115
115
|
self._schedule_broadcast()
|
|
116
116
|
|
|
117
117
|
def _schedule_broadcast(self) -> None:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|