pymammotion 0.2.62__py3-none-any.whl → 0.5.51__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.
Potentially problematic release.
This version of pymammotion might be problematic. Click here for more details.
- pymammotion/__init__.py +9 -6
- pymammotion/aliyun/client.py +235 -0
- pymammotion/aliyun/cloud_gateway.py +320 -69
- pymammotion/aliyun/model/aep_response.py +1 -2
- pymammotion/aliyun/model/dev_by_account_response.py +170 -23
- pymammotion/aliyun/model/login_by_oauth_response.py +2 -3
- pymammotion/aliyun/model/regions_response.py +3 -3
- pymammotion/aliyun/model/session_by_authcode_response.py +2 -2
- pymammotion/aliyun/model/thing_response.py +12 -0
- pymammotion/aliyun/regions.py +62 -0
- pymammotion/aliyun/tea/core.py +297 -0
- pymammotion/bluetooth/ble.py +11 -15
- pymammotion/bluetooth/ble_message.py +389 -106
- pymammotion/bluetooth/model/atomic_integer.py +54 -0
- pymammotion/const.py +3 -0
- pymammotion/data/model/__init__.py +1 -2
- pymammotion/data/model/device.py +92 -240
- pymammotion/data/model/device_config.py +10 -24
- pymammotion/data/model/device_info.py +35 -0
- pymammotion/data/model/device_limits.py +49 -0
- pymammotion/data/model/enums.py +12 -2
- pymammotion/data/model/errors.py +12 -0
- pymammotion/data/model/events.py +14 -0
- pymammotion/data/model/generate_geojson.py +521 -0
- pymammotion/data/model/generate_route_information.py +3 -4
- pymammotion/data/model/hash_list.py +384 -48
- pymammotion/data/model/location.py +4 -4
- pymammotion/data/model/mowing_modes.py +24 -1
- pymammotion/data/model/raw_data.py +215 -0
- pymammotion/data/model/region_data.py +10 -11
- pymammotion/data/model/report_info.py +62 -6
- pymammotion/data/model/work.py +27 -0
- pymammotion/data/mower_state_manager.py +316 -0
- pymammotion/data/mqtt/event.py +73 -28
- pymammotion/data/mqtt/mammotion_properties.py +257 -0
- pymammotion/data/mqtt/properties.py +93 -78
- pymammotion/data/mqtt/status.py +18 -17
- pymammotion/event/event.py +32 -8
- pymammotion/homeassistant/__init__.py +3 -0
- pymammotion/homeassistant/mower_api.py +484 -0
- pymammotion/homeassistant/rtk_api.py +54 -0
- pymammotion/http/__init__.py +0 -0
- pymammotion/http/encryption.py +220 -0
- pymammotion/http/http.py +652 -44
- pymammotion/http/model/__init__.py +0 -0
- pymammotion/{aliyun/model/stream_subscription_response.py → http/model/camera_stream.py} +14 -2
- pymammotion/http/model/http.py +160 -9
- pymammotion/http/model/response_factory.py +61 -0
- pymammotion/http/model/rtk.py +16 -0
- pymammotion/mammotion/commands/abstract_message.py +7 -5
- pymammotion/mammotion/commands/mammotion_command.py +32 -3
- pymammotion/mammotion/commands/messages/basestation.py +43 -0
- pymammotion/mammotion/commands/messages/driver.py +61 -29
- pymammotion/mammotion/commands/messages/media.py +68 -15
- pymammotion/mammotion/commands/messages/navigation.py +61 -25
- pymammotion/mammotion/commands/messages/network.py +93 -100
- pymammotion/mammotion/commands/messages/ota.py +18 -18
- pymammotion/mammotion/commands/messages/system.py +97 -72
- pymammotion/mammotion/commands/messages/video.py +17 -12
- pymammotion/mammotion/devices/__init__.py +27 -3
- pymammotion/mammotion/devices/base.py +50 -127
- pymammotion/mammotion/devices/mammotion.py +447 -212
- pymammotion/mammotion/devices/mammotion_bluetooth.py +105 -60
- pymammotion/mammotion/devices/mammotion_cloud.py +157 -105
- pymammotion/mammotion/devices/mammotion_mower_ble.py +49 -0
- pymammotion/mammotion/devices/mammotion_mower_cloud.py +39 -0
- pymammotion/mammotion/devices/managers/managers.py +81 -0
- pymammotion/mammotion/devices/mower_device.py +124 -0
- pymammotion/mammotion/devices/mower_manager.py +107 -0
- pymammotion/mammotion/devices/rtk_ble.py +89 -0
- pymammotion/mammotion/devices/rtk_cloud.py +113 -0
- pymammotion/mammotion/devices/rtk_device.py +50 -0
- pymammotion/mammotion/devices/rtk_manager.py +122 -0
- pymammotion/mqtt/__init__.py +2 -1
- pymammotion/mqtt/aliyun_mqtt.py +232 -0
- pymammotion/mqtt/linkkit/__init__.py +5 -0
- pymammotion/mqtt/linkkit/h2client.py +585 -0
- pymammotion/mqtt/linkkit/linkkit.py +3023 -0
- pymammotion/mqtt/mammotion_mqtt.py +176 -169
- pymammotion/mqtt/mqtt_models.py +66 -0
- pymammotion/proto/__init__.py +4839 -4
- pymammotion/proto/basestation.proto +8 -0
- pymammotion/proto/basestation_pb2.py +11 -9
- pymammotion/proto/basestation_pb2.pyi +16 -2
- pymammotion/proto/dev_net.proto +79 -55
- pymammotion/proto/dev_net_pb2.py +60 -56
- pymammotion/proto/dev_net_pb2.pyi +49 -6
- pymammotion/proto/luba_msg.proto +2 -1
- pymammotion/proto/luba_msg_pb2.py +6 -6
- pymammotion/proto/luba_msg_pb2.pyi +1 -0
- pymammotion/proto/luba_mul.proto +62 -1
- pymammotion/proto/luba_mul_pb2.py +38 -22
- pymammotion/proto/luba_mul_pb2.pyi +94 -7
- pymammotion/proto/mctrl_driver.proto +44 -4
- pymammotion/proto/mctrl_driver_pb2.py +26 -14
- pymammotion/proto/mctrl_driver_pb2.pyi +66 -11
- pymammotion/proto/mctrl_nav.proto +97 -51
- pymammotion/proto/mctrl_nav_pb2.py +75 -67
- pymammotion/proto/mctrl_nav_pb2.pyi +142 -56
- pymammotion/proto/mctrl_ota.proto +40 -2
- pymammotion/proto/mctrl_ota_pb2.py +23 -13
- pymammotion/proto/mctrl_ota_pb2.pyi +67 -4
- pymammotion/proto/mctrl_pept.proto +8 -3
- pymammotion/proto/mctrl_pept_pb2.py +8 -6
- pymammotion/proto/mctrl_pept_pb2.pyi +14 -6
- pymammotion/proto/mctrl_sys.proto +325 -86
- pymammotion/proto/mctrl_sys_pb2.py +162 -98
- pymammotion/proto/mctrl_sys_pb2.pyi +451 -25
- pymammotion/proto/message_pool.py +3 -0
- pymammotion/proto/py.typed +0 -0
- pymammotion/utility/constant/device_constant.py +65 -21
- pymammotion/utility/datatype_converter.py +13 -12
- pymammotion/utility/device_config.py +755 -0
- pymammotion/utility/device_type.py +218 -21
- pymammotion/utility/map.py +238 -51
- pymammotion/utility/mur_mur_hash.py +159 -0
- {pymammotion-0.2.62.dist-info → pymammotion-0.5.51.dist-info}/METADATA +27 -31
- pymammotion-0.5.51.dist-info/RECORD +152 -0
- {pymammotion-0.2.62.dist-info → pymammotion-0.5.51.dist-info}/WHEEL +1 -1
- pymammotion/aliyun/cloud_service.py +0 -65
- pymammotion/data/model/plan.py +0 -58
- pymammotion/data/state_manager.py +0 -130
- pymammotion/proto/basestation.py +0 -59
- pymammotion/proto/common.py +0 -12
- pymammotion/proto/dev_net.py +0 -381
- pymammotion/proto/luba_msg.py +0 -81
- pymammotion/proto/luba_mul.py +0 -76
- pymammotion/proto/mctrl_driver.py +0 -100
- pymammotion/proto/mctrl_nav.py +0 -660
- pymammotion/proto/mctrl_ota.py +0 -48
- pymammotion/proto/mctrl_pept.py +0 -41
- pymammotion/proto/mctrl_sys.py +0 -574
- pymammotion-0.2.62.dist-info/RECORD +0 -125
- /pymammotion/{http/_init_.py → bluetooth/model/__init__.py} +0 -0
- {pymammotion-0.2.62.dist-info → pymammotion-0.5.51.dist-info/licenses}/LICENSE +0 -0
pymammotion/bluetooth/ble.py
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
from bleak import BleakClient, BleakScanner, BLEDevice
|
|
2
2
|
from bleak.backends.characteristic import BleakGATTCharacteristic
|
|
3
3
|
|
|
4
|
-
from pymammotion.bluetooth.const import
|
|
5
|
-
SERVICE_CHANGED_CHARACTERISTIC,
|
|
6
|
-
UUID_NOTIFICATION_CHARACTERISTIC,
|
|
7
|
-
)
|
|
4
|
+
from pymammotion.bluetooth.const import SERVICE_CHANGED_CHARACTERISTIC, UUID_NOTIFICATION_CHARACTERISTIC
|
|
8
5
|
from pymammotion.event.event import BleNotificationEvent
|
|
9
6
|
|
|
10
|
-
# TODO setup for each Luba
|
|
11
|
-
address = "90:38:0C:6E:EE:9E"
|
|
12
|
-
|
|
13
7
|
|
|
14
8
|
class MammotionBLE:
|
|
9
|
+
"""Class for basic ble connections to mowers."""
|
|
10
|
+
|
|
15
11
|
client: BleakClient
|
|
16
12
|
|
|
17
13
|
def __init__(self, bleEvt: BleNotificationEvent) -> None:
|
|
@@ -24,27 +20,26 @@ class MammotionBLE:
|
|
|
24
20
|
# TODO: do something with incoming data
|
|
25
21
|
print(device)
|
|
26
22
|
print(advertising_data)
|
|
27
|
-
if
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
if advertising_data.local_name and (
|
|
24
|
+
"Luba-" in advertising_data.local_name or "Yuka-" in advertising_data.local_name
|
|
25
|
+
):
|
|
30
26
|
return True
|
|
31
27
|
return False
|
|
32
28
|
|
|
33
29
|
device = await scanner.find_device_by_filter(scanCallback)
|
|
34
30
|
if device is not None:
|
|
35
31
|
return await self.create_client(device)
|
|
32
|
+
return False
|
|
36
33
|
|
|
37
34
|
async def create_client(self, device: BLEDevice):
|
|
38
35
|
self.client = BleakClient(device.address)
|
|
39
36
|
return await self.connect()
|
|
40
37
|
|
|
41
38
|
async def connect(self) -> bool:
|
|
42
|
-
if self.client is not None
|
|
43
|
-
return await self.client.connect()
|
|
39
|
+
return await self.client.connect() if self.client is not None else False
|
|
44
40
|
|
|
45
41
|
async def disconnect(self) -> bool:
|
|
46
|
-
if self.client is not None
|
|
47
|
-
return await self.client.disconnect()
|
|
42
|
+
return await self.client.disconnect() if self.client is not None else False
|
|
48
43
|
|
|
49
44
|
async def notification_handler(self, _characteristic: BleakGATTCharacteristic, data: bytearray) -> None:
|
|
50
45
|
"""Simple notification handler which prints the data received."""
|
|
@@ -62,5 +57,6 @@ class MammotionBLE:
|
|
|
62
57
|
await self.client.start_notify(UUID_NOTIFICATION_CHARACTERISTIC, self.notification_handler)
|
|
63
58
|
await self.client.start_notify(SERVICE_CHANGED_CHARACTERISTIC, self.service_changed_handler)
|
|
64
59
|
|
|
65
|
-
def
|
|
60
|
+
def get_client(self):
|
|
61
|
+
"""Returns the ble client."""
|
|
66
62
|
return self.client
|
|
@@ -1,29 +1,285 @@
|
|
|
1
|
+
from asyncio import sleep
|
|
2
|
+
from io import BytesIO
|
|
1
3
|
import itertools
|
|
2
4
|
import json
|
|
3
5
|
import logging
|
|
4
6
|
import queue
|
|
5
7
|
import sys
|
|
6
8
|
import time
|
|
7
|
-
from asyncio import sleep
|
|
8
|
-
from io import BytesIO
|
|
9
9
|
|
|
10
10
|
from bleak import BleakClient
|
|
11
11
|
from jsonic.serializable import serialize
|
|
12
12
|
|
|
13
13
|
from pymammotion.aliyun.tmp_constant import tmp_constant
|
|
14
14
|
from pymammotion.bluetooth.const import UUID_WRITE_CHARACTERISTIC
|
|
15
|
-
from pymammotion.bluetooth.data.convert import parse_custom_data
|
|
16
15
|
from pymammotion.bluetooth.data.framectrldata import FrameCtrlData
|
|
17
16
|
from pymammotion.bluetooth.data.notifydata import BlufiNotifyData
|
|
17
|
+
from pymammotion.bluetooth.model.atomic_integer import AtomicInteger
|
|
18
18
|
from pymammotion.data.model.execute_boarder import ExecuteBorder
|
|
19
|
-
from pymammotion.proto import
|
|
20
|
-
dev_net_pb2,
|
|
21
|
-
luba_msg_pb2,
|
|
22
|
-
)
|
|
19
|
+
from pymammotion.proto import DevNet, DrvDevInfoReq, LubaMsg, MsgAttr, MsgCmdType, MsgDevice
|
|
23
20
|
from pymammotion.utility.constant.device_constant import bleOrderCmd
|
|
24
21
|
|
|
25
22
|
_LOGGER = logging.getLogger(__name__)
|
|
26
23
|
|
|
24
|
+
CRC_TB = [
|
|
25
|
+
0x0000,
|
|
26
|
+
0x1021,
|
|
27
|
+
0x2042,
|
|
28
|
+
0x3063,
|
|
29
|
+
0x4084,
|
|
30
|
+
0x50A5,
|
|
31
|
+
0x60C6,
|
|
32
|
+
0x70E7,
|
|
33
|
+
0x8108,
|
|
34
|
+
0x9129,
|
|
35
|
+
0xA14A,
|
|
36
|
+
0xB16B,
|
|
37
|
+
0xC18C,
|
|
38
|
+
0xD1AD,
|
|
39
|
+
0xE1CE,
|
|
40
|
+
0xF1EF,
|
|
41
|
+
0x1231,
|
|
42
|
+
0x0210,
|
|
43
|
+
0x3273,
|
|
44
|
+
0x2252,
|
|
45
|
+
0x52B5,
|
|
46
|
+
0x4294,
|
|
47
|
+
0x72F7,
|
|
48
|
+
0x62D6,
|
|
49
|
+
0x9339,
|
|
50
|
+
0x8318,
|
|
51
|
+
0xB37B,
|
|
52
|
+
0xA35A,
|
|
53
|
+
0xD3BD,
|
|
54
|
+
0xC39C,
|
|
55
|
+
0xF3FF,
|
|
56
|
+
0xE3DE,
|
|
57
|
+
0x2462,
|
|
58
|
+
0x3443,
|
|
59
|
+
0x0420,
|
|
60
|
+
0x1401,
|
|
61
|
+
0x64E6,
|
|
62
|
+
0x74C7,
|
|
63
|
+
0x44A4,
|
|
64
|
+
0x5485,
|
|
65
|
+
0xA56A,
|
|
66
|
+
0xB54B,
|
|
67
|
+
0x8528,
|
|
68
|
+
0x9509,
|
|
69
|
+
0xE5EE,
|
|
70
|
+
0xF5CF,
|
|
71
|
+
0xC5AC,
|
|
72
|
+
0xD58D,
|
|
73
|
+
0x3653,
|
|
74
|
+
0x2672,
|
|
75
|
+
0x1611,
|
|
76
|
+
0x0630,
|
|
77
|
+
0x76D7,
|
|
78
|
+
0x66F6,
|
|
79
|
+
0x5695,
|
|
80
|
+
0x46B4,
|
|
81
|
+
0xB75B,
|
|
82
|
+
0xA77A,
|
|
83
|
+
0x9719,
|
|
84
|
+
0x8738,
|
|
85
|
+
0xF7DF,
|
|
86
|
+
0xE7FE,
|
|
87
|
+
0xD79D,
|
|
88
|
+
0xC7BC,
|
|
89
|
+
0x48C4,
|
|
90
|
+
0x58E5,
|
|
91
|
+
0x6886,
|
|
92
|
+
0x78A7,
|
|
93
|
+
0x0840,
|
|
94
|
+
0x1861,
|
|
95
|
+
0x2802,
|
|
96
|
+
0x3823,
|
|
97
|
+
0xC9CC,
|
|
98
|
+
0xD9ED,
|
|
99
|
+
0xE98E,
|
|
100
|
+
0xF9AF,
|
|
101
|
+
0x8948,
|
|
102
|
+
0x9969,
|
|
103
|
+
0xA90A,
|
|
104
|
+
0xB92B,
|
|
105
|
+
0x5AF5,
|
|
106
|
+
0x4AD4,
|
|
107
|
+
0x7AB7,
|
|
108
|
+
0x6A96,
|
|
109
|
+
0x1A71,
|
|
110
|
+
0x0A50,
|
|
111
|
+
0x3A33,
|
|
112
|
+
0x2A12,
|
|
113
|
+
0xDBFD,
|
|
114
|
+
0xCBDC,
|
|
115
|
+
0xFBBF,
|
|
116
|
+
0xEB9E,
|
|
117
|
+
0x9B79,
|
|
118
|
+
0x8B58,
|
|
119
|
+
0xBB3B,
|
|
120
|
+
0xAB1A,
|
|
121
|
+
0x6CA6,
|
|
122
|
+
0x7C87,
|
|
123
|
+
0x4CE4,
|
|
124
|
+
0x5CC5,
|
|
125
|
+
0x2C22,
|
|
126
|
+
0x3C03,
|
|
127
|
+
0x0C60,
|
|
128
|
+
0x1C41,
|
|
129
|
+
0xEDAE,
|
|
130
|
+
0xFD8F,
|
|
131
|
+
0xCDEC,
|
|
132
|
+
0xDDCD,
|
|
133
|
+
0xAD2A,
|
|
134
|
+
0xBD0B,
|
|
135
|
+
0x8D68,
|
|
136
|
+
0x9D49,
|
|
137
|
+
0x7E97,
|
|
138
|
+
0x6EB6,
|
|
139
|
+
0x5ED5,
|
|
140
|
+
0x4EF4,
|
|
141
|
+
0x3E13,
|
|
142
|
+
0x2E32,
|
|
143
|
+
0x1E51,
|
|
144
|
+
0x0E70,
|
|
145
|
+
0xFF9F,
|
|
146
|
+
0xEFBE,
|
|
147
|
+
0xDFDD,
|
|
148
|
+
0xCFFC,
|
|
149
|
+
0xBF1B,
|
|
150
|
+
0xAF3A,
|
|
151
|
+
0x9F59,
|
|
152
|
+
0x8F78,
|
|
153
|
+
0x9188,
|
|
154
|
+
0x81A9,
|
|
155
|
+
0xB1CA,
|
|
156
|
+
0xA1EB,
|
|
157
|
+
0xD10C,
|
|
158
|
+
0xC12D,
|
|
159
|
+
0xF14E,
|
|
160
|
+
0xE16F,
|
|
161
|
+
0x1080,
|
|
162
|
+
0x00A1,
|
|
163
|
+
0x30C2,
|
|
164
|
+
0x20E3,
|
|
165
|
+
0x5004,
|
|
166
|
+
0x4025,
|
|
167
|
+
0x7046,
|
|
168
|
+
0x6067,
|
|
169
|
+
0x83B9,
|
|
170
|
+
0x9398,
|
|
171
|
+
0xA3FB,
|
|
172
|
+
0xB3DA,
|
|
173
|
+
0xC33D,
|
|
174
|
+
0xD31C,
|
|
175
|
+
0xE37F,
|
|
176
|
+
0xF35E,
|
|
177
|
+
0x02B1,
|
|
178
|
+
0x1290,
|
|
179
|
+
0x22F3,
|
|
180
|
+
0x32D2,
|
|
181
|
+
0x4235,
|
|
182
|
+
0x5214,
|
|
183
|
+
0x6277,
|
|
184
|
+
0x7256,
|
|
185
|
+
0xB5EA,
|
|
186
|
+
0xA5CB,
|
|
187
|
+
0x95A8,
|
|
188
|
+
0x8589,
|
|
189
|
+
0xF56E,
|
|
190
|
+
0xE54F,
|
|
191
|
+
0xD52C,
|
|
192
|
+
0xC50D,
|
|
193
|
+
0x34E2,
|
|
194
|
+
0x24C3,
|
|
195
|
+
0x14A0,
|
|
196
|
+
0x0481,
|
|
197
|
+
0x7466,
|
|
198
|
+
0x6447,
|
|
199
|
+
0x5424,
|
|
200
|
+
0x4405,
|
|
201
|
+
0xA7DB,
|
|
202
|
+
0xB7FA,
|
|
203
|
+
0x8799,
|
|
204
|
+
0x97B8,
|
|
205
|
+
0xE75F,
|
|
206
|
+
0xF77E,
|
|
207
|
+
0xC71D,
|
|
208
|
+
0xD73C,
|
|
209
|
+
0x26D3,
|
|
210
|
+
0x36F2,
|
|
211
|
+
0x0691,
|
|
212
|
+
0x16B0,
|
|
213
|
+
0x6657,
|
|
214
|
+
0x7676,
|
|
215
|
+
0x4615,
|
|
216
|
+
0x5634,
|
|
217
|
+
0xD94C,
|
|
218
|
+
0xC96D,
|
|
219
|
+
0xF90E,
|
|
220
|
+
0xE92F,
|
|
221
|
+
0x99C8,
|
|
222
|
+
0x89E9,
|
|
223
|
+
0xB98A,
|
|
224
|
+
0xA9AB,
|
|
225
|
+
0x5844,
|
|
226
|
+
0x4865,
|
|
227
|
+
0x7806,
|
|
228
|
+
0x6827,
|
|
229
|
+
0x18C0,
|
|
230
|
+
0x08E1,
|
|
231
|
+
0x3882,
|
|
232
|
+
0x28A3,
|
|
233
|
+
0xCB7D,
|
|
234
|
+
0xDB5C,
|
|
235
|
+
0xEB3F,
|
|
236
|
+
0xFB1E,
|
|
237
|
+
0x8BF9,
|
|
238
|
+
0x9BD8,
|
|
239
|
+
0xABBB,
|
|
240
|
+
0xBB9A,
|
|
241
|
+
0x4A75,
|
|
242
|
+
0x5A54,
|
|
243
|
+
0x6A37,
|
|
244
|
+
0x7A16,
|
|
245
|
+
0x0AF1,
|
|
246
|
+
0x1AD0,
|
|
247
|
+
0x2AB3,
|
|
248
|
+
0x3A92,
|
|
249
|
+
0xFD2E,
|
|
250
|
+
0xED0F,
|
|
251
|
+
0xDD6C,
|
|
252
|
+
0xCD4D,
|
|
253
|
+
0xBDAA,
|
|
254
|
+
0xAD8B,
|
|
255
|
+
0x9DE8,
|
|
256
|
+
0x8DC9,
|
|
257
|
+
0x7C26,
|
|
258
|
+
0x6C07,
|
|
259
|
+
0x5C64,
|
|
260
|
+
0x4C45,
|
|
261
|
+
0x3CA2,
|
|
262
|
+
0x2C83,
|
|
263
|
+
0x1CE0,
|
|
264
|
+
0x0CC1,
|
|
265
|
+
0xEF1F,
|
|
266
|
+
0xFF3E,
|
|
267
|
+
0xCF5D,
|
|
268
|
+
0xDF7C,
|
|
269
|
+
0xAF9B,
|
|
270
|
+
0xBFBA,
|
|
271
|
+
0x8FD9,
|
|
272
|
+
0x9FF8,
|
|
273
|
+
0x6E17,
|
|
274
|
+
0x7E36,
|
|
275
|
+
0x4E55,
|
|
276
|
+
0x5E74,
|
|
277
|
+
0x2E93,
|
|
278
|
+
0x3EB2,
|
|
279
|
+
0x0ED1,
|
|
280
|
+
0x1EF0,
|
|
281
|
+
]
|
|
282
|
+
|
|
27
283
|
|
|
28
284
|
class BleMessage:
|
|
29
285
|
"""Class for sending and recieving messages from Luba"""
|
|
@@ -44,15 +300,11 @@ class BleMessage:
|
|
|
44
300
|
mChecksum = False
|
|
45
301
|
mRequireAck = False
|
|
46
302
|
mConnectState = 0
|
|
47
|
-
mSendSequence: iter
|
|
48
|
-
mReadSequence: iter
|
|
49
|
-
mAck: queue
|
|
50
|
-
notification: BlufiNotifyData
|
|
51
303
|
|
|
52
304
|
def __init__(self, client: BleakClient) -> None:
|
|
53
305
|
self.client = client
|
|
54
|
-
self.mSendSequence =
|
|
55
|
-
self.mReadSequence =
|
|
306
|
+
self.mSendSequence = AtomicInteger(-1)
|
|
307
|
+
self.mReadSequence = AtomicInteger(-1)
|
|
56
308
|
self.mAck = queue.Queue()
|
|
57
309
|
self.notification = BlufiNotifyData()
|
|
58
310
|
|
|
@@ -64,7 +316,7 @@ class BleMessage:
|
|
|
64
316
|
hash_map = {"ctrl": 1}
|
|
65
317
|
await self.post_custom_data(self.get_json_string(bleOrderCmd.bleAlive, hash_map))
|
|
66
318
|
|
|
67
|
-
def get_json_string(self, cmd: int, hash_map: dict[str,
|
|
319
|
+
def get_json_string(self, cmd: int, hash_map: dict[str, int]) -> str:
|
|
68
320
|
jSONObject = {}
|
|
69
321
|
try:
|
|
70
322
|
jSONObject["cmd"] = cmd
|
|
@@ -78,7 +330,7 @@ class BleMessage:
|
|
|
78
330
|
print(e)
|
|
79
331
|
return ""
|
|
80
332
|
|
|
81
|
-
def
|
|
333
|
+
def clear_notification(self) -> None:
|
|
82
334
|
self.notification = None
|
|
83
335
|
self.notification = BlufiNotifyData()
|
|
84
336
|
|
|
@@ -87,15 +339,15 @@ class BleMessage:
|
|
|
87
339
|
|
|
88
340
|
async def send_device_info(self) -> None:
|
|
89
341
|
"""Currently not called"""
|
|
90
|
-
luba_msg =
|
|
91
|
-
msgtype=
|
|
92
|
-
sender=
|
|
93
|
-
rcver=
|
|
94
|
-
msgattr=
|
|
342
|
+
luba_msg = LubaMsg(
|
|
343
|
+
msgtype=MsgCmdType.ESP,
|
|
344
|
+
sender=MsgDevice.DEV_MOBILEAPP,
|
|
345
|
+
rcver=MsgDevice.DEV_COMM_ESP,
|
|
346
|
+
msgattr=MsgAttr.REQ,
|
|
95
347
|
seqs=1,
|
|
96
348
|
version=1,
|
|
97
349
|
subtype=1,
|
|
98
|
-
net=
|
|
350
|
+
net=DevNet(todev_ble_sync=1, todev_devinfo_req=DrvDevInfoReq()),
|
|
99
351
|
)
|
|
100
352
|
byte_arr = luba_msg.SerializeToString()
|
|
101
353
|
await self.post_custom_data_bytes(byte_arr)
|
|
@@ -132,7 +384,7 @@ class BleMessage:
|
|
|
132
384
|
await self.client.write_gatt_char(UUID_WRITE_CHARACTERISTIC, data, True)
|
|
133
385
|
|
|
134
386
|
def parseNotification(self, response: bytearray):
|
|
135
|
-
|
|
387
|
+
"""Parse notification data from BLE device."""
|
|
136
388
|
if response is None:
|
|
137
389
|
# Log.w(TAG, "parseNotification null data");
|
|
138
390
|
return -1
|
|
@@ -140,72 +392,70 @@ class BleMessage:
|
|
|
140
392
|
# if (this.mPrintDebug):
|
|
141
393
|
# Log.d(TAG, "parseNotification Notification= " + Arrays.toString(response));
|
|
142
394
|
# }
|
|
143
|
-
if len(response)
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
self.
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
# Log.w(TAG, "parseNotification data length less than 4");
|
|
208
|
-
return -2
|
|
395
|
+
if len(response) < 4:
|
|
396
|
+
_LOGGER.debug("parseNotification data length less than 4")
|
|
397
|
+
return -2
|
|
398
|
+
|
|
399
|
+
sequence = int(response[2]) # toInt
|
|
400
|
+
current_sequence = self.mReadSequence.get() & 255
|
|
401
|
+
if sequence == current_sequence:
|
|
402
|
+
# _LOGGER.debug(f"Received bluetooth data 1: {response.hex()}, object: {self}")
|
|
403
|
+
return 2
|
|
404
|
+
|
|
405
|
+
# Compare with the second counter, mod 255
|
|
406
|
+
if sequence != (self.mReadSequence.increment_and_get() & 255):
|
|
407
|
+
_LOGGER.debug(
|
|
408
|
+
"parseNotification read sequence wrong %s %s",
|
|
409
|
+
sequence,
|
|
410
|
+
self.mReadSequence.get(),
|
|
411
|
+
)
|
|
412
|
+
# Set the value for mReadSequence manually
|
|
413
|
+
self.mReadSequence.set(sequence)
|
|
414
|
+
|
|
415
|
+
# LogUtil.m7773e(self.mGatt.getDevice().getName() + "打印丢包率", self.mReadSequence_2 + "/" + self.mReadSequence_1);
|
|
416
|
+
pkt_type = int(response[0]) # toInt
|
|
417
|
+
pkgType = self._getPackageType(pkt_type)
|
|
418
|
+
subType = self._getSubType(pkt_type)
|
|
419
|
+
self.notification.setType(pkt_type)
|
|
420
|
+
self.notification.setPkgType(pkgType)
|
|
421
|
+
self.notification.setSubType(subType)
|
|
422
|
+
frameCtrl = int(response[1]) # toInt
|
|
423
|
+
# _LOGGER.debug("frame ctrl")
|
|
424
|
+
# _LOGGER.debug(frameCtrl)
|
|
425
|
+
# _LOGGER.debug(response)
|
|
426
|
+
# _LOGGER.debug(f"pktType {pkt_type} pkgType {pkgType} subType {subType}")
|
|
427
|
+
self.notification.setFrameCtrl(frameCtrl)
|
|
428
|
+
frameCtrlData = FrameCtrlData(frameCtrl)
|
|
429
|
+
dataLen = int(response[3]) # toInt specifies length of data
|
|
430
|
+
|
|
431
|
+
try:
|
|
432
|
+
dataBytes = response[4 : 4 + dataLen]
|
|
433
|
+
if frameCtrlData.isEncrypted():
|
|
434
|
+
_LOGGER.debug("is encrypted")
|
|
435
|
+
# BlufiAES aes = new BlufiAES(self.mAESKey, AES_TRANSFORMATION, generateAESIV(sequence));
|
|
436
|
+
# dataBytes = aes.decrypt(dataBytes);
|
|
437
|
+
# }
|
|
438
|
+
if frameCtrlData.isChecksum():
|
|
439
|
+
respChecksum1 = int(response[-1])
|
|
440
|
+
respChecksum2 = int(response[-2])
|
|
441
|
+
crc = self.calc_crc(self.calc_crc(0, bytes([sequence, dataLen])), dataBytes)
|
|
442
|
+
calcChecksum1 = (crc >> 8) & 255
|
|
443
|
+
calcChecksum2 = crc & 255
|
|
444
|
+
|
|
445
|
+
if respChecksum1 != calcChecksum1 or respChecksum2 != calcChecksum2:
|
|
446
|
+
_LOGGER.debug(
|
|
447
|
+
f"expect checksum: {respChecksum1}, {respChecksum2}\n"
|
|
448
|
+
f"received checksum: {calcChecksum1}, {calcChecksum2}"
|
|
449
|
+
)
|
|
450
|
+
return -4
|
|
451
|
+
|
|
452
|
+
data_offset = 2 if frameCtrlData.hasFrag() else 0
|
|
453
|
+
|
|
454
|
+
self.notification.addData(dataBytes, data_offset)
|
|
455
|
+
return 1 if frameCtrlData.hasFrag() else 0
|
|
456
|
+
except Exception as e:
|
|
457
|
+
_LOGGER.debug(e)
|
|
458
|
+
return -100
|
|
209
459
|
|
|
210
460
|
async def parseBlufiNotifyData(self, return_bytes: bool = False):
|
|
211
461
|
pkgType = self.notification.getPkgType()
|
|
@@ -245,14 +495,8 @@ class BleMessage:
|
|
|
245
495
|
# return;
|
|
246
496
|
case 19:
|
|
247
497
|
# # com/agilexrobotics/utils/EspBleUtil$BlufiCallbackMain.smali
|
|
248
|
-
luba_msg = parse_custom_data(data) # parse to protobuf message
|
|
249
|
-
|
|
250
|
-
if luba_msg.HasField("net"):
|
|
251
|
-
if luba_msg.net.HasField("toapp_wifi_iot_status"):
|
|
252
|
-
# await sleep(1.5)
|
|
253
|
-
_LOGGER.debug("sending ble sync")
|
|
254
|
-
# await self.send_todev_ble_sync(2)
|
|
255
|
-
return luba_msg
|
|
498
|
+
# luba_msg = parse_custom_data(data) # parse to protobuf message
|
|
499
|
+
return data
|
|
256
500
|
|
|
257
501
|
# private void parseCtrlData(int i, byte[] bArr) {
|
|
258
502
|
# if (i == 0) {
|
|
@@ -287,17 +531,17 @@ class BleMessage:
|
|
|
287
531
|
|
|
288
532
|
def receiveAck(self, expectAck: int) -> bool:
|
|
289
533
|
try:
|
|
290
|
-
ack =
|
|
534
|
+
ack = self.mAck.get()
|
|
291
535
|
return ack == expectAck
|
|
292
536
|
except Exception as err:
|
|
293
537
|
_LOGGER.debug(err)
|
|
294
538
|
return False
|
|
295
539
|
|
|
296
|
-
def
|
|
297
|
-
return
|
|
540
|
+
def generate_send_sequence(self) -> int:
|
|
541
|
+
return self.mSendSequence.increment_and_get() & 255
|
|
298
542
|
|
|
299
543
|
async def post_custom_data_bytes(self, data: bytes) -> None:
|
|
300
|
-
if data
|
|
544
|
+
if data is None:
|
|
301
545
|
return
|
|
302
546
|
type_val = self.getTypeValue(1, 19)
|
|
303
547
|
try:
|
|
@@ -306,6 +550,7 @@ class BleMessage:
|
|
|
306
550
|
# onPostCustomDataResult(status, data)
|
|
307
551
|
# _LOGGER.debug(suc)
|
|
308
552
|
except Exception as err:
|
|
553
|
+
await self.client.disconnect()
|
|
309
554
|
_LOGGER.debug(err)
|
|
310
555
|
|
|
311
556
|
async def post_custom_data(self, data_str: str) -> None:
|
|
@@ -338,7 +583,7 @@ class BleMessage:
|
|
|
338
583
|
return await self.post_contains_data(encrypt, checksum, require_ack, type_of, data)
|
|
339
584
|
|
|
340
585
|
async def post_non_data(self, encrypt: bool, checksum: bool, require_ack: bool, type_of: int) -> bool:
|
|
341
|
-
sequence = self.
|
|
586
|
+
sequence = self.generate_send_sequence()
|
|
342
587
|
postBytes = self.getPostBytes(type_of, encrypt, checksum, require_ack, False, sequence, None)
|
|
343
588
|
posted = await self.gatt_write(postBytes)
|
|
344
589
|
return posted and (not require_ack or self.receiveAck(sequence))
|
|
@@ -361,22 +606,26 @@ class BleMessage:
|
|
|
361
606
|
chunks.append(data[i : i + chunk_size])
|
|
362
607
|
for index, chunk in enumerate(chunks):
|
|
363
608
|
frag = index != len(chunks) - 1
|
|
364
|
-
sequence = self.
|
|
609
|
+
sequence = self.generate_send_sequence()
|
|
365
610
|
postBytes = self.getPostBytes(type_of, encrypt, checksum, require_ack, frag, sequence, chunk)
|
|
366
611
|
# _LOGGER.debug("sequence")
|
|
367
612
|
# _LOGGER.debug(sequence)
|
|
368
613
|
posted = await self.gatt_write(postBytes)
|
|
369
|
-
if posted
|
|
614
|
+
if posted is not None:
|
|
370
615
|
return False
|
|
371
616
|
|
|
372
617
|
if not frag:
|
|
373
618
|
return not require_ack or self.receiveAck(sequence)
|
|
374
619
|
|
|
620
|
+
if require_ack and not self.receiveAck(sequence):
|
|
621
|
+
return False
|
|
622
|
+
|
|
623
|
+
_LOGGER.debug("sleeping 0.01")
|
|
624
|
+
await sleep(0.01)
|
|
375
625
|
if require_ack and not self.receiveAck(sequence):
|
|
376
626
|
return False
|
|
377
627
|
else:
|
|
378
|
-
|
|
379
|
-
await sleep(0.01)
|
|
628
|
+
return True
|
|
380
629
|
|
|
381
630
|
def getPostBytes(
|
|
382
631
|
self,
|
|
@@ -396,8 +645,42 @@ class BleMessage:
|
|
|
396
645
|
byteOS.write(sequence.to_bytes(1, sys.byteorder))
|
|
397
646
|
byteOS.write(dataLength.to_bytes(1, sys.byteorder))
|
|
398
647
|
|
|
399
|
-
if data
|
|
648
|
+
if data is not None:
|
|
400
649
|
byteOS.write(data)
|
|
401
650
|
|
|
402
651
|
_LOGGER.debug(byteOS.getvalue())
|
|
403
652
|
return byteOS.getvalue()
|
|
653
|
+
|
|
654
|
+
@staticmethod
|
|
655
|
+
def calc_crc(initial: int, data: bytes | bytearray) -> int:
|
|
656
|
+
"""Calculate CRC value for given initial value and byte array.
|
|
657
|
+
|
|
658
|
+
Args:
|
|
659
|
+
initial: Initial CRC value
|
|
660
|
+
data: Bytes to calculate CRC for
|
|
661
|
+
|
|
662
|
+
Returns:
|
|
663
|
+
Calculated CRC value (16-bit)
|
|
664
|
+
|
|
665
|
+
Raises:
|
|
666
|
+
TypeError: If data is not bytes or bytearray
|
|
667
|
+
ValueError: If initial value is out of valid range
|
|
668
|
+
|
|
669
|
+
"""
|
|
670
|
+
if not isinstance(data, (bytes, bytearray)):
|
|
671
|
+
raise TypeError("Data must be bytes or bytearray")
|
|
672
|
+
|
|
673
|
+
if not 0 <= initial <= 0xFFFF:
|
|
674
|
+
raise ValueError("Initial value must be between 0 and 65535")
|
|
675
|
+
|
|
676
|
+
try:
|
|
677
|
+
crc = (~initial) & 0xFFFF
|
|
678
|
+
|
|
679
|
+
for byte in data:
|
|
680
|
+
crc = ((crc << 8) ^ CRC_TB[byte ^ (crc >> 8)]) & 0xFFFF
|
|
681
|
+
|
|
682
|
+
return (~crc) & 0xFFFF
|
|
683
|
+
|
|
684
|
+
except Exception as e:
|
|
685
|
+
_LOGGER.error("Error calculating CRC: %s", str(e))
|
|
686
|
+
raise
|