pymammotion 0.5.34__py3-none-any.whl → 0.5.41__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 +3 -3
- pymammotion/aliyun/cloud_gateway.py +106 -18
- pymammotion/aliyun/model/dev_by_account_response.py +198 -20
- pymammotion/data/model/device.py +1 -0
- pymammotion/data/model/device_config.py +1 -1
- pymammotion/data/model/enums.py +3 -1
- pymammotion/data/model/generate_route_information.py +2 -2
- pymammotion/data/model/hash_list.py +113 -33
- pymammotion/data/model/region_data.py +4 -4
- pymammotion/data/{state_manager.py → mower_state_manager.py} +17 -7
- pymammotion/homeassistant/__init__.py +3 -0
- pymammotion/homeassistant/mower_api.py +446 -0
- pymammotion/homeassistant/rtk_api.py +54 -0
- pymammotion/http/http.py +115 -4
- pymammotion/http/model/http.py +77 -2
- pymammotion/http/model/response_factory.py +10 -4
- pymammotion/mammotion/commands/mammotion_command.py +6 -0
- pymammotion/mammotion/commands/messages/navigation.py +10 -6
- pymammotion/mammotion/devices/__init__.py +27 -3
- pymammotion/mammotion/devices/base.py +16 -138
- pymammotion/mammotion/devices/mammotion.py +361 -204
- pymammotion/mammotion/devices/mammotion_bluetooth.py +7 -5
- pymammotion/mammotion/devices/mammotion_cloud.py +22 -74
- 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 +121 -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/mammotion_mqtt.py +132 -194
- pymammotion/mqtt/mqtt_models.py +66 -0
- pymammotion/proto/__init__.py +1 -1
- pymammotion/proto/mctrl_nav.proto +1 -1
- pymammotion/proto/mctrl_nav_pb2.py +1 -1
- pymammotion/proto/mctrl_nav_pb2.pyi +4 -4
- pymammotion/proto/mctrl_sys.proto +1 -1
- pymammotion/utility/device_type.py +88 -3
- pymammotion/utility/mur_mur_hash.py +132 -87
- {pymammotion-0.5.34.dist-info → pymammotion-0.5.41.dist-info}/METADATA +25 -31
- {pymammotion-0.5.34.dist-info → pymammotion-0.5.41.dist-info}/RECORD +54 -40
- {pymammotion-0.5.34.dist-info → pymammotion-0.5.41.dist-info}/WHEEL +1 -1
- {pymammotion-0.5.34.dist-info → pymammotion-0.5.41.dist-info/licenses}/LICENSE +0 -0
|
@@ -22,13 +22,31 @@ Luba2MiniProductKey = ["a1L5ZfJIxGl", "a1dCWYFLROK"]
|
|
|
22
22
|
|
|
23
23
|
YukaProductKey = ["a1kT0TlYEza", "a1IQV0BrnXb"]
|
|
24
24
|
|
|
25
|
-
YukaPlusProductKey = ["a1lNESu9VST"]
|
|
25
|
+
YukaPlusProductKey = ["a1lNESu9VST", "a1zAEzmvWDa"]
|
|
26
26
|
|
|
27
27
|
YukaMiniProductKey = ["a1BqmEWMRbX", "a1biqVGvxrE"]
|
|
28
28
|
|
|
29
29
|
RTKProductKey = ["a1qXkZ5P39W", "a1Nc68bGZzX"]
|
|
30
30
|
|
|
31
|
-
YukaMVProductKey = ["a1jFe8HzcDb"]
|
|
31
|
+
YukaMVProductKey = ["a1jFe8HzcDb", "a16cz0iXgUJ", "USpE46bNTC7", "pdA6uJrBfjz"]
|
|
32
|
+
|
|
33
|
+
LubaLDProductKey = ["a1jDMfG2Fgj", "a1vtZq9LUFS"]
|
|
34
|
+
|
|
35
|
+
LubaVAProductKey = ["a1Ce85210Be", "a1BBOJnnjb9"]
|
|
36
|
+
|
|
37
|
+
YukaMLProductKey = ["a1OWGO8WXbh", "a1s6znKxGvI"]
|
|
38
|
+
|
|
39
|
+
LubaMDProductKey = ["a1T6VTFTc0C", "a14iRDqMepW"]
|
|
40
|
+
|
|
41
|
+
LubaMBProductKey = ["a1pb9toor70"]
|
|
42
|
+
|
|
43
|
+
RTKNBProductKey = ["a1NfZqdSREf", "a1ZuQVL7UiN"]
|
|
44
|
+
|
|
45
|
+
LubaLAProductKey = ["CDYuKXTYrSP"]
|
|
46
|
+
|
|
47
|
+
YukaMN100ProductKey = ["NnbeYtaEUGE"]
|
|
48
|
+
|
|
49
|
+
Cm900ProductKey = ["zkRuTK9KsXG", "6DbgVh2Qs5m"]
|
|
32
50
|
|
|
33
51
|
|
|
34
52
|
class DeviceType(Enum):
|
|
@@ -47,7 +65,17 @@ class DeviceType(Enum):
|
|
|
47
65
|
LUBA_LD = (11, "Luba-LD", "HM431")
|
|
48
66
|
RTK3A0 = (12, "RBSA0", "RBS03A0")
|
|
49
67
|
RTK3A2 = (13, "RBSA2", "RBS03A2")
|
|
50
|
-
|
|
68
|
+
YUKA_MINIV = (14, "Yuka-MV", "MN231")
|
|
69
|
+
LUBA_VA = (15, "Luba-VA", "HM442")
|
|
70
|
+
YUKA_ML = (16, "Yuka-ML", "MN232")
|
|
71
|
+
LUBA_MD = (17, "Luba-MD", "HM433")
|
|
72
|
+
LUBA_LA = (18, "Luba-LA", "HM432")
|
|
73
|
+
SWIMMINGPOOL_S1 = (19, "Spino-S1", "Spino-S1")
|
|
74
|
+
SWIMMINGPOOL_E1 = (20, "Spino-E1", "Spino-E1")
|
|
75
|
+
YUKA_MN100 = (21, "Ezy-VT", "MN100")
|
|
76
|
+
RTKNB = (22, "NB", "NB")
|
|
77
|
+
LUBA_MB = (23, "Luba-MB", "HM434")
|
|
78
|
+
CM900 = (24, "Kumar-MK", "KM01")
|
|
51
79
|
|
|
52
80
|
def __init__(self, value: int, name: str, model: str) -> None:
|
|
53
81
|
self._value = value
|
|
@@ -112,6 +140,28 @@ class DeviceType(Enum):
|
|
|
112
140
|
return DeviceType.RTK3A0
|
|
113
141
|
elif value == 13:
|
|
114
142
|
return DeviceType.RTK3A2
|
|
143
|
+
elif value == 14:
|
|
144
|
+
return DeviceType.YUKA_MINIV
|
|
145
|
+
elif value == 15:
|
|
146
|
+
return DeviceType.LUBA_VA
|
|
147
|
+
elif value == 16:
|
|
148
|
+
return DeviceType.YUKA_ML
|
|
149
|
+
elif value == 17:
|
|
150
|
+
return DeviceType.LUBA_MD
|
|
151
|
+
elif value == 18:
|
|
152
|
+
return DeviceType.LUBA_LA
|
|
153
|
+
elif value == 19:
|
|
154
|
+
return DeviceType.SWIMMINGPOOL_S1
|
|
155
|
+
elif value == 20:
|
|
156
|
+
return DeviceType.SWIMMINGPOOL_E1
|
|
157
|
+
elif value == 21:
|
|
158
|
+
return DeviceType.YUKA_MN100
|
|
159
|
+
elif value == 22:
|
|
160
|
+
return DeviceType.RTKNB
|
|
161
|
+
elif value == 23:
|
|
162
|
+
return DeviceType.LUBA_MB
|
|
163
|
+
elif value == 24:
|
|
164
|
+
return DeviceType.CM900
|
|
115
165
|
else:
|
|
116
166
|
return DeviceType.UNKNOWN
|
|
117
167
|
|
|
@@ -156,6 +206,36 @@ class DeviceType(Enum):
|
|
|
156
206
|
return DeviceType.LUBA_YUKA
|
|
157
207
|
elif DeviceType.LUBA.get_name() in substring2 or DeviceType.contain_luba_product_key(product_key):
|
|
158
208
|
return DeviceType.LUBA
|
|
209
|
+
elif DeviceType.SPINO.get_name() in substring2:
|
|
210
|
+
return DeviceType.SPINO
|
|
211
|
+
elif DeviceType.RTK3A1.get_name() in substring2:
|
|
212
|
+
return DeviceType.RTK3A1
|
|
213
|
+
elif DeviceType.RTK3A0.get_name() in substring2:
|
|
214
|
+
return DeviceType.RTK3A0
|
|
215
|
+
elif DeviceType.RTK3A2.get_name() in substring2:
|
|
216
|
+
return DeviceType.RTK3A2
|
|
217
|
+
elif DeviceType.YUKA_MINIV.get_name() in substring2:
|
|
218
|
+
return DeviceType.YUKA_MINIV
|
|
219
|
+
elif DeviceType.LUBA_VA.get_name() in substring2:
|
|
220
|
+
return DeviceType.LUBA_VA
|
|
221
|
+
elif DeviceType.YUKA_ML.get_name() in substring2:
|
|
222
|
+
return DeviceType.YUKA_ML
|
|
223
|
+
elif DeviceType.LUBA_MD.get_name() in substring2:
|
|
224
|
+
return DeviceType.LUBA_MD
|
|
225
|
+
elif DeviceType.LUBA_LA.get_name() in substring2:
|
|
226
|
+
return DeviceType.LUBA_LA
|
|
227
|
+
elif DeviceType.SWIMMINGPOOL_S1.get_name() in substring2:
|
|
228
|
+
return DeviceType.SWIMMINGPOOL_S1
|
|
229
|
+
elif DeviceType.SWIMMINGPOOL_E1.get_name() in substring2:
|
|
230
|
+
return DeviceType.SWIMMINGPOOL_E1
|
|
231
|
+
elif DeviceType.YUKA_MN100.get_name() in substring2:
|
|
232
|
+
return DeviceType.YUKA_MN100
|
|
233
|
+
elif DeviceType.RTKNB.get_name() in substring2:
|
|
234
|
+
return DeviceType.RTKNB
|
|
235
|
+
elif DeviceType.LUBA_MB.get_name() in substring2:
|
|
236
|
+
return DeviceType.LUBA_MB
|
|
237
|
+
elif DeviceType.CM900.get_name() in substring2:
|
|
238
|
+
return DeviceType.CM900
|
|
159
239
|
else:
|
|
160
240
|
return DeviceType.UNKNOWN
|
|
161
241
|
except Exception:
|
|
@@ -252,6 +332,9 @@ class DeviceType(Enum):
|
|
|
252
332
|
or DeviceType.value_of_str(device_name).get_value() == DeviceType.YUKA_VP.get_value()
|
|
253
333
|
or DeviceType.value_of_str(device_name).get_value() == DeviceType.YUKA_MINI.get_value()
|
|
254
334
|
or DeviceType.value_of_str(device_name).get_value() == DeviceType.YUKA_MINI2.get_value()
|
|
335
|
+
or DeviceType.value_of_str(device_name).get_value() == DeviceType.YUKA_MINIV.get_value()
|
|
336
|
+
or DeviceType.value_of_str(device_name).get_value() == DeviceType.YUKA_ML.get_value()
|
|
337
|
+
or DeviceType.value_of_str(device_name).get_value() == DeviceType.YUKA_MN100.get_value()
|
|
255
338
|
)
|
|
256
339
|
|
|
257
340
|
@staticmethod
|
|
@@ -268,6 +351,7 @@ class DeviceType(Enum):
|
|
|
268
351
|
return (
|
|
269
352
|
DeviceType.value_of_str(device_name).get_value() == DeviceType.YUKA_MINI.get_value()
|
|
270
353
|
or DeviceType.value_of_str(device_name).get_value() == DeviceType.YUKA_MINI2.get_value()
|
|
354
|
+
or DeviceType.value_of_str(device_name).get_value() == DeviceType.YUKA_MINIV.get_value()
|
|
271
355
|
or DeviceType.value_of_str(device_name).get_value() == DeviceType.YUKA_VP.get_value()
|
|
272
356
|
or DeviceType.value_of_str(device_name).get_value() == DeviceType.LUBA_MN.get_value()
|
|
273
357
|
or DeviceType.value_of_str(device_name).get_value() == DeviceType.LUBA_VP.get_value()
|
|
@@ -301,6 +385,7 @@ class DeviceType(Enum):
|
|
|
301
385
|
or DeviceType.RTK3A0.get_value() == device_type.get_value()
|
|
302
386
|
or DeviceType.RTK3A1.get_value() == device_type.get_value()
|
|
303
387
|
or DeviceType.RTK3A2.get_value() == device_type.get_value()
|
|
388
|
+
or DeviceType.RTKNB.get_value() == device_type.get_value()
|
|
304
389
|
)
|
|
305
390
|
|
|
306
391
|
@staticmethod
|
|
@@ -2,113 +2,158 @@ import struct
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
class MurMurHashUtil:
|
|
5
|
+
MASK_32 = 0xFFFFFFFF
|
|
6
|
+
MULTIPLIER = 1540483477
|
|
7
|
+
|
|
5
8
|
@staticmethod
|
|
6
|
-
def get_unsigned_int(i):
|
|
7
|
-
|
|
9
|
+
def get_unsigned_int(i: int) -> int:
|
|
10
|
+
"""Convert signed int to unsigned (32-bit)"""
|
|
11
|
+
return i & MurMurHashUtil.MASK_32
|
|
8
12
|
|
|
9
13
|
@staticmethod
|
|
10
|
-
def hash(
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
def hash(data: bytes) -> int:
|
|
15
|
+
"""MurmurHash2 64-bit implementation"""
|
|
16
|
+
pos = 0
|
|
17
|
+
data_len = len(data)
|
|
14
18
|
|
|
15
|
-
|
|
16
|
-
remaining = remaining_bytes ^ 97
|
|
19
|
+
remaining = data_len ^ 97
|
|
17
20
|
j = 0
|
|
18
21
|
|
|
19
22
|
# Process 8 bytes at a time
|
|
20
|
-
while
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
23
|
+
while (data_len - pos) >= 8:
|
|
24
|
+
val1 = struct.unpack_from("<i", data, pos)[0]
|
|
25
|
+
pos += 4
|
|
26
|
+
|
|
27
|
+
unsigned_int_1 = MurMurHashUtil.get_unsigned_int(val1)
|
|
28
|
+
temp1 = (unsigned_int_1 * MurMurHashUtil.MULTIPLIER) & MurMurHashUtil.MASK_32
|
|
29
|
+
temp2 = (temp1 ^ (temp1 >> 24)) & MurMurHashUtil.MASK_32
|
|
30
|
+
temp3 = (temp2 * MurMurHashUtil.MULTIPLIER) & MurMurHashUtil.MASK_32
|
|
31
|
+
|
|
32
|
+
remaining = ((remaining * MurMurHashUtil.MULTIPLIER) & MurMurHashUtil.MASK_32) ^ temp3
|
|
33
|
+
remaining = remaining & MurMurHashUtil.MASK_32
|
|
34
|
+
|
|
35
|
+
val2 = struct.unpack_from("<i", data, pos)[0]
|
|
36
|
+
pos += 4
|
|
37
|
+
|
|
38
|
+
unsigned_int_2 = MurMurHashUtil.get_unsigned_int(val2)
|
|
39
|
+
temp1 = (unsigned_int_2 * MurMurHashUtil.MULTIPLIER) & MurMurHashUtil.MASK_32
|
|
40
|
+
temp2 = (temp1 ^ (temp1 >> 24)) & MurMurHashUtil.MASK_32
|
|
41
|
+
temp3 = (temp2 * MurMurHashUtil.MULTIPLIER) & MurMurHashUtil.MASK_32
|
|
42
|
+
|
|
43
|
+
j = ((j * MurMurHashUtil.MULTIPLIER) & MurMurHashUtil.MASK_32) ^ temp3
|
|
44
|
+
j = j & MurMurHashUtil.MASK_32
|
|
42
45
|
|
|
43
46
|
# Process remaining 4 bytes if available
|
|
44
|
-
if
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
j = (j ^ (
|
|
62
|
-
j = (
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
j = (j ^ ((MurMurHashUtil.get_unsigned_int(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
) &
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
47
|
+
if (data_len - pos) >= 4:
|
|
48
|
+
val = struct.unpack_from("<i", data, pos)[0]
|
|
49
|
+
pos += 4
|
|
50
|
+
|
|
51
|
+
unsigned_int_3 = MurMurHashUtil.get_unsigned_int(val)
|
|
52
|
+
temp1 = (unsigned_int_3 * MurMurHashUtil.MULTIPLIER) & MurMurHashUtil.MASK_32
|
|
53
|
+
temp2 = (temp1 ^ (temp1 >> 24)) & MurMurHashUtil.MASK_32
|
|
54
|
+
temp3 = (temp2 * MurMurHashUtil.MULTIPLIER) & MurMurHashUtil.MASK_32
|
|
55
|
+
|
|
56
|
+
remaining = ((remaining * MurMurHashUtil.MULTIPLIER) & MurMurHashUtil.MASK_32) ^ temp3
|
|
57
|
+
remaining = remaining & MurMurHashUtil.MASK_32
|
|
58
|
+
|
|
59
|
+
# Process tail bytes (1-3 bytes)
|
|
60
|
+
bytes_remaining = data_len - pos
|
|
61
|
+
|
|
62
|
+
if bytes_remaining == 1:
|
|
63
|
+
byte_val = data[pos] if data[pos] < 128 else data[pos] - 256
|
|
64
|
+
j = (j ^ (MurMurHashUtil.get_unsigned_int(byte_val) & 255)) & MurMurHashUtil.MASK_32
|
|
65
|
+
j = (j * MurMurHashUtil.MULTIPLIER) & MurMurHashUtil.MASK_32
|
|
66
|
+
|
|
67
|
+
elif bytes_remaining == 2:
|
|
68
|
+
byte_val1 = data[pos + 1] if data[pos + 1] < 128 else data[pos + 1] - 256
|
|
69
|
+
j = (j ^ ((MurMurHashUtil.get_unsigned_int(byte_val1) & 255) << 8)) & MurMurHashUtil.MASK_32
|
|
70
|
+
|
|
71
|
+
byte_val0 = data[pos] if data[pos] < 128 else data[pos] - 256
|
|
72
|
+
j = (j ^ (MurMurHashUtil.get_unsigned_int(byte_val0) & 255)) & MurMurHashUtil.MASK_32
|
|
73
|
+
j = (j * MurMurHashUtil.MULTIPLIER) & MurMurHashUtil.MASK_32
|
|
74
|
+
|
|
75
|
+
elif bytes_remaining == 3:
|
|
76
|
+
byte_val2 = data[pos + 2] if data[pos + 2] < 128 else data[pos + 2] - 256
|
|
77
|
+
j = (j ^ ((MurMurHashUtil.get_unsigned_int(byte_val2) & 255) << 16)) & MurMurHashUtil.MASK_32
|
|
78
|
+
|
|
79
|
+
byte_val1 = data[pos + 1] if data[pos + 1] < 128 else data[pos + 1] - 256
|
|
80
|
+
j = (j ^ ((MurMurHashUtil.get_unsigned_int(byte_val1) & 255) << 8)) & MurMurHashUtil.MASK_32
|
|
81
|
+
|
|
82
|
+
byte_val0 = data[pos] if data[pos] < 128 else data[pos] - 256
|
|
83
|
+
j = (j ^ (MurMurHashUtil.get_unsigned_int(byte_val0) & 255)) & MurMurHashUtil.MASK_32
|
|
84
|
+
j = (j * MurMurHashUtil.MULTIPLIER) & MurMurHashUtil.MASK_32
|
|
85
|
+
|
|
86
|
+
# Final avalanche
|
|
87
|
+
j4 = MurMurHashUtil.MULTIPLIER
|
|
88
|
+
|
|
89
|
+
j5 = remaining ^ (j >> 18)
|
|
90
|
+
j5 = (j5 & MurMurHashUtil.MASK_32) * j4
|
|
91
|
+
j5 = j5 & MurMurHashUtil.MASK_32
|
|
92
|
+
|
|
93
|
+
j6 = j ^ (j5 >> 22)
|
|
94
|
+
j6 = (j6 & MurMurHashUtil.MASK_32) * j4
|
|
95
|
+
j6 = j6 & MurMurHashUtil.MASK_32
|
|
96
|
+
|
|
97
|
+
j7 = j5 ^ (j6 >> 17)
|
|
98
|
+
j7 = (j7 & MurMurHashUtil.MASK_32) * j4
|
|
99
|
+
j7 = j7 & MurMurHashUtil.MASK_32
|
|
100
|
+
|
|
101
|
+
# Combine high and low parts
|
|
77
102
|
j8 = j7 << 32
|
|
78
103
|
|
|
79
|
-
|
|
104
|
+
low = j6 ^ (j7 >> 19)
|
|
105
|
+
low = (low & MurMurHashUtil.MASK_32) * j4
|
|
106
|
+
low = low & MurMurHashUtil.MASK_32
|
|
80
107
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
return
|
|
108
|
+
result = j8 | low
|
|
109
|
+
|
|
110
|
+
# Convert to signed 64-bit
|
|
111
|
+
if result > 0x7FFFFFFFFFFFFFFF:
|
|
112
|
+
result = result - 0x10000000000000000
|
|
113
|
+
|
|
114
|
+
return result
|
|
88
115
|
|
|
89
116
|
@staticmethod
|
|
90
|
-
def
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
for i in range(8):
|
|
94
|
-
result[7 - i] = (value >> (i * 8)) & 0xFF
|
|
95
|
-
return bytes(result)
|
|
117
|
+
def hash_string(s: str) -> int:
|
|
118
|
+
"""Hash a string using UTF-8 encoding"""
|
|
119
|
+
return MurMurHashUtil.hash(s.encode("utf-8"))
|
|
96
120
|
|
|
97
121
|
@staticmethod
|
|
98
122
|
def read_unsigned_long(value: int) -> int:
|
|
123
|
+
"""Convert to unsigned by masking with Long.MAX_VALUE"""
|
|
99
124
|
return value & 0x7FFFFFFFFFFFFFFF
|
|
100
125
|
|
|
101
126
|
@staticmethod
|
|
102
|
-
def
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
127
|
+
def hash_unsigned(data) -> int:
|
|
128
|
+
"""Get unsigned hash value
|
|
129
|
+
Can accept bytes or string
|
|
130
|
+
"""
|
|
131
|
+
if isinstance(data, str):
|
|
132
|
+
hash_val = MurMurHashUtil.hash_string(data)
|
|
133
|
+
else:
|
|
134
|
+
hash_val = MurMurHashUtil.hash(data)
|
|
109
135
|
|
|
110
|
-
return MurMurHashUtil.read_unsigned_long(
|
|
136
|
+
return MurMurHashUtil.read_unsigned_long(hash_val)
|
|
111
137
|
|
|
112
138
|
@staticmethod
|
|
113
|
-
def
|
|
114
|
-
|
|
139
|
+
def long_to_bytes(value: int) -> bytes:
|
|
140
|
+
"""Convert long to bytes exactly as Java does:
|
|
141
|
+
1. Pack as big-endian (ByteBuffer default)
|
|
142
|
+
2. Reverse all bytes
|
|
143
|
+
"""
|
|
144
|
+
if value < 0:
|
|
145
|
+
value = value & 0xFFFFFFFFFFFFFFFF
|
|
146
|
+
|
|
147
|
+
big_endian = struct.pack(">Q", value)
|
|
148
|
+
return big_endian[::-1]
|
|
149
|
+
|
|
150
|
+
@staticmethod
|
|
151
|
+
def hash_unsigned_list(values: list[int]) -> int:
|
|
152
|
+
"""Hash a list of long values"""
|
|
153
|
+
data = b""
|
|
154
|
+
|
|
155
|
+
for val in values:
|
|
156
|
+
data += MurMurHashUtil.long_to_bytes(val)
|
|
157
|
+
|
|
158
|
+
hash_val = MurMurHashUtil.hash(data)
|
|
159
|
+
return MurMurHashUtil.read_unsigned_long(hash_val)
|
|
@@ -1,34 +1,29 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: pymammotion
|
|
3
|
-
Version: 0.5.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
Requires-Python:
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
Requires-Dist:
|
|
15
|
-
Requires-Dist:
|
|
16
|
-
Requires-Dist:
|
|
17
|
-
Requires-Dist:
|
|
18
|
-
Requires-Dist:
|
|
19
|
-
Requires-Dist:
|
|
20
|
-
Requires-Dist:
|
|
21
|
-
Requires-Dist:
|
|
22
|
-
Requires-Dist:
|
|
23
|
-
Requires-Dist:
|
|
24
|
-
Requires-Dist:
|
|
25
|
-
Requires-Dist: jsonic
|
|
26
|
-
Requires-Dist:
|
|
27
|
-
Requires-Dist: numpy (>=1.26.0)
|
|
28
|
-
Requires-Dist: orjson (>=3.9.15,<4.0.0)
|
|
29
|
-
Requires-Dist: paho-mqtt (>=2.1.0,<3.0.0)
|
|
30
|
-
Requires-Dist: protobuf (>=4.23.1)
|
|
31
|
-
Requires-Dist: py-jsonic (>=0.0.2,<0.0.3)
|
|
3
|
+
Version: 0.5.41
|
|
4
|
+
Author: jLynx
|
|
5
|
+
Author-email: Michael Arthur <michael@jumblesoft.co.nz>
|
|
6
|
+
License-Expression: GPL-3.0
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Python: <4.0,>=3.12
|
|
9
|
+
Requires-Dist: aiohttp>=3.9.1
|
|
10
|
+
Requires-Dist: alibabacloud-apigateway-util<0.0.3,>=0.0.2
|
|
11
|
+
Requires-Dist: alibabacloud-iot-api-gateway<0.0.5,>=0.0.4
|
|
12
|
+
Requires-Dist: alicloud-gateway-iot<2,>=1.0.0
|
|
13
|
+
Requires-Dist: async-timeout<5,>=4.0.3
|
|
14
|
+
Requires-Dist: betterproto2<0.9,>=0.8.0
|
|
15
|
+
Requires-Dist: bleak-retry-connector>=3.5.0
|
|
16
|
+
Requires-Dist: bleak>=0.21.0
|
|
17
|
+
Requires-Dist: crcmod~=1.7
|
|
18
|
+
Requires-Dist: cryptography>=43.0.1
|
|
19
|
+
Requires-Dist: jsonic<2,>=1.0.0
|
|
20
|
+
Requires-Dist: mashumaro~=3.13
|
|
21
|
+
Requires-Dist: numpy>=1.26.0
|
|
22
|
+
Requires-Dist: orjson<4,>=3.9.15
|
|
23
|
+
Requires-Dist: paho-mqtt<3,>=2.1.0
|
|
24
|
+
Requires-Dist: protobuf>=4.23.1
|
|
25
|
+
Requires-Dist: py-jsonic<0.0.3,>=0.0.2
|
|
26
|
+
Requires-Dist: pyjwt>=2.10.1
|
|
32
27
|
Description-Content-Type: text/markdown
|
|
33
28
|
|
|
34
29
|
# PyMammotion - Python API for Mammotion Mowers [](https://discord.gg/vpZdWhJX8x)
|
|
@@ -97,4 +92,3 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
|
|
|
97
92
|
|
|
98
93
|
The trademarks "Mammotion," "Luba," and "Yuka" referenced herein are registered trademarks of their respective owners. The author of this software repository is not affiliated with, endorsed by, or connected to these trademark owners in any way.
|
|
99
94
|
|
|
100
|
-
|