pymammotion 0.2.21__py3-none-any.whl → 0.2.23__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.
@@ -34,7 +34,7 @@ class MowingDevice:
34
34
 
35
35
  def __init__(self):
36
36
  self.device = LubaMsg()
37
- self.map = HashList(area={}, path={}, obstacle={})
37
+ self.map = HashList(area={}, path={}, obstacle={}, hashlist=[])
38
38
  self.location = Location()
39
39
  self.report_data = ReportData()
40
40
  self.err_code_list = []
@@ -1,8 +1,15 @@
1
1
  from dataclasses import dataclass
2
+ from enum import IntEnum
2
3
 
3
4
  from pymammotion.proto.mctrl_nav import NavGetCommDataAck
4
5
 
5
6
 
7
+ class PathType(IntEnum):
8
+ """Path types for common data."""
9
+ AREA = 0
10
+ OBSTACLE = 1
11
+ PATH = 2
12
+
6
13
  @dataclass
7
14
  class FrameList:
8
15
  total_frame: int
@@ -13,23 +20,56 @@ class FrameList:
13
20
  class HashList:
14
21
  """stores our map data.
15
22
  [hashID, FrameList].
23
+ hashlist for all our hashIDs for verification
16
24
  """
17
25
 
18
26
  area: dict # type 0
19
27
  path: dict # type 2
20
28
  obstacle: dict # type 1
29
+ hashlist: list[int]
30
+
31
+ def set_hashlist(self, hashlist: list[int]):
32
+ self.hashlist = hashlist
33
+ self.area = {hash_id: frames for hash_id, frames in self.area.items() if hash_id in hashlist}
34
+ self.path = {hash_id: frames for hash_id, frames in self.path.items() if hash_id in hashlist}
35
+ self.obstacle = {hash_id: frames for hash_id, frames in self.obstacle.items() if hash_id in hashlist}
36
+
37
+
38
+ def missing_frame(self, hash_data: NavGetCommDataAck) -> list[int]:
39
+ if hash_data.type == PathType.AREA:
40
+ return self._find_missing_frames(self.area.get(hash_data.hash))
41
+
42
+ if hash_data.type == PathType.OBSTACLE:
43
+ return self._find_missing_frames(self.obstacle.get(hash_data.hash))
44
+
45
+ if hash_data.type == PathType.PATH:
46
+ return self._find_missing_frames(self.path.get(hash_data.hash))
47
+
48
+
21
49
 
22
50
  def update(self, hash_data: NavGetCommDataAck) -> bool:
23
51
  """Update the map data."""
24
- if hash_data.type == 0:
52
+ if hash_data.type == PathType.AREA:
25
53
  return self._add_hash_data(self.area, hash_data)
26
54
 
27
- if hash_data.type == 1:
55
+ if hash_data.type == PathType.OBSTACLE:
28
56
  return self._add_hash_data(self.obstacle, hash_data)
29
57
 
30
- if hash_data.type == 2:
58
+ if hash_data.type == PathType.PATH:
31
59
  return self._add_hash_data(self.path, hash_data)
32
60
 
61
+
62
+ @staticmethod
63
+ def _find_missing_frames(frame_list: FrameList) -> list[int]:
64
+ if frame_list.total_frame == len(frame_list.data):
65
+ return []
66
+ number_list = list(range(1, frame_list.total_frame+1))
67
+
68
+ current_frames = {frame.current_frame for frame in frame_list.data}
69
+ missing_numbers = [num for num in number_list if num not in current_frames]
70
+ return missing_numbers
71
+
72
+
33
73
  @staticmethod
34
74
  def _add_hash_data(hash_dict: dict, hash_data: NavGetCommDataAck) -> bool:
35
75
  if hash_dict.get(hash_data.hash) is None:
@@ -53,9 +53,8 @@ class StateManager:
53
53
  nav_msg = betterproto.which_one_of(message.nav, "SubNavMsg")
54
54
  match nav_msg[0]:
55
55
  case "toapp_gethash_ack":
56
- self._device.map.obstacle = dict()
57
- self._device.map.area = dict()
58
- self._device.map.path = dict()
56
+ hashlist_ack: NavGetHashListAck = nav_msg[1]
57
+ self._device.map.set_hashlist(hashlist_ack.data_couple)
59
58
  await self.gethash_ack_callback(nav_msg[1])
60
59
  case "toapp_get_commondata_ack":
61
60
  common_data: NavGetCommDataAck = nav_msg[1]
pymammotion/http/http.py CHANGED
@@ -49,8 +49,8 @@ class LoginResponseData(DataClassORJSONMixin):
49
49
  class MammotionHTTP:
50
50
  def __init__(self, response: Response):
51
51
  self._headers = dict()
52
- self._headers["Authorization"] = f"Bearer {response.data.access_token}"
53
- self.login_info = response.data
52
+ self.login_info = LoginResponseData.from_dict(response.data) if response.data else None
53
+ self._headers["Authorization"] = f"Bearer {self.login_info.access_token}" if response.data else None
54
54
  self.msg = response.msg
55
55
  self.code = response.code
56
56
 
@@ -30,20 +30,19 @@ class MessageSystem(AbstractMessage, ABC):
30
30
 
31
31
  def set_blade_control(self, on_off: int):
32
32
  mctlsys = mctrl_sys_pb2.MctlSys()
33
- sysKnifeControl = mctrl_sys_pb2.SysKnifeControl()
34
- sysKnifeControl.knife_status = on_off
35
- mctlsys.todev_knife_ctrl.CopyFrom(sysKnifeControl)
33
+ sys_knife_control = mctrl_sys_pb2.SysKnifeControl()
34
+ sys_knife_control.knife_status = on_off
35
+ mctlsys.todev_knife_ctrl.CopyFrom(sys_knife_control)
36
36
 
37
37
  return self.send_order_msg_sys(mctlsys)
38
38
 
39
39
  def get_device_product_model(self):
40
40
  return self.send_order_msg_sys(
41
- mctrl_sys_pb2.MctlSys(device_product_type_info=mctrl_sys_pb2.device_product_type_info_t()),
42
- 12,
43
- True,
41
+ mctrl_sys_pb2.MctlSys(device_product_type_info=mctrl_sys_pb2.device_product_type_info_t())
44
42
  )
45
43
 
46
44
  def read_and_set_sidelight(self, is_sidelight: bool, operate: int):
45
+ """Read state of sidelight as well as set it."""
47
46
  if is_sidelight:
48
47
  build = mctrl_sys_pb2.TimeCtrlLight(
49
48
  operate=operate,
@@ -80,7 +79,7 @@ class MessageSystem(AbstractMessage, ABC):
80
79
  param_id}, param_value={param_value}")
81
80
  return self.send_order_msg_sys(build2)
82
81
 
83
- def read_and_set_rt_k_paring_code(self, op: int, cgf: str):
82
+ def read_and_set_rtk_paring_code(self, op: int, cgf: str):
84
83
  print(f"Send read and write base station configuration quality op:{
85
84
  op}, cgf:{cgf}")
86
85
  return self.send_order_msg_sys(
@@ -8,13 +8,12 @@ from pyjoystick.utils import PeriodicThread
8
8
 
9
9
  from pymammotion import MammotionBaseBLEDevice
10
10
  from pymammotion.event import BleNotificationEvent
11
- from pymammotion.utility.rocker_util import RockerControlUtil
11
+ from pymammotion.utility.movement import transform_both_speeds, get_percent
12
12
 
13
13
  bleNotificationEvt = BleNotificationEvent()
14
14
 
15
15
  nest_asyncio.apply()
16
16
 
17
-
18
17
  class JoystickControl:
19
18
  """Joystick class for controlling Luba with a joystick"""
20
19
 
@@ -54,7 +53,7 @@ class JoystickControl:
54
53
  return
55
54
  self.stopped = True
56
55
  self.stopped = False
57
- (linear_speed, angular_speed) = self.transform_both_speeds(
56
+ (linear_speed, angular_speed) = transform_both_speeds(
58
57
  self.linear_speed,
59
58
  self.angular_speed,
60
59
  self.linear_percent,
@@ -75,23 +74,6 @@ class JoystickControl:
75
74
  self.mngr.start()
76
75
  self.worker.start()
77
76
 
78
- def get_percent(self, percent: float):
79
- if percent <= 15.0:
80
- return 0.0
81
-
82
- return percent - 15.0
83
-
84
- @staticmethod
85
- def transform_both_speeds(linear: float, angular: float, linear_percent: float, angular_percent: float):
86
- transfrom3 = RockerControlUtil.getInstance().transfrom3(linear, linear_percent)
87
- transform4 = RockerControlUtil.getInstance().transfrom3(angular, angular_percent)
88
-
89
- if transfrom3 is not None and len(transfrom3) > 0:
90
- linear_speed = transfrom3[0] * 10
91
- angular_speed = int(transform4[1] * 4.5)
92
- print(linear_speed, angular_speed)
93
- return linear_speed, angular_speed
94
-
95
77
  def handle_key_received(self, key):
96
78
  # print(key, "-", key.keytype, "-", key.number, "-", key.value)
97
79
 
@@ -129,11 +111,13 @@ class JoystickControl:
129
111
  # linear_speed==-1000
130
112
  print("case 1")
131
113
  if key.value > 0:
114
+ """Backwards."""
132
115
  self.linear_speed = 270.0
133
- self.linear_percent = self.get_percent(abs(key.value * 100))
116
+ self.linear_percent = get_percent(abs(key.value * 100))
134
117
  else:
118
+ """Forwards."""
135
119
  self.linear_speed = 90.0
136
- self.linear_percent = self.get_percent(abs(key.value * 100))
120
+ self.linear_percent = get_percent(abs(key.value * 100))
137
121
 
138
122
  case 2: # right (left right)
139
123
  # take left right values and convert to angular movement
@@ -143,12 +127,12 @@ class JoystickControl:
143
127
  # angular_speed==450
144
128
  if key.value > 0:
145
129
  self.angular_speed = 0.0
146
- self.angular_percent = self.get_percent(abs(key.value * 100))
130
+ self.angular_percent = get_percent(abs(key.value * 100))
147
131
  else:
148
132
  # angle=180.0
149
133
  # linear_speed=0//angular_speed=-450
150
134
  self.angular_speed = 180.0
151
- self.angular_percent = self.get_percent(abs(key.value * 100))
135
+ self.angular_percent = get_percent(abs(key.value * 100))
152
136
 
153
137
  else:
154
138
  match key.number:
@@ -18,7 +18,6 @@ from uuid import UUID
18
18
 
19
19
  import betterproto
20
20
  from aiohttp import ClientSession
21
- from bleak import BleakClient
22
21
  from bleak.backends.device import BLEDevice
23
22
  from bleak.backends.service import BleakGATTCharacteristic, BleakGATTServiceCollection
24
23
  from bleak.exc import BleakDBusError
@@ -44,7 +43,7 @@ from pymammotion.mqtt import MammotionMQTT
44
43
  from pymammotion.mqtt.mammotion_future import MammotionFuture
45
44
  from pymammotion.proto.luba_msg import LubaMsg
46
45
  from pymammotion.proto.mctrl_nav import NavGetCommDataAck, NavGetHashListAck
47
- from pymammotion.utility.rocker_util import RockerControlUtil
46
+ from pymammotion.utility.movement import get_percent, transform_both_speeds
48
47
 
49
48
 
50
49
  class CharacteristicMissingError(Exception):
@@ -346,37 +345,31 @@ class MammotionBaseDevice:
346
345
  self._notify_future: asyncio.Future[bytes] | None = None
347
346
  self._cloud_device = cloud_device
348
347
 
349
- def set_notifiction_callback(self, func: Callable[[],Awaitable[None]]):
348
+ def set_notification_callback(self, func: Callable[[],Awaitable[None]]):
350
349
  self._state_manager.on_notification_callback = func
351
350
 
352
351
  async def datahash_response(self, hash_ack: NavGetHashListAck):
353
352
  """Handle datahash responses."""
354
- result_hash = 0
355
- while hash_ack.data_couple[0] != result_hash:
356
- data = await self.queue_command("synchronize_hash_data", hash_num=hash_ack.data_couple[0])
357
- msg = LubaMsg().parse(data)
358
- if betterproto.serialized_on_wire(msg.nav.toapp_get_commondata_ack):
359
- result_hash = msg.nav.toapp_get_commondata_ack.hash
353
+ await self.queue_command("synchronize_hash_data", hash_num=hash_ack.data_couple[0])
360
354
 
361
355
  async def commdata_response(self, common_data: NavGetCommDataAck):
362
356
  """Handle common data responses."""
363
357
  total_frame = common_data.total_frame
364
358
  current_frame = common_data.current_frame
365
359
 
366
- if total_frame == current_frame:
360
+ missing_frames = self._mower.map.missing_frame(common_data)
361
+ if len(missing_frames) == 0:
367
362
  # get next in hash ack list
368
363
 
369
364
  data_hash = find_next_integer(self._mower.nav.toapp_gethash_ack.data_couple, common_data.hash)
370
365
  if data_hash is None:
371
366
  return
372
- result_hash = 0
373
- while data_hash != result_hash:
374
- data = await self.queue_command("synchronize_hash_data", hash_num=data_hash)
375
- msg = LubaMsg().parse(data)
376
- if betterproto.serialized_on_wire(msg.nav.toapp_get_commondata_ack):
377
- result_hash = msg.nav.toapp_get_commondata_ack.hash
367
+
368
+ await self.queue_command("synchronize_hash_data", hash_num=data_hash)
378
369
  else:
379
- # check if we have the data already first
370
+ if current_frame != missing_frames[0]-1:
371
+ current_frame = missing_frames[0]-1
372
+
380
373
  region_data = RegionData()
381
374
  region_data.hash = common_data.hash
382
375
  region_data.action = common_data.action
@@ -499,28 +492,28 @@ class MammotionBaseDevice:
499
492
 
500
493
  async def start_sync(self, retry: int):
501
494
  """Start synchronization with the device."""
502
- await self._send_command("get_device_base_info", retry)
503
- await self._send_command("get_report_cfg", retry)
495
+ await self.queue_command("get_device_base_info")
496
+ await self.queue_command("get_device_product_model")
497
+ await self.queue_command("get_report_cfg")
504
498
  """RTK and dock location."""
505
- await self._send_command_with_args("allpowerfull_rw", id=5, rw=1, context=1)
506
- """Error codes."""
507
- await self._send_command_with_args("allpowerfull_rw", id=5, rw=1, context=2)
508
- await self._send_command_with_args("allpowerfull_rw", id=5, rw=1, context=3)
499
+ await self.queue_command("allpowerfull_rw", id=5, rw=1, context=1)
509
500
 
510
501
  async def start_map_sync(self):
511
502
  """Start sync of map data."""
512
- await self._send_command_with_args("read_plan", sub_cmd=2, plan_index=0)
503
+ await self.queue_command("read_plan", sub_cmd=2, plan_index=0)
513
504
 
514
- await self._send_command_with_args("get_all_boundary_hash_list", sub_cmd=0)
505
+ await self.queue_command("get_all_boundary_hash_list", sub_cmd=0)
515
506
 
516
- await self._send_command_with_args("get_hash_response", total_frame=1, current_frame=1)
507
+ await self.queue_command("get_hash_response", total_frame=1, current_frame=1)
517
508
 
509
+
510
+ # work out why this crashes sometimes for better proto
518
511
  if self._cloud_device:
519
- await self._send_command_with_args(
512
+ await self.queue_command(
520
513
  "get_area_name_list", device_id=self._cloud_device.deviceName
521
514
  )
522
515
  if has_field(self._mower.net.toapp_wifi_iot_status):
523
- await self._send_command_with_args(
516
+ await self.queue_command(
524
517
  "get_area_name_list", device_id=self._mower.net.toapp_wifi_iot_status.devicename
525
518
  )
526
519
 
@@ -529,32 +522,40 @@ class MammotionBaseDevice:
529
522
  # sub_cmd 4 is dump location (yuka)
530
523
  # jobs list
531
524
  # hash_list_result = await self._send_command_with_args("get_all_boundary_hash_list", sub_cmd=3)
525
+ async def async_get_errors(self):
526
+ """Error codes."""
527
+ await self.queue_command("allpowerfull_rw", id=5, rw=1, context=2)
528
+ await self.queue_command("allpowerfull_rw", id=5, rw=1, context=3)
532
529
 
533
- async def move_forward(self):
534
- linear_speed = 1.0
535
- angular_speed = 0.0
536
- transfrom3 = RockerControlUtil.getInstance().transfrom3(90, 1000)
537
- transform4 = RockerControlUtil.getInstance().transfrom3(0, 0)
538
530
 
539
- if transfrom3 is not None and len(transfrom3) > 0:
540
- linear_speed = transfrom3[0] * 10
541
- angular_speed = int(transform4[1] * 4.5)
542
- await self._send_command_with_args("send_movement", linear_speed=linear_speed, angular_speed=angular_speed)
531
+ async def move_forward(self, linear: float):
532
+ """Move forward. values 0.0 1.0."""
533
+ linear_percent = get_percent(abs(linear * 100))
534
+ (linear_speed, angular_speed) = transform_both_speeds(90.0, 0.0, linear_percent, 0.0)
535
+ await self.queue_command("send_movement", linear_speed=linear_speed, angular_speed=angular_speed)
543
536
 
544
- async def move_stop(self):
545
- linear_speed = 0.0
546
- angular_speed = 0.0
547
- transfrom3 = RockerControlUtil.getInstance().transfrom3(0, 0)
548
- transform4 = RockerControlUtil.getInstance().transfrom3(0, 0)
537
+ async def move_back(self, linear: float):
538
+ """Move back. values 0.0 1.0."""
539
+ linear_percent = get_percent(abs(linear * 100))
540
+ (linear_speed, angular_speed) = transform_both_speeds(90.0, 0.0, linear_percent, 0.0)
541
+ await self.queue_command("send_movement", linear_speed=linear_speed, angular_speed=angular_speed)
542
+
543
+ async def move_left(self, angulur: float):
544
+ """Move forward. values 0.0 1.0."""
545
+ angular_percent = get_percent(abs(angulur * 100))
546
+ (linear_speed, angular_speed) = transform_both_speeds(0.0, 0.0, 0.0, angular_percent)
547
+ await self.queue_command("send_movement", linear_speed=linear_speed, angular_speed=angular_speed)
548
+
549
+ async def move_right(self, angulur: float):
550
+ """Move back. values 0.0 1.0."""
551
+ angular_percent = get_percent(abs(angulur * 100))
552
+ (linear_speed, angular_speed) = transform_both_speeds(0.0, 180.0, 0.0, angular_percent)
553
+ await self.queue_command("send_movement", linear_speed=linear_speed, angular_speed=angular_speed)
549
554
 
550
- if transfrom3 is not None and len(transfrom3) > 0:
551
- linear_speed = transfrom3[0] * 10
552
- angular_speed = int(transform4[1] * 4.5)
553
- await self._send_command_with_args("send_movement", linear_speed=linear_speed, angular_speed=angular_speed)
554
555
 
555
556
  async def command(self, key: str, **kwargs):
556
557
  """Send a command to the device."""
557
- return await self._send_command_with_args(key, **kwargs)
558
+ return await self.queue_command(key, **kwargs)
558
559
 
559
560
 
560
561
  class MammotionBaseBLEDevice(MammotionBaseDevice):
@@ -806,6 +807,33 @@ class MammotionBaseBLEDevice(MammotionBaseDevice):
806
807
  _LOGGER.debug("%s: Sending command: %s", self.name, key)
807
808
  await self._message.post_custom_data_bytes(command)
808
809
 
810
+ timeout = 2
811
+ timeout_handle = self.loop.call_at(self.loop.time() + timeout, _handle_timeout, self._notify_future)
812
+ timeout_expired = False
813
+ try:
814
+ notify_msg = await self._notify_future
815
+ except asyncio.TimeoutError:
816
+ timeout_expired = True
817
+ notify_msg = b''
818
+ self._notify_future.set_result(notify_msg)
819
+ finally:
820
+ if not timeout_expired:
821
+ timeout_handle.cancel()
822
+ self._notify_future = None
823
+
824
+ _LOGGER.debug("%s: Notification received: %s", self.name, notify_msg.hex())
825
+ return notify_msg
826
+
827
+ async def _execute_command_locked_old(self, key: str, command: bytes) -> bytes:
828
+ """Execute command and read response."""
829
+ assert self._client is not None
830
+ assert self._read_char is not None
831
+ assert self._write_char is not None
832
+ self._notify_future = self.loop.create_future()
833
+ self._key = key
834
+ _LOGGER.debug("%s: Sending command: %s", self.name, key)
835
+ await self._message.post_custom_data_bytes(command)
836
+
809
837
  retry_handle = self.loop.call_at(
810
838
  self.loop.time() + 2,
811
839
  lambda: asyncio.ensure_future(
@@ -961,7 +989,6 @@ class MammotionBaseCloudDevice(MammotionBaseDevice):
961
989
  self._ble_sync_task = None
962
990
  self.is_ready = False
963
991
  self.command_queue = asyncio.Queue()
964
- self.processing_task = asyncio.create_task(self._process_queue())
965
992
  self._mqtt_client = mqtt_client
966
993
  self.iot_id = cloud_device.iotId
967
994
  self.device = cloud_device
@@ -971,7 +998,7 @@ class MammotionBaseCloudDevice(MammotionBaseDevice):
971
998
  self.currentID = ""
972
999
  self.on_ready_callback: Optional[Callable[[], Awaitable[None]]] = None
973
1000
  self._waiting_queue = deque()
974
- self._operation_lock = threading.Lock()
1001
+ self._operation_lock = asyncio.Lock()
975
1002
 
976
1003
  self._mqtt_client.on_connected = self.on_connected
977
1004
  self._mqtt_client.on_disconnected = self.on_disconnected
@@ -986,11 +1013,13 @@ class MammotionBaseCloudDevice(MammotionBaseDevice):
986
1013
 
987
1014
  async def on_ready(self):
988
1015
  """Callback for when MQTT is subscribed to events."""
989
- if self.on_ready_callback:
990
- await self.on_ready_callback()
1016
+ loop = asyncio.get_event_loop()
991
1017
 
1018
+ if self.on_ready_callback:
1019
+ self.loop.create_task(self.on_ready_callback)
992
1020
  await self._ble_sync()
993
1021
  await self.run_periodic_sync_task()
1022
+ loop.create_task(self._process_queue())
994
1023
 
995
1024
  async def on_connected(self):
996
1025
  """Callback for when MQTT connects."""
@@ -1008,7 +1037,8 @@ class MammotionBaseCloudDevice(MammotionBaseDevice):
1008
1037
  async def run_periodic_sync_task(self) -> None:
1009
1038
  """Send ble sync to robot."""
1010
1039
  try:
1011
- await self._ble_sync()
1040
+ if not self._operation_lock.locked():
1041
+ await self._ble_sync()
1012
1042
  finally:
1013
1043
  self.schedule_ble_sync()
1014
1044
 
@@ -1116,7 +1146,7 @@ class MammotionBaseCloudDevice(MammotionBaseDevice):
1116
1146
  try:
1117
1147
  notify_msg = await future.async_get(timeout)
1118
1148
  except asyncio.TimeoutError:
1119
- raise
1149
+ notify_msg = b''
1120
1150
 
1121
1151
  _LOGGER.debug("%s: Message received", self.device.nickName)
1122
1152
 
@@ -1189,6 +1219,3 @@ class MammotionBaseCloudDevice(MammotionBaseDevice):
1189
1219
  def _disconnect(self):
1190
1220
  """Disconnect the MQTT client."""
1191
1221
  self._mqtt_client.disconnect()
1192
-
1193
-
1194
-
@@ -123,7 +123,8 @@ class MammotionMQTT:
123
123
 
124
124
  if self.on_ready:
125
125
  self.is_ready = True
126
- asyncio.run_coroutine_threadsafe(self.on_ready(), self.loop).result()
126
+ future = asyncio.run_coroutine_threadsafe(self.on_ready(), self.loop)
127
+ asyncio.wrap_future(future, loop=self.loop)
127
128
  # self._linkkit_client.query_ota_firmware()
128
129
  # command = MammotionCommand(device_name="Luba")
129
130
  # self._cloud_client.send_cloud_command(command.get_report_cfg())
@@ -0,0 +1,17 @@
1
+ from .rocker_util import RockerControlUtil
2
+
3
+
4
+ def transform_both_speeds(linear: float, angular: float, linear_percent: float, angular_percent: float):
5
+ transfrom3 = RockerControlUtil.getInstance().transfrom3(linear, linear_percent)
6
+ transform4 = RockerControlUtil.getInstance().transfrom3(angular, angular_percent)
7
+
8
+ if transfrom3 is not None and len(transfrom3) > 0:
9
+ linear_speed = transfrom3[0] * 10
10
+ angular_speed = int(transform4[1] * 4.5)
11
+ return linear_speed, angular_speed
12
+
13
+ def get_percent(percent: float):
14
+ if percent <= 15.0:
15
+ return 0.0
16
+
17
+ return percent - 15.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pymammotion
3
- Version: 0.2.21
3
+ Version: 0.2.23
4
4
  Summary:
5
5
  License: GNU-3.0
6
6
  Author: Michael Arthur
@@ -21,13 +21,13 @@ pymammotion/const.py,sha256=EEmZ1v4MqN2nPiNpS_mJQqaCkSNEa1EXUmtwZBUhXIg,329
21
21
  pymammotion/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  pymammotion/data/model/__init__.py,sha256=d8FlIgCcWqoH3jJSpnm-IY-25RM-l2nbRwLtWjSHo74,222
23
23
  pymammotion/data/model/account.py,sha256=stWLDtWPw1vOPp3xNdX-jWziMmdCvww4IYl00UUGKuI,139
24
- pymammotion/data/model/device.py,sha256=jIroL0wEAbxnVQWzd4vKYTUvWwqmUDF4VPss6T7J1bs,10390
24
+ pymammotion/data/model/device.py,sha256=XHw4q32TL6R60GmLkQiiJmlOv5Y3iHLNytR5ArtsySg,10403
25
25
  pymammotion/data/model/device_config.py,sha256=E3rhLvUH4BuWEpBfylBYBEwn4G8u7c0QbKxWRElw3Sg,177
26
26
  pymammotion/data/model/enums.py,sha256=tD_vYsxstOV_lUkYF9uWkrjVOgAJPNnGevy_xmiu3WE,1558
27
27
  pymammotion/data/model/excute_boarder_params.py,sha256=kadSth4y-VXlXIZ6R-Ng-kDvBbM-3YRr8bmR86qR0U0,1355
28
28
  pymammotion/data/model/execute_boarder.py,sha256=oDb2h5tFtOQIa8OCNYaDugqCgCZBLjQRzQTNVcJVAGQ,1072
29
29
  pymammotion/data/model/generate_route_information.py,sha256=5w1MM1-gXGXb_AoEap_I5xTxAFbNSzXuqQFEkw4NmDs,4301
30
- pymammotion/data/model/hash_list.py,sha256=z4y0mzbW8LQ5nsaHbMlt1y6uS4suB4D_VljAyIEjFR0,1171
30
+ pymammotion/data/model/hash_list.py,sha256=wHdM46r42_EF2OnXqBHNAyf-muDOibEB7NWVjc0gXYA,2683
31
31
  pymammotion/data/model/location.py,sha256=qO3G0U_eWP9alswbZXTpmYImIcXJeteBVHX1cGZGbHg,729
32
32
  pymammotion/data/model/mowing_modes.py,sha256=2GAF-xaHpv6CSGobYoNtfSi2if8_jW0nonCqN50SNx0,665
33
33
  pymammotion/data/model/plan.py,sha256=7JvqAo0a9Yg1Vtifd4J3Dx3StEppxrMOfmq2-877kYg,2891
@@ -38,11 +38,11 @@ pymammotion/data/mqtt/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdr
38
38
  pymammotion/data/mqtt/event.py,sha256=QkuFQtSUfg8eHisJ-llu-b6cpAlTePaP0JbqL6xZcvk,3900
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=jkedK5qAVDTGqIzlPNCmPpE-Pc1V4e-ZHW6Ds1ihJ50,3004
41
+ pymammotion/data/state_manager.py,sha256=Il9jJKXE_ga_wfnRS0bhSkQytcRXOzxb_wZAmL0VnQQ,2992
42
42
  pymammotion/event/__init__.py,sha256=mgATR6vPHACNQ-0zH5fi7NdzeTCDV1CZyaWPmtUusi8,115
43
43
  pymammotion/event/event.py,sha256=Fy5-I1p92AO_D67VW4eHQqA4pOt7MZsrP--tVfIVUz8,1820
44
44
  pymammotion/http/_init_.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
- pymammotion/http/http.py,sha256=izNb6BPy1qB-CXOWXkV8YhhpDQY3QdRVDIt3onQ7FX0,2406
45
+ pymammotion/http/http.py,sha256=XJ8_i20HwZ94BqKxCF29dRtRyP_gNOwqJ8gue4F7SOw,2491
46
46
  pymammotion/mammotion/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
47
  pymammotion/mammotion/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
48
  pymammotion/mammotion/commands/abstract_message.py,sha256=nw6r7694yzl7iJKqRqhLmAPRjd_TL_Xo_-JXq2_a_ug,222
@@ -53,15 +53,15 @@ pymammotion/mammotion/commands/messages/media.py,sha256=ps0l06CXy5Ej--gTNCsyKttw
53
53
  pymammotion/mammotion/commands/messages/navigation.py,sha256=-qit4SrtMpnPr0qsub_HD0pzKMlYsyzspW5uf1Ym008,23217
54
54
  pymammotion/mammotion/commands/messages/network.py,sha256=1a0BIhaBhBuhqYaK5EUqLbDgfzjzsIGrXS32wMKtxOU,8316
55
55
  pymammotion/mammotion/commands/messages/ota.py,sha256=XkeuWBZtpYMMBze6r8UN7dJXbe2FxUNGNnjwBpXJKM0,1240
56
- pymammotion/mammotion/commands/messages/system.py,sha256=nQ-g-0ESDQ2YBB6JW7IF4Q1bmTbX_baA4dOw2P3GixI,10957
56
+ pymammotion/mammotion/commands/messages/system.py,sha256=m4Cc1zUcLgMFCu6zp5rMupwjDnMD-1PM6hqXpXuXRtw,10984
57
57
  pymammotion/mammotion/commands/messages/video.py,sha256=_8lJsU4sLm2CGnc7RDkueA0A51Ysui6x7SqFnhX8O2g,1007
58
58
  pymammotion/mammotion/control/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
- pymammotion/mammotion/control/joystick.py,sha256=EWV20MMzQuhbLlNlXbsyZKSEpeM7x1CQL7saU4Pn0-g,6165
59
+ pymammotion/mammotion/control/joystick.py,sha256=mresPubTlWCuLQBOFD9KTyYJz5BjZgqt52BaRodemhM,5557
60
60
  pymammotion/mammotion/devices/__init__.py,sha256=T72jt0ejtMjo1rPmn_FeMF3pmp0LLeRRpc9WcDKEYYY,126
61
- pymammotion/mammotion/devices/mammotion.py,sha256=eZxYo4GWomEaSQNAm_kapE64nyjADj72vwsXmIkdidI,48239
61
+ pymammotion/mammotion/devices/mammotion.py,sha256=4cqUHjxjUbfZNeYIwtm1HmS6X7x4gDMUxi5I4uEZjag,49403
62
62
  pymammotion/mqtt/__init__.py,sha256=Ocs5e-HLJvTuDpVXyECEsWIvwsUaxzj7lZ9mSYutNDY,105
63
63
  pymammotion/mqtt/mammotion_future.py,sha256=WKnHqeHiS2Ut-SaDBNOxqh1jDLeTiyLTsJ7PNUexrjk,687
64
- pymammotion/mqtt/mammotion_mqtt.py,sha256=7V0JW2N9dshUJAGlg6d6Y5LKWYoXvlQd0o-9l6idPNg,8071
64
+ pymammotion/mqtt/mammotion_mqtt.py,sha256=X012f5RvmZI52FlgchLSWbngvPnkv9M_gTYvJHakYaM,8127
65
65
  pymammotion/proto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
66
66
  pymammotion/proto/basestation.proto,sha256=_x5gAz3FkZXS1jtq4GgZgaDCuRU-UV-7HTFdsfQ3zbo,1034
67
67
  pymammotion/proto/basestation.py,sha256=js64_N2xQYRxWPRdVNEapO0qe7vBlfYnjW5sE8hi7hw,2026
@@ -109,9 +109,10 @@ pymammotion/utility/constant/device_constant.py,sha256=aM69DJJy-h-btLP9RJezld1zm
109
109
  pymammotion/utility/datatype_converter.py,sha256=v6zym2Zu0upxQjR-xDqXwi3516zpntSlg7LP8tQF5K8,4216
110
110
  pymammotion/utility/device_type.py,sha256=KYawu2glZMVlPmxRbA4kVFujXz3miHp3rJiOWRVj-GI,8285
111
111
  pymammotion/utility/map.py,sha256=aoi-Luzuph02hKynTofMoq3mnPstanx75MDAVv49CuY,2211
112
+ pymammotion/utility/movement.py,sha256=JISPBWCOe4MqHbhmkewhV5aWykr1p6f01DzJfvOF-J8,613
112
113
  pymammotion/utility/periodic.py,sha256=9wJMfwXPlx6Mbp3Fws7LLTI34ZDKphH1bva_Ggyk32g,3281
113
114
  pymammotion/utility/rocker_util.py,sha256=syPL0QN4zMzHiTIkUKS7RXBBptjdbkfNlPddwUD5V3A,7171
114
- pymammotion-0.2.21.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
115
- pymammotion-0.2.21.dist-info/METADATA,sha256=GhYka3lZNszqjDllgK7DLJ184QnNH6ZMvsPguG2WxBo,3969
116
- pymammotion-0.2.21.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
117
- pymammotion-0.2.21.dist-info/RECORD,,
115
+ pymammotion-0.2.23.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
116
+ pymammotion-0.2.23.dist-info/METADATA,sha256=gKOZy5S7Pu2ee9TUEE8mISFQUQSljhSixqC5LSSyQdQ,3969
117
+ pymammotion-0.2.23.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
118
+ pymammotion-0.2.23.dist-info/RECORD,,