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.
Files changed (49) hide show
  1. pymammotion/__init__.py +11 -8
  2. pymammotion/aliyun/cloud_gateway.py +26 -24
  3. pymammotion/aliyun/cloud_service.py +3 -3
  4. pymammotion/aliyun/dataclass/dev_by_account_response.py +1 -1
  5. pymammotion/bluetooth/ble.py +5 -5
  6. pymammotion/bluetooth/ble_message.py +30 -16
  7. pymammotion/bluetooth/data/convert.py +1 -1
  8. pymammotion/bluetooth/data/framectrldata.py +1 -1
  9. pymammotion/bluetooth/data/notifydata.py +6 -6
  10. pymammotion/const.py +1 -0
  11. pymammotion/data/model/__init__.py +2 -0
  12. pymammotion/data/model/device.py +22 -20
  13. pymammotion/data/model/device_config.py +1 -1
  14. pymammotion/data/model/enums.py +4 -4
  15. pymammotion/data/model/excute_boarder_params.py +5 -5
  16. pymammotion/data/model/execute_boarder.py +4 -4
  17. pymammotion/data/model/hash_list.py +1 -1
  18. pymammotion/data/model/location.py +2 -2
  19. pymammotion/data/model/plan.py +4 -4
  20. pymammotion/data/model/region_data.py +4 -4
  21. pymammotion/data/model/report_info.py +1 -1
  22. pymammotion/data/mqtt/event.py +1 -1
  23. pymammotion/data/state_manager.py +9 -9
  24. pymammotion/event/event.py +14 -14
  25. pymammotion/http/http.py +29 -51
  26. pymammotion/http/model/http.py +75 -0
  27. pymammotion/mammotion/commands/messages/driver.py +20 -23
  28. pymammotion/mammotion/commands/messages/navigation.py +47 -48
  29. pymammotion/mammotion/commands/messages/network.py +17 -35
  30. pymammotion/mammotion/commands/messages/system.py +6 -7
  31. pymammotion/mammotion/control/joystick.py +10 -10
  32. pymammotion/mammotion/devices/__init__.py +2 -2
  33. pymammotion/mammotion/devices/base.py +248 -0
  34. pymammotion/mammotion/devices/mammotion.py +23 -1005
  35. pymammotion/mammotion/devices/mammotion_bluetooth.py +447 -0
  36. pymammotion/mammotion/devices/mammotion_cloud.py +246 -0
  37. pymammotion/mqtt/mammotion_future.py +2 -2
  38. pymammotion/mqtt/mammotion_mqtt.py +17 -14
  39. pymammotion/proto/__init__.py +6 -0
  40. pymammotion/utility/constant/__init__.py +3 -1
  41. pymammotion/utility/datatype_converter.py +9 -9
  42. pymammotion/utility/device_type.py +13 -13
  43. pymammotion/utility/map.py +2 -2
  44. pymammotion/utility/periodic.py +5 -5
  45. pymammotion/utility/rocker_util.py +1 -1
  46. {pymammotion-0.2.29.dist-info → pymammotion-0.2.31.dist-info}/METADATA +3 -1
  47. {pymammotion-0.2.29.dist-info → pymammotion-0.2.31.dist-info}/RECORD +49 -45
  48. {pymammotion-0.2.29.dist-info → pymammotion-0.2.31.dist-info}/LICENSE +0 -0
  49. {pymammotion-0.2.29.dist-info → pymammotion-0.2.31.dist-info}/WHEEL +0 -0
pymammotion/__init__.py CHANGED
@@ -8,15 +8,16 @@ import asyncio
8
8
  import logging
9
9
  import os
10
10
 
11
+ from pymammotion.aliyun.cloud_gateway import CloudIOTGateway
12
+
11
13
  # works outside HA on its own
12
14
  from pymammotion.bluetooth.ble import MammotionBLE
13
15
  from pymammotion.http.http import MammotionHTTP, connect_http
14
16
 
15
17
  # TODO make a working device that will work outside HA too.
16
- from pymammotion.mammotion.devices import MammotionBaseBLEDevice
17
18
  from pymammotion.mqtt import MammotionMQTT
18
19
 
19
- __all__ = ["MammotionBLE", "MammotionHTTP", "connect_http", "MammotionBaseBLEDevice", "MammotionMQTT"]
20
+ __all__ = ["MammotionBLE", "MammotionHTTP", "connect_http", "MammotionMQTT"]
20
21
 
21
22
  logger = logging.getLogger(__name__)
22
23
 
@@ -32,13 +33,15 @@ if __name__ == "__main__":
32
33
  CLIENT_ID = os.environ.get("CLIENT_ID")
33
34
  IOT_TOKEN = os.environ.get("IOT_TOKEN")
34
35
  REGION = os.environ.get("REGION")
36
+ cloud_client = CloudIOTGateway()
35
37
  luba = MammotionMQTT(
36
- iot_token=IOT_TOKEN,
37
- region_id=REGION,
38
- product_key=PRODUCT_KEY,
39
- device_name=DEVICE_NAME,
40
- device_secret=DEVICE_SECRET,
41
- client_id=CLIENT_ID,
38
+ iot_token=IOT_TOKEN or "",
39
+ region_id=REGION or "",
40
+ product_key=PRODUCT_KEY or "",
41
+ device_name=DEVICE_NAME or "",
42
+ device_secret=DEVICE_SECRET or "",
43
+ client_id=CLIENT_ID or "",
44
+ cloud_client=cloud_client,
42
45
  )
43
46
  luba.connect_async()
44
47
 
@@ -17,7 +17,6 @@ from alibabacloud_iot_api_gateway.models import CommonParams, Config, IoTApiRequ
17
17
  from alibabacloud_tea_util.client import Client as UtilClient
18
18
  from alibabacloud_tea_util.models import RuntimeOptions
19
19
 
20
- from pymammotion.http.http import MammotionHTTP
21
20
  from pymammotion.aliyun.dataclass.aep_response import AepResponse
22
21
  from pymammotion.aliyun.dataclass.connect_response import ConnectResponse
23
22
  from pymammotion.aliyun.dataclass.dev_by_account_response import (
@@ -29,6 +28,7 @@ from pymammotion.aliyun.dataclass.session_by_authcode_response import (
29
28
  SessionByAuthCodeResponse,
30
29
  )
31
30
  from pymammotion.const import ALIYUN_DOMAIN, APP_KEY, APP_SECRET, APP_VERSION
31
+ from pymammotion.http.http import MammotionHTTP
32
32
  from pymammotion.utility.datatype_converter import DatatypeConverter
33
33
 
34
34
  logger = getLogger(__name__)
@@ -88,7 +88,7 @@ class CloudIOTGateway:
88
88
  session_by_authcode_response: SessionByAuthCodeResponse | None = None,
89
89
  region_response: RegionResponse | None = None,
90
90
  dev_by_account: ListingDevByAccountResponse | None = None,
91
- ):
91
+ ) -> None:
92
92
  """Initialize the CloudIOTGateway."""
93
93
  self.mammotion_http: MammotionHTTP | None = None
94
94
  self._app_key = APP_KEY
@@ -106,13 +106,13 @@ class CloudIOTGateway:
106
106
  self._devices_by_account_response = dev_by_account
107
107
 
108
108
  @staticmethod
109
- def generate_random_string(length):
109
+ def generate_random_string(length: int):
110
110
  """Generate a random string of specified length."""
111
111
  characters = string.ascii_letters + string.digits
112
112
  return "".join(random.choice(characters) for _ in range(length))
113
113
 
114
114
  @staticmethod
115
- def generate_hardware_string(length) -> str:
115
+ def generate_hardware_string(length: int) -> str:
116
116
  """Generate hardware string that is consistent per device."""
117
117
  hashed_uuid = hashlib.sha1(f"{uuid.getnode()}".encode()).hexdigest()
118
118
  return "".join(itertools.islice(itertools.cycle(hashed_uuid), length))
@@ -132,24 +132,6 @@ class CloudIOTGateway:
132
132
  hashlib.sha1,
133
133
  ).hexdigest()
134
134
 
135
- def get_connect_response(self):
136
- return self._connect_response
137
-
138
- def get_login_by_oauth_response(self):
139
- return self._login_by_oauth_response
140
-
141
- def get_aep_response(self):
142
- return self._aep_response
143
-
144
- def get_session_by_authcode_response(self):
145
- return self._session_by_authcode_response
146
-
147
- def get_devices_by_account_response(self):
148
- return self._devices_by_account_response
149
-
150
- def get_region_response(self):
151
- return self._region_response
152
-
153
135
  def get_region(self, country_code: str, auth_code: str):
154
136
  """Get the region based on country code and auth code."""
155
137
  config = Config(
@@ -630,8 +612,28 @@ class CloudIOTGateway:
630
612
  return message_id
631
613
 
632
614
  @property
633
- def listing_dev_by_account_response(self):
615
+ def devices_by_account_response(self):
634
616
  return self._devices_by_account_response
635
617
 
636
- def set_http(self, mammotion_http):
618
+ def set_http(self, mammotion_http) -> None:
637
619
  self.mammotion_http = mammotion_http
620
+
621
+ @property
622
+ def region_response(self):
623
+ return self._region_response
624
+
625
+ @property
626
+ def aep_response(self):
627
+ return self._aep_response
628
+
629
+ @property
630
+ def session_by_authcode_response(self):
631
+ return self._session_by_authcode_response
632
+
633
+ @property
634
+ def client_id(self):
635
+ return self._client_id
636
+
637
+ @property
638
+ def login_by_oath_response(self):
639
+ return self._login_by_oauth_response
@@ -10,7 +10,7 @@ from aliyunsdkiot.request.v20180120.InvokeThingServiceRequest import (
10
10
  class CloudService:
11
11
  # com.aliyun.iot.aep.sdk
12
12
  # https://domestic.mammotion.com/privacy/ - lists all aliyun packages
13
- def __init__(self):
13
+ def __init__(self) -> None:
14
14
  self.selectDeviceIOTID = ""
15
15
  accessKeyId = "<your accessKey>"
16
16
  accessKeySecret = "<your accessSecret>"
@@ -31,7 +31,7 @@ class CloudService:
31
31
 
32
32
  """
33
33
 
34
- def invoke_thing_service(self, data: bytearray):
34
+ def invoke_thing_service(self, data: bytearray) -> None:
35
35
  base64_encoded = base64.b64encode(data).decode("utf-8")
36
36
 
37
37
  # Create a dictionary structure
@@ -53,7 +53,7 @@ class CloudService:
53
53
  # python2: print(response)
54
54
  print(response)
55
55
 
56
- def get_device_status(self):
56
+ def get_device_status(self) -> None:
57
57
  request = GetDeviceStatusRequest()
58
58
  request.set_accept_format("json")
59
59
 
@@ -36,7 +36,7 @@ class Device(DataClassORJSONMixin):
36
36
  @dataclass
37
37
  class Data(DataClassORJSONMixin):
38
38
  total: int
39
- data: List[Device]
39
+ data: list[Device]
40
40
  pageNo: int
41
41
  pageSize: int
42
42
 
@@ -14,13 +14,13 @@ address = "90:38:0C:6E:EE:9E"
14
14
  class MammotionBLE:
15
15
  client: BleakClient
16
16
 
17
- def __init__(self, bleEvt: BleNotificationEvent):
17
+ def __init__(self, bleEvt: BleNotificationEvent) -> None:
18
18
  self._bleEvt = bleEvt
19
19
 
20
20
  async def scanForLubaAndConnect(self) -> bool:
21
21
  scanner = BleakScanner()
22
22
 
23
- def scanCallback(device, advertising_data):
23
+ def scanCallback(device, advertising_data) -> bool:
24
24
  # TODO: do something with incoming data
25
25
  print(device)
26
26
  print(advertising_data)
@@ -46,18 +46,18 @@ class MammotionBLE:
46
46
  if self.client is not None:
47
47
  return await self.client.disconnect()
48
48
 
49
- async def notification_handler(self, _characteristic: BleakGATTCharacteristic, data: bytearray):
49
+ async def notification_handler(self, _characteristic: BleakGATTCharacteristic, data: bytearray) -> None:
50
50
  """Simple notification handler which prints the data received."""
51
51
  await self._bleEvt.BleNotification(data)
52
52
 
53
- def service_changed_handler(self, characteristic: BleakGATTCharacteristic, data: bytearray):
53
+ def service_changed_handler(self, characteristic: BleakGATTCharacteristic, data: bytearray) -> None:
54
54
  """Simple notification handler which prints the data received."""
55
55
  print(f"Response 2 {characteristic.description}: {data}")
56
56
  print(data.decode("utf-8"))
57
57
  # BlufiNotifyData
58
58
  # run an event handler back to somewhere
59
59
 
60
- async def notifications(self):
60
+ async def notifications(self) -> None:
61
61
  if self.client.is_connected:
62
62
  await self.client.start_notify(UUID_NOTIFICATION_CHARACTERISTIC, self.notification_handler)
63
63
  await self.client.start_notify(SERVICE_CHANGED_CHARACTERISTIC, self.service_changed_handler)
@@ -51,14 +51,14 @@ class BleMessage:
51
51
  notification: BlufiNotifyData
52
52
  messageNavigation: MessageNavigation = MessageNavigation()
53
53
 
54
- def __init__(self, client: BleakClient):
54
+ def __init__(self, client: BleakClient) -> None:
55
55
  self.client = client
56
56
  self.mSendSequence = itertools.count()
57
57
  self.mReadSequence = itertools.count()
58
58
  self.mAck = queue.Queue()
59
59
  self.notification = BlufiNotifyData()
60
60
 
61
- async def get_device_version_main(self):
61
+ async def get_device_version_main(self) -> None:
62
62
  commEsp = dev_net_pb2.DevNet(todev_devinfo_req=dev_net_pb2.DrvDevInfoReq())
63
63
 
64
64
  for i in range(1, 8):
@@ -75,24 +75,38 @@ class BleMessage:
75
75
  lubaMsg.subtype = 1
76
76
  lubaMsg.net.CopyFrom(commEsp)
77
77
  byte_arr = lubaMsg.SerializeToString()
78
- await self.messageNavigation.post_custom_data_bytes(byte_arr)
78
+ await self.post_custom_data_bytes(byte_arr)
79
79
 
80
- async def get_task(self):
80
+ async def get_task(self) -> None:
81
81
  hash_map = {"pver": 1, "subCmd": 2, "result": 0}
82
- await self.messageNavigation.post_custom_data(self.get_json_string(bleOrderCmd.task, hash_map))
82
+ await self.post_custom_data(self.get_json_string(bleOrderCmd.task, hash_map))
83
83
 
84
- async def send_ble_alive(self):
84
+ async def send_ble_alive(self) -> None:
85
85
  hash_map = {"ctrl": 1}
86
- await self.messageNavigation.post_custom_data(self.get_json_string(bleOrderCmd.bleAlive, hash_map))
86
+ await self.post_custom_data(self.get_json_string(bleOrderCmd.bleAlive, hash_map))
87
87
 
88
- def clearNotification(self):
88
+ def get_json_string(self, cmd: int, hash_map: dict[str, object]) -> str:
89
+ jSONObject = {}
90
+ try:
91
+ jSONObject["cmd"] = cmd
92
+ jSONObject[tmp_constant.REQUEST_ID] = int(time.time())
93
+ jSONObject2 = {}
94
+ for key, value in hash_map.items():
95
+ jSONObject2[key] = value
96
+ jSONObject["params"] = jSONObject2
97
+ return json.dumps(jSONObject)
98
+ except Exception as e:
99
+ print(e)
100
+ return ""
101
+
102
+ def clearNotification(self) -> None:
89
103
  self.notification = None
90
104
  self.notification = BlufiNotifyData()
91
105
 
92
106
  # async def get_device_info(self):
93
107
  # await self.postCustomData(self.getJsonString(bleOrderCmd.getDeviceInfo))
94
108
 
95
- async def send_device_info(self):
109
+ async def send_device_info(self) -> None:
96
110
  """Currently not called"""
97
111
  luba_msg = luba_msg_pb2.LubaMsg(
98
112
  msgtype=luba_msg_pb2.MsgCmdType.MSG_CMD_TYPE_ESP,
@@ -107,7 +121,7 @@ class BleMessage:
107
121
  byte_arr = luba_msg.SerializeToString()
108
122
  await self.post_custom_data_bytes(byte_arr)
109
123
 
110
- async def requestDeviceStatus(self):
124
+ async def requestDeviceStatus(self) -> None:
111
125
  request = False
112
126
  type = self.messageNavigation.getTypeValue(0, 5)
113
127
  try:
@@ -121,7 +135,7 @@ class BleMessage:
121
135
  # if not request:
122
136
  # onStatusResponse(BlufiCallback.CODE_WRITE_DATA_FAILED, null)
123
137
 
124
- async def requestDeviceVersion(self):
138
+ async def requestDeviceVersion(self) -> None:
125
139
  request = False
126
140
  type = self.messageNavigation.getTypeValue(0, 7)
127
141
  try:
@@ -132,7 +146,7 @@ class BleMessage:
132
146
  request = False
133
147
  _LOGGER.error(err)
134
148
 
135
- async def sendBorderPackage(self, executeBorder: ExecuteBorder):
149
+ async def sendBorderPackage(self, executeBorder: ExecuteBorder) -> None:
136
150
  await self.messageNavigation.post_custom_data(serialize(executeBorder))
137
151
 
138
152
  async def gatt_write(self, data: bytes) -> None:
@@ -226,7 +240,7 @@ class BleMessage:
226
240
  return dataBytes
227
241
  return await self._parseDataData(subType, dataBytes)
228
242
 
229
- def _parseCtrlData(self, subType: int, data: bytes):
243
+ def _parseCtrlData(self, subType: int, data: bytes) -> None:
230
244
  pass
231
245
  # self._parseAck(data)
232
246
 
@@ -303,7 +317,7 @@ class BleMessage:
303
317
  def generateSendSequence(self):
304
318
  return next(self.mSendSequence) & 255
305
319
 
306
- async def post_custom_data_bytes(self, data: bytes):
320
+ async def post_custom_data_bytes(self, data: bytes) -> None:
307
321
  if data == None:
308
322
  return
309
323
  type_val = self.getTypeValue(1, 19)
@@ -315,7 +329,7 @@ class BleMessage:
315
329
  except Exception as err:
316
330
  _LOGGER.debug(err)
317
331
 
318
- async def post_custom_data(self, data_str: str):
332
+ async def post_custom_data(self, data_str: str) -> None:
319
333
  data = data_str.encode()
320
334
  if data == None:
321
335
  return
@@ -389,7 +403,7 @@ class BleMessage:
389
403
  require_ack: bool,
390
404
  hasFrag: bool,
391
405
  sequence: int,
392
- data: bytes,
406
+ data: bytes | None,
393
407
  ) -> bytes:
394
408
  byteOS = BytesIO()
395
409
  dataLength = 0 if data == None else len(data)
@@ -14,7 +14,7 @@ def parse_custom_data(data: bytes):
14
14
  print(err)
15
15
 
16
16
 
17
- def store_sys_data(sys):
17
+ def store_sys_data(sys) -> None:
18
18
  if sys.HasField("systemTardStateTunnel"):
19
19
  tard_state_data_list = sys.systemTardStateTunnel.tard_state_data
20
20
  longValue8 = tard_state_data_list[0]
@@ -6,7 +6,7 @@ class FrameCtrlData:
6
6
  FRAME_CTRL_POSITION_REQUIRE_ACK = 3
7
7
  mValue = 0
8
8
 
9
- def __init__(self, frameCtrlValue):
9
+ def __init__(self, frameCtrlValue) -> None:
10
10
  self.mValue = frameCtrlValue
11
11
 
12
12
  def check(self, position):
@@ -6,7 +6,7 @@ from io import BytesIO
6
6
  class BlufiNotifyData:
7
7
  """generated source for class BlufiNotifyData"""
8
8
 
9
- def __init__(self):
9
+ def __init__(self) -> None:
10
10
  self.mDataOS = BytesIO()
11
11
  self.mFrameCtrlValue = 0
12
12
  self.mPkgType = 0
@@ -18,7 +18,7 @@ class BlufiNotifyData:
18
18
  return self.mTypeValue
19
19
 
20
20
  # JADX INFO: Access modifiers changed from: package-private
21
- def setType(self, i):
21
+ def setType(self, i) -> None:
22
22
  """Generated source for method setType"""
23
23
  self.mTypeValue = i
24
24
 
@@ -28,7 +28,7 @@ class BlufiNotifyData:
28
28
  return self.mPkgType
29
29
 
30
30
  # JADX INFO: Access modifiers changed from: package-private
31
- def setPkgType(self, i):
31
+ def setPkgType(self, i) -> None:
32
32
  """Generated source for method setPkgType"""
33
33
  self.mPkgType = i
34
34
 
@@ -38,7 +38,7 @@ class BlufiNotifyData:
38
38
  return self.mSubType
39
39
 
40
40
  # JADX INFO: Access modifiers changed from: package-private
41
- def setSubType(self, i):
41
+ def setSubType(self, i) -> None:
42
42
  """Generated source for method setSubType"""
43
43
  self.mSubType = i
44
44
 
@@ -47,12 +47,12 @@ class BlufiNotifyData:
47
47
  return self.mFrameCtrlValue
48
48
 
49
49
  # JADX INFO: Access modifiers changed from: package-private
50
- def setFrameCtrl(self, i):
50
+ def setFrameCtrl(self, i) -> None:
51
51
  """Generated source for method setFrameCtrl"""
52
52
  self.mFrameCtrlValue = i
53
53
 
54
54
  # JADX INFO: Access modifiers changed from: package-private
55
- def addData(self, bArr, i):
55
+ def addData(self, bArr, i) -> None:
56
56
  """Generated source for method addData"""
57
57
  self.mDataOS.write(bArr[i:])
58
58
 
pymammotion/const.py CHANGED
@@ -5,5 +5,6 @@ APP_SECRET = "1ba85698bb10e19c6437413b61ba3445"
5
5
  APP_VERSION = "1.11.130"
6
6
  ALIYUN_DOMAIN = "api.link.aliyun.com"
7
7
  MAMMOTION_DOMAIN = "https://id.mammotion.com"
8
+ MAMMOTION_API_DOMAIN = "https://domestic.mammotion.com"
8
9
  MAMMOTION_CLIENT_ID = "MADKALUBAS"
9
10
  MAMMOTION_CLIENT_SECRET = "GshzGRZJjuMUgd2sYHM7"
@@ -5,3 +5,5 @@ from .hash_list import HashList
5
5
  from .plan import Plan
6
6
  from .rapid_state import RapidState, RTKStatus
7
7
  from .region_data import RegionData
8
+
9
+ __all__ = ["GenerateRouteInformation", "HashList", "Plan", "RapidState", "RTKStatus", "RegionData"]
@@ -1,6 +1,5 @@
1
1
  """MowingDevice class to wrap around the betterproto dataclasses."""
2
2
 
3
- import math
4
3
  from dataclasses import dataclass
5
4
 
6
5
  import betterproto
@@ -20,8 +19,8 @@ from pymammotion.proto.mctrl_sys import (
20
19
  MctlSys,
21
20
  MowToAppInfoT,
22
21
  ReportInfoData,
23
- SystemUpdateBufMsg,
24
22
  SystemRapidStateTunnelMsg,
23
+ SystemUpdateBufMsg,
25
24
  )
26
25
  from pymammotion.utility.constant import WorkMode
27
26
  from pymammotion.utility.conversions import parse_double
@@ -37,7 +36,7 @@ class MowingDevice:
37
36
  location: Location
38
37
  mowing_state: RapidState
39
38
 
40
- def __init__(self):
39
+ def __init__(self) -> None:
41
40
  self.device = LubaMsg()
42
41
  self.map = HashList(area={}, path={}, obstacle={}, hashlist=[])
43
42
  self.location = Location()
@@ -58,7 +57,7 @@ class MowingDevice:
58
57
  """Update the raw LubaMsg data."""
59
58
  self.device = LubaMsg(**raw)
60
59
 
61
- def buffer(self, buffer_list: SystemUpdateBufMsg):
60
+ def buffer(self, buffer_list: SystemUpdateBufMsg) -> None:
62
61
  """Update the device based on which buffer we are reading from."""
63
62
  match buffer_list.update_buf_data[0]:
64
63
  case 1:
@@ -100,7 +99,7 @@ class MowingDevice:
100
99
  ]
101
100
  )
102
101
 
103
- def update_report_data(self, toapp_report_data: ReportInfoData):
102
+ def update_report_data(self, toapp_report_data: ReportInfoData) -> None:
104
103
  coordinate_converter = CoordinateConverter(self.location.RTK.latitude, self.location.RTK.longitude)
105
104
  for index, location in enumerate(toapp_report_data.locations):
106
105
  if index == 0 and location.real_pos_y != 0:
@@ -116,12 +115,15 @@ class MowingDevice:
116
115
 
117
116
  self.report_data = self.report_data.from_dict(toapp_report_data.to_dict(casing=betterproto.Casing.SNAKE))
118
117
 
119
- def run_state_update(self, rapid_state: SystemRapidStateTunnelMsg):
118
+ def run_state_update(self, rapid_state: SystemRapidStateTunnelMsg) -> None:
120
119
  self.mowing_state = RapidState().from_raw(rapid_state.rapid_state_data)
121
120
 
122
- def mow_info(self, toapp_mow_info: MowToAppInfoT):
121
+ def mow_info(self, toapp_mow_info: MowToAppInfoT) -> None:
123
122
  pass
124
123
 
124
+ def report_missing_data(self) -> None:
125
+ """Report missing data so we can refetch it."""
126
+
125
127
  @property
126
128
  def net(self):
127
129
  """Will return a wrapped betterproto of net."""
@@ -164,7 +166,7 @@ class DevNetData:
164
166
 
165
167
  net: dict
166
168
 
167
- def __init__(self, net: DevNet):
169
+ def __init__(self, net: DevNet) -> None:
168
170
  if isinstance(net, dict):
169
171
  self.net = net
170
172
  else:
@@ -187,13 +189,13 @@ class SysData:
187
189
 
188
190
  sys: dict
189
191
 
190
- def __init__(self, sys: MctlSys):
192
+ def __init__(self, sys: MctlSys) -> None:
191
193
  if isinstance(sys, dict):
192
194
  self.sys = sys
193
195
  else:
194
196
  self.sys = sys.to_dict()
195
197
 
196
- def __getattr__(self, item):
198
+ def __getattr__(self, item: str):
197
199
  """Intercept call to get sys in dict and return a betterproto dataclass."""
198
200
  if self.sys.get(item) is None:
199
201
  return MctlSys().__getattribute__(item)
@@ -210,13 +212,13 @@ class NavData:
210
212
 
211
213
  nav: dict
212
214
 
213
- def __init__(self, nav: MctlNav):
215
+ def __init__(self, nav: MctlNav) -> None:
214
216
  if isinstance(nav, dict):
215
217
  self.nav = nav
216
218
  else:
217
219
  self.nav = nav.to_dict()
218
220
 
219
- def __getattr__(self, item):
221
+ def __getattr__(self, item: str):
220
222
  """Intercept call to get nav in dict and return a betterproto dataclass."""
221
223
  if self.nav.get(item) is None:
222
224
  return MctlNav().__getattribute__(item)
@@ -233,13 +235,13 @@ class DriverData:
233
235
 
234
236
  driver: dict
235
237
 
236
- def __init__(self, driver: MctlDriver):
238
+ def __init__(self, driver: MctlDriver) -> None:
237
239
  if isinstance(driver, dict):
238
240
  self.driver = driver
239
241
  else:
240
242
  self.driver = driver.to_dict()
241
243
 
242
- def __getattr__(self, item):
244
+ def __getattr__(self, item: str):
243
245
  """Intercept call to get driver in dict and return a betterproto dataclass."""
244
246
  if self.driver.get(item) is None:
245
247
  return MctlDriver().__getattribute__(item)
@@ -256,13 +258,13 @@ class MulData:
256
258
 
257
259
  mul: dict
258
260
 
259
- def __init__(self, mul: SocMul):
261
+ def __init__(self, mul: SocMul) -> None:
260
262
  if isinstance(mul, dict):
261
263
  self.mul = mul
262
264
  else:
263
265
  self.mul = mul.to_dict()
264
266
 
265
- def __getattr__(self, item):
267
+ def __getattr__(self, item: str):
266
268
  """Intercept call to get mul in dict and return a betterproto dataclass."""
267
269
  if self.mul.get(item) is None:
268
270
  return SocMul().__getattribute__(item)
@@ -279,13 +281,13 @@ class OtaData:
279
281
 
280
282
  ota: dict
281
283
 
282
- def __init__(self, ota: MctlOta):
284
+ def __init__(self, ota: MctlOta) -> None:
283
285
  if isinstance(ota, dict):
284
286
  self.ota = ota
285
287
  else:
286
288
  self.ota = ota.to_dict()
287
289
 
288
- def __getattr__(self, item):
290
+ def __getattr__(self, item: str):
289
291
  """Intercept call to get ota in dict and return a betterproto dataclass."""
290
292
  if self.ota.get(item) is None:
291
293
  return MctlOta().__getattribute__(item)
@@ -302,13 +304,13 @@ class PeptData:
302
304
 
303
305
  pept: dict
304
306
 
305
- def __init__(self, pept: MctlPept):
307
+ def __init__(self, pept: MctlPept) -> None:
306
308
  if isinstance(pept, dict):
307
309
  self.pept = pept
308
310
  else:
309
311
  self.pept = pept.to_dict()
310
312
 
311
- def __getattr__(self, item):
313
+ def __getattr__(self, item: str):
312
314
  """Intercept call to get pept in dict and return a betterproto dataclass."""
313
315
  if self.pept.get(item) is None:
314
316
  return MctlPept().__getattribute__(item)
@@ -62,7 +62,7 @@ def create_path_order(operation_mode: OperationSettings, device_name: str) -> st
62
62
  return str(bArr, "UTF-8")
63
63
 
64
64
 
65
- def calculate_yuka_mode(operation_mode: OperationSettings):
65
+ def calculate_yuka_mode(operation_mode: OperationSettings) -> int:
66
66
  if operation_mode.is_mow and operation_mode.is_dump and operation_mode.is_edge:
67
67
  return 14
68
68
  if operation_mode.is_mow and operation_mode.is_dump and not operation_mode.is_edge:
@@ -9,7 +9,7 @@ class PositionMode(Enum):
9
9
  UNKNOWN = 4
10
10
 
11
11
  @staticmethod
12
- def from_value(value):
12
+ def from_value(value: int):
13
13
  if value == 0:
14
14
  return PositionMode.FIX
15
15
  elif value == 1:
@@ -21,7 +21,7 @@ class PositionMode(Enum):
21
21
  else:
22
22
  return PositionMode.UNKNOWN
23
23
 
24
- def __str__(self):
24
+ def __str__(self) -> str:
25
25
  if self == PositionMode.FIX:
26
26
  return "Fix"
27
27
  elif self == PositionMode.SINGLE:
@@ -42,7 +42,7 @@ class RTKStatus(Enum):
42
42
  UNKNOWN = 6
43
43
 
44
44
  @staticmethod
45
- def from_value(value):
45
+ def from_value(value: int):
46
46
  if value == 0:
47
47
  return RTKStatus.NONE
48
48
  elif value == 1 or value == 2:
@@ -54,7 +54,7 @@ class RTKStatus(Enum):
54
54
  else:
55
55
  return RTKStatus.UNKNOWN
56
56
 
57
- def __str__(self):
57
+ def __str__(self) -> str:
58
58
  if self == RTKStatus.NONE:
59
59
  return "None"
60
60
  elif self == RTKStatus.SINGLE:
@@ -5,7 +5,7 @@ class ExecuteBorderParams:
5
5
  currentFrame = 0
6
6
  jobIndex = ""
7
7
 
8
- def __init__(self, i, str_, list_):
8
+ def __init__(self, i, str_, list_) -> None:
9
9
  """Generated source for method __init__"""
10
10
  self.currentFrame = i
11
11
  self.border = list_
@@ -15,7 +15,7 @@ class ExecuteBorderParams:
15
15
  """Generated source for method getCurrentFrame"""
16
16
  return self.currentFrame
17
17
 
18
- def set_current_frame(self, i):
18
+ def set_current_frame(self, i) -> None:
19
19
  """Generated source for method setCurrentFrame"""
20
20
  self.currentFrame = i
21
21
 
@@ -23,7 +23,7 @@ class ExecuteBorderParams:
23
23
  """Generated source for method getJobIndex"""
24
24
  return self.jobIndex
25
25
 
26
- def set_job_index(self, str_):
26
+ def set_job_index(self, str_) -> None:
27
27
  """Generated source for method setJobIndex"""
28
28
  self.jobIndex = str_
29
29
 
@@ -31,11 +31,11 @@ class ExecuteBorderParams:
31
31
  """Generated source for method getBorder"""
32
32
  return self.border
33
33
 
34
- def set_border(self, border_list):
34
+ def set_border(self, border_list) -> None:
35
35
  """Generated source for method setBorder"""
36
36
  self.border = border_list
37
37
 
38
- def __str__(self):
38
+ def __str__(self) -> str:
39
39
  """Generated source for method toString"""
40
40
  return (
41
41
  "ExecuteBorderParamsBean{currentFrame="