pymammotion 0.4.22__py3-none-any.whl → 0.4.25__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.
@@ -11,7 +11,7 @@ import string
11
11
  import time
12
12
  import uuid
13
13
 
14
- from aiohttp import ClientSession
14
+ from aiohttp import ClientSession, ConnectionTimeoutError
15
15
  from alibabacloud_iot_api_gateway.models import CommonParams, Config, IoTApiRequest
16
16
  from alibabacloud_tea_util.client import Client as UtilClient
17
17
  from alibabacloud_tea_util.models import RuntimeOptions
@@ -24,6 +24,7 @@ from pymammotion.aliyun.model.dev_by_account_response import ListingDevByAccount
24
24
  from pymammotion.aliyun.model.login_by_oauth_response import LoginByOAuthResponse
25
25
  from pymammotion.aliyun.model.regions_response import RegionResponse
26
26
  from pymammotion.aliyun.model.session_by_authcode_response import SessionByAuthCodeResponse
27
+ from pymammotion.aliyun.regions import region_mappings
27
28
  from pymammotion.const import ALIYUN_DOMAIN, APP_KEY, APP_SECRET, APP_VERSION
28
29
  from pymammotion.http.http import MammotionHTTP
29
30
  from pymammotion.utility.datatype_converter import DatatypeConverter
@@ -178,14 +179,28 @@ class CloudIOTGateway:
178
179
  )
179
180
 
180
181
  # send request
181
- response = await client.async_do_request(
182
- "/living/account/region/get", "https", "POST", None, body, RuntimeOptions()
183
- )
184
- logger.debug(response.status_message)
185
- logger.debug(response.headers)
186
- logger.debug(response.status_code)
187
- logger.debug(response.body)
188
-
182
+ try:
183
+ response = await client.async_do_request(
184
+ "/living/account/region/get", "https", "POST", None, body, RuntimeOptions()
185
+ )
186
+ logger.debug(response.status_message)
187
+ logger.debug(response.headers)
188
+ logger.debug(response.status_code)
189
+ logger.debug(response.body)
190
+ except ConnectionTimeoutError:
191
+ body = {"data": {}, "code": 200}
192
+
193
+ region = region_mappings.get(country_code, "US")
194
+ body["data"]["shortRegionId"] = region
195
+ body["data"]["regionEnglishName"] = ""
196
+ body["data"]["oaApiGatewayEndpoint"] = f"living-account.{region}.aliyuncs.com"
197
+ body["data"]["regionId"] = region
198
+ body["data"]["mqttEndpoint"] = f"public.itls.{region}.aliyuncs.com:1883"
199
+ body["data"]["pushChannelEndpoint"] = f"living-accs.{region}.aliyuncs.com"
200
+ body["data"]["apiGatewayEndpoint"] = f"{region}.api-iot.aliyuncs.com"
201
+
202
+ RegionResponse.from_dict(body)
203
+ return body
189
204
  # Decode the response body
190
205
  response_body_str = response.body.decode("utf-8")
191
206
 
@@ -0,0 +1,62 @@
1
+ region_mappings = {
2
+ # Asia Pacific
3
+ "CN": "cn-hongkong", # China -> Hong Kong
4
+ "HK": "cn-hongkong", # Hong Kong
5
+ "TW": "cn-hongkong", # Taiwan -> Hong Kong
6
+ "MO": "cn-hongkong", # Macau -> Hong Kong
7
+ # Southeast Asia
8
+ "SG": "ap-southeast-1", # Singapore
9
+ "MY": "ap-southeast-3", # Malaysia
10
+ "ID": "ap-southeast-5", # Indonesia
11
+ "TH": "ap-southeast-1", # Thailand -> Singapore
12
+ "VN": "ap-southeast-1", # Vietnam -> Singapore
13
+ "PH": "ap-southeast-1", # Philippines -> Singapore
14
+ "BN": "ap-southeast-1", # Brunei -> Singapore
15
+ "KH": "ap-southeast-1", # Cambodia -> Singapore
16
+ "LA": "ap-southeast-1", # Laos -> Singapore
17
+ "MM": "ap-southeast-1", # Myanmar -> Singapore
18
+ # Australia/Oceania
19
+ "AU": "ap-southeast-2", # Australia
20
+ "NZ": "ap-southeast-2", # New Zealand -> Australia
21
+ "FJ": "ap-southeast-2", # Fiji -> Australia
22
+ "PG": "ap-southeast-2", # Papua New Guinea -> Australia
23
+ # South Asia
24
+ "IN": "ap-south-1", # India
25
+ "LK": "ap-south-1", # Sri Lanka -> India
26
+ "PK": "ap-south-1", # Pakistan -> India
27
+ "BD": "ap-south-1", # Bangladesh -> India
28
+ "NP": "ap-south-1", # Nepal -> India
29
+ "BT": "ap-south-1", # Bhutan -> India
30
+ "MV": "ap-south-1", # Maldives -> India
31
+ # Middle East
32
+ "AE": "me-east-1", # UAE
33
+ "SA": "me-east-1", # Saudi Arabia -> UAE
34
+ "QA": "me-east-1", # Qatar -> UAE
35
+ "KW": "me-east-1", # Kuwait -> UAE
36
+ "BH": "me-east-1", # Bahrain -> UAE
37
+ "OM": "me-east-1", # Oman -> UAE
38
+ "IL": "me-east-1", # Israel -> UAE
39
+ "TR": "me-east-1", # Turkey -> UAE
40
+ # Europe
41
+ "DE": "eu-central-1", # Germany
42
+ "FR": "eu-central-1", # France -> Germany
43
+ "IT": "eu-central-1", # Italy -> Germany
44
+ "ES": "eu-central-1", # Spain -> Germany
45
+ "GB": "eu-central-1", # UK -> Germany
46
+ "IE": "eu-central-1", # Ireland -> Germany
47
+ "NL": "eu-central-1", # Netherlands -> Germany
48
+ "BE": "eu-central-1", # Belgium -> Germany
49
+ "CH": "eu-central-1", # Switzerland -> Germany
50
+ "AT": "eu-central-1", # Austria -> Germany
51
+ "PL": "eu-central-1", # poland -> Germany
52
+ # North America
53
+ "US": "us-east-1", # USA
54
+ "CA": "us-east-1", # Canada -> US East
55
+ "MX": "us-west-1", # Mexico -> US West
56
+ # South America
57
+ "BR": "us-east-1", # Brazil -> US East
58
+ "AR": "us-east-1", # Argentina -> US East
59
+ "CL": "us-east-1", # Chile -> US East
60
+ "CO": "us-east-1", # Colombia -> US East
61
+ "PE": "us-east-1", # Peru -> US East
62
+ }
@@ -86,27 +86,43 @@ class FrameList(DataClassORJSONMixin):
86
86
 
87
87
  @dataclass
88
88
  class Plan(DataClassORJSONMixin):
89
+ pver: int = 0
89
90
  sub_cmd: int = 2
91
+ area: int = 0
92
+ work_time: int = 0
90
93
  version: str = ""
94
+ id: str = ""
91
95
  user_id: str = ""
92
96
  device_id: str = ""
93
97
  plan_id: str = ""
94
98
  task_id: str = ""
95
- start_time: str = "00:00"
99
+ job_id: str = ""
100
+ start_time: str = ""
101
+ end_time: str = ""
102
+ week: int = 0
96
103
  knife_height: int = 0
97
104
  model: int = 0
98
105
  edge_mode: int = 0
106
+ required_time: int = 0
107
+ route_angle: int = 0
99
108
  route_model: int = 0
100
109
  route_spacing: int = 0
101
110
  ultrasonic_barrier: int = 0
102
111
  total_plan_num: int = 0
112
+ plan_index: int = 0
113
+ result: int = 0
103
114
  speed: float = 0.0
104
115
  task_name: str = ""
105
- zone_hashs: list[str] = field(default_factory=list)
116
+ job_name: str = ""
117
+ zone_hashs: list[int] = field(default_factory=list)
106
118
  reserved: str = ""
107
119
  start_date: str = ""
120
+ end_date: str = ""
108
121
  trigger_type: int = 0
109
- remained_seconds: str = "-1"
122
+ day: int = 0
123
+ weeks: list[int] = field(default_factory=list)
124
+ remained_seconds: int = 0
125
+ toward_mode: int = 0
110
126
  toward_included_angle: int = 0
111
127
 
112
128
 
@@ -263,6 +279,9 @@ class HashList(DataClassORJSONMixin):
263
279
 
264
280
  return []
265
281
 
282
+ def update_plan(self, plan: Plan) -> None:
283
+ self.plan[plan.plan_index] = plan
284
+
266
285
  def update(self, hash_data: NavGetCommData | SvgMessage) -> bool:
267
286
  """Update the map data."""
268
287
 
@@ -9,7 +9,7 @@ import betterproto
9
9
 
10
10
  from pymammotion.data.model.device import MowingDevice
11
11
  from pymammotion.data.model.device_info import SideLight
12
- from pymammotion.data.model.hash_list import AreaHashNameList, NavGetCommData, NavGetHashListData, SvgMessage
12
+ from pymammotion.data.model.hash_list import AreaHashNameList, NavGetCommData, NavGetHashListData, Plan, SvgMessage
13
13
  from pymammotion.data.mqtt.properties import ThingPropertiesMessage
14
14
  from pymammotion.data.mqtt.status import ThingStatusMessage
15
15
  from pymammotion.proto import (
@@ -21,6 +21,7 @@ from pymammotion.proto import (
21
21
  LubaMsg,
22
22
  NavGetCommDataAck,
23
23
  NavGetHashListAck,
24
+ NavPlanJobSet,
24
25
  SvgMessageAckT,
25
26
  TimeCtrlLight,
26
27
  WifiIotStatusReport,
@@ -36,6 +37,7 @@ class StateManager:
36
37
  last_updated_at: datetime = datetime.now()
37
38
  cloud_gethash_ack_callback: Callable[[NavGetHashListAck], Awaitable[None]] | None = None
38
39
  cloud_get_commondata_ack_callback: Callable[[NavGetCommDataAck | SvgMessageAckT], Awaitable[None]] | None = None
40
+ cloud_get_plan_callback: Callable[[NavPlanJobSet], Awaitable[None]] | None = None
39
41
  cloud_on_notification_callback: Callable[[tuple[str, Any | None]], Awaitable[None]] | None = None
40
42
 
41
43
  # possibly don't need anymore
@@ -43,6 +45,7 @@ class StateManager:
43
45
 
44
46
  ble_gethash_ack_callback: Callable[[NavGetHashListAck], Awaitable[None]] | None = None
45
47
  ble_get_commondata_ack_callback: Callable[[NavGetCommDataAck | SvgMessageAckT], Awaitable[None]] | None = None
48
+ ble_get_plan_callback: Callable[[NavPlanJobSet], Awaitable[None]] | None = None
46
49
  ble_on_notification_callback: Callable[[tuple[str, Any | None]], Awaitable[None]] | None = None
47
50
 
48
51
  # possibly don't need anymore
@@ -97,6 +100,12 @@ class StateManager:
97
100
  elif self.ble_get_commondata_ack_callback:
98
101
  await self.ble_get_commondata_ack_callback(comm_data)
99
102
 
103
+ async def get_plan_callback(self, planjob: NavPlanJobSet) -> None:
104
+ if self.cloud_get_plan_callback:
105
+ await self.get_plan_callback(planjob)
106
+ elif self.ble_get_plan_callback:
107
+ await self.ble_get_plan_callback(planjob)
108
+
100
109
  async def notification(self, message: LubaMsg) -> None:
101
110
  """Handle protobuf notifications."""
102
111
  res = betterproto.which_one_of(message, "LubaSubMsg")
@@ -138,6 +147,11 @@ class StateManager:
138
147
  )
139
148
  if updated:
140
149
  await self.get_commondata_ack_callback(common_data)
150
+ case "todev_planjob_set":
151
+ planjob: NavPlanJobSet = nav_msg[1]
152
+ self._device.map.update_plan(Plan.from_dict(planjob.to_dict(casing=betterproto.Casing.SNAKE)))
153
+ await self.get_plan_callback(planjob)
154
+
141
155
  case "toapp_svg_msg":
142
156
  common_svg_data: SvgMessageAckT = nav_msg[1]
143
157
  updated = self._device.map.update(
@@ -10,7 +10,7 @@ from pymammotion.data.model import RegionData
10
10
  from pymammotion.data.model.device import MowingDevice
11
11
  from pymammotion.data.model.raw_data import RawMowerData
12
12
  from pymammotion.data.state_manager import StateManager
13
- from pymammotion.proto import LubaMsg, NavGetCommDataAck, NavGetHashListAck, SvgMessageAckT
13
+ from pymammotion.proto import LubaMsg, NavGetCommDataAck, NavGetHashListAck, NavPlanJobSet, SvgMessageAckT
14
14
  from pymammotion.utility.device_type import DeviceType
15
15
 
16
16
  _LOGGER = logging.getLogger(__name__)
@@ -89,6 +89,14 @@ class MammotionBaseDevice:
89
89
  region_data.current_frame = current_frame
90
90
  await self.queue_command("get_regional_data", regional_data=region_data)
91
91
 
92
+ async def plan_callback(self, plan: NavPlanJobSet) -> None:
93
+ if plan.plan_index != 0 and plan.total_plan_num - 1 != plan.plan_index:
94
+ index = plan.plan_index
95
+ while index in self.mower.map.plan and index < plan.total_plan_num:
96
+ index += 1
97
+ if index < plan.total_plan_num:
98
+ await self.queue_command("read_plan", plan_index=index)
99
+
92
100
  def _update_raw_data(self, data: bytes) -> None:
93
101
  """Update raw and model data from notifications."""
94
102
  tmp_msg = LubaMsg().parse(data)
@@ -216,7 +224,8 @@ class MammotionBaseDevice:
216
224
  if self._cloud_device and len(self.mower.map.area_name) == 0 and not DeviceType.is_luba1(self.mower.name):
217
225
  await self.queue_command("get_area_name_list", device_id=self._cloud_device.iotId)
218
226
 
219
- await self.queue_command("read_plan", sub_cmd=2, plan_index=0)
227
+ if len(self.mower.map.plan) == 0 or self.mower.map.plan[0].total_plan_num != len(self.mower.map.plan):
228
+ await self.queue_command("read_plan", sub_cmd=2, plan_index=0)
220
229
 
221
230
  for hash, frame in list(self.mower.map.area.items()):
222
231
  missing_frames = self.mower.map.find_missing_frames(frame)
@@ -91,6 +91,7 @@ class MammotionBaseBLEDevice(MammotionBaseDevice):
91
91
  self.set_queue_callback(self.queue_command)
92
92
  self._state_manager.ble_gethash_ack_callback = self.datahash_response
93
93
  self._state_manager.ble_get_commondata_ack_callback = self.commdata_response
94
+ self._state_manager.ble_get_plan_callback = self.plan_callback
94
95
  loop = asyncio.get_event_loop()
95
96
  loop.create_task(self.process_queue())
96
97
 
@@ -167,6 +167,7 @@ class MammotionBaseCloudDevice(MammotionBaseDevice):
167
167
  self._mqtt.on_connected_event.add_subscribers(self.on_connect)
168
168
  self._state_manager.cloud_gethash_ack_callback = self.datahash_response
169
169
  self._state_manager.cloud_get_commondata_ack_callback = self.commdata_response
170
+ self._state_manager.cloud_get_plan_callback = self.plan_callback
170
171
  self.set_queue_callback(self.queue_command)
171
172
 
172
173
  if self._mqtt.is_ready:
@@ -229,7 +230,7 @@ class MammotionBaseCloudDevice(MammotionBaseDevice):
229
230
  async def _ble_sync(self) -> None:
230
231
  if self.stopped or self._mqtt.is_connected is False:
231
232
  return
232
-
233
+
233
234
  command_bytes = self._commands.send_todev_ble_sync(3)
234
235
  try:
235
236
  await self._mqtt.send_command(self.iot_id, command_bytes)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pymammotion
3
- Version: 0.4.22
3
+ Version: 0.4.25
4
4
  Summary:
5
5
  License: GPL-3.0
6
6
  Author: Michael Arthur
@@ -1,7 +1,7 @@
1
1
  pymammotion/__init__.py,sha256=u1OHuD8Uj0qCOH4I7Lt5d7T-TPt1R0pY-bv8S6UfVxM,1587
2
2
  pymammotion/aliyun/__init__.py,sha256=T1lkX7TRYiL4nqYanG4l4MImV-SlavSbuooC-W-uUGw,29
3
3
  pymammotion/aliyun/client.py,sha256=DWHGBuRCMIHdm2AgIV8XsUCxc4kP7TAmhAlpxcrtz3s,9591
4
- pymammotion/aliyun/cloud_gateway.py,sha256=-mgofsFzUzh405ZurExnNQeoXsnPxB232Wv8G1WoSh0,27311
4
+ pymammotion/aliyun/cloud_gateway.py,sha256=5ffP4rwC-dCcyFOvk1pU0Pgi7euDlhoUYpgGL-X6NH8,28137
5
5
  pymammotion/aliyun/model/aep_response.py,sha256=EY4uMTJ4F9rvbcXnAOc5YKi7q__9kIVgfDwfyr65Gk0,421
6
6
  pymammotion/aliyun/model/connect_response.py,sha256=Yz-fEbDzgGPTo5Of2oAjmFkSv08T7ze80pQU4k-gKIU,824
7
7
  pymammotion/aliyun/model/dev_by_account_response.py,sha256=P9yYy4Z2tLkJSqXA_5XGaCUliSSVa5ILl7VoMtL_tCA,977
@@ -9,6 +9,7 @@ pymammotion/aliyun/model/login_by_oauth_response.py,sha256=g7JnvEjoa3SplHd-UqCuK
9
9
  pymammotion/aliyun/model/regions_response.py,sha256=HSnpPcgpjr6VNXBQHw__gn-xWCkQ-MZ-Tmus9_va9mI,635
10
10
  pymammotion/aliyun/model/session_by_authcode_response.py,sha256=0owdNcGFIP7rsVqLIf9rT-iOtvWmKCt2AW0cUUXwFiQ,427
11
11
  pymammotion/aliyun/model/stream_subscription_response.py,sha256=7d0i8cNMAMX7aQjd2yebMDdqQkugcCzk-SD6oVtf18M,333
12
+ pymammotion/aliyun/regions.py,sha256=ctlRGrmdE4-xgItl9slCANYOV502qVN5lkAU4lj92sk,2518
12
13
  pymammotion/aliyun/tea/core.py,sha256=Vnv4zclqxFdJcvCl013pAXz1MiU13WaHA0m7J_-nVX4,10147
13
14
  pymammotion/aliyun/tmp_constant.py,sha256=M4Hq_lrGB3LZdX6R2XohRPFoK1NDnNV-pTJwJcJ9838,6650
14
15
  pymammotion/bluetooth/__init__.py,sha256=LAl8jqZ1fPh-3mLmViNQsP3s814C1vsocYUa6oSaXt0,36
@@ -33,7 +34,7 @@ pymammotion/data/model/enums.py,sha256=EpKmO8yVUZyEnTY4yH0DMMVKYNQM42zpW1maUu0i3
33
34
  pymammotion/data/model/excute_boarder_params.py,sha256=9CpUqrygcle1C_1hDW-riLmm4map4ZbE842NXjcomEI,1394
34
35
  pymammotion/data/model/execute_boarder.py,sha256=9rd_h4fbcsXxgnLOd2rO2hWyD1abnTGc47QTEpp8DD0,1103
35
36
  pymammotion/data/model/generate_route_information.py,sha256=pgjqURwmEIzjCMbl4Z5JDDkfxyUAdry1KhPfyir3-mU,777
36
- pymammotion/data/model/hash_list.py,sha256=8HqUIz2_lVen-2iZwsWNz54odfErRS6mUCrKK861_wA,11628
37
+ pymammotion/data/model/hash_list.py,sha256=kB2p6OWIouEL2gD67JFxQSWkzUrG33-Kcg84E84ZZKg,12083
37
38
  pymammotion/data/model/location.py,sha256=PwmITejfI4pm7PI4rzqSuuHetwle6IJr_CV95435s2M,871
38
39
  pymammotion/data/model/mowing_modes.py,sha256=bBbRhDe-imZsXDR0TN0emQv6BiIkAlXJFb5isPEjgDk,1078
39
40
  pymammotion/data/model/plan.py,sha256=wGlcJT-w0EdbWK9jI838TCOm_MABFg7WoR664VB8RWg,2880
@@ -45,7 +46,7 @@ pymammotion/data/mqtt/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdr
45
46
  pymammotion/data/mqtt/event.py,sha256=r14gzZVxmlGVAwFdZQ1CUsMZFHHwRKnbt2VHnjugP28,5123
46
47
  pymammotion/data/mqtt/properties.py,sha256=pX5JRVmmpVO04CSPm5xAGcSWA_OeLd0JnBagLsfiSEc,3755
47
48
  pymammotion/data/mqtt/status.py,sha256=SgdrpE1Uldb01hybO6hYhgU1Sp1eILghC0UhMZMHrdQ,1091
48
- pymammotion/data/state_manager.py,sha256=H3xHcLorw4xBtDAhyigl5rd1SYkLaSTBB9qQ6XQV9SM,8646
49
+ pymammotion/data/state_manager.py,sha256=MiRnTzwHZ9lOZE_K-IjNPrtTu_MX75neUTTIQT2VBv4,9355
49
50
  pymammotion/event/__init__.py,sha256=mgATR6vPHACNQ-0zH5fi7NdzeTCDV1CZyaWPmtUusi8,115
50
51
  pymammotion/event/event.py,sha256=bj2RirSIRyBs0QvkcrOtwZWUX_8F3m1sySuHVyKmZLs,2143
51
52
  pymammotion/http/_init_.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -67,10 +68,10 @@ pymammotion/mammotion/commands/messages/video.py,sha256=YQGIxKx2prA0X01ovNmMkX6Y
67
68
  pymammotion/mammotion/control/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
68
69
  pymammotion/mammotion/control/joystick.py,sha256=QfBVxM_gxpWsZAGO90whtgxCI2tIZ3TTad9wHIPsU9s,5640
69
70
  pymammotion/mammotion/devices/__init__.py,sha256=f2qQFPgLGmV85W2hSlMUh5BYuht9o_Ar_JEAAMD4fsE,102
70
- pymammotion/mammotion/devices/base.py,sha256=w7ZucgZkOBdpPajrJs-W4oZpoDRpTDYgCCdVlwOP-uo,11901
71
+ pymammotion/mammotion/devices/base.py,sha256=FeESaqNcHqQ_4Ew8Hq2BCQQZQeS9M8lOvw8zBJLka2k,12435
71
72
  pymammotion/mammotion/devices/mammotion.py,sha256=ffzwsQqO9zDwMElWYMsxi-J5_rGaOOOHdAm5D3DXprc,13671
72
- pymammotion/mammotion/devices/mammotion_bluetooth.py,sha256=B1tpnC8vrbXGKhFq-l5LR86EcCvd6iHuW5kOkhpjwgY,19541
73
- pymammotion/mammotion/devices/mammotion_cloud.py,sha256=_huNqjEmQr6zHtMK4j4Gep_f-jPCcufXe_vfs8F55dk,13809
73
+ pymammotion/mammotion/devices/mammotion_bluetooth.py,sha256=nIuOW22Une1Zk1tN691jGUv_eqQJA8K2LuC9ohPUHAk,19612
74
+ pymammotion/mammotion/devices/mammotion_cloud.py,sha256=GSa9FPG2Ob7eP7L_WqV5Wk9LzL6dKbhFJsBTyLJBguI,13874
74
75
  pymammotion/mqtt/__init__.py,sha256=Ocs5e-HLJvTuDpVXyECEsWIvwsUaxzj7lZ9mSYutNDY,105
75
76
  pymammotion/mqtt/linkkit/__init__.py,sha256=ENgc3ynd2kd9gMQR3-kgmCu6Ed9Y6XCIzU0zFReUlkk,80
76
77
  pymammotion/mqtt/linkkit/h2client.py,sha256=w9Nvi_nY4CLD_fw-pHtYChwQf7e2TiAGeqkY_sF4cf0,19659
@@ -119,7 +120,7 @@ pymammotion/utility/map.py,sha256=GYscVMg2cX3IPlNpCBNHDW0S55yS1WGRf1iHnNZ7TfQ,22
119
120
  pymammotion/utility/movement.py,sha256=N75oAoAgFydqoaOedYIxGUHmuTCtPzAOtb-d_29tpfI,615
120
121
  pymammotion/utility/periodic.py,sha256=MbeSb9cfhxzYmdT_RiE0dZe3H9IfbQW_zSqhmSX2RUc,3321
121
122
  pymammotion/utility/rocker_util.py,sha256=6tX7sS87qoQC_tsxbx3NLL-HgS08wtzXiZkhDiz7uo0,7179
122
- pymammotion-0.4.22.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
123
- pymammotion-0.4.22.dist-info/METADATA,sha256=nyYzsPUltG7Qm3TLQ4EryiDU7BJmUjnt5jhW4COfrFc,3834
124
- pymammotion-0.4.22.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
125
- pymammotion-0.4.22.dist-info/RECORD,,
123
+ pymammotion-0.4.25.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
124
+ pymammotion-0.4.25.dist-info/METADATA,sha256=8-x044y_IVdK-evDfPwVGiFTZhXCxWJMGsWOak2SoqY,3834
125
+ pymammotion-0.4.25.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
126
+ pymammotion-0.4.25.dist-info/RECORD,,