pymammotion 0.4.0b2__py3-none-any.whl → 0.4.0b4__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.
- pymammotion/data/model/report_info.py +1 -1
- pymammotion/mqtt/mammotion_mqtt.py +1 -1
- pymammotion/utility/constant/device_constant.py +18 -5
- {pymammotion-0.4.0b2.dist-info → pymammotion-0.4.0b4.dist-info}/METADATA +3 -2
- {pymammotion-0.4.0b2.dist-info → pymammotion-0.4.0b4.dist-info}/RECORD +7 -10
- pymammotion/mqtt/linkkit/__init__.py +0 -5
- pymammotion/mqtt/linkkit/h2client.py +0 -585
- pymammotion/mqtt/linkkit/linkkit.py +0 -3020
- {pymammotion-0.4.0b2.dist-info → pymammotion-0.4.0b4.dist-info}/LICENSE +0 -0
- {pymammotion-0.4.0b2.dist-info → pymammotion-0.4.0b4.dist-info}/WHEEL +0 -0
@@ -1,3020 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Copyright (c) 2014-2018 Alibaba Group. All rights reserved.
|
3
|
-
# License-Identifier: Apache-2.0
|
4
|
-
#
|
5
|
-
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
6
|
-
# not use this file except in compliance with the License.
|
7
|
-
# You may obtain a copy of the License at
|
8
|
-
#
|
9
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
-
#
|
11
|
-
# Unless required by applicable law or agreed to in writing, software
|
12
|
-
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
13
|
-
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
-
# See the License for the specific language governing permissions and
|
15
|
-
# limitations under the License.
|
16
|
-
#
|
17
|
-
#
|
18
|
-
|
19
|
-
from enum import Enum
|
20
|
-
import hashlib
|
21
|
-
import hmac
|
22
|
-
import json
|
23
|
-
import logging
|
24
|
-
import os
|
25
|
-
import queue
|
26
|
-
import random
|
27
|
-
import re
|
28
|
-
import ssl
|
29
|
-
import string
|
30
|
-
import sys
|
31
|
-
import threading
|
32
|
-
import time
|
33
|
-
import urllib.parse
|
34
|
-
import urllib.request
|
35
|
-
|
36
|
-
import paho.mqtt.client as mqtt
|
37
|
-
from paho.mqtt.enums import CallbackAPIVersion
|
38
|
-
|
39
|
-
REQUIRED_MAJOR_VERSION = 3
|
40
|
-
REQUIRED_MINOR_VERSION = 5
|
41
|
-
|
42
|
-
|
43
|
-
# check Python version
|
44
|
-
def lk_check_python_version(major_version, minor_version) -> None:
|
45
|
-
version = sys.version_info
|
46
|
-
if version[0] < major_version or (version[0] == major_version and version[1] < minor_version):
|
47
|
-
print(
|
48
|
-
"WARNING: linkit requires Python %d.%d or higher, and the current version is %s"
|
49
|
-
% (major_version, minor_version, sys.version)
|
50
|
-
)
|
51
|
-
|
52
|
-
|
53
|
-
lk_check_python_version(REQUIRED_MAJOR_VERSION, REQUIRED_MINOR_VERSION)
|
54
|
-
|
55
|
-
|
56
|
-
class LinkKit:
|
57
|
-
TAG_KEY = "attrKey"
|
58
|
-
TAG_VALUE = "attrValue"
|
59
|
-
|
60
|
-
class LinkKitState(Enum):
|
61
|
-
INITIALIZED = 1
|
62
|
-
CONNECTING = 2
|
63
|
-
CONNECTED = 3
|
64
|
-
DISCONNECTING = 4
|
65
|
-
DISCONNECTED = 5
|
66
|
-
DESTRUCTING = 6
|
67
|
-
DESTRUCTED = 7
|
68
|
-
|
69
|
-
class ErrorCode(Enum):
|
70
|
-
SUCCESS = 0
|
71
|
-
# 错误码一共三位数,第一位为0表示为mqtt相关的错误码
|
72
|
-
NETWORK_DISCONNECTED = -0x001 # 当前mqtt连接断开
|
73
|
-
INVALID_TOPIC = -0x002 # 输入的topic为空
|
74
|
-
INVALID_QOS = -0x003 # 输入的qos非法
|
75
|
-
PAHO_MQTT_ERROR = -0x004 # 底层的mqtt报错
|
76
|
-
# 0x100开头的表示为网关相关的错误码
|
77
|
-
NULL_SUBDEV_ERR = -0x101 # 输入的子设备信息为空错误
|
78
|
-
SUBDEV_NOT_ARRAY_ERR = -0x102 # 输入数据并非数组错误
|
79
|
-
ARRAY_LENGTH_ERR = -0x103 # 数组长度错误
|
80
|
-
# 0x300开头的表示为动态注册相关的错误码
|
81
|
-
DYNREG_AUTH_FAILED = -0x301 # 预注册动态注册认证失败
|
82
|
-
DYNREG_AUTH_NWL_FAILED = -0x302 # 免白动态注册认证失败
|
83
|
-
# 0x400开头表示为OTA有关的错误
|
84
|
-
OTA_INVALID_PARAM = -0x401 # 参数非法
|
85
|
-
OTA_DIGEST_MISMATCH = -0x402 # 校验和不通过
|
86
|
-
OTA_PUB_FAILED = -0x403 # 上报失败
|
87
|
-
OTA_INVALID_SIGN_METHOD = -0x404 # 非法校验方法
|
88
|
-
OTA_DOWNLOAD_FAIL = -0x405 # 下载失败
|
89
|
-
OTA_INVALID_URL = -0x406 # 无法访问HTTP链接
|
90
|
-
OTA_INVALID_PATH = -0x407 # 存储路径打开失败
|
91
|
-
|
92
|
-
class StateError(Exception):
|
93
|
-
def __init__(self, err) -> None:
|
94
|
-
Exception.__init__(self, err)
|
95
|
-
|
96
|
-
class Shadow:
|
97
|
-
def __init__(self) -> None:
|
98
|
-
self.__version = None
|
99
|
-
self.__timestamp = None
|
100
|
-
self.__state = None
|
101
|
-
self.__metadata = None
|
102
|
-
self.__latest_shadow_lock = threading.Lock()
|
103
|
-
self.__latest_received_time = None
|
104
|
-
self.__lastest_received_payload = None
|
105
|
-
|
106
|
-
def get_version(self):
|
107
|
-
with self.__latest_shadow_lock:
|
108
|
-
return self.__version
|
109
|
-
|
110
|
-
def get_metadata(self):
|
111
|
-
with self.__latest_shadow_lock:
|
112
|
-
return self.__metadata
|
113
|
-
|
114
|
-
def get_state(self):
|
115
|
-
with self.__latest_shadow_lock:
|
116
|
-
return self.__state
|
117
|
-
|
118
|
-
def set_state(self, state) -> None:
|
119
|
-
with self.__latest_shadow_lock:
|
120
|
-
self.__state = state
|
121
|
-
|
122
|
-
def set_metadata(self, metadata) -> None:
|
123
|
-
with self.__latest_shadow_lock:
|
124
|
-
self.__metadata = metadata
|
125
|
-
|
126
|
-
def set_version(self, version) -> None:
|
127
|
-
with self.__latest_shadow_lock:
|
128
|
-
self.__version = version
|
129
|
-
|
130
|
-
def set_timestamp(self, timestamp) -> None:
|
131
|
-
with self.__latest_shadow_lock:
|
132
|
-
self.__timestamp = timestamp
|
133
|
-
|
134
|
-
def set_latest_recevied_time(self, timestamp) -> None:
|
135
|
-
with self.__latest_shadow_lock:
|
136
|
-
self.__latest_received_time = timestamp
|
137
|
-
|
138
|
-
def get_latest_recevied_time(self):
|
139
|
-
with self.__latest_shadow_lock:
|
140
|
-
return self.__latest_received_time
|
141
|
-
|
142
|
-
def set_latest_recevied_payload(self, payload) -> None:
|
143
|
-
with self.__latest_shadow_lock:
|
144
|
-
self.__latest_received_payload = payload
|
145
|
-
|
146
|
-
def get_latest_recevied_payload(self):
|
147
|
-
with self.__latest_shadow_lock:
|
148
|
-
return self.__latest_received_payload
|
149
|
-
|
150
|
-
def to_dict(self):
|
151
|
-
return {
|
152
|
-
"state": self.__state,
|
153
|
-
"metadata": self.__metadata,
|
154
|
-
"version": self.__version,
|
155
|
-
"timestamp": self.__timestamp,
|
156
|
-
}
|
157
|
-
|
158
|
-
def to_json_string(self):
|
159
|
-
return json.dumps(self.to_dict())
|
160
|
-
|
161
|
-
class __HandlerTask:
|
162
|
-
def __init__(self, logger=None) -> None:
|
163
|
-
self.__logger = logger
|
164
|
-
if self.__logger is not None:
|
165
|
-
self.__logger.info("HandlerTask init enter")
|
166
|
-
self.__message_queue = queue.Queue(2000)
|
167
|
-
self.__cmd_callback = {}
|
168
|
-
self.__started = False
|
169
|
-
self.__exited = False
|
170
|
-
self.__thread = None
|
171
|
-
|
172
|
-
def register_cmd_callback(self, cmd, callback) -> int:
|
173
|
-
if self.__started is False:
|
174
|
-
if cmd != "req_exit":
|
175
|
-
self.__cmd_callback[cmd] = callback
|
176
|
-
return 0
|
177
|
-
else:
|
178
|
-
return 1
|
179
|
-
else:
|
180
|
-
return 2
|
181
|
-
|
182
|
-
def post_message(self, cmd, value) -> bool:
|
183
|
-
self.__logger.debug("post_message :%r " % cmd)
|
184
|
-
if self.__started and self.__exited is False:
|
185
|
-
try:
|
186
|
-
self.__message_queue.put((cmd, value), timeout=5)
|
187
|
-
except queue.Full as e:
|
188
|
-
self.__logger.error("queue full: %r" % e)
|
189
|
-
return False
|
190
|
-
self.__logger.debug("post_message success")
|
191
|
-
return True
|
192
|
-
self.__logger.debug("post_message fail started:%r,exited:%r" % (self.__started, self.__exited))
|
193
|
-
return False
|
194
|
-
|
195
|
-
def start(self) -> int:
|
196
|
-
if self.__logger is not None:
|
197
|
-
self.__logger.info("HandlerTask start")
|
198
|
-
if self.__started is False:
|
199
|
-
if self.__logger is not None:
|
200
|
-
self.__logger.info("HandlerTask try start")
|
201
|
-
self.__exited = False
|
202
|
-
self.__started = True
|
203
|
-
self.__message_queue = queue.Queue(2000)
|
204
|
-
self.__thread = threading.Thread(target=self.__thread_runnable)
|
205
|
-
self.__thread.daemon = True
|
206
|
-
self.__thread.start()
|
207
|
-
return 0
|
208
|
-
return 1
|
209
|
-
|
210
|
-
def stop(self) -> None:
|
211
|
-
if self.__started and self.__exited is False:
|
212
|
-
self.__exited = True
|
213
|
-
self.__message_queue.put(("req_exit", None))
|
214
|
-
|
215
|
-
def wait_stop(self) -> None:
|
216
|
-
if self.__started is True:
|
217
|
-
self.__thread.join()
|
218
|
-
|
219
|
-
def __thread_runnable(self) -> None:
|
220
|
-
if self.__logger is not None:
|
221
|
-
self.__logger.debug("thread runnable enter")
|
222
|
-
while True:
|
223
|
-
cmd, value = self.__message_queue.get()
|
224
|
-
self.__logger.debug("thread runnable pop cmd:%r" % cmd)
|
225
|
-
if cmd == "req_exit":
|
226
|
-
break
|
227
|
-
if self.__cmd_callback[cmd] is not None:
|
228
|
-
try:
|
229
|
-
self.__cmd_callback[cmd](value)
|
230
|
-
except Exception as e:
|
231
|
-
if self.__logger is not None:
|
232
|
-
self.__logger.error("thread runnable raise exception:%s" % e)
|
233
|
-
self.__started = False
|
234
|
-
if self.__logger is not None:
|
235
|
-
self.__logger.debug("thread runnable exit")
|
236
|
-
|
237
|
-
class LoopThread:
|
238
|
-
def __init__(self, logger=None) -> None:
|
239
|
-
self.__logger = logger
|
240
|
-
if logger is not None:
|
241
|
-
self.__logger.info("LoopThread init enter")
|
242
|
-
self.__callback = None
|
243
|
-
self.__thread = None
|
244
|
-
self.__started = False
|
245
|
-
self.__req_wait = threading.Event()
|
246
|
-
if logger is not None:
|
247
|
-
self.__logger.info("LoopThread init exit")
|
248
|
-
|
249
|
-
def start(self, callback) -> int:
|
250
|
-
if self.__started is True:
|
251
|
-
self.__logger.info("LoopThread already ")
|
252
|
-
return 1
|
253
|
-
else:
|
254
|
-
self.__callback = callback
|
255
|
-
self.__thread = threading.Thread(target=self.__thread_main)
|
256
|
-
self.__thread.daemon = True
|
257
|
-
self.__thread.start()
|
258
|
-
return 0
|
259
|
-
|
260
|
-
def stop(self) -> None:
|
261
|
-
self.__req_wait.wait()
|
262
|
-
self.__req_wait.clear()
|
263
|
-
|
264
|
-
def __thread_main(self) -> None:
|
265
|
-
self.__started = True
|
266
|
-
try:
|
267
|
-
if self.__logger is not None:
|
268
|
-
self.__logger.debug("LoopThread thread enter")
|
269
|
-
if self.__callback is not None:
|
270
|
-
self.__callback()
|
271
|
-
if self.__logger is not None:
|
272
|
-
self.__logger.debug("LoopThread thread exit")
|
273
|
-
except Exception as e:
|
274
|
-
self.__logger.error("LoopThread thread Exception:" + str(e))
|
275
|
-
self.__started = False
|
276
|
-
self.__req_wait.set()
|
277
|
-
|
278
|
-
def _on_file_upload_start(self, id, upload_file_info, user_data) -> None:
|
279
|
-
if self.__on_file_upload_begin != None:
|
280
|
-
self.__on_file_upload_begin(id, upload_file_info, self.__user_data)
|
281
|
-
|
282
|
-
def _on_file_upload_end(self, id, upload_file_info, upload_file_result, user_data) -> None:
|
283
|
-
if self.__on_file_upload_end != None:
|
284
|
-
self.__on_file_upload_end(id, upload_file_info, upload_file_result, self.__user_data)
|
285
|
-
|
286
|
-
def _on_file_upload_progress(self, id, upload_file_result, upload_file_info, user_data) -> None:
|
287
|
-
pass
|
288
|
-
|
289
|
-
class __LinkKitLog:
|
290
|
-
def __init__(self) -> None:
|
291
|
-
self.__logger = logging.getLogger("linkkit")
|
292
|
-
self.__enabled = False
|
293
|
-
|
294
|
-
def enable_logger(self) -> None:
|
295
|
-
self.__enabled = True
|
296
|
-
|
297
|
-
def disable_logger(self) -> None:
|
298
|
-
self.__enabled = False
|
299
|
-
|
300
|
-
def is_enabled(self):
|
301
|
-
return self.__enabled
|
302
|
-
|
303
|
-
def config_logger(self, level) -> None:
|
304
|
-
self.__logger.setLevel(level)
|
305
|
-
|
306
|
-
def debug(self, fmt, *args) -> None:
|
307
|
-
if self.__enabled:
|
308
|
-
self.__logger.debug(fmt, *args)
|
309
|
-
|
310
|
-
def warring(self, fmt, *args) -> None:
|
311
|
-
if self.__enabled:
|
312
|
-
self.__logger.warning(fmt, *args)
|
313
|
-
|
314
|
-
def info(self, fmt, *args) -> None:
|
315
|
-
if self.__enabled:
|
316
|
-
self.__logger.info(fmt, *args)
|
317
|
-
|
318
|
-
def error(self, fmt, *args) -> None:
|
319
|
-
if self.__enabled:
|
320
|
-
self.__logger.error(fmt, *args)
|
321
|
-
|
322
|
-
def critical(self, fmt, *args) -> None:
|
323
|
-
if self.__enabled:
|
324
|
-
self.__logger.critical(fmt, *args)
|
325
|
-
|
326
|
-
__USER_TOPIC_PREFIX = "/%s/%s/%s"
|
327
|
-
__ALIYUN_BROKER_CA_DATA = """
|
328
|
-
-----BEGIN CERTIFICATE-----
|
329
|
-
MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG
|
330
|
-
A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
|
331
|
-
b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
|
332
|
-
MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
|
333
|
-
YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
|
334
|
-
aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
|
335
|
-
jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
|
336
|
-
xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
|
337
|
-
1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
|
338
|
-
snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
|
339
|
-
U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
|
340
|
-
9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
|
341
|
-
BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B
|
342
|
-
AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz
|
343
|
-
yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE
|
344
|
-
38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP
|
345
|
-
AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
|
346
|
-
DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
|
347
|
-
HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
|
348
|
-
-----END CERTIFICATE-----
|
349
|
-
-----BEGIN CERTIFICATE-----
|
350
|
-
MIID3zCCAsegAwIBAgISfiX6mTa5RMUTGSC3rQhnestIMA0GCSqGSIb3DQEBCwUA
|
351
|
-
MHcxCzAJBgNVBAYTAkNOMREwDwYDVQQIDAhaaGVqaWFuZzERMA8GA1UEBwwISGFu
|
352
|
-
Z3pob3UxEzARBgNVBAoMCkFsaXl1biBJb1QxEDAOBgNVBAsMB1Jvb3QgQ0ExGzAZ
|
353
|
-
BgNVBAMMEkFsaXl1biBJb1QgUm9vdCBDQTAgFw0yMzA3MDQwNjM2NThaGA8yMDUz
|
354
|
-
MDcwNDA2MzY1OFowdzELMAkGA1UEBhMCQ04xETAPBgNVBAgMCFpoZWppYW5nMREw
|
355
|
-
DwYDVQQHDAhIYW5nemhvdTETMBEGA1UECgwKQWxpeXVuIElvVDEQMA4GA1UECwwH
|
356
|
-
Um9vdCBDQTEbMBkGA1UEAwwSQWxpeXVuIElvVCBSb290IENBMIIBIjANBgkqhkiG
|
357
|
-
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoK//6vc2oXhnvJD7BVhj6grj7PMlN2N4iNH4
|
358
|
-
GBmLmMdkF1z9eQLjksYc4Zid/FX67ypWFtdycOei5ec0X00m53Gvy4zLGBo2uKgi
|
359
|
-
T9IxMudmt95bORZbaph4VK82gPNU4ewbiI1q2loRZEHRdyPORTPpvNLHu8DrYBnY
|
360
|
-
Vg5feEYLLyhxg5M1UTrT/30RggHpaa0BYIPxwsKyylQ1OskOsyZQeOyPe8t8r2D4
|
361
|
-
RBpUGc5ix4j537HYTKSyK3Hv57R7w1NzKtXoOioDOm+YySsz9sTLFajZkUcQci4X
|
362
|
-
aedyEeguDLAIUKiYicJhRCZWljVlZActorTgjCY4zRajodThrQIDAQABo2MwYTAO
|
363
|
-
BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUkWHoKi2h
|
364
|
-
DlS1/rYpcT/Ue+aKhP8wHwYDVR0jBBgwFoAUkWHoKi2hDlS1/rYpcT/Ue+aKhP8w
|
365
|
-
DQYJKoZIhvcNAQELBQADggEBADrrLcBY7gDXN8/0KHvPbGwMrEAJcnF9z4MBxRvt
|
366
|
-
rEoRxhlvRZzPi7w/868xbipwwnksZsn0QNIiAZ6XzbwvIFG01ONJET+OzDy6ZqUb
|
367
|
-
YmJI09EOe9/Hst8Fac2D14Oyw0+6KTqZW7WWrP2TAgv8/Uox2S05pCWNfJpRZxOv
|
368
|
-
Lr4DZmnXBJCMNMY/X7xpcjylq+uCj118PBobfH9Oo+iAJ4YyjOLmX3bflKIn1Oat
|
369
|
-
vdJBtXCj3phpfuf56VwKxoxEVR818GqPAHnz9oVvye4sQqBp/2ynrKFxZKUaJtk0
|
370
|
-
7UeVbtecwnQTrlcpWM7ACQC0OO0M9+uNjpKIbksv1s11xu0=
|
371
|
-
-----END CERTIFICATE-----
|
372
|
-
-----BEGIN CERTIFICATE-----
|
373
|
-
MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDE
|
374
|
-
gMB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2
|
375
|
-
JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNM
|
376
|
-
zQxMjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBS
|
377
|
-
NjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiI
|
378
|
-
wDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQ
|
379
|
-
ssgrRIxutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuT
|
380
|
-
ToVBu1kZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSK
|
381
|
-
vGRMIRxDaNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n
|
382
|
-
16qIfKtJwLnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9
|
383
|
-
CgYXfIWHSw1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJ
|
384
|
-
Da38O+2HBNXk7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiW
|
385
|
-
m05OWgtH8wY2SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4
|
386
|
-
UoQSwC+n+7o/hbguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQ
|
387
|
-
Ce24DWJfncBZ4nWUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFl
|
388
|
-
WQaYw55PfWzjMpYrZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZ
|
389
|
-
cIN5kZeR1BonvzceMgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjA
|
390
|
-
PBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToD
|
391
|
-
AfBgNVHSMEGDAWgBSubAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFA
|
392
|
-
AOCAgEAgyXt6NH9lVLNnsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcW
|
393
|
-
c+ZfwFSY1XS+wc3iEZGtIxg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKP
|
394
|
-
rmzU+sQghoefEQzd5Mr6155wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waN
|
395
|
-
rlU/yDXNOd8v9EDERm8tLjvUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944
|
396
|
-
Hn+Xds+qkxV/ZoVqW/hpvvfcDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl
|
397
|
-
+68KnyBr3TsTjxKM4kEaSHpzoHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU
|
398
|
-
3/gKbaKxCXcPu9czc8FB10jZpnOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTO
|
399
|
-
wY3WzvUy2MmeFe8nI+z1TIvWfspA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsVi
|
400
|
-
VO6LAUP5MSeGbEYNNVMnbrt9x+vJJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9
|
401
|
-
x8jvOOJckvB595yEunQtYQEgfn7R8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDf
|
402
|
-
LRVpOoERIyNiwmcUVhAn21klJwGW45hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA=
|
403
|
-
-----END CERTIFICATE-----
|
404
|
-
-----BEGIN CERTIFICATE-----
|
405
|
-
MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDME
|
406
|
-
YxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYD
|
407
|
-
VQQDExNHbG9iYWxTaWduIFJvb3QgRTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MD
|
408
|
-
MyMDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24g
|
409
|
-
bnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcqhkjOPQ
|
410
|
-
IBBgUrgQQAIgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omw
|
411
|
-
lwxwEwkBjtjqR+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4
|
412
|
-
Tb+0cUB+hflGddyXqBPCCjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8E
|
413
|
-
BTADAQH/MB0GA1UdDgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAKBggqhkjOPQ
|
414
|
-
QDAwNoADBlAjEA31SQ7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZkvLtoURMMA/cV
|
415
|
-
i4RguYv/Uo7njLwcAjA8+RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/alt
|
416
|
-
P+CAezNIm8BZ/3Hobui3A=
|
417
|
-
-----END CERTIFICATE-----
|
418
|
-
-----BEGIN CERTIFICATE-----
|
419
|
-
MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAU
|
420
|
-
AMEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGg
|
421
|
-
YDVQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2M
|
422
|
-
DMyMDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24g
|
423
|
-
bnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIiMA0GCSqGSIb
|
424
|
-
3DQEBAQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08
|
425
|
-
EsCVeJOaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUl
|
426
|
-
ghYruQGvGIFAha/r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTq
|
427
|
-
a1VbkNud316HCkD7rRlr+/fKYIje2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/O
|
428
|
-
rffGFqfUo0q3v84RLHIf8E6M6cqJaESvWJ3En7YEtbWaBkoe0G1h6zD8K+kZPT
|
429
|
-
Xhc+CtI4wSEy132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvjK8Cd+RTy
|
430
|
-
G/FWaha/LIWFzXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0N
|
431
|
-
XfeD412lPFzYE+cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JM
|
432
|
-
WKmIJ5jqSngiCNI/onccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+F
|
433
|
-
fy7dXxd7Pj2Fxzsx2sZy/N78CsHpdlseVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7
|
434
|
-
/mrLZqrcZdCinkqaByFrgY/bxFn63iLABJzjqls2k+g9vXqhnQt2sQvHnf3PmKg
|
435
|
-
Gwvgqo6GDoLclcqUC4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQ
|
436
|
-
H/BAUwAwEB/zAdBgNVHQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIh
|
437
|
-
vcNAQEMBQADggIBAHx47PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048
|
438
|
-
p9gkUbJUHJNOxO97k4VgJuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63b
|
439
|
-
EIaZHU1VNaL8FpO7XJqti2kM3S+LGteWygxk6x9PbTZ4IevPuzz5i+6zoYMzRx6
|
440
|
-
Fcg0XERczzF2sUyQQCPtIkpnnpHs6i58FZFZ8d4kuaPp92CC1r2LpXFNqD6v6MV
|
441
|
-
enQTqnMdzGxRBF6XLE+0xRFFRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZmOUdk
|
442
|
-
LG5NrmJ7v2B0GbhWrJKsFjLtrWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSy
|
443
|
-
BQ7N0H3qqJZ4d16GLuc1CLgSkZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7f
|
444
|
-
XwgNNgyYMqIgXQBztSvwyeqiv5u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJ
|
445
|
-
Mbfc2hIkCwU9D9SGuTSyxTDYWnP4vkYxboznxSjBF25cfe1lNj2M8FawTSLfJvd
|
446
|
-
kzrnE6JwYZ+vj+vYxXX4M2bUdGc6N3ec592kD3ZDZopD8p/7DEJ4Y9HiD2971KE
|
447
|
-
9dJeFt0g5QdYg/NA6s/rob8SKunE3vouXsXgxT7PntgMTzlSdriVZzH81Xwj3QE
|
448
|
-
UxeCp6
|
449
|
-
-----END CERTIFICATE-----
|
450
|
-
"""
|
451
|
-
|
452
|
-
def __init__(
|
453
|
-
self,
|
454
|
-
host_name,
|
455
|
-
product_key,
|
456
|
-
device_name,
|
457
|
-
device_secret,
|
458
|
-
auth_type=None,
|
459
|
-
username=None,
|
460
|
-
client_id=None,
|
461
|
-
password=None,
|
462
|
-
instance_id=None,
|
463
|
-
product_secret=None,
|
464
|
-
user_data=None,
|
465
|
-
) -> None:
|
466
|
-
# logging configs
|
467
|
-
self.__just_for_pycharm_autocomplete = False
|
468
|
-
|
469
|
-
def __str_is_empty(value) -> bool:
|
470
|
-
if value is None or value == "":
|
471
|
-
return True
|
472
|
-
else:
|
473
|
-
return False
|
474
|
-
|
475
|
-
# param check
|
476
|
-
if __str_is_empty(host_name):
|
477
|
-
raise ValueError("host_name wrong")
|
478
|
-
if __str_is_empty(product_key):
|
479
|
-
raise ValueError("product key wrong")
|
480
|
-
if __str_is_empty(device_name):
|
481
|
-
raise ValueError("device name wrong")
|
482
|
-
if __str_is_empty(device_secret) and __str_is_empty(product_secret):
|
483
|
-
lack_other_auth_info = __str_is_empty(username) or __str_is_empty(client_id) or __str_is_empty(password)
|
484
|
-
if lack_other_auth_info:
|
485
|
-
raise ValueError("device secret & product secret are both empty")
|
486
|
-
|
487
|
-
self.__link_log = LinkKit.__LinkKitLog()
|
488
|
-
self.__PahoLog = logging.getLogger("Paho")
|
489
|
-
self.__PahoLog.setLevel(logging.DEBUG)
|
490
|
-
|
491
|
-
# config internal property
|
492
|
-
self.__host_name = host_name
|
493
|
-
self.__product_key = product_key
|
494
|
-
self.__device_name = device_name
|
495
|
-
self.__device_secret = device_secret
|
496
|
-
self.__product_secret = product_secret
|
497
|
-
self.__user_data = user_data
|
498
|
-
self.__device_interface_info = ""
|
499
|
-
self.__device_mac = None
|
500
|
-
self.__cellular_IMEI = None
|
501
|
-
self.__cellular_ICCID = None
|
502
|
-
self.__cellular_IMSI = None
|
503
|
-
self.__cellular_MSISDN = None
|
504
|
-
self.__mqtt_client = None
|
505
|
-
self.__sdk_version = "1.2.13"
|
506
|
-
self.__sdk_program_language = "Python"
|
507
|
-
self.__endpoint = None
|
508
|
-
self.__check_hostname = True
|
509
|
-
self.__instance_id = instance_id
|
510
|
-
|
511
|
-
self.__mqtt_port = 8883
|
512
|
-
self.__mqtt_protocol = "MQTTv311"
|
513
|
-
self.__mqtt_transport = "TCP"
|
514
|
-
self.__mqtt_secure = "TLS"
|
515
|
-
self.__mqtt_keep_alive = 60
|
516
|
-
self.__mqtt_clean_session = True
|
517
|
-
self.__mqtt_max_inflight_message = 20
|
518
|
-
self.__mqtt_max_queued_message = 40
|
519
|
-
self.__mqtt_auto_reconnect_min_sec = 1
|
520
|
-
self.__mqtt_auto_reconnect_max_sec = 60
|
521
|
-
self.__mqtt_auto_reconnect_sec = 0
|
522
|
-
self.__mqtt_request_timeout = 10
|
523
|
-
# 动态注册(免预注册)的flag
|
524
|
-
self.__dynamic_register_nwl_flag = 0
|
525
|
-
# 动态注册(预注册)的flag
|
526
|
-
self.__dynamic_register_flag = 0
|
527
|
-
self.__linkkit_state = LinkKit.LinkKitState.INITIALIZED
|
528
|
-
self.__aliyun_broker_ca_data = self.__ALIYUN_BROKER_CA_DATA
|
529
|
-
self.__force_reconnect = False
|
530
|
-
|
531
|
-
self.__latest_shadow = LinkKit.Shadow()
|
532
|
-
self.__auth_type = auth_type
|
533
|
-
self.__username = username
|
534
|
-
self.__client_id = client_id
|
535
|
-
self.__password = password
|
536
|
-
|
537
|
-
# aliyun IoT callbacks
|
538
|
-
self.__on_device_dynamic_register = None
|
539
|
-
|
540
|
-
# mqtt callbacks
|
541
|
-
self.__on_connect = None
|
542
|
-
self.__on_disconnect = None
|
543
|
-
self.__on_publish_topic = None
|
544
|
-
self.__on_subscribe_topic = None
|
545
|
-
self.__on_unsubscribe_topic = None
|
546
|
-
self.__on_topic_message = None
|
547
|
-
|
548
|
-
self.__on_topic_rrpc_message = None
|
549
|
-
self.__on_subscribe_rrpc_topic = None
|
550
|
-
self.__on_unsubscribe_rrpc_topic = None
|
551
|
-
|
552
|
-
# thing model callbacks
|
553
|
-
self.__on_thing_create = None
|
554
|
-
self.__on_thing_enable = None
|
555
|
-
self.__on_thing_disable = None
|
556
|
-
self.__on_thing_raw_data_arrived = None
|
557
|
-
self.__on_thing_raw_data_post = None
|
558
|
-
self.__on_thing_call_service = None
|
559
|
-
self.__on_thing_prop_changed = None
|
560
|
-
self.__on_thing_event_post = None
|
561
|
-
self.__on_thing_prop_post = None
|
562
|
-
self.__on_thing_shadow_get = None
|
563
|
-
self.__on_thing_device_info_update = None
|
564
|
-
self.__on_thing_device_info_delete = None
|
565
|
-
|
566
|
-
self.__on_file_upload_begin = None
|
567
|
-
self.__on_file_upload_end = None
|
568
|
-
|
569
|
-
self.__user_topics = {}
|
570
|
-
self.__user_topics_subscribe_request = {}
|
571
|
-
self.__user_topics_unsubscribe_request = {}
|
572
|
-
self.__user_topics_request_lock = threading.Lock()
|
573
|
-
self.__user_topics_unsubscribe_request_lock = threading.Lock()
|
574
|
-
|
575
|
-
self.__user_rrpc_topics = {}
|
576
|
-
self.__user_rrpc_topics_lock = threading.RLock()
|
577
|
-
self.__user_rrpc_topics_subscribe_request = {}
|
578
|
-
self.__user_rrpc_topics_unsubscribe_request = {}
|
579
|
-
self.__user_rrpc_topics_subscribe_request_lock = threading.RLock()
|
580
|
-
self.__user_rrpc_topics_unsubscribe_request_lock = threading.RLock()
|
581
|
-
self.__user_rrpc_request_ids = []
|
582
|
-
self.__user_rrpc_request_id_index_map = {}
|
583
|
-
self.__user_rrpc_request_ids_lock = threading.RLock()
|
584
|
-
self.__user_rrpc_request_max_len = 100
|
585
|
-
|
586
|
-
# things topic - Alink
|
587
|
-
self.__thing_topic_prop_post = "/sys/%s/%s/thing/event/property/post" % (self.__product_key, self.__device_name)
|
588
|
-
self.__thing_topic_prop_post_reply = self.__thing_topic_prop_post + "_reply"
|
589
|
-
self.__thing_topic_prop_set = "/sys/%s/%s/thing/service/property/set" % (self.__product_key, self.__device_name)
|
590
|
-
self.__thing_topic_prop_set_reply = self.__thing_topic_prop_set + "_reply"
|
591
|
-
self.__thing_topic_prop_get = "/sys/%s/%s/thing/service/property/get" % (self.__product_key, self.__device_name)
|
592
|
-
self.__thing_topic_event_post_pattern = "/sys/%s/%s/thing/event/%s/post"
|
593
|
-
self.__gateway_topic_add_subdev_topo = "/sys/%s/%s/thing/topo/add" % (self.__product_key, self.__device_name)
|
594
|
-
self.__gateway_topic_add_subdev_topo_reply = self.__gateway_topic_add_subdev_topo + "_reply"
|
595
|
-
|
596
|
-
self.__gateway_topic_delete_subdev_topo = "/sys/%s/%s/thing/topo/delete" % (
|
597
|
-
self.__product_key,
|
598
|
-
self.__device_name,
|
599
|
-
)
|
600
|
-
self.__gateway_topic_delete_subdev_topo_reply = self.__gateway_topic_delete_subdev_topo + "_reply"
|
601
|
-
|
602
|
-
self.__gateway_topic_login_subdev = "/ext/session/%s/%s/combine/batch_login" % (
|
603
|
-
self.__product_key,
|
604
|
-
self.__device_name,
|
605
|
-
)
|
606
|
-
self.__gateway_topic_login_subdev_reply = self.__gateway_topic_login_subdev + "_reply"
|
607
|
-
|
608
|
-
self.__gateway_topic_logout_subdev = "/ext/session/%s/%s/combine/batch_logout" % (
|
609
|
-
self.__product_key,
|
610
|
-
self.__device_name,
|
611
|
-
)
|
612
|
-
self.__gateway_topic_logout_subdev_reply = self.__gateway_topic_logout_subdev + "_reply"
|
613
|
-
|
614
|
-
self.__gateway_topic_register_subdev = "/sys/%s/%s/thing/sub/register" % (
|
615
|
-
self.__product_key,
|
616
|
-
self.__device_name,
|
617
|
-
)
|
618
|
-
self.__gateway_topic_register_subdev_reply = self.__gateway_topic_register_subdev + "_reply"
|
619
|
-
|
620
|
-
self.__gateway_topic_product_register_subdev = "/sys/%s/%s/thing/proxy/provisioning/product_register" % (
|
621
|
-
self.__product_key,
|
622
|
-
self.__device_name,
|
623
|
-
)
|
624
|
-
self.__gateway_topic_product_register_subdev_reply = self.__gateway_topic_product_register_subdev + "_reply"
|
625
|
-
|
626
|
-
self.__gateway_topic_topo_change = "/sys/%s/%s/thing/topo/change" % (self.__product_key, self.__device_name)
|
627
|
-
self.__dynamic_register_nwl_topic = "/ext/regnwl"
|
628
|
-
self.__dynamic_register_topic = "/ext/register"
|
629
|
-
|
630
|
-
self.__ota_report_version_topic = "/ota/device/inform/%s/%s" % (self.__product_key, self.__device_name)
|
631
|
-
self.__ota_push_topic = "/ota/device/upgrade/%s/%s" % (self.__product_key, self.__device_name)
|
632
|
-
self.__ota_pull_topic = "/sys/%s/%s/thing/ota/firmware/get" % (self.__product_key, self.__device_name)
|
633
|
-
self.__ota_pull_reply_topic = "/sys/%s/%s/thing/ota/firmware/get_reply" % (
|
634
|
-
self.__product_key,
|
635
|
-
self.__device_name,
|
636
|
-
)
|
637
|
-
|
638
|
-
self.__thing_prop_post_mid = {}
|
639
|
-
self.__thing_prop_post_mid_lock = threading.Lock()
|
640
|
-
self.__thing_prop_set_reply_mid = {}
|
641
|
-
self.__thing_prop_set_reply_mid_lock = threading.Lock()
|
642
|
-
self.__gateway_add_subdev_topo_mid = {}
|
643
|
-
self.__gateway_add_subdev_topo_mid_lock = threading.Lock()
|
644
|
-
self.__gateway_delete_subdev_topo_mid = {}
|
645
|
-
self.__gateway_delete_subdev_topo_mid_lock = threading.Lock()
|
646
|
-
# event:post topic
|
647
|
-
self.__thing_topic_event_post = {}
|
648
|
-
self.__thing_topic_event_post_reply = set()
|
649
|
-
self.__thing_events = set()
|
650
|
-
self.__thing_request_id_max = 1000000
|
651
|
-
self.__thing_request_value = 0
|
652
|
-
self.__thing_request_id = {}
|
653
|
-
self.__thing_request_id_lock = threading.Lock()
|
654
|
-
self.__thing_event_post_mid = {}
|
655
|
-
self.__thing_event_post_mid_lock = threading.Lock()
|
656
|
-
|
657
|
-
self.__thing_topic_shadow_get = "/shadow/get/%s/%s" % (self.__product_key, self.__device_name)
|
658
|
-
self.__thing_topic_shadow_update = "/shadow/update/%s/%s" % (self.__product_key, self.__device_name)
|
659
|
-
self.__thing_shadow_mid = {}
|
660
|
-
self.__thing_shadow_mid_lock = threading.Lock()
|
661
|
-
|
662
|
-
# service topic
|
663
|
-
self.__thing_topic_service_pattern = "/sys/%s/%s/thing/service/%s"
|
664
|
-
self.__thing_topic_services = set()
|
665
|
-
self.__thing_topic_services_reply = set()
|
666
|
-
self.__thing_services = set()
|
667
|
-
self.__thing_answer_service_mid = {}
|
668
|
-
self.__thing_answer_service_mid_lock = threading.Lock()
|
669
|
-
|
670
|
-
# thing topic - raw
|
671
|
-
self.__thing_topic_raw_up = "/sys/%s/%s/thing/model/up_raw" % (self.__product_key, self.__device_name)
|
672
|
-
self.__thing_topic_raw_up_reply = self.__thing_topic_raw_up + "_reply"
|
673
|
-
self.__thing_topic_raw_down = "/sys/%s/%s/thing/model/down_raw" % (self.__product_key, self.__device_name)
|
674
|
-
self.__thing_topic_raw_down_reply = self.__thing_topic_raw_down + "_reply"
|
675
|
-
self.__thing_raw_up_mid = {}
|
676
|
-
self.__thing_raw_up_mid_lock = threading.Lock()
|
677
|
-
self.__thing_raw_down_reply_mid = {}
|
678
|
-
self.__thing_raw_down_reply_mid_lock = threading.Lock()
|
679
|
-
|
680
|
-
# thing topic - device_info
|
681
|
-
self.__thing_topic_update_device_info_up = "/sys/%s/%s/thing/deviceinfo/update" % (
|
682
|
-
self.__product_key,
|
683
|
-
self.__device_name,
|
684
|
-
)
|
685
|
-
self.__thing_topic_update_device_info_reply = self.__thing_topic_update_device_info_up + "_reply"
|
686
|
-
self.__thing_topic_delete_device_info_up = "/sys/%s/%s/thing/deviceinfo/delete" % (
|
687
|
-
self.__product_key,
|
688
|
-
self.__device_name,
|
689
|
-
)
|
690
|
-
self.__thing_topic_delete_device_info_reply = self.__thing_topic_delete_device_info_up + "_reply"
|
691
|
-
self.__thing_update_device_info_up_mid = {}
|
692
|
-
self.__thing_update_device_info_up_mid_lock = threading.Lock()
|
693
|
-
self.__thing_delete_device_info_up_mid = {}
|
694
|
-
self.__thing_delete_device_info_up_mid_lock = threading.Lock()
|
695
|
-
|
696
|
-
# properties
|
697
|
-
self.__thing_properties_set = set()
|
698
|
-
self.__thing_properties_get = set()
|
699
|
-
self.__thing_properties_post = set()
|
700
|
-
|
701
|
-
# thing setup state
|
702
|
-
self.__thing_setup_state = False
|
703
|
-
self.__thing_raw_only = False
|
704
|
-
self.__thing_enable_state = False
|
705
|
-
self.__on_gateway_add_subdev_topo_reply = None
|
706
|
-
self.__on_gateway_delete_subdev_topo_reply = None
|
707
|
-
self.__on_gateway_login_subdev_reply = None
|
708
|
-
self.__on_gateway_logout_subdev_reply = None
|
709
|
-
self.__on_gateway_register_subdev_reply = None
|
710
|
-
self.__on_gateway_product_register_subdev_reply = None
|
711
|
-
self.__on_gateway_topo_change = None
|
712
|
-
self.__on_device_dynamic_register_nwl_reply = None
|
713
|
-
self.__on_ota_message_arrived = None
|
714
|
-
|
715
|
-
if self.__just_for_pycharm_autocomplete:
|
716
|
-
self.__mqtt_client = mqtt.Client(CallbackAPIVersion.VERSION1)
|
717
|
-
|
718
|
-
# device interface info
|
719
|
-
self.__device_info_topic = "/sys/%s/%s/thing/deviceinfo/update" % (self.__product_key, self.__device_name)
|
720
|
-
self.__device_info_topic_reply = self.__device_info_topic + "_reply"
|
721
|
-
self.__device_info_mid_lock = threading.Lock()
|
722
|
-
self.__device_info_mid = {}
|
723
|
-
|
724
|
-
# connect_async
|
725
|
-
self.__connect_async_req = False
|
726
|
-
self.__worker_loop_exit_req = False
|
727
|
-
self.__worker_loop_runing_state = False
|
728
|
-
self.__worker_loop_exit_req_lock = threading.Lock()
|
729
|
-
|
730
|
-
# loop thread
|
731
|
-
self.__loop_thread = LinkKit.LoopThread(self.__link_log)
|
732
|
-
|
733
|
-
# HandlerTask
|
734
|
-
self.__handler_task = LinkKit.__HandlerTask(self.__link_log)
|
735
|
-
self.__handler_task_cmd_on_connect = "on_connect"
|
736
|
-
self.__handler_task_cmd_on_disconnect = "on_disconnect"
|
737
|
-
self.__handler_task_cmd_on_message = "on_message"
|
738
|
-
self.__handler_task_cmd_on_publish = "on_publish"
|
739
|
-
self.__handler_task_cmd_on_subscribe = "on_subscribe"
|
740
|
-
self.__handler_task_cmd_on_unsubscribe = "on_unsubscribe"
|
741
|
-
self.__handler_task.register_cmd_callback(
|
742
|
-
self.__handler_task_cmd_on_connect, self.__handler_task_on_connect_callback
|
743
|
-
)
|
744
|
-
self.__handler_task.register_cmd_callback(
|
745
|
-
self.__handler_task_cmd_on_disconnect, self.__handler_task_on_disconnect_callback
|
746
|
-
)
|
747
|
-
self.__handler_task.register_cmd_callback(
|
748
|
-
self.__handler_task_cmd_on_message, self.__handler_task_on_message_callback
|
749
|
-
)
|
750
|
-
self.__handler_task.register_cmd_callback(
|
751
|
-
self.__handler_task_cmd_on_publish, self.__handler_task_on_publish_callback
|
752
|
-
)
|
753
|
-
self.__handler_task.register_cmd_callback(
|
754
|
-
self.__handler_task_cmd_on_subscribe, self.__handler_task_on_subscribe_callback
|
755
|
-
)
|
756
|
-
self.__handler_task.register_cmd_callback(
|
757
|
-
self.__handler_task_cmd_on_unsubscribe, self.__handler_task_on_unsubscribe_callback
|
758
|
-
)
|
759
|
-
self.__handler_task.start()
|
760
|
-
|
761
|
-
@property
|
762
|
-
def on_device_dynamic_register(self):
|
763
|
-
return None
|
764
|
-
|
765
|
-
@on_device_dynamic_register.setter
|
766
|
-
def on_device_dynamic_register(self, value) -> None:
|
767
|
-
self.__on_device_dynamic_register = value
|
768
|
-
|
769
|
-
@property
|
770
|
-
def on_connect(self):
|
771
|
-
return self.__on_connect
|
772
|
-
|
773
|
-
@on_connect.setter
|
774
|
-
def on_connect(self, value) -> None:
|
775
|
-
self.__on_connect = value
|
776
|
-
|
777
|
-
@property
|
778
|
-
def on_disconnect(self):
|
779
|
-
return self.__on_disconnect
|
780
|
-
|
781
|
-
@on_disconnect.setter
|
782
|
-
def on_disconnect(self, value) -> None:
|
783
|
-
self.__on_disconnect = value
|
784
|
-
|
785
|
-
@property
|
786
|
-
def on_publish_topic(self):
|
787
|
-
return None
|
788
|
-
|
789
|
-
@on_publish_topic.setter
|
790
|
-
def on_publish_topic(self, value) -> None:
|
791
|
-
self.__on_publish_topic = value
|
792
|
-
|
793
|
-
@property
|
794
|
-
def on_subscribe_topic(self):
|
795
|
-
return None
|
796
|
-
|
797
|
-
@on_subscribe_topic.setter
|
798
|
-
def on_subscribe_topic(self, value) -> None:
|
799
|
-
self.__on_subscribe_topic = value
|
800
|
-
|
801
|
-
@property
|
802
|
-
def on_unsubscribe_topic(self):
|
803
|
-
return None
|
804
|
-
|
805
|
-
@on_unsubscribe_topic.setter
|
806
|
-
def on_unsubscribe_topic(self, value) -> None:
|
807
|
-
self.__on_unsubscribe_topic = value
|
808
|
-
|
809
|
-
@property
|
810
|
-
def on_topic_message(self):
|
811
|
-
return None
|
812
|
-
|
813
|
-
@on_topic_message.setter
|
814
|
-
def on_topic_message(self, value) -> None:
|
815
|
-
self.__on_topic_message = value
|
816
|
-
|
817
|
-
@property
|
818
|
-
def on_topic_rrpc_message(self):
|
819
|
-
return None
|
820
|
-
|
821
|
-
@on_topic_rrpc_message.setter
|
822
|
-
def on_topic_rrpc_message(self, value) -> None:
|
823
|
-
self.__on_topic_rrpc_message = value
|
824
|
-
|
825
|
-
@property
|
826
|
-
def on_thing_create(self):
|
827
|
-
return None
|
828
|
-
|
829
|
-
@on_thing_create.setter
|
830
|
-
def on_thing_create(self, value) -> None:
|
831
|
-
self.__on_thing_create = value
|
832
|
-
|
833
|
-
@property
|
834
|
-
def on_thing_enable(self):
|
835
|
-
return None
|
836
|
-
|
837
|
-
@on_thing_enable.setter
|
838
|
-
def on_thing_enable(self, value) -> None:
|
839
|
-
self.__on_thing_enable = value
|
840
|
-
|
841
|
-
@property
|
842
|
-
def on_thing_disable(self):
|
843
|
-
return None
|
844
|
-
|
845
|
-
@on_thing_disable.setter
|
846
|
-
def on_thing_disable(self, value) -> None:
|
847
|
-
self.__on_thing_disable = value
|
848
|
-
|
849
|
-
@property
|
850
|
-
def on_thing_raw_data_arrived(self):
|
851
|
-
return None
|
852
|
-
|
853
|
-
@on_thing_raw_data_arrived.setter
|
854
|
-
def on_thing_raw_data_arrived(self, value) -> None:
|
855
|
-
self.__on_thing_raw_data_arrived = value
|
856
|
-
|
857
|
-
@property
|
858
|
-
def on_thing_raw_data_post(self):
|
859
|
-
return self.__on_thing_raw_data_post
|
860
|
-
|
861
|
-
@property
|
862
|
-
def on_thing_device_info_update(self):
|
863
|
-
return self.__on_thing_device_info_update
|
864
|
-
|
865
|
-
@on_thing_device_info_update.setter
|
866
|
-
def on_thing_device_info_update(self, value) -> None:
|
867
|
-
self.__on_thing_device_info_update = value
|
868
|
-
|
869
|
-
@property
|
870
|
-
def on_thing_device_info_delete(self):
|
871
|
-
return self.__on_thing_device_info_delete
|
872
|
-
|
873
|
-
@on_thing_device_info_delete.setter
|
874
|
-
def on_thing_device_info_delete(self, value) -> None:
|
875
|
-
self.__on_thing_device_info_delete = value
|
876
|
-
|
877
|
-
@on_thing_raw_data_post.setter
|
878
|
-
def on_thing_raw_data_post(self, value) -> None:
|
879
|
-
self.__on_thing_raw_data_post = value
|
880
|
-
|
881
|
-
@property
|
882
|
-
def on_thing_call_service(self):
|
883
|
-
return None
|
884
|
-
|
885
|
-
@on_thing_call_service.setter
|
886
|
-
def on_thing_call_service(self, value) -> None:
|
887
|
-
self.__on_thing_call_service = value
|
888
|
-
|
889
|
-
@property
|
890
|
-
def on_thing_prop_changed(self):
|
891
|
-
return None
|
892
|
-
|
893
|
-
@on_thing_prop_changed.setter
|
894
|
-
def on_thing_prop_changed(self, value) -> None:
|
895
|
-
self.__on_thing_prop_changed = value
|
896
|
-
|
897
|
-
@property
|
898
|
-
def on_thing_event_post(self):
|
899
|
-
return self.__on_thing_event_post
|
900
|
-
|
901
|
-
@on_thing_event_post.setter
|
902
|
-
def on_thing_event_post(self, value) -> None:
|
903
|
-
self.__on_thing_event_post = value
|
904
|
-
|
905
|
-
@property
|
906
|
-
def on_thing_prop_post(self):
|
907
|
-
return self.__on_thing_prop_post
|
908
|
-
|
909
|
-
@on_thing_prop_post.setter
|
910
|
-
def on_thing_prop_post(self, value) -> None:
|
911
|
-
self.__on_thing_prop_post = value
|
912
|
-
|
913
|
-
@property
|
914
|
-
def on_thing_shadow_get(self):
|
915
|
-
return self.__on_thing_shadow_get
|
916
|
-
|
917
|
-
@on_thing_shadow_get.setter
|
918
|
-
def on_thing_shadow_get(self, value) -> None:
|
919
|
-
self.__on_thing_shadow_get = value
|
920
|
-
|
921
|
-
@property
|
922
|
-
def on_file_upload_begin(self):
|
923
|
-
return self.__on_file_upload_begin
|
924
|
-
|
925
|
-
@on_file_upload_begin.setter
|
926
|
-
def on_file_upload_begin(self, value) -> None:
|
927
|
-
self.__on_file_upload_begin = value
|
928
|
-
|
929
|
-
@property
|
930
|
-
def on_file_upload_end(self):
|
931
|
-
return self.__on_file_upload_end
|
932
|
-
|
933
|
-
@on_file_upload_end.setter
|
934
|
-
def on_file_upload_end(self, value) -> None:
|
935
|
-
self.__on_file_upload_end = value
|
936
|
-
|
937
|
-
@property
|
938
|
-
def on_gateway_add_subdev_topo_reply(self):
|
939
|
-
return None
|
940
|
-
|
941
|
-
@on_gateway_add_subdev_topo_reply.setter
|
942
|
-
def on_gateway_add_subdev_topo_reply(self, value) -> None:
|
943
|
-
self.__on_gateway_add_subdev_topo_reply = value
|
944
|
-
|
945
|
-
@property
|
946
|
-
def on_gateway_delete_subdev_topo_reply(self):
|
947
|
-
return None
|
948
|
-
|
949
|
-
@on_gateway_delete_subdev_topo_reply.setter
|
950
|
-
def on_gateway_delete_subdev_topo_reply(self, value) -> None:
|
951
|
-
self.__on_gateway_delete_subdev_topo_reply = value
|
952
|
-
|
953
|
-
@property
|
954
|
-
def on_gateway_login_subdev_reply(self):
|
955
|
-
return None
|
956
|
-
|
957
|
-
@on_gateway_login_subdev_reply.setter
|
958
|
-
def on_gateway_login_subdev_reply(self, value) -> None:
|
959
|
-
self.__on_gateway_login_subdev_reply = value
|
960
|
-
|
961
|
-
@property
|
962
|
-
def on_gateway_logout_subdev_reply(self):
|
963
|
-
return None
|
964
|
-
|
965
|
-
@on_gateway_logout_subdev_reply.setter
|
966
|
-
def on_gateway_logout_subdev_reply(self, value) -> None:
|
967
|
-
self.__on_gateway_logout_subdev_reply = value
|
968
|
-
|
969
|
-
@property
|
970
|
-
def on_gateway_register_subdev_reply(self):
|
971
|
-
return None
|
972
|
-
|
973
|
-
@on_gateway_register_subdev_reply.setter
|
974
|
-
def on_gateway_register_subdev_reply(self, value) -> None:
|
975
|
-
self.__on_gateway_register_subdev_reply = value
|
976
|
-
|
977
|
-
@property
|
978
|
-
def on_gateway_product_register_subdev_reply(self):
|
979
|
-
return None
|
980
|
-
|
981
|
-
@on_gateway_product_register_subdev_reply.setter
|
982
|
-
def on_gateway_product_register_subdev_reply(self, value) -> None:
|
983
|
-
self.__on_gateway_product_register_subdev_reply = value
|
984
|
-
|
985
|
-
@property
|
986
|
-
def on_device_dynamic_register_nwl_reply(self):
|
987
|
-
return None
|
988
|
-
|
989
|
-
@on_device_dynamic_register_nwl_reply.setter
|
990
|
-
def on_device_dynamic_register_nwl_reply(self, value) -> None:
|
991
|
-
self.__on_device_dynamic_register_nwl_reply = value
|
992
|
-
|
993
|
-
@property
|
994
|
-
def on_ota_message_arrived(self):
|
995
|
-
return None
|
996
|
-
|
997
|
-
@on_ota_message_arrived.setter
|
998
|
-
def on_ota_message_arrived(self, value) -> None:
|
999
|
-
self.__on_ota_message_arrived = value
|
1000
|
-
|
1001
|
-
@property
|
1002
|
-
def on_gateway_topo_change(self):
|
1003
|
-
return None
|
1004
|
-
|
1005
|
-
@on_gateway_topo_change.setter
|
1006
|
-
def on_gateway_topo_change(self, value) -> None:
|
1007
|
-
self.__on_gateway_topo_change = value
|
1008
|
-
|
1009
|
-
def enable_logger(self, level) -> None:
|
1010
|
-
self.__link_log.config_logger(level)
|
1011
|
-
self.__link_log.enable_logger()
|
1012
|
-
if self.__mqtt_client is not None:
|
1013
|
-
self.__mqtt_client.enable_logger(self.__PahoLog)
|
1014
|
-
self.__PahoLog.setLevel(level)
|
1015
|
-
|
1016
|
-
def disable_logger(self) -> None:
|
1017
|
-
self.__link_log.disable_logger()
|
1018
|
-
if self.__mqtt_client is not None:
|
1019
|
-
self.__mqtt_client.disable_logger()
|
1020
|
-
|
1021
|
-
def config_logger(self, level) -> None:
|
1022
|
-
self.__link_log.config_logger(level)
|
1023
|
-
if self.__mqtt_client is not None:
|
1024
|
-
self.__PahoLog.setLevel(level)
|
1025
|
-
|
1026
|
-
def config_http2(self, endpoint=None):
|
1027
|
-
raise LinkKit.StateError("not supported any more")
|
1028
|
-
|
1029
|
-
def config_mqtt(
|
1030
|
-
self,
|
1031
|
-
port=8883,
|
1032
|
-
protocol="MQTTv311",
|
1033
|
-
transport="TCP",
|
1034
|
-
secure="TLS",
|
1035
|
-
keep_alive=60,
|
1036
|
-
clean_session=True,
|
1037
|
-
max_inflight_message=20,
|
1038
|
-
max_queued_message=40,
|
1039
|
-
auto_reconnect_min_sec=1,
|
1040
|
-
auto_reconnect_max_sec=60,
|
1041
|
-
cadata=None,
|
1042
|
-
endpoint=None,
|
1043
|
-
check_hostname=True,
|
1044
|
-
):
|
1045
|
-
if self.__linkkit_state is not LinkKit.LinkKitState.INITIALIZED:
|
1046
|
-
raise LinkKit.StateError("not in INITIALIZED state")
|
1047
|
-
if port < 1 or port > 65535:
|
1048
|
-
raise ValueError("port wrong")
|
1049
|
-
if protocol not in ("MQTTv311", "MQTTv31"):
|
1050
|
-
raise ValueError("protocol wrong")
|
1051
|
-
if transport != "TCP":
|
1052
|
-
raise ValueError("transport wrong")
|
1053
|
-
if secure != "TLS" and secure != "":
|
1054
|
-
raise ValueError("secure wrong")
|
1055
|
-
if keep_alive < 30 or keep_alive > 1200:
|
1056
|
-
raise ValueError("keep_alive range wrong")
|
1057
|
-
if clean_session is not True and clean_session is not False:
|
1058
|
-
raise ValueError("clean session wrong")
|
1059
|
-
if max_queued_message < 0:
|
1060
|
-
raise ValueError("max_queued_message wrong")
|
1061
|
-
if max_inflight_message < 0:
|
1062
|
-
raise ValueError("max_inflight_message wrong")
|
1063
|
-
if auto_reconnect_min_sec < 1 or auto_reconnect_min_sec > 120 * 60:
|
1064
|
-
raise ValueError("auto_reconnect_min_sec wrong")
|
1065
|
-
if auto_reconnect_max_sec < 1 or auto_reconnect_max_sec > 120 * 60:
|
1066
|
-
raise ValueError("auto_reconnect_max_sec wrong")
|
1067
|
-
if auto_reconnect_min_sec > auto_reconnect_max_sec:
|
1068
|
-
raise ValueError("auto_reconnect_max_sec less than auto_reconnect_min_sec")
|
1069
|
-
|
1070
|
-
self.__link_log.info("config_mqtt enter")
|
1071
|
-
if self.__linkkit_state == LinkKit.LinkKitState.INITIALIZED:
|
1072
|
-
if port is not None:
|
1073
|
-
self.__mqtt_port = port
|
1074
|
-
if protocol is not None:
|
1075
|
-
self.__mqtt_protocol = protocol
|
1076
|
-
if transport is not None:
|
1077
|
-
self.__mqtt_transport = transport
|
1078
|
-
if secure is not None:
|
1079
|
-
self.__mqtt_secure = secure
|
1080
|
-
if keep_alive is not None:
|
1081
|
-
self.__mqtt_keep_alive = keep_alive
|
1082
|
-
if clean_session is not None:
|
1083
|
-
self.__mqtt_clean_session = clean_session
|
1084
|
-
if max_inflight_message is not None:
|
1085
|
-
self.__mqtt_max_inflight_message = max_inflight_message
|
1086
|
-
if max_queued_message is not None:
|
1087
|
-
self.__mqtt_max_queued_message = max_queued_message
|
1088
|
-
if auto_reconnect_min_sec is not None:
|
1089
|
-
self.__mqtt_auto_reconnect_min_sec = auto_reconnect_min_sec
|
1090
|
-
if auto_reconnect_max_sec is not None:
|
1091
|
-
self.__mqtt_auto_reconnect_max_sec = auto_reconnect_max_sec
|
1092
|
-
if cadata is not None:
|
1093
|
-
self.__aliyun_broker_ca_data = cadata
|
1094
|
-
if endpoint is not None:
|
1095
|
-
self.__endpoint = endpoint
|
1096
|
-
if check_hostname is not None:
|
1097
|
-
self.__check_hostname = check_hostname
|
1098
|
-
if check_hostname == False:
|
1099
|
-
self.__link_log.info("skip hostname check")
|
1100
|
-
|
1101
|
-
def config_device_info(self, interface_info) -> int:
|
1102
|
-
if self.__linkkit_state is not LinkKit.LinkKitState.INITIALIZED:
|
1103
|
-
raise LinkKit.StateError("LinkKit object not in INITIALIZED")
|
1104
|
-
if not isinstance(interface_info, str):
|
1105
|
-
raise ValueError("interface info must be string")
|
1106
|
-
if len(interface_info) > 160:
|
1107
|
-
return 1
|
1108
|
-
self.__device_interface_info = interface_info
|
1109
|
-
return 0
|
1110
|
-
|
1111
|
-
def get_product(self):
|
1112
|
-
return self.__product_key
|
1113
|
-
|
1114
|
-
def get_device_name(self):
|
1115
|
-
return self.__device_name
|
1116
|
-
|
1117
|
-
def get_endpoint(self):
|
1118
|
-
return self.__endpoint
|
1119
|
-
|
1120
|
-
def get_h2_endpoint(self):
|
1121
|
-
raise LinkKit.StateError("not supported any more")
|
1122
|
-
|
1123
|
-
def get_actual_endpoint(self):
|
1124
|
-
return self.__generate_endpoint()
|
1125
|
-
|
1126
|
-
def get_actual_h2_endpoint(self):
|
1127
|
-
raise LinkKit.StateError("not supported any more")
|
1128
|
-
|
1129
|
-
def __load_json(self, payload):
|
1130
|
-
return json.loads(self.__to_str(payload))
|
1131
|
-
|
1132
|
-
def __to_str(self, payload):
|
1133
|
-
if type(payload) is bytes:
|
1134
|
-
return str(payload, "utf-8")
|
1135
|
-
else:
|
1136
|
-
return payload
|
1137
|
-
|
1138
|
-
def upload_file_sync(self, local_filename, remote_filename=None, over_write=True, timeout=None):
|
1139
|
-
raise LinkKit.StateError("not supported any more")
|
1140
|
-
|
1141
|
-
def upload_file_async(self, local_filename, remote_filename=None, over_write=True):
|
1142
|
-
raise LinkKit.StateError("not supported any more")
|
1143
|
-
|
1144
|
-
def __upload_device_interface_info(self) -> int:
|
1145
|
-
request_id = self.__get_thing_request_id()
|
1146
|
-
payload = {
|
1147
|
-
"id": request_id,
|
1148
|
-
"version": "1.0",
|
1149
|
-
"params": [
|
1150
|
-
{"domain": "SYSTEM", "attrKey": "SYS_SDK_LANGUAGE", "attrValue": self.__sdk_program_language},
|
1151
|
-
{"domain": "SYSTEM", "attrKey": "SYS_LP_SDK_VERSION", "attrValue": self.__sdk_version},
|
1152
|
-
{"domain": "SYSTEM", "attrKey": "SYS_SDK_IF_INFO", "attrValue": self.__device_interface_info},
|
1153
|
-
],
|
1154
|
-
"method": "thing.deviceinfo.update",
|
1155
|
-
}
|
1156
|
-
with self.__device_info_mid_lock:
|
1157
|
-
rc, mid = self.__mqtt_client.publish(self.__device_info_topic, json.dumps(payload), 0)
|
1158
|
-
if rc == mqtt.MQTT_ERR_SUCCESS:
|
1159
|
-
self.__device_info_mid[mid] = self.__timestamp()
|
1160
|
-
return 0
|
1161
|
-
else:
|
1162
|
-
return 1
|
1163
|
-
|
1164
|
-
def destruct(self) -> None:
|
1165
|
-
if self.__linkkit_state is LinkKit.LinkKitState.DESTRUCTED:
|
1166
|
-
self.__link_log.info("LinkKit object has already destructed")
|
1167
|
-
return
|
1168
|
-
self.__link_log.debug("destruct enter")
|
1169
|
-
if (
|
1170
|
-
self.__linkkit_state == LinkKit.LinkKitState.CONNECTED
|
1171
|
-
or self.__linkkit_state == LinkKit.LinkKitState.CONNECTING
|
1172
|
-
):
|
1173
|
-
self.__linkkit_state = LinkKit.LinkKitState.DESTRUCTING
|
1174
|
-
if self.__connect_async_req:
|
1175
|
-
with self.__worker_loop_exit_req_lock:
|
1176
|
-
self.__worker_loop_exit_req = True
|
1177
|
-
if self.__mqtt_client is not None:
|
1178
|
-
self.__mqtt_client.disconnect()
|
1179
|
-
self.__handler_task.wait_stop()
|
1180
|
-
else:
|
1181
|
-
self.__linkkit_state = LinkKit.LinkKitState.DESTRUCTING
|
1182
|
-
if self.__connect_async_req:
|
1183
|
-
with self.__worker_loop_exit_req_lock:
|
1184
|
-
self.__worker_loop_exit_req = True
|
1185
|
-
self.__handler_task.stop()
|
1186
|
-
self.__handler_task.wait_stop()
|
1187
|
-
self.__linkkit_state = LinkKit.LinkKitState.DESTRUCTED
|
1188
|
-
|
1189
|
-
def destroy(self) -> None:
|
1190
|
-
self.destruct()
|
1191
|
-
|
1192
|
-
def check_state(self):
|
1193
|
-
return self.__linkkit_state
|
1194
|
-
|
1195
|
-
@staticmethod
|
1196
|
-
def __generate_random_str(randomlength=16):
|
1197
|
-
"""Generate radom string"""
|
1198
|
-
random_str = ""
|
1199
|
-
for i in range(randomlength):
|
1200
|
-
random_str += random.choice(string.digits + string.ascii_letters)
|
1201
|
-
return random_str
|
1202
|
-
|
1203
|
-
# 基于HTTPS的一型一密预注册
|
1204
|
-
def __dynamic_register_device(self):
|
1205
|
-
pk = self.__product_key
|
1206
|
-
ps = self.__product_secret
|
1207
|
-
dn = self.__device_name
|
1208
|
-
random_str = self.__generate_random_str(15)
|
1209
|
-
context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cadata=self.__aliyun_broker_ca_data)
|
1210
|
-
sign_content = "deviceName%sproductKey%srandom%s" % (dn, pk, random_str)
|
1211
|
-
sign = hmac.new(ps.encode("utf-8"), sign_content.encode("utf-8"), hashlib.sha256).hexdigest()
|
1212
|
-
post_data = {"productKey": pk, "deviceName": dn, "random": random_str, "sign": sign, "signMethod": "hmacsha256"}
|
1213
|
-
data = urllib.parse.urlencode(post_data)
|
1214
|
-
data = data.encode("ascii")
|
1215
|
-
request_url = "https://iot-auth.%s.aliyuncs.com/auth/register/device" % self.__host_name
|
1216
|
-
with urllib.request.urlopen(request_url, data, context=context) as f:
|
1217
|
-
reply_data = f.read().decode("utf-8")
|
1218
|
-
reply_obj = self.__load_json(reply_data)
|
1219
|
-
if reply_obj["code"] == 200:
|
1220
|
-
reply_obj_data = reply_obj["data"]
|
1221
|
-
if reply_obj_data is not None:
|
1222
|
-
return 0, reply_obj_data["deviceSecret"]
|
1223
|
-
else:
|
1224
|
-
return 1, reply_obj["message"]
|
1225
|
-
|
1226
|
-
def __config_mqtt_client_internal(self):
|
1227
|
-
self.__link_log.info("start connect")
|
1228
|
-
|
1229
|
-
timestamp = str(int(time.time()))
|
1230
|
-
if self.__mqtt_secure == "TLS":
|
1231
|
-
securemode = 2
|
1232
|
-
else:
|
1233
|
-
securemode = 3
|
1234
|
-
if self.__device_interface_info:
|
1235
|
-
sii_option = "sii=%s," % (self.__device_interface_info)
|
1236
|
-
else:
|
1237
|
-
sii_option = ""
|
1238
|
-
|
1239
|
-
# 普通的一机一密认证方式
|
1240
|
-
if self.__is_valid_str(self.__device_secret):
|
1241
|
-
client_id = "%s&%s|securemode=%d,signmethod=hmacsha1,ext=1,_ss=1,lan=%s,_v=%s,%stimestamp=%s|" % (
|
1242
|
-
self.__product_key,
|
1243
|
-
self.__device_name,
|
1244
|
-
securemode,
|
1245
|
-
self.__sdk_program_language,
|
1246
|
-
self.__sdk_version,
|
1247
|
-
sii_option,
|
1248
|
-
timestamp,
|
1249
|
-
)
|
1250
|
-
username = self.__device_name + "&" + self.__product_key
|
1251
|
-
# calc sign
|
1252
|
-
sign_content = "clientId%sdeviceName%sproductKey%stimestamp%s" % (
|
1253
|
-
self.__product_key + "&" + self.__device_name,
|
1254
|
-
self.__device_name,
|
1255
|
-
self.__product_key,
|
1256
|
-
timestamp,
|
1257
|
-
)
|
1258
|
-
password = hmac.new(
|
1259
|
-
self.__device_secret.encode("utf-8"), sign_content.encode("utf-8"), hashlib.sha1
|
1260
|
-
).hexdigest()
|
1261
|
-
# 通过username, passwd, cilentid直连接入的方式
|
1262
|
-
elif (
|
1263
|
-
self.__is_valid_str(self.__client_id)
|
1264
|
-
and self.__is_valid_str(self.__username)
|
1265
|
-
and self.__is_valid_str(self.__password)
|
1266
|
-
):
|
1267
|
-
# 如果已经通过基于mqtt的免预注册一型一密协议获取到了client_id, user_name, password
|
1268
|
-
client_id = self.__client_id
|
1269
|
-
username = self.__username
|
1270
|
-
password = self.__password
|
1271
|
-
# 基于mqtt协议的一型一密,包括预注册和非预注册两种, 尝试去获取username, clientid和password
|
1272
|
-
elif self.__is_valid_str(self.__product_secret):
|
1273
|
-
if self.__auth_type == "regnwl":
|
1274
|
-
# 通过一型一密免预注册协议发起认证
|
1275
|
-
self.__dynamic_register_nwl_flag = 1
|
1276
|
-
elif self.__auth_type == "register":
|
1277
|
-
# 通过一型一密预注册协议发起认证
|
1278
|
-
self.__dynamic_register_flag = 1
|
1279
|
-
else:
|
1280
|
-
raise LinkKit.StateError("unknow dynreg param error")
|
1281
|
-
|
1282
|
-
auth_type_str = self.__auth_type
|
1283
|
-
random_str = self.__generate_random_str(15)
|
1284
|
-
if self.__is_valid_str(self.__instance_id):
|
1285
|
-
client_id = "%s.%s|random=%s,authType=%s,securemode=2,signmethod=hmacsha256,instanceId=%s|" % (
|
1286
|
-
self.__device_name,
|
1287
|
-
self.__product_key,
|
1288
|
-
random_str,
|
1289
|
-
auth_type_str,
|
1290
|
-
self.__instance_id,
|
1291
|
-
)
|
1292
|
-
else:
|
1293
|
-
client_id = "%s.%s|random=%s,authType=%s,securemode=2,signmethod=hmacsha256|" % (
|
1294
|
-
self.__device_name,
|
1295
|
-
self.__product_key,
|
1296
|
-
random_str,
|
1297
|
-
auth_type_str,
|
1298
|
-
)
|
1299
|
-
username = "%s&%s" % (self.__device_name, self.__product_key)
|
1300
|
-
password_src = "deviceName%sproductKey%srandom%s" % (self.__device_name, self.__product_key, random_str)
|
1301
|
-
password = hmac.new(
|
1302
|
-
self.__product_secret.encode("utf-8"), password_src.encode("utf-8"), hashlib.sha256
|
1303
|
-
).hexdigest()
|
1304
|
-
else:
|
1305
|
-
raise LinkKit.StateError("unknow auth error")
|
1306
|
-
|
1307
|
-
# mqtt client start initialize
|
1308
|
-
mqtt_protocol_version = mqtt.MQTTv311
|
1309
|
-
if self.__mqtt_protocol == "MQTTv311":
|
1310
|
-
mqtt_protocol_version = mqtt.MQTTv311
|
1311
|
-
elif self.__mqtt_protocol == "MQTTv31":
|
1312
|
-
mqtt_protocol_version = mqtt.MQTTv31
|
1313
|
-
self.__mqtt_client = mqtt.Client(
|
1314
|
-
client_id=client_id, clean_session=self.__mqtt_clean_session, protocol=mqtt_protocol_version
|
1315
|
-
)
|
1316
|
-
|
1317
|
-
if self.__link_log.is_enabled():
|
1318
|
-
self.__mqtt_client.enable_logger(self.__PahoLog)
|
1319
|
-
self.__mqtt_client.username_pw_set(username, password)
|
1320
|
-
self.__mqtt_client.on_connect = self.__on_internal_connect
|
1321
|
-
self.__mqtt_client.on_disconnect = self.__on_internal_disconnect
|
1322
|
-
self.__mqtt_client.on_message = self.__on_internal_message
|
1323
|
-
self.__mqtt_client.on_publish = self.__on_internal_publish
|
1324
|
-
self.__mqtt_client.on_subscribe = self.__on_internal_subscribe
|
1325
|
-
self.__mqtt_client.on_unsubscribe = self.__on_internal_unsubscribe
|
1326
|
-
|
1327
|
-
self.__mqtt_client.reconnect_delay_set(self.__mqtt_auto_reconnect_min_sec, self.__mqtt_auto_reconnect_max_sec)
|
1328
|
-
self.__mqtt_client.max_queued_messages_set(self.__mqtt_max_queued_message)
|
1329
|
-
self.__mqtt_client.max_inflight_messages_set(self.__mqtt_max_inflight_message)
|
1330
|
-
|
1331
|
-
# mqtt set tls
|
1332
|
-
self.__link_log.debug("current working directory:" + os.getcwd())
|
1333
|
-
if self.__mqtt_secure == "TLS":
|
1334
|
-
context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cadata=self.__aliyun_broker_ca_data)
|
1335
|
-
context.check_hostname = self.__check_hostname
|
1336
|
-
self.__mqtt_client.tls_set_context(context)
|
1337
|
-
# mqtt client start connect
|
1338
|
-
self.__host_name_internal = self.__generate_endpoint()
|
1339
|
-
|
1340
|
-
def __generate_endpoint(self):
|
1341
|
-
if self.__endpoint:
|
1342
|
-
return self.__endpoint
|
1343
|
-
elif self.__host_name == "127.0.0.1" or self.__host_name == "localhost":
|
1344
|
-
return self.__host_name
|
1345
|
-
elif self.__is_valid_str(self.__instance_id):
|
1346
|
-
return self.__instance_id + ".mqtt.iothub.aliyuncs.com"
|
1347
|
-
else:
|
1348
|
-
return "%s.iot-as-mqtt.%s.aliyuncs.com" % (self.__product_key, self.__host_name)
|
1349
|
-
|
1350
|
-
def connect(self):
|
1351
|
-
raise LinkKit.StateError("not supported")
|
1352
|
-
|
1353
|
-
def connect_async(self):
|
1354
|
-
self.__link_log.debug("connect_async")
|
1355
|
-
if self.__linkkit_state not in (LinkKit.LinkKitState.INITIALIZED, LinkKit.LinkKitState.DISCONNECTED):
|
1356
|
-
raise LinkKit.StateError("not in INITIALIZED or DISCONNECTED state")
|
1357
|
-
self.__connect_async_req = True
|
1358
|
-
with self.__worker_loop_exit_req_lock:
|
1359
|
-
self.__worker_loop_exit_req = False
|
1360
|
-
return self.__loop_thread.start(self.__loop_forever_internal)
|
1361
|
-
|
1362
|
-
def disconnect(self) -> None:
|
1363
|
-
self.__link_log.debug("disconnect")
|
1364
|
-
if self.__linkkit_state is not LinkKit.LinkKitState.CONNECTED:
|
1365
|
-
self.__link_log.info("already disconnected, return")
|
1366
|
-
return
|
1367
|
-
self.__linkkit_state = LinkKit.LinkKitState.DISCONNECTING
|
1368
|
-
if self.__connect_async_req:
|
1369
|
-
with self.__worker_loop_exit_req_lock:
|
1370
|
-
self.__worker_loop_exit_req = True
|
1371
|
-
self.__mqtt_client.disconnect()
|
1372
|
-
self.__loop_thread.stop()
|
1373
|
-
|
1374
|
-
@staticmethod
|
1375
|
-
def __check_topic_string(topic):
|
1376
|
-
if len(topic) > 128 or len(topic) == 0:
|
1377
|
-
raise ValueError("topic string length too long,need decrease %d bytes" % (128 - len(topic)))
|
1378
|
-
|
1379
|
-
def publish_topic(self, topic, payload=None, qos=1):
|
1380
|
-
if self.__linkkit_state is not LinkKit.LinkKitState.CONNECTED:
|
1381
|
-
self.__link_log.error("disconnected, pub fail")
|
1382
|
-
return LinkKit.ErrorCode.NETWORK_DISCONNECTED.value, None
|
1383
|
-
if topic is None or len(topic) == 0:
|
1384
|
-
return LinkKit.ErrorCode.INVALID_TOPIC.value, None
|
1385
|
-
if qos != 0 and qos != 1:
|
1386
|
-
return LinkKit.ErrorCode.INVALID_QOS.value, None
|
1387
|
-
self.__check_topic_string(topic)
|
1388
|
-
rc, mid = self.__mqtt_client.publish(topic, payload, qos)
|
1389
|
-
if rc == 0:
|
1390
|
-
return LinkKit.ErrorCode.SUCCESS.value, mid
|
1391
|
-
else:
|
1392
|
-
return LinkKit.ErrorCode.PAHO_MQTT_ERROR.value, None
|
1393
|
-
|
1394
|
-
def subscribe_topic(self, topic, qos=1):
|
1395
|
-
if self.__linkkit_state is not LinkKit.LinkKitState.CONNECTED:
|
1396
|
-
self.__link_log.error("disconnected, sub fail")
|
1397
|
-
return LinkKit.ErrorCode.NETWORK_DISCONNECTED.value, None
|
1398
|
-
if isinstance(topic, tuple):
|
1399
|
-
topic, qos = topic
|
1400
|
-
|
1401
|
-
if isinstance(topic, str):
|
1402
|
-
if qos < 0 or qos > 1:
|
1403
|
-
return LinkKit.ErrorCode.INVALID_QOS.value, None
|
1404
|
-
if topic is None or len(topic) == 0:
|
1405
|
-
return LinkKit.ErrorCode.INVALID_TOPIC.value, None
|
1406
|
-
self.__check_topic_string(topic)
|
1407
|
-
if topic not in self.__user_topics:
|
1408
|
-
self.__user_topics_request_lock.acquire()
|
1409
|
-
ret = self.__mqtt_client.subscribe(topic, qos)
|
1410
|
-
rc, mid = ret
|
1411
|
-
if rc == mqtt.MQTT_ERR_SUCCESS:
|
1412
|
-
self.__user_topics_subscribe_request[mid] = [(topic, qos)]
|
1413
|
-
self.__user_topics_request_lock.release()
|
1414
|
-
if rc == mqtt.MQTT_ERR_SUCCESS:
|
1415
|
-
return 0, mid
|
1416
|
-
if rc == mqtt.MQTT_ERR_NO_CONN:
|
1417
|
-
return 2, None
|
1418
|
-
return 3, None
|
1419
|
-
else:
|
1420
|
-
return 1, None
|
1421
|
-
elif isinstance(topic, list):
|
1422
|
-
topic_qos_list = []
|
1423
|
-
user_topic_dict = {}
|
1424
|
-
for t, q in topic:
|
1425
|
-
if q < 0 or q > 1:
|
1426
|
-
return LinkKit.ErrorCode.INVALID_QOS.value, None
|
1427
|
-
if t is None or len(t) == 0 or not isinstance(t, str):
|
1428
|
-
return LinkKit.ErrorCode.INVALID_TOPIC.value, None
|
1429
|
-
self.__check_topic_string(t)
|
1430
|
-
user_topic_dict[t] = q
|
1431
|
-
topic_qos_list.append((t, q))
|
1432
|
-
self.__user_topics_request_lock.acquire()
|
1433
|
-
ret = self.__mqtt_client.subscribe(topic_qos_list)
|
1434
|
-
rc, mid = ret
|
1435
|
-
if rc == mqtt.MQTT_ERR_SUCCESS:
|
1436
|
-
self.__user_topics_subscribe_request[mid] = topic_qos_list
|
1437
|
-
self.__link_log.debug("__user_topics_subscribe_request add mid:%d" % mid)
|
1438
|
-
self.__user_topics_request_lock.release()
|
1439
|
-
return rc, mid
|
1440
|
-
else:
|
1441
|
-
self.__link_log.error("Parameter type wrong")
|
1442
|
-
return LinkKit.ErrorCode.INVALID_TOPIC.value, None
|
1443
|
-
|
1444
|
-
def unsubscribe_topic(self, topic):
|
1445
|
-
if self.__linkkit_state is not LinkKit.LinkKitState.CONNECTED:
|
1446
|
-
self.__link_log.error("disconnected, unsub fail")
|
1447
|
-
return LinkKit.ErrorCode.NETWORK_DISCONNECTED.value, None
|
1448
|
-
unsubscribe_topics = []
|
1449
|
-
if topic is None or topic == "":
|
1450
|
-
return LinkKit.ErrorCode.INVALID_TOPIC.value, None
|
1451
|
-
if isinstance(topic, str):
|
1452
|
-
self.__check_topic_string(topic)
|
1453
|
-
if topic not in self.__user_topics:
|
1454
|
-
return 1, None
|
1455
|
-
unsubscribe_topics.append(topic)
|
1456
|
-
elif isinstance(topic, list):
|
1457
|
-
for one_topic in topic:
|
1458
|
-
self.__check_topic_string(one_topic)
|
1459
|
-
if one_topic in self.__user_topics:
|
1460
|
-
unsubscribe_topics.append(one_topic)
|
1461
|
-
else:
|
1462
|
-
pass
|
1463
|
-
with self.__user_topics_unsubscribe_request_lock:
|
1464
|
-
if len(unsubscribe_topics) == 0:
|
1465
|
-
return 2, None
|
1466
|
-
ret = self.__mqtt_client.unsubscribe(unsubscribe_topics)
|
1467
|
-
rc, mid = ret
|
1468
|
-
if rc == mqtt.MQTT_ERR_SUCCESS:
|
1469
|
-
self.__user_topics_unsubscribe_request[mid] = unsubscribe_topics
|
1470
|
-
return ret
|
1471
|
-
else:
|
1472
|
-
return 1, None
|
1473
|
-
|
1474
|
-
def __make_rrpc_topic(self, topic) -> str:
|
1475
|
-
return "/ext/rrpc/+%s" % (topic)
|
1476
|
-
|
1477
|
-
def subscribe_rrpc_topic(self, topic):
|
1478
|
-
if self.__linkkit_state is not LinkKit.LinkKitState.CONNECTED:
|
1479
|
-
self.__link_log.error("disconnected, sub rrpc fail")
|
1480
|
-
return LinkKit.ErrorCode.NETWORK_DISCONNECTED.value, None
|
1481
|
-
qos = 0
|
1482
|
-
if isinstance(topic, str):
|
1483
|
-
if topic is None or len(topic) == 0:
|
1484
|
-
return LinkKit.ErrorCode.INVALID_TOPIC.value, None
|
1485
|
-
self.__check_topic_string(topic)
|
1486
|
-
topic = self.__tidy_topic(topic)
|
1487
|
-
rrpc_topic = self.__make_rrpc_topic(topic)
|
1488
|
-
with self.__user_rrpc_topics_lock:
|
1489
|
-
not_exist = topic not in self.__user_rrpc_topics.keys()
|
1490
|
-
if not_exist:
|
1491
|
-
with self.__user_rrpc_topics_lock:
|
1492
|
-
self.__user_rrpc_topics[topic] = qos
|
1493
|
-
with self.__user_rrpc_topics_subscribe_request_lock:
|
1494
|
-
ret = self.__mqtt_client.subscribe(rrpc_topic, qos)
|
1495
|
-
rc, mid = ret
|
1496
|
-
if rc == mqtt.MQTT_ERR_SUCCESS:
|
1497
|
-
self.__user_rrpc_topics_subscribe_request[mid] = [(rrpc_topic, qos)]
|
1498
|
-
if rc == mqtt.MQTT_ERR_SUCCESS:
|
1499
|
-
return 0, mid
|
1500
|
-
if rc == mqtt.MQTT_ERR_NO_CONN:
|
1501
|
-
return 2, None
|
1502
|
-
return 3, None
|
1503
|
-
else:
|
1504
|
-
return 1, None
|
1505
|
-
elif isinstance(topic, list):
|
1506
|
-
topic_qos_list = []
|
1507
|
-
for t in topic:
|
1508
|
-
if t is None or len(t) == 0 or not isinstance(t, str):
|
1509
|
-
return LinkKit.ErrorCode.INVALID_TOPIC.value, None
|
1510
|
-
self.__check_topic_string(t)
|
1511
|
-
t = self.__tidy_topic(t)
|
1512
|
-
rrpc_t = self.__make_rrpc_topic(t)
|
1513
|
-
with self.__user_rrpc_topics_lock:
|
1514
|
-
self.__user_rrpc_topics[t] = qos
|
1515
|
-
topic_qos_list.append((rrpc_t, qos))
|
1516
|
-
with self.__user_rrpc_topics_subscribe_request_lock:
|
1517
|
-
ret = self.__mqtt_client.subscribe(topic_qos_list)
|
1518
|
-
rc, mid = ret
|
1519
|
-
if rc == mqtt.MQTT_ERR_SUCCESS:
|
1520
|
-
self.__user_rrpc_topics_subscribe_request[mid] = topic_qos_list
|
1521
|
-
self.__link_log.debug("__user_rrpc_topics_subscribe_request add mid:%d" % mid)
|
1522
|
-
return rc, mid
|
1523
|
-
else:
|
1524
|
-
self.__link_log.debug("Parameter type wrong")
|
1525
|
-
return LinkKit.ErrorCode.INVALID_TOPIC.value, None
|
1526
|
-
|
1527
|
-
def unsubscribe_rrpc_topic(self, topic):
|
1528
|
-
if self.__linkkit_state is not LinkKit.LinkKitState.CONNECTED:
|
1529
|
-
self.__link_log.error("disconnected, unsub rrpc fail")
|
1530
|
-
return LinkKit.ErrorCode.NETWORK_DISCONNECTED.value, None
|
1531
|
-
unsubscribe_topics = []
|
1532
|
-
if topic is None or topic == "":
|
1533
|
-
return LinkKit.ErrorCode.INVALID_TOPIC.value, None
|
1534
|
-
if isinstance(topic, str):
|
1535
|
-
self.__check_topic_string(topic)
|
1536
|
-
topic = self.__tidy_topic(topic)
|
1537
|
-
with self.__user_rrpc_topics_lock:
|
1538
|
-
if topic not in self.__user_rrpc_topics:
|
1539
|
-
return 1, None
|
1540
|
-
rrpc_topic = self.__make_rrpc_topic(topic)
|
1541
|
-
unsubscribe_topics.append(rrpc_topic)
|
1542
|
-
with self.__user_rrpc_topics_lock:
|
1543
|
-
del self.__user_rrpc_topics[topic]
|
1544
|
-
|
1545
|
-
elif isinstance(topic, list):
|
1546
|
-
for one_topic in topic:
|
1547
|
-
self.__check_topic_string(one_topic)
|
1548
|
-
one_topic = self.__tidy_topic(one_topic)
|
1549
|
-
with self.__user_rrpc_topics_lock:
|
1550
|
-
if one_topic in self.__user_rrpc_topics:
|
1551
|
-
rrpc_topic = self.__make_rrpc_topic(one_topic)
|
1552
|
-
unsubscribe_topics.append(rrpc_topic)
|
1553
|
-
del self.__user_rrpc_topics[one_topic]
|
1554
|
-
else:
|
1555
|
-
pass
|
1556
|
-
with self.__user_rrpc_topics_unsubscribe_request_lock:
|
1557
|
-
if len(unsubscribe_topics) == 0:
|
1558
|
-
return 2, None
|
1559
|
-
ret = self.__mqtt_client.unsubscribe(unsubscribe_topics)
|
1560
|
-
rc, mid = ret
|
1561
|
-
if rc == mqtt.MQTT_ERR_SUCCESS:
|
1562
|
-
self.__user_rrpc_topics_unsubscribe_request[mid] = unsubscribe_topics
|
1563
|
-
return ret
|
1564
|
-
else:
|
1565
|
-
return 1, None
|
1566
|
-
|
1567
|
-
def __on_internal_connect_safe(self, client, user_data, session_flag, rc) -> None:
|
1568
|
-
if rc == 0:
|
1569
|
-
self.__reset_reconnect_wait()
|
1570
|
-
self.__force_reconnect = False
|
1571
|
-
session_flag_internal = {"session present": session_flag}
|
1572
|
-
self.__handler_task.post_message(
|
1573
|
-
self.__handler_task_cmd_on_connect, (client, user_data, session_flag_internal, rc)
|
1574
|
-
)
|
1575
|
-
|
1576
|
-
def __loop_forever_internal(self):
|
1577
|
-
self.__link_log.debug("enter")
|
1578
|
-
self.__linkkit_state = LinkKit.LinkKitState.CONNECTING
|
1579
|
-
|
1580
|
-
# 为了保持存量设备兼容,保留了基于https的需要预注册的一型一密的预注册
|
1581
|
-
if not self.__is_valid_str(self.__device_secret) and self.__is_valid_str(self.__product_secret):
|
1582
|
-
lack_other_auth_info = (
|
1583
|
-
not self.__is_valid_str(self.__username)
|
1584
|
-
or not self.__is_valid_str(self.__client_id)
|
1585
|
-
or not self.__is_valid_str(self.__password)
|
1586
|
-
)
|
1587
|
-
if not self.__is_valid_str(self.__auth_type) and lack_other_auth_info:
|
1588
|
-
rc, value = self.__dynamic_register_device()
|
1589
|
-
try:
|
1590
|
-
self.__on_device_dynamic_register(rc, value, self.__user_data)
|
1591
|
-
if rc == 0:
|
1592
|
-
self.__device_secret = value
|
1593
|
-
else:
|
1594
|
-
self.__link_log.error("dynamic register device fail:" + value)
|
1595
|
-
self.__linkkit_state = LinkKit.LinkKitState.INITIALIZED
|
1596
|
-
return 1
|
1597
|
-
except Exception as e:
|
1598
|
-
self.__link_log.error(e)
|
1599
|
-
self.__linkkit_state = LinkKit.LinkKitState.INITIALIZED
|
1600
|
-
return 2
|
1601
|
-
try:
|
1602
|
-
self.__config_mqtt_client_internal()
|
1603
|
-
except ssl.SSLError as e:
|
1604
|
-
self.__link_log.error("config mqtt raise exception:" + str(e))
|
1605
|
-
self.__linkkit_state = LinkKit.LinkKitState.INITIALIZED
|
1606
|
-
self.__on_internal_connect_safe(None, None, 0, 6)
|
1607
|
-
return
|
1608
|
-
|
1609
|
-
try:
|
1610
|
-
self.__mqtt_client.connect_async(
|
1611
|
-
host=self.__host_name_internal, port=self.__mqtt_port, keepalive=self.__mqtt_keep_alive
|
1612
|
-
)
|
1613
|
-
except Exception as e:
|
1614
|
-
self.__link_log.error("__loop_forever_internal connect raise exception:" + str(e))
|
1615
|
-
self.__linkkit_state = LinkKit.LinkKitState.INITIALIZED
|
1616
|
-
self.__on_internal_connect_safe(None, None, 0, 7)
|
1617
|
-
return
|
1618
|
-
while True:
|
1619
|
-
if self.__worker_loop_exit_req:
|
1620
|
-
if self.__linkkit_state == LinkKit.LinkKitState.DESTRUCTING:
|
1621
|
-
self.__handler_task.stop()
|
1622
|
-
self.__linkkit_state = LinkKit.LinkKitState.DESTRUCTED
|
1623
|
-
break
|
1624
|
-
try:
|
1625
|
-
self.__linkkit_state = LinkKit.LinkKitState.CONNECTING
|
1626
|
-
self.__mqtt_client.reconnect()
|
1627
|
-
except OSError as e:
|
1628
|
-
self.__link_log.error(e)
|
1629
|
-
# if isinstance(e, socket.timeout):
|
1630
|
-
# self.__link_log.error("connect timeout")
|
1631
|
-
# self.__on_internal_connect_safe(None, None, 0, 8)
|
1632
|
-
# self.__reconnect_wait()
|
1633
|
-
# continue
|
1634
|
-
# if isinstance(e, ssl.SSLError):
|
1635
|
-
# self.__on_internal_connect_safe(None, None, 0, 6)
|
1636
|
-
# return
|
1637
|
-
if self.__linkkit_state == LinkKit.LinkKitState.CONNECTING:
|
1638
|
-
self.__linkkit_state = LinkKit.LinkKitState.DISCONNECTED
|
1639
|
-
self.__on_internal_connect_safe(None, None, 0, 9)
|
1640
|
-
if self.__linkkit_state == LinkKit.LinkKitState.DESTRUCTING:
|
1641
|
-
self.__handler_task.stop()
|
1642
|
-
self.__linkkit_state = LinkKit.LinkKitState.DESTRUCTED
|
1643
|
-
break
|
1644
|
-
self.__reconnect_wait()
|
1645
|
-
continue
|
1646
|
-
# 1. ca wrong 2.socket create timeout 3.connect timeout, call on_connect error
|
1647
|
-
# connect success
|
1648
|
-
rc = mqtt.MQTT_ERR_SUCCESS
|
1649
|
-
while rc == mqtt.MQTT_ERR_SUCCESS:
|
1650
|
-
try:
|
1651
|
-
rc = self.__mqtt_client.loop(self.__mqtt_request_timeout)
|
1652
|
-
except Exception as e:
|
1653
|
-
self.__link_log.info("loop error:" + str(e))
|
1654
|
-
self.__clean_timeout_message()
|
1655
|
-
self.__clean_thing_timeout_request_id()
|
1656
|
-
if self.__force_reconnect is True:
|
1657
|
-
self.__force_reconnect = False
|
1658
|
-
break
|
1659
|
-
|
1660
|
-
if self.__linkkit_state == LinkKit.LinkKitState.CONNECTED:
|
1661
|
-
self.__on_internal_disconnect(None, None, 1)
|
1662
|
-
self.__link_log.info("loop return:%r" % rc)
|
1663
|
-
|
1664
|
-
if self.__worker_loop_exit_req:
|
1665
|
-
if self.__linkkit_state == LinkKit.LinkKitState.DESTRUCTING:
|
1666
|
-
self.__handler_task.stop()
|
1667
|
-
self.__linkkit_state = LinkKit.LinkKitState.DESTRUCTED
|
1668
|
-
break
|
1669
|
-
self.__reconnect_wait()
|
1670
|
-
# 在mqtt + 一型一密免预注册的情况下,由于三元组不对,导致无法与服务器建连,因此需要退出,否则会一直重试
|
1671
|
-
if self.__dynamic_register_nwl_flag == 1:
|
1672
|
-
if self.__on_device_dynamic_register_nwl_reply is not None:
|
1673
|
-
self.__on_device_dynamic_register_nwl_reply(
|
1674
|
-
LinkKit.ErrorCode.DYNREG_AUTH_NWL_FAILED.value, None, None, None
|
1675
|
-
)
|
1676
|
-
self.__linkkit_state = LinkKit.LinkKitState.DISCONNECTED
|
1677
|
-
self.__dynamic_register_nwl_flag = 0
|
1678
|
-
break
|
1679
|
-
# 在mqtt + 一型一密预注册的情况下,由于三元组不对,导致无法与服务器建连,因此需要退出,否则会一直重试
|
1680
|
-
if self.__dynamic_register_flag == 1:
|
1681
|
-
if self.__on_device_dynamic_register is not None:
|
1682
|
-
self.__on_device_dynamic_register(LinkKit.ErrorCode.DYNREG_AUTH_FAILED.value, None, None)
|
1683
|
-
self.__linkkit_state = LinkKit.LinkKitState.DISCONNECTED
|
1684
|
-
self.__dynamic_register_flag = 0
|
1685
|
-
break
|
1686
|
-
|
1687
|
-
def __clean_timeout_message(self) -> None:
|
1688
|
-
# self.__link_log.debug("__clean_timeout_message enter")
|
1689
|
-
expire_timestamp = self.__timestamp() - self.__mqtt_request_timeout * 1000
|
1690
|
-
with self.__thing_prop_post_mid_lock:
|
1691
|
-
self.__clean_timeout_message_item(self.__thing_prop_post_mid, expire_timestamp)
|
1692
|
-
with self.__thing_event_post_mid_lock:
|
1693
|
-
self.__clean_timeout_message_item(self.__thing_event_post_mid, expire_timestamp)
|
1694
|
-
with self.__thing_answer_service_mid_lock:
|
1695
|
-
self.__clean_timeout_message_item(self.__thing_answer_service_mid, expire_timestamp)
|
1696
|
-
with self.__thing_raw_up_mid_lock:
|
1697
|
-
self.__clean_timeout_message_item(self.__thing_raw_up_mid, expire_timestamp)
|
1698
|
-
with self.__thing_raw_down_reply_mid_lock:
|
1699
|
-
self.__clean_timeout_message_item(self.__thing_raw_down_reply_mid, expire_timestamp)
|
1700
|
-
with self.__thing_prop_set_reply_mid_lock:
|
1701
|
-
self.__clean_timeout_message_item(self.__thing_prop_set_reply_mid, expire_timestamp)
|
1702
|
-
self.__clean_timeout_message_item(self.__device_info_mid, expire_timestamp)
|
1703
|
-
# self.__link_log.debug("__clean_timeout_message exit")
|
1704
|
-
|
1705
|
-
def __clean_timeout_message_item(self, mids, expire_time) -> None:
|
1706
|
-
for mid in list(mids.keys()):
|
1707
|
-
if mids[mid] < expire_time:
|
1708
|
-
timestamp = mids.pop(mid)
|
1709
|
-
self.__link_log.error("__clean_timeout_message_item pop:%r,timestamp:%r", mid, timestamp)
|
1710
|
-
|
1711
|
-
def __reconnect_wait(self) -> None:
|
1712
|
-
if self.__mqtt_auto_reconnect_sec == 0:
|
1713
|
-
self.__mqtt_auto_reconnect_sec = self.__mqtt_auto_reconnect_min_sec
|
1714
|
-
else:
|
1715
|
-
self.__mqtt_auto_reconnect_sec = min(self.__mqtt_auto_reconnect_sec * 2, self.__mqtt_auto_reconnect_max_sec)
|
1716
|
-
self.__mqtt_auto_reconnect_sec += random.randint(1, self.__mqtt_auto_reconnect_sec)
|
1717
|
-
time.sleep(self.__mqtt_auto_reconnect_sec)
|
1718
|
-
|
1719
|
-
def __reset_reconnect_wait(self) -> None:
|
1720
|
-
self.__mqtt_auto_reconnect_sec = 0
|
1721
|
-
|
1722
|
-
def start_worker_loop(self) -> None:
|
1723
|
-
pass
|
1724
|
-
|
1725
|
-
def thing_setup(self, file=None) -> int:
|
1726
|
-
if self.__linkkit_state is not LinkKit.LinkKitState.INITIALIZED:
|
1727
|
-
raise LinkKit.StateError("not in INITIALIZED state")
|
1728
|
-
if self.__thing_setup_state:
|
1729
|
-
return 1
|
1730
|
-
if file is None:
|
1731
|
-
self.__thing_raw_only = True
|
1732
|
-
self.__thing_setup_state = True
|
1733
|
-
return 0
|
1734
|
-
try:
|
1735
|
-
with open(file, encoding="utf-8") as f:
|
1736
|
-
tsl = json.load(f)
|
1737
|
-
index = 0
|
1738
|
-
while "events" in tsl and index < len(tsl["events"]):
|
1739
|
-
identifier = tsl["events"][index]["identifier"]
|
1740
|
-
if identifier == "post":
|
1741
|
-
output_data = tsl["events"][index]["outputData"]
|
1742
|
-
output_data_index = 0
|
1743
|
-
while output_data_index < len(output_data):
|
1744
|
-
output_data_item = output_data[output_data_index]["identifier"]
|
1745
|
-
self.__thing_properties_post.add(output_data_item)
|
1746
|
-
output_data_index += 1
|
1747
|
-
else:
|
1748
|
-
self.__thing_events.add(identifier)
|
1749
|
-
index += 1
|
1750
|
-
index = 0
|
1751
|
-
while "services" in tsl and index < len(tsl["services"]):
|
1752
|
-
identifier = tsl["services"][index]["identifier"]
|
1753
|
-
if identifier == "set":
|
1754
|
-
input_data = tsl["services"][index]["inputData"]
|
1755
|
-
input_data_index = 0
|
1756
|
-
while input_data_index < len(input_data):
|
1757
|
-
input_data_item = input_data[input_data_index]
|
1758
|
-
self.__thing_properties_set.add(input_data_item["identifier"])
|
1759
|
-
input_data_index += 1
|
1760
|
-
elif identifier == "get":
|
1761
|
-
output_data = tsl["services"][index]["outputData"]
|
1762
|
-
output_data_index = 0
|
1763
|
-
while output_data_index < len(output_data):
|
1764
|
-
output_data_item = output_data[output_data_index]
|
1765
|
-
self.__thing_properties_get.add(output_data_item["identifier"])
|
1766
|
-
output_data_index += 1
|
1767
|
-
else:
|
1768
|
-
self.__thing_services.add(identifier)
|
1769
|
-
service_reply_topic = self.__thing_topic_service_pattern % (
|
1770
|
-
self.__product_key,
|
1771
|
-
self.__device_name,
|
1772
|
-
identifier + "_reply",
|
1773
|
-
)
|
1774
|
-
self.__thing_topic_services_reply.add(service_reply_topic)
|
1775
|
-
index += 1
|
1776
|
-
|
1777
|
-
for event in self.__thing_events:
|
1778
|
-
post_topic = self.__thing_topic_event_post_pattern % (self.__product_key, self.__device_name, event)
|
1779
|
-
self.__thing_topic_event_post[event] = post_topic
|
1780
|
-
self.__thing_topic_event_post_reply.add(post_topic + "_reply")
|
1781
|
-
# service topic
|
1782
|
-
for service in self.__thing_services:
|
1783
|
-
self.__thing_topic_services.add(
|
1784
|
-
self.__thing_topic_service_pattern % (self.__product_key, self.__device_name, service)
|
1785
|
-
)
|
1786
|
-
|
1787
|
-
except Exception as e:
|
1788
|
-
self.__link_log.info("file open error:" + str(e))
|
1789
|
-
return 2
|
1790
|
-
self.__thing_setup_state = True
|
1791
|
-
return 0
|
1792
|
-
|
1793
|
-
def thing_raw_post_data(self, payload):
|
1794
|
-
if self.__linkkit_state is not LinkKit.LinkKitState.CONNECTED:
|
1795
|
-
self.__link_log.error("disconnected, post raw fail")
|
1796
|
-
return LinkKit.ErrorCode.NETWORK_DISCONNECTED.value
|
1797
|
-
with self.__thing_raw_up_mid_lock:
|
1798
|
-
rc, mid = self.__mqtt_client.publish(self.__thing_topic_raw_up, payload, 0)
|
1799
|
-
if rc == mqtt.MQTT_ERR_SUCCESS:
|
1800
|
-
self.__thing_raw_up_mid[mid] = self.__timestamp()
|
1801
|
-
return 0
|
1802
|
-
return 1
|
1803
|
-
|
1804
|
-
def thing_raw_data_reply(self, payload):
|
1805
|
-
if self.__linkkit_state is not LinkKit.LinkKitState.CONNECTED:
|
1806
|
-
self.__link_log.error("disconnected, raw data reply fail")
|
1807
|
-
return LinkKit.ErrorCode.NETWORK_DISCONNECTED.value
|
1808
|
-
with self.__thing_raw_down_reply_mid_lock:
|
1809
|
-
rc, mid = self.__mqtt_client.publish(self.__thing_topic_raw_down_reply, payload, 0)
|
1810
|
-
if rc == mqtt.MQTT_ERR_SUCCESS:
|
1811
|
-
self.__thing_raw_down_reply_mid[mid] = self.__timestamp()
|
1812
|
-
return 0
|
1813
|
-
return 1
|
1814
|
-
|
1815
|
-
def thing_update_device_info(self, payload):
|
1816
|
-
if self.__linkkit_state is not LinkKit.LinkKitState.CONNECTED:
|
1817
|
-
self.__link_log.error("disconnected, update device info fail")
|
1818
|
-
return LinkKit.ErrorCode.NETWORK_DISCONNECTED.value, None
|
1819
|
-
if not self.__thing_setup_state or not self.__thing_enable_state:
|
1820
|
-
raise LinkKit.StateError("not in SETUP & ENABLE state")
|
1821
|
-
return 1, None
|
1822
|
-
request_id = self.__get_thing_request_id()
|
1823
|
-
with self.__thing_update_device_info_up_mid_lock:
|
1824
|
-
rc, mid = self.__mqtt_client.publish(
|
1825
|
-
self.__thing_topic_update_device_info_up,
|
1826
|
-
self.__pack_alink_request(request_id, "thing.deviceinfo.update", payload),
|
1827
|
-
0,
|
1828
|
-
)
|
1829
|
-
if rc == mqtt.MQTT_ERR_SUCCESS:
|
1830
|
-
self.__thing_update_device_info_up_mid[mid] = self.__timestamp()
|
1831
|
-
return rc, request_id
|
1832
|
-
return 1, None
|
1833
|
-
|
1834
|
-
def thing_delete_device_info(self, payload):
|
1835
|
-
if self.__linkkit_state is not LinkKit.LinkKitState.CONNECTED:
|
1836
|
-
self.__link_log.error("disconnected, delete device info fail")
|
1837
|
-
return LinkKit.ErrorCode.NETWORK_DISCONNECTED.value, None
|
1838
|
-
if not self.__thing_setup_state or not self.__thing_enable_state:
|
1839
|
-
return 1
|
1840
|
-
request_id = self.__get_thing_request_id()
|
1841
|
-
with self.__thing_delete_device_info_up_mid_lock:
|
1842
|
-
rc, mid = self.__mqtt_client.publish(
|
1843
|
-
self.__thing_topic_delete_device_info_up,
|
1844
|
-
self.__pack_alink_request(request_id, "thing.deviceinfo.delete", payload),
|
1845
|
-
0,
|
1846
|
-
)
|
1847
|
-
if rc == mqtt.MQTT_ERR_SUCCESS:
|
1848
|
-
self.__thing_delete_device_info_up_mid[mid] = self.__timestamp()
|
1849
|
-
return rc, request_id
|
1850
|
-
return 1, None
|
1851
|
-
|
1852
|
-
def thing_update_tags(self, tagMap):
|
1853
|
-
if not isinstance(tagMap, dict):
|
1854
|
-
raise ValueError("tagMap must be a dictionary")
|
1855
|
-
return 1, None
|
1856
|
-
|
1857
|
-
payload = []
|
1858
|
-
for k, v in tagMap.items():
|
1859
|
-
payload.append({LinkKit.TAG_KEY: k, LinkKit.TAG_VALUE: v})
|
1860
|
-
return self.thing_update_device_info(payload)
|
1861
|
-
|
1862
|
-
def thing_remove_tags(self, tagKeys):
|
1863
|
-
if not isinstance(tagKeys, list) and not isinstance(tagKeys, tuple):
|
1864
|
-
raise ValueError("tagKeys must be a list or tuple")
|
1865
|
-
return 1, None
|
1866
|
-
|
1867
|
-
payload = []
|
1868
|
-
for tagKey in tagKeys:
|
1869
|
-
payload.append({LinkKit.TAG_KEY: tagKey})
|
1870
|
-
return self.thing_delete_device_info(payload)
|
1871
|
-
|
1872
|
-
def __pack_alink_request(self, request_id, method, params):
|
1873
|
-
request = {"id": request_id, "version": "1.0", "params": params, "method": method}
|
1874
|
-
return json.dumps(request)
|
1875
|
-
|
1876
|
-
def thing_answer_service(self, identifier, request_id, code, data=None):
|
1877
|
-
if self.__linkkit_state is not LinkKit.LinkKitState.CONNECTED:
|
1878
|
-
self.__link_log.error("disconnected, answer service fail")
|
1879
|
-
return LinkKit.ErrorCode.NETWORK_DISCONNECTED.value
|
1880
|
-
if not self.__thing_setup_state or not self.__thing_enable_state:
|
1881
|
-
return 1
|
1882
|
-
if data is None:
|
1883
|
-
data = {}
|
1884
|
-
response = {"id": request_id, "code": code, "data": data}
|
1885
|
-
|
1886
|
-
item = self.__pop_rrpc_service("alink_" + str(request_id))
|
1887
|
-
if item:
|
1888
|
-
service_reply_topic = item["topic"]
|
1889
|
-
else:
|
1890
|
-
service_reply_topic = self.__thing_topic_service_pattern % (
|
1891
|
-
self.__product_key,
|
1892
|
-
self.__device_name,
|
1893
|
-
identifier + "_reply",
|
1894
|
-
)
|
1895
|
-
with self.__thing_answer_service_mid_lock:
|
1896
|
-
rc, mid = self.__mqtt_client.publish(service_reply_topic, json.dumps(response), 0)
|
1897
|
-
if rc == mqtt.MQTT_ERR_SUCCESS:
|
1898
|
-
self.__thing_answer_service_mid[mid] = self.__timestamp()
|
1899
|
-
return 0
|
1900
|
-
return 1
|
1901
|
-
|
1902
|
-
def __get_thing_request_id(self):
|
1903
|
-
with self.__thing_request_id_lock:
|
1904
|
-
self.__thing_request_value += 1
|
1905
|
-
if self.__thing_request_value > self.__thing_request_id_max:
|
1906
|
-
self.__thing_request_value = 0
|
1907
|
-
if len(self.__thing_request_id) > self.__mqtt_max_queued_message:
|
1908
|
-
return None
|
1909
|
-
if self.__thing_request_value not in self.__thing_request_id:
|
1910
|
-
self.__thing_request_id[self.__thing_request_value] = self.__timestamp()
|
1911
|
-
self.__link_log.debug("__get_thing_request_id pop:%r" % self.__thing_request_value)
|
1912
|
-
return str(self.__thing_request_value)
|
1913
|
-
return None
|
1914
|
-
|
1915
|
-
def __back_thing_request_id(self, post_id) -> None:
|
1916
|
-
with self.__thing_request_id_lock:
|
1917
|
-
try:
|
1918
|
-
self.__thing_request_id.pop(int(post_id))
|
1919
|
-
except Exception as e:
|
1920
|
-
self.__link_log.error("__back_thing_request_id pop:%r,%r" % (post_id, e))
|
1921
|
-
|
1922
|
-
def __reset_thing_request_id(self) -> None:
|
1923
|
-
with self.__thing_request_id_lock:
|
1924
|
-
self.__thing_request_value = 0
|
1925
|
-
self.__thing_request_id.clear()
|
1926
|
-
|
1927
|
-
def __clean_thing_timeout_request_id(self) -> None:
|
1928
|
-
with self.__thing_request_id_lock:
|
1929
|
-
expire_timestamp = self.__timestamp() - self.__mqtt_request_timeout * 1000
|
1930
|
-
for request_id in list(self.__thing_request_id.keys()):
|
1931
|
-
if self.__thing_request_id[request_id] < expire_timestamp:
|
1932
|
-
timestamp = self.__thing_request_id.pop(request_id)
|
1933
|
-
self.__link_log.error("__clean_thing_timeout_request_id pop:%r,timestamp:%r", request_id, timestamp)
|
1934
|
-
|
1935
|
-
def thing_trigger_event(self, event_tuple):
|
1936
|
-
if self.__linkkit_state is not LinkKit.LinkKitState.CONNECTED:
|
1937
|
-
self.__link_log.error("disconnected, trigger event fail")
|
1938
|
-
return LinkKit.ErrorCode.NETWORK_DISCONNECTED.value, None
|
1939
|
-
if not self.__thing_setup_state or not self.__thing_enable_state:
|
1940
|
-
return 1, None
|
1941
|
-
if isinstance(event_tuple, tuple):
|
1942
|
-
event, params = event_tuple
|
1943
|
-
else:
|
1944
|
-
return 1, None
|
1945
|
-
if event not in self.__thing_topic_event_post.keys():
|
1946
|
-
return 1, None
|
1947
|
-
request_id = self.__get_thing_request_id()
|
1948
|
-
if request_id is None:
|
1949
|
-
return 1
|
1950
|
-
request = {
|
1951
|
-
"id": request_id,
|
1952
|
-
"version": "1.0",
|
1953
|
-
"params": {
|
1954
|
-
"value": params,
|
1955
|
-
},
|
1956
|
-
"method": "thing.event.%s.post" % event,
|
1957
|
-
}
|
1958
|
-
with self.__thing_event_post_mid_lock:
|
1959
|
-
event_topic = self.__thing_topic_event_post[event]
|
1960
|
-
self.__link_log.debug("thing_trigger_event publish topic")
|
1961
|
-
rc, mid = self.__mqtt_client.publish(event_topic, json.dumps(request), 0)
|
1962
|
-
self.__link_log.debug("thing_trigger_event publish done")
|
1963
|
-
if rc == mqtt.MQTT_ERR_SUCCESS:
|
1964
|
-
self.__thing_event_post_mid[mid] = self.__timestamp()
|
1965
|
-
return 0, request_id
|
1966
|
-
else:
|
1967
|
-
return 1, None
|
1968
|
-
|
1969
|
-
def thing_post_property(self, property_data):
|
1970
|
-
if self.__linkkit_state is not LinkKit.LinkKitState.CONNECTED:
|
1971
|
-
self.__link_log.error("disconnected, post property fail")
|
1972
|
-
return LinkKit.ErrorCode.NETWORK_DISCONNECTED.value, None
|
1973
|
-
if not self.__thing_setup_state or not self.__thing_enable_state:
|
1974
|
-
return 1, None
|
1975
|
-
request_params = property_data
|
1976
|
-
request_id = self.__get_thing_request_id()
|
1977
|
-
if request_id is None:
|
1978
|
-
return 1, None
|
1979
|
-
request = {"id": request_id, "version": "1.0", "params": request_params, "method": "thing.event.property.post"}
|
1980
|
-
with self.__thing_prop_post_mid_lock:
|
1981
|
-
rc, mid = self.__mqtt_client.publish(self.__thing_topic_prop_post, json.dumps(request), 1)
|
1982
|
-
if rc == mqtt.MQTT_ERR_SUCCESS:
|
1983
|
-
self.__thing_prop_post_mid[mid] = self.__timestamp()
|
1984
|
-
return 0, request_id
|
1985
|
-
else:
|
1986
|
-
return 1, None
|
1987
|
-
|
1988
|
-
def __on_internal_async_message(self, message) -> None:
|
1989
|
-
self.__link_log.debug("__on_internal_async_message topic:%r" % message.topic)
|
1990
|
-
triggered_flag = 0
|
1991
|
-
|
1992
|
-
if message.topic == self.__thing_topic_prop_set:
|
1993
|
-
payload = self.__load_json(message.payload)
|
1994
|
-
params = payload["params"]
|
1995
|
-
try:
|
1996
|
-
reply = {"id": payload["id"], "code": 200, "data": {}}
|
1997
|
-
with self.__thing_prop_set_reply_mid_lock:
|
1998
|
-
rc, mid = self.__mqtt_client.publish(self.__thing_topic_prop_set_reply, json.dumps(reply), 1)
|
1999
|
-
if rc == 0:
|
2000
|
-
self.__link_log.info("prop changed reply success,mid:%d" % mid)
|
2001
|
-
self.__thing_prop_set_reply_mid[mid] = self.__timestamp()
|
2002
|
-
self.__link_log.info("prop changed reply success")
|
2003
|
-
else:
|
2004
|
-
self.__link_log.info("prop changed reply fail")
|
2005
|
-
if self.__on_thing_prop_changed is not None:
|
2006
|
-
triggered_flag = 1
|
2007
|
-
self.__on_thing_prop_changed(params, self.__user_data)
|
2008
|
-
except Exception as e:
|
2009
|
-
self.__link_log.error("on_thing_prop_changed raise exception:%s" % e)
|
2010
|
-
elif message.topic == self.__device_info_topic_reply:
|
2011
|
-
payload = self.__load_json(message.payload)
|
2012
|
-
request_id = payload["id"]
|
2013
|
-
code = payload["code"]
|
2014
|
-
reply_message = payload["message"]
|
2015
|
-
data = payload["data"]
|
2016
|
-
self.__back_thing_request_id(request_id)
|
2017
|
-
if code != 200:
|
2018
|
-
self.__link_log.error("upload device info reply error:%s" % reply_message)
|
2019
|
-
try:
|
2020
|
-
if self.__on_thing_device_info_update is not None:
|
2021
|
-
triggered_flag = 1
|
2022
|
-
self.__on_thing_device_info_update(request_id, code, data, reply_message, self.__user_data)
|
2023
|
-
except Exception as e:
|
2024
|
-
self.__link_log.error("__on_thing_device_info_update process raise exception:%s" % e)
|
2025
|
-
elif message.topic == self.__thing_topic_prop_post_reply:
|
2026
|
-
payload = self.__load_json(message.payload)
|
2027
|
-
request_id = payload["id"]
|
2028
|
-
code = payload["code"]
|
2029
|
-
data = payload["data"]
|
2030
|
-
reply_message = payload["message"]
|
2031
|
-
try:
|
2032
|
-
if self.__on_thing_prop_post is not None:
|
2033
|
-
triggered_flag = 1
|
2034
|
-
self.__on_thing_prop_post(request_id, code, data, reply_message, self.__user_data)
|
2035
|
-
except Exception as e:
|
2036
|
-
self.__link_log.error("on_thing_prop_post raise exception:%s" % e)
|
2037
|
-
self.__back_thing_request_id(request_id)
|
2038
|
-
elif message.topic == self.__thing_topic_prop_get:
|
2039
|
-
pass
|
2040
|
-
elif message.topic in self.__thing_topic_event_post_reply:
|
2041
|
-
event = message.topic.split("/", 7)[6]
|
2042
|
-
payload = self.__load_json(message.payload)
|
2043
|
-
request_id = payload["id"]
|
2044
|
-
code = payload["code"]
|
2045
|
-
data = payload["data"]
|
2046
|
-
reply_message = payload["message"]
|
2047
|
-
self.__link_log.info("on_thing_event_post message:%s" % reply_message)
|
2048
|
-
try:
|
2049
|
-
if self.on_thing_event_post is not None:
|
2050
|
-
triggered_flag = 1
|
2051
|
-
self.on_thing_event_post(event, request_id, code, data, reply_message, self.__user_data)
|
2052
|
-
except Exception as e:
|
2053
|
-
self.__link_log.error("on_thing_event_post raise exception:%s" % e)
|
2054
|
-
self.__back_thing_request_id(request_id)
|
2055
|
-
elif message.topic in self.__thing_topic_services:
|
2056
|
-
identifier = message.topic.split("/", 6)[6]
|
2057
|
-
payload = self.__load_json(message.payload)
|
2058
|
-
try:
|
2059
|
-
request_id = payload["id"]
|
2060
|
-
params = payload["params"]
|
2061
|
-
if self.__on_thing_call_service is not None:
|
2062
|
-
triggered_flag = 1
|
2063
|
-
self.__on_thing_call_service(identifier, request_id, params, self.__user_data)
|
2064
|
-
except Exception as e:
|
2065
|
-
self.__link_log.error("on_thing_call_service raise exception: %s" % e)
|
2066
|
-
elif message.topic == self.__thing_topic_raw_down:
|
2067
|
-
try:
|
2068
|
-
if self.__on_thing_raw_data_arrived is not None:
|
2069
|
-
triggered_flag = 1
|
2070
|
-
self.__on_thing_raw_data_arrived(message.payload, self.__user_data)
|
2071
|
-
except Exception as e:
|
2072
|
-
self.__link_log.error("on_thing_raw_data_arrived process raise exception:%s" % e)
|
2073
|
-
elif message.topic == self.__thing_topic_raw_up_reply:
|
2074
|
-
try:
|
2075
|
-
if self.__on_thing_raw_data_post is not None:
|
2076
|
-
triggered_flag = 1
|
2077
|
-
self.__on_thing_raw_data_post(message.payload, self.__user_data)
|
2078
|
-
except Exception as e:
|
2079
|
-
self.__link_log.error("on_thing_raw_post_data process raise exception:%s" % e)
|
2080
|
-
elif message.topic == self.__thing_topic_update_device_info_reply:
|
2081
|
-
try:
|
2082
|
-
if self.__on_thing_device_info_update is not None:
|
2083
|
-
triggered_flag = 1
|
2084
|
-
payload = self.__load_json(message.payload)
|
2085
|
-
request_id = payload["id"]
|
2086
|
-
code = payload["code"]
|
2087
|
-
data = payload["data"]
|
2088
|
-
msg = payload["message"]
|
2089
|
-
self.__on_thing_device_info_update(request_id, code, data, msg, self.__user_data)
|
2090
|
-
except Exception as e:
|
2091
|
-
self.__link_log.error("__on_thing_device_info_update process raise exception:%s" % e)
|
2092
|
-
elif message.topic == self.__thing_topic_delete_device_info_reply:
|
2093
|
-
try:
|
2094
|
-
if self.__on_thing_device_info_delete is not None:
|
2095
|
-
triggered_flag = 1
|
2096
|
-
payload = self.__load_json(message.payload)
|
2097
|
-
request_id = payload["id"]
|
2098
|
-
code = payload["code"]
|
2099
|
-
data = payload["data"]
|
2100
|
-
msg = payload["message"]
|
2101
|
-
self.__on_thing_device_info_delete(request_id, code, data, msg, self.__user_data)
|
2102
|
-
except Exception as e:
|
2103
|
-
self.__link_log.error("__on_thing_device_info_update process raise exception:%s" % e)
|
2104
|
-
elif message.topic == self.__thing_topic_shadow_get:
|
2105
|
-
self.__try_parse_try_shadow(message.payload)
|
2106
|
-
try:
|
2107
|
-
if self.__on_thing_shadow_get is not None:
|
2108
|
-
triggered_flag = 1
|
2109
|
-
self.__on_thing_shadow_get(self.__load_json(message.payload), self.__user_data)
|
2110
|
-
except Exception as e:
|
2111
|
-
self.__link_log.error("__on_thing_shadow_get process raise exception:%s" % e)
|
2112
|
-
elif message.topic.startswith("/ext/rrpc/"):
|
2113
|
-
triggered_flag = self.__try_parse_rrpc_topic(message)
|
2114
|
-
elif message.topic == self.__gateway_topic_topo_change:
|
2115
|
-
try:
|
2116
|
-
payload = self.__load_json(message.payload)
|
2117
|
-
request_id = payload["id"]
|
2118
|
-
params = payload["params"]
|
2119
|
-
if self.__on_gateway_topo_change is not None:
|
2120
|
-
triggered_flag = 1
|
2121
|
-
self.__on_gateway_topo_change(request_id, params, self.__user_data)
|
2122
|
-
except Exception as e:
|
2123
|
-
self.__link_log.error("__on_gateway_topo_change process raise exception:%s" % e)
|
2124
|
-
elif message.topic == self.__gateway_topic_add_subdev_topo_reply:
|
2125
|
-
try:
|
2126
|
-
payload = self.__load_json(message.payload)
|
2127
|
-
request_id = payload["id"]
|
2128
|
-
code = payload["code"]
|
2129
|
-
data = payload["data"]
|
2130
|
-
msg = payload["message"]
|
2131
|
-
self.__back_thing_request_id(request_id)
|
2132
|
-
if self.__on_gateway_add_subdev_topo_reply is not None:
|
2133
|
-
triggered_flag = 1
|
2134
|
-
self.__on_gateway_add_subdev_topo_reply(request_id, code, data, msg, self.__user_data)
|
2135
|
-
except Exception as e:
|
2136
|
-
self.__link_log.error("__on_gateway_add_subdev_topo_reply process raise exception:%s" % e)
|
2137
|
-
elif message.topic == self.__gateway_topic_delete_subdev_topo_reply:
|
2138
|
-
try:
|
2139
|
-
payload = self.__load_json(message.payload)
|
2140
|
-
request_id = payload["id"]
|
2141
|
-
code = payload["code"]
|
2142
|
-
data = payload["data"]
|
2143
|
-
msg = payload["message"]
|
2144
|
-
self.__back_thing_request_id(request_id)
|
2145
|
-
if self.__on_gateway_delete_subdev_topo_reply is not None:
|
2146
|
-
triggered_flag = 1
|
2147
|
-
self.__on_gateway_delete_subdev_topo_reply(request_id, code, data, msg, self.__user_data)
|
2148
|
-
except Exception as e:
|
2149
|
-
self.__link_log.error("__on_gateway_delete_subdev_topo_reply process raise exception:%s" % e)
|
2150
|
-
elif message.topic == self.__gateway_topic_login_subdev_reply:
|
2151
|
-
try:
|
2152
|
-
payload = self.__load_json(message.payload)
|
2153
|
-
request_id = payload["id"]
|
2154
|
-
code = payload["code"]
|
2155
|
-
data = payload["data"]
|
2156
|
-
msg = payload["message"]
|
2157
|
-
self.__back_thing_request_id(request_id)
|
2158
|
-
if self.__on_gateway_login_subdev_reply is not None:
|
2159
|
-
triggered_flag = 1
|
2160
|
-
self.__on_gateway_login_subdev_reply(request_id, code, data, msg, self.__user_data)
|
2161
|
-
except Exception as e:
|
2162
|
-
self.__link_log.error("__on_gateway_login_subdev_reply process raise exception:%s" % e)
|
2163
|
-
elif message.topic == self.__gateway_topic_logout_subdev_reply:
|
2164
|
-
try:
|
2165
|
-
payload = self.__load_json(message.payload)
|
2166
|
-
request_id = payload["id"]
|
2167
|
-
code = payload["code"]
|
2168
|
-
data = payload["data"]
|
2169
|
-
msg = payload["message"]
|
2170
|
-
self.__back_thing_request_id(request_id)
|
2171
|
-
if self.__on_gateway_logout_subdev_reply is not None:
|
2172
|
-
triggered_flag = 1
|
2173
|
-
self.__on_gateway_logout_subdev_reply(request_id, code, data, msg, self.__user_data)
|
2174
|
-
except Exception as e:
|
2175
|
-
self.__link_log.error("__on_gateway_logout_subdev_reply process raise exception:%s" % e)
|
2176
|
-
elif message.topic == self.__gateway_topic_register_subdev_reply:
|
2177
|
-
try:
|
2178
|
-
payload = self.__load_json(message.payload)
|
2179
|
-
request_id = payload["id"]
|
2180
|
-
code = payload["code"]
|
2181
|
-
data = payload["data"]
|
2182
|
-
msg = payload["message"]
|
2183
|
-
self.__back_thing_request_id(request_id)
|
2184
|
-
if self.__on_gateway_register_subdev_reply is not None:
|
2185
|
-
triggered_flag = 1
|
2186
|
-
self.__on_gateway_register_subdev_reply(request_id, code, data, msg, self.__user_data)
|
2187
|
-
except Exception as e:
|
2188
|
-
self.__link_log.error("__on_gateway_register_subdev_reply process raise exception:%s" % e)
|
2189
|
-
elif message.topic == self.__gateway_topic_product_register_subdev_reply:
|
2190
|
-
try:
|
2191
|
-
payload = self.__load_json(message.payload)
|
2192
|
-
request_id = payload["id"]
|
2193
|
-
code = payload["code"]
|
2194
|
-
data = payload["data"]
|
2195
|
-
msg = payload["message"]
|
2196
|
-
self.__back_thing_request_id(request_id)
|
2197
|
-
if self.__on_gateway_product_register_subdev_reply is not None:
|
2198
|
-
triggered_flag = 1
|
2199
|
-
self.__on_gateway_product_register_subdev_reply(request_id, code, data, msg, self.__user_data)
|
2200
|
-
except Exception as e:
|
2201
|
-
self.__link_log.error("__on_gateway_product_register_subdev_reply process raise exception:%s" % e)
|
2202
|
-
elif message.topic == self.__dynamic_register_topic:
|
2203
|
-
try:
|
2204
|
-
payload = self.__load_json(message.payload)
|
2205
|
-
device_secret = payload["deviceSecret"]
|
2206
|
-
self.disconnect()
|
2207
|
-
self.__dynamic_register_flag = 0
|
2208
|
-
if self.__on_device_dynamic_register is not None:
|
2209
|
-
triggered_flag = 1
|
2210
|
-
self.__on_device_dynamic_register(LinkKit.ErrorCode.SUCCESS.value, device_secret, None)
|
2211
|
-
except Exception as e:
|
2212
|
-
self.__link_log.error("__on_device_dynamic_register process raise exception:%s" % e)
|
2213
|
-
|
2214
|
-
elif message.topic == self.__dynamic_register_nwl_topic:
|
2215
|
-
# 一型一密免动态注册获取到username和token
|
2216
|
-
try:
|
2217
|
-
payload = self.__load_json(message.payload)
|
2218
|
-
client_id = payload["clientId"]
|
2219
|
-
client_id = client_id + "|authType=connwl,securemode=-2,_ss=1,ext=3,lan=%s,_v=%s|" % (
|
2220
|
-
self.__sdk_program_language,
|
2221
|
-
self.__sdk_version,
|
2222
|
-
)
|
2223
|
-
product_key = payload["productKey"]
|
2224
|
-
device_name = payload["deviceName"]
|
2225
|
-
username = device_name + "&" + product_key
|
2226
|
-
password = payload["deviceToken"]
|
2227
|
-
self.disconnect()
|
2228
|
-
self.__dynamic_register_nwl_flag = 0
|
2229
|
-
if self.__on_device_dynamic_register_nwl_reply is not None:
|
2230
|
-
triggered_flag = 1
|
2231
|
-
self.__on_device_dynamic_register_nwl_reply(
|
2232
|
-
LinkKit.ErrorCode.SUCCESS.value, client_id, username, password
|
2233
|
-
)
|
2234
|
-
except Exception as e:
|
2235
|
-
self.__link_log.error("__on_device_dynamic_register_nwl_reply process raise exception:%s" % e)
|
2236
|
-
elif message.topic == self.__ota_push_topic or message.topic == self.__ota_pull_reply_topic:
|
2237
|
-
try:
|
2238
|
-
payload = json.loads(self.__to_str(message.payload))
|
2239
|
-
data = payload.setdefault("data", "")
|
2240
|
-
|
2241
|
-
json_data = json.dumps(data)
|
2242
|
-
download_info = json.loads(str(json_data))
|
2243
|
-
|
2244
|
-
url = download_info.setdefault("url", "")
|
2245
|
-
version = download_info.setdefault("version", "")
|
2246
|
-
size = download_info.setdefault("size", "")
|
2247
|
-
sign_method = download_info.setdefault("signMethod", "")
|
2248
|
-
sign = download_info.setdefault("sign", "")
|
2249
|
-
extra = download_info.setdefault("extData", "")
|
2250
|
-
module = download_info.setdefault("module", "default")
|
2251
|
-
|
2252
|
-
if (
|
2253
|
-
not self.__is_valid_str(url)
|
2254
|
-
or not self.__is_valid_str(version)
|
2255
|
-
or not self.__is_valid_str(size)
|
2256
|
-
or not self.__is_valid_str(sign_method)
|
2257
|
-
or not self.__is_valid_str(sign)
|
2258
|
-
):
|
2259
|
-
self.__link_log.error("invalid download params")
|
2260
|
-
return
|
2261
|
-
|
2262
|
-
ota_notice_type = 0
|
2263
|
-
if message.topic == self.__ota_push_topic:
|
2264
|
-
ota_notice_type = 1
|
2265
|
-
else:
|
2266
|
-
ota_notice_type = 2
|
2267
|
-
|
2268
|
-
if self.__on_ota_message_arrived is not None:
|
2269
|
-
triggered_flag = 1
|
2270
|
-
self.__on_ota_message_arrived(
|
2271
|
-
ota_notice_type, version, size, url, sign_method, sign, module, str(extra)
|
2272
|
-
)
|
2273
|
-
except Exception as e:
|
2274
|
-
self.__link_log.error("__on_ota_message_arrived process raise exception:%s" % e)
|
2275
|
-
|
2276
|
-
if triggered_flag == 1:
|
2277
|
-
return
|
2278
|
-
|
2279
|
-
if self.__on_topic_message is not None:
|
2280
|
-
try:
|
2281
|
-
self.__on_topic_message(message.topic, message.payload, message.qos, self.__user_data)
|
2282
|
-
except Exception as e:
|
2283
|
-
self.__link_log.error("on_topic_message process raise exception:%s" % e)
|
2284
|
-
else:
|
2285
|
-
self.__link_log.error("receive unscubscibe topic : %s" % message.topic)
|
2286
|
-
|
2287
|
-
def query_ota_firmware(self, module=None):
|
2288
|
-
request_id = self.__get_thing_request_id()
|
2289
|
-
if request_id is None:
|
2290
|
-
request_id = "1"
|
2291
|
-
|
2292
|
-
if self.__is_valid_str(module):
|
2293
|
-
payload = '{"id": %s, "params": {"module": "%s"}}' % (request_id, module)
|
2294
|
-
else:
|
2295
|
-
payload = '{"id": %s, "params": {}}' % request_id
|
2296
|
-
|
2297
|
-
rc = self.__mqtt_client.publish(self.__ota_pull_topic, payload, 0)
|
2298
|
-
if rc == mqtt.MQTT_ERR_SUCCESS:
|
2299
|
-
return 0
|
2300
|
-
else:
|
2301
|
-
return LinkKit.ErrorCode.OTA_PUB_FAILED
|
2302
|
-
|
2303
|
-
def __cal_file_sign(self, filename, sign_method):
|
2304
|
-
if sign_method == "Md5":
|
2305
|
-
hash_tool = hashlib.md5()
|
2306
|
-
elif sign_method == "SHA256":
|
2307
|
-
hash_tool = hashlib.sha256()
|
2308
|
-
else:
|
2309
|
-
return LinkKit.ErrorCode.OTA_INVALID_SIGN_METHOD, -1
|
2310
|
-
|
2311
|
-
with open(filename, "rb") as f:
|
2312
|
-
while True:
|
2313
|
-
chunk = f.read(4096)
|
2314
|
-
if not chunk:
|
2315
|
-
break
|
2316
|
-
hash_tool.update(chunk)
|
2317
|
-
return LinkKit.ErrorCode.SUCCESS, hash_tool.hexdigest()
|
2318
|
-
|
2319
|
-
def ota_report_version(self, module, version):
|
2320
|
-
if not self.__is_valid_str(version):
|
2321
|
-
return LinkKit.ErrorCode.OTA_INVALID_PARAM
|
2322
|
-
|
2323
|
-
request_id = "1"
|
2324
|
-
if self.__is_valid_str(module):
|
2325
|
-
payload = '{"id": %s,"params": {"version":"%s","module": "%s"}}' % (request_id, version, module)
|
2326
|
-
else:
|
2327
|
-
payload = '{"id": %s, "params": {"version": "%s"}}' % (request_id, version)
|
2328
|
-
|
2329
|
-
rc = self.__mqtt_client.publish(self.__ota_report_version_topic, payload, 0)
|
2330
|
-
if rc == mqtt.MQTT_ERR_SUCCESS:
|
2331
|
-
return LinkKit.ErrorCode.SUCCESS
|
2332
|
-
else:
|
2333
|
-
return LinkKit.ErrorCode.OTA_PUB_FAILED
|
2334
|
-
|
2335
|
-
def download_ota_firmware(self, url, local_path, sign_method, sign, download_step=10 * 1024):
|
2336
|
-
if (
|
2337
|
-
not self.__is_valid_str(url)
|
2338
|
-
or not self.__is_valid_str(local_path)
|
2339
|
-
or not self.__is_valid_str(sign_method)
|
2340
|
-
or not self.__is_valid_str(sign)
|
2341
|
-
):
|
2342
|
-
return LinkKit.ErrorCode.OTA_INVALID_PARAM
|
2343
|
-
|
2344
|
-
context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cadata=self.__aliyun_broker_ca_data)
|
2345
|
-
|
2346
|
-
try:
|
2347
|
-
conn = urllib.request.urlopen(url, context=context)
|
2348
|
-
except Exception as e:
|
2349
|
-
# Return code error (e.g. 404, 501, ...)
|
2350
|
-
self.__link_log.error("HTTPError: {} %s" % e)
|
2351
|
-
return LinkKit.ErrorCode.OTA_INVALID_URL
|
2352
|
-
else:
|
2353
|
-
# 200
|
2354
|
-
self.__link_log.info("https return 200")
|
2355
|
-
|
2356
|
-
try:
|
2357
|
-
file = open(local_path, "wb")
|
2358
|
-
except OSError as e:
|
2359
|
-
self.__link_log.error("open file error: {}" + e.filename)
|
2360
|
-
return LinkKit.ErrorCode.OTA_INVALID_PATH
|
2361
|
-
else:
|
2362
|
-
# Download ota file
|
2363
|
-
with file:
|
2364
|
-
while True:
|
2365
|
-
try:
|
2366
|
-
data = conn.read(download_step)
|
2367
|
-
except Exception as e:
|
2368
|
-
self.__link_log.error("download exception %s" % e)
|
2369
|
-
return LinkKit.ErrorCode.OTA_DOWNLOAD_FAIL
|
2370
|
-
else:
|
2371
|
-
if len(data) <= 0:
|
2372
|
-
break
|
2373
|
-
else:
|
2374
|
-
file.write(data)
|
2375
|
-
|
2376
|
-
# Compare checksum
|
2377
|
-
ret, firmware_sign = self.__cal_file_sign(local_path, sign_method)
|
2378
|
-
if ret == LinkKit.ErrorCode.SUCCESS and firmware_sign == sign:
|
2379
|
-
self.__link_log.info("sign match")
|
2380
|
-
return LinkKit.ErrorCode.SUCCESS
|
2381
|
-
else:
|
2382
|
-
self.__link_log.error("sign mismatch, expect:" + firmware_sign + ", actually:" + sign)
|
2383
|
-
return LinkKit.ErrorCode.OTA_DIGEST_MISMATCH
|
2384
|
-
|
2385
|
-
def __parse_raw_topic(self, topic):
|
2386
|
-
return re.search("/ext/rrpc/.*?(/.*)", topic).group(1)
|
2387
|
-
|
2388
|
-
def __tidy_topic(self, topic):
|
2389
|
-
if topic == None:
|
2390
|
-
return None
|
2391
|
-
topic = topic.strip()
|
2392
|
-
if len(topic) == 0:
|
2393
|
-
return None
|
2394
|
-
if topic[0] != "/":
|
2395
|
-
topic = "/" + topic
|
2396
|
-
return topic
|
2397
|
-
|
2398
|
-
def __push_rrpc_service(self, item) -> None:
|
2399
|
-
with self.__user_rrpc_request_ids_lock:
|
2400
|
-
if len(self.__user_rrpc_request_ids) > self.__user_rrpc_request_max_len:
|
2401
|
-
removed_item = self.__user_rrpc_request_ids.pop(0)
|
2402
|
-
del self.__user_rrpc_request_id_index_map[removed_item["id"]]
|
2403
|
-
|
2404
|
-
self.__user_rrpc_request_ids.append(item)
|
2405
|
-
self.__user_rrpc_request_id_index_map[item["id"]] = 0
|
2406
|
-
|
2407
|
-
def __pop_rrpc_service(self, id):
|
2408
|
-
with self.__user_rrpc_request_ids_lock:
|
2409
|
-
if id not in self.__user_rrpc_request_id_index_map:
|
2410
|
-
return None
|
2411
|
-
del self.__user_rrpc_request_id_index_map[id]
|
2412
|
-
for index in range(len(self.__user_rrpc_request_ids)):
|
2413
|
-
item = self.__user_rrpc_request_ids[index]
|
2414
|
-
if item["id"] == id:
|
2415
|
-
del self.__user_rrpc_request_ids[index]
|
2416
|
-
return item
|
2417
|
-
return None
|
2418
|
-
|
2419
|
-
def thing_answer_rrpc(self, id, response):
|
2420
|
-
item = self.__pop_rrpc_service("rrpc_" + id)
|
2421
|
-
if item == None:
|
2422
|
-
self.__link_log.error("answer_rrpc_topic, the id does not exist: %s" % id)
|
2423
|
-
return 1, None
|
2424
|
-
rc, mid = self.__mqtt_client.publish(item["topic"], response, 0)
|
2425
|
-
self.__link_log.debug("reply topic:%s" % item["topic"])
|
2426
|
-
return rc, mid
|
2427
|
-
|
2428
|
-
def __try_parse_rrpc_topic(self, message):
|
2429
|
-
self.__link_log.debug("receive a rrpc topic:%s" % message.topic)
|
2430
|
-
raw_topic = self.__parse_raw_topic(message.topic)
|
2431
|
-
triggered = 0
|
2432
|
-
# if it is a service, log it...
|
2433
|
-
if raw_topic.startswith("/sys") and raw_topic in self.__thing_topic_services:
|
2434
|
-
identifier = raw_topic.split("/", 6)[6]
|
2435
|
-
payload = self.__load_json(self.__to_str(message.payload))
|
2436
|
-
try:
|
2437
|
-
request_id = payload["id"]
|
2438
|
-
params = payload["params"]
|
2439
|
-
item_id = "alink_" + request_id
|
2440
|
-
item = {
|
2441
|
-
"id": item_id,
|
2442
|
-
"request_id": request_id,
|
2443
|
-
"payload": payload,
|
2444
|
-
"identifier": identifier,
|
2445
|
-
"topic": message.topic,
|
2446
|
-
}
|
2447
|
-
self.__push_rrpc_service(item)
|
2448
|
-
if self.__on_thing_call_service is not None:
|
2449
|
-
triggered = 1
|
2450
|
-
self.__on_thing_call_service(identifier, request_id, params, self.__user_data)
|
2451
|
-
except Exception as e:
|
2452
|
-
self.__link_log.error("on_thing_call_service raise exception: %s" % e)
|
2453
|
-
return triggered
|
2454
|
-
|
2455
|
-
# parse
|
2456
|
-
with self.__user_rrpc_topics_subscribe_request_lock:
|
2457
|
-
with self.__user_rrpc_topics_lock:
|
2458
|
-
if raw_topic not in self.__user_rrpc_topics:
|
2459
|
-
self.__link_log.error("%s is not in the rrpc-subscribed list" % raw_topic)
|
2460
|
-
return
|
2461
|
-
if not self.__on_topic_rrpc_message:
|
2462
|
-
return
|
2463
|
-
try:
|
2464
|
-
rrpc_id = message.topic.split("/", 4)[3]
|
2465
|
-
item_id = "rrpc_" + rrpc_id
|
2466
|
-
item = {"id": item_id, "payload": message.payload, "topic": message.topic}
|
2467
|
-
self.__push_rrpc_service(item)
|
2468
|
-
self.__on_topic_rrpc_message(rrpc_id, message.topic, message.payload, message.qos, self.__user_data)
|
2469
|
-
# self.__mqtt_client.publish(message.topic, response, 0)
|
2470
|
-
# self.__link_log.debug('reply topic:%s' % message.topic)
|
2471
|
-
except Exception as e:
|
2472
|
-
self.__link_log.error("on_topic_rrpc_message process raise exception:%r" % e)
|
2473
|
-
|
2474
|
-
def __try_parse_try_shadow(self, payload) -> None:
|
2475
|
-
try:
|
2476
|
-
self.__latest_shadow.set_latest_recevied_time(self.__timestamp())
|
2477
|
-
self.__latest_shadow.set_latest_recevied_payload(payload)
|
2478
|
-
|
2479
|
-
# parse the pay load
|
2480
|
-
msg = self.__load_json(payload)
|
2481
|
-
# set version
|
2482
|
-
if "version" in msg:
|
2483
|
-
self.__latest_shadow.set_version(msg["version"])
|
2484
|
-
elif "payload" in msg and "version" in msg["payload"]:
|
2485
|
-
self.__latest_shadow.set_version(msg["payload"]["version"])
|
2486
|
-
|
2487
|
-
# set timestamp
|
2488
|
-
if "timestamp" in msg:
|
2489
|
-
self.__latest_shadow.set_timestamp(msg["timestamp"])
|
2490
|
-
elif "payload" in msg and "timestamp" in msg["payload"]:
|
2491
|
-
self.__latest_shadow.set_timestamp(msg["payload"]["timestamp"])
|
2492
|
-
|
2493
|
-
# set state and metadata
|
2494
|
-
if "payload" in msg and msg["payload"]["status"] == "success":
|
2495
|
-
if "state" in msg["payload"]:
|
2496
|
-
self.__latest_shadow.set_state(msg["payload"]["state"])
|
2497
|
-
if "metadata" in msg["payload"]:
|
2498
|
-
self.__latest_shadow.set_metadata(msg["payload"]["metadata"])
|
2499
|
-
except Exception:
|
2500
|
-
pass
|
2501
|
-
|
2502
|
-
def thing_update_shadow(self, reported, version):
|
2503
|
-
request = {"state": {"reported": reported}, "method": "update", "version": version}
|
2504
|
-
return self.__thing_update_shadow(request)
|
2505
|
-
|
2506
|
-
def thing_get_shadow(self):
|
2507
|
-
request = {"method": "get"}
|
2508
|
-
return self.__thing_update_shadow(request)
|
2509
|
-
|
2510
|
-
def local_get_latest_shadow(self):
|
2511
|
-
return self.__latest_shadow
|
2512
|
-
|
2513
|
-
def __thing_update_shadow(self, request):
|
2514
|
-
if self.__linkkit_state is not LinkKit.LinkKitState.CONNECTED:
|
2515
|
-
self.__link_log.error("disconnected, update shadow fail")
|
2516
|
-
return LinkKit.ErrorCode.NETWORK_DISCONNECTED.value, None
|
2517
|
-
if not self.__thing_setup_state or not self.__thing_enable_state:
|
2518
|
-
return 1, None
|
2519
|
-
with self.__thing_shadow_mid_lock:
|
2520
|
-
rc, mid = self.__mqtt_client.publish(self.__thing_topic_shadow_update, json.dumps(request), 1)
|
2521
|
-
if rc == mqtt.MQTT_ERR_SUCCESS:
|
2522
|
-
self.__thing_shadow_mid[mid] = self.__timestamp()
|
2523
|
-
return 0, mid
|
2524
|
-
else:
|
2525
|
-
return 1, None
|
2526
|
-
|
2527
|
-
def __on_internal_message(self, client, user_data, message) -> None:
|
2528
|
-
self.__link_log.info("__on_internal_message")
|
2529
|
-
self.__handler_task.post_message(self.__handler_task_cmd_on_message, (client, user_data, message))
|
2530
|
-
# self.__worker_thread.async_post_message(message)
|
2531
|
-
|
2532
|
-
def __handler_task_on_message_callback(self, value) -> None:
|
2533
|
-
client, user_data, message = value
|
2534
|
-
self.__on_internal_async_message(message)
|
2535
|
-
|
2536
|
-
def __on_internal_connect(self, client, user_data, session_flag, rc) -> None:
|
2537
|
-
self.__link_log.info("__on_internal_connect")
|
2538
|
-
if rc == 0:
|
2539
|
-
self.__reset_reconnect_wait()
|
2540
|
-
# self.__upload_device_interface_info()
|
2541
|
-
self.__handler_task.post_message(self.__handler_task_cmd_on_connect, (client, user_data, session_flag, rc))
|
2542
|
-
|
2543
|
-
def __handler_task_on_connect_callback(self, value) -> None:
|
2544
|
-
client, user_data, session_flag, rc = value
|
2545
|
-
self.__link_log.info("__on_internal_connect enter")
|
2546
|
-
self.__link_log.debug("session:%d, return code:%d" % (session_flag["session present"], rc))
|
2547
|
-
if rc == 0:
|
2548
|
-
self.__linkkit_state = LinkKit.LinkKitState.CONNECTED
|
2549
|
-
# self.__worker_thread.start()
|
2550
|
-
if self.__on_connect is not None:
|
2551
|
-
try:
|
2552
|
-
self.__on_connect(session_flag["session present"], rc, self.__user_data)
|
2553
|
-
except Exception as e:
|
2554
|
-
self.__link_log.error("on_connect process raise exception:%r" % e)
|
2555
|
-
if self.__thing_setup_state:
|
2556
|
-
self.__thing_enable_state = True
|
2557
|
-
if self.__on_thing_enable:
|
2558
|
-
self.__on_thing_enable(self.__user_data)
|
2559
|
-
|
2560
|
-
def __on_internal_disconnect(self, client, user_data, rc) -> None:
|
2561
|
-
self.__link_log.info("__on_internal_disconnect enter")
|
2562
|
-
if self.__linkkit_state == LinkKit.LinkKitState.DESTRUCTING:
|
2563
|
-
self.__linkkit_state = LinkKit.LinkKitState.DESTRUCTED
|
2564
|
-
elif (
|
2565
|
-
self.__linkkit_state == LinkKit.LinkKitState.DISCONNECTING
|
2566
|
-
or self.__linkkit_state == LinkKit.LinkKitState.CONNECTED
|
2567
|
-
):
|
2568
|
-
self.__linkkit_state = LinkKit.LinkKitState.DISCONNECTED
|
2569
|
-
elif self.__linkkit_state == LinkKit.LinkKitState.DISCONNECTED:
|
2570
|
-
self.__link_log.error("__on_internal_disconnect enter from wrong state:%r" % self.__linkkit_state)
|
2571
|
-
return
|
2572
|
-
else:
|
2573
|
-
self.__link_log.error("__on_internal_disconnect enter from wrong state:%r" % self.__linkkit_state)
|
2574
|
-
|
2575
|
-
return
|
2576
|
-
self.__user_topics.clear()
|
2577
|
-
self.__user_topics_subscribe_request.clear()
|
2578
|
-
self.__user_topics_unsubscribe_request.clear()
|
2579
|
-
|
2580
|
-
self.__user_rrpc_topics.clear()
|
2581
|
-
self.__user_rrpc_topics_subscribe_request.clear()
|
2582
|
-
self.__user_rrpc_topics_unsubscribe_request.clear()
|
2583
|
-
|
2584
|
-
self.__thing_prop_post_mid.clear()
|
2585
|
-
self.__thing_event_post_mid.clear()
|
2586
|
-
self.__thing_answer_service_mid.clear()
|
2587
|
-
self.__thing_raw_down_reply_mid.clear()
|
2588
|
-
self.__thing_raw_up_mid.clear()
|
2589
|
-
self.__thing_shadow_mid.clear()
|
2590
|
-
self.__device_info_mid.clear()
|
2591
|
-
self.__thing_update_device_info_up_mid.clear()
|
2592
|
-
self.__thing_delete_device_info_up_mid.clear()
|
2593
|
-
self.__handler_task.post_message(self.__handler_task_cmd_on_disconnect, (client, user_data, rc))
|
2594
|
-
if self.__linkkit_state == LinkKit.LinkKitState.DESTRUCTED:
|
2595
|
-
self.__handler_task.stop()
|
2596
|
-
|
2597
|
-
def __handler_task_on_disconnect_callback(self, value) -> None:
|
2598
|
-
self.__link_log.info("__handler_task_on_disconnect_callback enter")
|
2599
|
-
client, user_data, rc = value
|
2600
|
-
if self.__thing_setup_state:
|
2601
|
-
if self.__thing_enable_state:
|
2602
|
-
self.__thing_enable_state = False
|
2603
|
-
if self.__on_thing_disable is not None:
|
2604
|
-
try:
|
2605
|
-
self.__on_thing_disable(self.__user_data)
|
2606
|
-
except Exception as e:
|
2607
|
-
self.__link_log.error("on_thing_disable process raise exception:%r" % e)
|
2608
|
-
if self.__on_disconnect is not None:
|
2609
|
-
try:
|
2610
|
-
self.__on_disconnect(rc, self.__user_data)
|
2611
|
-
except Exception as e:
|
2612
|
-
self.__link_log.error("on_disconnect process raise exception:%r" % e)
|
2613
|
-
|
2614
|
-
def __on_internal_publish(self, client, user_data, mid) -> None:
|
2615
|
-
self.__handler_task.post_message(self.__handler_task_cmd_on_publish, (client, user_data, mid))
|
2616
|
-
|
2617
|
-
def __gateway_add_subdev_topo(self, subdev_array):
|
2618
|
-
request_params = []
|
2619
|
-
for subdev in subdev_array:
|
2620
|
-
ret = self.__validate_subdev_param(subdev, 3)
|
2621
|
-
if ret != 0:
|
2622
|
-
return ret, None
|
2623
|
-
|
2624
|
-
pk = subdev[0]
|
2625
|
-
dn = subdev[1]
|
2626
|
-
ds = subdev[2]
|
2627
|
-
millis = str(self.__timestamp())
|
2628
|
-
client_id = pk + "." + dn
|
2629
|
-
|
2630
|
-
sign_content = "clientId%sdeviceName%sproductKey%stimestamp%s" % (client_id, dn, pk, millis)
|
2631
|
-
sign = hmac.new(ds.encode("utf-8"), sign_content.encode("utf-8"), hashlib.sha256).hexdigest()
|
2632
|
-
params = {
|
2633
|
-
"productKey": pk,
|
2634
|
-
"deviceName": dn,
|
2635
|
-
"clientId": client_id,
|
2636
|
-
"timestamp": millis,
|
2637
|
-
"signmethod": "hmacSha256",
|
2638
|
-
"sign": sign,
|
2639
|
-
}
|
2640
|
-
request_params.append(params)
|
2641
|
-
request_id = self.__get_thing_request_id()
|
2642
|
-
if request_id is None:
|
2643
|
-
return 1, None
|
2644
|
-
request = {
|
2645
|
-
"id": request_id,
|
2646
|
-
"version": "1.0",
|
2647
|
-
"params": request_params,
|
2648
|
-
}
|
2649
|
-
with self.__gateway_add_subdev_topo_mid_lock:
|
2650
|
-
rc, mid = self.__mqtt_client.publish(self.__gateway_topic_add_subdev_topo, json.dumps(request), 1)
|
2651
|
-
if rc == mqtt.MQTT_ERR_SUCCESS:
|
2652
|
-
self.__gateway_add_subdev_topo_mid[mid] = self.__timestamp()
|
2653
|
-
return 0, request_id
|
2654
|
-
else:
|
2655
|
-
return 1, None
|
2656
|
-
|
2657
|
-
def gateway_add_subdev_topo(self, subdev_array):
|
2658
|
-
return self.__gateway_add_subdev_topo(subdev_array)
|
2659
|
-
|
2660
|
-
def __validate_subdev_param(self, subdev, expected_len):
|
2661
|
-
if subdev is None:
|
2662
|
-
return LinkKit.ErrorCode.NULL_SUBDEV_ERR.value
|
2663
|
-
if not isinstance(subdev, list):
|
2664
|
-
return LinkKit.ErrorCode.SUBDEV_NOT_ARRAY_ERR.value
|
2665
|
-
if len(subdev) < expected_len:
|
2666
|
-
self.__link_log.error("input subdev length mismatch")
|
2667
|
-
return LinkKit.ErrorCode.ARRAY_LENGTH_ERR.value
|
2668
|
-
else:
|
2669
|
-
return LinkKit.ErrorCode.SUCCESS.value
|
2670
|
-
|
2671
|
-
def __gateway_delete_subdev_topo(self, subdev_array):
|
2672
|
-
request_params = []
|
2673
|
-
for subdev in subdev_array:
|
2674
|
-
ret = self.__validate_subdev_param(subdev, 2)
|
2675
|
-
if ret != 0:
|
2676
|
-
return ret, None
|
2677
|
-
|
2678
|
-
pk = subdev[0]
|
2679
|
-
dn = subdev[1]
|
2680
|
-
|
2681
|
-
params = {
|
2682
|
-
"productKey": pk,
|
2683
|
-
"deviceName": dn,
|
2684
|
-
}
|
2685
|
-
request_params.append(params)
|
2686
|
-
request_id = self.__get_thing_request_id()
|
2687
|
-
if request_id is None:
|
2688
|
-
return 1, None
|
2689
|
-
request = {
|
2690
|
-
"id": request_id,
|
2691
|
-
"version": "1.0",
|
2692
|
-
"params": request_params,
|
2693
|
-
}
|
2694
|
-
with self.__gateway_delete_subdev_topo_mid_lock:
|
2695
|
-
rc, mid = self.__mqtt_client.publish(self.__gateway_topic_delete_subdev_topo, json.dumps(request), 1)
|
2696
|
-
if rc == mqtt.MQTT_ERR_SUCCESS:
|
2697
|
-
self.__gateway_delete_subdev_topo_mid[mid] = self.__timestamp()
|
2698
|
-
return 0, request_id
|
2699
|
-
else:
|
2700
|
-
return 1, None
|
2701
|
-
|
2702
|
-
def gateway_delete_subdev_topo(self, subdev_array):
|
2703
|
-
return self.__gateway_delete_subdev_topo(subdev_array)
|
2704
|
-
|
2705
|
-
def __gateway_login_subdev(self, subdev_array):
|
2706
|
-
device_list = []
|
2707
|
-
for subdev in subdev_array:
|
2708
|
-
ret = self.__validate_subdev_param(subdev, 3)
|
2709
|
-
if ret != 0:
|
2710
|
-
return ret, None
|
2711
|
-
|
2712
|
-
pk = subdev[0]
|
2713
|
-
dn = subdev[1]
|
2714
|
-
ds = subdev[2]
|
2715
|
-
millis = str(self.__timestamp())
|
2716
|
-
client_id = pk + "." + dn + "|lan=Python,_v=2.2.1,_ss=1|"
|
2717
|
-
|
2718
|
-
sign_content = "clientId%sdeviceName%sproductKey%stimestamp%s" % (client_id, dn, pk, millis)
|
2719
|
-
sign = hmac.new(ds.encode("utf-8"), sign_content.encode("utf-8"), hashlib.sha256).hexdigest()
|
2720
|
-
dev_params = {
|
2721
|
-
"productKey": pk,
|
2722
|
-
"deviceName": dn,
|
2723
|
-
"clientId": client_id,
|
2724
|
-
"timestamp": millis,
|
2725
|
-
"cleanSession": "false",
|
2726
|
-
"sign": sign,
|
2727
|
-
}
|
2728
|
-
device_list.append(dev_params)
|
2729
|
-
request_params = {
|
2730
|
-
"signMethod": "hmacSha256",
|
2731
|
-
"deviceList": device_list,
|
2732
|
-
}
|
2733
|
-
request_id = self.__get_thing_request_id()
|
2734
|
-
if request_id is None:
|
2735
|
-
return 1, None
|
2736
|
-
request = {
|
2737
|
-
"id": request_id,
|
2738
|
-
"version": "1.0",
|
2739
|
-
"params": request_params,
|
2740
|
-
}
|
2741
|
-
rc, mid = self.__mqtt_client.publish(self.__gateway_topic_login_subdev, json.dumps(request), 0)
|
2742
|
-
if rc == mqtt.MQTT_ERR_SUCCESS:
|
2743
|
-
return 0, request_id
|
2744
|
-
else:
|
2745
|
-
return 1, None
|
2746
|
-
|
2747
|
-
def gateway_login_subdev(self, subdev_array):
|
2748
|
-
return self.__gateway_login_subdev(subdev_array)
|
2749
|
-
|
2750
|
-
def gateway_logout_subdev(self, subdev_array):
|
2751
|
-
return self.__gateway_logout_subdev(subdev_array)
|
2752
|
-
|
2753
|
-
def __gateway_logout_subdev(self, subdev_array):
|
2754
|
-
request_params = []
|
2755
|
-
for subdev in subdev_array:
|
2756
|
-
ret = self.__validate_subdev_param(subdev, 2)
|
2757
|
-
if ret != 0:
|
2758
|
-
return ret, None
|
2759
|
-
|
2760
|
-
pk = subdev[0]
|
2761
|
-
dn = subdev[1]
|
2762
|
-
|
2763
|
-
params = {
|
2764
|
-
"productKey": pk,
|
2765
|
-
"deviceName": dn,
|
2766
|
-
}
|
2767
|
-
request_params.append(params)
|
2768
|
-
request_id = self.__get_thing_request_id()
|
2769
|
-
if request_id is None:
|
2770
|
-
return 1, None
|
2771
|
-
request = {
|
2772
|
-
"id": request_id,
|
2773
|
-
"version": "1.0",
|
2774
|
-
"params": request_params,
|
2775
|
-
}
|
2776
|
-
rc, mid = self.__mqtt_client.publish(self.__gateway_topic_logout_subdev, json.dumps(request), 0)
|
2777
|
-
if rc == mqtt.MQTT_ERR_SUCCESS:
|
2778
|
-
return 0, request_id
|
2779
|
-
else:
|
2780
|
-
return 1, None
|
2781
|
-
|
2782
|
-
def __gateway_register_subdev(self, subdev_array):
|
2783
|
-
request_params = []
|
2784
|
-
for subdev in subdev_array:
|
2785
|
-
ret = self.__validate_subdev_param(subdev, 2)
|
2786
|
-
if ret != 0:
|
2787
|
-
return ret, None
|
2788
|
-
|
2789
|
-
pk = subdev[0]
|
2790
|
-
dn = subdev[1]
|
2791
|
-
|
2792
|
-
params = {
|
2793
|
-
"productKey": pk,
|
2794
|
-
"deviceName": dn,
|
2795
|
-
}
|
2796
|
-
request_params.append(params)
|
2797
|
-
request_id = self.__get_thing_request_id()
|
2798
|
-
if request_id is None:
|
2799
|
-
return 1, None
|
2800
|
-
request = {
|
2801
|
-
"id": request_id,
|
2802
|
-
"version": "1.0",
|
2803
|
-
"params": request_params,
|
2804
|
-
}
|
2805
|
-
rc, mid = self.__mqtt_client.publish(self.__gateway_topic_register_subdev, json.dumps(request), 0)
|
2806
|
-
if rc == mqtt.MQTT_ERR_SUCCESS:
|
2807
|
-
return 0, request_id
|
2808
|
-
else:
|
2809
|
-
return 1, None
|
2810
|
-
|
2811
|
-
def gateway_register_subdev(self, subdev_array):
|
2812
|
-
return self.__gateway_register_subdev(subdev_array)
|
2813
|
-
|
2814
|
-
def gateway_product_register_subdev(self, subdev_array):
|
2815
|
-
return self.__gateway_product_register_subdev(subdev_array)
|
2816
|
-
|
2817
|
-
def __gateway_product_register_subdev(self, subdev_array):
|
2818
|
-
device_list = []
|
2819
|
-
for subdev in subdev_array:
|
2820
|
-
ret = self.__validate_subdev_param(subdev, 3)
|
2821
|
-
if ret != 0:
|
2822
|
-
return ret, None
|
2823
|
-
|
2824
|
-
pk = subdev[0]
|
2825
|
-
dn = subdev[1]
|
2826
|
-
ps = subdev[2]
|
2827
|
-
random_str = self.__generate_random_str(15)
|
2828
|
-
|
2829
|
-
sign_content = "deviceName%sproductKey%srandom%s" % (dn, pk, random_str)
|
2830
|
-
sign = hmac.new(ps.encode("utf-8"), sign_content.encode("utf-8"), hashlib.sha256).hexdigest()
|
2831
|
-
dev_params = {
|
2832
|
-
"productKey": pk,
|
2833
|
-
"deviceName": dn,
|
2834
|
-
"random": random_str,
|
2835
|
-
"signMethod": "hmacSha256",
|
2836
|
-
"sign": sign,
|
2837
|
-
}
|
2838
|
-
device_list.append(dev_params)
|
2839
|
-
request_params = {
|
2840
|
-
"proxieds": device_list,
|
2841
|
-
}
|
2842
|
-
request_id = self.__get_thing_request_id()
|
2843
|
-
if request_id is None:
|
2844
|
-
return 1, None
|
2845
|
-
request = {
|
2846
|
-
"id": request_id,
|
2847
|
-
"version": "1.0",
|
2848
|
-
"params": request_params,
|
2849
|
-
}
|
2850
|
-
rc, mid = self.__mqtt_client.publish(self.__gateway_topic_product_register_subdev, json.dumps(request), 0)
|
2851
|
-
if rc == mqtt.MQTT_ERR_SUCCESS:
|
2852
|
-
self.__link_log.debug("mid for product dynamic register:%d" % mid)
|
2853
|
-
return 0, request_id
|
2854
|
-
else:
|
2855
|
-
return 1, None
|
2856
|
-
|
2857
|
-
def __handler_task_on_publish_callback(self, value) -> None:
|
2858
|
-
client, user_data, mid = value
|
2859
|
-
self.__link_log.debug("__on_internal_publish message:%d" % mid)
|
2860
|
-
with self.__thing_event_post_mid_lock:
|
2861
|
-
if mid in self.__thing_event_post_mid:
|
2862
|
-
self.__thing_event_post_mid.pop(mid)
|
2863
|
-
self.__link_log.debug("__on_internal_publish event post mid removed")
|
2864
|
-
return
|
2865
|
-
with self.__thing_prop_post_mid_lock:
|
2866
|
-
if mid in self.__thing_prop_post_mid:
|
2867
|
-
self.__thing_prop_post_mid.pop(mid)
|
2868
|
-
self.__link_log.debug("__on_internal_publish prop post mid removed")
|
2869
|
-
return
|
2870
|
-
with self.__thing_prop_set_reply_mid_lock:
|
2871
|
-
if mid in self.__thing_prop_set_reply_mid:
|
2872
|
-
self.__thing_prop_set_reply_mid.pop(mid)
|
2873
|
-
self.__link_log.debug("__on_internal_publish prop set reply mid removed")
|
2874
|
-
return
|
2875
|
-
with self.__thing_answer_service_mid_lock:
|
2876
|
-
if mid in self.__thing_answer_service_mid:
|
2877
|
-
self.__thing_answer_service_mid.pop(mid)
|
2878
|
-
self.__link_log.debug("__thing_answer_service_mid mid removed")
|
2879
|
-
return
|
2880
|
-
with self.__thing_raw_up_mid_lock:
|
2881
|
-
if mid in self.__thing_raw_up_mid:
|
2882
|
-
self.__thing_raw_up_mid.pop(mid)
|
2883
|
-
self.__link_log.debug("__thing_raw_up_mid mid removed")
|
2884
|
-
return
|
2885
|
-
with self.__thing_raw_down_reply_mid_lock:
|
2886
|
-
if mid in self.__thing_raw_down_reply_mid:
|
2887
|
-
self.__thing_raw_down_reply_mid.pop(mid)
|
2888
|
-
self.__link_log.debug("__thing_raw_down_reply_mid mid removed")
|
2889
|
-
return
|
2890
|
-
with self.__device_info_mid_lock:
|
2891
|
-
if mid in self.__device_info_mid:
|
2892
|
-
self.__device_info_mid.pop(mid)
|
2893
|
-
self.__link_log.debug("__device_info_mid mid removed")
|
2894
|
-
return
|
2895
|
-
with self.__thing_shadow_mid_lock:
|
2896
|
-
if mid in self.__thing_shadow_mid:
|
2897
|
-
self.__thing_shadow_mid.pop(mid)
|
2898
|
-
self.__link_log.debug("__thing_shadow_mid mid removed")
|
2899
|
-
return
|
2900
|
-
with self.__thing_update_device_info_up_mid_lock:
|
2901
|
-
if mid in self.__thing_update_device_info_up_mid:
|
2902
|
-
self.__thing_update_device_info_up_mid.pop(mid)
|
2903
|
-
self.__link_log.debug("__thing_update_device_info_up_mid mid removed")
|
2904
|
-
return
|
2905
|
-
with self.__thing_delete_device_info_up_mid_lock:
|
2906
|
-
if mid in self.__thing_delete_device_info_up_mid:
|
2907
|
-
self.__thing_delete_device_info_up_mid.pop(mid)
|
2908
|
-
self.__link_log.debug("__thing_delete_device_info_up_mid mid removed")
|
2909
|
-
return
|
2910
|
-
with self.__gateway_add_subdev_topo_mid_lock:
|
2911
|
-
if mid in self.__gateway_add_subdev_topo_mid:
|
2912
|
-
self.__gateway_add_subdev_topo_mid.pop(mid)
|
2913
|
-
self.__link_log.debug("__gateway_add_subdev_topo_mid removed")
|
2914
|
-
return
|
2915
|
-
with self.__gateway_delete_subdev_topo_mid_lock:
|
2916
|
-
if mid in self.__gateway_delete_subdev_topo_mid:
|
2917
|
-
self.__gateway_delete_subdev_topo_mid.pop(mid)
|
2918
|
-
self.__link_log.debug("__gateway_delete_subdev_topo_mid removed")
|
2919
|
-
return
|
2920
|
-
if self.__on_publish_topic is not None:
|
2921
|
-
self.__on_publish_topic(mid, self.__user_data)
|
2922
|
-
|
2923
|
-
def __on_internal_subscribe(self, client, user_data, mid, granted_qos) -> None:
|
2924
|
-
self.__handler_task.post_message(self.__handler_task_cmd_on_subscribe, (client, user_data, mid, granted_qos))
|
2925
|
-
|
2926
|
-
def __handler_task_on_subscribe_callback(self, value) -> None:
|
2927
|
-
client, user_data, mid, granted_qos = value
|
2928
|
-
self.__link_log.debug(
|
2929
|
-
"__on_internal_subscribe mid:%d granted_qos:%s" % (mid, str(",".join("%s" % it for it in granted_qos)))
|
2930
|
-
)
|
2931
|
-
# try to read rrpc
|
2932
|
-
with self.__user_rrpc_topics_subscribe_request_lock:
|
2933
|
-
if mid in self.__user_rrpc_topics_subscribe_request:
|
2934
|
-
self.__user_rrpc_topics_subscribe_request.pop(mid)
|
2935
|
-
if self.__on_subscribe_rrpc_topic:
|
2936
|
-
try:
|
2937
|
-
self.__on_subscribe_rrpc_topic(mid, granted_qos, self.__user_data)
|
2938
|
-
except Exception as err:
|
2939
|
-
self.__link_log.error("Caught exception in on_subscribe_topic: %s", err)
|
2940
|
-
return
|
2941
|
-
|
2942
|
-
# try to read other topic
|
2943
|
-
topics_requests = None
|
2944
|
-
self.__user_topics_request_lock.acquire()
|
2945
|
-
if mid in self.__user_topics_subscribe_request:
|
2946
|
-
topics_requests = self.__user_topics_subscribe_request.pop(mid)
|
2947
|
-
self.__user_topics_request_lock.release()
|
2948
|
-
if topics_requests is not None:
|
2949
|
-
return_topics = []
|
2950
|
-
for index in range(len(topics_requests)):
|
2951
|
-
if granted_qos[index] < 0 or granted_qos[index] > 1:
|
2952
|
-
self.__link_log.error("topics:%s, granted wrong:%d" % (topics_requests[index], granted_qos[index]))
|
2953
|
-
else:
|
2954
|
-
self.__user_topics[topics_requests[index][0]] = granted_qos[index]
|
2955
|
-
return_topics.append((topics_requests[index], granted_qos[index]))
|
2956
|
-
if self.__on_subscribe_topic is not None:
|
2957
|
-
try:
|
2958
|
-
self.__on_subscribe_topic(mid, granted_qos, self.__user_data)
|
2959
|
-
except Exception as err:
|
2960
|
-
self.__link_log.error("Caught exception in on_subscribe_topic: %s", err)
|
2961
|
-
|
2962
|
-
def __on_internal_unsubscribe(self, client, user_data, mid) -> None:
|
2963
|
-
self.__handler_task.post_message(self.__handler_task_cmd_on_unsubscribe, (client, user_data, mid))
|
2964
|
-
|
2965
|
-
def __handler_task_on_unsubscribe_callback(self, value) -> None:
|
2966
|
-
client, user_data, mid = value
|
2967
|
-
self.__link_log.debug("__on_internal_unsubscribe mid:%d" % mid)
|
2968
|
-
unsubscribe_request = None
|
2969
|
-
# try to read rrpc
|
2970
|
-
with self.__user_rrpc_topics_unsubscribe_request_lock:
|
2971
|
-
if mid in self.__user_rrpc_topics_unsubscribe_request:
|
2972
|
-
self.__user_rrpc_topics_unsubscribe_request.pop(mid)
|
2973
|
-
if self.__on_unsubscribe_rrpc_topic:
|
2974
|
-
try:
|
2975
|
-
self.__on_unsubscribe_rrpc_topic(mid, self.__user_data)
|
2976
|
-
except Exception as err:
|
2977
|
-
self.__link_log.error("Caught exception in on_unsubscribe_rrpc_topic: %s", err)
|
2978
|
-
return
|
2979
|
-
|
2980
|
-
with self.__user_topics_unsubscribe_request_lock:
|
2981
|
-
if mid in self.__user_topics_unsubscribe_request:
|
2982
|
-
unsubscribe_request = self.__user_topics_unsubscribe_request.pop(mid)
|
2983
|
-
if unsubscribe_request is not None:
|
2984
|
-
for t in unsubscribe_request:
|
2985
|
-
self.__link_log.debug("__user_topics:%s" % str(self.__user_topics))
|
2986
|
-
try:
|
2987
|
-
self.__user_topics.pop(t)
|
2988
|
-
except Exception as e:
|
2989
|
-
self.__link_log.error("__on_internal_unsubscribe e:" + str(e))
|
2990
|
-
return
|
2991
|
-
if self.__on_unsubscribe_topic is not None:
|
2992
|
-
try:
|
2993
|
-
self.__on_unsubscribe_topic(mid, self.__user_data)
|
2994
|
-
except Exception as err:
|
2995
|
-
self.__link_log.error("Caught exception in on_unsubscribe_topic: %s", err)
|
2996
|
-
|
2997
|
-
def dump_user_topics(self):
|
2998
|
-
return self.__user_topics
|
2999
|
-
|
3000
|
-
def force_reconnect(self) -> None:
|
3001
|
-
self.__link_log.error("force reconnecting")
|
3002
|
-
self.__force_reconnect = True
|
3003
|
-
|
3004
|
-
@staticmethod
|
3005
|
-
def to_user_topic(topic):
|
3006
|
-
topic_section = topic.split("/", 3)
|
3007
|
-
user_topic = topic_section[3]
|
3008
|
-
return user_topic
|
3009
|
-
|
3010
|
-
def to_full_topic(self, topic):
|
3011
|
-
return self.__USER_TOPIC_PREFIX % (self.__product_key, self.__device_name, topic)
|
3012
|
-
|
3013
|
-
def __is_valid_str(self, user_str) -> bool:
|
3014
|
-
if user_str is None or user_str == "":
|
3015
|
-
return False
|
3016
|
-
return True
|
3017
|
-
|
3018
|
-
@staticmethod
|
3019
|
-
def __timestamp():
|
3020
|
-
return int(time.time() * 1000)
|