pymammotion 0.4.0a8__py3-none-any.whl → 0.4.0b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. pymammotion/aliyun/cloud_gateway.py +3 -7
  2. pymammotion/aliyun/model/aep_response.py +1 -2
  3. pymammotion/aliyun/model/dev_by_account_response.py +7 -8
  4. pymammotion/aliyun/model/login_by_oauth_response.py +2 -3
  5. pymammotion/aliyun/model/regions_response.py +3 -3
  6. pymammotion/aliyun/model/session_by_authcode_response.py +1 -2
  7. pymammotion/aliyun/model/stream_subscription_response.py +1 -2
  8. pymammotion/bluetooth/ble.py +1 -4
  9. pymammotion/bluetooth/ble_message.py +4 -7
  10. pymammotion/data/model/generate_route_information.py +1 -1
  11. pymammotion/data/model/plan.py +0 -3
  12. pymammotion/data/model/raw_data.py +1 -2
  13. pymammotion/data/model/region_data.py +10 -11
  14. pymammotion/data/mqtt/properties.py +1 -1
  15. pymammotion/data/state_manager.py +151 -125
  16. pymammotion/http/encryption.py +5 -6
  17. pymammotion/http/http.py +1 -6
  18. pymammotion/http/model/http.py +2 -2
  19. pymammotion/mammotion/commands/messages/driver.py +1 -1
  20. pymammotion/mammotion/commands/messages/navigation.py +1 -1
  21. pymammotion/mammotion/commands/messages/network.py +2 -2
  22. pymammotion/mammotion/commands/messages/system.py +1 -1
  23. pymammotion/mammotion/commands/messages/video.py +3 -6
  24. pymammotion/mammotion/devices/base.py +2 -10
  25. pymammotion/mammotion/devices/mammotion.py +4 -2
  26. pymammotion/mammotion/devices/mammotion_bluetooth.py +9 -0
  27. pymammotion/mammotion/devices/mammotion_cloud.py +11 -3
  28. pymammotion/mqtt/linkkit/h2client.py +7 -4
  29. pymammotion/mqtt/linkkit/linkkit.py +2 -2
  30. pymammotion/mqtt/mammotion_mqtt.py +1 -1
  31. {pymammotion-0.4.0a8.dist-info → pymammotion-0.4.0b1.dist-info}/METADATA +2 -2
  32. {pymammotion-0.4.0a8.dist-info → pymammotion-0.4.0b1.dist-info}/RECORD +34 -34
  33. {pymammotion-0.4.0a8.dist-info → pymammotion-0.4.0b1.dist-info}/WHEEL +1 -1
  34. {pymammotion-0.4.0a8.dist-info → pymammotion-0.4.0b1.dist-info}/LICENSE +0 -0
@@ -5,11 +5,11 @@ import hashlib
5
5
  import hmac
6
6
  import itertools
7
7
  import json
8
+ from logging import getLogger
8
9
  import random
9
10
  import string
10
11
  import time
11
12
  import uuid
12
- from logging import getLogger
13
13
 
14
14
  from aiohttp import ClientSession
15
15
  from alibabacloud_iot_api_gateway.client import Client
@@ -19,14 +19,10 @@ from alibabacloud_tea_util.models import RuntimeOptions
19
19
 
20
20
  from pymammotion.aliyun.model.aep_response import AepResponse
21
21
  from pymammotion.aliyun.model.connect_response import ConnectResponse
22
- from pymammotion.aliyun.model.dev_by_account_response import (
23
- ListingDevByAccountResponse,
24
- )
22
+ from pymammotion.aliyun.model.dev_by_account_response import ListingDevByAccountResponse
25
23
  from pymammotion.aliyun.model.login_by_oauth_response import LoginByOAuthResponse
26
24
  from pymammotion.aliyun.model.regions_response import RegionResponse
27
- from pymammotion.aliyun.model.session_by_authcode_response import (
28
- SessionByAuthCodeResponse,
29
- )
25
+ from pymammotion.aliyun.model.session_by_authcode_response import SessionByAuthCodeResponse
30
26
  from pymammotion.const import ALIYUN_DOMAIN, APP_KEY, APP_SECRET, APP_VERSION
31
27
  from pymammotion.http.http import MammotionHTTP
32
28
  from pymammotion.utility.datatype_converter import DatatypeConverter
@@ -1,5 +1,4 @@
1
1
  from dataclasses import dataclass
2
- from typing import Optional
3
2
 
4
3
  from mashumaro.config import BaseConfig
5
4
  from mashumaro.mixins.orjson import DataClassORJSONMixin
@@ -16,7 +15,7 @@ class DeviceData(DataClassORJSONMixin):
16
15
  class AepResponse(DataClassORJSONMixin):
17
16
  code: int
18
17
  data: DeviceData
19
- id: Optional[str] = None
18
+ id: str | None = None
20
19
 
21
20
  class Config(BaseConfig):
22
21
  omit_default = True
@@ -1,5 +1,4 @@
1
1
  from dataclasses import dataclass
2
- from typing import Optional
3
2
 
4
3
  from mashumaro.config import BaseConfig
5
4
  from mashumaro.mixins.orjson import DataClassORJSONMixin
@@ -23,11 +22,11 @@ class Device(DataClassORJSONMixin):
23
22
  identityId: str
24
23
  thingType: str
25
24
  status: int
26
- nickName: Optional[str] = None
27
- description: Optional[str] = None
28
- productImage: Optional[str] = None
29
- categoryImage: Optional[str] = None
30
- productModel: Optional[str] = None
25
+ nickName: str | None = None
26
+ description: str | None = None
27
+ productImage: str | None = None
28
+ categoryImage: str | None = None
29
+ productModel: str | None = None
31
30
 
32
31
  class Config(BaseConfig):
33
32
  omit_default = True
@@ -44,5 +43,5 @@ class Data(DataClassORJSONMixin):
44
43
  @dataclass
45
44
  class ListingDevByAccountResponse(DataClassORJSONMixin):
46
45
  code: int
47
- data: Optional[Data]
48
- id: Optional[str] = None
46
+ data: Data | None
47
+ id: str | None = None
@@ -1,5 +1,4 @@
1
1
  from dataclasses import dataclass
2
- from typing import Optional
3
2
 
4
3
  from mashumaro.mixins.orjson import DataClassORJSONMixin
5
4
 
@@ -18,7 +17,7 @@ class OpenAccount(DataClassORJSONMixin):
18
17
  domainId: int
19
18
  enableDevice: str
20
19
  status: int
21
- country: Optional[str] = None
20
+ country: str | None = None
22
21
 
23
22
 
24
23
  @dataclass
@@ -54,7 +53,7 @@ class InnerData(DataClassORJSONMixin):
54
53
  subCode: int
55
54
  message: str
56
55
  successful: str
57
- deviceId: Optional[str] = None
56
+ deviceId: str | None = None
58
57
 
59
58
 
60
59
  @dataclass
@@ -1,5 +1,5 @@
1
1
  from dataclasses import dataclass
2
- from typing import Optional, TypeVar
2
+ from typing import TypeVar
3
3
 
4
4
  from mashumaro.config import BaseConfig
5
5
  from mashumaro.mixins.orjson import DataClassORJSONMixin
@@ -22,8 +22,8 @@ class RegionResponseData(DataClassORJSONMixin):
22
22
  class RegionResponse(DataClassORJSONMixin):
23
23
  data: RegionResponseData
24
24
  code: int
25
- id: Optional[str] = None
26
- msg: Optional[str] = None
25
+ id: str | None = None
26
+ msg: str | None = None
27
27
 
28
28
  class Config(BaseConfig):
29
29
  omit_default = True
@@ -1,5 +1,4 @@
1
1
  from dataclasses import dataclass
2
- from typing import Optional
3
2
 
4
3
  from mashumaro.mixins.orjson import DataClassORJSONMixin
5
4
 
@@ -16,4 +15,4 @@ class SessionOauthToken(DataClassORJSONMixin):
16
15
  @dataclass
17
16
  class SessionByAuthCodeResponse(DataClassORJSONMixin):
18
17
  code: int
19
- data: Optional[SessionOauthToken] = None
18
+ data: SessionOauthToken | None = None
@@ -1,5 +1,4 @@
1
1
  from dataclasses import dataclass
2
- from typing import List
3
2
 
4
3
  from mashumaro.mixins.orjson import DataClassORJSONMixin
5
4
 
@@ -13,7 +12,7 @@ class Camera(DataClassORJSONMixin):
13
12
  @dataclass
14
13
  class StreamSubscriptionResponse(DataClassORJSONMixin):
15
14
  appid: str
16
- cameras: List[Camera]
15
+ cameras: list[Camera]
17
16
  channelName: str
18
17
  token: str
19
18
  uid: int
@@ -1,10 +1,7 @@
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
7
 
@@ -1,12 +1,11 @@
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
- from typing import Union
10
9
 
11
10
  from bleak import BleakClient
12
11
  from jsonic.serializable import serialize
@@ -17,9 +16,7 @@ from pymammotion.bluetooth.data.framectrldata import FrameCtrlData
17
16
  from pymammotion.bluetooth.data.notifydata import BlufiNotifyData
18
17
  from pymammotion.bluetooth.model.atomic_integer import AtomicInteger
19
18
  from pymammotion.data.model.execute_boarder import ExecuteBorder
20
- from pymammotion.proto import (
21
- dev_net_pb2,
22
- )
19
+ from pymammotion.proto import dev_net_pb2
23
20
  from pymammotion.proto.luba_msg import LubaMsg, MsgAttr, MsgCmdType, MsgDevice
24
21
  from pymammotion.utility.constant.device_constant import bleOrderCmd
25
22
 
@@ -656,7 +653,7 @@ class BleMessage:
656
653
  return byteOS.getvalue()
657
654
 
658
655
  @staticmethod
659
- def calc_crc(initial: int, data: Union[bytes, bytearray]) -> int:
656
+ def calc_crc(initial: int, data: bytes | bytearray) -> int:
660
657
  """Calculate CRC value for given initial value and byte array.
661
658
 
662
659
  Args:
@@ -1,5 +1,5 @@
1
- import logging
2
1
  from dataclasses import dataclass
2
+ import logging
3
3
 
4
4
  logger = logging.getLogger(__name__)
5
5
 
@@ -1,6 +1,3 @@
1
- from typing import List
2
-
3
-
4
1
  class Plan:
5
2
  def __init__(self) -> None:
6
3
  self.pver: int = 0
@@ -1,5 +1,4 @@
1
1
  from dataclasses import dataclass, field
2
- from typing import Optional
3
2
 
4
3
  from mashumaro.mixins.orjson import DataClassORJSONMixin
5
4
 
@@ -15,7 +14,7 @@ from pymammotion.proto.mctrl_sys import MctlSys
15
14
 
16
15
  @dataclass
17
16
  class RawMowerData:
18
- raw: Optional[LubaMsg] = field(default_factory=LubaMsg)
17
+ raw: LubaMsg | None = field(default_factory=LubaMsg)
19
18
 
20
19
  @classmethod
21
20
  def from_raw(cls, raw: dict) -> "RawMowerData":
@@ -1,5 +1,4 @@
1
1
  from dataclasses import dataclass
2
- from typing import Optional
3
2
 
4
3
  from mashumaro.mixins.orjson import DataClassORJSONMixin
5
4
 
@@ -7,14 +6,14 @@ from mashumaro.mixins.orjson import DataClassORJSONMixin
7
6
  @dataclass
8
7
  class RegionData(DataClassORJSONMixin):
9
8
  def __init__(self) -> None:
10
- self.hash: Optional[int] = None
9
+ self.hash: int | None = None
11
10
  self.action: int = 0
12
11
  self.current_frame: int = 0
13
- self.data_hash: Optional[int] = None
12
+ self.data_hash: int | None = None
14
13
  self.data_len: int = 0
15
- self.p_hash_a: Optional[int] = None
16
- self.p_hash_b: Optional[int] = None
17
- self.path: Optional[list[list[float]]] = None
14
+ self.p_hash_a: int | None = None
15
+ self.p_hash_b: int | None = None
16
+ self.path: list[list[float]] | None = None
18
17
  self.pver: int = 0
19
18
  self.result: int = 0
20
19
  self.sub_cmd: int = 0
@@ -72,31 +71,31 @@ class RegionData(DataClassORJSONMixin):
72
71
  def set_current_frame(self, current_frame: int) -> None:
73
72
  self.current_frame = current_frame
74
73
 
75
- def get_path(self) -> Optional[list[list[float]]]:
74
+ def get_path(self) -> list[list[float]] | None:
76
75
  return self.path
77
76
 
78
77
  def set_path(self, path: list[list[float]]) -> None:
79
78
  self.path = path
80
79
 
81
- def get_hash(self) -> Optional[int]:
80
+ def get_hash(self) -> int | None:
82
81
  return self.hash
83
82
 
84
83
  def set_data_hash(self, data_hash: int) -> None:
85
84
  self.data_hash = data_hash
86
85
 
87
- def get_data_hash(self) -> Optional[int]:
86
+ def get_data_hash(self) -> int | None:
88
87
  return self.data_hash
89
88
 
90
89
  def set_p_hash_a(self, p_hash_a: int) -> None:
91
90
  self.p_hash_a = p_hash_a
92
91
 
93
- def get_p_hash_a(self) -> Optional[int]:
92
+ def get_p_hash_a(self) -> int | None:
94
93
  return self.p_hash_a
95
94
 
96
95
  def set_p_hash_b(self, p_hash_b: int) -> None:
97
96
  self.p_hash_b = p_hash_b
98
97
 
99
- def get_p_hash_b(self) -> Optional[int]:
98
+ def get_p_hash_b(self) -> int | None:
100
99
  return self.p_hash_b
101
100
 
102
101
  def __str__(self) -> str:
@@ -116,7 +116,7 @@ Items = Union[
116
116
  @dataclass
117
117
  class Item:
118
118
  time: int
119
- value: Union[int, float, str, dict[str, Any]] # Depending on the type of value
119
+ value: int | float | str | dict[str, Any] # Depending on the type of value
120
120
 
121
121
 
122
122
  @dataclass
@@ -1,8 +1,8 @@
1
1
  """Manage state from notifications into MowingDevice."""
2
2
 
3
- import logging
4
3
  from collections.abc import Awaitable, Callable
5
4
  from datetime import datetime
5
+ import logging
6
6
  from typing import Any
7
7
 
8
8
  import betterproto
@@ -21,127 +21,153 @@ logger = logging.getLogger(__name__)
21
21
 
22
22
 
23
23
  class StateManager:
24
- """Manage state."""
25
-
26
- _device: MowingDevice
27
- last_updated_at: datetime = datetime.now()
28
-
29
- def __init__(self, device: MowingDevice) -> None:
30
- self._device = device
31
- self.gethash_ack_callback: Callable[[NavGetHashListAck], Awaitable[None]] | None = None
32
- self.get_commondata_ack_callback: Callable[[NavGetCommDataAck | SvgMessageAckT], Awaitable[None]] | None = None
33
- self.on_notification_callback: Callable[[tuple[str, Any | None]], Awaitable[None]] | None = None
34
- self.queue_command_callback: Callable[[str, dict[str, Any]], Awaitable[bytes]] | None = None
35
- self.last_updated_at = datetime.now()
36
-
37
- def get_device(self) -> MowingDevice:
38
- """Get device."""
39
- return self._device
40
-
41
- def set_device(self, device: MowingDevice) -> None:
42
- """Set device."""
43
- self._device = device
44
-
45
- async def properties(self, properties: ThingPropertiesMessage) -> None:
46
- self._device.mqtt_properties = properties
47
-
48
- async def status(self, status: ThingStatusMessage) -> None:
49
- if not self._device.online:
50
- self._device.online = True
51
- self._device.status_properties = status
52
-
53
- @property
54
- def online(self) -> bool:
55
- return self._device.online
56
-
57
- @online.setter
58
- def online(self, value: bool) -> None:
59
- self._device.online = value
60
-
61
- async def notification(self, message: LubaMsg) -> None:
62
- """Handle protobuf notifications."""
63
- res = betterproto.which_one_of(message, "LubaSubMsg")
64
- self.last_updated_at = datetime.now()
65
-
66
- match res[0]:
67
- case "nav":
68
- await self._update_nav_data(message)
69
- case "sys":
70
- await self._update_sys_data(message)
71
- case "driver":
72
- self._update_driver_data(message)
73
- case "net":
74
- self._update_net_data(message)
75
- case "mul":
76
- self._update_mul_data(message)
77
- case "ota":
78
- self._update_ota_data(message)
79
-
80
- if self.on_notification_callback:
81
- await self.on_notification_callback(res)
82
-
83
- async def _update_nav_data(self, message) -> None:
84
- """Update nav data."""
85
- nav_msg = betterproto.which_one_of(message.nav, "SubNavMsg")
86
- match nav_msg[0]:
87
- case "toapp_gethash_ack":
88
- hashlist_ack: NavGetHashListAck = nav_msg[1]
89
- self._device.map.update_root_hash_list(hashlist_ack)
90
- await self.gethash_ack_callback(nav_msg[1])
91
- case "toapp_get_commondata_ack":
92
- common_data: NavGetCommDataAck = nav_msg[1]
93
- updated = self._device.map.update(common_data)
94
- if updated:
95
- await self.get_commondata_ack_callback(common_data)
96
- case "toapp_svg_msg":
97
- common_data: SvgMessageAckT = nav_msg[1]
98
- updated = self._device.map.update(common_data)
99
- if updated:
100
- await self.get_commondata_ack_callback(common_data)
101
-
102
- case "toapp_all_hash_name":
103
- hash_names: AppGetAllAreaHashName = nav_msg[1]
104
- converted_list = [AreaHashNameList(name=item.name, hash=item.hash) for item in hash_names.hashnames]
105
- self._device.map.area_name = converted_list
106
-
107
- async def _update_sys_data(self, message) -> None:
108
- """Update system."""
109
- sys_msg = betterproto.which_one_of(message.sys, "SubSysMsg")
110
- match sys_msg[0]:
111
- case "system_update_buf":
112
- self._device.buffer(sys_msg[1])
113
- case "toapp_report_data":
114
- self._device.update_report_data(sys_msg[1])
115
- case "mow_to_app_info":
116
- self._device.mow_info(sys_msg[1])
117
- case "system_tard_state_tunnel":
118
- self._device.run_state_update(sys_msg[1])
119
- case "todev_time_ctrl_light":
120
- ctrl_light: TimeCtrlLight = sys_msg[1]
121
- side_led: SideLight = SideLight.from_dict(ctrl_light.to_dict(casing=betterproto.Casing.SNAKE))
122
- self._device.mower_state.side_led = side_led
123
- case "device_product_type_info":
124
- device_product_type: DeviceProductTypeInfoT = sys_msg[1]
125
- self._device.mower_state.model_id = device_product_type.main_product_type
126
-
127
- def _update_driver_data(self, message) -> None:
128
- pass
129
-
130
- def _update_net_data(self, message) -> None:
131
- net_msg = betterproto.which_one_of(message.net, "NetSubType")
132
- match net_msg[0]:
133
- case "toapp_wifi_iot_status":
134
- wifi_iot_status: WifiIotStatusReport = net_msg[1]
135
- self._device.mower_state.product_key = wifi_iot_status.productkey
136
- case "toapp_devinfo_resp":
137
- toapp_devinfo_resp: DrvDevInfoResp = net_msg[1]
138
- for resp in toapp_devinfo_resp.resp_ids:
139
- if resp.res == "DRV_RESULT_SUC":
140
- self._device.mower_state.swversion = resp.info
141
- self._device.device_firmwares.device_version = resp.info
142
-
143
- def _update_mul_data(self, message) -> None:
144
- pass
145
-
146
- def _update_ota_data(self, message) -> None:
147
- pass
24
+ """Manage state."""
25
+
26
+ _device: MowingDevice
27
+ last_updated_at: datetime = datetime.now()
28
+
29
+ def __init__(self, device: MowingDevice) -> None:
30
+ self._device = device
31
+ self.cloud_gethash_ack_callback: Callable[[NavGetHashListAck], Awaitable[None]] | None = None
32
+ self.cloud_get_commondata_ack_callback: Callable[[NavGetCommDataAck | SvgMessageAckT], Awaitable[None]] | None = None
33
+ self.cloud_on_notification_callback: Callable[[tuple[str, Any | None]], Awaitable[None]] | None = None
34
+
35
+ # possibly don't need anymore
36
+ self.cloud_queue_command_callback: Callable[[str, dict[str, Any]], Awaitable[bytes]] | None = None
37
+
38
+ self.ble_gethash_ack_callback: Callable[[NavGetHashListAck], Awaitable[None]] | None = None
39
+ self.ble_get_commondata_ack_callback: Callable[[NavGetCommDataAck | SvgMessageAckT], Awaitable[None]] | None = None
40
+ self.ble_on_notification_callback: Callable[[tuple[str, Any | None]], Awaitable[None]] | None = None
41
+
42
+ # possibly don't need anymore
43
+ self.ble_queue_command_callback: Callable[[str, dict[str, Any]], Awaitable[bytes]] | None = None
44
+ self.last_updated_at = datetime.now()
45
+
46
+ def get_device(self) -> MowingDevice:
47
+ """Get device."""
48
+ return self._device
49
+
50
+ def set_device(self, device: MowingDevice) -> None:
51
+ """Set device."""
52
+ self._device = device
53
+
54
+ async def properties(self, properties: ThingPropertiesMessage) -> None:
55
+ self._device.mqtt_properties = properties
56
+
57
+ async def status(self, status: ThingStatusMessage) -> None:
58
+ if not self._device.online:
59
+ self._device.online = True
60
+ self._device.status_properties = status
61
+
62
+ @property
63
+ def online(self) -> bool:
64
+ return self._device.online
65
+
66
+ @online.setter
67
+ def online(self, value: bool) -> None:
68
+ self._device.online = value
69
+
70
+ async def gethash_ack_callback(self, msg: NavGetHashListAck):
71
+ if self.cloud_gethash_ack_callback:
72
+ await self.cloud_gethash_ack_callback(msg)
73
+ if self.ble_gethash_ack_callback:
74
+ await self.ble_gethash_ack_callback(msg)
75
+
76
+ async def on_notification_callback(self, res: tuple[str, Any | None]):
77
+ if self.cloud_on_notification_callback:
78
+ await self.cloud_on_notification_callback(res)
79
+ if self.ble_on_notification_callback:
80
+ await self.ble_on_notification_callback(res)
81
+
82
+ async def get_commondata_ack_callback(self, comm_data: NavGetCommDataAck | SvgMessageAckT):
83
+ if self.cloud_get_commondata_ack_callback:
84
+ await self.cloud_get_commondata_ack_callback(comm_data)
85
+ if self.ble_get_commondata_ack_callback:
86
+ await self.ble_get_commondata_ack_callback(comm_data)
87
+
88
+ async def notification(self, message: LubaMsg) -> None:
89
+ """Handle protobuf notifications."""
90
+ res = betterproto.which_one_of(message, "LubaSubMsg")
91
+ self.last_updated_at = datetime.now()
92
+
93
+ match res[0]:
94
+ case "nav":
95
+ await self._update_nav_data(message)
96
+ case "sys":
97
+ await self._update_sys_data(message)
98
+ case "driver":
99
+ self._update_driver_data(message)
100
+ case "net":
101
+ self._update_net_data(message)
102
+ case "mul":
103
+ self._update_mul_data(message)
104
+ case "ota":
105
+ self._update_ota_data(message)
106
+
107
+ await self.on_notification_callback(res)
108
+
109
+ async def _update_nav_data(self, message) -> None:
110
+ """Update nav data."""
111
+ nav_msg = betterproto.which_one_of(message.nav, "SubNavMsg")
112
+ match nav_msg[0]:
113
+ case "toapp_gethash_ack":
114
+ hashlist_ack: NavGetHashListAck = nav_msg[1]
115
+ self._device.map.update_root_hash_list(hashlist_ack)
116
+ await self.gethash_ack_callback(nav_msg[1])
117
+ case "toapp_get_commondata_ack":
118
+ common_data: NavGetCommDataAck = nav_msg[1]
119
+ updated = self._device.map.update(common_data)
120
+ if updated:
121
+ await self.get_commondata_ack_callback(common_data)
122
+ case "toapp_svg_msg":
123
+ common_data: SvgMessageAckT = nav_msg[1]
124
+ updated = self._device.map.update(common_data)
125
+ if updated:
126
+ await self.get_commondata_ack_callback(common_data)
127
+
128
+ case "toapp_all_hash_name":
129
+ hash_names: AppGetAllAreaHashName = nav_msg[1]
130
+ converted_list = [AreaHashNameList(name=item.name, hash=item.hash) for item in hash_names.hashnames]
131
+ self._device.map.area_name = converted_list
132
+
133
+ async def _update_sys_data(self, message) -> None:
134
+ """Update system."""
135
+ sys_msg = betterproto.which_one_of(message.sys, "SubSysMsg")
136
+ match sys_msg[0]:
137
+ case "system_update_buf":
138
+ self._device.buffer(sys_msg[1])
139
+ case "toapp_report_data":
140
+ self._device.update_report_data(sys_msg[1])
141
+ case "mow_to_app_info":
142
+ self._device.mow_info(sys_msg[1])
143
+ case "system_tard_state_tunnel":
144
+ self._device.run_state_update(sys_msg[1])
145
+ case "todev_time_ctrl_light":
146
+ ctrl_light: TimeCtrlLight = sys_msg[1]
147
+ side_led: SideLight = SideLight.from_dict(ctrl_light.to_dict(casing=betterproto.Casing.SNAKE))
148
+ self._device.mower_state.side_led = side_led
149
+ case "device_product_type_info":
150
+ device_product_type: DeviceProductTypeInfoT = sys_msg[1]
151
+ self._device.mower_state.model_id = device_product_type.main_product_type
152
+
153
+ def _update_driver_data(self, message) -> None:
154
+ pass
155
+
156
+ def _update_net_data(self, message) -> None:
157
+ net_msg = betterproto.which_one_of(message.net, "NetSubType")
158
+ match net_msg[0]:
159
+ case "toapp_wifi_iot_status":
160
+ wifi_iot_status: WifiIotStatusReport = net_msg[1]
161
+ self._device.mower_state.product_key = wifi_iot_status.productkey
162
+ case "toapp_devinfo_resp":
163
+ toapp_devinfo_resp: DrvDevInfoResp = net_msg[1]
164
+ for resp in toapp_devinfo_resp.resp_ids:
165
+ if resp.res == "DRV_RESULT_SUC":
166
+ self._device.mower_state.swversion = resp.info
167
+ self._device.device_firmwares.device_version = resp.info
168
+
169
+ def _update_mul_data(self, message) -> None:
170
+ pass
171
+
172
+ def _update_ota_data(self, message) -> None:
173
+ pass
@@ -2,7 +2,6 @@ import base64
2
2
  import logging
3
3
  import secrets
4
4
  import string
5
- from typing import Optional
6
5
 
7
6
  from cryptography.hazmat.backends import default_backend
8
7
  from cryptography.hazmat.primitives import padding, serialization
@@ -50,7 +49,7 @@ class EncryptionUtils:
50
49
  private_key_bytes = base64.b64decode(EncryptionUtils.PRIVATE_KEY)
51
50
  return serialization.load_der_private_key(private_key_bytes, password=None, backend=default_backend())
52
51
  except Exception as e:
53
- raise Exception(f"Failed to load private key: {str(e)}")
52
+ raise Exception(f"Failed to load private key: {e!s}")
54
53
 
55
54
  @staticmethod
56
55
  def load_public_key(is_production: bool = True):
@@ -65,7 +64,7 @@ class EncryptionUtils:
65
64
  public_key_bytes = base64.b64decode(key_string)
66
65
  return serialization.load_der_public_key(public_key_bytes, backend=default_backend())
67
66
  except Exception as e:
68
- raise Exception(f"Failed to load public key: {str(e)}")
67
+ raise Exception(f"Failed to load public key: {e!s}")
69
68
 
70
69
  @staticmethod
71
70
  def encrypt(plaintext: str, key: str, iv: str) -> str:
@@ -104,7 +103,7 @@ class EncryptionUtils:
104
103
  return base64.b64encode(encrypted_bytes).decode("utf-8")
105
104
 
106
105
  except Exception as e:
107
- raise Exception(f"Encryption failed: {str(e)}")
106
+ raise Exception(f"Encryption failed: {e!s}")
108
107
 
109
108
  def encryption_by_aes(self, text: str) -> str:
110
109
  """Encrypt text using AES with class-level key and IV
@@ -123,10 +122,10 @@ class EncryptionUtils:
123
122
  return encrypted
124
123
 
125
124
  except Exception as e:
126
- _LOGGER.error(f"Encryption failed: {str(e)}")
125
+ _LOGGER.error(f"Encryption failed: {e!s}")
127
126
  return None
128
127
 
129
- def encrypt_by_public_key(self) -> Optional[str]:
128
+ def encrypt_by_public_key(self) -> str | None:
130
129
  """Encrypt data using RSA public key.
131
130
 
132
131
  Args:
pymammotion/http/http.py CHANGED
@@ -4,12 +4,7 @@ from typing import cast
4
4
  from aiohttp import ClientSession
5
5
 
6
6
  from pymammotion.aliyun.model.stream_subscription_response import StreamSubscriptionResponse
7
- from pymammotion.const import (
8
- MAMMOTION_API_DOMAIN,
9
- MAMMOTION_CLIENT_ID,
10
- MAMMOTION_CLIENT_SECRET,
11
- MAMMOTION_DOMAIN,
12
- )
7
+ from pymammotion.const import MAMMOTION_API_DOMAIN, MAMMOTION_CLIENT_ID, MAMMOTION_CLIENT_SECRET, MAMMOTION_DOMAIN
13
8
  from pymammotion.http.encryption import EncryptionUtils
14
9
  from pymammotion.http.model.http import ErrorInfo, LoginResponseData, Response
15
10
 
@@ -1,5 +1,5 @@
1
1
  from dataclasses import dataclass
2
- from typing import Generic, Literal, Optional, TypeVar
2
+ from typing import Generic, Literal, TypeVar
3
3
 
4
4
  from mashumaro import DataClassDictMixin
5
5
  from mashumaro.config import BaseConfig
@@ -83,7 +83,7 @@ class LoginResponseUserInformation(DataClassORJSONMixin):
83
83
  userId: str
84
84
  userAccount: str
85
85
  authType: str
86
- email: Optional[str] = None
86
+ email: str | None = None
87
87
 
88
88
  class Config(BaseConfig):
89
89
  omit_none = True
@@ -1,7 +1,7 @@
1
1
  # === sendOrderMsg_Driver ===
2
- import time
3
2
  from abc import ABC
4
3
  from logging import getLogger
4
+ import time
5
5
 
6
6
  from pymammotion.mammotion.commands.abstract_message import AbstractMessage
7
7
  from pymammotion.proto import mctrl_driver
@@ -1,7 +1,7 @@
1
1
  # === sendOrderMsg_Nav ===
2
+ from abc import ABC
2
3
  import logging
3
4
  import time
4
- from abc import ABC
5
5
 
6
6
  from pymammotion.data.model import GenerateRouteInformation
7
7
  from pymammotion.data.model.plan import Plan
@@ -1,6 +1,6 @@
1
1
  # === sendOrderMsg_Net ===
2
- import time
3
2
  from abc import ABC
3
+ import time
4
4
 
5
5
  from pymammotion import logger
6
6
  from pymammotion.mammotion.commands.abstract_message import AbstractMessage
@@ -193,7 +193,7 @@ class MessageNetwork(AbstractMessage, ABC):
193
193
  def wifi_connectinfo_update2(self) -> None:
194
194
  hash_map = {"getMsgCmd": 1}
195
195
  # self.post_custom_data(self.get_json_string(
196
- # 68, hash_map)) # ToDo: Fix this
196
+ # 68, hash_map)) # TODO: Fix this
197
197
 
198
198
  def get_record_wifi_list(self) -> bytes:
199
199
  build = DevNet(todev_ble_sync=1, todev__wifi_list_upload=DrvWifiList())
@@ -1,7 +1,7 @@
1
1
  # === sendOrderMsg_Sys ===
2
+ from abc import ABC
2
3
  import datetime
3
4
  import time
4
- from abc import ABC
5
5
 
6
6
  from pymammotion import logger
7
7
  from pymammotion.mammotion.commands.abstract_message import AbstractMessage
@@ -1,10 +1,11 @@
1
1
  # === sendOrderMsg_Video ===
2
- import time
3
2
  from abc import ABC
3
+ import time
4
4
 
5
5
  from pymammotion.mammotion.commands.abstract_message import AbstractMessage
6
6
  from pymammotion.proto import luba_msg_pb2, luba_mul_pb2
7
7
  from pymammotion.proto.luba_msg import MsgAttr, MsgCmdType, MsgDevice
8
+ from pymammotion.proto.luba_mul import MUL_CAMERA_POSITION
8
9
  from pymammotion.utility.device_type import DeviceType
9
10
 
10
11
 
@@ -25,10 +26,6 @@ class MessageVideo(AbstractMessage, ABC):
25
26
  return luba_msg.SerializeToString()
26
27
 
27
28
  def device_agora_join_channel_with_position(self, enter_state: int):
28
- position = (
29
- luba_mul_pb2.MUL_CAMERA_POSITION.ALL
30
- if DeviceType.is_yuka(self.get_device_name())
31
- else luba_mul_pb2.MUL_CAMERA_POSITION.LEFT
32
- )
29
+ position = MUL_CAMERA_POSITION.ALL if DeviceType.is_yuka(self.get_device_name()) else MUL_CAMERA_POSITION.LEFT
33
30
  mctl_sys = luba_mul_pb2.SocMul(set_video=luba_mul_pb2.MulSetVideo(position=position, vi_switch=enter_state))
34
31
  return self.send_order_msg_video(mctl_sys)
@@ -1,7 +1,7 @@
1
+ from abc import abstractmethod
1
2
  import asyncio
2
3
  import logging
3
- from abc import abstractmethod
4
- from typing import Any, Awaitable, Callable
4
+ from typing import Any
5
5
 
6
6
  import betterproto
7
7
 
@@ -40,17 +40,9 @@ class MammotionBaseDevice:
40
40
  self._state_manager = state_manager
41
41
  self._raw_data = dict()
42
42
  self._raw_mower_data: RawMowerData = RawMowerData()
43
- self._state_manager.gethash_ack_callback = self.datahash_response
44
- self._state_manager.get_commondata_ack_callback = self.commdata_response
45
43
  self._notify_future: asyncio.Future[bytes] | None = None
46
44
  self._cloud_device = cloud_device
47
45
 
48
- def set_notification_callback(self, func: Callable[[tuple[str, Any | None]], Awaitable[None]]) -> None:
49
- self._state_manager.on_notification_callback = func
50
-
51
- def set_queue_callback(self, func: Callable[[str, dict[str, Any]], Awaitable[bytes]]) -> None:
52
- self._state_manager.queue_command_callback = func
53
-
54
46
  async def datahash_response(self, hash_ack: NavGetHashListAck) -> None:
55
47
  """Handle datahash responses."""
56
48
  current_frame = hash_ack.current_frame
@@ -3,8 +3,8 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import asyncio
6
- import logging
7
6
  from enum import Enum
7
+ import logging
8
8
  from typing import Any
9
9
 
10
10
  from bleak.backends.device import BLEDevice
@@ -296,7 +296,9 @@ class Mammotion:
296
296
  device = self.get_device_by_name(name)
297
297
  if device.preference is ConnectionPreference.WIFI:
298
298
  if device.has_cloud():
299
- _stream_response = await device.cloud().mqtt.cloud_client.get_stream_subscription(device.cloud().iot_id)
299
+ _stream_response = await device.cloud().mqtt.cloud_client.mammotion_http.get_stream_subscription(
300
+ device.cloud().iot_id
301
+ )
300
302
  _LOGGER.debug(_stream_response)
301
303
  return _stream_response
302
304
 
@@ -1,4 +1,5 @@
1
1
  import asyncio
2
+ from collections.abc import Awaitable, Callable
2
3
  import logging
3
4
  from typing import Any, cast
4
5
  from uuid import UUID
@@ -89,9 +90,17 @@ class MammotionBaseBLEDevice(MammotionBaseDevice):
89
90
  self._operation_lock = asyncio.Lock()
90
91
  self._key: str | None = None
91
92
  self.set_queue_callback(self.queue_command)
93
+ self._state_manager.ble_gethash_ack_callback = self.datahash_response
94
+ self._state_manager.ble_get_commondata_ack_callback = self.commdata_response
92
95
  loop = asyncio.get_event_loop()
93
96
  loop.create_task(self.process_queue())
94
97
 
98
+ def set_notification_callback(self, func: Callable[[tuple[str, Any | None]], Awaitable[None]]) -> None:
99
+ self._state_manager.ble_on_notification_callback = func
100
+
101
+ def set_queue_callback(self, func: Callable[[str, dict[str, Any]], Awaitable[bytes]]) -> None:
102
+ self._state_manager.ble_queue_command_callback = func
103
+
95
104
  def update_device(self, device: BLEDevice) -> None:
96
105
  """Update the BLE device."""
97
106
  self.ble_device = device
@@ -1,10 +1,10 @@
1
1
  import asyncio
2
- import base64
3
- import json
4
- import logging
5
2
  from asyncio import TimerHandle
3
+ import base64
6
4
  from collections import deque
7
5
  from collections.abc import Awaitable, Callable
6
+ import json
7
+ import logging
8
8
  from typing import Any, cast
9
9
 
10
10
  import betterproto
@@ -172,6 +172,8 @@ class MammotionBaseCloudDevice(MammotionBaseDevice):
172
172
  self._mqtt.on_ready_event.add_subscribers(self.on_ready)
173
173
  self._mqtt.on_disconnected_event.add_subscribers(self.on_disconnect)
174
174
  self._mqtt.on_connected_event.add_subscribers(self.on_connect)
175
+ self._state_manager.cloud_gethash_ack_callback = self.datahash_response
176
+ self._state_manager.cloud_get_commondata_ack_callback = self.commdata_response
175
177
  self.set_queue_callback(self.queue_command)
176
178
 
177
179
  if self._mqtt.is_ready:
@@ -185,6 +187,12 @@ class MammotionBaseCloudDevice(MammotionBaseDevice):
185
187
  if self._ble_sync_task:
186
188
  self._ble_sync_task.cancel()
187
189
 
190
+ def set_notification_callback(self, func: Callable[[tuple[str, Any | None]], Awaitable[None]]) -> None:
191
+ self._state_manager.cloud_on_notification_callback = func
192
+
193
+ def set_queue_callback(self, func: Callable[[str, dict[str, Any]], Awaitable[bytes]]) -> None:
194
+ self._state_manager.cloud_queue_command_callback = func
195
+
188
196
  async def on_ready(self) -> None:
189
197
  """Callback for when MQTT is subscribed to events."""
190
198
  if self.stopped:
@@ -24,11 +24,10 @@ import os
24
24
  import ssl
25
25
  import threading
26
26
  import time
27
+ from types import TracebackType
27
28
 
28
29
  import crcmod
29
30
  import hyper
30
- from types import TracebackType
31
- from typing import Optional, Type
32
31
 
33
32
 
34
33
  def _assert_value(condition, error_msg):
@@ -60,7 +59,9 @@ class StreamHandler:
60
59
  def __enter__(self) -> None:
61
60
  pass
62
61
 
63
- def __exit__(self, type: Optional[Type[BaseException]], value: Optional[BaseException], trace: Optional[TracebackType]) -> None:
62
+ def __exit__(
63
+ self, type: type[BaseException] | None, value: BaseException | None, trace: TracebackType | None
64
+ ) -> None:
64
65
  pass
65
66
 
66
67
  def get_content_length(self):
@@ -90,7 +91,9 @@ class FileStreamHandler(StreamHandler):
90
91
  self.__f = open(self.__filename, "rb")
91
92
  self.__read_size = 0
92
93
 
93
- def __exit__(self, type: Optional[Type[BaseException]], value: Optional[BaseException], trace: Optional[TracebackType]) -> None:
94
+ def __exit__(
95
+ self, type: type[BaseException] | None, value: BaseException | None, trace: TracebackType | None
96
+ ) -> None:
94
97
  if self.__f:
95
98
  self.__f.close()
96
99
  self.__f = None
@@ -16,6 +16,7 @@
16
16
  #
17
17
  #
18
18
 
19
+ from enum import Enum
19
20
  import hashlib
20
21
  import hmac
21
22
  import json
@@ -31,7 +32,6 @@ import threading
31
32
  import time
32
33
  import urllib.parse
33
34
  import urllib.request
34
- from enum import Enum
35
35
 
36
36
  import paho.mqtt.client as mqtt
37
37
  from paho.mqtt.enums import CallbackAPIVersion
@@ -1046,7 +1046,7 @@ UxeCp6
1046
1046
  raise LinkKit.StateError("not in INITIALIZED state")
1047
1047
  if port < 1 or port > 65535:
1048
1048
  raise ValueError("port wrong")
1049
- if protocol != "MQTTv311" and protocol != "MQTTv31":
1049
+ if protocol not in ("MQTTv311", "MQTTv31"):
1050
1050
  raise ValueError("protocol wrong")
1051
1051
  if transport != "TCP":
1052
1052
  raise ValueError("transport wrong")
@@ -2,11 +2,11 @@
2
2
 
3
3
  import asyncio
4
4
  import base64
5
+ from collections.abc import Awaitable, Callable
5
6
  import hashlib
6
7
  import hmac
7
8
  import json
8
9
  import logging
9
- from collections.abc import Awaitable, Callable
10
10
  from logging import getLogger
11
11
 
12
12
  import betterproto
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pymammotion
3
- Version: 0.4.0a8
3
+ Version: 0.4.0b1
4
4
  Summary:
5
5
  License: GPL-3.0
6
6
  Author: Michael Arthur
@@ -25,7 +25,7 @@ Requires-Dist: jsonic (>=1.0.0,<2.0.0)
25
25
  Requires-Dist: mashumaro (>=3.13,<4.0)
26
26
  Requires-Dist: numpy (>=1.26.0)
27
27
  Requires-Dist: orjson (>=3.9.15,<4.0.0)
28
- Requires-Dist: paho-mqtt (==2.1.0)
28
+ Requires-Dist: paho-mqtt (>=2.1.0,<3.0.0)
29
29
  Requires-Dist: protobuf (>=4.23.1)
30
30
  Requires-Dist: py-jsonic (>=0.0.2,<0.0.3)
31
31
  Description-Content-Type: text/markdown
@@ -1,17 +1,17 @@
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=XLe1crlSmntZtt3MekGBZzqQ0zHh_c4sVAb_x-hDRe0,26117
4
- pymammotion/aliyun/model/aep_response.py,sha256=8f6GIP58ve8gd6AL3HBoXxsy0n2q4ygWvjELGnoOnVc,452
3
+ pymammotion/aliyun/cloud_gateway.py,sha256=bLTFivD7qpNXjzpM85Tao2y2urHXah5PZOdLc3iQ1nw,26099
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
- pymammotion/aliyun/model/dev_by_account_response.py,sha256=QZeopszFlGI7wltla-XDyGMbg5QSnb4Q1wTINkkaJyA,1026
7
- pymammotion/aliyun/model/login_by_oauth_response.py,sha256=IXSLZ6XnOliOnyXo5Bh0ErqFjA11puACh_9NH0sSJGQ,1262
8
- pymammotion/aliyun/model/regions_response.py,sha256=TBBWKF9j5iWjX4YbvMBHNDOnr0cEhbdfgApgCyJZhVg,651
9
- pymammotion/aliyun/model/session_by_authcode_response.py,sha256=qW0pnnRXfyEuMbb9ORc013sYqZwO8z4i_h_SfSaA_bw,419
10
- pymammotion/aliyun/model/stream_subscription_response.py,sha256=po765WASQDboVCosbPEfDHNlanBf-3WMrA6iV3ezooY,357
6
+ pymammotion/aliyun/model/dev_by_account_response.py,sha256=P9yYy4Z2tLkJSqXA_5XGaCUliSSVa5ILl7VoMtL_tCA,977
7
+ pymammotion/aliyun/model/login_by_oauth_response.py,sha256=g7JnvEjoa3SplHd-UqCuK6x0qtODpHlDyJCHRz7tfDI,1228
8
+ pymammotion/aliyun/model/regions_response.py,sha256=HSnpPcgpjr6VNXBQHw__gn-xWCkQ-MZ-Tmus9_va9mI,635
9
+ pymammotion/aliyun/model/session_by_authcode_response.py,sha256=naMDigtvmpf-Ikf5VdNrToaM8LR3PbO4rJFX8R_E0qM,388
10
+ pymammotion/aliyun/model/stream_subscription_response.py,sha256=7d0i8cNMAMX7aQjd2yebMDdqQkugcCzk-SD6oVtf18M,333
11
11
  pymammotion/aliyun/tmp_constant.py,sha256=M4Hq_lrGB3LZdX6R2XohRPFoK1NDnNV-pTJwJcJ9838,6650
12
12
  pymammotion/bluetooth/__init__.py,sha256=LAl8jqZ1fPh-3mLmViNQsP3s814C1vsocYUa6oSaXt0,36
13
- pymammotion/bluetooth/ble.py,sha256=Z2cO1EV2ndORKoJMzc2RdUdYbUe_PIzxCZICJg0_V24,2404
14
- pymammotion/bluetooth/ble_message.py,sha256=toiUjfrH9VXPgYSUdufoCT2ZKGO0QoXoFZLea1t-Vdg,18911
13
+ pymammotion/bluetooth/ble.py,sha256=HMBHdebocRm8je7fJ0PvWfb58ww8HUNwi-0kKTSEAtU,2391
14
+ pymammotion/bluetooth/ble_message.py,sha256=Uz64_PiQPqulEZIUhGg9g5ABr3wSVDChO8grfqsV4f8,18871
15
15
  pymammotion/bluetooth/const.py,sha256=CCqyHsYbB0BAYjwdhXt_n6eWWxmhlUrAFjvVv57mbvE,1749
16
16
  pymammotion/bluetooth/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
17
  pymammotion/bluetooth/data/convert.py,sha256=6DMwvzVr9FWCoQFIKSI2poFXjISc_m6X59g8FlVO0-o,800
@@ -30,51 +30,51 @@ pymammotion/data/model/device_limits.py,sha256=saW3iUvGq8WEn6CASn5hS5tVJpSeak4FD
30
30
  pymammotion/data/model/enums.py,sha256=EpKmO8yVUZyEnTY4yH0DMMVKYNQM42zpW1maUu0i3IE,1582
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
- pymammotion/data/model/generate_route_information.py,sha256=tCF3-HDm4O30hy8BJrTOaMpP3ArHbI9i9ZG7ARc5eLg,777
33
+ pymammotion/data/model/generate_route_information.py,sha256=pgjqURwmEIzjCMbl4Z5JDDkfxyUAdry1KhPfyir3-mU,777
34
34
  pymammotion/data/model/hash_list.py,sha256=ZPg5d1hy4bPMgPw5JkHujT06LIoEmXn7qSdQW79FF3A,6257
35
35
  pymammotion/data/model/location.py,sha256=PwmITejfI4pm7PI4rzqSuuHetwle6IJr_CV95435s2M,871
36
36
  pymammotion/data/model/mowing_modes.py,sha256=87R4T-hs6tZ0baPvdYII9Fd6ZbJRqkXj7MRFZ7nIPOY,941
37
- pymammotion/data/model/plan.py,sha256=mcadkSL7fQXy0iJ0q786I3GEQY4i6kmQXfW6Ri69lcQ,2906
37
+ pymammotion/data/model/plan.py,sha256=wGlcJT-w0EdbWK9jI838TCOm_MABFg7WoR664VB8RWg,2880
38
38
  pymammotion/data/model/rapid_state.py,sha256=mIdhAG_LZXpVcybxqTLgLXkNOmVmDTn04B9PGIDA8Ls,1251
39
- pymammotion/data/model/raw_data.py,sha256=NO7FMzg_nE3WxT_K2ny-pEqbMf25LnvoYMB86s6cZFY,6785
40
- pymammotion/data/model/region_data.py,sha256=OTV15vRyn9JORXsQPjWMNF1ZujuNhsOKl25KeqwMObA,3007
39
+ pymammotion/data/model/raw_data.py,sha256=oO8JX4JP8YuWGj_-6XdooCQn8MnXuNYJ3S6e502NzpU,6754
40
+ pymammotion/data/model/region_data.py,sha256=VokMRqB_o4OFL1TWAM90Fvm-1z4jcYrw3X2o760qpx4,2949
41
41
  pymammotion/data/model/report_info.py,sha256=9sPPfhBv8f0K-xuHRkKrbez-7nZ_oCND2vZYLuKvkBA,3436
42
42
  pymammotion/data/mqtt/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
43
43
  pymammotion/data/mqtt/event.py,sha256=r14gzZVxmlGVAwFdZQ1CUsMZFHHwRKnbt2VHnjugP28,5123
44
- pymammotion/data/mqtt/properties.py,sha256=kvphcjrDuJHuX8Az98-wKeFv_rSmu2Fz9YKLGodGSj0,3759
44
+ pymammotion/data/mqtt/properties.py,sha256=pX5JRVmmpVO04CSPm5xAGcSWA_OeLd0JnBagLsfiSEc,3755
45
45
  pymammotion/data/mqtt/status.py,sha256=DuNC3JdewLPKNqNHx76_FPXRvheYSiM-CdiVTCCYY8s,1079
46
- pymammotion/data/state_manager.py,sha256=t8RtRPUZuqp6dyMgy5bTV9W1Te-Ppq8-Qatj80o-85g,6140
46
+ pymammotion/data/state_manager.py,sha256=4NLSzJIfYi2fS_Y8qRgCyAo0eMd3qpmjJ961L_5Iy4o,7009
47
47
  pymammotion/event/__init__.py,sha256=mgATR6vPHACNQ-0zH5fi7NdzeTCDV1CZyaWPmtUusi8,115
48
48
  pymammotion/event/event.py,sha256=bj2RirSIRyBs0QvkcrOtwZWUX_8F3m1sySuHVyKmZLs,2143
49
49
  pymammotion/http/_init_.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
- pymammotion/http/encryption.py,sha256=BEJXNsnM-PIaqGocsGtWh07T8-jnBleYqjcqZoFrg2A,8330
51
- pymammotion/http/http.py,sha256=xRs1f7nECgLASzFv15MFrO_QluM1UI2ViEpBBN1-Zlg,6708
52
- pymammotion/http/model/http.py,sha256=SxpAtwJFlCQl6YfRFwJjpeOsB4QfQdhoOAKQzM6uMVI,2346
50
+ pymammotion/http/encryption.py,sha256=lzXu3WwBdQlzjXxWnlJuRgkCrKdPbxx5drhMitVKIEk,8287
51
+ pymammotion/http/http.py,sha256=gFAvmjGorqUh35U4b9z-Bqy8bKS02lLrp0Lu6Giz4xk,6687
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
55
  pymammotion/mammotion/commands/abstract_message.py,sha256=l2Wcyg7tIEjRGyQAk9T2rQVOLwilxG1hXTNf7811jGA,727
56
56
  pymammotion/mammotion/commands/mammotion_command.py,sha256=PM9UCuBCKp_TWDfkeVJsBelSbRrKosRa2LvHA-By1k8,2510
57
57
  pymammotion/mammotion/commands/messages/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
- pymammotion/mammotion/commands/messages/driver.py,sha256=DlOAC_yi1ycO5hKr5rfCpLmrqao6Mb6Fv1JWwMISnKE,3766
58
+ pymammotion/mammotion/commands/messages/driver.py,sha256=xyGuzBJeHUiu_9lsOznh2rftzuMEDeXMLB0s3a-C46w,3766
59
59
  pymammotion/mammotion/commands/messages/media.py,sha256=l-m4l2Vp1ZOHPHyJTceuLaLvdgHOEfmykkbDncCDUI4,1359
60
- pymammotion/mammotion/commands/messages/navigation.py,sha256=Z6RQK-pMh8o7_K_1yTENx3lkNBFQTU_ojunolSre0oM,23241
61
- pymammotion/mammotion/commands/messages/network.py,sha256=I3ot4rYxtI6saJWUe-6CYCnL35GpsJMi9O18D19KuyU,7623
60
+ pymammotion/mammotion/commands/messages/navigation.py,sha256=BE5h8xN2XCkcfynb5cQou24dt5tn7_shZG90nydJbww,23241
61
+ pymammotion/mammotion/commands/messages/network.py,sha256=vUjBvuiBhRkOA4nftqTFw6rFdXNjho-ZA9Y37hL2q5Q,7623
62
62
  pymammotion/mammotion/commands/messages/ota.py,sha256=g937HT_-OQXV6A3zUiZ53b45cOX6y-rzs5m-4b0IcTk,1473
63
- pymammotion/mammotion/commands/messages/system.py,sha256=6LWcucdt0nyzVkyd9BJjMLzR6D6wDwSQXinR5ItdDZk,14371
64
- pymammotion/mammotion/commands/messages/video.py,sha256=xili9khz4Op5NwjXfvIkeRYzQlQPIf8o8bnoYx-Ylpw,1319
63
+ pymammotion/mammotion/commands/messages/system.py,sha256=CYf_Ju5nMK9cFd0r5jOzEJ_w4k70PzassdhE8xLeSJU,14371
64
+ pymammotion/mammotion/commands/messages/video.py,sha256=JBPyK1C9gZ6B3QcNe3IUTUnn0QWNXR4Pwj9W0qNO9Ps,1304
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=2IKm7CYGmvRLpJaAKp25tL23UhOoSEHJ6On5D0N5TSk,10763
69
- pymammotion/mammotion/devices/mammotion.py,sha256=_4w8dGoA1dcylZWtfMJyr7z-bjp9WcIEnWJ3mPHqOKA,12632
70
- pymammotion/mammotion/devices/mammotion_bluetooth.py,sha256=HUOKnjYUWTGjksyQDCPKF_u3dWo2ddgrWCBXnJ2VkwA,18963
71
- pymammotion/mammotion/devices/mammotion_cloud.py,sha256=IzJeWeLL8maLGHRi1-FO_cnTTbfB0gp1o8l0lCn0vbc,13329
68
+ pymammotion/mammotion/devices/base.py,sha256=evNKt1PDDGPkm4wleIEC2dtHuyDP_nHRCg35nrQg6qg,10260
69
+ pymammotion/mammotion/devices/mammotion.py,sha256=-x9hf_M-_3fp5srHGBuMmO5DBsSDnwVGMyEiAEz5dW8,12685
70
+ pymammotion/mammotion/devices/mammotion_bluetooth.py,sha256=tfD8TIgKVd57Hrr-totXP0-WFSRFYBuoV5Dw0EpvOi4,19509
71
+ pymammotion/mammotion/devices/mammotion_cloud.py,sha256=nd1Uj6rF8UKHJbHC6nlPRrNQPggPXxfpydT0o0cWbMM,13835
72
72
  pymammotion/mqtt/__init__.py,sha256=Ocs5e-HLJvTuDpVXyECEsWIvwsUaxzj7lZ9mSYutNDY,105
73
73
  pymammotion/mqtt/linkkit/__init__.py,sha256=ENgc3ynd2kd9gMQR3-kgmCu6Ed9Y6XCIzU0zFReUlkk,80
74
- pymammotion/mqtt/linkkit/h2client.py,sha256=cca526y3NiZjMPodXWHGupgELpIBTc9MxM5fN4Ku0z0,19683
75
- pymammotion/mqtt/linkkit/linkkit.py,sha256=1kmQP3G-S2hOVZjL2HRu3anaaJR5YThljIXlnlfzzAg,132781
74
+ pymammotion/mqtt/linkkit/h2client.py,sha256=w9Nvi_nY4CLD_fw-pHtYChwQf7e2TiAGeqkY_sF4cf0,19659
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=Zpub35HFkixviTojnthKrYo0L_chodagHh4e3PWch4o,8876
77
+ pymammotion/mqtt/mammotion_mqtt.py,sha256=csnKHAOqjmNYtk2uAly2_Qg7J6ZNtiULZO7q5Poua30,8876
78
78
  pymammotion/proto/__init__.py,sha256=v3_P1LOsYRBN9qCAhaWrWMX7GWHrox9XD3hdZQxcPZM,190
79
79
  pymammotion/proto/basestation.proto,sha256=_x5gAz3FkZXS1jtq4GgZgaDCuRU-UV-7HTFdsfQ3zbo,1034
80
80
  pymammotion/proto/basestation.py,sha256=js64_N2xQYRxWPRdVNEapO0qe7vBlfYnjW5sE8hi7hw,2026
@@ -127,7 +127,7 @@ pymammotion/utility/map.py,sha256=GYscVMg2cX3IPlNpCBNHDW0S55yS1WGRf1iHnNZ7TfQ,22
127
127
  pymammotion/utility/movement.py,sha256=N75oAoAgFydqoaOedYIxGUHmuTCtPzAOtb-d_29tpfI,615
128
128
  pymammotion/utility/periodic.py,sha256=MbeSb9cfhxzYmdT_RiE0dZe3H9IfbQW_zSqhmSX2RUc,3321
129
129
  pymammotion/utility/rocker_util.py,sha256=6tX7sS87qoQC_tsxbx3NLL-HgS08wtzXiZkhDiz7uo0,7179
130
- pymammotion-0.4.0a8.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
131
- pymammotion-0.4.0a8.dist-info/METADATA,sha256=R7_WJcbRLeF1uFrAbhKXQ6chMTXprwfrJRh0dqKDOVo,3879
132
- pymammotion-0.4.0a8.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
133
- pymammotion-0.4.0a8.dist-info/RECORD,,
130
+ pymammotion-0.4.0b1.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
131
+ pymammotion-0.4.0b1.dist-info/METADATA,sha256=QzBQE6mluKSxxyVSZan9r9lsbv9EYV57h3mw789NUdE,3886
132
+ pymammotion-0.4.0b1.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
133
+ pymammotion-0.4.0b1.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.0.1
2
+ Generator: poetry-core 2.1.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any