pymammotion 0.2.28__py3-none-any.whl → 0.2.30__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.
Files changed (55) hide show
  1. pymammotion/__init__.py +12 -9
  2. pymammotion/aliyun/cloud_gateway.py +57 -39
  3. pymammotion/aliyun/cloud_service.py +3 -3
  4. pymammotion/aliyun/dataclass/dev_by_account_response.py +1 -2
  5. pymammotion/aliyun/dataclass/session_by_authcode_response.py +1 -0
  6. pymammotion/bluetooth/ble.py +6 -6
  7. pymammotion/bluetooth/ble_message.py +30 -16
  8. pymammotion/bluetooth/data/convert.py +1 -1
  9. pymammotion/bluetooth/data/framectrldata.py +1 -1
  10. pymammotion/bluetooth/data/notifydata.py +6 -6
  11. pymammotion/const.py +1 -0
  12. pymammotion/data/model/__init__.py +2 -0
  13. pymammotion/data/model/account.py +1 -1
  14. pymammotion/data/model/device.py +31 -24
  15. pymammotion/data/model/device_config.py +71 -0
  16. pymammotion/data/model/enums.py +4 -4
  17. pymammotion/data/model/excute_boarder_params.py +5 -5
  18. pymammotion/data/model/execute_boarder.py +4 -4
  19. pymammotion/data/model/generate_route_information.py +18 -124
  20. pymammotion/data/model/hash_list.py +4 -7
  21. pymammotion/data/model/location.py +3 -3
  22. pymammotion/data/model/mowing_modes.py +1 -1
  23. pymammotion/data/model/plan.py +4 -4
  24. pymammotion/data/model/region_data.py +4 -4
  25. pymammotion/data/model/report_info.py +1 -1
  26. pymammotion/data/mqtt/event.py +8 -3
  27. pymammotion/data/state_manager.py +13 -12
  28. pymammotion/event/event.py +14 -14
  29. pymammotion/http/http.py +33 -45
  30. pymammotion/http/model/http.py +75 -0
  31. pymammotion/mammotion/commands/messages/driver.py +20 -23
  32. pymammotion/mammotion/commands/messages/navigation.py +47 -48
  33. pymammotion/mammotion/commands/messages/network.py +17 -35
  34. pymammotion/mammotion/commands/messages/system.py +6 -7
  35. pymammotion/mammotion/control/joystick.py +11 -10
  36. pymammotion/mammotion/devices/__init__.py +2 -2
  37. pymammotion/mammotion/devices/base.py +248 -0
  38. pymammotion/mammotion/devices/mammotion.py +52 -1042
  39. pymammotion/mammotion/devices/mammotion_bluetooth.py +447 -0
  40. pymammotion/mammotion/devices/mammotion_cloud.py +244 -0
  41. pymammotion/mqtt/mammotion_future.py +3 -2
  42. pymammotion/mqtt/mammotion_mqtt.py +23 -23
  43. pymammotion/proto/__init__.py +6 -0
  44. pymammotion/utility/constant/__init__.py +3 -1
  45. pymammotion/utility/conversions.py +1 -1
  46. pymammotion/utility/datatype_converter.py +9 -9
  47. pymammotion/utility/device_type.py +47 -18
  48. pymammotion/utility/map.py +2 -2
  49. pymammotion/utility/movement.py +2 -1
  50. pymammotion/utility/periodic.py +5 -5
  51. pymammotion/utility/rocker_util.py +1 -1
  52. {pymammotion-0.2.28.dist-info → pymammotion-0.2.30.dist-info}/METADATA +3 -1
  53. {pymammotion-0.2.28.dist-info → pymammotion-0.2.30.dist-info}/RECORD +55 -51
  54. {pymammotion-0.2.28.dist-info → pymammotion-0.2.30.dist-info}/LICENSE +0 -0
  55. {pymammotion-0.2.28.dist-info → pymammotion-0.2.30.dist-info}/WHEEL +0 -0
@@ -10,7 +10,7 @@ from pymammotion.proto import luba_msg_pb2
10
10
 
11
11
 
12
12
  class Base64EncodedProtobuf(SerializableType):
13
- def __init__(self, proto: str):
13
+ def __init__(self, proto: str) -> None:
14
14
  self.proto = proto
15
15
 
16
16
  def _serialize(self):
@@ -45,23 +45,25 @@ class DeviceWarningEventValue(DataClassORJSONMixin):
45
45
  # (see resources/res/values-en-rUS/strings.xml in APK)
46
46
  code: int
47
47
 
48
+
48
49
  @dataclass
49
50
  class DeviceConfigurationRequestValue(DataClassORJSONMixin):
50
51
  code: int
51
52
  bizId: str
52
53
  params: str
53
54
 
55
+
54
56
  @dataclass
55
57
  class DeviceNotificationEventCode(DataClassORJSONMixin):
56
58
  localTime: int
57
59
  code: str
58
60
 
61
+
59
62
  @dataclass
60
63
  class DeviceNotificationEventValue(DataClassORJSONMixin):
61
64
  data: DeviceNotificationEventCode
62
65
 
63
66
 
64
-
65
67
  @dataclass
66
68
  class GeneralParams(DataClassORJSONMixin):
67
69
  groupIdList: list[str]
@@ -100,6 +102,7 @@ class DeviceProtobufMsgEventParams(GeneralParams):
100
102
  type: Literal["info"]
101
103
  value: DeviceProtobufMsgEventValue
102
104
 
105
+
103
106
  @dataclass
104
107
  class DeviceNotificationEventParams(GeneralParams):
105
108
  """Device notification event.
@@ -111,12 +114,14 @@ class DeviceNotificationEventParams(GeneralParams):
111
114
  type: Literal["info"]
112
115
  value: DeviceNotificationEventValue
113
116
 
117
+
114
118
  @dataclass
115
119
  class DeviceWarningEventParams(GeneralParams):
116
120
  identifier: Literal["device_warning_event"]
117
121
  type: Literal["alert"]
118
122
  value: DeviceWarningEventValue
119
123
 
124
+
120
125
  @dataclass
121
126
  class DeviceConfigurationRequestEvent(GeneralParams):
122
127
  type: Literal["info"]
@@ -127,7 +132,7 @@ class DeviceConfigurationRequestEvent(GeneralParams):
127
132
  class ThingEventMessage(DataClassORJSONMixin):
128
133
  method: Literal["thing.events", "thing.properties"]
129
134
  id: str
130
- params: Union[DeviceProtobufMsgEventParams, DeviceWarningEventParams, str]
135
+ params: Union[DeviceProtobufMsgEventParams, DeviceWarningEventParams, dict]
131
136
  version: Literal["1.0"]
132
137
 
133
138
  @classmethod
@@ -1,4 +1,5 @@
1
1
  """Manage state from notifications into MowingDevice."""
2
+
2
3
  from typing import Optional, Callable, Awaitable
3
4
 
4
5
  import betterproto
@@ -13,21 +14,21 @@ class StateManager:
13
14
 
14
15
  _device: MowingDevice
15
16
 
16
- def __init__(self, device: MowingDevice):
17
+ def __init__(self, device: MowingDevice) -> None:
17
18
  self._device = device
18
- self.gethash_ack_callback: Optional[Callable[[NavGetHashListAck],Awaitable[None]]] = None
19
- self.get_commondata_ack_callback: Optional[Callable[[NavGetCommDataAck],Awaitable[None]]] = None
20
- self.on_notification_callback: Optional[Callable[[],Awaitable[None]]] = None
19
+ self.gethash_ack_callback: Optional[Callable[[NavGetHashListAck], Awaitable[None]]] = None
20
+ self.get_commondata_ack_callback: Optional[Callable[[NavGetCommDataAck], Awaitable[None]]] = None
21
+ self.on_notification_callback: Optional[Callable[[], Awaitable[None]]] = None
21
22
 
22
23
  def get_device(self) -> MowingDevice:
23
24
  """Get device."""
24
25
  return self._device
25
26
 
26
- def set_device(self, device: MowingDevice):
27
+ def set_device(self, device: MowingDevice) -> None:
27
28
  """Set device."""
28
29
  self._device = device
29
30
 
30
- async def notification(self, message: LubaMsg):
31
+ async def notification(self, message: LubaMsg) -> None:
31
32
  """Handle protobuf notifications."""
32
33
  res = betterproto.which_one_of(message, "LubaSubMsg")
33
34
 
@@ -48,7 +49,7 @@ class StateManager:
48
49
  if self.on_notification_callback:
49
50
  await self.on_notification_callback()
50
51
 
51
- async def _update_nav_data(self, message):
52
+ async def _update_nav_data(self, message) -> None:
52
53
  """Update nav data."""
53
54
  nav_msg = betterproto.which_one_of(message.nav, "SubNavMsg")
54
55
  match nav_msg[0]:
@@ -62,7 +63,7 @@ class StateManager:
62
63
  if updated:
63
64
  await self.get_commondata_ack_callback(common_data)
64
65
 
65
- def _update_sys_data(self, message):
66
+ def _update_sys_data(self, message) -> None:
66
67
  """Update system."""
67
68
  sys_msg = betterproto.which_one_of(message.sys, "SubSysMsg")
68
69
  match sys_msg[0]:
@@ -75,14 +76,14 @@ class StateManager:
75
76
  case "system_tard_state_tunnel":
76
77
  self._device.run_state_update(sys_msg[1])
77
78
 
78
- def _update_driver_data(self, message):
79
+ def _update_driver_data(self, message) -> None:
79
80
  pass
80
81
 
81
- def _update_net_data(self, message):
82
+ def _update_net_data(self, message) -> None:
82
83
  pass
83
84
 
84
- def _update_mul_data(self, message):
85
+ def _update_mul_data(self, message) -> None:
85
86
  pass
86
87
 
87
- def _update_ota_data(self, message):
88
+ def _update_ota_data(self, message) -> None:
88
89
  pass
@@ -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,59 +1,48 @@
1
- from dataclasses import dataclass
2
- from typing import Generic, Literal, Optional, TypeVar
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
 
23
+ async def get_all_error_codes(self) -> list[ErrorInfo]:
24
+ async with ClientSession(MAMMOTION_API_DOMAIN) as session:
25
+ async with session.post(
26
+ "/user-server/v1/code/record/export-data",
27
+ headers=self._headers,
28
+ ) as resp:
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)
45
+
57
46
  @classmethod
58
47
  async def login(cls, session: ClientSession, username: str, password: str) -> Response[LoginResponseData]:
59
48
  async with session.post(
@@ -66,12 +55,11 @@ class MammotionHTTP:
66
55
  grant_type="password",
67
56
  ),
68
57
  ) as resp:
69
- if resp.status == 200:
70
- data = await resp.json()
71
- response = Response.from_dict(data)
72
- # TODO catch errors from mismatch user / password elsewhere
73
- # Assuming the data format matches the expected structure
74
- 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
75
63
 
76
64
 
77
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 luba_msg_pb2, mctrl_driver_pb2
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
- luba_msg = luba_msg_pb2.LubaMsg(
16
- msgtype=luba_msg_pb2.MSG_CMD_TYPE_EMBED_DRIVER,
17
- sender=luba_msg_pb2.DEV_MOBILEAPP,
18
- rcver=luba_msg_pb2.DEV_MAINCTL,
19
- msgattr=luba_msg_pb2.MSG_ATTR_REQ,
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 = mctrl_driver_pb2.MctlDriver(todev_knife_height_set=mctrl_driver_pb2.DrvKnifeHeight(knifeHeight=height))
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 = mctrl_driver_pb2.MctlDriver(bidire_speed_read_set=mctrl_driver_pb2.DrvSrSpeed(speed=speed, rw=1))
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 = mctrl_driver_pb2.MctlDriver(
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 = mctrl_driver_pb2.MctlDriver(
50
- rtk_cfg_req=mctrl_driver_pb2.rtk_cfg_req_t(cmd_req=cmd_req, cmd_length=len(cmd_req) - 1)
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 = mctrl_driver_pb2.MctlDriver(bidire_speed_read_set=mctrl_driver_pb2.DrvSrSpeed(rw=0))
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 = mctrl_driver_pb2.MctlDriver(
71
- mow_ctrl_by_hand=mctrl_driver_pb2.DrvMowCtrlByHand(
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
- max_run_Speed=max_run_speed,
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
- mctrl_driver_pb2.MctlDriver(
90
- todev_devmotion_ctrl=mctrl_driver_pb2.DrvMotionCtrl(
91
- setLinearSpeed=linear_speed, setAngularSpeed=angular_speed
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
  )