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.
- pymammotion/data/model/device.py +1 -1
- pymammotion/data/model/hash_list.py +43 -3
- pymammotion/data/state_manager.py +2 -3
- pymammotion/http/http.py +2 -2
- pymammotion/mammotion/commands/messages/system.py +6 -7
- pymammotion/mammotion/control/joystick.py +8 -24
- pymammotion/mammotion/devices/mammotion.py +83 -56
- pymammotion/mqtt/mammotion_mqtt.py +2 -1
- pymammotion/utility/movement.py +17 -0
- {pymammotion-0.2.21.dist-info → pymammotion-0.2.23.dist-info}/METADATA +1 -1
- {pymammotion-0.2.21.dist-info → pymammotion-0.2.23.dist-info}/RECORD +13 -12
- {pymammotion-0.2.21.dist-info → pymammotion-0.2.23.dist-info}/LICENSE +0 -0
- {pymammotion-0.2.21.dist-info → pymammotion-0.2.23.dist-info}/WHEEL +0 -0
pymammotion/data/model/device.py
CHANGED
@@ -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 ==
|
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 ==
|
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 ==
|
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
|
-
|
57
|
-
self._device.map.
|
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.
|
53
|
-
self.
|
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
|
-
|
34
|
-
|
35
|
-
mctlsys.todev_knife_ctrl.CopyFrom(
|
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
|
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.
|
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) =
|
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 =
|
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 =
|
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 =
|
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 =
|
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.
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
373
|
-
|
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
|
-
|
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.
|
503
|
-
await self.
|
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.
|
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.
|
503
|
+
await self.queue_command("read_plan", sub_cmd=2, plan_index=0)
|
513
504
|
|
514
|
-
await self.
|
505
|
+
await self.queue_command("get_all_boundary_hash_list", sub_cmd=0)
|
515
506
|
|
516
|
-
await self.
|
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.
|
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.
|
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
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
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
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
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.
|
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 =
|
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
|
-
|
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
|
-
|
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
|
-
|
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)
|
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
|
@@ -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=
|
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=
|
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=
|
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=
|
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=
|
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=
|
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=
|
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=
|
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.
|
115
|
-
pymammotion-0.2.
|
116
|
-
pymammotion-0.2.
|
117
|
-
pymammotion-0.2.
|
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,,
|
File without changes
|
File without changes
|