pymammotion 0.2.28__py3-none-any.whl → 0.2.30__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 (55) hide show
  1. pymammotion/__init__.py +12 -9
  2. pymammotion/aliyun/cloud_gateway.py +57 -39
  3. pymammotion/aliyun/cloud_service.py +3 -3
  4. pymammotion/aliyun/dataclass/dev_by_account_response.py +1 -2
  5. pymammotion/aliyun/dataclass/session_by_authcode_response.py +1 -0
  6. pymammotion/bluetooth/ble.py +6 -6
  7. pymammotion/bluetooth/ble_message.py +30 -16
  8. pymammotion/bluetooth/data/convert.py +1 -1
  9. pymammotion/bluetooth/data/framectrldata.py +1 -1
  10. pymammotion/bluetooth/data/notifydata.py +6 -6
  11. pymammotion/const.py +1 -0
  12. pymammotion/data/model/__init__.py +2 -0
  13. pymammotion/data/model/account.py +1 -1
  14. pymammotion/data/model/device.py +31 -24
  15. pymammotion/data/model/device_config.py +71 -0
  16. pymammotion/data/model/enums.py +4 -4
  17. pymammotion/data/model/excute_boarder_params.py +5 -5
  18. pymammotion/data/model/execute_boarder.py +4 -4
  19. pymammotion/data/model/generate_route_information.py +18 -124
  20. pymammotion/data/model/hash_list.py +4 -7
  21. pymammotion/data/model/location.py +3 -3
  22. pymammotion/data/model/mowing_modes.py +1 -1
  23. pymammotion/data/model/plan.py +4 -4
  24. pymammotion/data/model/region_data.py +4 -4
  25. pymammotion/data/model/report_info.py +1 -1
  26. pymammotion/data/mqtt/event.py +8 -3
  27. pymammotion/data/state_manager.py +13 -12
  28. pymammotion/event/event.py +14 -14
  29. pymammotion/http/http.py +33 -45
  30. pymammotion/http/model/http.py +75 -0
  31. pymammotion/mammotion/commands/messages/driver.py +20 -23
  32. pymammotion/mammotion/commands/messages/navigation.py +47 -48
  33. pymammotion/mammotion/commands/messages/network.py +17 -35
  34. pymammotion/mammotion/commands/messages/system.py +6 -7
  35. pymammotion/mammotion/control/joystick.py +11 -10
  36. pymammotion/mammotion/devices/__init__.py +2 -2
  37. pymammotion/mammotion/devices/base.py +248 -0
  38. pymammotion/mammotion/devices/mammotion.py +52 -1042
  39. pymammotion/mammotion/devices/mammotion_bluetooth.py +447 -0
  40. pymammotion/mammotion/devices/mammotion_cloud.py +244 -0
  41. pymammotion/mqtt/mammotion_future.py +3 -2
  42. pymammotion/mqtt/mammotion_mqtt.py +23 -23
  43. pymammotion/proto/__init__.py +6 -0
  44. pymammotion/utility/constant/__init__.py +3 -1
  45. pymammotion/utility/conversions.py +1 -1
  46. pymammotion/utility/datatype_converter.py +9 -9
  47. pymammotion/utility/device_type.py +47 -18
  48. pymammotion/utility/map.py +2 -2
  49. pymammotion/utility/movement.py +2 -1
  50. pymammotion/utility/periodic.py +5 -5
  51. pymammotion/utility/rocker_util.py +1 -1
  52. {pymammotion-0.2.28.dist-info → pymammotion-0.2.30.dist-info}/METADATA +3 -1
  53. {pymammotion-0.2.28.dist-info → pymammotion-0.2.30.dist-info}/RECORD +55 -51
  54. {pymammotion-0.2.28.dist-info → pymammotion-0.2.30.dist-info}/LICENSE +0 -0
  55. {pymammotion-0.2.28.dist-info → pymammotion-0.2.30.dist-info}/WHEEL +0 -0
@@ -1,12 +1,13 @@
1
1
  from asyncio import Future
2
- from typing import Any
3
2
 
4
3
  import async_timeout
5
4
 
6
5
 
7
6
  class MammotionFuture:
8
7
  """Create futures for each MQTT Message."""
9
- def __init__(self):
8
+
9
+ def __init__(self, iot_id) -> None:
10
+ self.iot_id = iot_id
10
11
  self.fut: Future = Future()
11
12
  self.loop = self.fut.get_loop()
12
13
 
@@ -1,12 +1,15 @@
1
1
  """MammotionMQTT."""
2
+
2
3
  import asyncio
4
+ import base64
3
5
  import hashlib
4
6
  import hmac
5
7
  import json
6
8
  import logging
7
9
  from logging import getLogger
8
- from typing import Callable, Optional, cast, Awaitable
10
+ from typing import Awaitable, Callable, Optional
9
11
 
12
+ import betterproto
10
13
  from linkkit.linkkit import LinkKit
11
14
  from paho.mqtt.client import MQTTMessage
12
15
 
@@ -14,7 +17,7 @@ from pymammotion.aliyun.cloud_gateway import CloudIOTGateway
14
17
  from pymammotion.data.mqtt.event import ThingEventMessage
15
18
  from pymammotion.data.mqtt.properties import ThingPropertiesMessage
16
19
  from pymammotion.data.mqtt.status import ThingStatusMessage
17
- from pymammotion.proto import luba_msg_pb2
20
+ from pymammotion.proto.luba_msg import LubaMsg
18
21
 
19
22
  logger = getLogger(__name__)
20
23
 
@@ -29,18 +32,19 @@ class MammotionMQTT:
29
32
  device_name: str,
30
33
  device_secret: str,
31
34
  iot_token: str,
35
+ cloud_client: CloudIOTGateway,
32
36
  client_id: Optional[str] = None,
33
- ):
37
+ ) -> None:
34
38
  """Create instance of MammotionMQTT."""
35
39
  super().__init__()
36
- self._cloud_client = None
40
+ self._cloud_client = cloud_client
37
41
  self.is_connected = False
38
42
  self.is_ready = False
39
- self.on_connected: Optional[Callable[[],Awaitable[None]]] = None
40
- self.on_ready: Optional[Callable[[],Awaitable[None]]] = None
41
- self.on_error: Optional[Callable[[str],Awaitable[None]]] = None
42
- self.on_disconnected: Optional[Callable[[],Awaitable[None]]] = None
43
- self.on_message: Optional[Callable[[str, str, str],Awaitable[None]]] = None
43
+ self.on_connected: Optional[Callable[[], Awaitable[None]]] = None
44
+ self.on_ready: Optional[Callable[[], Awaitable[None]]] = None
45
+ self.on_error: Optional[Callable[[str], Awaitable[None]]] = None
46
+ self.on_disconnected: Optional[Callable[[], Awaitable[None]]] = None
47
+ self.on_message: Optional[Callable[[str, str, str], Awaitable[None]]] = None
44
48
 
45
49
  self._product_key = product_key
46
50
  self._device_name = device_name
@@ -77,20 +81,19 @@ class MammotionMQTT:
77
81
  self._linkkit_client.on_topic_message = self._thing_on_topic_message
78
82
  self._mqtt_host = f"{self._product_key}.iot-as-mqtt.{region_id}.aliyuncs.com"
79
83
 
80
- def connect_async(self):
84
+ def connect_async(self) -> None:
81
85
  """Connect async to MQTT Server."""
82
86
  logger.info("Connecting...")
83
87
  if self._linkkit_client.check_state() is LinkKit.LinkKitState.INITIALIZED:
84
88
  self._linkkit_client.thing_setup()
85
89
  self._linkkit_client.connect_async()
86
90
 
87
-
88
- def disconnect(self):
91
+ def disconnect(self) -> None:
89
92
  """Disconnect from MQTT Server."""
90
93
  logger.info("Disconnecting...")
91
94
  self._linkkit_client.disconnect()
92
95
 
93
- def _thing_on_thing_enable(self, user_data):
96
+ def _thing_on_thing_enable(self, user_data) -> None:
94
97
  """Is called when Thing is enabled."""
95
98
  logger.debug("on_thing_enable")
96
99
  self.is_connected = True
@@ -129,7 +132,7 @@ class MammotionMQTT:
129
132
  # command = MammotionCommand(device_name="Luba")
130
133
  # self._cloud_client.send_cloud_command(command.get_report_cfg())
131
134
 
132
- def _thing_on_topic_message(self, topic, payload, qos, user_data):
135
+ def _thing_on_topic_message(self, topic, payload, qos, user_data) -> None:
133
136
  """Is called when thing topic comes in."""
134
137
  logger.debug(
135
138
  "on_topic_message, receive message, topic:%s, payload:%s, qos:%d",
@@ -143,8 +146,7 @@ class MammotionMQTT:
143
146
  future = asyncio.run_coroutine_threadsafe(self.on_message(topic, payload, iot_id), self.loop)
144
147
  asyncio.wrap_future(future, loop=self.loop)
145
148
 
146
-
147
- def _thing_on_connect(self, session_flag, rc, user_data):
149
+ def _thing_on_connect(self, session_flag, rc, user_data) -> None:
148
150
  """Is called on thing connect."""
149
151
  self.is_connected = True
150
152
  if self.on_connected is not None:
@@ -155,7 +157,7 @@ class MammotionMQTT:
155
157
 
156
158
  # self._linkkit_client.subscribe_topic(f"/sys/{self._product_key}/{self._device_name}/#")
157
159
 
158
- def _on_disconnect(self, _client, _userdata):
160
+ def _on_disconnect(self, _client, _userdata) -> None:
159
161
  """Is called on disconnect."""
160
162
  logger.info("Disconnected")
161
163
  self.is_connected = False
@@ -164,8 +166,7 @@ class MammotionMQTT:
164
166
  future = asyncio.run_coroutine_threadsafe(self.on_disconnected(), self.loop)
165
167
  asyncio.wrap_future(future, loop=self.loop)
166
168
 
167
-
168
- def _on_message(self, _client, _userdata, message: MQTTMessage):
169
+ def _on_message(self, _client, _userdata, message: MQTTMessage) -> None:
169
170
  """Is called when message is received."""
170
171
  logger.info("Message on topic %s", message.topic)
171
172
 
@@ -174,9 +175,9 @@ class MammotionMQTT:
174
175
  event = ThingEventMessage(**payload)
175
176
  params = event.params
176
177
  if params.identifier == "device_protobuf_msg_event":
177
- content = cast(luba_msg_pb2, params.value.content)
178
+ content = LubaMsg().parse(base64.b64decode(params.value.content.proto))
178
179
 
179
- logger.info("Unhandled protobuf event: %s", content.WhichOneof("subMsg"))
180
+ logger.info("Unhandled protobuf event: %s", betterproto.which_one_of(content, "LubaSubMsg"))
180
181
  elif params.identifier == "device_warning_event":
181
182
  logger.debug("identifier event: %s", params.identifier)
182
183
  else:
@@ -191,7 +192,6 @@ class MammotionMQTT:
191
192
  logger.debug("Unhandled topic: %s", message.topic)
192
193
  logger.debug(payload)
193
194
 
194
- def get_cloud_client(self) -> Optional[CloudIOTGateway]:
195
+ def get_cloud_client(self) -> CloudIOTGateway:
195
196
  """Return internal cloud client."""
196
197
  return self._cloud_client
197
-
@@ -0,0 +1,6 @@
1
+ import betterproto
2
+
3
+
4
+ def has_field(message: betterproto.Message) -> bool:
5
+ """Check if the message has any fields serialized on wire."""
6
+ return betterproto.serialized_on_wire(message)
@@ -1 +1,3 @@
1
- from .device_constant import WorkMode
1
+ from .device_constant import PosType, WorkMode, device_mode
2
+
3
+ __all__ = ["WorkMode", "device_mode", "PosType"]
@@ -2,4 +2,4 @@ import math
2
2
 
3
3
 
4
4
  def parse_double(val: float, d: float):
5
- return val / math.pow(10.0, d)
5
+ return val / math.pow(10.0, d)
@@ -20,13 +20,13 @@ class DatatypeConverter:
20
20
  """
21
21
 
22
22
  if DatatypeConverter.encode_map is None:
23
- cArr = [0] * 64
24
- for i in range(26):
25
- cArr[i] = chr(i + 65)
26
- for i in range(26, 52):
27
- cArr[i] = chr(i - 26 + 97)
28
- for i in range(52, 62):
29
- cArr[i] = chr(i - 52 + 48)
23
+ cArr: list[str | int] = [0] * 64
24
+ for num in range(26):
25
+ cArr[num] = chr(num + 65)
26
+ for num_2 in range(26, 52):
27
+ cArr[num_2] = chr(num_2 - 26 + 97)
28
+ for num_3 in range(52, 62):
29
+ cArr[num_3] = chr(num_3 - 52 + 48)
30
30
  cArr[62] = "+"
31
31
  cArr[63] = "/"
32
32
  DatatypeConverter.encode_map = cArr
@@ -45,7 +45,7 @@ class DatatypeConverter:
45
45
  return DatatypeConverter.encode_map[i & 63]
46
46
 
47
47
  @staticmethod
48
- def _printBase64Binary(bArr, i=0, i2=None):
48
+ def _printBase64Binary(bArr: bytes, i: int = 0, i2=None):
49
49
  """Print the Base64 binary representation of a byte array.
50
50
 
51
51
  This function takes a byte array and optional start and end indices to
@@ -68,7 +68,7 @@ class DatatypeConverter:
68
68
  return "".join(cArr)
69
69
 
70
70
  @staticmethod
71
- def _printBase64Binary_core(bArr, i, i2, cArr, i3):
71
+ def _printBase64Binary_core(bArr: bytes, i, i2, cArr, i3):
72
72
  """Encode binary data into Base64 format.
73
73
 
74
74
  This function encodes binary data into Base64 format following the
@@ -11,12 +11,12 @@ class DeviceType(Enum):
11
11
  YUKA_MINI2 = (5, "Yuka-YM", "Yuka Mini 2")
12
12
  LUBA_VP = (6, "Luba-VP", "Luba VP")
13
13
 
14
- def __init__(self, value: int, name: str, model: str):
14
+ def __init__(self, value: int, name: str, model: str) -> None:
15
15
  self._value = value
16
16
  self._name = name
17
17
  self._model = model
18
18
 
19
- def get_name(self):
19
+ def get_name(self) -> str:
20
20
  return self._name
21
21
 
22
22
  def get_model(self):
@@ -28,7 +28,7 @@ class DeviceType(Enum):
28
28
  def get_value_str(self):
29
29
  return str(self._value)
30
30
 
31
- def set_value(self, value):
31
+ def set_value(self, value) -> None:
32
32
  self._value = value
33
33
 
34
34
  @staticmethod
@@ -54,11 +54,15 @@ class DeviceType(Enum):
54
54
  return DeviceType.LUBA_2
55
55
  elif value == 3:
56
56
  return DeviceType.LUBA_YUKA
57
+ elif value == 4:
58
+ return DeviceType.YUKA_MINI
59
+ elif value == 5:
60
+ return DeviceType.YUKA_MINI2
57
61
  else:
58
62
  return DeviceType.UNKNOWN
59
63
 
60
64
  @staticmethod
61
- def value_of_str(device_name, product_key=""):
65
+ def value_of_str(device_name: str, product_key: str = ""):
62
66
  """Determine the type of device based on the provided device name and
63
67
  product key.
64
68
 
@@ -78,21 +82,26 @@ class DeviceType(Enum):
78
82
  substring = device_name[:3]
79
83
  substring2 = device_name[:7]
80
84
 
81
- if DeviceType.RTK.name in substring or DeviceType.contain_rtk_product_key(product_key):
85
+ if DeviceType.RTK.get_name() in substring or DeviceType.contain_rtk_product_key(product_key):
82
86
  return DeviceType.RTK
83
- elif DeviceType.LUBA_2.name in substring2 or DeviceType.contain_luba_2_product_key(product_key):
87
+ elif DeviceType.LUBA_2.get_name() in substring2 or DeviceType.contain_luba_2_product_key(product_key):
84
88
  return DeviceType.LUBA_2
85
- elif DeviceType.LUBA_YUKA.name in substring2:
89
+ elif DeviceType.LUBA_YUKA.get_name() in substring2:
86
90
  return DeviceType.LUBA_YUKA
87
- elif DeviceType.LUBA.name in substring2 or DeviceType.contain_luba_product_key(product_key):
91
+ elif DeviceType.YUKA_MINI.get_name() in substring2:
92
+ return DeviceType.YUKA_MINI
93
+ elif DeviceType.YUKA_MINI2.get_name() in substring2:
94
+ return DeviceType.YUKA_MINI2
95
+ elif DeviceType.LUBA.get_name() in substring2 or DeviceType.contain_luba_product_key(product_key):
88
96
  return DeviceType.LUBA
89
97
  else:
98
+ print("unknown device type")
90
99
  return DeviceType.UNKNOWN
91
100
  except Exception:
92
101
  return DeviceType.UNKNOWN
93
102
 
94
103
  @staticmethod
95
- def has_4g(device_name, product_key=""):
104
+ def has_4g(device_name: str, product_key: str = ""):
96
105
  """Check if the device has 4G capability based on the device name and
97
106
  optional product key.
98
107
 
@@ -117,7 +126,7 @@ class DeviceType(Enum):
117
126
  return device_type.get_value() >= DeviceType.LUBA_2.get_value()
118
127
 
119
128
  @staticmethod
120
- def is_luba1(device_name, product_key=""):
129
+ def is_luba1(device_name: str, product_key: str = ""):
121
130
  """Check if the given device is of type LUBA.
122
131
 
123
132
  This function determines if the device specified by 'device_name' is of
@@ -141,7 +150,7 @@ class DeviceType(Enum):
141
150
  return device_type.get_value() == DeviceType.LUBA.get_value()
142
151
 
143
152
  @staticmethod
144
- def is_luba_2(device_name, product_key=""):
153
+ def is_luba_2(device_name: str, product_key: str = ""):
145
154
  """Check if the device type is LUBA 2 or higher based on the device name
146
155
  and optional product key.
147
156
 
@@ -162,7 +171,7 @@ class DeviceType(Enum):
162
171
  return device_type.get_value() >= DeviceType.LUBA_2.get_value()
163
172
 
164
173
  @staticmethod
165
- def is_yuka(device_name):
174
+ def is_yuka(device_name: str):
166
175
  """Check if the given device name corresponds to a LUBA_YUKA device type.
167
176
 
168
177
  Args:
@@ -173,10 +182,14 @@ class DeviceType(Enum):
173
182
 
174
183
  """
175
184
 
176
- return DeviceType.value_of_str(device_name).get_value() == DeviceType.LUBA_YUKA.get_value()
185
+ return (
186
+ DeviceType.value_of_str(device_name).get_value() == DeviceType.LUBA_YUKA.get_value()
187
+ or DeviceType.value_of_str(device_name).get_value() == DeviceType.YUKA_MINI.get_value()
188
+ or DeviceType.value_of_str(device_name).get_value() == DeviceType.YUKA_MINI2.get_value()
189
+ )
177
190
 
178
191
  @staticmethod
179
- def is_rtk(device_name, product_key=""):
192
+ def is_rtk(device_name: str, product_key: str = ""):
180
193
  """Check if the device type is within the range of RTK devices.
181
194
 
182
195
  This function determines if the device type corresponding to the given
@@ -200,7 +213,7 @@ class DeviceType(Enum):
200
213
  return DeviceType.RTK.get_value() <= device_type.get_value() < DeviceType.LUBA.get_value()
201
214
 
202
215
  @staticmethod
203
- def contain_rtk_product_key(product_key):
216
+ def contain_rtk_product_key(product_key) -> bool:
204
217
  """Check if the given product key is in a predefined list of RTK product
205
218
  keys.
206
219
 
@@ -217,7 +230,7 @@ class DeviceType(Enum):
217
230
  return product_key in ["a1qXkZ5P39W", "a1Nc68bGZzX"]
218
231
 
219
232
  @staticmethod
220
- def contain_luba_product_key(product_key):
233
+ def contain_luba_product_key(product_key) -> bool:
221
234
  """Check if the given product key is in the list of valid product keys.
222
235
 
223
236
  Args:
@@ -245,7 +258,7 @@ class DeviceType(Enum):
245
258
  ]
246
259
 
247
260
  @staticmethod
248
- def contain_luba_2_product_key(product_key):
261
+ def contain_luba_2_product_key(product_key) -> bool:
249
262
  """Check if the given product key is present in a predefined list.
250
263
 
251
264
  Args:
@@ -260,5 +273,21 @@ class DeviceType(Enum):
260
273
  return False
261
274
  return product_key in ["a1iMygIwxFC", "a1LLmy1zc0j", "a1LLmy1zc0j"]
262
275
 
276
+ @staticmethod
277
+ def contain_yuka_product_key(product_key) -> bool:
278
+ """Check if the given product key is present in a predefined list.
279
+
280
+ Args:
281
+ product_key (str): The product key to be checked.
282
+
283
+ Returns:
284
+ bool: True if the product key is in the predefined list, False otherwise.
285
+
286
+ """
287
+
288
+ if not product_key:
289
+ return False
290
+ return product_key in ["a1IQV0BrnXb"]
291
+
263
292
  def is_support_video(self):
264
- return self == DeviceType.LUBA_YUKA
293
+ return self != DeviceType.LUBA
@@ -6,7 +6,7 @@ from pymammotion.data.model.location import Point
6
6
 
7
7
 
8
8
  class CoordinateConverter:
9
- def __init__(self, latitude_rad: float, longitude_rad: float):
9
+ def __init__(self, latitude_rad: float, longitude_rad: float) -> None:
10
10
  # Initialize constants
11
11
  self.WGS84A = 6378137.0
12
12
  self.f_ = 3.3528106647474805e-21
@@ -26,7 +26,7 @@ class CoordinateConverter:
26
26
  # Call set_init_lla with provided lat/lon
27
27
  self.set_init_lla(latitude_rad, longitude_rad)
28
28
 
29
- def set_init_lla(self, lat_rad, lon_rad):
29
+ def set_init_lla(self, lat_rad, lon_rad) -> None:
30
30
  sin_lat = math.sin(lat_rad)
31
31
  cos_lat = math.cos(lat_rad)
32
32
  sin_lon = math.sin(lon_rad)
@@ -10,8 +10,9 @@ def transform_both_speeds(linear: float, angular: float, linear_percent: float,
10
10
  angular_speed = int(transform4[1] * 4.5)
11
11
  return linear_speed, angular_speed
12
12
 
13
+
13
14
  def get_percent(percent: float):
14
15
  if percent <= 15.0:
15
16
  return 0.0
16
17
 
17
- return percent - 15.0
18
+ return percent - 15.0
@@ -3,13 +3,13 @@ from contextlib import suppress
3
3
 
4
4
 
5
5
  class Periodic:
6
- def __init__(self, func, time):
6
+ def __init__(self, func, time) -> None:
7
7
  self.func = func
8
8
  self.time = time
9
9
  self.is_started = False
10
10
  self._task = None
11
11
 
12
- def start(self):
12
+ def start(self) -> None:
13
13
  """Start the task if it is not already started.
14
14
 
15
15
  If the task is not already started, it sets the 'is_started' flag to
@@ -21,7 +21,7 @@ class Periodic:
21
21
  # Start task to call func periodically:
22
22
  self._task = asyncio.ensure_future(self._run())
23
23
 
24
- async def stop(self):
24
+ async def stop(self) -> None:
25
25
  """Stop the task if it is currently running.
26
26
 
27
27
  If the task is currently running, it will be cancelled and awaited until
@@ -35,7 +35,7 @@ class Periodic:
35
35
  with suppress(asyncio.CancelledError):
36
36
  await self._task
37
37
 
38
- async def _run(self):
38
+ async def _run(self) -> None:
39
39
  """Run the specified function at regular intervals using asyncio.
40
40
 
41
41
  This method runs the specified function at regular intervals based on
@@ -84,7 +84,7 @@ def periodic(period):
84
84
 
85
85
  """
86
86
 
87
- async def wrapper(*args, **kwargs):
87
+ async def wrapper(*args, **kwargs) -> None:
88
88
  """Execute the given function periodically using asyncio tasks.
89
89
 
90
90
  This function continuously creates an asyncio task to execute the
@@ -11,7 +11,7 @@ class RockerControlUtil:
11
11
  thresholdValue_2 = 7
12
12
  thresholdValue_3 = 15
13
13
 
14
- def __init__(self):
14
+ def __init__(self) -> None:
15
15
  """Generated source for method __init__"""
16
16
 
17
17
  @classmethod
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pymammotion
3
- Version: 0.2.28
3
+ Version: 0.2.30
4
4
  Summary:
5
5
  License: GNU-3.0
6
6
  Author: Michael Arthur
@@ -18,11 +18,13 @@ Requires-Dist: alicloud-gateway-iot (>=1.0.0,<2.0.0)
18
18
  Requires-Dist: aliyun-iot-linkkit (>=1.2.12,<2.0.0)
19
19
  Requires-Dist: aliyun-python-sdk-iot (>=8.57.0,<9.0.0)
20
20
  Requires-Dist: async-timeout (>=4.0.3,<5.0.0)
21
+ Requires-Dist: autotyping (>=24.3.0,<25.0.0)
21
22
  Requires-Dist: betterproto (>=1.2.5,<2.0.0)
22
23
  Requires-Dist: bleak (>=0.21.0)
23
24
  Requires-Dist: bleak-retry-connector (>=3.5.0,<4.0.0)
24
25
  Requires-Dist: jsonic (>=1.0.0,<2.0.0)
25
26
  Requires-Dist: mashumaro (>=3.13,<4.0)
27
+ Requires-Dist: mypy (>=1.11.2,<2.0.0)
26
28
  Requires-Dist: nest-asyncio (>=1.6.0,<2.0.0)
27
29
  Requires-Dist: numpy (>=1.26.0,<2.0.0)
28
30
  Requires-Dist: orjson (>=3.9.15,<4.0.0)
@@ -1,68 +1,72 @@
1
- pymammotion/__init__.py,sha256=kmnjdt3AEMejIz5JK7h1tTJj5ZriAgKwZBa3ScA4-Ao,1516
1
+ pymammotion/__init__.py,sha256=jHCQrpJaG1jAoID9T4RT3g4JsZc0JpJqIcqjnA7cXd0,1605
2
2
  pymammotion/aliyun/__init__.py,sha256=T1lkX7TRYiL4nqYanG4l4MImV-SlavSbuooC-W-uUGw,29
3
- pymammotion/aliyun/cloud_gateway.py,sha256=L3efICH21kHNz2eXpReGoTBoTQU-PERX5RTyS7J6eDA,22576
4
- pymammotion/aliyun/cloud_service.py,sha256=YWcKuKK6iRWy5mTnBYgHxcCusiRGGzQt3spSf7dGDss,2183
3
+ pymammotion/aliyun/cloud_gateway.py,sha256=d2A4F-bCZD4Oz4wdBdyFBKBvFf1GZxCKvFRcDDpczRs,22686
4
+ pymammotion/aliyun/cloud_service.py,sha256=px7dUKow5Z7VyebjYzuKkzkm77XbUXYiFiYO_2e-UQ0,2207
5
5
  pymammotion/aliyun/dataclass/aep_response.py,sha256=8f6GIP58ve8gd6AL3HBoXxsy0n2q4ygWvjELGnoOnVc,452
6
6
  pymammotion/aliyun/dataclass/connect_response.py,sha256=Yz-fEbDzgGPTo5Of2oAjmFkSv08T7ze80pQU4k-gKIU,824
7
- pymammotion/aliyun/dataclass/dev_by_account_response.py,sha256=YV7I1Gd3RyHXi369AzEKa604VOV5bmtjD1mVElg9wOw,1033
7
+ pymammotion/aliyun/dataclass/dev_by_account_response.py,sha256=gskum11h9HPf4lKjLJKVrsxRl5BHaHJP2TPrI09SUYs,1032
8
8
  pymammotion/aliyun/dataclass/login_by_oauth_response.py,sha256=IXSLZ6XnOliOnyXo5Bh0ErqFjA11puACh_9NH0sSJGQ,1262
9
9
  pymammotion/aliyun/dataclass/regions_response.py,sha256=CVPpdFhDD6_emWHyLRzOdp2j3HLPtP8tlNyzGnr8AcI,690
10
- pymammotion/aliyun/dataclass/session_by_authcode_response.py,sha256=_5vsyIxocoecEqygPTmhOQnzjwaK845ssIqbTeaLcmk,406
10
+ pymammotion/aliyun/dataclass/session_by_authcode_response.py,sha256=1K8Uu_V6flSBU8kLCh1Qj59tD9aZQSn7X3hLKeouE_g,407
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=9fA8yw5xXNJRSbC68SdOMf2QJnHoD7RhhCjLFoF0c0I,2404
14
- pymammotion/bluetooth/ble_message.py,sha256=byibcxZ5b_hE3UzHAImyTcxdBOcya9rdswdtuLV8_hY,15663
13
+ pymammotion/bluetooth/ble.py,sha256=YfkfEK3TLJ8BaidjAXfUVFv8reLCu6U_lYa3Bo0pddw,2449
14
+ pymammotion/bluetooth/ble_message.py,sha256=m-RyxHncCWrYFoeNg_G9Co5afNADZuCm32jQaqaIFc8,16211
15
15
  pymammotion/bluetooth/const.py,sha256=CCqyHsYbB0BAYjwdhXt_n6eWWxmhlUrAFjvVv57mbvE,1749
16
16
  pymammotion/bluetooth/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
- pymammotion/bluetooth/data/convert.py,sha256=tlctvRODoYypy4FpMD_UBwB1bIn5hG0QdQQdNI0e1R8,792
18
- pymammotion/bluetooth/data/framectrldata.py,sha256=-qRmbHBXDLDEPOp-N9e44C9l3SUcJX7vyEvACx5DpDA,987
19
- pymammotion/bluetooth/data/notifydata.py,sha256=N1bphpueWUWbsWUcpZmMGt2CyCgLcKAFAIHG4RCnqBU,1947
20
- pymammotion/const.py,sha256=EEmZ1v4MqN2nPiNpS_mJQqaCkSNEa1EXUmtwZBUhXIg,329
17
+ pymammotion/bluetooth/data/convert.py,sha256=6DMwvzVr9FWCoQFIKSI2poFXjISc_m6X59g8FlVO0-o,800
18
+ pymammotion/bluetooth/data/framectrldata.py,sha256=qxhGQsTGsfPx-CarEMLkgBn_RJ6I2-exmr9AX2U4pFg,995
19
+ pymammotion/bluetooth/data/notifydata.py,sha256=jeROpoFmaZfNTidkLLm5VYeFbeIgDSi8waJ0nVLRUTA,1995
20
+ pymammotion/const.py,sha256=lWRxvTVdXnNHuxqvRkjO5ziK0Ic-fZMM6J2dbe5M6Nc,385
21
21
  pymammotion/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
- pymammotion/data/model/__init__.py,sha256=d8FlIgCcWqoH3jJSpnm-IY-25RM-l2nbRwLtWjSHo74,222
23
- pymammotion/data/model/account.py,sha256=stWLDtWPw1vOPp3xNdX-jWziMmdCvww4IYl00UUGKuI,139
24
- pymammotion/data/model/device.py,sha256=wDmmuCkWvuyoFhZxULCGeigMErmN5GX08NqYJrZbVhQ,10903
25
- pymammotion/data/model/device_config.py,sha256=E3rhLvUH4BuWEpBfylBYBEwn4G8u7c0QbKxWRElw3Sg,177
26
- pymammotion/data/model/enums.py,sha256=tD_vYsxstOV_lUkYF9uWkrjVOgAJPNnGevy_xmiu3WE,1558
27
- pymammotion/data/model/excute_boarder_params.py,sha256=kadSth4y-VXlXIZ6R-Ng-kDvBbM-3YRr8bmR86qR0U0,1355
28
- pymammotion/data/model/execute_boarder.py,sha256=oDb2h5tFtOQIa8OCNYaDugqCgCZBLjQRzQTNVcJVAGQ,1072
29
- pymammotion/data/model/generate_route_information.py,sha256=5w1MM1-gXGXb_AoEap_I5xTxAFbNSzXuqQFEkw4NmDs,4301
30
- pymammotion/data/model/hash_list.py,sha256=wHdM46r42_EF2OnXqBHNAyf-muDOibEB7NWVjc0gXYA,2683
31
- pymammotion/data/model/location.py,sha256=mafcOPFcb6niTiiZdDWIh_TbnS76jA3Cqd5paKbnhgc,752
32
- pymammotion/data/model/mowing_modes.py,sha256=aBTAucvcUPXL36Mw2YgrHfLcBKFYVvY97s2Vn12fLuE,824
33
- pymammotion/data/model/plan.py,sha256=7JvqAo0a9Yg1Vtifd4J3Dx3StEppxrMOfmq2-877kYg,2891
22
+ pymammotion/data/model/__init__.py,sha256=aSyroxYQQS-WMRi6WmWm2js4wLa9nmsi160gx9tts4o,323
23
+ pymammotion/data/model/account.py,sha256=vJM-KTf2q6eBfVC-UlNHBSmJvqHiCawZ40vnuhXhaz8,140
24
+ pymammotion/data/model/device.py,sha256=ejIMloTHlJcBi-qNFewTDt1K0pPJYpgjtJqqqhUqR1g,11182
25
+ pymammotion/data/model/device_config.py,sha256=fsUSfYsICD7oTZm9dIaNTNSwo54A94n9VAWJcJvEz2Y,2574
26
+ pymammotion/data/model/enums.py,sha256=EpKmO8yVUZyEnTY4yH0DMMVKYNQM42zpW1maUu0i3IE,1582
27
+ pymammotion/data/model/excute_boarder_params.py,sha256=9CpUqrygcle1C_1hDW-riLmm4map4ZbE842NXjcomEI,1394
28
+ pymammotion/data/model/execute_boarder.py,sha256=9rd_h4fbcsXxgnLOd2rO2hWyD1abnTGc47QTEpp8DD0,1103
29
+ pymammotion/data/model/generate_route_information.py,sha256=MkUBoqGtCAKmiVQ4Q1pEoDVHZs5uLIo7vhfWT4nGbtY,801
30
+ pymammotion/data/model/hash_list.py,sha256=-2z_g9bhr3A7EK_J-oYrOpg6MjUnhliO__76HLUdDSo,2690
31
+ pymammotion/data/model/location.py,sha256=H1h4Rhr0z_mDplNf1CP_ZCA3zM4_FJ_nMqzkbaoh7To,787
32
+ pymammotion/data/model/mowing_modes.py,sha256=UxQrRAHQNC_lJTOA0ms2wuLAAi5UEVTkvvSZjnFpUjE,826
33
+ pymammotion/data/model/plan.py,sha256=mcadkSL7fQXy0iJ0q786I3GEQY4i6kmQXfW6Ri69lcQ,2906
34
34
  pymammotion/data/model/rapid_state.py,sha256=BdJFD_DlhrVneg-PqEruqCoMty-CR7q_9Qna-hk1yd8,1171
35
- pymammotion/data/model/region_data.py,sha256=75xOTM1qeRbSROp53eIczw3yCmYM9DgMjMh8qE9xkKo,2880
36
- pymammotion/data/model/report_info.py,sha256=1Rj_yRZ9apWX296QHae5prdObDbs32bsQf9rzMz2KEQ,4458
35
+ pymammotion/data/model/region_data.py,sha256=FLuL6kA7lbbh_idRh1eT9EosDqh4SpAqzpqHuQRDM88,2888
36
+ pymammotion/data/model/report_info.py,sha256=gBSOmylSUdsYyIDsRms0L0nhQBx4V4LO-4tERvFpqXU,4475
37
37
  pymammotion/data/mqtt/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
38
- pymammotion/data/mqtt/event.py,sha256=ec5TfIBaPZefTKTM3SBweM758hYR3ocjb7rNUMpttn0,4522
38
+ pymammotion/data/mqtt/event.py,sha256=omGNFYLjPKV_IY0remhEc8vcx2LkI_spZNysosPIvUM,4536
39
39
  pymammotion/data/mqtt/properties.py,sha256=HkBPghr26L9_b4QaOi1DtPgb0UoPIOGSe9wb3kgnM6Y,2815
40
40
  pymammotion/data/mqtt/status.py,sha256=zqnlo-MzejEQZszl0i0Wucoc3E76x6UtI9JLxoBnu54,1067
41
- pymammotion/data/state_manager.py,sha256=T6slACOpbnhWVKmJD_XrBY9vrcCFc6q2l6jEf-g89NQ,3095
41
+ pymammotion/data/state_manager.py,sha256=OQlfLeCYFglgJZdHeqG8djaCwVDC-SqDqDeqz7Q7LR4,3171
42
42
  pymammotion/event/__init__.py,sha256=mgATR6vPHACNQ-0zH5fi7NdzeTCDV1CZyaWPmtUusi8,115
43
- pymammotion/event/event.py,sha256=Fy5-I1p92AO_D67VW4eHQqA4pOt7MZsrP--tVfIVUz8,1820
43
+ pymammotion/event/event.py,sha256=LFUhjUhlFRL2mEo1WKpn_jUJq_8K_Sw1EBWCYenWF0I,1932
44
44
  pymammotion/http/_init_.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
- pymammotion/http/http.py,sha256=XJ8_i20HwZ94BqKxCF29dRtRyP_gNOwqJ8gue4F7SOw,2491
45
+ pymammotion/http/http.py,sha256=OZHjQY9ZLdlsKK6MDqqV79JIH9WYWJe3-ey-WWbe2z4,2642
46
+ pymammotion/http/model/http.py,sha256=_aVrtZZyR4EdR6GcuqMP9vH8qBLN7nKu0U2OeraCcG0,1607
46
47
  pymammotion/mammotion/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
48
  pymammotion/mammotion/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
49
  pymammotion/mammotion/commands/abstract_message.py,sha256=nw6r7694yzl7iJKqRqhLmAPRjd_TL_Xo_-JXq2_a_ug,222
49
50
  pymammotion/mammotion/commands/mammotion_command.py,sha256=84XxnatnBm_5WQ_KOa2N0ltydQOhSvCme3fFqkuyEhg,1056
50
51
  pymammotion/mammotion/commands/messages/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
- pymammotion/mammotion/commands/messages/driver.py,sha256=IFtmp9gJ3p3U2xtTgWVpKBMbnVnUht6Ioih17po6Hr4,3783
52
+ pymammotion/mammotion/commands/messages/driver.py,sha256=ANIOEtjF23k7W_R_Yfgzxmc7p1KSBCF-l-tijUtw0Yg,3709
52
53
  pymammotion/mammotion/commands/messages/media.py,sha256=ps0l06CXy5Ej--gTNCsyKttwo7yHLVrJUpn-wNJYecs,1150
53
- pymammotion/mammotion/commands/messages/navigation.py,sha256=-qit4SrtMpnPr0qsub_HD0pzKMlYsyzspW5uf1Ym008,23217
54
- pymammotion/mammotion/commands/messages/network.py,sha256=Hv5u7omEdffpTsOKw-uIlfhRkd_X1GyvKJT-nswHJ2w,8490
54
+ pymammotion/mammotion/commands/messages/navigation.py,sha256=igP_SJfZPc7g9AaqP0qqN3tgnuZiaD9nqYdJG33_JQ0,23589
55
+ pymammotion/mammotion/commands/messages/network.py,sha256=gD7NKVKg8U2KNbPvgOxvTJXbznWdpdPQo9jBsQSx4OI,8027
55
56
  pymammotion/mammotion/commands/messages/ota.py,sha256=XkeuWBZtpYMMBze6r8UN7dJXbe2FxUNGNnjwBpXJKM0,1240
56
- pymammotion/mammotion/commands/messages/system.py,sha256=m4Cc1zUcLgMFCu6zp5rMupwjDnMD-1PM6hqXpXuXRtw,10984
57
+ pymammotion/mammotion/commands/messages/system.py,sha256=xm9Nj3wva9leVV1tyzfS_Hf53t-j7Nk8RBlFd00CQFM,10972
57
58
  pymammotion/mammotion/commands/messages/video.py,sha256=_8lJsU4sLm2CGnc7RDkueA0A51Ysui6x7SqFnhX8O2g,1007
58
59
  pymammotion/mammotion/control/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
- pymammotion/mammotion/control/joystick.py,sha256=mresPubTlWCuLQBOFD9KTyYJz5BjZgqt52BaRodemhM,5557
60
- pymammotion/mammotion/devices/__init__.py,sha256=T72jt0ejtMjo1rPmn_FeMF3pmp0LLeRRpc9WcDKEYYY,126
61
- pymammotion/mammotion/devices/mammotion.py,sha256=Cu6N_zq93TsOnvpd-nH7StopmkKTrzBOQsDKv_RYKEE,49478
60
+ pymammotion/mammotion/control/joystick.py,sha256=QfBVxM_gxpWsZAGO90whtgxCI2tIZ3TTad9wHIPsU9s,5640
61
+ pymammotion/mammotion/devices/__init__.py,sha256=f2qQFPgLGmV85W2hSlMUh5BYuht9o_Ar_JEAAMD4fsE,102
62
+ pymammotion/mammotion/devices/base.py,sha256=p_YUOolzcEvJGtyPPileAvc5jwYmTtEh0TsIG1LpvQ8,10692
63
+ pymammotion/mammotion/devices/mammotion.py,sha256=am2Rpsi1SdOaABrKC3ONBkQh17gfFcWTKAmV5mZsKK8,9301
64
+ pymammotion/mammotion/devices/mammotion_bluetooth.py,sha256=3XUjhE2sb_2aZnJlevmwxd99zR_4qZOfaK86h6hKV5E,17303
65
+ pymammotion/mammotion/devices/mammotion_cloud.py,sha256=O42-jloP-emGBErgOyRCZHtqt_FntCgcqOvMoieJWI4,9791
62
66
  pymammotion/mqtt/__init__.py,sha256=Ocs5e-HLJvTuDpVXyECEsWIvwsUaxzj7lZ9mSYutNDY,105
63
- pymammotion/mqtt/mammotion_future.py,sha256=WKnHqeHiS2Ut-SaDBNOxqh1jDLeTiyLTsJ7PNUexrjk,687
64
- pymammotion/mqtt/mammotion_mqtt.py,sha256=X012f5RvmZI52FlgchLSWbngvPnkv9M_gTYvJHakYaM,8127
65
- pymammotion/proto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
67
+ pymammotion/mqtt/mammotion_future.py,sha256=_OWqKOlUGl2yT1xOsXFQYpGd-1zQ63OxqXgy7KRQgYc,710
68
+ pymammotion/mqtt/mammotion_mqtt.py,sha256=pugfSXAEwrA-jPzUgBH5QvoON_B1iE6_Ouib8pLi_so,8301
69
+ pymammotion/proto/__init__.py,sha256=v3_P1LOsYRBN9qCAhaWrWMX7GWHrox9XD3hdZQxcPZM,190
66
70
  pymammotion/proto/basestation.proto,sha256=_x5gAz3FkZXS1jtq4GgZgaDCuRU-UV-7HTFdsfQ3zbo,1034
67
71
  pymammotion/proto/basestation.py,sha256=js64_N2xQYRxWPRdVNEapO0qe7vBlfYnjW5sE8hi7hw,2026
68
72
  pymammotion/proto/basestation_pb2.py,sha256=PTVlHcDLQeRV6qv7ZPjGke9MF68mpqoUeJA0Sw_AoT0,2776
@@ -104,16 +108,16 @@ pymammotion/proto/mctrl_sys.py,sha256=GVciaKPcp4h1qrIILHX_Pd76tKSBFlaEvFPF7FZsj8
104
108
  pymammotion/proto/mctrl_sys_pb2.py,sha256=DYemb514mlC7c27t-k1YqqBif0xxhLmnIWk8rXtSj1c,21497
105
109
  pymammotion/proto/mctrl_sys_pb2.pyi,sha256=Dj_1UM86kZ5MfcVyNC76Z0gKrfl5YFsVWP2b-bKoZvk,38912
106
110
  pymammotion/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
107
- pymammotion/utility/constant/__init__.py,sha256=tZz7szqIhrzNjfcLU3ysfINfg5VEBUAisd9AhP4mvT0,38
111
+ pymammotion/utility/constant/__init__.py,sha256=tcY0LDeD-qDDHx2LKt55KOyv9ZI0UfCNM6fknLCmm8s,110
108
112
  pymammotion/utility/constant/device_constant.py,sha256=rAEK60F52VyJL31uLnq0Y60D-0VK5gVm59yi9kBfndM,7123
109
- pymammotion/utility/conversions.py,sha256=ioVTEGTmq2-H9GSQbHlm2D9mNAhOTbabuiTaKPElyXQ,88
110
- pymammotion/utility/datatype_converter.py,sha256=v6zym2Zu0upxQjR-xDqXwi3516zpntSlg7LP8tQF5K8,4216
111
- pymammotion/utility/device_type.py,sha256=KYawu2glZMVlPmxRbA4kVFujXz3miHp3rJiOWRVj-GI,8285
112
- pymammotion/utility/map.py,sha256=aoi-Luzuph02hKynTofMoq3mnPstanx75MDAVv49CuY,2211
113
- pymammotion/utility/movement.py,sha256=JISPBWCOe4MqHbhmkewhV5aWykr1p6f01DzJfvOF-J8,613
114
- pymammotion/utility/periodic.py,sha256=9wJMfwXPlx6Mbp3Fws7LLTI34ZDKphH1bva_Ggyk32g,3281
115
- pymammotion/utility/rocker_util.py,sha256=syPL0QN4zMzHiTIkUKS7RXBBptjdbkfNlPddwUD5V3A,7171
116
- pymammotion-0.2.28.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
117
- pymammotion-0.2.28.dist-info/METADATA,sha256=UdcZD1jBGHdxwi4d3SWoE0VpgE7FIEB4kkpQS3cVRcY,3969
118
- pymammotion-0.2.28.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
119
- pymammotion-0.2.28.dist-info/RECORD,,
113
+ pymammotion/utility/conversions.py,sha256=v3YICy0zZwwBBzrUZgabI7GRfiDBnkiAX2qdtk3NxOY,89
114
+ pymammotion/utility/datatype_converter.py,sha256=SPM_HuaaD_XOawlqEnA8qlRRZXGba3WjA8kGOZgeBlQ,4284
115
+ pymammotion/utility/device_type.py,sha256=6Mmv8oJoJ0DQrfGhRGt3rg20f_GLwIRw4NtpAdF6wcE,9478
116
+ pymammotion/utility/map.py,sha256=GYscVMg2cX3IPlNpCBNHDW0S55yS1WGRf1iHnNZ7TfQ,2227
117
+ pymammotion/utility/movement.py,sha256=N75oAoAgFydqoaOedYIxGUHmuTCtPzAOtb-d_29tpfI,615
118
+ pymammotion/utility/periodic.py,sha256=MbeSb9cfhxzYmdT_RiE0dZe3H9IfbQW_zSqhmSX2RUc,3321
119
+ pymammotion/utility/rocker_util.py,sha256=6tX7sS87qoQC_tsxbx3NLL-HgS08wtzXiZkhDiz7uo0,7179
120
+ pymammotion-0.2.30.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
121
+ pymammotion-0.2.30.dist-info/METADATA,sha256=KOkVJ470-8fRi2_lwz9GDVJ7clwXavwOYcin6s30NaM,4052
122
+ pymammotion-0.2.30.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
123
+ pymammotion-0.2.30.dist-info/RECORD,,