pymammotion 0.5.69__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/__init__.py +53 -0
- pymammotion/agora/__init__.py +0 -0
- pymammotion/agora/agora_api.py +755 -0
- pymammotion/agora/agora_rtc_capabilities.py +748 -0
- pymammotion/agora/agora_websockets.py +1175 -0
- pymammotion/aliyun/__init__.py +1 -0
- pymammotion/aliyun/client.py +235 -0
- pymammotion/aliyun/cloud_gateway.py +982 -0
- pymammotion/aliyun/model/aep_response.py +21 -0
- pymammotion/aliyun/model/connect_response.py +51 -0
- pymammotion/aliyun/model/dev_by_account_response.py +195 -0
- pymammotion/aliyun/model/login_by_oauth_response.py +64 -0
- pymammotion/aliyun/model/regions_response.py +29 -0
- pymammotion/aliyun/model/session_by_authcode_response.py +19 -0
- pymammotion/aliyun/model/thing_response.py +12 -0
- pymammotion/aliyun/regions.py +62 -0
- pymammotion/aliyun/tea/core.py +297 -0
- pymammotion/aliyun/tmp_constant.py +171 -0
- pymammotion/bluetooth/__init__.py +1 -0
- pymammotion/bluetooth/ble.py +62 -0
- pymammotion/bluetooth/ble_message.py +676 -0
- pymammotion/bluetooth/const.py +27 -0
- pymammotion/bluetooth/data/__init__.py +0 -0
- pymammotion/bluetooth/data/convert.py +25 -0
- pymammotion/bluetooth/data/framectrldata.py +40 -0
- pymammotion/bluetooth/data/notifydata.py +62 -0
- pymammotion/bluetooth/model/__init__.py +0 -0
- pymammotion/bluetooth/model/atomic_integer.py +54 -0
- pymammotion/const.py +13 -0
- pymammotion/data/__init__.py +0 -0
- pymammotion/data/model/__init__.py +8 -0
- pymammotion/data/model/account.py +8 -0
- pymammotion/data/model/device.py +192 -0
- pymammotion/data/model/device_config.py +72 -0
- pymammotion/data/model/device_info.py +60 -0
- pymammotion/data/model/device_limits.py +49 -0
- pymammotion/data/model/enums.py +77 -0
- pymammotion/data/model/errors.py +12 -0
- pymammotion/data/model/events.py +14 -0
- pymammotion/data/model/generate_geojson.py +565 -0
- pymammotion/data/model/generate_route_information.py +26 -0
- pymammotion/data/model/hash_list.py +475 -0
- pymammotion/data/model/location.py +36 -0
- pymammotion/data/model/mowing_modes.py +77 -0
- pymammotion/data/model/rapid_state.py +45 -0
- pymammotion/data/model/raw_data.py +215 -0
- pymammotion/data/model/region_data.py +102 -0
- pymammotion/data/model/report_info.py +182 -0
- pymammotion/data/model/work.py +27 -0
- pymammotion/data/mower_state_manager.py +369 -0
- pymammotion/data/mqtt/__init__.py +1 -0
- pymammotion/data/mqtt/event.py +227 -0
- pymammotion/data/mqtt/mammotion_properties.py +276 -0
- pymammotion/data/mqtt/properties.py +203 -0
- pymammotion/data/mqtt/status.py +57 -0
- pymammotion/event/__init__.py +6 -0
- pymammotion/event/event.py +96 -0
- pymammotion/homeassistant/__init__.py +3 -0
- pymammotion/homeassistant/mower_api.py +514 -0
- pymammotion/homeassistant/rtk_api.py +54 -0
- pymammotion/http/__init__.py +0 -0
- pymammotion/http/encryption.py +220 -0
- pymammotion/http/http.py +673 -0
- pymammotion/http/model/__init__.py +0 -0
- pymammotion/http/model/camera_stream.py +31 -0
- pymammotion/http/model/http.py +249 -0
- pymammotion/http/model/response_factory.py +61 -0
- pymammotion/http/model/rtk.py +16 -0
- pymammotion/mammotion/__init__.py +0 -0
- pymammotion/mammotion/commands/__init__.py +0 -0
- pymammotion/mammotion/commands/abstract_message.py +24 -0
- pymammotion/mammotion/commands/mammotion_command.py +81 -0
- pymammotion/mammotion/commands/messages/__init__.py +0 -0
- pymammotion/mammotion/commands/messages/basestation.py +43 -0
- pymammotion/mammotion/commands/messages/driver.py +122 -0
- pymammotion/mammotion/commands/messages/media.py +87 -0
- pymammotion/mammotion/commands/messages/navigation.py +564 -0
- pymammotion/mammotion/commands/messages/network.py +205 -0
- pymammotion/mammotion/commands/messages/ota.py +38 -0
- pymammotion/mammotion/commands/messages/system.py +330 -0
- pymammotion/mammotion/commands/messages/video.py +33 -0
- pymammotion/mammotion/control/__init__.py +0 -0
- pymammotion/mammotion/control/joystick.py +145 -0
- pymammotion/mammotion/devices/__init__.py +29 -0
- pymammotion/mammotion/devices/base.py +163 -0
- pymammotion/mammotion/devices/mammotion.py +571 -0
- pymammotion/mammotion/devices/mammotion_bluetooth.py +496 -0
- pymammotion/mammotion/devices/mammotion_cloud.py +355 -0
- pymammotion/mammotion/devices/mammotion_mower_ble.py +48 -0
- pymammotion/mammotion/devices/mammotion_mower_cloud.py +39 -0
- pymammotion/mammotion/devices/managers/managers.py +81 -0
- pymammotion/mammotion/devices/mower_device.py +120 -0
- pymammotion/mammotion/devices/mower_manager.py +107 -0
- pymammotion/mammotion/devices/rtk_ble.py +89 -0
- pymammotion/mammotion/devices/rtk_cloud.py +115 -0
- pymammotion/mammotion/devices/rtk_device.py +50 -0
- pymammotion/mammotion/devices/rtk_manager.py +125 -0
- pymammotion/mqtt/__init__.py +6 -0
- pymammotion/mqtt/aliyun_mqtt.py +237 -0
- pymammotion/mqtt/linkkit/__init__.py +5 -0
- pymammotion/mqtt/linkkit/h2client.py +585 -0
- pymammotion/mqtt/linkkit/linkkit.py +3025 -0
- pymammotion/mqtt/mammotion_future.py +26 -0
- pymammotion/mqtt/mammotion_mqtt.py +214 -0
- pymammotion/mqtt/mqtt_models.py +66 -0
- pymammotion/proto/__init__.py +4841 -0
- pymammotion/proto/basestation.proto +51 -0
- pymammotion/proto/basestation_pb2.py +35 -0
- pymammotion/proto/basestation_pb2.pyi +89 -0
- pymammotion/proto/common.proto +7 -0
- pymammotion/proto/common_pb2.py +25 -0
- pymammotion/proto/common_pb2.pyi +13 -0
- pymammotion/proto/dev_net.proto +321 -0
- pymammotion/proto/dev_net_pb2.py +111 -0
- pymammotion/proto/dev_net_pb2.pyi +515 -0
- pymammotion/proto/luba_msg.proto +76 -0
- pymammotion/proto/luba_msg_pb2.py +41 -0
- pymammotion/proto/luba_msg_pb2.pyi +97 -0
- pymammotion/proto/luba_mul.proto +129 -0
- pymammotion/proto/luba_mul_pb2.py +61 -0
- pymammotion/proto/luba_mul_pb2.pyi +178 -0
- pymammotion/proto/mctrl_driver.proto +107 -0
- pymammotion/proto/mctrl_driver_pb2.py +57 -0
- pymammotion/proto/mctrl_driver_pb2.pyi +167 -0
- pymammotion/proto/mctrl_nav.proto +591 -0
- pymammotion/proto/mctrl_nav_pb2.py +136 -0
- pymammotion/proto/mctrl_nav_pb2.pyi +1067 -0
- pymammotion/proto/mctrl_ota.proto +80 -0
- pymammotion/proto/mctrl_ota_pb2.py +45 -0
- pymammotion/proto/mctrl_ota_pb2.pyi +128 -0
- pymammotion/proto/mctrl_pept.proto +34 -0
- pymammotion/proto/mctrl_pept_pb2.py +33 -0
- pymammotion/proto/mctrl_pept_pb2.pyi +58 -0
- pymammotion/proto/mctrl_sys.proto +741 -0
- pymammotion/proto/mctrl_sys_pb2.py +206 -0
- pymammotion/proto/mctrl_sys_pb2.pyi +1213 -0
- pymammotion/proto/message_pool.py +3 -0
- pymammotion/proto/py.typed +0 -0
- pymammotion/py.typed +0 -0
- pymammotion/utility/constant/__init__.py +3 -0
- pymammotion/utility/constant/device_constant.py +315 -0
- pymammotion/utility/conversions.py +5 -0
- pymammotion/utility/datatype_converter.py +124 -0
- pymammotion/utility/device_config.py +755 -0
- pymammotion/utility/device_type.py +489 -0
- pymammotion/utility/map.py +259 -0
- pymammotion/utility/movement.py +18 -0
- pymammotion/utility/mur_mur_hash.py +159 -0
- pymammotion/utility/periodic.py +106 -0
- pymammotion/utility/rocker_util.py +194 -0
- pymammotion-0.5.69.dist-info/METADATA +93 -0
- pymammotion-0.5.69.dist-info/RECORD +154 -0
- pymammotion-0.5.69.dist-info/WHEEL +4 -0
- pymammotion-0.5.69.dist-info/licenses/LICENSE +674 -0
|
@@ -0,0 +1,676 @@
|
|
|
1
|
+
from asyncio import sleep
|
|
2
|
+
from io import BytesIO
|
|
3
|
+
import json
|
|
4
|
+
import logging
|
|
5
|
+
import queue
|
|
6
|
+
import sys
|
|
7
|
+
import time
|
|
8
|
+
|
|
9
|
+
from bleak import BleakClient
|
|
10
|
+
|
|
11
|
+
from pymammotion.aliyun.tmp_constant import tmp_constant
|
|
12
|
+
from pymammotion.bluetooth.const import UUID_WRITE_CHARACTERISTIC
|
|
13
|
+
from pymammotion.bluetooth.data.framectrldata import FrameCtrlData
|
|
14
|
+
from pymammotion.bluetooth.data.notifydata import BlufiNotifyData
|
|
15
|
+
from pymammotion.bluetooth.model.atomic_integer import AtomicInteger
|
|
16
|
+
from pymammotion.proto import DevNet, DrvDevInfoReq, LubaMsg, MsgAttr, MsgCmdType, MsgDevice
|
|
17
|
+
from pymammotion.utility.constant.device_constant import bleOrderCmd
|
|
18
|
+
|
|
19
|
+
_LOGGER = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
CRC_TB = [
|
|
22
|
+
0x0000,
|
|
23
|
+
0x1021,
|
|
24
|
+
0x2042,
|
|
25
|
+
0x3063,
|
|
26
|
+
0x4084,
|
|
27
|
+
0x50A5,
|
|
28
|
+
0x60C6,
|
|
29
|
+
0x70E7,
|
|
30
|
+
0x8108,
|
|
31
|
+
0x9129,
|
|
32
|
+
0xA14A,
|
|
33
|
+
0xB16B,
|
|
34
|
+
0xC18C,
|
|
35
|
+
0xD1AD,
|
|
36
|
+
0xE1CE,
|
|
37
|
+
0xF1EF,
|
|
38
|
+
0x1231,
|
|
39
|
+
0x0210,
|
|
40
|
+
0x3273,
|
|
41
|
+
0x2252,
|
|
42
|
+
0x52B5,
|
|
43
|
+
0x4294,
|
|
44
|
+
0x72F7,
|
|
45
|
+
0x62D6,
|
|
46
|
+
0x9339,
|
|
47
|
+
0x8318,
|
|
48
|
+
0xB37B,
|
|
49
|
+
0xA35A,
|
|
50
|
+
0xD3BD,
|
|
51
|
+
0xC39C,
|
|
52
|
+
0xF3FF,
|
|
53
|
+
0xE3DE,
|
|
54
|
+
0x2462,
|
|
55
|
+
0x3443,
|
|
56
|
+
0x0420,
|
|
57
|
+
0x1401,
|
|
58
|
+
0x64E6,
|
|
59
|
+
0x74C7,
|
|
60
|
+
0x44A4,
|
|
61
|
+
0x5485,
|
|
62
|
+
0xA56A,
|
|
63
|
+
0xB54B,
|
|
64
|
+
0x8528,
|
|
65
|
+
0x9509,
|
|
66
|
+
0xE5EE,
|
|
67
|
+
0xF5CF,
|
|
68
|
+
0xC5AC,
|
|
69
|
+
0xD58D,
|
|
70
|
+
0x3653,
|
|
71
|
+
0x2672,
|
|
72
|
+
0x1611,
|
|
73
|
+
0x0630,
|
|
74
|
+
0x76D7,
|
|
75
|
+
0x66F6,
|
|
76
|
+
0x5695,
|
|
77
|
+
0x46B4,
|
|
78
|
+
0xB75B,
|
|
79
|
+
0xA77A,
|
|
80
|
+
0x9719,
|
|
81
|
+
0x8738,
|
|
82
|
+
0xF7DF,
|
|
83
|
+
0xE7FE,
|
|
84
|
+
0xD79D,
|
|
85
|
+
0xC7BC,
|
|
86
|
+
0x48C4,
|
|
87
|
+
0x58E5,
|
|
88
|
+
0x6886,
|
|
89
|
+
0x78A7,
|
|
90
|
+
0x0840,
|
|
91
|
+
0x1861,
|
|
92
|
+
0x2802,
|
|
93
|
+
0x3823,
|
|
94
|
+
0xC9CC,
|
|
95
|
+
0xD9ED,
|
|
96
|
+
0xE98E,
|
|
97
|
+
0xF9AF,
|
|
98
|
+
0x8948,
|
|
99
|
+
0x9969,
|
|
100
|
+
0xA90A,
|
|
101
|
+
0xB92B,
|
|
102
|
+
0x5AF5,
|
|
103
|
+
0x4AD4,
|
|
104
|
+
0x7AB7,
|
|
105
|
+
0x6A96,
|
|
106
|
+
0x1A71,
|
|
107
|
+
0x0A50,
|
|
108
|
+
0x3A33,
|
|
109
|
+
0x2A12,
|
|
110
|
+
0xDBFD,
|
|
111
|
+
0xCBDC,
|
|
112
|
+
0xFBBF,
|
|
113
|
+
0xEB9E,
|
|
114
|
+
0x9B79,
|
|
115
|
+
0x8B58,
|
|
116
|
+
0xBB3B,
|
|
117
|
+
0xAB1A,
|
|
118
|
+
0x6CA6,
|
|
119
|
+
0x7C87,
|
|
120
|
+
0x4CE4,
|
|
121
|
+
0x5CC5,
|
|
122
|
+
0x2C22,
|
|
123
|
+
0x3C03,
|
|
124
|
+
0x0C60,
|
|
125
|
+
0x1C41,
|
|
126
|
+
0xEDAE,
|
|
127
|
+
0xFD8F,
|
|
128
|
+
0xCDEC,
|
|
129
|
+
0xDDCD,
|
|
130
|
+
0xAD2A,
|
|
131
|
+
0xBD0B,
|
|
132
|
+
0x8D68,
|
|
133
|
+
0x9D49,
|
|
134
|
+
0x7E97,
|
|
135
|
+
0x6EB6,
|
|
136
|
+
0x5ED5,
|
|
137
|
+
0x4EF4,
|
|
138
|
+
0x3E13,
|
|
139
|
+
0x2E32,
|
|
140
|
+
0x1E51,
|
|
141
|
+
0x0E70,
|
|
142
|
+
0xFF9F,
|
|
143
|
+
0xEFBE,
|
|
144
|
+
0xDFDD,
|
|
145
|
+
0xCFFC,
|
|
146
|
+
0xBF1B,
|
|
147
|
+
0xAF3A,
|
|
148
|
+
0x9F59,
|
|
149
|
+
0x8F78,
|
|
150
|
+
0x9188,
|
|
151
|
+
0x81A9,
|
|
152
|
+
0xB1CA,
|
|
153
|
+
0xA1EB,
|
|
154
|
+
0xD10C,
|
|
155
|
+
0xC12D,
|
|
156
|
+
0xF14E,
|
|
157
|
+
0xE16F,
|
|
158
|
+
0x1080,
|
|
159
|
+
0x00A1,
|
|
160
|
+
0x30C2,
|
|
161
|
+
0x20E3,
|
|
162
|
+
0x5004,
|
|
163
|
+
0x4025,
|
|
164
|
+
0x7046,
|
|
165
|
+
0x6067,
|
|
166
|
+
0x83B9,
|
|
167
|
+
0x9398,
|
|
168
|
+
0xA3FB,
|
|
169
|
+
0xB3DA,
|
|
170
|
+
0xC33D,
|
|
171
|
+
0xD31C,
|
|
172
|
+
0xE37F,
|
|
173
|
+
0xF35E,
|
|
174
|
+
0x02B1,
|
|
175
|
+
0x1290,
|
|
176
|
+
0x22F3,
|
|
177
|
+
0x32D2,
|
|
178
|
+
0x4235,
|
|
179
|
+
0x5214,
|
|
180
|
+
0x6277,
|
|
181
|
+
0x7256,
|
|
182
|
+
0xB5EA,
|
|
183
|
+
0xA5CB,
|
|
184
|
+
0x95A8,
|
|
185
|
+
0x8589,
|
|
186
|
+
0xF56E,
|
|
187
|
+
0xE54F,
|
|
188
|
+
0xD52C,
|
|
189
|
+
0xC50D,
|
|
190
|
+
0x34E2,
|
|
191
|
+
0x24C3,
|
|
192
|
+
0x14A0,
|
|
193
|
+
0x0481,
|
|
194
|
+
0x7466,
|
|
195
|
+
0x6447,
|
|
196
|
+
0x5424,
|
|
197
|
+
0x4405,
|
|
198
|
+
0xA7DB,
|
|
199
|
+
0xB7FA,
|
|
200
|
+
0x8799,
|
|
201
|
+
0x97B8,
|
|
202
|
+
0xE75F,
|
|
203
|
+
0xF77E,
|
|
204
|
+
0xC71D,
|
|
205
|
+
0xD73C,
|
|
206
|
+
0x26D3,
|
|
207
|
+
0x36F2,
|
|
208
|
+
0x0691,
|
|
209
|
+
0x16B0,
|
|
210
|
+
0x6657,
|
|
211
|
+
0x7676,
|
|
212
|
+
0x4615,
|
|
213
|
+
0x5634,
|
|
214
|
+
0xD94C,
|
|
215
|
+
0xC96D,
|
|
216
|
+
0xF90E,
|
|
217
|
+
0xE92F,
|
|
218
|
+
0x99C8,
|
|
219
|
+
0x89E9,
|
|
220
|
+
0xB98A,
|
|
221
|
+
0xA9AB,
|
|
222
|
+
0x5844,
|
|
223
|
+
0x4865,
|
|
224
|
+
0x7806,
|
|
225
|
+
0x6827,
|
|
226
|
+
0x18C0,
|
|
227
|
+
0x08E1,
|
|
228
|
+
0x3882,
|
|
229
|
+
0x28A3,
|
|
230
|
+
0xCB7D,
|
|
231
|
+
0xDB5C,
|
|
232
|
+
0xEB3F,
|
|
233
|
+
0xFB1E,
|
|
234
|
+
0x8BF9,
|
|
235
|
+
0x9BD8,
|
|
236
|
+
0xABBB,
|
|
237
|
+
0xBB9A,
|
|
238
|
+
0x4A75,
|
|
239
|
+
0x5A54,
|
|
240
|
+
0x6A37,
|
|
241
|
+
0x7A16,
|
|
242
|
+
0x0AF1,
|
|
243
|
+
0x1AD0,
|
|
244
|
+
0x2AB3,
|
|
245
|
+
0x3A92,
|
|
246
|
+
0xFD2E,
|
|
247
|
+
0xED0F,
|
|
248
|
+
0xDD6C,
|
|
249
|
+
0xCD4D,
|
|
250
|
+
0xBDAA,
|
|
251
|
+
0xAD8B,
|
|
252
|
+
0x9DE8,
|
|
253
|
+
0x8DC9,
|
|
254
|
+
0x7C26,
|
|
255
|
+
0x6C07,
|
|
256
|
+
0x5C64,
|
|
257
|
+
0x4C45,
|
|
258
|
+
0x3CA2,
|
|
259
|
+
0x2C83,
|
|
260
|
+
0x1CE0,
|
|
261
|
+
0x0CC1,
|
|
262
|
+
0xEF1F,
|
|
263
|
+
0xFF3E,
|
|
264
|
+
0xCF5D,
|
|
265
|
+
0xDF7C,
|
|
266
|
+
0xAF9B,
|
|
267
|
+
0xBFBA,
|
|
268
|
+
0x8FD9,
|
|
269
|
+
0x9FF8,
|
|
270
|
+
0x6E17,
|
|
271
|
+
0x7E36,
|
|
272
|
+
0x4E55,
|
|
273
|
+
0x5E74,
|
|
274
|
+
0x2E93,
|
|
275
|
+
0x3EB2,
|
|
276
|
+
0x0ED1,
|
|
277
|
+
0x1EF0,
|
|
278
|
+
]
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
class BleMessage:
|
|
282
|
+
"""Class for sending and recieving messages from Luba"""
|
|
283
|
+
|
|
284
|
+
AES_TRANSFORMATION = "AES/CFB/NoPadding"
|
|
285
|
+
DEFAULT_PACKAGE_LENGTH = 20
|
|
286
|
+
DH_G = "2"
|
|
287
|
+
DH_P = "cf5cf5c38419a724957ff5dd323b9c45c3cdd261eb740f69aa94b8bb1a5c96409153bd76b24222d03274e4725a5406092e9e82e9135c643cae98132b0d95f7d65347c68afc1e677da90e51bbab5f5cf429c291b4ba39c6b2dc5e8c7231e46aa7728e87664532cdf547be20c9a3fa8342be6e34371a27c06f7dc0edddd2f86373"
|
|
288
|
+
MIN_PACKAGE_LENGTH = 20
|
|
289
|
+
NEG_SECURITY_SET_ALL_DATA = 1
|
|
290
|
+
NEG_SECURITY_SET_TOTAL_LENGTH = 0
|
|
291
|
+
PACKAGE_HEADER_LENGTH = 4
|
|
292
|
+
mPrintDebug = False
|
|
293
|
+
mWriteTimeout = -1
|
|
294
|
+
mPackageLengthLimit = -1
|
|
295
|
+
mBlufiMTU = -1
|
|
296
|
+
mEncrypted = False
|
|
297
|
+
mChecksum = False
|
|
298
|
+
mRequireAck = False
|
|
299
|
+
mConnectState = 0
|
|
300
|
+
|
|
301
|
+
def __init__(self, client: BleakClient) -> None:
|
|
302
|
+
self.client = client
|
|
303
|
+
self.mSendSequence = AtomicInteger(-1)
|
|
304
|
+
self.mReadSequence = AtomicInteger(-1)
|
|
305
|
+
self.mAck = queue.Queue()
|
|
306
|
+
self.notification = BlufiNotifyData()
|
|
307
|
+
|
|
308
|
+
async def get_task(self) -> None:
|
|
309
|
+
hash_map = {"pver": 1, "subCmd": 2, "result": 0}
|
|
310
|
+
await self.post_custom_data(self.get_json_string(bleOrderCmd.task, hash_map))
|
|
311
|
+
|
|
312
|
+
async def send_ble_alive(self) -> None:
|
|
313
|
+
hash_map = {"ctrl": 1}
|
|
314
|
+
await self.post_custom_data(self.get_json_string(bleOrderCmd.bleAlive, hash_map))
|
|
315
|
+
|
|
316
|
+
def get_json_string(self, cmd: int, hash_map: dict[str, int]) -> str:
|
|
317
|
+
jSONObject = {}
|
|
318
|
+
try:
|
|
319
|
+
jSONObject["cmd"] = cmd
|
|
320
|
+
jSONObject[tmp_constant.REQUEST_ID] = int(time.time())
|
|
321
|
+
jSONObject2 = {}
|
|
322
|
+
for key, value in hash_map.items():
|
|
323
|
+
jSONObject2[key] = value
|
|
324
|
+
jSONObject["params"] = jSONObject2
|
|
325
|
+
return json.dumps(jSONObject)
|
|
326
|
+
except Exception as e:
|
|
327
|
+
print(e)
|
|
328
|
+
return ""
|
|
329
|
+
|
|
330
|
+
def clear_notification(self) -> None:
|
|
331
|
+
self.notification = BlufiNotifyData()
|
|
332
|
+
|
|
333
|
+
# async def get_device_info(self):
|
|
334
|
+
# await self.postCustomData(self.getJsonString(bleOrderCmd.getDeviceInfo))
|
|
335
|
+
|
|
336
|
+
async def send_device_info(self) -> None:
|
|
337
|
+
"""Currently not called"""
|
|
338
|
+
luba_msg = LubaMsg(
|
|
339
|
+
msgtype=MsgCmdType.ESP,
|
|
340
|
+
sender=MsgDevice.DEV_MOBILEAPP,
|
|
341
|
+
rcver=MsgDevice.DEV_COMM_ESP,
|
|
342
|
+
msgattr=MsgAttr.REQ,
|
|
343
|
+
seqs=1,
|
|
344
|
+
version=1,
|
|
345
|
+
subtype=1,
|
|
346
|
+
net=DevNet(todev_ble_sync=1, todev_devinfo_req=DrvDevInfoReq()),
|
|
347
|
+
)
|
|
348
|
+
byte_arr = luba_msg.SerializeToString()
|
|
349
|
+
await self.post_custom_data_bytes(byte_arr)
|
|
350
|
+
|
|
351
|
+
async def requestDeviceStatus(self) -> None:
|
|
352
|
+
request = False
|
|
353
|
+
type = self.getTypeValue(0, 5)
|
|
354
|
+
try:
|
|
355
|
+
request = await self.post(BleMessage.mEncrypted, BleMessage.mChecksum, False, type, None)
|
|
356
|
+
# _LOGGER.debug(request)
|
|
357
|
+
except Exception as err:
|
|
358
|
+
# Log.w(TAG, "post requestDeviceStatus interrupted")
|
|
359
|
+
request = False
|
|
360
|
+
_LOGGER.error(err)
|
|
361
|
+
|
|
362
|
+
# if not request:
|
|
363
|
+
# onStatusResponse(BlufiCallback.CODE_WRITE_DATA_FAILED, null)
|
|
364
|
+
|
|
365
|
+
async def requestDeviceVersion(self) -> None:
|
|
366
|
+
request = False
|
|
367
|
+
type = self.getTypeValue(0, 7)
|
|
368
|
+
try:
|
|
369
|
+
request = await self.post(BleMessage.mEncrypted, BleMessage.mChecksum, False, type, None)
|
|
370
|
+
# _LOGGER.debug(request)
|
|
371
|
+
except Exception as err:
|
|
372
|
+
# Log.w(TAG, "post requestDeviceStatus interrupted")
|
|
373
|
+
request = False
|
|
374
|
+
_LOGGER.error(err)
|
|
375
|
+
|
|
376
|
+
async def gatt_write(self, data: bytes) -> None:
|
|
377
|
+
await self.client.write_gatt_char(UUID_WRITE_CHARACTERISTIC, data, True)
|
|
378
|
+
|
|
379
|
+
def parseNotification(self, response: bytes):
|
|
380
|
+
"""Parse notification data from BLE device."""
|
|
381
|
+
if response is None:
|
|
382
|
+
# Log.w(TAG, "parseNotification null data");
|
|
383
|
+
return -1
|
|
384
|
+
|
|
385
|
+
# if (this.mPrintDebug):
|
|
386
|
+
# Log.d(TAG, "parseNotification Notification= " + Arrays.toString(response));
|
|
387
|
+
# }
|
|
388
|
+
if len(response) < 4:
|
|
389
|
+
_LOGGER.debug("parseNotification data length less than 4")
|
|
390
|
+
return -2
|
|
391
|
+
|
|
392
|
+
sequence = int(response[2]) # toInt
|
|
393
|
+
current_sequence = self.mReadSequence.get() & 255
|
|
394
|
+
if sequence == current_sequence:
|
|
395
|
+
# _LOGGER.debug(f"Received bluetooth data 1: {response.hex()}, object: {self}")
|
|
396
|
+
return 2
|
|
397
|
+
|
|
398
|
+
# Compare with the second counter, mod 255
|
|
399
|
+
if sequence != (self.mReadSequence.increment_and_get() & 255):
|
|
400
|
+
_LOGGER.debug(
|
|
401
|
+
"parseNotification read sequence wrong %s %s",
|
|
402
|
+
sequence,
|
|
403
|
+
self.mReadSequence.get(),
|
|
404
|
+
)
|
|
405
|
+
# Set the value for mReadSequence manually
|
|
406
|
+
self.mReadSequence.set(sequence)
|
|
407
|
+
|
|
408
|
+
# LogUtil.m7773e(self.mGatt.getDevice().getName() + "打印丢包率", self.mReadSequence_2 + "/" + self.mReadSequence_1);
|
|
409
|
+
pkt_type = int(response[0]) # toInt
|
|
410
|
+
pkgType = self._getPackageType(pkt_type)
|
|
411
|
+
subType = self._getSubType(pkt_type)
|
|
412
|
+
self.notification.setType(pkt_type)
|
|
413
|
+
self.notification.setPkgType(pkgType)
|
|
414
|
+
self.notification.setSubType(subType)
|
|
415
|
+
frameCtrl = int(response[1]) # toInt
|
|
416
|
+
# _LOGGER.debug("frame ctrl")
|
|
417
|
+
# _LOGGER.debug(frameCtrl)
|
|
418
|
+
# _LOGGER.debug(response)
|
|
419
|
+
# _LOGGER.debug(f"pktType {pkt_type} pkgType {pkgType} subType {subType}")
|
|
420
|
+
self.notification.setFrameCtrl(frameCtrl)
|
|
421
|
+
frameCtrlData = FrameCtrlData(frameCtrl)
|
|
422
|
+
dataLen = int(response[3]) # toInt specifies length of data
|
|
423
|
+
|
|
424
|
+
try:
|
|
425
|
+
dataBytes = response[4 : 4 + dataLen]
|
|
426
|
+
if frameCtrlData.isEncrypted():
|
|
427
|
+
_LOGGER.debug("is encrypted")
|
|
428
|
+
# BlufiAES aes = new BlufiAES(self.mAESKey, AES_TRANSFORMATION, generateAESIV(sequence));
|
|
429
|
+
# dataBytes = aes.decrypt(dataBytes);
|
|
430
|
+
# }
|
|
431
|
+
if frameCtrlData.isChecksum():
|
|
432
|
+
respChecksum1 = int(response[-1])
|
|
433
|
+
respChecksum2 = int(response[-2])
|
|
434
|
+
crc = self.calc_crc(self.calc_crc(0, bytes([sequence, dataLen])), dataBytes)
|
|
435
|
+
calcChecksum1 = (crc >> 8) & 255
|
|
436
|
+
calcChecksum2 = crc & 255
|
|
437
|
+
|
|
438
|
+
if respChecksum1 != calcChecksum1 or respChecksum2 != calcChecksum2:
|
|
439
|
+
_LOGGER.debug(
|
|
440
|
+
f"expect checksum: {respChecksum1}, {respChecksum2}\n"
|
|
441
|
+
f"received checksum: {calcChecksum1}, {calcChecksum2}"
|
|
442
|
+
)
|
|
443
|
+
return -4
|
|
444
|
+
|
|
445
|
+
data_offset = 2 if frameCtrlData.hasFrag() else 0
|
|
446
|
+
|
|
447
|
+
self.notification.addData(dataBytes, data_offset)
|
|
448
|
+
return 1 if frameCtrlData.hasFrag() else 0
|
|
449
|
+
except Exception as e:
|
|
450
|
+
_LOGGER.debug(e)
|
|
451
|
+
return -100
|
|
452
|
+
|
|
453
|
+
async def parseBlufiNotifyData(self, return_bytes: bool = False):
|
|
454
|
+
pkgType = self.notification.getPkgType()
|
|
455
|
+
subType = self.notification.getSubType()
|
|
456
|
+
dataBytes = self.notification.getDataArray()
|
|
457
|
+
if pkgType == 0:
|
|
458
|
+
# never seem to get these..
|
|
459
|
+
self._parseCtrlData(subType, dataBytes)
|
|
460
|
+
if pkgType == 1:
|
|
461
|
+
if return_bytes:
|
|
462
|
+
return dataBytes
|
|
463
|
+
return await self._parseDataData(subType, dataBytes)
|
|
464
|
+
|
|
465
|
+
def _parseCtrlData(self, subType: int, data: bytes) -> None:
|
|
466
|
+
pass
|
|
467
|
+
# self._parseAck(data)
|
|
468
|
+
|
|
469
|
+
async def _parseDataData(self, subType: int, data: bytes):
|
|
470
|
+
# if (subType == 0) {
|
|
471
|
+
# this.mSecurityCallback.onReceiveDevicePublicKey(data);
|
|
472
|
+
# return;
|
|
473
|
+
# }
|
|
474
|
+
_LOGGER.debug(subType)
|
|
475
|
+
match subType:
|
|
476
|
+
# case 15:
|
|
477
|
+
# parseWifiState(data);
|
|
478
|
+
# return;
|
|
479
|
+
# case 16:
|
|
480
|
+
# parseVersion(data);
|
|
481
|
+
# return;
|
|
482
|
+
# case 17:
|
|
483
|
+
# parseWifiScanList(data);
|
|
484
|
+
# return;
|
|
485
|
+
# case 18:
|
|
486
|
+
# int errCode = data.length > 0 ? 255 & data[0] : 255;
|
|
487
|
+
# onError(errCode);
|
|
488
|
+
# return;
|
|
489
|
+
case 19:
|
|
490
|
+
# # com/agilexrobotics/utils/EspBleUtil$BlufiCallbackMain.smali
|
|
491
|
+
return data
|
|
492
|
+
|
|
493
|
+
# private void parseCtrlData(int i, byte[] bArr) {
|
|
494
|
+
# if (i == 0) {
|
|
495
|
+
# parseAck(bArr);
|
|
496
|
+
# }
|
|
497
|
+
# }
|
|
498
|
+
|
|
499
|
+
# private void parseAck(byte[] bArr) {
|
|
500
|
+
# this.mAck.add(Integer.valueOf(bArr.length > 0 ? bArr[0] & 255 : 256));
|
|
501
|
+
# }
|
|
502
|
+
|
|
503
|
+
def getJsonString(self, cmd: int) -> str:
|
|
504
|
+
jSONObject = {}
|
|
505
|
+
try:
|
|
506
|
+
jSONObject["cmd"] = cmd
|
|
507
|
+
jSONObject[tmp_constant.REQUEST_ID] = int(time.time())
|
|
508
|
+
return json.dumps(jSONObject)
|
|
509
|
+
except Exception:
|
|
510
|
+
return ""
|
|
511
|
+
|
|
512
|
+
def current_milli_time(self):
|
|
513
|
+
return round(time.time() * 1000)
|
|
514
|
+
|
|
515
|
+
def _getPackageType(self, typeValue: int):
|
|
516
|
+
return typeValue & 3
|
|
517
|
+
|
|
518
|
+
def _getSubType(self, typeValue: int):
|
|
519
|
+
return (typeValue & 252) >> 2
|
|
520
|
+
|
|
521
|
+
def getTypeValue(self, type: int, subtype: int):
|
|
522
|
+
return (subtype << 2) | type
|
|
523
|
+
|
|
524
|
+
def receiveAck(self, expectAck: int) -> bool:
|
|
525
|
+
try:
|
|
526
|
+
ack = self.mAck.get()
|
|
527
|
+
return ack == expectAck
|
|
528
|
+
except Exception as err:
|
|
529
|
+
_LOGGER.debug(err)
|
|
530
|
+
return False
|
|
531
|
+
|
|
532
|
+
def generate_send_sequence(self) -> int:
|
|
533
|
+
return self.mSendSequence.increment_and_get() & 255
|
|
534
|
+
|
|
535
|
+
async def post_custom_data_bytes(self, data: bytes) -> None:
|
|
536
|
+
if data is None:
|
|
537
|
+
return
|
|
538
|
+
type_val = self.getTypeValue(1, 19)
|
|
539
|
+
try:
|
|
540
|
+
suc = await self.post(self.mEncrypted, self.mChecksum, self.mRequireAck, type_val, data)
|
|
541
|
+
# int status = suc ? 0 : BlufiCallback.CODE_WRITE_DATA_FAILED
|
|
542
|
+
# onPostCustomDataResult(status, data)
|
|
543
|
+
# _LOGGER.debug(suc)
|
|
544
|
+
except Exception as err:
|
|
545
|
+
await self.client.disconnect()
|
|
546
|
+
_LOGGER.debug(err)
|
|
547
|
+
|
|
548
|
+
async def post_custom_data(self, data_str: str) -> None:
|
|
549
|
+
data = data_str.encode()
|
|
550
|
+
if data == None:
|
|
551
|
+
return
|
|
552
|
+
type_val = self.getTypeValue(1, 19)
|
|
553
|
+
try:
|
|
554
|
+
suc = await self.post(self.mEncrypted, self.mChecksum, self.mRequireAck, type_val, data)
|
|
555
|
+
# int status = suc ? 0 : BlufiCallback.CODE_WRITE_DATA_FAILED
|
|
556
|
+
# onPostCustomDataResult(status, data)
|
|
557
|
+
except Exception as err:
|
|
558
|
+
_LOGGER.debug(err)
|
|
559
|
+
# we might be constantly connected and in a bad state
|
|
560
|
+
self.mSendSequence = AtomicInteger(-1)
|
|
561
|
+
self.mReadSequence = AtomicInteger(-1)
|
|
562
|
+
await self.client.disconnect()
|
|
563
|
+
|
|
564
|
+
async def post(
|
|
565
|
+
self,
|
|
566
|
+
encrypt: bool,
|
|
567
|
+
checksum: bool,
|
|
568
|
+
require_ack: bool,
|
|
569
|
+
type_of: int,
|
|
570
|
+
data: bytes,
|
|
571
|
+
) -> bool:
|
|
572
|
+
if data is None:
|
|
573
|
+
return await self.post_non_data(encrypt, checksum, require_ack, type_of)
|
|
574
|
+
|
|
575
|
+
return await self.post_contains_data(encrypt, checksum, require_ack, type_of, data)
|
|
576
|
+
|
|
577
|
+
async def post_non_data(self, encrypt: bool, checksum: bool, require_ack: bool, type_of: int) -> bool:
|
|
578
|
+
sequence = self.generate_send_sequence()
|
|
579
|
+
postBytes = self.getPostBytes(type_of, encrypt, checksum, require_ack, False, sequence, None)
|
|
580
|
+
await self.gatt_write(postBytes)
|
|
581
|
+
return not require_ack or self.receiveAck(sequence)
|
|
582
|
+
|
|
583
|
+
async def post_contains_data(
|
|
584
|
+
self,
|
|
585
|
+
encrypt: bool,
|
|
586
|
+
checksum: bool,
|
|
587
|
+
require_ack: bool,
|
|
588
|
+
type_of: int,
|
|
589
|
+
data: bytes,
|
|
590
|
+
) -> bool:
|
|
591
|
+
chunk_size = 517 # self.client.mtu_size - 3
|
|
592
|
+
|
|
593
|
+
chunks = list()
|
|
594
|
+
for i in range(0, len(data), chunk_size):
|
|
595
|
+
if i + chunk_size > len(data):
|
|
596
|
+
chunks.append(data[i : len(data)])
|
|
597
|
+
else:
|
|
598
|
+
chunks.append(data[i : i + chunk_size])
|
|
599
|
+
for index, chunk in enumerate(chunks):
|
|
600
|
+
frag = index != len(chunks) - 1
|
|
601
|
+
sequence = self.generate_send_sequence()
|
|
602
|
+
postBytes = self.getPostBytes(type_of, encrypt, checksum, require_ack, frag, sequence, chunk)
|
|
603
|
+
# _LOGGER.debug("sequence")
|
|
604
|
+
# _LOGGER.debug(sequence)
|
|
605
|
+
await self.gatt_write(postBytes)
|
|
606
|
+
|
|
607
|
+
if not frag:
|
|
608
|
+
return not require_ack or self.receiveAck(sequence)
|
|
609
|
+
|
|
610
|
+
if require_ack and not self.receiveAck(sequence):
|
|
611
|
+
return False
|
|
612
|
+
|
|
613
|
+
_LOGGER.debug("sleeping 0.01")
|
|
614
|
+
await sleep(0.01)
|
|
615
|
+
if require_ack and not self.receiveAck(sequence):
|
|
616
|
+
return False
|
|
617
|
+
|
|
618
|
+
return True
|
|
619
|
+
|
|
620
|
+
def getPostBytes(
|
|
621
|
+
self,
|
|
622
|
+
type: int,
|
|
623
|
+
encrypt: bool,
|
|
624
|
+
checksum: bool,
|
|
625
|
+
require_ack: bool,
|
|
626
|
+
hasFrag: bool,
|
|
627
|
+
sequence: int,
|
|
628
|
+
data: bytes | None,
|
|
629
|
+
) -> bytes:
|
|
630
|
+
byteOS = BytesIO()
|
|
631
|
+
dataLength = 0 if data == None else len(data)
|
|
632
|
+
frameCtrl = FrameCtrlData.getFrameCTRLValue(encrypt, checksum, 0, require_ack, hasFrag)
|
|
633
|
+
byteOS.write(type.to_bytes(1, sys.byteorder))
|
|
634
|
+
byteOS.write(frameCtrl.to_bytes(1, sys.byteorder))
|
|
635
|
+
byteOS.write(sequence.to_bytes(1, sys.byteorder))
|
|
636
|
+
byteOS.write(dataLength.to_bytes(1, sys.byteorder))
|
|
637
|
+
|
|
638
|
+
if data is not None:
|
|
639
|
+
byteOS.write(data)
|
|
640
|
+
|
|
641
|
+
_LOGGER.debug(byteOS.getvalue())
|
|
642
|
+
return byteOS.getvalue()
|
|
643
|
+
|
|
644
|
+
@staticmethod
|
|
645
|
+
def calc_crc(initial: int, data: bytes | bytearray) -> int:
|
|
646
|
+
"""Calculate CRC value for given initial value and byte array.
|
|
647
|
+
|
|
648
|
+
Args:
|
|
649
|
+
initial: Initial CRC value
|
|
650
|
+
data: Bytes to calculate CRC for
|
|
651
|
+
|
|
652
|
+
Returns:
|
|
653
|
+
Calculated CRC value (16-bit)
|
|
654
|
+
|
|
655
|
+
Raises:
|
|
656
|
+
TypeError: If data is not bytes or bytearray
|
|
657
|
+
ValueError: If initial value is out of valid range
|
|
658
|
+
|
|
659
|
+
"""
|
|
660
|
+
if not isinstance(data, (bytes, bytearray)):
|
|
661
|
+
raise TypeError("Data must be bytes or bytearray")
|
|
662
|
+
|
|
663
|
+
if not 0 <= initial <= 0xFFFF:
|
|
664
|
+
raise ValueError("Initial value must be between 0 and 65535")
|
|
665
|
+
|
|
666
|
+
try:
|
|
667
|
+
crc = (~initial) & 0xFFFF
|
|
668
|
+
|
|
669
|
+
for byte in data:
|
|
670
|
+
crc = ((crc << 8) ^ CRC_TB[byte ^ (crc >> 8)]) & 0xFFFF
|
|
671
|
+
|
|
672
|
+
return (~crc) & 0xFFFF
|
|
673
|
+
|
|
674
|
+
except Exception as e:
|
|
675
|
+
_LOGGER.error("Error calculating CRC: %s", str(e))
|
|
676
|
+
raise
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
MODEL_NBR_UUID = "0000ff02-0000-1000-8000-00805f9b34fb"
|
|
2
|
+
|
|
3
|
+
UART_SERVICE_UUID = "0000ffff-0000-1000-8000-00805f9b34fb"
|
|
4
|
+
UART_RX_CHAR_UUID = "0000ff01-0000-1000-8000-00805f9b34fb"
|
|
5
|
+
UART_TX_CHAR_UUID = "0000ff02-0000-1000-8000-00805f9b34fb"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# 01-31 14:06:23.761 21981 22174 E EspBleUtil: ServiceName:00001801-0000-1000-8000-00805f9b34fb
|
|
9
|
+
# 01-31 14:06:23.761 21981 22174 E EspBleUtil: ---CharacterName:00002a05-0000-1000-8000-00805f9b34fb
|
|
10
|
+
# 01-31 14:06:23.761 21981 22174 E EspBleUtil: ServiceName:00001800-0000-1000-8000-00805f9b34fb
|
|
11
|
+
# 01-31 14:06:23.761 21981 22174 E EspBleUtil: ---CharacterName:00002a00-0000-1000-8000-00805f9b34fb
|
|
12
|
+
# 01-31 14:06:23.761 21981 22174 E EspBleUtil: ---CharacterName:00002a01-0000-1000-8000-00805f9b34fb
|
|
13
|
+
# 01-31 14:06:23.761 21981 22174 E EspBleUtil: ---CharacterName:00002aa6-0000-1000-8000-00805f9b34fb
|
|
14
|
+
# 01-31 14:06:23.761 21981 22174 E EspBleUtil: ServiceName:0000ffff-0000-1000-8000-00805f9b34fb
|
|
15
|
+
# 01-31 14:06:23.762 21981 22174 E EspBleUtil: ---CharacterName:0000ff01-0000-1000-8000-00805f9b34fb
|
|
16
|
+
# 01-31 14:06:23.762 21981 22174 E EspBleUtil: ---CharacterName:0000ff02-0000-1000-8000-00805f9b34fb
|
|
17
|
+
|
|
18
|
+
UUID_SERVICE = "0000ffff-0000-1000-8000-00805f9b34fb"
|
|
19
|
+
UUID_WRITE_CHARACTERISTIC = "0000ff01-0000-1000-8000-00805f9b34fb"
|
|
20
|
+
UUID_NOTIFICATION_CHARACTERISTIC = "0000ff02-0000-1000-8000-00805f9b34fb"
|
|
21
|
+
UUID_NOTIFICATION_DESCRIPTOR = "00002902-0000-1000-8000-00805f9b34fb"
|
|
22
|
+
|
|
23
|
+
CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID = "00002902-0000-1000-8000-00805f9b34fb"
|
|
24
|
+
BATTERY_SERVICE = "0000180F-0000-1000-8000-00805f9b34fb"
|
|
25
|
+
BATTERY_LEVEL_CHARACTERISTIC = "00002A19-0000-1000-8000-00805f9b34fb"
|
|
26
|
+
GENERIC_ATTRIBUTE_SERVICE = "00001801-0000-1000-8000-00805f9b34fb"
|
|
27
|
+
SERVICE_CHANGED_CHARACTERISTIC = "00002A05-0000-1000-8000-00805f9b34fb"
|
|
File without changes
|