pymammotion 0.3.7__py3-none-any.whl → 0.4.0__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 +2 -2
- pymammotion/aliyun/cloud_gateway.py +12 -9
- pymammotion/aliyun/model/aep_response.py +1 -2
- pymammotion/aliyun/model/dev_by_account_response.py +7 -8
- pymammotion/aliyun/model/login_by_oauth_response.py +2 -3
- pymammotion/aliyun/model/regions_response.py +3 -3
- pymammotion/aliyun/model/session_by_authcode_response.py +1 -2
- pymammotion/aliyun/model/stream_subscription_response.py +1 -2
- pymammotion/bluetooth/ble.py +5 -5
- pymammotion/bluetooth/ble_message.py +9 -13
- pymammotion/data/model/device.py +31 -228
- pymammotion/data/model/device_config.py +0 -10
- pymammotion/data/model/device_info.py +13 -0
- pymammotion/data/model/device_limits.py +49 -0
- pymammotion/data/model/generate_route_information.py +1 -1
- pymammotion/data/model/hash_list.py +6 -2
- pymammotion/data/model/plan.py +0 -3
- pymammotion/data/model/raw_data.py +215 -0
- pymammotion/data/model/region_data.py +10 -11
- pymammotion/data/model/report_info.py +1 -1
- pymammotion/data/mqtt/event.py +18 -14
- pymammotion/data/mqtt/properties.py +1 -1
- pymammotion/data/mqtt/status.py +1 -1
- pymammotion/data/state_manager.py +83 -23
- pymammotion/http/encryption.py +220 -0
- pymammotion/http/http.py +92 -39
- pymammotion/http/model/http.py +4 -2
- pymammotion/mammotion/commands/abstract_message.py +2 -2
- pymammotion/mammotion/commands/messages/driver.py +28 -21
- pymammotion/mammotion/commands/messages/media.py +10 -14
- pymammotion/mammotion/commands/messages/navigation.py +14 -11
- pymammotion/mammotion/commands/messages/network.py +17 -14
- pymammotion/mammotion/commands/messages/ota.py +9 -14
- pymammotion/mammotion/commands/messages/system.py +32 -29
- pymammotion/mammotion/commands/messages/video.py +9 -14
- pymammotion/mammotion/devices/base.py +7 -14
- pymammotion/mammotion/devices/mammotion.py +22 -13
- pymammotion/mammotion/devices/mammotion_bluetooth.py +15 -4
- pymammotion/mammotion/devices/mammotion_cloud.py +30 -12
- pymammotion/mqtt/linkkit/__init__.py +5 -0
- pymammotion/mqtt/linkkit/h2client.py +585 -0
- pymammotion/mqtt/linkkit/linkkit.py +3020 -0
- pymammotion/mqtt/mammotion_mqtt.py +13 -9
- pymammotion/proto/__init__.py +2176 -1
- pymammotion/proto/luba_mul.proto +1 -0
- pymammotion/proto/luba_mul_pb2.py +8 -8
- pymammotion/proto/luba_mul_pb2.pyi +1 -0
- 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/constant/device_constant.py +14 -5
- pymammotion/utility/device_config.py +754 -0
- pymammotion/utility/device_type.py +64 -16
- {pymammotion-0.3.7.dist-info → pymammotion-0.4.0.dist-info}/METADATA +9 -9
- {pymammotion-0.3.7.dist-info → pymammotion-0.4.0.dist-info}/RECORD +58 -62
- {pymammotion-0.3.7.dist-info → pymammotion-0.4.0.dist-info}/WHEEL +1 -1
- pymammotion/aliyun/cloud_service.py +0 -65
- 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 -76
- 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.3.7.dist-info → pymammotion-0.4.0.dist-info}/LICENSE +0 -0
pymammotion/__init__.py
CHANGED
@@ -12,7 +12,7 @@ from pymammotion.aliyun.cloud_gateway import CloudIOTGateway
|
|
12
12
|
|
13
13
|
# works outside HA on its own
|
14
14
|
from pymammotion.bluetooth.ble import MammotionBLE
|
15
|
-
from pymammotion.http.http import MammotionHTTP
|
15
|
+
from pymammotion.http.http import MammotionHTTP
|
16
16
|
|
17
17
|
# TODO make a working device that will work outside HA too.
|
18
18
|
from pymammotion.mqtt import MammotionMQTT
|
@@ -20,7 +20,7 @@ from pymammotion.mqtt import MammotionMQTT
|
|
20
20
|
logger = logging.getLogger(__name__)
|
21
21
|
|
22
22
|
|
23
|
-
__all__ = ["MammotionBLE", "MammotionHTTP", "
|
23
|
+
__all__ = ["MammotionBLE", "MammotionHTTP", "MammotionMQTT", "logger"]
|
24
24
|
|
25
25
|
|
26
26
|
# TODO provide interface to pick between mqtt/cloud/bluetooth
|
@@ -5,11 +5,11 @@ import hashlib
|
|
5
5
|
import hmac
|
6
6
|
import itertools
|
7
7
|
import json
|
8
|
+
from logging import getLogger
|
8
9
|
import random
|
9
10
|
import string
|
10
11
|
import time
|
11
12
|
import uuid
|
12
|
-
from logging import getLogger
|
13
13
|
|
14
14
|
from aiohttp import ClientSession
|
15
15
|
from alibabacloud_iot_api_gateway.client import Client
|
@@ -19,14 +19,10 @@ from alibabacloud_tea_util.models import RuntimeOptions
|
|
19
19
|
|
20
20
|
from pymammotion.aliyun.model.aep_response import AepResponse
|
21
21
|
from pymammotion.aliyun.model.connect_response import ConnectResponse
|
22
|
-
from pymammotion.aliyun.model.dev_by_account_response import
|
23
|
-
ListingDevByAccountResponse,
|
24
|
-
)
|
22
|
+
from pymammotion.aliyun.model.dev_by_account_response import ListingDevByAccountResponse
|
25
23
|
from pymammotion.aliyun.model.login_by_oauth_response import LoginByOAuthResponse
|
26
24
|
from pymammotion.aliyun.model.regions_response import RegionResponse
|
27
|
-
from pymammotion.aliyun.model.session_by_authcode_response import
|
28
|
-
SessionByAuthCodeResponse,
|
29
|
-
)
|
25
|
+
from pymammotion.aliyun.model.session_by_authcode_response import SessionByAuthCodeResponse
|
30
26
|
from pymammotion.const import ALIYUN_DOMAIN, APP_KEY, APP_SECRET, APP_VERSION
|
31
27
|
from pymammotion.http.http import MammotionHTTP
|
32
28
|
from pymammotion.utility.datatype_converter import DatatypeConverter
|
@@ -58,6 +54,10 @@ class DeviceOfflineException(Exception):
|
|
58
54
|
"""Raise exception when device is offline."""
|
59
55
|
|
60
56
|
|
57
|
+
class GatewayTimeoutException(Exception):
|
58
|
+
"""Raise exception when the gateway times out."""
|
59
|
+
|
60
|
+
|
61
61
|
class LoginException(Exception):
|
62
62
|
"""Raise exception when library cannot log in."""
|
63
63
|
|
@@ -657,7 +657,7 @@ class CloudIOTGateway:
|
|
657
657
|
iot_token=self._session_by_authcode_response.data.iotToken,
|
658
658
|
)
|
659
659
|
|
660
|
-
# TODO move to using
|
660
|
+
# TODO move to using InvokeThingServiceRequest()
|
661
661
|
|
662
662
|
message_id = str(uuid.uuid4())
|
663
663
|
|
@@ -689,13 +689,16 @@ class CloudIOTGateway:
|
|
689
689
|
str(response_body_dict.get("code")),
|
690
690
|
str(response_body_dict.get("message")),
|
691
691
|
)
|
692
|
+
if response_body_dict.get("code") == 20056:
|
693
|
+
logger.debug("Gateway timeout.")
|
694
|
+
raise GatewayTimeoutException(response_body_dict.get("code"))
|
695
|
+
|
692
696
|
if response_body_dict.get("code") == 29003:
|
693
697
|
logger.debug(self._session_by_authcode_response.data.identityId)
|
694
698
|
self.sign_out()
|
695
699
|
raise SetupException(response_body_dict.get("code"))
|
696
700
|
if response_body_dict.get("code") == 6205:
|
697
701
|
raise DeviceOfflineException(response_body_dict.get("code"))
|
698
|
-
"""Device is offline."""
|
699
702
|
|
700
703
|
return message_id
|
701
704
|
|
@@ -1,5 +1,4 @@
|
|
1
1
|
from dataclasses import dataclass
|
2
|
-
from typing import Optional
|
3
2
|
|
4
3
|
from mashumaro.config import BaseConfig
|
5
4
|
from mashumaro.mixins.orjson import DataClassORJSONMixin
|
@@ -16,7 +15,7 @@ class DeviceData(DataClassORJSONMixin):
|
|
16
15
|
class AepResponse(DataClassORJSONMixin):
|
17
16
|
code: int
|
18
17
|
data: DeviceData
|
19
|
-
id:
|
18
|
+
id: str | None = None
|
20
19
|
|
21
20
|
class Config(BaseConfig):
|
22
21
|
omit_default = True
|
@@ -1,5 +1,4 @@
|
|
1
1
|
from dataclasses import dataclass
|
2
|
-
from typing import Optional
|
3
2
|
|
4
3
|
from mashumaro.config import BaseConfig
|
5
4
|
from mashumaro.mixins.orjson import DataClassORJSONMixin
|
@@ -23,11 +22,11 @@ class Device(DataClassORJSONMixin):
|
|
23
22
|
identityId: str
|
24
23
|
thingType: str
|
25
24
|
status: int
|
26
|
-
nickName:
|
27
|
-
description:
|
28
|
-
productImage:
|
29
|
-
categoryImage:
|
30
|
-
productModel:
|
25
|
+
nickName: str | None = None
|
26
|
+
description: str | None = None
|
27
|
+
productImage: str | None = None
|
28
|
+
categoryImage: str | None = None
|
29
|
+
productModel: str | None = None
|
31
30
|
|
32
31
|
class Config(BaseConfig):
|
33
32
|
omit_default = True
|
@@ -44,5 +43,5 @@ class Data(DataClassORJSONMixin):
|
|
44
43
|
@dataclass
|
45
44
|
class ListingDevByAccountResponse(DataClassORJSONMixin):
|
46
45
|
code: int
|
47
|
-
data:
|
48
|
-
id:
|
46
|
+
data: Data | None
|
47
|
+
id: str | None = None
|
@@ -1,5 +1,4 @@
|
|
1
1
|
from dataclasses import dataclass
|
2
|
-
from typing import Optional
|
3
2
|
|
4
3
|
from mashumaro.mixins.orjson import DataClassORJSONMixin
|
5
4
|
|
@@ -18,7 +17,7 @@ class OpenAccount(DataClassORJSONMixin):
|
|
18
17
|
domainId: int
|
19
18
|
enableDevice: str
|
20
19
|
status: int
|
21
|
-
country:
|
20
|
+
country: str | None = None
|
22
21
|
|
23
22
|
|
24
23
|
@dataclass
|
@@ -54,7 +53,7 @@ class InnerData(DataClassORJSONMixin):
|
|
54
53
|
subCode: int
|
55
54
|
message: str
|
56
55
|
successful: str
|
57
|
-
deviceId:
|
56
|
+
deviceId: str | None = None
|
58
57
|
|
59
58
|
|
60
59
|
@dataclass
|
@@ -1,5 +1,5 @@
|
|
1
1
|
from dataclasses import dataclass
|
2
|
-
from typing import
|
2
|
+
from typing import TypeVar
|
3
3
|
|
4
4
|
from mashumaro.config import BaseConfig
|
5
5
|
from mashumaro.mixins.orjson import DataClassORJSONMixin
|
@@ -22,8 +22,8 @@ class RegionResponseData(DataClassORJSONMixin):
|
|
22
22
|
class RegionResponse(DataClassORJSONMixin):
|
23
23
|
data: RegionResponseData
|
24
24
|
code: int
|
25
|
-
id:
|
26
|
-
msg:
|
25
|
+
id: str | None = None
|
26
|
+
msg: str | None = None
|
27
27
|
|
28
28
|
class Config(BaseConfig):
|
29
29
|
omit_default = True
|
@@ -1,5 +1,4 @@
|
|
1
1
|
from dataclasses import dataclass
|
2
|
-
from typing import Optional
|
3
2
|
|
4
3
|
from mashumaro.mixins.orjson import DataClassORJSONMixin
|
5
4
|
|
@@ -16,4 +15,4 @@ class SessionOauthToken(DataClassORJSONMixin):
|
|
16
15
|
@dataclass
|
17
16
|
class SessionByAuthCodeResponse(DataClassORJSONMixin):
|
18
17
|
code: int
|
19
|
-
data:
|
18
|
+
data: SessionOauthToken | None = None
|
@@ -1,5 +1,4 @@
|
|
1
1
|
from dataclasses import dataclass
|
2
|
-
from typing import List
|
3
2
|
|
4
3
|
from mashumaro.mixins.orjson import DataClassORJSONMixin
|
5
4
|
|
@@ -13,7 +12,7 @@ class Camera(DataClassORJSONMixin):
|
|
13
12
|
@dataclass
|
14
13
|
class StreamSubscriptionResponse(DataClassORJSONMixin):
|
15
14
|
appid: str
|
16
|
-
cameras:
|
15
|
+
cameras: list[Camera]
|
17
16
|
channelName: str
|
18
17
|
token: str
|
19
18
|
uid: int
|
pymammotion/bluetooth/ble.py
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
from bleak import BleakClient, BleakScanner, BLEDevice
|
2
2
|
from bleak.backends.characteristic import BleakGATTCharacteristic
|
3
3
|
|
4
|
-
from pymammotion.bluetooth.const import
|
5
|
-
SERVICE_CHANGED_CHARACTERISTIC,
|
6
|
-
UUID_NOTIFICATION_CHARACTERISTIC,
|
7
|
-
)
|
4
|
+
from pymammotion.bluetooth.const import SERVICE_CHANGED_CHARACTERISTIC, UUID_NOTIFICATION_CHARACTERISTIC
|
8
5
|
from pymammotion.event.event import BleNotificationEvent
|
9
6
|
|
10
7
|
|
11
8
|
class MammotionBLE:
|
9
|
+
"""Class for basic ble connections to mowers."""
|
10
|
+
|
12
11
|
client: BleakClient
|
13
12
|
|
14
13
|
def __init__(self, bleEvt: BleNotificationEvent) -> None:
|
@@ -60,5 +59,6 @@ class MammotionBLE:
|
|
60
59
|
await self.client.start_notify(UUID_NOTIFICATION_CHARACTERISTIC, self.notification_handler)
|
61
60
|
await self.client.start_notify(SERVICE_CHANGED_CHARACTERISTIC, self.service_changed_handler)
|
62
61
|
|
63
|
-
def
|
62
|
+
def get_client(self):
|
63
|
+
"""Returns the ble client."""
|
64
64
|
return self.client
|
@@ -1,12 +1,11 @@
|
|
1
|
+
from asyncio import sleep
|
2
|
+
from io import BytesIO
|
1
3
|
import itertools
|
2
4
|
import json
|
3
5
|
import logging
|
4
6
|
import queue
|
5
7
|
import sys
|
6
8
|
import time
|
7
|
-
from asyncio import sleep
|
8
|
-
from io import BytesIO
|
9
|
-
from typing import Union
|
10
9
|
|
11
10
|
from bleak import BleakClient
|
12
11
|
from jsonic.serializable import serialize
|
@@ -17,10 +16,7 @@ from pymammotion.bluetooth.data.framectrldata import FrameCtrlData
|
|
17
16
|
from pymammotion.bluetooth.data.notifydata import BlufiNotifyData
|
18
17
|
from pymammotion.bluetooth.model.atomic_integer import AtomicInteger
|
19
18
|
from pymammotion.data.model.execute_boarder import ExecuteBorder
|
20
|
-
from pymammotion.proto import
|
21
|
-
dev_net_pb2,
|
22
|
-
)
|
23
|
-
from pymammotion.proto.luba_msg import LubaMsg, MsgAttr, MsgCmdType, MsgDevice
|
19
|
+
from pymammotion.proto import DevNet, DrvDevInfoReq, LubaMsg, MsgAttr, MsgCmdType, MsgDevice
|
24
20
|
from pymammotion.utility.constant.device_constant import bleOrderCmd
|
25
21
|
|
26
22
|
_LOGGER = logging.getLogger(__name__)
|
@@ -320,7 +316,7 @@ class BleMessage:
|
|
320
316
|
hash_map = {"ctrl": 1}
|
321
317
|
await self.post_custom_data(self.get_json_string(bleOrderCmd.bleAlive, hash_map))
|
322
318
|
|
323
|
-
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:
|
324
320
|
jSONObject = {}
|
325
321
|
try:
|
326
322
|
jSONObject["cmd"] = cmd
|
@@ -334,7 +330,7 @@ class BleMessage:
|
|
334
330
|
print(e)
|
335
331
|
return ""
|
336
332
|
|
337
|
-
def
|
333
|
+
def clear_notification(self) -> None:
|
338
334
|
self.notification = None
|
339
335
|
self.notification = BlufiNotifyData()
|
340
336
|
|
@@ -344,14 +340,14 @@ class BleMessage:
|
|
344
340
|
async def send_device_info(self) -> None:
|
345
341
|
"""Currently not called"""
|
346
342
|
luba_msg = LubaMsg(
|
347
|
-
msgtype=MsgCmdType.
|
343
|
+
msgtype=MsgCmdType.ESP,
|
348
344
|
sender=MsgDevice.DEV_MOBILEAPP,
|
349
345
|
rcver=MsgDevice.DEV_COMM_ESP,
|
350
|
-
msgattr=MsgAttr.
|
346
|
+
msgattr=MsgAttr.REQ,
|
351
347
|
seqs=1,
|
352
348
|
version=1,
|
353
349
|
subtype=1,
|
354
|
-
net=
|
350
|
+
net=DevNet(todev_ble_sync=1, todev_devinfo_req=DrvDevInfoReq()),
|
355
351
|
)
|
356
352
|
byte_arr = luba_msg.SerializeToString()
|
357
353
|
await self.post_custom_data_bytes(byte_arr)
|
@@ -656,7 +652,7 @@ class BleMessage:
|
|
656
652
|
return byteOS.getvalue()
|
657
653
|
|
658
654
|
@staticmethod
|
659
|
-
def calc_crc(initial: int, data:
|
655
|
+
def calc_crc(initial: int, data: bytes | bytearray) -> int:
|
660
656
|
"""Calculate CRC value for given initial value and byte array.
|
661
657
|
|
662
658
|
Args:
|
pymammotion/data/model/device.py
CHANGED
@@ -1,32 +1,18 @@
|
|
1
1
|
"""MowingDevice class to wrap around the betterproto dataclasses."""
|
2
2
|
|
3
3
|
from dataclasses import dataclass, field
|
4
|
-
from typing import Optional
|
5
4
|
|
6
5
|
import betterproto
|
7
6
|
from mashumaro.mixins.orjson import DataClassORJSONMixin
|
8
7
|
|
9
8
|
from pymammotion.data.model import HashList, RapidState
|
10
|
-
from pymammotion.data.model.
|
11
|
-
from pymammotion.data.model.device_info import MowerInfo
|
9
|
+
from pymammotion.data.model.device_info import DeviceFirmwares, MowerInfo
|
12
10
|
from pymammotion.data.model.location import Location
|
13
11
|
from pymammotion.data.model.report_info import ReportData
|
14
12
|
from pymammotion.data.mqtt.properties import ThingPropertiesMessage
|
13
|
+
from pymammotion.data.mqtt.status import ThingStatusMessage
|
15
14
|
from pymammotion.http.model.http import ErrorInfo
|
16
|
-
from pymammotion.proto
|
17
|
-
from pymammotion.proto.luba_msg import LubaMsg
|
18
|
-
from pymammotion.proto.luba_mul import SocMul
|
19
|
-
from pymammotion.proto.mctrl_driver import MctlDriver
|
20
|
-
from pymammotion.proto.mctrl_nav import MctlNav
|
21
|
-
from pymammotion.proto.mctrl_ota import MctlOta
|
22
|
-
from pymammotion.proto.mctrl_pept import MctlPept
|
23
|
-
from pymammotion.proto.mctrl_sys import (
|
24
|
-
MctlSys,
|
25
|
-
MowToAppInfoT,
|
26
|
-
ReportInfoData,
|
27
|
-
SystemRapidStateTunnelMsg,
|
28
|
-
SystemUpdateBufMsg,
|
29
|
-
)
|
15
|
+
from pymammotion.proto import DeviceFwInfo, MowToAppInfoT, ReportInfoData, SystemRapidStateTunnelMsg, SystemUpdateBufMsg
|
30
16
|
from pymammotion.utility.constant import WorkMode
|
31
17
|
from pymammotion.utility.conversions import parse_double
|
32
18
|
from pymammotion.utility.map import CoordinateConverter
|
@@ -36,29 +22,19 @@ from pymammotion.utility.map import CoordinateConverter
|
|
36
22
|
class MowingDevice(DataClassORJSONMixin):
|
37
23
|
"""Wraps the betterproto dataclasses, so we can bypass the groups for keeping all data."""
|
38
24
|
|
25
|
+
online: bool = True
|
39
26
|
mower_state: MowerInfo = field(default_factory=MowerInfo)
|
40
27
|
mqtt_properties: ThingPropertiesMessage | None = None
|
28
|
+
status_properties: ThingStatusMessage | None = None
|
41
29
|
map: HashList = field(default_factory=HashList)
|
42
30
|
location: Location = field(default_factory=Location)
|
43
31
|
mowing_state: RapidState = field(default_factory=RapidState)
|
44
32
|
report_data: ReportData = field(default_factory=ReportData)
|
33
|
+
device_firmwares: DeviceFirmwares = field(default_factory=DeviceFirmwares)
|
45
34
|
err_code_list: list = field(default_factory=list)
|
46
|
-
err_code_list_time:
|
47
|
-
limits: DeviceLimits = field(default_factory=DeviceLimits)
|
48
|
-
device: Optional[LubaMsg] = field(default_factory=LubaMsg)
|
35
|
+
err_code_list_time: list | None = field(default_factory=list)
|
49
36
|
error_codes: dict[str, ErrorInfo] = field(default_factory=dict)
|
50
37
|
|
51
|
-
@classmethod
|
52
|
-
def from_raw(cls, raw: dict) -> "MowingDevice":
|
53
|
-
"""Take in raw data to hold in the betterproto dataclass."""
|
54
|
-
mowing_device = MowingDevice()
|
55
|
-
mowing_device.device = LubaMsg(**raw)
|
56
|
-
return mowing_device
|
57
|
-
|
58
|
-
def update_raw(self, raw: dict) -> None:
|
59
|
-
"""Update the raw LubaMsg data."""
|
60
|
-
self.device = LubaMsg(**raw)
|
61
|
-
|
62
38
|
def buffer(self, buffer_list: SystemUpdateBufMsg) -> None:
|
63
39
|
"""Update the device based on which buffer we are reading from."""
|
64
40
|
match buffer_list.update_buf_data[0]:
|
@@ -106,7 +82,7 @@ class MowingDevice(DataClassORJSONMixin):
|
|
106
82
|
for index, location in enumerate(toapp_report_data.locations):
|
107
83
|
if index == 0 and location.real_pos_y != 0:
|
108
84
|
self.location.position_type = location.pos_type
|
109
|
-
self.location.orientation = location.real_toward / 10000
|
85
|
+
self.location.orientation = int(location.real_toward / 10000)
|
110
86
|
self.location.device = coordinate_converter.enu_to_lla(
|
111
87
|
parse_double(location.real_pos_y, 4.0), parse_double(location.real_pos_x, 4.0)
|
112
88
|
)
|
@@ -115,13 +91,16 @@ class MowingDevice(DataClassORJSONMixin):
|
|
115
91
|
location.zone_hash if self.report_data.dev.sys_status == WorkMode.MODE_WORKING else 0
|
116
92
|
)
|
117
93
|
|
94
|
+
if toapp_report_data.fw_info:
|
95
|
+
self.update_device_firmwares(toapp_report_data.fw_info)
|
96
|
+
|
118
97
|
self.report_data.update(toapp_report_data.to_dict(casing=betterproto.Casing.SNAKE))
|
119
98
|
|
120
99
|
def run_state_update(self, rapid_state: SystemRapidStateTunnelMsg) -> None:
|
121
100
|
coordinate_converter = CoordinateConverter(self.location.RTK.latitude, self.location.RTK.longitude)
|
122
101
|
self.mowing_state = RapidState().from_raw(rapid_state.rapid_state_data)
|
123
102
|
self.location.position_type = self.mowing_state.pos_type
|
124
|
-
self.location.orientation = self.mowing_state.toward / 10000
|
103
|
+
self.location.orientation = int(self.mowing_state.toward / 10000)
|
125
104
|
self.location.device = coordinate_converter.enu_to_lla(
|
126
105
|
parse_double(self.mowing_state.pos_y, 4.0), parse_double(self.mowing_state.pos_x, 4.0)
|
127
106
|
)
|
@@ -136,198 +115,22 @@ class MowingDevice(DataClassORJSONMixin):
|
|
136
115
|
def report_missing_data(self) -> None:
|
137
116
|
"""Report missing data so we can refetch it."""
|
138
117
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
@property
|
160
|
-
def mul(self):
|
161
|
-
"""Will return a wrapped betterproto of mul."""
|
162
|
-
return MulData(mul=self.device.mul)
|
163
|
-
|
164
|
-
@property
|
165
|
-
def ota(self):
|
166
|
-
"""Will return a wrapped betterproto of ota."""
|
167
|
-
return OtaData(ota=self.device.ota)
|
168
|
-
|
169
|
-
@property
|
170
|
-
def pept(self):
|
171
|
-
"""Will return a wrapped betterproto of pept."""
|
172
|
-
return PeptData(pept=self.device.pept)
|
173
|
-
|
174
|
-
|
175
|
-
@dataclass
|
176
|
-
class DevNetData(DataClassORJSONMixin):
|
177
|
-
"""Wrapping class around LubaMsg to return a dataclass from the raw dict."""
|
178
|
-
|
179
|
-
net: dict
|
180
|
-
|
181
|
-
def __init__(self, net: DevNet) -> None:
|
182
|
-
if isinstance(net, dict):
|
183
|
-
self.net = net
|
184
|
-
else:
|
185
|
-
self.net = net.to_dict()
|
186
|
-
|
187
|
-
def __getattr__(self, item):
|
188
|
-
"""Intercept call to get net in dict and return a betterproto dataclass."""
|
189
|
-
if self.net.get(item) is None:
|
190
|
-
return DevNet().__getattribute__(item)
|
191
|
-
|
192
|
-
if not isinstance(self.net.get(item), dict):
|
193
|
-
return self.net.get(item)
|
194
|
-
|
195
|
-
return DevNet().__getattribute__(item).from_dict(value=self.net.get(item))
|
196
|
-
|
197
|
-
|
198
|
-
@dataclass
|
199
|
-
class SysData(DataClassORJSONMixin):
|
200
|
-
"""Wrapping class around LubaMsg to return a dataclass from the raw dict."""
|
201
|
-
|
202
|
-
sys: dict
|
203
|
-
|
204
|
-
def __init__(self, sys: MctlSys) -> None:
|
205
|
-
if isinstance(sys, dict):
|
206
|
-
self.sys = sys
|
207
|
-
else:
|
208
|
-
self.sys = sys.to_dict()
|
209
|
-
|
210
|
-
def __getattr__(self, item: str):
|
211
|
-
"""Intercept call to get sys in dict and return a betterproto dataclass."""
|
212
|
-
if self.sys.get(item) is None:
|
213
|
-
return MctlSys().__getattribute__(item)
|
214
|
-
|
215
|
-
if not isinstance(self.sys.get(item), dict):
|
216
|
-
return self.sys.get(item)
|
217
|
-
|
218
|
-
return MctlSys().__getattribute__(item).from_dict(value=self.sys.get(item))
|
219
|
-
|
220
|
-
|
221
|
-
@dataclass
|
222
|
-
class NavData(DataClassORJSONMixin):
|
223
|
-
"""Wrapping class around LubaMsg to return a dataclass from the raw dict."""
|
224
|
-
|
225
|
-
nav: dict
|
226
|
-
|
227
|
-
def __init__(self, nav: MctlNav) -> None:
|
228
|
-
if isinstance(nav, dict):
|
229
|
-
self.nav = nav
|
230
|
-
else:
|
231
|
-
self.nav = nav.to_dict()
|
232
|
-
|
233
|
-
def __getattr__(self, item: str):
|
234
|
-
"""Intercept call to get nav in dict and return a betterproto dataclass."""
|
235
|
-
if self.nav.get(item) is None:
|
236
|
-
return MctlNav().__getattribute__(item)
|
237
|
-
|
238
|
-
if not isinstance(self.nav.get(item), dict):
|
239
|
-
return self.nav.get(item)
|
240
|
-
|
241
|
-
return MctlNav().__getattribute__(item).from_dict(value=self.nav.get(item))
|
242
|
-
|
243
|
-
|
244
|
-
@dataclass
|
245
|
-
class DriverData(DataClassORJSONMixin):
|
246
|
-
"""Wrapping class around LubaMsg to return a dataclass from the raw dict."""
|
247
|
-
|
248
|
-
driver: dict
|
249
|
-
|
250
|
-
def __init__(self, driver: MctlDriver) -> None:
|
251
|
-
if isinstance(driver, dict):
|
252
|
-
self.driver = driver
|
253
|
-
else:
|
254
|
-
self.driver = driver.to_dict()
|
255
|
-
|
256
|
-
def __getattr__(self, item: str):
|
257
|
-
"""Intercept call to get driver in dict and return a betterproto dataclass."""
|
258
|
-
if self.driver.get(item) is None:
|
259
|
-
return MctlDriver().__getattribute__(item)
|
260
|
-
|
261
|
-
if not isinstance(self.driver.get(item), dict):
|
262
|
-
return self.driver.get(item)
|
263
|
-
|
264
|
-
return MctlDriver().__getattribute__(item).from_dict(value=self.driver.get(item))
|
265
|
-
|
266
|
-
|
267
|
-
@dataclass
|
268
|
-
class MulData(DataClassORJSONMixin):
|
269
|
-
"""Wrapping class around LubaMsg to return a dataclass from the raw dict."""
|
270
|
-
|
271
|
-
mul: dict
|
272
|
-
|
273
|
-
def __init__(self, mul: SocMul) -> None:
|
274
|
-
if isinstance(mul, dict):
|
275
|
-
self.mul = mul
|
276
|
-
else:
|
277
|
-
self.mul = mul.to_dict()
|
278
|
-
|
279
|
-
def __getattr__(self, item: str):
|
280
|
-
"""Intercept call to get mul in dict and return a betterproto dataclass."""
|
281
|
-
if self.mul.get(item) is None:
|
282
|
-
return SocMul().__getattribute__(item)
|
283
|
-
|
284
|
-
if not isinstance(self.mul.get(item), dict):
|
285
|
-
return self.mul.get(item)
|
286
|
-
|
287
|
-
return SocMul().__getattribute__(item).from_dict(value=self.mul.get(item))
|
288
|
-
|
289
|
-
|
290
|
-
@dataclass
|
291
|
-
class OtaData(DataClassORJSONMixin):
|
292
|
-
"""Wrapping class around LubaMsg to return a dataclass from the raw dict."""
|
293
|
-
|
294
|
-
ota: dict
|
295
|
-
|
296
|
-
def __init__(self, ota: MctlOta) -> None:
|
297
|
-
if isinstance(ota, dict):
|
298
|
-
self.ota = ota
|
299
|
-
else:
|
300
|
-
self.ota = ota.to_dict()
|
301
|
-
|
302
|
-
def __getattr__(self, item: str):
|
303
|
-
"""Intercept call to get ota in dict and return a betterproto dataclass."""
|
304
|
-
if self.ota.get(item) is None:
|
305
|
-
return MctlOta().__getattribute__(item)
|
306
|
-
|
307
|
-
if not isinstance(self.ota.get(item), dict):
|
308
|
-
return self.ota.get(item)
|
309
|
-
|
310
|
-
return MctlOta().__getattribute__(item).from_dict(value=self.ota.get(item))
|
311
|
-
|
312
|
-
|
313
|
-
@dataclass
|
314
|
-
class PeptData(DataClassORJSONMixin):
|
315
|
-
"""Wrapping class around LubaMsg to return a dataclass from the raw dict."""
|
316
|
-
|
317
|
-
pept: dict
|
318
|
-
|
319
|
-
def __init__(self, pept: MctlPept) -> None:
|
320
|
-
if isinstance(pept, dict):
|
321
|
-
self.pept = pept
|
322
|
-
else:
|
323
|
-
self.pept = pept.to_dict()
|
324
|
-
|
325
|
-
def __getattr__(self, item: str):
|
326
|
-
"""Intercept call to get pept in dict and return a betterproto dataclass."""
|
327
|
-
if self.pept.get(item) is None:
|
328
|
-
return MctlPept().__getattribute__(item)
|
329
|
-
|
330
|
-
if not isinstance(self.pept.get(item), dict):
|
331
|
-
return self.pept.get(item)
|
332
|
-
|
333
|
-
return MctlPept().__getattribute__(item).from_dict(value=self.pept.get(item))
|
118
|
+
def update_device_firmwares(self, fw_info: DeviceFwInfo) -> None:
|
119
|
+
"""Sets firmware versions on all parts of the robot or RTK."""
|
120
|
+
for mod in fw_info.mod:
|
121
|
+
match mod.type:
|
122
|
+
case 1:
|
123
|
+
self.device_firmwares.main_controller = mod.version
|
124
|
+
case 3:
|
125
|
+
self.device_firmwares.left_motor_driver = mod.version
|
126
|
+
case 4:
|
127
|
+
self.device_firmwares.right_motor_driver = mod.version
|
128
|
+
case 5:
|
129
|
+
self.device_firmwares.rtk_rover_station = mod.version
|
130
|
+
case 101:
|
131
|
+
# RTK main board
|
132
|
+
self.device_firmwares.main_controller = mod.version
|
133
|
+
case 102:
|
134
|
+
self.device_firmwares.rtk_version = mod.version
|
135
|
+
case 103:
|
136
|
+
self.device_firmwares.lora_version = mod.version
|
@@ -5,16 +5,6 @@ from mashumaro.mixins.orjson import DataClassORJSONMixin
|
|
5
5
|
from pymammotion.utility.device_type import DeviceType
|
6
6
|
|
7
7
|
|
8
|
-
@dataclass
|
9
|
-
class DeviceLimits(DataClassORJSONMixin):
|
10
|
-
blade_height_min: int = 30
|
11
|
-
blade_height_max: int = 100
|
12
|
-
working_speed_min: float = 0.2
|
13
|
-
working_speed_max: float = 1.2
|
14
|
-
working_path_min: int = 15
|
15
|
-
working_path_max: int = 35
|
16
|
-
|
17
|
-
|
18
8
|
@dataclass
|
19
9
|
class OperationSettings(DataClassORJSONMixin):
|
20
10
|
"""Operation settings for a device."""
|
@@ -23,3 +23,16 @@ class MowerInfo(DataClassORJSONMixin):
|
|
23
23
|
swversion: str = ""
|
24
24
|
product_key: str = ""
|
25
25
|
model_id: str = ""
|
26
|
+
sub_model_id: str = ""
|
27
|
+
|
28
|
+
|
29
|
+
@dataclass
|
30
|
+
class DeviceFirmwares(DataClassORJSONMixin):
|
31
|
+
device_version: str = ""
|
32
|
+
left_motor_driver: str = ""
|
33
|
+
lora_version: str = ""
|
34
|
+
main_controller: str = ""
|
35
|
+
model_name: str = ""
|
36
|
+
right_motor_driver: str = ""
|
37
|
+
rtk_rover_station: str = ""
|
38
|
+
rtk_version: str = ""
|