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.
Files changed (154) hide show
  1. pymammotion/__init__.py +53 -0
  2. pymammotion/agora/__init__.py +0 -0
  3. pymammotion/agora/agora_api.py +755 -0
  4. pymammotion/agora/agora_rtc_capabilities.py +748 -0
  5. pymammotion/agora/agora_websockets.py +1175 -0
  6. pymammotion/aliyun/__init__.py +1 -0
  7. pymammotion/aliyun/client.py +235 -0
  8. pymammotion/aliyun/cloud_gateway.py +982 -0
  9. pymammotion/aliyun/model/aep_response.py +21 -0
  10. pymammotion/aliyun/model/connect_response.py +51 -0
  11. pymammotion/aliyun/model/dev_by_account_response.py +195 -0
  12. pymammotion/aliyun/model/login_by_oauth_response.py +64 -0
  13. pymammotion/aliyun/model/regions_response.py +29 -0
  14. pymammotion/aliyun/model/session_by_authcode_response.py +19 -0
  15. pymammotion/aliyun/model/thing_response.py +12 -0
  16. pymammotion/aliyun/regions.py +62 -0
  17. pymammotion/aliyun/tea/core.py +297 -0
  18. pymammotion/aliyun/tmp_constant.py +171 -0
  19. pymammotion/bluetooth/__init__.py +1 -0
  20. pymammotion/bluetooth/ble.py +62 -0
  21. pymammotion/bluetooth/ble_message.py +676 -0
  22. pymammotion/bluetooth/const.py +27 -0
  23. pymammotion/bluetooth/data/__init__.py +0 -0
  24. pymammotion/bluetooth/data/convert.py +25 -0
  25. pymammotion/bluetooth/data/framectrldata.py +40 -0
  26. pymammotion/bluetooth/data/notifydata.py +62 -0
  27. pymammotion/bluetooth/model/__init__.py +0 -0
  28. pymammotion/bluetooth/model/atomic_integer.py +54 -0
  29. pymammotion/const.py +13 -0
  30. pymammotion/data/__init__.py +0 -0
  31. pymammotion/data/model/__init__.py +8 -0
  32. pymammotion/data/model/account.py +8 -0
  33. pymammotion/data/model/device.py +192 -0
  34. pymammotion/data/model/device_config.py +72 -0
  35. pymammotion/data/model/device_info.py +60 -0
  36. pymammotion/data/model/device_limits.py +49 -0
  37. pymammotion/data/model/enums.py +77 -0
  38. pymammotion/data/model/errors.py +12 -0
  39. pymammotion/data/model/events.py +14 -0
  40. pymammotion/data/model/generate_geojson.py +565 -0
  41. pymammotion/data/model/generate_route_information.py +26 -0
  42. pymammotion/data/model/hash_list.py +475 -0
  43. pymammotion/data/model/location.py +36 -0
  44. pymammotion/data/model/mowing_modes.py +77 -0
  45. pymammotion/data/model/rapid_state.py +45 -0
  46. pymammotion/data/model/raw_data.py +215 -0
  47. pymammotion/data/model/region_data.py +102 -0
  48. pymammotion/data/model/report_info.py +182 -0
  49. pymammotion/data/model/work.py +27 -0
  50. pymammotion/data/mower_state_manager.py +369 -0
  51. pymammotion/data/mqtt/__init__.py +1 -0
  52. pymammotion/data/mqtt/event.py +227 -0
  53. pymammotion/data/mqtt/mammotion_properties.py +276 -0
  54. pymammotion/data/mqtt/properties.py +203 -0
  55. pymammotion/data/mqtt/status.py +57 -0
  56. pymammotion/event/__init__.py +6 -0
  57. pymammotion/event/event.py +96 -0
  58. pymammotion/homeassistant/__init__.py +3 -0
  59. pymammotion/homeassistant/mower_api.py +514 -0
  60. pymammotion/homeassistant/rtk_api.py +54 -0
  61. pymammotion/http/__init__.py +0 -0
  62. pymammotion/http/encryption.py +220 -0
  63. pymammotion/http/http.py +673 -0
  64. pymammotion/http/model/__init__.py +0 -0
  65. pymammotion/http/model/camera_stream.py +31 -0
  66. pymammotion/http/model/http.py +249 -0
  67. pymammotion/http/model/response_factory.py +61 -0
  68. pymammotion/http/model/rtk.py +16 -0
  69. pymammotion/mammotion/__init__.py +0 -0
  70. pymammotion/mammotion/commands/__init__.py +0 -0
  71. pymammotion/mammotion/commands/abstract_message.py +24 -0
  72. pymammotion/mammotion/commands/mammotion_command.py +81 -0
  73. pymammotion/mammotion/commands/messages/__init__.py +0 -0
  74. pymammotion/mammotion/commands/messages/basestation.py +43 -0
  75. pymammotion/mammotion/commands/messages/driver.py +122 -0
  76. pymammotion/mammotion/commands/messages/media.py +87 -0
  77. pymammotion/mammotion/commands/messages/navigation.py +564 -0
  78. pymammotion/mammotion/commands/messages/network.py +205 -0
  79. pymammotion/mammotion/commands/messages/ota.py +38 -0
  80. pymammotion/mammotion/commands/messages/system.py +330 -0
  81. pymammotion/mammotion/commands/messages/video.py +33 -0
  82. pymammotion/mammotion/control/__init__.py +0 -0
  83. pymammotion/mammotion/control/joystick.py +145 -0
  84. pymammotion/mammotion/devices/__init__.py +29 -0
  85. pymammotion/mammotion/devices/base.py +163 -0
  86. pymammotion/mammotion/devices/mammotion.py +571 -0
  87. pymammotion/mammotion/devices/mammotion_bluetooth.py +496 -0
  88. pymammotion/mammotion/devices/mammotion_cloud.py +355 -0
  89. pymammotion/mammotion/devices/mammotion_mower_ble.py +48 -0
  90. pymammotion/mammotion/devices/mammotion_mower_cloud.py +39 -0
  91. pymammotion/mammotion/devices/managers/managers.py +81 -0
  92. pymammotion/mammotion/devices/mower_device.py +120 -0
  93. pymammotion/mammotion/devices/mower_manager.py +107 -0
  94. pymammotion/mammotion/devices/rtk_ble.py +89 -0
  95. pymammotion/mammotion/devices/rtk_cloud.py +115 -0
  96. pymammotion/mammotion/devices/rtk_device.py +50 -0
  97. pymammotion/mammotion/devices/rtk_manager.py +125 -0
  98. pymammotion/mqtt/__init__.py +6 -0
  99. pymammotion/mqtt/aliyun_mqtt.py +237 -0
  100. pymammotion/mqtt/linkkit/__init__.py +5 -0
  101. pymammotion/mqtt/linkkit/h2client.py +585 -0
  102. pymammotion/mqtt/linkkit/linkkit.py +3025 -0
  103. pymammotion/mqtt/mammotion_future.py +26 -0
  104. pymammotion/mqtt/mammotion_mqtt.py +214 -0
  105. pymammotion/mqtt/mqtt_models.py +66 -0
  106. pymammotion/proto/__init__.py +4841 -0
  107. pymammotion/proto/basestation.proto +51 -0
  108. pymammotion/proto/basestation_pb2.py +35 -0
  109. pymammotion/proto/basestation_pb2.pyi +89 -0
  110. pymammotion/proto/common.proto +7 -0
  111. pymammotion/proto/common_pb2.py +25 -0
  112. pymammotion/proto/common_pb2.pyi +13 -0
  113. pymammotion/proto/dev_net.proto +321 -0
  114. pymammotion/proto/dev_net_pb2.py +111 -0
  115. pymammotion/proto/dev_net_pb2.pyi +515 -0
  116. pymammotion/proto/luba_msg.proto +76 -0
  117. pymammotion/proto/luba_msg_pb2.py +41 -0
  118. pymammotion/proto/luba_msg_pb2.pyi +97 -0
  119. pymammotion/proto/luba_mul.proto +129 -0
  120. pymammotion/proto/luba_mul_pb2.py +61 -0
  121. pymammotion/proto/luba_mul_pb2.pyi +178 -0
  122. pymammotion/proto/mctrl_driver.proto +107 -0
  123. pymammotion/proto/mctrl_driver_pb2.py +57 -0
  124. pymammotion/proto/mctrl_driver_pb2.pyi +167 -0
  125. pymammotion/proto/mctrl_nav.proto +591 -0
  126. pymammotion/proto/mctrl_nav_pb2.py +136 -0
  127. pymammotion/proto/mctrl_nav_pb2.pyi +1067 -0
  128. pymammotion/proto/mctrl_ota.proto +80 -0
  129. pymammotion/proto/mctrl_ota_pb2.py +45 -0
  130. pymammotion/proto/mctrl_ota_pb2.pyi +128 -0
  131. pymammotion/proto/mctrl_pept.proto +34 -0
  132. pymammotion/proto/mctrl_pept_pb2.py +33 -0
  133. pymammotion/proto/mctrl_pept_pb2.pyi +58 -0
  134. pymammotion/proto/mctrl_sys.proto +741 -0
  135. pymammotion/proto/mctrl_sys_pb2.py +206 -0
  136. pymammotion/proto/mctrl_sys_pb2.pyi +1213 -0
  137. pymammotion/proto/message_pool.py +3 -0
  138. pymammotion/proto/py.typed +0 -0
  139. pymammotion/py.typed +0 -0
  140. pymammotion/utility/constant/__init__.py +3 -0
  141. pymammotion/utility/constant/device_constant.py +315 -0
  142. pymammotion/utility/conversions.py +5 -0
  143. pymammotion/utility/datatype_converter.py +124 -0
  144. pymammotion/utility/device_config.py +755 -0
  145. pymammotion/utility/device_type.py +489 -0
  146. pymammotion/utility/map.py +259 -0
  147. pymammotion/utility/movement.py +18 -0
  148. pymammotion/utility/mur_mur_hash.py +159 -0
  149. pymammotion/utility/periodic.py +106 -0
  150. pymammotion/utility/rocker_util.py +194 -0
  151. pymammotion-0.5.69.dist-info/METADATA +93 -0
  152. pymammotion-0.5.69.dist-info/RECORD +154 -0
  153. pymammotion-0.5.69.dist-info/WHEEL +4 -0
  154. 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