pymammotion 0.4.0b8__py3-none-any.whl → 0.4.2__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/bluetooth/ble_message.py +6 -7
- pymammotion/data/model/device.py +2 -7
- pymammotion/data/model/device_limits.py +4 -4
- pymammotion/data/model/hash_list.py +84 -10
- pymammotion/data/model/raw_data.py +1 -8
- pymammotion/data/state_manager.py +30 -10
- pymammotion/mammotion/commands/abstract_message.py +2 -2
- pymammotion/mammotion/commands/messages/driver.py +27 -20
- pymammotion/mammotion/commands/messages/media.py +13 -14
- pymammotion/mammotion/commands/messages/navigation.py +16 -13
- pymammotion/mammotion/commands/messages/network.py +13 -10
- pymammotion/mammotion/commands/messages/ota.py +9 -14
- pymammotion/mammotion/commands/messages/system.py +36 -25
- pymammotion/mammotion/commands/messages/video.py +8 -10
- pymammotion/mammotion/devices/base.py +10 -10
- pymammotion/mammotion/devices/mammotion.py +18 -14
- pymammotion/mammotion/devices/mammotion_bluetooth.py +2 -3
- pymammotion/mammotion/devices/mammotion_cloud.py +1 -2
- pymammotion/mqtt/mammotion_mqtt.py +1 -1
- pymammotion/proto/__init__.py +2174 -1
- pymammotion/proto/luba_mul_pb2.py +8 -8
- pymammotion/proto/luba_mul_pb2.pyi +1 -0
- pymammotion/proto/mctrl_nav.proto +3 -3
- pymammotion/proto/mctrl_nav_pb2.py +69 -67
- pymammotion/proto/mctrl_nav_pb2.pyi +13 -5
- pymammotion/proto/mctrl_sys_pb2.py +41 -37
- pymammotion/proto/mctrl_sys_pb2.pyi +34 -11
- pymammotion/utility/device_config.py +121 -121
- {pymammotion-0.4.0b8.dist-info → pymammotion-0.4.2.dist-info}/METADATA +1 -1
- {pymammotion-0.4.0b8.dist-info → pymammotion-0.4.2.dist-info}/RECORD +32 -42
- pymammotion/proto/basestation.py +0 -59
- pymammotion/proto/common.py +0 -12
- pymammotion/proto/dev_net.py +0 -381
- pymammotion/proto/luba_msg.py +0 -81
- pymammotion/proto/luba_mul.py +0 -77
- pymammotion/proto/mctrl_driver.py +0 -100
- pymammotion/proto/mctrl_nav.py +0 -664
- pymammotion/proto/mctrl_ota.py +0 -48
- pymammotion/proto/mctrl_pept.py +0 -41
- pymammotion/proto/mctrl_sys.py +0 -574
- {pymammotion-0.4.0b8.dist-info → pymammotion-0.4.2.dist-info}/LICENSE +0 -0
- {pymammotion-0.4.0b8.dist-info → pymammotion-0.4.2.dist-info}/WHEEL +0 -0
@@ -16,8 +16,7 @@ from pymammotion.bluetooth.data.framectrldata import FrameCtrlData
|
|
16
16
|
from pymammotion.bluetooth.data.notifydata import BlufiNotifyData
|
17
17
|
from pymammotion.bluetooth.model.atomic_integer import AtomicInteger
|
18
18
|
from pymammotion.data.model.execute_boarder import ExecuteBorder
|
19
|
-
from pymammotion.proto import
|
20
|
-
from pymammotion.proto.luba_msg import LubaMsg, MsgAttr, MsgCmdType, MsgDevice
|
19
|
+
from pymammotion.proto import DevNet, DrvDevInfoReq, LubaMsg, MsgAttr, MsgCmdType, MsgDevice
|
21
20
|
from pymammotion.utility.constant.device_constant import bleOrderCmd
|
22
21
|
|
23
22
|
_LOGGER = logging.getLogger(__name__)
|
@@ -317,7 +316,7 @@ class BleMessage:
|
|
317
316
|
hash_map = {"ctrl": 1}
|
318
317
|
await self.post_custom_data(self.get_json_string(bleOrderCmd.bleAlive, hash_map))
|
319
318
|
|
320
|
-
def get_json_string(self, cmd: int, hash_map: dict[str,
|
319
|
+
def get_json_string(self, cmd: int, hash_map: dict[str, int]) -> str:
|
321
320
|
jSONObject = {}
|
322
321
|
try:
|
323
322
|
jSONObject["cmd"] = cmd
|
@@ -331,7 +330,7 @@ class BleMessage:
|
|
331
330
|
print(e)
|
332
331
|
return ""
|
333
332
|
|
334
|
-
def
|
333
|
+
def clear_notification(self) -> None:
|
335
334
|
self.notification = None
|
336
335
|
self.notification = BlufiNotifyData()
|
337
336
|
|
@@ -341,14 +340,14 @@ class BleMessage:
|
|
341
340
|
async def send_device_info(self) -> None:
|
342
341
|
"""Currently not called"""
|
343
342
|
luba_msg = LubaMsg(
|
344
|
-
msgtype=MsgCmdType.
|
343
|
+
msgtype=MsgCmdType.ESP,
|
345
344
|
sender=MsgDevice.DEV_MOBILEAPP,
|
346
345
|
rcver=MsgDevice.DEV_COMM_ESP,
|
347
|
-
msgattr=MsgAttr.
|
346
|
+
msgattr=MsgAttr.REQ,
|
348
347
|
seqs=1,
|
349
348
|
version=1,
|
350
349
|
subtype=1,
|
351
|
-
net=
|
350
|
+
net=DevNet(todev_ble_sync=1, todev_devinfo_req=DrvDevInfoReq()),
|
352
351
|
)
|
353
352
|
byte_arr = luba_msg.SerializeToString()
|
354
353
|
await self.post_custom_data_bytes(byte_arr)
|
pymammotion/data/model/device.py
CHANGED
@@ -12,13 +12,7 @@ from pymammotion.data.model.report_info import ReportData
|
|
12
12
|
from pymammotion.data.mqtt.properties import ThingPropertiesMessage
|
13
13
|
from pymammotion.data.mqtt.status import ThingStatusMessage
|
14
14
|
from pymammotion.http.model.http import ErrorInfo
|
15
|
-
from pymammotion.proto
|
16
|
-
DeviceFwInfo,
|
17
|
-
MowToAppInfoT,
|
18
|
-
ReportInfoData,
|
19
|
-
SystemRapidStateTunnelMsg,
|
20
|
-
SystemUpdateBufMsg,
|
21
|
-
)
|
15
|
+
from pymammotion.proto import DeviceFwInfo, MowToAppInfoT, ReportInfoData, SystemRapidStateTunnelMsg, SystemUpdateBufMsg
|
22
16
|
from pymammotion.utility.constant import WorkMode
|
23
17
|
from pymammotion.utility.conversions import parse_double
|
24
18
|
from pymammotion.utility.map import CoordinateConverter
|
@@ -28,6 +22,7 @@ from pymammotion.utility.map import CoordinateConverter
|
|
28
22
|
class MowingDevice(DataClassORJSONMixin):
|
29
23
|
"""Wraps the betterproto dataclasses, so we can bypass the groups for keeping all data."""
|
30
24
|
|
25
|
+
name: str = ""
|
31
26
|
online: bool = True
|
32
27
|
mower_state: MowerInfo = field(default_factory=MowerInfo)
|
33
28
|
mqtt_properties: ThingPropertiesMessage | None = None
|
@@ -9,7 +9,7 @@ class RangeLimit:
|
|
9
9
|
|
10
10
|
@dataclass
|
11
11
|
class DeviceLimits:
|
12
|
-
|
12
|
+
blade_height: RangeLimit = field(default_factory=RangeLimit)
|
13
13
|
working_speed: RangeLimit = field(default_factory=RangeLimit)
|
14
14
|
working_path: RangeLimit = field(default_factory=RangeLimit)
|
15
15
|
work_area_num_max: int = 60
|
@@ -18,7 +18,7 @@ class DeviceLimits:
|
|
18
18
|
def to_dict(self) -> dict:
|
19
19
|
"""Convert the device limits to a dictionary format."""
|
20
20
|
return {
|
21
|
-
"
|
21
|
+
"blade_height": {"min": self.blade_height.min, "max": self.blade_height.max},
|
22
22
|
"working_speed": {"min": self.working_speed.min, "max": self.working_speed.max},
|
23
23
|
"working_path": {"min": self.working_path.min, "max": self.working_path.max},
|
24
24
|
"work_area_num_max": self.work_area_num_max,
|
@@ -29,7 +29,7 @@ class DeviceLimits:
|
|
29
29
|
def from_dict(cls, data: dict) -> "DeviceLimits":
|
30
30
|
"""Create a DeviceLimits instance from a dictionary."""
|
31
31
|
return cls(
|
32
|
-
|
32
|
+
blade_height=RangeLimit(min=data["blade_height"]["min"], max=data["blade_height"]["max"]),
|
33
33
|
working_speed=RangeLimit(min=data["working_speed"]["min"], max=data["working_speed"]["max"]),
|
34
34
|
working_path=RangeLimit(min=data["working_path"]["min"], max=data["working_path"]["max"]),
|
35
35
|
work_area_num_max=data["work_area_num_max"],
|
@@ -40,7 +40,7 @@ class DeviceLimits:
|
|
40
40
|
"""Validate that all ranges are logical (min <= max)."""
|
41
41
|
return all(
|
42
42
|
[
|
43
|
-
self.
|
43
|
+
self.blade_height.min <= self.blade_height.max,
|
44
44
|
self.working_speed.min <= self.working_speed.max,
|
45
45
|
self.working_path.min <= self.working_path.max,
|
46
46
|
self.work_area_num_max > 0,
|
@@ -3,7 +3,7 @@ from enum import IntEnum
|
|
3
3
|
|
4
4
|
from mashumaro.mixins.orjson import DataClassORJSONMixin
|
5
5
|
|
6
|
-
from pymammotion.proto
|
6
|
+
from pymammotion.proto import NavGetCommDataAck, SvgMessageAckT
|
7
7
|
|
8
8
|
|
9
9
|
class PathType(IntEnum):
|
@@ -16,21 +16,91 @@ class PathType(IntEnum):
|
|
16
16
|
SVG = 13
|
17
17
|
|
18
18
|
|
19
|
+
@dataclass
|
20
|
+
class CommDataCouple:
|
21
|
+
x: float = 0.0
|
22
|
+
y: float = 0.0
|
23
|
+
|
24
|
+
|
25
|
+
@dataclass
|
26
|
+
class AreaLabelName(DataClassORJSONMixin):
|
27
|
+
label: str = ""
|
28
|
+
|
29
|
+
|
30
|
+
@dataclass
|
31
|
+
class NavGetCommData(DataClassORJSONMixin):
|
32
|
+
pver: int = 0
|
33
|
+
sub_cmd: int = 0
|
34
|
+
result: int = 0
|
35
|
+
action: int = 0
|
36
|
+
type: int = 0
|
37
|
+
hash: int = 0
|
38
|
+
paternal_hash_a: int = 0
|
39
|
+
paternal_hash_b: int = 0
|
40
|
+
total_frame: int = 0
|
41
|
+
current_frame: int = 0
|
42
|
+
data_hash: int = 0
|
43
|
+
data_len: int = 0
|
44
|
+
data_couple: list["CommDataCouple"] = field(default_factory=list)
|
45
|
+
reserved: str = ""
|
46
|
+
area_label: "AreaLabelName" = field(default_factory=AreaLabelName)
|
47
|
+
|
48
|
+
|
49
|
+
@dataclass
|
50
|
+
class SvgMessageData(DataClassORJSONMixin):
|
51
|
+
x_move: float = 0.0
|
52
|
+
y_move: float = 0.0
|
53
|
+
scale: float = 0.0
|
54
|
+
rotate: float = 0.0
|
55
|
+
base_width_m: float = 0.0
|
56
|
+
base_width_pix: int = 0
|
57
|
+
base_height_m: float = 0.0
|
58
|
+
base_height_pix: int = 0
|
59
|
+
data_count: int = 0
|
60
|
+
hide_svg: bool = False
|
61
|
+
name_count: int = 0
|
62
|
+
svg_file_name: str = ""
|
63
|
+
svg_file_data: str = ""
|
64
|
+
|
65
|
+
|
66
|
+
@dataclass
|
67
|
+
class SvgMessage(DataClassORJSONMixin):
|
68
|
+
pver: int = 0
|
69
|
+
sub_cmd: int = 0
|
70
|
+
total_frame: int = 0
|
71
|
+
current_frame: int = 0
|
72
|
+
data_hash: int = 0
|
73
|
+
paternal_hash_a: int = 0
|
74
|
+
type: int = 0
|
75
|
+
result: int = 0
|
76
|
+
svg_message: "SvgMessageData" = field(default_factory=SvgMessageData)
|
77
|
+
|
78
|
+
|
19
79
|
@dataclass
|
20
80
|
class FrameList(DataClassORJSONMixin):
|
21
81
|
total_frame: int
|
22
|
-
data: list[
|
82
|
+
data: list[NavGetCommData | SvgMessage]
|
23
83
|
|
24
84
|
|
25
|
-
@dataclass
|
26
|
-
class NavGetHashListData(DataClassORJSONMixin
|
85
|
+
@dataclass(eq=False, repr=False)
|
86
|
+
class NavGetHashListData(DataClassORJSONMixin):
|
27
87
|
"""Dataclass for NavGetHashListData."""
|
28
88
|
|
89
|
+
pver: int = 0
|
90
|
+
sub_cmd: int = 0
|
91
|
+
total_frame: int = 0
|
92
|
+
current_frame: int = 0
|
93
|
+
data_hash: int = 0
|
94
|
+
hash_len: int = 0
|
95
|
+
reserved: str = ""
|
96
|
+
result: int = 0
|
97
|
+
data_couple: list[int] = field(default_factory=list)
|
98
|
+
|
29
99
|
|
30
100
|
@dataclass
|
31
101
|
class RootHashList(DataClassORJSONMixin):
|
32
102
|
total_frame: int = 0
|
33
|
-
data: list[
|
103
|
+
data: list[NavGetHashListData] = field(default_factory=list)
|
34
104
|
|
35
105
|
|
36
106
|
@dataclass
|
@@ -81,7 +151,7 @@ class HashList(DataClassORJSONMixin):
|
|
81
151
|
)
|
82
152
|
]
|
83
153
|
|
84
|
-
def update_root_hash_list(self, hash_list:
|
154
|
+
def update_root_hash_list(self, hash_list: NavGetHashListData) -> None:
|
85
155
|
self.root_hash_list.total_frame = hash_list.total_frame
|
86
156
|
|
87
157
|
for index, obj in enumerate(self.root_hash_list.data):
|
@@ -93,7 +163,7 @@ class HashList(DataClassORJSONMixin):
|
|
93
163
|
# If no match was found, append the new item
|
94
164
|
self.root_hash_list.data.append(hash_list)
|
95
165
|
|
96
|
-
def missing_hash_frame(self):
|
166
|
+
def missing_hash_frame(self) -> list[int]:
|
97
167
|
return self._find_missing_frames(self.root_hash_list)
|
98
168
|
|
99
169
|
def missing_frame(self, hash_data: NavGetCommDataAck | SvgMessageAckT) -> list[int]:
|
@@ -112,7 +182,9 @@ class HashList(DataClassORJSONMixin):
|
|
112
182
|
if hash_data.type == PathType.SVG:
|
113
183
|
return self._find_missing_frames(self.svg.get(hash_data.data_hash))
|
114
184
|
|
115
|
-
|
185
|
+
return []
|
186
|
+
|
187
|
+
def update(self, hash_data: NavGetCommData | SvgMessage) -> bool:
|
116
188
|
"""Update the map data."""
|
117
189
|
if hash_data.type == PathType.AREA:
|
118
190
|
existing_name = next((area for area in self.area_name if area.hash == hash_data.hash), None)
|
@@ -133,6 +205,8 @@ class HashList(DataClassORJSONMixin):
|
|
133
205
|
if hash_data.type == PathType.SVG:
|
134
206
|
return self._add_hash_data(self.svg, hash_data)
|
135
207
|
|
208
|
+
return False
|
209
|
+
|
136
210
|
@staticmethod
|
137
211
|
def _find_missing_frames(frame_list: FrameList | RootHashList) -> list[int]:
|
138
212
|
if frame_list.total_frame == len(frame_list.data):
|
@@ -144,8 +218,8 @@ class HashList(DataClassORJSONMixin):
|
|
144
218
|
return missing_numbers
|
145
219
|
|
146
220
|
@staticmethod
|
147
|
-
def _add_hash_data(hash_dict: dict, hash_data:
|
148
|
-
if isinstance(hash_data,
|
221
|
+
def _add_hash_data(hash_dict: dict, hash_data: NavGetCommData | SvgMessage) -> bool:
|
222
|
+
if isinstance(hash_data, SvgMessage):
|
149
223
|
if hash_dict.get(hash_data.data_hash) is None:
|
150
224
|
hash_dict[hash_data.data_hash] = FrameList(total_frame=hash_data.total_frame, data=[hash_data])
|
151
225
|
return True
|
@@ -2,14 +2,7 @@ from dataclasses import dataclass, field
|
|
2
2
|
|
3
3
|
from mashumaro.mixins.orjson import DataClassORJSONMixin
|
4
4
|
|
5
|
-
from pymammotion.proto
|
6
|
-
from pymammotion.proto.luba_msg import LubaMsg
|
7
|
-
from pymammotion.proto.luba_mul import SocMul
|
8
|
-
from pymammotion.proto.mctrl_driver import MctlDriver
|
9
|
-
from pymammotion.proto.mctrl_nav import MctlNav
|
10
|
-
from pymammotion.proto.mctrl_ota import MctlOta
|
11
|
-
from pymammotion.proto.mctrl_pept import MctlPept
|
12
|
-
from pymammotion.proto.mctrl_sys import MctlSys
|
5
|
+
from pymammotion.proto import DevNet, LubaMsg, MctlDriver, MctlNav, MctlOta, MctlPept, MctlSys, SocMul
|
13
6
|
|
14
7
|
|
15
8
|
@dataclass
|
@@ -9,13 +9,22 @@ 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
|
12
|
+
from pymammotion.data.model.hash_list import AreaHashNameList, NavGetCommData, NavGetHashListData, SvgMessage
|
13
13
|
from pymammotion.data.mqtt.properties import ThingPropertiesMessage
|
14
14
|
from pymammotion.data.mqtt.status import ThingStatusMessage
|
15
|
-
from pymammotion.proto
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
from pymammotion.proto import (
|
16
|
+
AppGetAllAreaHashName,
|
17
|
+
DeviceFwInfo,
|
18
|
+
DeviceProductTypeInfoT,
|
19
|
+
DrvDevInfoResp,
|
20
|
+
DrvDevInfoResult,
|
21
|
+
LubaMsg,
|
22
|
+
NavGetCommDataAck,
|
23
|
+
NavGetHashListAck,
|
24
|
+
SvgMessageAckT,
|
25
|
+
TimeCtrlLight,
|
26
|
+
WifiIotStatusReport,
|
27
|
+
)
|
19
28
|
|
20
29
|
logger = logging.getLogger(__name__)
|
21
30
|
|
@@ -59,6 +68,8 @@ class StateManager:
|
|
59
68
|
if not self._device.online:
|
60
69
|
self._device.online = True
|
61
70
|
self._device.status_properties = thing_status
|
71
|
+
if self._device.mower_state.product_key == "":
|
72
|
+
self._device.mower_state.product_key = thing_status.params.productKey
|
62
73
|
|
63
74
|
@property
|
64
75
|
def online(self) -> bool:
|
@@ -90,6 +101,9 @@ class StateManager:
|
|
90
101
|
"""Handle protobuf notifications."""
|
91
102
|
res = betterproto.which_one_of(message, "LubaSubMsg")
|
92
103
|
self.last_updated_at = datetime.now()
|
104
|
+
# additional catch all if we don't get a status update
|
105
|
+
if not self._device.online:
|
106
|
+
self._device.online = True
|
93
107
|
|
94
108
|
match res[0]:
|
95
109
|
case "nav":
|
@@ -113,18 +127,24 @@ class StateManager:
|
|
113
127
|
match nav_msg[0]:
|
114
128
|
case "toapp_gethash_ack":
|
115
129
|
hashlist_ack: NavGetHashListAck = nav_msg[1]
|
116
|
-
self._device.map.update_root_hash_list(
|
130
|
+
self._device.map.update_root_hash_list(
|
131
|
+
NavGetHashListData.from_dict(hashlist_ack.to_dict(casing=betterproto.Casing.SNAKE))
|
132
|
+
)
|
117
133
|
await self.gethash_ack_callback(nav_msg[1])
|
118
134
|
case "toapp_get_commondata_ack":
|
119
135
|
common_data: NavGetCommDataAck = nav_msg[1]
|
120
|
-
updated = self._device.map.update(
|
136
|
+
updated = self._device.map.update(
|
137
|
+
NavGetCommData.from_dict(common_data.to_dict(casing=betterproto.Casing.SNAKE))
|
138
|
+
)
|
121
139
|
if updated:
|
122
140
|
await self.get_commondata_ack_callback(common_data)
|
123
141
|
case "toapp_svg_msg":
|
124
|
-
|
125
|
-
updated = self._device.map.update(
|
142
|
+
common_svg_data: SvgMessageAckT = nav_msg[1]
|
143
|
+
updated = self._device.map.update(
|
144
|
+
SvgMessage.from_dict(common_svg_data.to_dict(casing=betterproto.Casing.SNAKE))
|
145
|
+
)
|
126
146
|
if updated:
|
127
|
-
await self.get_commondata_ack_callback(
|
147
|
+
await self.get_commondata_ack_callback(common_svg_data)
|
128
148
|
|
129
149
|
case "toapp_all_hash_name":
|
130
150
|
hash_names: AppGetAllAreaHashName = nav_msg[1]
|
@@ -1,6 +1,6 @@
|
|
1
1
|
from abc import abstractmethod
|
2
2
|
|
3
|
-
from pymammotion.proto
|
3
|
+
from pymammotion.proto import MsgCmdType, MsgDevice
|
4
4
|
from pymammotion.utility.device_type import DeviceType
|
5
5
|
|
6
6
|
|
@@ -16,7 +16,7 @@ class AbstractMessage:
|
|
16
16
|
"""Changes the rcver name if it's not a luba1."""
|
17
17
|
if (
|
18
18
|
not DeviceType.is_luba1(self.get_device_name(), self.get_device_product_key())
|
19
|
-
and msg_type == MsgCmdType.
|
19
|
+
and msg_type == MsgCmdType.NAV
|
20
20
|
):
|
21
21
|
return MsgDevice.DEV_NAVIGATION
|
22
22
|
return msg_device
|
@@ -4,8 +4,19 @@ from logging import getLogger
|
|
4
4
|
import time
|
5
5
|
|
6
6
|
from pymammotion.mammotion.commands.abstract_message import AbstractMessage
|
7
|
-
from pymammotion.proto import
|
8
|
-
|
7
|
+
from pymammotion.proto import (
|
8
|
+
DrvKnifeHeight,
|
9
|
+
DrvMotionCtrl,
|
10
|
+
DrvMowCtrlByHand,
|
11
|
+
DrvSrSpeed,
|
12
|
+
LubaMsg,
|
13
|
+
MctlDriver,
|
14
|
+
MsgAttr,
|
15
|
+
MsgCmdType,
|
16
|
+
MsgDevice,
|
17
|
+
RtkCfgReqT,
|
18
|
+
RtkSysMaskQueryT,
|
19
|
+
)
|
9
20
|
|
10
21
|
logger = getLogger(__name__)
|
11
22
|
|
@@ -13,10 +24,10 @@ logger = getLogger(__name__)
|
|
13
24
|
class MessageDriver(AbstractMessage, ABC):
|
14
25
|
def send_order_msg_driver(self, driver) -> bytes:
|
15
26
|
return LubaMsg(
|
16
|
-
msgtype=MsgCmdType.
|
27
|
+
msgtype=MsgCmdType.EMBED_DRIVER,
|
17
28
|
sender=MsgDevice.DEV_MOBILEAPP,
|
18
|
-
rcver=self.get_msg_device(MsgCmdType.
|
19
|
-
msgattr=MsgAttr.
|
29
|
+
rcver=self.get_msg_device(MsgCmdType.EMBED_DRIVER, MsgDevice.DEV_MAINCTL),
|
30
|
+
msgattr=MsgAttr.REQ,
|
20
31
|
timestamp=round(time.time() * 1000),
|
21
32
|
seqs=1,
|
22
33
|
version=1,
|
@@ -26,25 +37,23 @@ class MessageDriver(AbstractMessage, ABC):
|
|
26
37
|
|
27
38
|
def set_blade_height(self, height: int):
|
28
39
|
logger.debug(f"Send knife height height={height}")
|
29
|
-
build =
|
40
|
+
build = MctlDriver(todev_knife_height_set=DrvKnifeHeight(knife_height=height))
|
30
41
|
logger.debug(f"Send command--Knife motor height setting height={height}")
|
31
42
|
return self.send_order_msg_driver(build)
|
32
43
|
|
33
44
|
def set_speed(self, speed: float):
|
34
45
|
logger.debug(f"{self.get_device_name()} set speed, {speed}")
|
35
|
-
build =
|
46
|
+
build = MctlDriver(bidire_speed_read_set=DrvSrSpeed(speed=speed, rw=1))
|
36
47
|
logger.debug(f"Send command--Speed setting speed={speed}")
|
37
48
|
return self.send_order_msg_driver(build)
|
38
49
|
|
39
50
|
def syn_nav_star_point_data(self, sat_system: int):
|
40
|
-
build =
|
51
|
+
build = MctlDriver(rtk_sys_mask_query=RtkSysMaskQueryT(sat_system=sat_system))
|
41
52
|
logger.debug(f"Send command--Navigation satellite frequency point synchronization={sat_system}")
|
42
53
|
return self.send_order_msg_driver(build)
|
43
54
|
|
44
55
|
def set_nav_star_point(self, cmd_req: str):
|
45
|
-
build =
|
46
|
-
rtk_cfg_req=mctrl_driver.RtkCfgReqT(cmd_req=cmd_req, cmd_length=len(cmd_req) - 1)
|
47
|
-
)
|
56
|
+
build = MctlDriver(rtk_cfg_req=RtkCfgReqT(cmd_req=cmd_req, cmd_length=len(cmd_req) - 1))
|
48
57
|
logger.debug(f"Send command--Navigation satellite frequency point setting={cmd_req}")
|
49
58
|
logger.debug(
|
50
59
|
f"Navigation satellite setting, Send command--Navigation satellite frequency point setting={cmd_req}"
|
@@ -52,7 +61,7 @@ class MessageDriver(AbstractMessage, ABC):
|
|
52
61
|
return self.send_order_msg_driver(build)
|
53
62
|
|
54
63
|
def get_speed(self):
|
55
|
-
build =
|
64
|
+
build = MctlDriver(bidire_speed_read_set=DrvSrSpeed(rw=0))
|
56
65
|
logger.debug("Send command--Get speed value")
|
57
66
|
return self.send_order_msg_driver(build)
|
58
67
|
|
@@ -63,12 +72,12 @@ class MessageDriver(AbstractMessage, ABC):
|
|
63
72
|
cut_knife_height: int,
|
64
73
|
max_run_speed: float,
|
65
74
|
):
|
66
|
-
build =
|
67
|
-
mow_ctrl_by_hand=
|
75
|
+
build = MctlDriver(
|
76
|
+
mow_ctrl_by_hand=DrvMowCtrlByHand(
|
68
77
|
main_ctrl=main_ctrl,
|
69
78
|
cut_knife_ctrl=cut_knife_ctrl,
|
70
79
|
cut_knife_height=cut_knife_height,
|
71
|
-
|
80
|
+
max_run_speed=max_run_speed,
|
72
81
|
)
|
73
82
|
)
|
74
83
|
logger.debug(
|
@@ -78,13 +87,11 @@ class MessageDriver(AbstractMessage, ABC):
|
|
78
87
|
|
79
88
|
return self.send_order_msg_driver(build)
|
80
89
|
|
81
|
-
def send_movement(self, linear_speed: int, angular_speed: int):
|
90
|
+
def send_movement(self, linear_speed: int, angular_speed: int) -> bytes:
|
82
91
|
logger.debug(f"Control command print, linearSpeed={
|
83
92
|
linear_speed} // angularSpeed={angular_speed}")
|
84
93
|
return self.send_order_msg_driver(
|
85
|
-
|
86
|
-
todev_devmotion_ctrl=
|
87
|
-
set_linear_speed=linear_speed, set_angular_speed=angular_speed
|
88
|
-
)
|
94
|
+
MctlDriver(
|
95
|
+
todev_devmotion_ctrl=DrvMotionCtrl(set_linear_speed=linear_speed, set_angular_speed=angular_speed)
|
89
96
|
)
|
90
97
|
)
|
@@ -2,18 +2,16 @@
|
|
2
2
|
from abc import ABC
|
3
3
|
|
4
4
|
from pymammotion.mammotion.commands.abstract_message import AbstractMessage
|
5
|
-
from pymammotion.proto import
|
6
|
-
from pymammotion.proto.luba_msg import MsgCmdType, MsgDevice
|
7
|
-
from pymammotion.proto.luba_mul import MUL_LANGUAGE
|
5
|
+
from pymammotion.proto import LubaMsg, MsgAttr, MsgCmdType, MsgDevice, MulLanguage, MulSetAudio, MulSetWiper, SocMul
|
8
6
|
|
9
7
|
|
10
8
|
class MessageMedia(AbstractMessage, ABC):
|
11
9
|
def send_order_msg_media(self, mul):
|
12
|
-
luba_msg =
|
13
|
-
msgtype=
|
14
|
-
sender=
|
15
|
-
rcver=self.get_msg_device(MsgCmdType.
|
16
|
-
msgattr=
|
10
|
+
luba_msg = LubaMsg(
|
11
|
+
msgtype=MsgCmdType.MUL,
|
12
|
+
sender=MsgDevice.DEV_MOBILEAPP,
|
13
|
+
rcver=self.get_msg_device(MsgCmdType.MUL, MsgDevice.SOC_MODULE_MULTIMEDIA),
|
14
|
+
msgattr=MsgAttr.REQ,
|
17
15
|
seqs=1,
|
18
16
|
version=1,
|
19
17
|
subtype=1,
|
@@ -23,12 +21,13 @@ class MessageMedia(AbstractMessage, ABC):
|
|
23
21
|
return luba_msg.SerializeToString()
|
24
22
|
|
25
23
|
def set_car_volume(self, volume: int):
|
26
|
-
|
24
|
+
"""Set the car volume. 0 - 100"""
|
25
|
+
return self.send_order_msg_media(SocMul(set_audio=MulSetAudio(at_switch=volume)))
|
27
26
|
|
28
|
-
def set_car_voice_language(self, language_type:
|
29
|
-
return self.send_order_msg_media(
|
30
|
-
luba_mul_pb2.SocMul(set_audio=luba_mul_pb2.MulSetAudio(au_language=language_type))
|
31
|
-
)
|
27
|
+
def set_car_voice_language(self, language_type: MulLanguage | str | None):
|
28
|
+
return self.send_order_msg_media(SocMul(set_audio=MulSetAudio(au_language=language_type)))
|
32
29
|
|
33
30
|
def set_car_wiper(self, round_num: int):
|
34
|
-
|
31
|
+
"""Set mower wiper."""
|
32
|
+
# 2
|
33
|
+
return self.send_order_msg_media(SocMul(set_wiper=MulSetWiper(round=round_num)))
|
@@ -7,10 +7,13 @@ from pymammotion.data.model import GenerateRouteInformation
|
|
7
7
|
from pymammotion.data.model.plan import Plan
|
8
8
|
from pymammotion.data.model.region_data import RegionData
|
9
9
|
from pymammotion.mammotion.commands.abstract_message import AbstractMessage
|
10
|
-
from pymammotion.proto
|
11
|
-
from pymammotion.proto.mctrl_nav import (
|
10
|
+
from pymammotion.proto import (
|
12
11
|
AppRequestCoverPathsT,
|
12
|
+
LubaMsg,
|
13
13
|
MctlNav,
|
14
|
+
MsgAttr,
|
15
|
+
MsgCmdType,
|
16
|
+
MsgDevice,
|
14
17
|
NavGetCommData,
|
15
18
|
NavGetHashList,
|
16
19
|
NavMapNameMsg,
|
@@ -32,10 +35,10 @@ logger = logging.getLogger(__name__)
|
|
32
35
|
class MessageNavigation(AbstractMessage, ABC):
|
33
36
|
def send_order_msg_nav(self, build) -> bytes:
|
34
37
|
luba_msg = LubaMsg(
|
35
|
-
msgtype=MsgCmdType.
|
38
|
+
msgtype=MsgCmdType.NAV,
|
36
39
|
sender=MsgDevice.DEV_MOBILEAPP,
|
37
|
-
rcver=self.get_msg_device(MsgCmdType.
|
38
|
-
msgattr=MsgAttr.
|
40
|
+
rcver=self.get_msg_device(MsgCmdType.NAV, MsgDevice.DEV_MAINCTL),
|
41
|
+
msgattr=MsgAttr.REQ,
|
39
42
|
seqs=1,
|
40
43
|
version=1,
|
41
44
|
subtype=1,
|
@@ -45,8 +48,8 @@ class MessageNavigation(AbstractMessage, ABC):
|
|
45
48
|
|
46
49
|
return luba_msg.SerializeToString()
|
47
50
|
|
48
|
-
def allpowerfull_rw_adapter_x3(self,
|
49
|
-
build = MctlNav(nav_sys_param_cmd=NavSysParamMsg(id=
|
51
|
+
def allpowerfull_rw_adapter_x3(self, rw_id: int, context: int, rw: int) -> bytes:
|
52
|
+
build = MctlNav(nav_sys_param_cmd=NavSysParamMsg(id=rw_id, context=context, rw=rw))
|
50
53
|
logger.debug(f"Send command--9 general read and write command id={id}, context={context}, rw={rw}")
|
51
54
|
return self.send_order_msg_nav(build)
|
52
55
|
|
@@ -268,7 +271,7 @@ class MessageNavigation(AbstractMessage, ABC):
|
|
268
271
|
logger.debug("Send command--Get area name list")
|
269
272
|
return self.send_order_msg_nav(mctl_nav)
|
270
273
|
|
271
|
-
def set_area_name(self, device_id, hash_id: int, name: str) -> bytes:
|
274
|
+
def set_area_name(self, device_id: str, hash_id: int, name: str) -> bytes:
|
272
275
|
# Build the NavMapNameMsg with the specified parameters
|
273
276
|
mctl_nav = MctlNav(
|
274
277
|
toapp_map_name_msg=NavMapNameMsg(hash=hash_id, name=name, result=0, device_id=device_id, rw=1)
|
@@ -280,7 +283,7 @@ class MessageNavigation(AbstractMessage, ABC):
|
|
280
283
|
|
281
284
|
def get_all_boundary_hash_list(self, sub_cmd: int) -> bytes:
|
282
285
|
build = MctlNav(todev_gethash=NavGetHashList(pver=1, sub_cmd=sub_cmd))
|
283
|
-
logger.debug(f"Area loading=====================:Get area hash list
|
286
|
+
logger.debug(f"Area loading=====================:Get area hash list:{sub_cmd}")
|
284
287
|
return self.send_order_msg_nav(build)
|
285
288
|
|
286
289
|
def get_hash_response(self, total_frame: int, current_frame: int) -> bytes:
|
@@ -327,9 +330,9 @@ class MessageNavigation(AbstractMessage, ABC):
|
|
327
330
|
logger.debug(f"Send command--Send tool command id={param_id},values={values}")
|
328
331
|
return self.send_order_msg_nav(build)
|
329
332
|
|
330
|
-
def end_draw_border(self, type: int) -> bytes:
|
333
|
+
def end_draw_border(self, type: int) -> bytes | None:
|
331
334
|
if type == -1:
|
332
|
-
return
|
335
|
+
return None
|
333
336
|
build = MctlNav(todev_get_commondata=NavGetCommData(pver=1, action=1, type=type))
|
334
337
|
logger.debug(f"Send command--End drawing boundary, obstacle, channel command type={type}")
|
335
338
|
return self.send_order_msg_nav(build)
|
@@ -339,9 +342,9 @@ class MessageNavigation(AbstractMessage, ABC):
|
|
339
342
|
logger.debug("Send command--Cancel current recording (boundary, obstacle)")
|
340
343
|
return self.send_order_msg_nav(build)
|
341
344
|
|
342
|
-
def delete_map_elements(self, type: int, hash_num: int) -> bytes:
|
345
|
+
def delete_map_elements(self, type: int, hash_num: int) -> bytes | None:
|
343
346
|
if type == -1:
|
344
|
-
return
|
347
|
+
return None
|
345
348
|
build = MctlNav(todev_get_commondata=NavGetCommData(pver=1, action=6, type=type, hash=hash_num))
|
346
349
|
logger.debug(f"Send command--Delete boundary or obstacle or channel command type={type},hash={hash}")
|
347
350
|
return self.send_order_msg_nav(build)
|