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.
@@ -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
 
@@ -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
- data: list[NavGetCommData | SvgMessage]
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
- root_hash_list: RootHashList = field(default_factory=RootHashList)
122
- area: dict = field(default_factory=dict) # type 0
123
- path: dict = field(default_factory=dict) # type 2
124
- obstacle: dict = field(default_factory=dict) # type 1
125
- dump: dict = field(default_factory=dict) # type 12?
126
- svg: dict = field(default_factory=dict) # type 13
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 len(self.root_hash_list.data) == 0:
141
+ if not self.root_hash_lists:
139
142
  return []
140
- return [i for obj in self.root_hash_list.data for i in obj.data_couple]
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 obj in self.root_hash_list.data
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 f"{i}"
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
- self.root_hash_list.total_frame = hash_list.total_frame
157
-
158
- for index, obj in enumerate(self.root_hash_list.data):
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
- self.root_hash_list.data[index] = hash_list
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
- self.root_hash_list.data.append(hash_list)
166
-
167
- def missing_hash_frame(self) -> list[int]:
168
- return self._find_missing_frames(self.root_hash_list)
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=1,
32
+ seqs=self.seqs.increment_and_get() & 255,
33
33
  version=1,
34
- subtype=1,
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=1,
15
+ seqs=self.seqs.increment_and_get() & 255,
16
16
  version=1,
17
- subtype=1,
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=1,
42
+ seqs=self.seqs.increment_and_get() & 255,
43
43
  version=1,
44
- subtype=1,
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
- @staticmethod
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=1,
40
+ seqs=self.seqs.increment_and_get() & 255,
42
41
  version=1,
43
- subtype=1,
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.MSG_ATTR_REQ,
15
- seqs=1,
16
+ msgattr=MsgAttr.REQ,
17
+ seqs=self.seqs.increment_and_get() & 255,
16
18
  version=1,
17
- subtype=1,
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=1,
39
+ seqs=self.seqs.increment_and_get() & 255,
40
40
  version=1,
41
- subtype=1,
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
- @staticmethod
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=1,
54
+ seqs=self.seqs.increment_and_get() & 255,
56
55
  version=1,
57
- subtype=1,
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=1,
317
+ seqs=self.seqs.increment_and_get() & 255,
319
318
  version=1,
320
- subtype=1,
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=1,
353
+ seqs=self.seqs.increment_and_get() & 255,
355
354
  version=1,
356
- subtype=1,
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=1,
18
+ seqs=self.seqs.increment_and_get() & 255,
19
19
  version=1,
20
- subtype=1,
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
- if current_frame != missing_frames[0] - 1:
58
- current_frame = missing_frames[0] - 1
59
- await self.queue_command("get_hash_response", total_frame=hash_ack.total_frame, current_frame=current_frame)
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(cloud_device.deviceName)
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
- self.mqtt.connect_async()
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(
@@ -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.fixed64_field(5)
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.9
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=2IE72NSM93rtHIAmdTnIdXU_Ak2txXNiaayVSkND6WQ,26254
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=GRKaXPocoetyekHo4DQtPKmJQH9v7ksZvGxe0XgmnLc,6892
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=1mwL715Q-OizowBDDPk1n_mYDZgb7kz24cIfzKu0QUM,7892
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=iZans5v1Z41rMgIbcWEbrSDIvBbaJ8N3Z8xHUKQQVAE,705
56
- pymammotion/mammotion/commands/mammotion_command.py,sha256=PM9UCuBCKp_TWDfkeVJsBelSbRrKosRa2LvHA-By1k8,2510
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=4DH6Q0Xzu1whS7shjDg2N3gzCH1KEYpojPQ1GsasMIY,3597
59
- pymammotion/mammotion/commands/messages/media.py,sha256=JaFMJiC-vtfG68dBfHmbDSvEHY-GTVkhPq02Mc_dGPg,1232
60
- pymammotion/mammotion/commands/messages/navigation.py,sha256=HQhkIu8ZEkyZAuZ0eN_jBuk5luw3YLo3hvlnDRCHt6c,23198
61
- pymammotion/mammotion/commands/messages/network.py,sha256=EDMXjX_j2aPUZvz5izSV913YSLrEVvdW1lVjfojEhYI,7557
62
- pymammotion/mammotion/commands/messages/ota.py,sha256=gySHuPw52tEmK0MT2ng2U1sn6r7O42z0Gvnb3E5KYgc,1305
63
- pymammotion/mammotion/commands/messages/system.py,sha256=bdq4RGhic-nmMEVlC4i152YWoC78ATFzij_M7VAYDr0,14623
64
- pymammotion/mammotion/commands/messages/video.py,sha256=_q2R-ePcR2IaS5KjLm_H63iF0INj_GelmfAnIwJj09Y,1145
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=Klkmvo56VgAX_zqen__lhbRb41k2U9HEHzA7t9FoZjc,10333
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=oNDwtDKsdsG62frehBCg6xmwF3CD3VJ32iUwQcAjzKo,19576
71
- pymammotion/mammotion/devices/mammotion_cloud.py,sha256=Pgd_jEX2-Y4g5zRI_HW3vr_hW0g_8U73aQkgN3FVG5o,14001
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=dQuGz-dQnOYI7vz_v5Kn9nHcizs-S0E2lZzJlZVkG5Y,8867
78
- pymammotion/proto/__init__.py,sha256=BLOSkNGEVbDJGtg9wYi0ziO3_tl3CIBRU3Sf9pmjuKU,72202
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.9.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
121
- pymammotion-0.4.9.dist-info/METADATA,sha256=XNyGzp7QPZdl5_8dAyCTXeu4KpdeBkyA_dCEK_fXQJM,3884
122
- pymammotion-0.4.9.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
123
- pymammotion-0.4.9.dist-info/RECORD,,
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,,