pymammotion 0.2.29__py3-none-any.whl → 0.2.31__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/__init__.py +11 -8
- pymammotion/aliyun/cloud_gateway.py +26 -24
- pymammotion/aliyun/cloud_service.py +3 -3
- pymammotion/aliyun/dataclass/dev_by_account_response.py +1 -1
- pymammotion/bluetooth/ble.py +5 -5
- pymammotion/bluetooth/ble_message.py +30 -16
- pymammotion/bluetooth/data/convert.py +1 -1
- pymammotion/bluetooth/data/framectrldata.py +1 -1
- pymammotion/bluetooth/data/notifydata.py +6 -6
- pymammotion/const.py +1 -0
- pymammotion/data/model/__init__.py +2 -0
- pymammotion/data/model/device.py +22 -20
- pymammotion/data/model/device_config.py +1 -1
- pymammotion/data/model/enums.py +4 -4
- pymammotion/data/model/excute_boarder_params.py +5 -5
- pymammotion/data/model/execute_boarder.py +4 -4
- pymammotion/data/model/hash_list.py +1 -1
- pymammotion/data/model/location.py +2 -2
- pymammotion/data/model/plan.py +4 -4
- pymammotion/data/model/region_data.py +4 -4
- pymammotion/data/model/report_info.py +1 -1
- pymammotion/data/mqtt/event.py +1 -1
- pymammotion/data/state_manager.py +9 -9
- pymammotion/event/event.py +14 -14
- pymammotion/http/http.py +29 -51
- pymammotion/http/model/http.py +75 -0
- pymammotion/mammotion/commands/messages/driver.py +20 -23
- pymammotion/mammotion/commands/messages/navigation.py +47 -48
- pymammotion/mammotion/commands/messages/network.py +17 -35
- pymammotion/mammotion/commands/messages/system.py +6 -7
- pymammotion/mammotion/control/joystick.py +10 -10
- pymammotion/mammotion/devices/__init__.py +2 -2
- pymammotion/mammotion/devices/base.py +248 -0
- pymammotion/mammotion/devices/mammotion.py +23 -1005
- pymammotion/mammotion/devices/mammotion_bluetooth.py +447 -0
- pymammotion/mammotion/devices/mammotion_cloud.py +246 -0
- pymammotion/mqtt/mammotion_future.py +2 -2
- pymammotion/mqtt/mammotion_mqtt.py +17 -14
- pymammotion/proto/__init__.py +6 -0
- pymammotion/utility/constant/__init__.py +3 -1
- pymammotion/utility/datatype_converter.py +9 -9
- pymammotion/utility/device_type.py +13 -13
- pymammotion/utility/map.py +2 -2
- pymammotion/utility/periodic.py +5 -5
- pymammotion/utility/rocker_util.py +1 -1
- {pymammotion-0.2.29.dist-info → pymammotion-0.2.31.dist-info}/METADATA +3 -1
- {pymammotion-0.2.29.dist-info → pymammotion-0.2.31.dist-info}/RECORD +49 -45
- {pymammotion-0.2.29.dist-info → pymammotion-0.2.31.dist-info}/LICENSE +0 -0
- {pymammotion-0.2.29.dist-info → pymammotion-0.2.31.dist-info}/WHEEL +0 -0
@@ -9,7 +9,7 @@ class ExecuteBorder(Serializable):
|
|
9
9
|
cmd = 0
|
10
10
|
params = ExecuteBorderParams(None, None, None)
|
11
11
|
|
12
|
-
def __init__(self, i, execute_border_params: ExecuteBorderParams):
|
12
|
+
def __init__(self, i, execute_border_params: ExecuteBorderParams) -> None:
|
13
13
|
"""Generated source for method __init__"""
|
14
14
|
super().__init__()
|
15
15
|
self.cmd = i
|
@@ -19,7 +19,7 @@ class ExecuteBorder(Serializable):
|
|
19
19
|
"""Generated source for method getCmd"""
|
20
20
|
return self.cmd
|
21
21
|
|
22
|
-
def set_cmd(self, i):
|
22
|
+
def set_cmd(self, i) -> None:
|
23
23
|
"""Generated source for method setCmd"""
|
24
24
|
self.cmd = i
|
25
25
|
|
@@ -27,10 +27,10 @@ class ExecuteBorder(Serializable):
|
|
27
27
|
"""Generated source for method getParams"""
|
28
28
|
return self.params
|
29
29
|
|
30
|
-
def set_params(self, execute_border_params):
|
30
|
+
def set_params(self, execute_border_params) -> None:
|
31
31
|
"""Generated source for method setParams"""
|
32
32
|
self.params = execute_border_params
|
33
33
|
|
34
|
-
def __str__(self):
|
34
|
+
def __str__(self) -> str:
|
35
35
|
"""Generated source for method toString"""
|
36
36
|
return "ExecuteBean{cmd=" + self.cmd + ", params=" + self.params + "}"
|
@@ -30,7 +30,7 @@ class HashList:
|
|
30
30
|
obstacle: dict # type 1
|
31
31
|
hashlist: list[int]
|
32
32
|
|
33
|
-
def set_hashlist(self, hashlist: list[int]):
|
33
|
+
def set_hashlist(self, hashlist: list[int]) -> None:
|
34
34
|
self.hashlist = hashlist
|
35
35
|
self.area = {hash_id: frames for hash_id, frames in self.area.items() if hash_id in hashlist}
|
36
36
|
self.path = {hash_id: frames for hash_id, frames in self.path.items() if hash_id in hashlist}
|
@@ -10,7 +10,7 @@ class Point:
|
|
10
10
|
latitude: float = 0.0
|
11
11
|
longitude: float = 0.0
|
12
12
|
|
13
|
-
def __init__(self, latitude=0.0, longitude=0.0):
|
13
|
+
def __init__(self, latitude: float = 0.0, longitude: float = 0.0) -> None:
|
14
14
|
self.latitude = latitude
|
15
15
|
self.longitude = longitude
|
16
16
|
|
@@ -33,7 +33,7 @@ class Location:
|
|
33
33
|
orientation: int = 0 # 360 degree rotation +-
|
34
34
|
work_zone: int = 0
|
35
35
|
|
36
|
-
def __init__(self):
|
36
|
+
def __init__(self) -> None:
|
37
37
|
self.device = Point()
|
38
38
|
self.RTK = Point()
|
39
39
|
self.dock = Dock()
|
pymammotion/data/model/plan.py
CHANGED
@@ -2,7 +2,7 @@ from typing import List
|
|
2
2
|
|
3
3
|
|
4
4
|
class Plan:
|
5
|
-
def __init__(self):
|
5
|
+
def __init__(self) -> None:
|
6
6
|
self.pver: int = 0
|
7
7
|
self.sub_cmd: int = 0
|
8
8
|
self.area: int = 0
|
@@ -31,9 +31,9 @@ class Plan:
|
|
31
31
|
self.speed: float = 0.0
|
32
32
|
self.task_name: str = ""
|
33
33
|
self.job_name: str = ""
|
34
|
-
self.zone_hashs:
|
34
|
+
self.zone_hashs: list[int] = []
|
35
35
|
self.reserved: str = ""
|
36
|
-
self.weeks:
|
36
|
+
self.weeks: list[int] = []
|
37
37
|
self.start_date: str = ""
|
38
38
|
self.end_date: str = ""
|
39
39
|
self.job_type: int = 0
|
@@ -46,7 +46,7 @@ class Plan:
|
|
46
46
|
self.path_order: int = 0
|
47
47
|
self.demond_angle: int = 90
|
48
48
|
|
49
|
-
def __str__(self):
|
49
|
+
def __str__(self) -> str:
|
50
50
|
return f"Plan(pver={self.pver}, sub_cmd={self.sub_cmd}, area={self.area}, work_time={self.work_time}, version='{self.version}', id='{self.id}', user_id='{self.user_id}', device_id='{self.device_id}', plan_id='{self.plan_id}', task_id='{self.task_id}', job_id='{self.job_id}', start_time='{self.start_time}', end_time='{self.end_time}', week={self.week}, knife_height={self.knife_height}, model={self.model}, edge_mode={self.edge_mode}, required_time={self.required_time}, route_angle={self.route_angle}, route_model={self.route_model}, route_spacing={self.route_spacing}, ultrasonic_barrier={self.ultrasonic_barrier}, total_plan_num={self.total_plan_num}, plan_index={self.plan_index}, result={self.result}, speed={self.speed}, task_name='{self.task_name}', job_name='{self.job_name}', zone_hashs={self.zone_hashs}, reserved='{self.reserved}', weeks={self.weeks}, start_date='{self.start_date}', end_date='{self.end_date}', job_type={self.job_type}, interval_days={self.interval_days}, count_down={self.count_down}, is_enable={self.is_enable}, mowing_laps={self.mowing_laps}, path_order={self.path_order}, demond_angle={self.demond_angle}, is_mow_work={self.is_mow_work}, is_sweeping_work={self.is_sweeping_work})"
|
51
51
|
|
52
52
|
def __eq__(self, other):
|
@@ -2,7 +2,7 @@ from typing import List, Optional
|
|
2
2
|
|
3
3
|
|
4
4
|
class RegionData:
|
5
|
-
def __init__(self):
|
5
|
+
def __init__(self) -> None:
|
6
6
|
self.hash: Optional[int] = None
|
7
7
|
self.action: int = 0
|
8
8
|
self.current_frame: int = 0
|
@@ -10,7 +10,7 @@ class RegionData:
|
|
10
10
|
self.data_len: int = 0
|
11
11
|
self.p_hash_a: Optional[int] = None
|
12
12
|
self.p_hash_b: Optional[int] = None
|
13
|
-
self.path: Optional[
|
13
|
+
self.path: Optional[list[list[float]]] = None
|
14
14
|
self.pver: int = 0
|
15
15
|
self.result: int = 0
|
16
16
|
self.sub_cmd: int = 0
|
@@ -68,10 +68,10 @@ class RegionData:
|
|
68
68
|
def set_current_frame(self, current_frame: int) -> None:
|
69
69
|
self.current_frame = current_frame
|
70
70
|
|
71
|
-
def get_path(self) -> Optional[
|
71
|
+
def get_path(self) -> Optional[list[list[float]]]:
|
72
72
|
return self.path
|
73
73
|
|
74
|
-
def set_path(self, path:
|
74
|
+
def set_path(self, path: list[list[float]]) -> None:
|
75
75
|
self.path = path
|
76
76
|
|
77
77
|
def get_hash(self) -> Optional[int]:
|
pymammotion/data/mqtt/event.py
CHANGED
@@ -14,7 +14,7 @@ class StateManager:
|
|
14
14
|
|
15
15
|
_device: MowingDevice
|
16
16
|
|
17
|
-
def __init__(self, device: MowingDevice):
|
17
|
+
def __init__(self, device: MowingDevice) -> None:
|
18
18
|
self._device = device
|
19
19
|
self.gethash_ack_callback: Optional[Callable[[NavGetHashListAck], Awaitable[None]]] = None
|
20
20
|
self.get_commondata_ack_callback: Optional[Callable[[NavGetCommDataAck], Awaitable[None]]] = None
|
@@ -24,11 +24,11 @@ class StateManager:
|
|
24
24
|
"""Get device."""
|
25
25
|
return self._device
|
26
26
|
|
27
|
-
def set_device(self, device: MowingDevice):
|
27
|
+
def set_device(self, device: MowingDevice) -> None:
|
28
28
|
"""Set device."""
|
29
29
|
self._device = device
|
30
30
|
|
31
|
-
async def notification(self, message: LubaMsg):
|
31
|
+
async def notification(self, message: LubaMsg) -> None:
|
32
32
|
"""Handle protobuf notifications."""
|
33
33
|
res = betterproto.which_one_of(message, "LubaSubMsg")
|
34
34
|
|
@@ -49,7 +49,7 @@ class StateManager:
|
|
49
49
|
if self.on_notification_callback:
|
50
50
|
await self.on_notification_callback()
|
51
51
|
|
52
|
-
async def _update_nav_data(self, message):
|
52
|
+
async def _update_nav_data(self, message) -> None:
|
53
53
|
"""Update nav data."""
|
54
54
|
nav_msg = betterproto.which_one_of(message.nav, "SubNavMsg")
|
55
55
|
match nav_msg[0]:
|
@@ -63,7 +63,7 @@ class StateManager:
|
|
63
63
|
if updated:
|
64
64
|
await self.get_commondata_ack_callback(common_data)
|
65
65
|
|
66
|
-
def _update_sys_data(self, message):
|
66
|
+
def _update_sys_data(self, message) -> None:
|
67
67
|
"""Update system."""
|
68
68
|
sys_msg = betterproto.which_one_of(message.sys, "SubSysMsg")
|
69
69
|
match sys_msg[0]:
|
@@ -76,14 +76,14 @@ class StateManager:
|
|
76
76
|
case "system_tard_state_tunnel":
|
77
77
|
self._device.run_state_update(sys_msg[1])
|
78
78
|
|
79
|
-
def _update_driver_data(self, message):
|
79
|
+
def _update_driver_data(self, message) -> None:
|
80
80
|
pass
|
81
81
|
|
82
|
-
def _update_net_data(self, message):
|
82
|
+
def _update_net_data(self, message) -> None:
|
83
83
|
pass
|
84
84
|
|
85
|
-
def _update_mul_data(self, message):
|
85
|
+
def _update_mul_data(self, message) -> None:
|
86
86
|
pass
|
87
87
|
|
88
|
-
def _update_ota_data(self, message):
|
88
|
+
def _update_ota_data(self, message) -> None:
|
89
89
|
pass
|
pymammotion/event/event.py
CHANGED
@@ -2,7 +2,7 @@ import asyncio
|
|
2
2
|
|
3
3
|
|
4
4
|
class Event:
|
5
|
-
def __init__(self):
|
5
|
+
def __init__(self) -> None:
|
6
6
|
self.__eventhandlers = []
|
7
7
|
|
8
8
|
def __iadd__(self, handler):
|
@@ -13,53 +13,53 @@ class Event:
|
|
13
13
|
self.__eventhandlers.remove(handler)
|
14
14
|
return self
|
15
15
|
|
16
|
-
async def __call__(self, *args, **kwargs):
|
16
|
+
async def __call__(self, *args, **kwargs) -> None:
|
17
17
|
await asyncio.gather(*[handler(*args, **kwargs) for handler in self.__eventhandlers])
|
18
18
|
|
19
19
|
|
20
20
|
class MoveEvent:
|
21
|
-
def __init__(self):
|
21
|
+
def __init__(self) -> None:
|
22
22
|
self.OnMoveFinished = Event()
|
23
23
|
|
24
|
-
async def MoveFinished(self):
|
24
|
+
async def MoveFinished(self) -> None:
|
25
25
|
# This function will be executed once blufi finishes after a movement command and will
|
26
26
|
# raise an event
|
27
27
|
await self.OnMoveFinished()
|
28
28
|
|
29
|
-
def AddSubscribersForMoveFinishedEvent(self, objMethod):
|
29
|
+
def AddSubscribersForMoveFinishedEvent(self, objMethod) -> None:
|
30
30
|
self.OnMoveFinished += objMethod
|
31
31
|
|
32
|
-
def RemoveSubscribersForMoveFinishedEvent(self, objMethod):
|
32
|
+
def RemoveSubscribersForMoveFinishedEvent(self, objMethod) -> None:
|
33
33
|
self.OnMoveFinished -= objMethod
|
34
34
|
|
35
35
|
|
36
36
|
class BleNotificationEvent:
|
37
|
-
def __init__(self):
|
37
|
+
def __init__(self) -> None:
|
38
38
|
self.OnBleNotification = Event()
|
39
39
|
|
40
|
-
async def BleNotification(self, data: bytearray):
|
40
|
+
async def BleNotification(self, data: bytearray) -> None:
|
41
41
|
# This function will be executed when data is received.
|
42
42
|
await self.OnBleNotification(data)
|
43
43
|
|
44
|
-
def AddSubscribersForBleNotificationEvent(self, objMethod):
|
44
|
+
def AddSubscribersForBleNotificationEvent(self, objMethod) -> None:
|
45
45
|
self.OnBleNotification += objMethod
|
46
46
|
|
47
|
-
def RemoveSubscribersForBleNotificationEvent(self, objMethod):
|
47
|
+
def RemoveSubscribersForBleNotificationEvent(self, objMethod) -> None:
|
48
48
|
self.OnBleNotification -= objMethod
|
49
49
|
|
50
50
|
|
51
51
|
class DataEvent:
|
52
52
|
"""Callbacks for data events."""
|
53
53
|
|
54
|
-
def __init__(self):
|
54
|
+
def __init__(self) -> None:
|
55
55
|
self.on_data_event = Event()
|
56
56
|
|
57
|
-
async def data_event(self, data):
|
57
|
+
async def data_event(self, data) -> None:
|
58
58
|
# This function will be executed when data is received.
|
59
59
|
await self.on_data_event(data)
|
60
60
|
|
61
|
-
def add_subscribers(self, obj_method):
|
61
|
+
def add_subscribers(self, obj_method) -> None:
|
62
62
|
self.on_data_event += obj_method
|
63
63
|
|
64
|
-
def remove_subscribers(self, obj_method):
|
64
|
+
def remove_subscribers(self, obj_method) -> None:
|
65
65
|
self.on_data_event -= obj_method
|
pymammotion/http/http.py
CHANGED
@@ -1,68 +1,47 @@
|
|
1
|
-
|
2
|
-
from typing import
|
1
|
+
import csv
|
2
|
+
from typing import cast
|
3
3
|
|
4
4
|
from aiohttp import ClientSession
|
5
|
-
from aiohttp.hdrs import AUTHORIZATION
|
6
|
-
from mashumaro import DataClassDictMixin
|
7
|
-
from mashumaro.mixins.orjson import DataClassORJSONMixin
|
8
5
|
|
9
|
-
from pymammotion.aliyun.dataclass.connect_response import Device
|
10
6
|
from pymammotion.const import (
|
7
|
+
MAMMOTION_API_DOMAIN,
|
11
8
|
MAMMOTION_CLIENT_ID,
|
12
9
|
MAMMOTION_CLIENT_SECRET,
|
13
10
|
MAMMOTION_DOMAIN,
|
14
11
|
)
|
15
|
-
|
16
|
-
DataT = TypeVar("DataT")
|
17
|
-
|
18
|
-
|
19
|
-
@dataclass
|
20
|
-
class Response(DataClassDictMixin, Generic[DataT]):
|
21
|
-
code: int
|
22
|
-
msg: str
|
23
|
-
data: DataT | None = None
|
24
|
-
|
25
|
-
|
26
|
-
@dataclass
|
27
|
-
class LoginResponseUserInformation(DataClassORJSONMixin):
|
28
|
-
areaCode: str
|
29
|
-
domainAbbreviation: str
|
30
|
-
email: Optional[str]
|
31
|
-
userId: str
|
32
|
-
userAccount: str
|
33
|
-
authType: str
|
34
|
-
|
35
|
-
|
36
|
-
@dataclass
|
37
|
-
class LoginResponseData(DataClassORJSONMixin):
|
38
|
-
access_token: str
|
39
|
-
token_type: Literal["bearer"]
|
40
|
-
refresh_token: str
|
41
|
-
expires_in: int
|
42
|
-
scope: Literal["read"]
|
43
|
-
grant_type: Literal["password"]
|
44
|
-
authorization_code: str
|
45
|
-
userInformation: LoginResponseUserInformation
|
46
|
-
jti: str
|
12
|
+
from pymammotion.http.model.http import ErrorInfo, LoginResponseData, Response
|
47
13
|
|
48
14
|
|
49
15
|
class MammotionHTTP:
|
50
|
-
def __init__(self, response: Response):
|
16
|
+
def __init__(self, response: Response) -> None:
|
51
17
|
self._headers = dict()
|
52
18
|
self.login_info = LoginResponseData.from_dict(response.data) if response.data else None
|
53
19
|
self._headers["Authorization"] = f"Bearer {self.login_info.access_token}" if response.data else None
|
54
20
|
self.msg = response.msg
|
55
21
|
self.code = response.code
|
56
22
|
|
57
|
-
async def get_all_error_codes(self):
|
58
|
-
async with ClientSession() as session:
|
23
|
+
async def get_all_error_codes(self) -> list[ErrorInfo]:
|
24
|
+
async with ClientSession(MAMMOTION_API_DOMAIN) as session:
|
59
25
|
async with session.post(
|
60
|
-
"code/record/export-data",
|
26
|
+
"/user-server/v1/code/record/export-data",
|
61
27
|
headers=self._headers,
|
62
28
|
) as resp:
|
63
|
-
|
64
|
-
|
65
|
-
|
29
|
+
data = await resp.json()
|
30
|
+
reader = csv.DictReader(data.get("data", "").split("\n"), delimiter=",")
|
31
|
+
codes = []
|
32
|
+
for row in reader:
|
33
|
+
codes.append(ErrorInfo(**cast(row, dict)))
|
34
|
+
return codes
|
35
|
+
|
36
|
+
async def oauth_check(self) -> None:
|
37
|
+
"""Check if token is valid.
|
38
|
+
|
39
|
+
Returns 401 if token is invalid. We then need to re-authenticate, can try to refresh token first
|
40
|
+
"""
|
41
|
+
async with ClientSession(MAMMOTION_API_DOMAIN) as session:
|
42
|
+
async with session.post("/user-server/v1/user/oauth/check") as resp:
|
43
|
+
data = await resp.json()
|
44
|
+
response = Response.from_dict(data)
|
66
45
|
|
67
46
|
@classmethod
|
68
47
|
async def login(cls, session: ClientSession, username: str, password: str) -> Response[LoginResponseData]:
|
@@ -76,12 +55,11 @@ class MammotionHTTP:
|
|
76
55
|
grant_type="password",
|
77
56
|
),
|
78
57
|
) as resp:
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
return response
|
58
|
+
data = await resp.json()
|
59
|
+
response = Response.from_dict(data)
|
60
|
+
# TODO catch errors from mismatch user / password elsewhere
|
61
|
+
# Assuming the data format matches the expected structure
|
62
|
+
return response
|
85
63
|
|
86
64
|
|
87
65
|
async def connect_http(username: str, password: str) -> MammotionHTTP:
|
@@ -0,0 +1,75 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
from typing import Generic, Literal, Optional, TypeVar
|
3
|
+
|
4
|
+
from mashumaro import DataClassDictMixin
|
5
|
+
from mashumaro.mixins.orjson import DataClassORJSONMixin
|
6
|
+
|
7
|
+
DataT = TypeVar("DataT")
|
8
|
+
|
9
|
+
|
10
|
+
@dataclass
|
11
|
+
class ErrorInfo:
|
12
|
+
code: str
|
13
|
+
platform: str
|
14
|
+
module: str
|
15
|
+
variant: str
|
16
|
+
level: str
|
17
|
+
description: str
|
18
|
+
en_implication: str
|
19
|
+
en_solution: str
|
20
|
+
zh_implication: str
|
21
|
+
zh_solution: str
|
22
|
+
de_implication: str
|
23
|
+
de_solution: str
|
24
|
+
fr_implication: str
|
25
|
+
fr_solution: str
|
26
|
+
it_implication: str
|
27
|
+
it_solution: str
|
28
|
+
es_implication: str
|
29
|
+
es_solution: str
|
30
|
+
cs_implication: str
|
31
|
+
cs_solution: str
|
32
|
+
sk_implication: str
|
33
|
+
sk_solution: str
|
34
|
+
pl_implication: str
|
35
|
+
pl_solution: str
|
36
|
+
nl_implication: str
|
37
|
+
nl_solution: str
|
38
|
+
da_implication: str
|
39
|
+
da_solution: str
|
40
|
+
sv_implication: str
|
41
|
+
sv_solution: str
|
42
|
+
sl_implication: str
|
43
|
+
sl_solution: str
|
44
|
+
pt_implication: str
|
45
|
+
pt_solution: str
|
46
|
+
|
47
|
+
|
48
|
+
@dataclass
|
49
|
+
class Response(DataClassDictMixin, Generic[DataT]):
|
50
|
+
code: int
|
51
|
+
msg: str
|
52
|
+
data: DataT | None = None
|
53
|
+
|
54
|
+
|
55
|
+
@dataclass
|
56
|
+
class LoginResponseUserInformation(DataClassORJSONMixin):
|
57
|
+
areaCode: str
|
58
|
+
domainAbbreviation: str
|
59
|
+
email: Optional[str]
|
60
|
+
userId: str
|
61
|
+
userAccount: str
|
62
|
+
authType: str
|
63
|
+
|
64
|
+
|
65
|
+
@dataclass
|
66
|
+
class LoginResponseData(DataClassORJSONMixin):
|
67
|
+
access_token: str
|
68
|
+
token_type: Literal["bearer"]
|
69
|
+
refresh_token: str
|
70
|
+
expires_in: int
|
71
|
+
scope: Literal["read"]
|
72
|
+
grant_type: Literal["password"]
|
73
|
+
authorization_code: str
|
74
|
+
userInformation: LoginResponseUserInformation
|
75
|
+
jti: str
|
@@ -4,7 +4,8 @@ from abc import ABC
|
|
4
4
|
from logging import getLogger
|
5
5
|
|
6
6
|
from pymammotion.mammotion.commands.abstract_message import AbstractMessage
|
7
|
-
from pymammotion.proto import
|
7
|
+
from pymammotion.proto import mctrl_driver
|
8
|
+
from pymammotion.proto.luba_msg import LubaMsg, MsgAttr, MsgCmdType, MsgDevice
|
8
9
|
|
9
10
|
logger = getLogger(__name__)
|
10
11
|
|
@@ -12,42 +13,38 @@ logger = getLogger(__name__)
|
|
12
13
|
class MessageDriver(AbstractMessage, ABC):
|
13
14
|
@staticmethod
|
14
15
|
def send_order_msg_driver(driver):
|
15
|
-
|
16
|
-
msgtype=
|
17
|
-
sender=
|
18
|
-
rcver=
|
19
|
-
msgattr=
|
16
|
+
return LubaMsg(
|
17
|
+
msgtype=MsgCmdType.MSG_CMD_TYPE_EMBED_DRIVER,
|
18
|
+
sender=MsgDevice.DEV_MOBILEAPP,
|
19
|
+
rcver=MsgDevice.DEV_MAINCTL,
|
20
|
+
msgattr=MsgAttr.MSG_ATTR_REQ,
|
20
21
|
timestamp=round(time.time() * 1000),
|
21
22
|
seqs=1,
|
22
23
|
version=1,
|
23
24
|
subtype=1,
|
24
25
|
driver=driver,
|
25
|
-
)
|
26
|
-
|
27
|
-
return luba_msg.SerializeToString()
|
26
|
+
).SerializeToString()
|
28
27
|
|
29
28
|
def set_blade_height(self, height: int):
|
30
29
|
logger.debug(f"Send knife height height={height}")
|
31
|
-
build =
|
30
|
+
build = mctrl_driver.MctlDriver(todev_knife_height_set=mctrl_driver.DrvKnifeHeight(knifeHeight=height))
|
32
31
|
logger.debug(f"Send command--Knife motor height setting height={height}")
|
33
32
|
return self.send_order_msg_driver(build)
|
34
33
|
|
35
34
|
def set_speed(self, speed: float):
|
36
35
|
logger.debug(f"{self.get_device_name()} set speed, {speed}")
|
37
|
-
build =
|
36
|
+
build = mctrl_driver.MctlDriver(bidire_speed_read_set=mctrl_driver.DrvSrSpeed(speed=speed, rw=1))
|
38
37
|
logger.debug(f"Send command--Speed setting speed={speed}")
|
39
38
|
return self.send_order_msg_driver(build)
|
40
39
|
|
41
40
|
def syn_nav_star_point_data(self, sat_system: int):
|
42
|
-
build =
|
43
|
-
rtk_sys_mask_query=mctrl_driver_pb2.rtk_sys_mask_query_t(sat_system=sat_system)
|
44
|
-
)
|
41
|
+
build = mctrl_driver.MctlDriver(rtk_sys_mask_query=mctrl_driver.RtkSysMaskQueryT(sat_system=sat_system))
|
45
42
|
logger.debug(f"Send command--Navigation satellite frequency point synchronization={sat_system}")
|
46
43
|
return self.send_order_msg_driver(build)
|
47
44
|
|
48
45
|
def set_nav_star_point(self, cmd_req: str):
|
49
|
-
build =
|
50
|
-
rtk_cfg_req=
|
46
|
+
build = mctrl_driver.MctlDriver(
|
47
|
+
rtk_cfg_req=mctrl_driver.RtkCfgReqT(cmd_req=cmd_req, cmd_length=len(cmd_req) - 1)
|
51
48
|
)
|
52
49
|
logger.debug(f"Send command--Navigation satellite frequency point setting={cmd_req}")
|
53
50
|
logger.debug(
|
@@ -56,7 +53,7 @@ class MessageDriver(AbstractMessage, ABC):
|
|
56
53
|
return self.send_order_msg_driver(build)
|
57
54
|
|
58
55
|
def get_speed(self):
|
59
|
-
build =
|
56
|
+
build = mctrl_driver.MctlDriver(bidire_speed_read_set=mctrl_driver.DrvSrSpeed(rw=0))
|
60
57
|
logger.debug("Send command--Get speed value")
|
61
58
|
return self.send_order_msg_driver(build)
|
62
59
|
|
@@ -67,12 +64,12 @@ class MessageDriver(AbstractMessage, ABC):
|
|
67
64
|
cut_knife_height: int,
|
68
65
|
max_run_speed: float,
|
69
66
|
):
|
70
|
-
build =
|
71
|
-
mow_ctrl_by_hand=
|
67
|
+
build = mctrl_driver.MctlDriver(
|
68
|
+
mow_ctrl_by_hand=mctrl_driver.DrvMowCtrlByHand(
|
72
69
|
main_ctrl=main_ctrl,
|
73
70
|
cut_knife_ctrl=cut_knife_ctrl,
|
74
71
|
cut_knife_height=cut_knife_height,
|
75
|
-
|
72
|
+
max_run__speed=max_run_speed,
|
76
73
|
)
|
77
74
|
)
|
78
75
|
logger.debug(
|
@@ -86,9 +83,9 @@ class MessageDriver(AbstractMessage, ABC):
|
|
86
83
|
logger.debug(f"Control command print, linearSpeed={
|
87
84
|
linear_speed} // angularSpeed={angular_speed}")
|
88
85
|
return self.send_order_msg_driver(
|
89
|
-
|
90
|
-
todev_devmotion_ctrl=
|
91
|
-
|
86
|
+
mctrl_driver.MctlDriver(
|
87
|
+
todev_devmotion_ctrl=mctrl_driver.DrvMotionCtrl(
|
88
|
+
set_linear_speed=linear_speed, set_angular_speed=angular_speed
|
92
89
|
)
|
93
90
|
)
|
94
91
|
)
|