pymammotion 0.4.9__py3-none-any.whl → 0.4.11__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/aliyun/cloud_gateway.py +15 -3
- pymammotion/data/model/device.py +2 -0
- pymammotion/data/model/hash_list.py +49 -24
- pymammotion/mammotion/commands/abstract_message.py +4 -0
- pymammotion/mammotion/commands/mammotion_command.py +2 -1
- pymammotion/mammotion/commands/messages/driver.py +2 -2
- pymammotion/mammotion/commands/messages/media.py +2 -2
- pymammotion/mammotion/commands/messages/navigation.py +2 -2
- pymammotion/mammotion/commands/messages/network.py +3 -4
- pymammotion/mammotion/commands/messages/ota.py +5 -3
- pymammotion/mammotion/commands/messages/system.py +9 -10
- pymammotion/mammotion/commands/messages/video.py +2 -2
- pymammotion/mammotion/devices/base.py +7 -6
- pymammotion/mammotion/devices/mammotion_bluetooth.py +1 -1
- pymammotion/mammotion/devices/mammotion_cloud.py +11 -4
- pymammotion/mqtt/mammotion_mqtt.py +25 -0
- pymammotion/proto/__init__.py +1 -1
- {pymammotion-0.4.9.dist-info → pymammotion-0.4.11.dist-info}/METADATA +1 -2
- {pymammotion-0.4.9.dist-info → pymammotion-0.4.11.dist-info}/RECORD +21 -21
- {pymammotion-0.4.9.dist-info → pymammotion-0.4.11.dist-info}/LICENSE +0 -0
- {pymammotion-0.4.9.dist-info → pymammotion-0.4.11.dist-info}/WHEEL +0 -0
@@ -46,6 +46,10 @@ MOVE_HEADERS = (
|
|
46
46
|
class SetupException(Exception):
|
47
47
|
"""Raise when mqtt expires token or token is invalid."""
|
48
48
|
|
49
|
+
def __init__(self, *args: object) -> None:
|
50
|
+
super().__init__(args)
|
51
|
+
self.iot_id = args[1]
|
52
|
+
|
49
53
|
|
50
54
|
class AuthRefreshException(Exception):
|
51
55
|
"""Raise exception when library cannot refresh token."""
|
@@ -54,6 +58,10 @@ class AuthRefreshException(Exception):
|
|
54
58
|
class DeviceOfflineException(Exception):
|
55
59
|
"""Raise exception when device is offline."""
|
56
60
|
|
61
|
+
def __init__(self, *args: object) -> None:
|
62
|
+
super().__init__(args)
|
63
|
+
self.iot_id = args[1]
|
64
|
+
|
57
65
|
|
58
66
|
class NoConnectionException(UnretryableException):
|
59
67
|
"""Raise exception when device is unreachable."""
|
@@ -62,6 +70,10 @@ class NoConnectionException(UnretryableException):
|
|
62
70
|
class GatewayTimeoutException(Exception):
|
63
71
|
"""Raise exception when the gateway times out."""
|
64
72
|
|
73
|
+
def __init__(self, *args: object) -> None:
|
74
|
+
super().__init__(args)
|
75
|
+
self.iot_id = args[1]
|
76
|
+
|
65
77
|
|
66
78
|
class LoginException(Exception):
|
67
79
|
"""Raise exception when library cannot log in."""
|
@@ -696,14 +708,14 @@ class CloudIOTGateway:
|
|
696
708
|
)
|
697
709
|
if response_body_dict.get("code") == 20056:
|
698
710
|
logger.debug("Gateway timeout.")
|
699
|
-
raise GatewayTimeoutException(response_body_dict.get("code"))
|
711
|
+
raise GatewayTimeoutException(response_body_dict.get("code"), iot_id)
|
700
712
|
|
701
713
|
if response_body_dict.get("code") == 29003:
|
702
714
|
logger.debug(self._session_by_authcode_response.data.identityId)
|
703
715
|
self.sign_out()
|
704
|
-
raise SetupException(response_body_dict.get("code"))
|
716
|
+
raise SetupException(response_body_dict.get("code"), iot_id)
|
705
717
|
if response_body_dict.get("code") == 6205:
|
706
|
-
raise DeviceOfflineException(response_body_dict.get("code"))
|
718
|
+
raise DeviceOfflineException(response_body_dict.get("code"), iot_id)
|
707
719
|
|
708
720
|
return message_id
|
709
721
|
|
pymammotion/data/model/device.py
CHANGED
@@ -92,6 +92,8 @@ class MowingDevice(DataClassORJSONMixin):
|
|
92
92
|
self.location.work_zone = (
|
93
93
|
location.zone_hash if self.report_data.dev.sys_status == WorkMode.MODE_WORKING else 0
|
94
94
|
)
|
95
|
+
if location.bol_hash:
|
96
|
+
self.map.bol_hash = location.bol_hash
|
95
97
|
|
96
98
|
if toapp_report_data.fw_info:
|
97
99
|
self.update_device_firmwares(toapp_report_data.fw_info)
|
@@ -3,7 +3,7 @@ from enum import IntEnum
|
|
3
3
|
|
4
4
|
from mashumaro.mixins.orjson import DataClassORJSONMixin
|
5
5
|
|
6
|
-
from pymammotion.proto import NavGetCommDataAck, SvgMessageAckT
|
6
|
+
from pymammotion.proto import NavGetCommDataAck, NavGetHashListAck, SvgMessageAckT
|
7
7
|
|
8
8
|
|
9
9
|
class PathType(IntEnum):
|
@@ -78,8 +78,9 @@ class SvgMessage(DataClassORJSONMixin):
|
|
78
78
|
|
79
79
|
@dataclass
|
80
80
|
class FrameList(DataClassORJSONMixin):
|
81
|
-
total_frame: int
|
82
|
-
|
81
|
+
total_frame: int = 0
|
82
|
+
sub_cmd: int = 0
|
83
|
+
data: list[NavGetCommData | SvgMessage] = field(default_factory=list)
|
83
84
|
|
84
85
|
|
85
86
|
@dataclass(eq=False, repr=False)
|
@@ -100,6 +101,7 @@ class NavGetHashListData(DataClassORJSONMixin):
|
|
100
101
|
@dataclass
|
101
102
|
class RootHashList(DataClassORJSONMixin):
|
102
103
|
total_frame: int = 0
|
104
|
+
sub_cmd: int = 0
|
103
105
|
data: list[NavGetHashListData] = field(default_factory=list)
|
104
106
|
|
105
107
|
|
@@ -118,12 +120,13 @@ class HashList(DataClassORJSONMixin):
|
|
118
120
|
hashlist for all our hashIDs for verification
|
119
121
|
"""
|
120
122
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
123
|
+
bol_hash: str = ""
|
124
|
+
root_hash_lists: list[RootHashList] = field(default_factory=list)
|
125
|
+
area: dict[int, FrameList] = field(default_factory=dict) # type 0
|
126
|
+
path: dict[int, FrameList] = field(default_factory=dict) # type 2
|
127
|
+
obstacle: dict[int, FrameList] = field(default_factory=dict) # type 1
|
128
|
+
dump: dict[int, FrameList] = field(default_factory=dict) # type 12?
|
129
|
+
svg: dict[int, FrameList] = field(default_factory=dict) # type 13
|
127
130
|
area_name: list[AreaHashNameList] = field(default_factory=list)
|
128
131
|
|
129
132
|
def update_hash_lists(self, hashlist: list[int]) -> None:
|
@@ -135,37 +138,59 @@ class HashList(DataClassORJSONMixin):
|
|
135
138
|
|
136
139
|
@property
|
137
140
|
def hashlist(self) -> list[int]:
|
138
|
-
if
|
141
|
+
if not self.root_hash_lists:
|
139
142
|
return []
|
140
|
-
|
143
|
+
# Combine data_couple from all RootHashLists
|
144
|
+
return [i for root_list in self.root_hash_lists for obj in root_list.data for i in obj.data_couple]
|
141
145
|
|
142
146
|
@property
|
143
147
|
def missing_hashlist(self) -> list[int]:
|
144
148
|
"""Return missing hashlist."""
|
149
|
+
all_hash_ids = set(self.area.keys()).union(
|
150
|
+
self.path.keys(), self.obstacle.keys(), self.dump.keys(), self.svg.keys()
|
151
|
+
)
|
145
152
|
return [
|
146
153
|
i
|
147
|
-
for
|
154
|
+
for root_list in self.root_hash_lists
|
155
|
+
for obj in root_list.data
|
148
156
|
for i in obj.data_couple
|
149
|
-
if
|
150
|
-
not in set(self.area.keys()).union(
|
151
|
-
self.path.keys(), self.obstacle.keys(), self.dump.keys(), self.svg.keys()
|
152
|
-
)
|
157
|
+
if i not in all_hash_ids
|
153
158
|
]
|
154
159
|
|
155
160
|
def update_root_hash_list(self, hash_list: NavGetHashListData) -> None:
|
156
|
-
|
157
|
-
|
158
|
-
|
161
|
+
target_root_list = next(
|
162
|
+
(
|
163
|
+
rhl
|
164
|
+
for rhl in self.root_hash_lists
|
165
|
+
if rhl.total_frame == hash_list.total_frame and rhl.sub_cmd == hash_list.sub_cmd
|
166
|
+
),
|
167
|
+
None,
|
168
|
+
)
|
169
|
+
|
170
|
+
if target_root_list is None:
|
171
|
+
# Create new RootHashList if none exists for this total_frame
|
172
|
+
new_root_list = RootHashList(total_frame=hash_list.total_frame, sub_cmd=hash_list.sub_cmd, data=[hash_list])
|
173
|
+
self.root_hash_lists.append(new_root_list)
|
174
|
+
return
|
175
|
+
|
176
|
+
for index, obj in enumerate(target_root_list.data):
|
159
177
|
if obj.current_frame == hash_list.current_frame:
|
160
178
|
# Replace the item if current_frame matches
|
161
|
-
|
179
|
+
target_root_list.data[index] = hash_list
|
162
180
|
return
|
163
181
|
|
164
182
|
# If no match was found, append the new item
|
165
|
-
|
166
|
-
|
167
|
-
def missing_hash_frame(self) -> list[int]:
|
168
|
-
|
183
|
+
target_root_list.data.append(hash_list)
|
184
|
+
|
185
|
+
def missing_hash_frame(self, hash_ack: NavGetHashListAck) -> list[int]:
|
186
|
+
"""Returns a combined list of all missing frames across all RootHashLists."""
|
187
|
+
missing_frames = []
|
188
|
+
filtered_lists = [rl for rl in self.root_hash_lists if rl.sub_cmd == hash_ack.sub_cmd]
|
189
|
+
for root_list in filtered_lists:
|
190
|
+
missing = self._find_missing_frames(root_list)
|
191
|
+
if missing:
|
192
|
+
missing_frames.extend(missing)
|
193
|
+
return missing_frames
|
169
194
|
|
170
195
|
def missing_frame(self, hash_data: NavGetCommDataAck | SvgMessageAckT) -> list[int]:
|
171
196
|
if hash_data.type == PathType.AREA:
|
@@ -1,10 +1,14 @@
|
|
1
1
|
from abc import abstractmethod
|
2
2
|
|
3
|
+
from pymammotion.bluetooth.model.atomic_integer import AtomicInteger
|
3
4
|
from pymammotion.proto import MsgCmdType, MsgDevice
|
4
5
|
from pymammotion.utility.device_type import DeviceType
|
5
6
|
|
6
7
|
|
7
8
|
class AbstractMessage:
|
9
|
+
seqs = AtomicInteger(0)
|
10
|
+
user_account: int = 1
|
11
|
+
|
8
12
|
@abstractmethod
|
9
13
|
def get_device_name(self) -> str:
|
10
14
|
"""Get device name."""
|
@@ -13,9 +13,10 @@ class MammotionCommand(
|
|
13
13
|
):
|
14
14
|
"""MQTT commands for Luba."""
|
15
15
|
|
16
|
-
def __init__(self, device_name: str) -> None:
|
16
|
+
def __init__(self, device_name: str, user_account: int) -> None:
|
17
17
|
self._device_name = device_name
|
18
18
|
self._product_key = ""
|
19
|
+
self.user_account = user_account
|
19
20
|
|
20
21
|
def get_device_name(self) -> str:
|
21
22
|
"""Get device name."""
|
@@ -29,9 +29,9 @@ class MessageDriver(AbstractMessage, ABC):
|
|
29
29
|
rcver=self.get_msg_device(MsgCmdType.EMBED_DRIVER, MsgDevice.DEV_MAINCTL),
|
30
30
|
msgattr=MsgAttr.REQ,
|
31
31
|
timestamp=round(time.time() * 1000),
|
32
|
-
seqs=
|
32
|
+
seqs=self.seqs.increment_and_get() & 255,
|
33
33
|
version=1,
|
34
|
-
subtype=
|
34
|
+
subtype=self.user_account,
|
35
35
|
driver=driver,
|
36
36
|
).SerializeToString()
|
37
37
|
|
@@ -12,9 +12,9 @@ class MessageMedia(AbstractMessage, ABC):
|
|
12
12
|
sender=MsgDevice.DEV_MOBILEAPP,
|
13
13
|
rcver=self.get_msg_device(MsgCmdType.MUL, MsgDevice.SOC_MODULE_MULTIMEDIA),
|
14
14
|
msgattr=MsgAttr.REQ,
|
15
|
-
seqs=
|
15
|
+
seqs=self.seqs.increment_and_get() & 255,
|
16
16
|
version=1,
|
17
|
-
subtype=
|
17
|
+
subtype=self.user_account,
|
18
18
|
mul=mul,
|
19
19
|
)
|
20
20
|
|
@@ -39,9 +39,9 @@ class MessageNavigation(AbstractMessage, ABC):
|
|
39
39
|
sender=MsgDevice.DEV_MOBILEAPP,
|
40
40
|
rcver=self.get_msg_device(MsgCmdType.NAV, MsgDevice.DEV_MAINCTL),
|
41
41
|
msgattr=MsgAttr.REQ,
|
42
|
-
seqs=
|
42
|
+
seqs=self.seqs.increment_and_get() & 255,
|
43
43
|
version=1,
|
44
|
-
subtype=
|
44
|
+
subtype=self.user_account,
|
45
45
|
nav=build,
|
46
46
|
timestamp=round(time.time() * 1000),
|
47
47
|
)
|
@@ -31,16 +31,15 @@ from pymammotion.proto import (
|
|
31
31
|
class MessageNetwork(AbstractMessage, ABC):
|
32
32
|
messageNavigation: MessageNavigation = MessageNavigation()
|
33
33
|
|
34
|
-
|
35
|
-
def send_order_msg_net(build: DevNet) -> bytes:
|
34
|
+
def send_order_msg_net(self, build: DevNet) -> bytes:
|
36
35
|
luba_msg = LubaMsg(
|
37
36
|
msgtype=MsgCmdType.ESP,
|
38
37
|
sender=MsgDevice.DEV_MOBILEAPP,
|
39
38
|
rcver=MsgDevice.DEV_COMM_ESP,
|
40
39
|
msgattr=MsgAttr.REQ,
|
41
|
-
seqs=
|
40
|
+
seqs=self.seqs.increment_and_get() & 255,
|
42
41
|
version=1,
|
43
|
-
subtype=
|
42
|
+
subtype=self.user_account,
|
44
43
|
net=build,
|
45
44
|
timestamp=round(time.time() * 1000),
|
46
45
|
)
|
@@ -6,15 +6,17 @@ from pymammotion.proto import GetInfoReq, InfoType, LubaMsg, MctlOta, MsgAttr, M
|
|
6
6
|
|
7
7
|
|
8
8
|
class MessageOta(AbstractMessage, ABC):
|
9
|
+
"""Message OTA class."""
|
10
|
+
|
9
11
|
def send_order_msg_ota(self, ota):
|
10
12
|
luba_msg = LubaMsg(
|
11
13
|
msgtype=MsgCmdType.EMBED_OTA,
|
12
14
|
sender=MsgDevice.DEV_MOBILEAPP,
|
13
15
|
rcver=self.get_msg_device(MsgCmdType.EMBED_OTA, MsgDevice.DEV_MAINCTL),
|
14
|
-
msgattr=MsgAttr.
|
15
|
-
seqs=
|
16
|
+
msgattr=MsgAttr.REQ,
|
17
|
+
seqs=self.seqs.increment_and_get() & 255,
|
16
18
|
version=1,
|
17
|
-
subtype=
|
19
|
+
subtype=self.user_account,
|
18
20
|
ota=ota,
|
19
21
|
)
|
20
22
|
|
@@ -36,25 +36,24 @@ class MessageSystem(AbstractMessage, ABC):
|
|
36
36
|
sender=MsgDevice.DEV_MOBILEAPP,
|
37
37
|
rcver=self.get_msg_device(MsgCmdType.EMBED_SYS, MsgDevice.DEV_MAINCTL),
|
38
38
|
sys=sys,
|
39
|
-
seqs=
|
39
|
+
seqs=self.seqs.increment_and_get() & 255,
|
40
40
|
version=1,
|
41
|
-
subtype=
|
41
|
+
subtype=self.user_account,
|
42
42
|
timestamp=round(time.time() * 1000),
|
43
43
|
)
|
44
44
|
|
45
45
|
return luba_msg.SerializeToString()
|
46
46
|
|
47
|
-
|
48
|
-
def send_order_msg_sys_legacy(sys) -> bytes:
|
47
|
+
def send_order_msg_sys_legacy(self, sys) -> bytes:
|
49
48
|
luba_msg = LubaMsg(
|
50
49
|
msgtype=MsgCmdType.EMBED_SYS,
|
51
50
|
msgattr=MsgAttr.REQ,
|
52
51
|
sender=MsgDevice.DEV_MOBILEAPP,
|
53
52
|
rcver=MsgDevice.DEV_MAINCTL,
|
54
53
|
sys=sys,
|
55
|
-
seqs=
|
54
|
+
seqs=self.seqs.increment_and_get() & 255,
|
56
55
|
version=1,
|
57
|
-
subtype=
|
56
|
+
subtype=self.user_account,
|
58
57
|
timestamp=round(time.time() * 1000),
|
59
58
|
)
|
60
59
|
|
@@ -315,9 +314,9 @@ class MessageSystem(AbstractMessage, ABC):
|
|
315
314
|
sender=MsgDevice.DEV_MOBILEAPP,
|
316
315
|
rcver=MsgDevice.DEV_MAINCTL,
|
317
316
|
msgattr=MsgAttr.REQ,
|
318
|
-
seqs=
|
317
|
+
seqs=self.seqs.increment_and_get() & 255,
|
319
318
|
version=1,
|
320
|
-
subtype=
|
319
|
+
subtype=self.user_account,
|
321
320
|
sys=mctl_sys,
|
322
321
|
timestamp=round(time.time() * 1000),
|
323
322
|
)
|
@@ -351,9 +350,9 @@ class MessageSystem(AbstractMessage, ABC):
|
|
351
350
|
sender=MsgDevice.DEV_MOBILEAPP,
|
352
351
|
rcver=MsgDevice.DEV_MAINCTL,
|
353
352
|
msgattr=MsgAttr.REQ,
|
354
|
-
seqs=
|
353
|
+
seqs=self.seqs.increment_and_get() & 255,
|
355
354
|
version=1,
|
356
|
-
subtype=
|
355
|
+
subtype=self.user_account,
|
357
356
|
sys=mctl_sys,
|
358
357
|
timestamp=round(time.time() * 1000),
|
359
358
|
)
|
@@ -15,9 +15,9 @@ class MessageVideo(AbstractMessage, ABC):
|
|
15
15
|
sender=MsgDevice.DEV_MOBILEAPP,
|
16
16
|
rcver=self.get_msg_device(MsgCmdType.MUL, MsgDevice.SOC_MODULE_MULTIMEDIA),
|
17
17
|
mul=mul,
|
18
|
-
seqs=
|
18
|
+
seqs=self.seqs.increment_and_get() & 255,
|
19
19
|
version=1,
|
20
|
-
subtype=
|
20
|
+
subtype=self.user_account,
|
21
21
|
timestamp=round(time.time() * 1000),
|
22
22
|
)
|
23
23
|
|
@@ -45,18 +45,18 @@ class MammotionBaseDevice:
|
|
45
45
|
|
46
46
|
async def datahash_response(self, hash_ack: NavGetHashListAck) -> None:
|
47
47
|
"""Handle datahash responses."""
|
48
|
-
current_frame = hash_ack.current_frame
|
49
48
|
|
50
|
-
missing_frames = self.mower.map.missing_hash_frame()
|
49
|
+
missing_frames = self.mower.map.missing_hash_frame(hash_ack)
|
51
50
|
if len(missing_frames) == 0:
|
52
51
|
if len(self.mower.map.missing_hashlist) > 0:
|
53
52
|
data_hash = self.mower.map.missing_hashlist.pop()
|
54
53
|
return await self.queue_command("synchronize_hash_data", hash_num=data_hash)
|
55
54
|
return
|
56
55
|
|
57
|
-
|
58
|
-
|
59
|
-
|
56
|
+
for frame in missing_frames:
|
57
|
+
await self.queue_command(
|
58
|
+
"get_hash_response", sub_cmd=hash_ack.sub_cmd, total_frame=hash_ack.total_frame, current_frame=frame - 1
|
59
|
+
)
|
60
60
|
|
61
61
|
async def commdata_response(self, common_data: NavGetCommDataAck | SvgMessageAckT) -> None:
|
62
62
|
"""Handle common data responses."""
|
@@ -80,6 +80,7 @@ class MammotionBaseDevice:
|
|
80
80
|
region_data.hash = common_data.data_hash if isinstance(common_data, SvgMessageAckT) else common_data.hash
|
81
81
|
region_data.action = common_data.action if isinstance(common_data, NavGetCommDataAck) else None
|
82
82
|
region_data.type = common_data.type
|
83
|
+
region_data.sub_cmd = common_data.sub_cmd
|
83
84
|
region_data.total_frame = total_frame
|
84
85
|
region_data.current_frame = current_frame
|
85
86
|
await self.queue_command("get_regional_data", regional_data=region_data)
|
@@ -210,7 +211,6 @@ class MammotionBaseDevice:
|
|
210
211
|
await self.queue_command("read_plan", sub_cmd=2, plan_index=0)
|
211
212
|
|
212
213
|
await self.queue_command("get_all_boundary_hash_list", sub_cmd=0)
|
213
|
-
await self.queue_command("get_hash_response", total_frame=1, current_frame=1)
|
214
214
|
if len(self.mower.map.missing_hashlist) > 0:
|
215
215
|
data_hash = self.mower.map.missing_hashlist.pop()
|
216
216
|
await self.queue_command("synchronize_hash_data", hash_num=data_hash)
|
@@ -218,6 +218,7 @@ class MammotionBaseDevice:
|
|
218
218
|
# sub_cmd 3 is job hashes??
|
219
219
|
# sub_cmd 4 is dump location (yuka)
|
220
220
|
# jobs list
|
221
|
+
#
|
221
222
|
# hash_list_result = await self._send_command_with_args("get_all_boundary_hash_list", sub_cmd=3)
|
222
223
|
|
223
224
|
async def async_read_settings(self) -> None:
|
@@ -82,7 +82,7 @@ class MammotionBaseBLEDevice(MammotionBaseDevice):
|
|
82
82
|
self._write_char: BleakGATTCharacteristic | int | str | UUID = 0
|
83
83
|
self._disconnect_timer: asyncio.TimerHandle | None = None
|
84
84
|
self._message: BleMessage | None = None
|
85
|
-
self._commands: MammotionCommand = MammotionCommand(device.name)
|
85
|
+
self._commands: MammotionCommand = MammotionCommand(device.name, 1)
|
86
86
|
self.command_queue = asyncio.Queue()
|
87
87
|
self._expected_disconnect = False
|
88
88
|
self._connect_lock = asyncio.Lock()
|
@@ -164,7 +164,10 @@ class MammotionBaseCloudDevice(MammotionBaseDevice):
|
|
164
164
|
self.iot_id = cloud_device.iotId
|
165
165
|
self.device = cloud_device
|
166
166
|
self._command_futures = {}
|
167
|
-
self._commands: MammotionCommand = MammotionCommand(
|
167
|
+
self._commands: MammotionCommand = MammotionCommand(
|
168
|
+
cloud_device.deviceName,
|
169
|
+
int(mqtt.cloud_client.mammotion_http.response.data.get("userInformation").get("userAccount")),
|
170
|
+
)
|
168
171
|
self.currentID = ""
|
169
172
|
self._mqtt.mqtt_message_event.add_subscribers(self._parse_message_for_device)
|
170
173
|
self._mqtt.mqtt_properties_event.add_subscribers(self._parse_message_properties_for_device)
|
@@ -219,6 +222,7 @@ class MammotionBaseCloudDevice(MammotionBaseDevice):
|
|
219
222
|
"""Stop all tasks and disconnect."""
|
220
223
|
if self._ble_sync_task:
|
221
224
|
self._ble_sync_task.cancel()
|
225
|
+
# self._mqtt._mqtt_client.unsubscribe()
|
222
226
|
self.stopped = True
|
223
227
|
|
224
228
|
async def start(self) -> None:
|
@@ -227,7 +231,10 @@ class MammotionBaseCloudDevice(MammotionBaseDevice):
|
|
227
231
|
await self.run_periodic_sync_task()
|
228
232
|
self.stopped = False
|
229
233
|
if not self.mqtt.is_connected():
|
230
|
-
|
234
|
+
loop = asyncio.get_running_loop()
|
235
|
+
await loop.run_in_executor(None, self.mqtt.connect_async)
|
236
|
+
# else:
|
237
|
+
# self.mqtt._mqtt_client.thing_on_thing_enable(None)
|
231
238
|
|
232
239
|
async def _ble_sync(self) -> None:
|
233
240
|
command_bytes = self._commands.send_todev_ble_sync(3)
|
@@ -325,9 +332,9 @@ class MammotionBaseCloudDevice(MammotionBaseDevice):
|
|
325
332
|
fut: MammotionFuture = self.dequeue_by_iot_id(self._mqtt.waiting_queue, self.iot_id)
|
326
333
|
if fut is None:
|
327
334
|
return
|
328
|
-
while fut.fut.cancelled() and len(self._mqtt.waiting_queue) > 0:
|
335
|
+
while fut is None or fut.fut.cancelled() and len(self._mqtt.waiting_queue) > 0:
|
329
336
|
fut = self.dequeue_by_iot_id(self._mqtt.waiting_queue, self.iot_id)
|
330
|
-
if not fut.fut.cancelled():
|
337
|
+
if fut is not None and not fut.fut.cancelled():
|
331
338
|
fut.resolve(cast(bytes, binary_data))
|
332
339
|
|
333
340
|
@property
|
@@ -142,6 +142,31 @@ class MammotionMQTT:
|
|
142
142
|
# command = MammotionCommand(device_name="Luba")
|
143
143
|
# self._cloud_client.send_cloud_command(command.get_report_cfg())
|
144
144
|
|
145
|
+
def unsubscribe(self) -> None:
|
146
|
+
self._linkkit_client.unsubscribe_topic(
|
147
|
+
f"/sys/{self._product_key}/{self._device_name}/app/down/account/bind_reply"
|
148
|
+
)
|
149
|
+
self._linkkit_client.unsubscribe_topic(
|
150
|
+
f"/sys/{self._product_key}/{self._device_name}/app/down/thing/event/property/post_reply"
|
151
|
+
)
|
152
|
+
self._linkkit_client.unsubscribe_topic(
|
153
|
+
f"/sys/{self._product_key}/{self._device_name}/app/down/thing/wifi/status/notify"
|
154
|
+
)
|
155
|
+
self._linkkit_client.unsubscribe_topic(
|
156
|
+
f"/sys/{self._product_key}/{self._device_name}/app/down/thing/wifi/connect/event/notify"
|
157
|
+
)
|
158
|
+
self._linkkit_client.unsubscribe_topic(
|
159
|
+
f"/sys/{self._product_key}/{self._device_name}/app/down/_thing/event/notify"
|
160
|
+
)
|
161
|
+
self._linkkit_client.unsubscribe_topic(f"/sys/{self._product_key}/{self._device_name}/app/down/thing/events")
|
162
|
+
self._linkkit_client.unsubscribe_topic(f"/sys/{self._product_key}/{self._device_name}/app/down/thing/status")
|
163
|
+
self._linkkit_client.unsubscribe_topic(
|
164
|
+
f"/sys/{self._product_key}/{self._device_name}/app/down/thing/properties"
|
165
|
+
)
|
166
|
+
self._linkkit_client.unsubscribe_topic(
|
167
|
+
f"/sys/{self._product_key}/{self._device_name}/app/down/thing/model/down_raw"
|
168
|
+
)
|
169
|
+
|
145
170
|
def _thing_on_topic_message(self, topic, payload, qos, user_data) -> None:
|
146
171
|
"""Is called when thing topic comes in."""
|
147
172
|
logger.debug(
|
pymammotion/proto/__init__.py
CHANGED
@@ -892,7 +892,7 @@ class NavGetCommData(betterproto.Message):
|
|
892
892
|
sub_cmd: int = betterproto.int32_field(2)
|
893
893
|
action: int = betterproto.int32_field(3)
|
894
894
|
type: int = betterproto.int32_field(4)
|
895
|
-
hash: int = betterproto.
|
895
|
+
hash: int = betterproto.int64_field(5)
|
896
896
|
paternal_hash_a: int = betterproto.int64_field(6)
|
897
897
|
paternal_hash_b: int = betterproto.int64_field(7)
|
898
898
|
total_frame: int = betterproto.int32_field(8)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: pymammotion
|
3
|
-
Version: 0.4.
|
3
|
+
Version: 0.4.11
|
4
4
|
Summary:
|
5
5
|
License: GPL-3.0
|
6
6
|
Author: Michael Arthur
|
@@ -8,7 +8,6 @@ Author-email: michael@jumblesoft.co.nz
|
|
8
8
|
Requires-Python: >=3.10
|
9
9
|
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
11
|
-
Classifier: Programming Language :: Python :: 3.10
|
12
11
|
Classifier: Programming Language :: Python :: 3.11
|
13
12
|
Classifier: Programming Language :: Python :: 3.12
|
14
13
|
Requires-Dist: aiohttp (>=3.9.1,<4.0.0)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
pymammotion/__init__.py,sha256=u1OHuD8Uj0qCOH4I7Lt5d7T-TPt1R0pY-bv8S6UfVxM,1587
|
2
2
|
pymammotion/aliyun/__init__.py,sha256=T1lkX7TRYiL4nqYanG4l4MImV-SlavSbuooC-W-uUGw,29
|
3
|
-
pymammotion/aliyun/cloud_gateway.py,sha256=
|
3
|
+
pymammotion/aliyun/cloud_gateway.py,sha256=mafX63IuRhbSLNv5WjwhbDY4HJGHRCYAMJseVOQebJE,26605
|
4
4
|
pymammotion/aliyun/model/aep_response.py,sha256=EY4uMTJ4F9rvbcXnAOc5YKi7q__9kIVgfDwfyr65Gk0,421
|
5
5
|
pymammotion/aliyun/model/connect_response.py,sha256=Yz-fEbDzgGPTo5Of2oAjmFkSv08T7ze80pQU4k-gKIU,824
|
6
6
|
pymammotion/aliyun/model/dev_by_account_response.py,sha256=P9yYy4Z2tLkJSqXA_5XGaCUliSSVa5ILl7VoMtL_tCA,977
|
@@ -23,7 +23,7 @@ pymammotion/const.py,sha256=lWRxvTVdXnNHuxqvRkjO5ziK0Ic-fZMM6J2dbe5M6Nc,385
|
|
23
23
|
pymammotion/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
24
24
|
pymammotion/data/model/__init__.py,sha256=aSyroxYQQS-WMRi6WmWm2js4wLa9nmsi160gx9tts4o,323
|
25
25
|
pymammotion/data/model/account.py,sha256=vJM-KTf2q6eBfVC-UlNHBSmJvqHiCawZ40vnuhXhaz8,140
|
26
|
-
pymammotion/data/model/device.py,sha256=
|
26
|
+
pymammotion/data/model/device.py,sha256=iyTqtWkpd6SCC-Y99z9mOdbQQtj7pROkfNdtKiUY2Jo,6988
|
27
27
|
pymammotion/data/model/device_config.py,sha256=dfva6mErOepLaen1CrjGaEVbEPrxRTSWXJh-yIn5iMI,2636
|
28
28
|
pymammotion/data/model/device_info.py,sha256=Q0qJ6BflQycH_VFugwaFFXcvM69q2v9JAe2wWOcCggE,904
|
29
29
|
pymammotion/data/model/device_limits.py,sha256=m8HdxD-RaAkPm7jHYb9GLxMEH9IfzBPz0ZypmsLnId4,1946
|
@@ -31,7 +31,7 @@ pymammotion/data/model/enums.py,sha256=EpKmO8yVUZyEnTY4yH0DMMVKYNQM42zpW1maUu0i3
|
|
31
31
|
pymammotion/data/model/excute_boarder_params.py,sha256=9CpUqrygcle1C_1hDW-riLmm4map4ZbE842NXjcomEI,1394
|
32
32
|
pymammotion/data/model/execute_boarder.py,sha256=9rd_h4fbcsXxgnLOd2rO2hWyD1abnTGc47QTEpp8DD0,1103
|
33
33
|
pymammotion/data/model/generate_route_information.py,sha256=pgjqURwmEIzjCMbl4Z5JDDkfxyUAdry1KhPfyir3-mU,777
|
34
|
-
pymammotion/data/model/hash_list.py,sha256=
|
34
|
+
pymammotion/data/model/hash_list.py,sha256=8PTjTS9upK8ZKHHQZMFQTmFCoOHqvje0tGzAqyROAHU,9077
|
35
35
|
pymammotion/data/model/location.py,sha256=PwmITejfI4pm7PI4rzqSuuHetwle6IJr_CV95435s2M,871
|
36
36
|
pymammotion/data/model/mowing_modes.py,sha256=bBbRhDe-imZsXDR0TN0emQv6BiIkAlXJFb5isPEjgDk,1078
|
37
37
|
pymammotion/data/model/plan.py,sha256=wGlcJT-w0EdbWK9jI838TCOm_MABFg7WoR664VB8RWg,2880
|
@@ -52,30 +52,30 @@ pymammotion/http/http.py,sha256=t4GWoF8qfCvFCVDR5-koIwSq-rEq-vYmQYLNbpwIDQ4,6871
|
|
52
52
|
pymammotion/http/model/http.py,sha256=tM5ikwVkWhRdXc2xi1NOLmWPH2mQEQelpaVgMlAEmlI,2333
|
53
53
|
pymammotion/mammotion/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
54
54
|
pymammotion/mammotion/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
55
|
-
pymammotion/mammotion/commands/abstract_message.py,sha256=
|
56
|
-
pymammotion/mammotion/commands/mammotion_command.py,sha256=
|
55
|
+
pymammotion/mammotion/commands/abstract_message.py,sha256=C1teY4Bd_BpBhAWWzKokoeXm7bjvDeV0sDL5CVpoyhI,829
|
56
|
+
pymammotion/mammotion/commands/mammotion_command.py,sha256=3OFXQjF7HFwPd_j6utHVI2Kfwh7t6_6ff_9MKAWGTlk,2570
|
57
57
|
pymammotion/mammotion/commands/messages/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
58
|
-
pymammotion/mammotion/commands/messages/driver.py,sha256=
|
59
|
-
pymammotion/mammotion/commands/messages/media.py,sha256=
|
60
|
-
pymammotion/mammotion/commands/messages/navigation.py,sha256=
|
61
|
-
pymammotion/mammotion/commands/messages/network.py,sha256=
|
62
|
-
pymammotion/mammotion/commands/messages/ota.py,sha256=
|
63
|
-
pymammotion/mammotion/commands/messages/system.py,sha256=
|
64
|
-
pymammotion/mammotion/commands/messages/video.py,sha256=
|
58
|
+
pymammotion/mammotion/commands/messages/driver.py,sha256=7lVfk3bHymgNf3toVhqYmCq8KrLTk_OaNz3oTmT_xY8,3647
|
59
|
+
pymammotion/mammotion/commands/messages/media.py,sha256=NUmd6W5171sOZZ08GhUCqzpGMptVqXC36t-H3i42tOQ,1282
|
60
|
+
pymammotion/mammotion/commands/messages/navigation.py,sha256=05ZstacaIqTcuSkDox-EVbt5aUIbuajflros_Tmm8I4,23248
|
61
|
+
pymammotion/mammotion/commands/messages/network.py,sha256=oO3PK6TKY563Jw-ZRpNmIzGCgkuk2SQm0BhcDL5claM,7595
|
62
|
+
pymammotion/mammotion/commands/messages/ota.py,sha256=ZHLQRE5ETvLEIu2Vbj3m2XidIWT8uorYSHxkZd3pkRc,1376
|
63
|
+
pymammotion/mammotion/commands/messages/system.py,sha256=ScXlurQAy8Z9WntXBRrxThnsVHFWfiNNltEWh-SVcvQ,14811
|
64
|
+
pymammotion/mammotion/commands/messages/video.py,sha256=YQGIxKx2prA0X01ovNmMkX6YfjuQKlq1KF5z_eRwfws,1195
|
65
65
|
pymammotion/mammotion/control/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
66
66
|
pymammotion/mammotion/control/joystick.py,sha256=QfBVxM_gxpWsZAGO90whtgxCI2tIZ3TTad9wHIPsU9s,5640
|
67
67
|
pymammotion/mammotion/devices/__init__.py,sha256=f2qQFPgLGmV85W2hSlMUh5BYuht9o_Ar_JEAAMD4fsE,102
|
68
|
-
pymammotion/mammotion/devices/base.py,sha256=
|
68
|
+
pymammotion/mammotion/devices/base.py,sha256=M8YiGc9Oi6gWGfjlaFHrkzKAfT4JQ4Pr7K9eTcp2GJM,10264
|
69
69
|
pymammotion/mammotion/devices/mammotion.py,sha256=Zz2tUIdGA-jFSHLM3aO8tBMvVl7sBIBiqC9Kg7f-lm8,13190
|
70
|
-
pymammotion/mammotion/devices/mammotion_bluetooth.py,sha256=
|
71
|
-
pymammotion/mammotion/devices/mammotion_cloud.py,sha256=
|
70
|
+
pymammotion/mammotion/devices/mammotion_bluetooth.py,sha256=0c-HXawLQVHz28s0HKaSCNq4wmLWJZZ3ATDVnCXdSrc,19579
|
71
|
+
pymammotion/mammotion/devices/mammotion_cloud.py,sha256=gLdxaD759QphR10LsQchTTOHZi6jvnI2EHlbhMfsXvE,14373
|
72
72
|
pymammotion/mqtt/__init__.py,sha256=Ocs5e-HLJvTuDpVXyECEsWIvwsUaxzj7lZ9mSYutNDY,105
|
73
73
|
pymammotion/mqtt/linkkit/__init__.py,sha256=ENgc3ynd2kd9gMQR3-kgmCu6Ed9Y6XCIzU0zFReUlkk,80
|
74
74
|
pymammotion/mqtt/linkkit/h2client.py,sha256=w9Nvi_nY4CLD_fw-pHtYChwQf7e2TiAGeqkY_sF4cf0,19659
|
75
75
|
pymammotion/mqtt/linkkit/linkkit.py,sha256=NzFpdtfxNHQ6xNu-POyp45fTK7AWUAWV7RavFevX4m4,132772
|
76
76
|
pymammotion/mqtt/mammotion_future.py,sha256=_OWqKOlUGl2yT1xOsXFQYpGd-1zQ63OxqXgy7KRQgYc,710
|
77
|
-
pymammotion/mqtt/mammotion_mqtt.py,sha256=
|
78
|
-
pymammotion/proto/__init__.py,sha256=
|
77
|
+
pymammotion/mqtt/mammotion_mqtt.py,sha256=urqhTIXabJ8QGAkArPZZQAm7CJQiA00912mviotTSds,10194
|
78
|
+
pymammotion/proto/__init__.py,sha256=qKfF78NyD__2p1URDpzhCHa9EsIxKbXHUhTuep7esWQ,72200
|
79
79
|
pymammotion/proto/basestation.proto,sha256=_x5gAz3FkZXS1jtq4GgZgaDCuRU-UV-7HTFdsfQ3zbo,1034
|
80
80
|
pymammotion/proto/basestation_pb2.py,sha256=PTVlHcDLQeRV6qv7ZPjGke9MF68mpqoUeJA0Sw_AoT0,2776
|
81
81
|
pymammotion/proto/basestation_pb2.pyi,sha256=eeYW9l_5OsokGzP9OE_lg6TdJwXGAFvPiojQ3tipcak,3970
|
@@ -117,7 +117,7 @@ pymammotion/utility/map.py,sha256=GYscVMg2cX3IPlNpCBNHDW0S55yS1WGRf1iHnNZ7TfQ,22
|
|
117
117
|
pymammotion/utility/movement.py,sha256=N75oAoAgFydqoaOedYIxGUHmuTCtPzAOtb-d_29tpfI,615
|
118
118
|
pymammotion/utility/periodic.py,sha256=MbeSb9cfhxzYmdT_RiE0dZe3H9IfbQW_zSqhmSX2RUc,3321
|
119
119
|
pymammotion/utility/rocker_util.py,sha256=6tX7sS87qoQC_tsxbx3NLL-HgS08wtzXiZkhDiz7uo0,7179
|
120
|
-
pymammotion-0.4.
|
121
|
-
pymammotion-0.4.
|
122
|
-
pymammotion-0.4.
|
123
|
-
pymammotion-0.4.
|
120
|
+
pymammotion-0.4.11.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
121
|
+
pymammotion-0.4.11.dist-info/METADATA,sha256=FBZkAzoPsVivbbmMHe5fnnTh7viBsYwFcatQL0923xs,3834
|
122
|
+
pymammotion-0.4.11.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
|
123
|
+
pymammotion-0.4.11.dist-info/RECORD,,
|
File without changes
|
File without changes
|