python-aidot 0.3.54b3__tar.gz → 0.3.54b4__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.54b3/python_aidot.egg-info → python_aidot-0.3.54b4}/PKG-INFO +1 -1
- {python_aidot-0.3.54b3 → python_aidot-0.3.54b4}/aidot/discover.py +2 -2
- python_aidot-0.3.54b4/aidot/models/__init__.py +37 -0
- python_aidot-0.3.54b4/aidot/models/device_client_model.py +210 -0
- python_aidot-0.3.54b4/aidot/models/device_model.py +83 -0
- python_aidot-0.3.54b4/aidot/models/discover_model.py +102 -0
- {python_aidot-0.3.54b3 → python_aidot-0.3.54b4/python_aidot.egg-info}/PKG-INFO +1 -1
- {python_aidot-0.3.54b3 → python_aidot-0.3.54b4}/python_aidot.egg-info/SOURCES.txt +4 -0
- {python_aidot-0.3.54b3 → python_aidot-0.3.54b4}/setup.py +1 -1
- {python_aidot-0.3.54b3 → python_aidot-0.3.54b4}/LICENSE +0 -0
- {python_aidot-0.3.54b3 → python_aidot-0.3.54b4}/README.md +0 -0
- {python_aidot-0.3.54b3 → python_aidot-0.3.54b4}/aidot/__init__.py +0 -0
- {python_aidot-0.3.54b3 → python_aidot-0.3.54b4}/aidot/aes_utils.py +0 -0
- {python_aidot-0.3.54b3 → python_aidot-0.3.54b4}/aidot/client.py +0 -0
- {python_aidot-0.3.54b3 → python_aidot-0.3.54b4}/aidot/const.py +0 -0
- {python_aidot-0.3.54b3 → python_aidot-0.3.54b4}/aidot/device_client.py +0 -0
- {python_aidot-0.3.54b3 → python_aidot-0.3.54b4}/aidot/exceptions.py +0 -0
- {python_aidot-0.3.54b3 → python_aidot-0.3.54b4}/aidot/login_const.py +0 -0
- {python_aidot-0.3.54b3 → python_aidot-0.3.54b4}/python_aidot.egg-info/dependency_links.txt +0 -0
- {python_aidot-0.3.54b3 → python_aidot-0.3.54b4}/python_aidot.egg-info/requires.txt +0 -0
- {python_aidot-0.3.54b3 → python_aidot-0.3.54b4}/python_aidot.egg-info/top_level.txt +0 -0
- {python_aidot-0.3.54b3 → python_aidot-0.3.54b4}/setup.cfg +0 -0
|
@@ -35,7 +35,7 @@ class BroadcastProtocol:
|
|
|
35
35
|
try:
|
|
36
36
|
request = DiscoverRequest.from_params(userId=self.user_id)
|
|
37
37
|
message = request.to_dict()
|
|
38
|
-
_LOGGER.
|
|
38
|
+
_LOGGER.warning(f"send_broadcast {message}")
|
|
39
39
|
send_data = aes_encrypt(json.dumps(message).encode(), self.aes_key)
|
|
40
40
|
self.transport.sendto(send_data, ("255.255.255.255", 6666))
|
|
41
41
|
except Exception as error:
|
|
@@ -46,7 +46,7 @@ class BroadcastProtocol:
|
|
|
46
46
|
data_str = aes_decrypt(data, self.aes_key)
|
|
47
47
|
data_json = json.loads(data_str)
|
|
48
48
|
response = DiscoverResponse.from_json(data=data_json)
|
|
49
|
-
_LOGGER.
|
|
49
|
+
_LOGGER.warning(f"datagram_received {data_json}")
|
|
50
50
|
if response.payload and response.payload.devId and self._discover_cb:
|
|
51
51
|
self._discover_cb(response.payload.devId, {CONF_IPADDRESS: addr[0]})
|
|
52
52
|
except Exception as error:
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Models for AiDot."""
|
|
2
|
+
|
|
3
|
+
from .device_client_model import (
|
|
4
|
+
DeviceAck,
|
|
5
|
+
DeviceAttr,
|
|
6
|
+
DeviceAttrPayload,
|
|
7
|
+
DeviceResponse,
|
|
8
|
+
DeviceActionPayload,
|
|
9
|
+
DeviceActionRequest,
|
|
10
|
+
LoginPayload,
|
|
11
|
+
LoginRequest,
|
|
12
|
+
PingRequest,
|
|
13
|
+
PingResponse,
|
|
14
|
+
)
|
|
15
|
+
from .device_model import (
|
|
16
|
+
DeviceFading,
|
|
17
|
+
DeviceProperties,
|
|
18
|
+
DeviceProduct,
|
|
19
|
+
DeviceInformation,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
"DeviceAck",
|
|
24
|
+
"DeviceAttr",
|
|
25
|
+
"DeviceAttrPayload",
|
|
26
|
+
"DeviceResponse",
|
|
27
|
+
"DeviceActionPayload",
|
|
28
|
+
"DeviceActionRequest",
|
|
29
|
+
"LoginPayload",
|
|
30
|
+
"LoginRequest",
|
|
31
|
+
"PingRequest",
|
|
32
|
+
"PingResponse",
|
|
33
|
+
"DeviceFading",
|
|
34
|
+
"DeviceProperties",
|
|
35
|
+
"DeviceProduct",
|
|
36
|
+
"DeviceInformation",
|
|
37
|
+
]
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"""Models for AiDot device client."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, asdict, field
|
|
4
|
+
from typing import Any, Optional
|
|
5
|
+
|
|
6
|
+
from dacite import Config, from_dict
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class PingRequest:
|
|
11
|
+
"""Ping request (heartbeat)."""
|
|
12
|
+
|
|
13
|
+
service: str = "test"
|
|
14
|
+
method: str = "pingreq"
|
|
15
|
+
seq: str = "123456"
|
|
16
|
+
srcAddr: str = "123456"
|
|
17
|
+
payload: dict[str, Any] = field(default_factory=dict)
|
|
18
|
+
|
|
19
|
+
def to_dict(self) -> dict[str, Any]:
|
|
20
|
+
"""Convert to dictionary."""
|
|
21
|
+
return asdict(self)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class PingResponse:
|
|
26
|
+
"""Ping response."""
|
|
27
|
+
|
|
28
|
+
service: str = None
|
|
29
|
+
method: str = None
|
|
30
|
+
seq: str = None
|
|
31
|
+
srcAddr: str = None
|
|
32
|
+
payload: dict[str, Any] = None
|
|
33
|
+
|
|
34
|
+
@staticmethod
|
|
35
|
+
def from_json(data: dict[str, Any]) -> "PingResponse":
|
|
36
|
+
"""Create PingResponse from JSON dict."""
|
|
37
|
+
return from_dict(
|
|
38
|
+
data_class=PingResponse, data=data, config=Config(check_types=False)
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
def to_dict(self) -> dict[str, Any]:
|
|
42
|
+
"""Convert to dictionary."""
|
|
43
|
+
return asdict(self)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass
|
|
47
|
+
class LoginPayload:
|
|
48
|
+
"""Login request payload."""
|
|
49
|
+
|
|
50
|
+
userId: str = None
|
|
51
|
+
password: str = None
|
|
52
|
+
timestamp: str = field(default=None)
|
|
53
|
+
ascNumber: int = 1
|
|
54
|
+
|
|
55
|
+
def __post_init__(self):
|
|
56
|
+
"""Auto-generate timestamp if not provided."""
|
|
57
|
+
if self.timestamp is None:
|
|
58
|
+
from datetime import datetime
|
|
59
|
+
self.timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@dataclass
|
|
63
|
+
class LoginRequest:
|
|
64
|
+
"""Login request."""
|
|
65
|
+
|
|
66
|
+
service: str = "device"
|
|
67
|
+
method: str = "loginReq"
|
|
68
|
+
seq: str = None
|
|
69
|
+
srcAddr: str = None
|
|
70
|
+
deviceId: str = None
|
|
71
|
+
payload: LoginPayload = None
|
|
72
|
+
|
|
73
|
+
def to_dict(self) -> dict[str, Any]:
|
|
74
|
+
"""Convert to dictionary."""
|
|
75
|
+
return asdict(self)
|
|
76
|
+
|
|
77
|
+
@dataclass
|
|
78
|
+
class DeviceAck:
|
|
79
|
+
"""Device response ack."""
|
|
80
|
+
|
|
81
|
+
code: int = 0
|
|
82
|
+
tst: str = ""
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@dataclass
|
|
86
|
+
class DeviceAttr:
|
|
87
|
+
"""Device attribute."""
|
|
88
|
+
|
|
89
|
+
OnOff: int = None
|
|
90
|
+
Dimming: int = None
|
|
91
|
+
RGBW: int = None
|
|
92
|
+
CCT: int = None
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@dataclass
|
|
96
|
+
class DeviceAttrPayload:
|
|
97
|
+
"""Device payload."""
|
|
98
|
+
|
|
99
|
+
devId: str = ""
|
|
100
|
+
parentId: str = ""
|
|
101
|
+
userId: str = ""
|
|
102
|
+
password: str = ""
|
|
103
|
+
timestamp: str = ""
|
|
104
|
+
channel: str = ""
|
|
105
|
+
ascNumber: int = 0
|
|
106
|
+
attr: Optional[DeviceAttr] = None
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@dataclass
|
|
110
|
+
class DeviceResponse:
|
|
111
|
+
"""Generic device response."""
|
|
112
|
+
|
|
113
|
+
service: str = ""
|
|
114
|
+
method: str = ""
|
|
115
|
+
seq: str = ""
|
|
116
|
+
srcAddr: str = ""
|
|
117
|
+
deviceId: str = ""
|
|
118
|
+
clientId: str = ""
|
|
119
|
+
payload: DeviceAttrPayload = field(default_factory=DeviceAttrPayload)
|
|
120
|
+
ack: DeviceAck = field(default_factory=DeviceAck)
|
|
121
|
+
tst: int = 0
|
|
122
|
+
|
|
123
|
+
@staticmethod
|
|
124
|
+
def from_json(data: dict[str, Any]) -> "DeviceResponse":
|
|
125
|
+
"""Create DeviceResponse from JSON dict."""
|
|
126
|
+
return from_dict(
|
|
127
|
+
data_class=DeviceResponse, data=data, config=Config(check_types=False)
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
def to_dict(self) -> dict[str, Any]:
|
|
131
|
+
"""Convert to dictionary."""
|
|
132
|
+
return asdict(self)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@dataclass
|
|
136
|
+
class DeviceActionPayload:
|
|
137
|
+
"""Device action payload."""
|
|
138
|
+
|
|
139
|
+
devId: str = ""
|
|
140
|
+
parentId: str = ""
|
|
141
|
+
userId: str = ""
|
|
142
|
+
password: str = ""
|
|
143
|
+
attr: dict[str, Any] = field(default_factory=dict)
|
|
144
|
+
channel: str = "tcp"
|
|
145
|
+
ascNumber: int = 0
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
@dataclass
|
|
149
|
+
class DeviceActionRequest:
|
|
150
|
+
"""Device action request."""
|
|
151
|
+
|
|
152
|
+
method: str = ""
|
|
153
|
+
service: str = "device"
|
|
154
|
+
clientId: str = ""
|
|
155
|
+
srcAddr: str = ""
|
|
156
|
+
seq: str = ""
|
|
157
|
+
payload: DeviceActionPayload = field(default_factory=DeviceActionPayload)
|
|
158
|
+
tst: int = 0
|
|
159
|
+
deviceId: str = ""
|
|
160
|
+
|
|
161
|
+
def __post_init__(self):
|
|
162
|
+
"""Auto-generate timestamp if not provided."""
|
|
163
|
+
if self.tst == 0:
|
|
164
|
+
import time
|
|
165
|
+
self.tst = int(time.time() * 1000)
|
|
166
|
+
|
|
167
|
+
def to_dict(self) -> dict[str, Any]:
|
|
168
|
+
"""Convert to dictionary."""
|
|
169
|
+
return asdict(self)
|
|
170
|
+
|
|
171
|
+
@staticmethod
|
|
172
|
+
def from_params(
|
|
173
|
+
method: str,
|
|
174
|
+
user_id: str,
|
|
175
|
+
device_id: str,
|
|
176
|
+
password: str,
|
|
177
|
+
ascNumber: int,
|
|
178
|
+
attr: dict[str, Any],
|
|
179
|
+
seq: str,
|
|
180
|
+
simpleVersion: str = None,
|
|
181
|
+
) -> "DeviceActionRequest":
|
|
182
|
+
"""Create DeviceActionRequest from params."""
|
|
183
|
+
if simpleVersion is not None:
|
|
184
|
+
return DeviceActionRequest(
|
|
185
|
+
method=method,
|
|
186
|
+
clientId="ha-" + user_id,
|
|
187
|
+
srcAddr="0." + user_id,
|
|
188
|
+
seq=seq,
|
|
189
|
+
payload=DeviceActionPayload(
|
|
190
|
+
devId=device_id,
|
|
191
|
+
parentId=device_id,
|
|
192
|
+
userId=user_id,
|
|
193
|
+
password=password,
|
|
194
|
+
attr=attr,
|
|
195
|
+
ascNumber=ascNumber,
|
|
196
|
+
),
|
|
197
|
+
deviceId=device_id,
|
|
198
|
+
)
|
|
199
|
+
else:
|
|
200
|
+
return DeviceActionRequest(
|
|
201
|
+
method=method,
|
|
202
|
+
srcAddr="0." + user_id,
|
|
203
|
+
seq=seq,
|
|
204
|
+
payload=DeviceActionPayload(
|
|
205
|
+
attr=attr,
|
|
206
|
+
ascNumber=ascNumber,
|
|
207
|
+
),
|
|
208
|
+
deviceId=device_id,
|
|
209
|
+
)
|
|
210
|
+
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""Models for AiDot device."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, asdict, field
|
|
4
|
+
from typing import Any, Optional, List
|
|
5
|
+
|
|
6
|
+
from dacite import Config, from_dict
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class DeviceFading:
|
|
11
|
+
"""Device fading config."""
|
|
12
|
+
|
|
13
|
+
in_value: Optional[int] = field(default=None, metadata={"alias": "in"})
|
|
14
|
+
out: Optional[int] = None
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class DeviceProperties:
|
|
19
|
+
"""Device properties."""
|
|
20
|
+
|
|
21
|
+
ssidName: str = None
|
|
22
|
+
ipAddress: str = None
|
|
23
|
+
macAddress: str = None
|
|
24
|
+
networkRssi: str = None
|
|
25
|
+
networkSecurity: str = None
|
|
26
|
+
wifiChannel: str = None
|
|
27
|
+
OnOff: str = None
|
|
28
|
+
Dimming: str = None
|
|
29
|
+
CCT: str = None
|
|
30
|
+
RGBW: str = None
|
|
31
|
+
EffectMode: str = None
|
|
32
|
+
Area: str = None
|
|
33
|
+
city: str = None
|
|
34
|
+
CityTimezone: str = None
|
|
35
|
+
lastNotifyCctRgbw: str = None
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass
|
|
39
|
+
class DeviceProduct:
|
|
40
|
+
"""Device product info."""
|
|
41
|
+
|
|
42
|
+
id: str = None
|
|
43
|
+
name: str = None
|
|
44
|
+
type: str = None
|
|
45
|
+
modelId: str = None
|
|
46
|
+
picture: str = None
|
|
47
|
+
icon: str = None
|
|
48
|
+
isDirectDevice: int = None
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass
|
|
52
|
+
class DeviceInformation:
|
|
53
|
+
"""Device information."""
|
|
54
|
+
|
|
55
|
+
id: str = None
|
|
56
|
+
name: str = None
|
|
57
|
+
mac: str = None
|
|
58
|
+
type: str = None
|
|
59
|
+
modelId: str = None
|
|
60
|
+
productId: str = None
|
|
61
|
+
houseId: str = None
|
|
62
|
+
roomId: str = None
|
|
63
|
+
online: bool = None
|
|
64
|
+
firmwareVersion: str = None
|
|
65
|
+
hardwareVersion: str = None
|
|
66
|
+
protocolVersion: str = None
|
|
67
|
+
picture: str = None
|
|
68
|
+
aesKey: List[str] = field(default_factory=list)
|
|
69
|
+
password: str = None
|
|
70
|
+
fading: Optional[DeviceFading] = None
|
|
71
|
+
properties: Optional[DeviceProperties] = None
|
|
72
|
+
product: Optional[DeviceProduct] = None
|
|
73
|
+
|
|
74
|
+
@staticmethod
|
|
75
|
+
def from_json(data: dict[str, Any]) -> "DeviceInformation":
|
|
76
|
+
"""Create DeviceInformation from JSON dict."""
|
|
77
|
+
return from_dict(
|
|
78
|
+
data_class=DeviceInformation, data=data, config=Config(check_types=False)
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
def to_dict(self) -> dict[str, Any]:
|
|
82
|
+
"""Convert to dictionary."""
|
|
83
|
+
return asdict(self)
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"""Models for AiDot discover."""
|
|
2
|
+
import time
|
|
3
|
+
from dataclasses import dataclass, asdict, field
|
|
4
|
+
from typing import Any, Optional
|
|
5
|
+
|
|
6
|
+
from dacite import Config, from_dict
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class DiscoverAck:
|
|
11
|
+
"""Discover response ack."""
|
|
12
|
+
|
|
13
|
+
code: int = None
|
|
14
|
+
tst: str = None
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class DiscoverExtends:
|
|
19
|
+
"""Discover payload extends."""
|
|
20
|
+
|
|
21
|
+
srvHost: str = None
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class DiscoverPayload:
|
|
26
|
+
"""Discover response payload."""
|
|
27
|
+
|
|
28
|
+
ip: str = None
|
|
29
|
+
mac: str = None
|
|
30
|
+
devId: str = None
|
|
31
|
+
productModel: str = None
|
|
32
|
+
bindFlag: int = None
|
|
33
|
+
conMode: int = None
|
|
34
|
+
lanMode: int = None
|
|
35
|
+
wifiMode: int = None
|
|
36
|
+
wifiBand: int = None
|
|
37
|
+
version: int = None
|
|
38
|
+
extends: Optional[DiscoverExtends] = None
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass
|
|
42
|
+
class DiscoverResponse:
|
|
43
|
+
"""Discover device response."""
|
|
44
|
+
|
|
45
|
+
srcAddr: str = None
|
|
46
|
+
seq: str = None
|
|
47
|
+
service: str = None
|
|
48
|
+
method: str = None
|
|
49
|
+
ack: DiscoverAck = None
|
|
50
|
+
protocolVer: str = None
|
|
51
|
+
payload: DiscoverPayload = None
|
|
52
|
+
|
|
53
|
+
@staticmethod
|
|
54
|
+
def from_json(data: dict[str, Any]) -> "DiscoverResponse":
|
|
55
|
+
"""Create DiscoverResponse from JSON dict."""
|
|
56
|
+
return from_dict(
|
|
57
|
+
data_class=DiscoverResponse, data=data, config=Config(check_types=False)
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
def to_dict(self) -> dict[str, Any]:
|
|
61
|
+
"""Convert to dictionary."""
|
|
62
|
+
return asdict(self)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@dataclass
|
|
66
|
+
class DiscoverRequestPayload:
|
|
67
|
+
"""Discover request payload."""
|
|
68
|
+
|
|
69
|
+
extends: dict[str, Any] = field(default_factory=dict)
|
|
70
|
+
localCtrFlag: int = 1
|
|
71
|
+
timestamp: str = None
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@dataclass
|
|
75
|
+
class DiscoverRequest:
|
|
76
|
+
"""Discover device request."""
|
|
77
|
+
|
|
78
|
+
protocolVer: str = "2.0.0"
|
|
79
|
+
service: str = "device"
|
|
80
|
+
method: str = "devDiscoveryReq"
|
|
81
|
+
seq: str = None
|
|
82
|
+
srcAddr: str = None
|
|
83
|
+
tst: int = None
|
|
84
|
+
payload: DiscoverRequestPayload = field(default_factory=DiscoverRequestPayload)
|
|
85
|
+
|
|
86
|
+
@staticmethod
|
|
87
|
+
def from_params(userId: str) -> "DiscoverResponse":
|
|
88
|
+
"""Create DiscoverResponse from JSON dict."""
|
|
89
|
+
current_timestamp_milliseconds = int(time.time() * 1000)
|
|
90
|
+
seq = str(current_timestamp_milliseconds + 1)[-9:]
|
|
91
|
+
return DiscoverRequest(
|
|
92
|
+
seq=seq,
|
|
93
|
+
srcAddr=f"0.{userId}",
|
|
94
|
+
tst=current_timestamp_milliseconds,
|
|
95
|
+
payload=DiscoverRequestPayload(
|
|
96
|
+
timestamp=str(current_timestamp_milliseconds)
|
|
97
|
+
)
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
def to_dict(self) -> dict[str, Any]:
|
|
101
|
+
"""Convert to dictionary."""
|
|
102
|
+
return asdict(self)
|
|
@@ -10,6 +10,10 @@ aidot/device_client.py
|
|
|
10
10
|
aidot/discover.py
|
|
11
11
|
aidot/exceptions.py
|
|
12
12
|
aidot/login_const.py
|
|
13
|
+
aidot/models/__init__.py
|
|
14
|
+
aidot/models/device_client_model.py
|
|
15
|
+
aidot/models/device_model.py
|
|
16
|
+
aidot/models/discover_model.py
|
|
13
17
|
python_aidot.egg-info/PKG-INFO
|
|
14
18
|
python_aidot.egg-info/SOURCES.txt
|
|
15
19
|
python_aidot.egg-info/dependency_links.txt
|
|
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
|
|
File without changes
|
|
File without changes
|