pymammotion 0.4.56__tar.gz → 0.4.57__tar.gz
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.
Potentially problematic release.
This version of pymammotion might be problematic. Click here for more details.
- {pymammotion-0.4.56 → pymammotion-0.4.57}/PKG-INFO +1 -1
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/aliyun/cloud_gateway.py +13 -3
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/data/model/device.py +2 -1
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/data/mqtt/properties.py +56 -44
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/data/state_manager.py +16 -3
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/http/http.py +43 -8
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/http/model/http.py +46 -1
- pymammotion-0.4.57/pymammotion/http/model/response_factory.py +39 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/mammotion/commands/abstract_message.py +1 -4
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/mammotion/devices/mammotion.py +30 -9
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/mammotion/devices/mammotion_bluetooth.py +3 -3
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/mammotion/devices/mammotion_cloud.py +7 -2
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/proto/__init__.py +2 -6
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/proto/basestation.proto +8 -0
- pymammotion-0.4.57/pymammotion/proto/basestation_pb2.py +35 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/proto/basestation_pb2.pyi +16 -2
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/proto/dev_net.proto +2 -0
- pymammotion-0.4.57/pymammotion/proto/dev_net_pb2.py +111 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/proto/dev_net_pb2.pyi +8 -4
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/proto/luba_mul.proto +2 -2
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/proto/luba_mul_pb2.py +15 -15
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/proto/luba_mul_pb2.pyi +1 -1
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/proto/mctrl_driver.proto +23 -4
- pymammotion-0.4.57/pymammotion/proto/mctrl_driver_pb2.py +57 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/proto/mctrl_driver_pb2.pyi +38 -10
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/proto/mctrl_nav.proto +18 -1
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/proto/mctrl_nav_pb2.py +5 -3
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/proto/mctrl_nav_pb2.pyi +34 -2
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/proto/mctrl_pept.proto +6 -1
- pymammotion-0.4.57/pymammotion/proto/mctrl_pept_pb2.py +33 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/proto/mctrl_pept_pb2.pyi +14 -6
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/proto/mctrl_sys.proto +82 -9
- pymammotion-0.4.57/pymammotion/proto/mctrl_sys_pb2.py +206 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/proto/mctrl_sys_pb2.pyi +151 -34
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/utility/device_type.py +3 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pyproject.toml +3 -3
- pymammotion-0.4.56/pymammotion/proto/basestation_pb2.py +0 -33
- pymammotion-0.4.56/pymammotion/proto/dev_net_pb2.py +0 -111
- pymammotion-0.4.56/pymammotion/proto/mctrl_driver_pb2.py +0 -51
- pymammotion-0.4.56/pymammotion/proto/mctrl_pept_pb2.py +0 -31
- pymammotion-0.4.56/pymammotion/proto/mctrl_sys_pb2.py +0 -190
- {pymammotion-0.4.56 → pymammotion-0.4.57}/LICENSE +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/README.md +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/__init__.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/aliyun/__init__.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/aliyun/client.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/aliyun/model/aep_response.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/aliyun/model/connect_response.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/aliyun/model/dev_by_account_response.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/aliyun/model/login_by_oauth_response.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/aliyun/model/regions_response.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/aliyun/model/session_by_authcode_response.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/aliyun/regions.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/aliyun/tea/core.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/aliyun/tmp_constant.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/bluetooth/__init__.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/bluetooth/ble.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/bluetooth/ble_message.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/bluetooth/const.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/bluetooth/data/__init__.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/bluetooth/data/convert.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/bluetooth/data/framectrldata.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/bluetooth/data/notifydata.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/bluetooth/model/__init__.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/bluetooth/model/atomic_integer.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/const.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/data/__init__.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/data/model/__init__.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/data/model/account.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/data/model/device_config.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/data/model/device_info.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/data/model/device_limits.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/data/model/enums.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/data/model/excute_boarder_params.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/data/model/execute_boarder.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/data/model/generate_route_information.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/data/model/hash_list.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/data/model/location.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/data/model/mowing_modes.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/data/model/rapid_state.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/data/model/raw_data.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/data/model/region_data.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/data/model/report_info.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/data/model/work.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/data/mqtt/__init__.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/data/mqtt/event.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/data/mqtt/status.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/event/__init__.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/event/event.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/http/__init__.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/http/_init_.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/http/encryption.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/http/model/__init__.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/http/model/camera_stream.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/mammotion/__init__.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/mammotion/commands/__init__.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/mammotion/commands/mammotion_command.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/mammotion/commands/messages/__init__.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/mammotion/commands/messages/driver.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/mammotion/commands/messages/media.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/mammotion/commands/messages/navigation.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/mammotion/commands/messages/network.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/mammotion/commands/messages/ota.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/mammotion/commands/messages/system.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/mammotion/commands/messages/video.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/mammotion/control/__init__.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/mammotion/control/joystick.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/mammotion/devices/__init__.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/mammotion/devices/base.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/mqtt/__init__.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/mqtt/linkkit/__init__.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/mqtt/linkkit/h2client.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/mqtt/linkkit/linkkit.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/mqtt/mammotion_future.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/mqtt/mammotion_mqtt.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/proto/common.proto +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/proto/common_pb2.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/proto/common_pb2.pyi +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/proto/luba_msg.proto +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/proto/luba_msg_pb2.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/proto/luba_msg_pb2.pyi +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/proto/mctrl_ota.proto +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/proto/mctrl_ota_pb2.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/proto/mctrl_ota_pb2.pyi +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/py.typed +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/utility/constant/__init__.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/utility/constant/device_constant.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/utility/conversions.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/utility/datatype_converter.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/utility/device_config.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/utility/map.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/utility/movement.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/utility/mur_mur_hash.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/utility/periodic.py +0 -0
- {pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/utility/rocker_util.py +0 -0
|
@@ -15,8 +15,8 @@ from aiohttp import ClientSession, ConnectionTimeoutError
|
|
|
15
15
|
from alibabacloud_iot_api_gateway.models import CommonParams, Config, IoTApiRequest
|
|
16
16
|
from alibabacloud_tea_util.client import Client as UtilClient
|
|
17
17
|
from alibabacloud_tea_util.models import RuntimeOptions
|
|
18
|
-
from Tea.exceptions import UnretryableException
|
|
19
18
|
from orjson.orjson import JSONDecodeError
|
|
19
|
+
from Tea.exceptions import UnretryableException
|
|
20
20
|
|
|
21
21
|
from pymammotion.aliyun.client import Client
|
|
22
22
|
from pymammotion.aliyun.model.aep_response import AepResponse
|
|
@@ -65,6 +65,14 @@ class DeviceOfflineException(Exception):
|
|
|
65
65
|
self.iot_id = args[1]
|
|
66
66
|
|
|
67
67
|
|
|
68
|
+
class FailedRequestException(Exception):
|
|
69
|
+
"""Raise exception when request response is bad."""
|
|
70
|
+
|
|
71
|
+
def __init__(self, *args: object) -> None:
|
|
72
|
+
super().__init__(args)
|
|
73
|
+
self.iot_id = args[0]
|
|
74
|
+
|
|
75
|
+
|
|
68
76
|
class NoConnectionException(UnretryableException):
|
|
69
77
|
"""Raise exception when device is unreachable."""
|
|
70
78
|
|
|
@@ -145,7 +153,7 @@ class CloudIOTGateway:
|
|
|
145
153
|
return json.loads(response_body_str) if response_body_str is not None else {}
|
|
146
154
|
except JSONDecodeError:
|
|
147
155
|
logger.error("Couldn't decode message %s", response_body_str)
|
|
148
|
-
return {}
|
|
156
|
+
return {'code': 22000}
|
|
149
157
|
|
|
150
158
|
def sign(self, data):
|
|
151
159
|
"""Generate signature for the given data."""
|
|
@@ -739,7 +747,6 @@ class CloudIOTGateway:
|
|
|
739
747
|
logger.debug(response.body)
|
|
740
748
|
logger.debug(iot_id)
|
|
741
749
|
|
|
742
|
-
|
|
743
750
|
response_body_str = response.body.decode("utf-8")
|
|
744
751
|
response_body_dict = self.parse_json_response(response_body_str)
|
|
745
752
|
|
|
@@ -749,6 +756,9 @@ class CloudIOTGateway:
|
|
|
749
756
|
str(response_body_dict.get("code")),
|
|
750
757
|
str(response_body_dict.get("message")),
|
|
751
758
|
)
|
|
759
|
+
if response_body_dict.get("code") == 22000:
|
|
760
|
+
logger.error(response)
|
|
761
|
+
raise FailedRequestException(iot_id)
|
|
752
762
|
if response_body_dict.get("code") == 20056:
|
|
753
763
|
logger.debug("Gateway timeout.")
|
|
754
764
|
raise GatewayTimeoutException(response_body_dict.get("code"), iot_id)
|
|
@@ -12,7 +12,7 @@ from pymammotion.data.model.report_info import ReportData
|
|
|
12
12
|
from pymammotion.data.model.work import CurrentTaskSettings
|
|
13
13
|
from pymammotion.data.mqtt.properties import ThingPropertiesMessage
|
|
14
14
|
from pymammotion.data.mqtt.status import ThingStatusMessage
|
|
15
|
-
from pymammotion.http.model.http import ErrorInfo
|
|
15
|
+
from pymammotion.http.model.http import CheckDeviceVersion, ErrorInfo
|
|
16
16
|
from pymammotion.proto import DeviceFwInfo, MowToAppInfoT, ReportInfoData, SystemRapidStateTunnelMsg, SystemUpdateBufMsg
|
|
17
17
|
from pymammotion.utility.constant import WorkMode
|
|
18
18
|
from pymammotion.utility.conversions import parse_double
|
|
@@ -26,6 +26,7 @@ class MowingDevice(DataClassORJSONMixin):
|
|
|
26
26
|
name: str = ""
|
|
27
27
|
online: bool = True
|
|
28
28
|
enabled: bool = True
|
|
29
|
+
update_check: CheckDeviceVersion = field(default_factory=CheckDeviceVersion)
|
|
29
30
|
mower_state: MowerInfo = field(default_factory=MowerInfo)
|
|
30
31
|
mqtt_properties: ThingPropertiesMessage | None = None
|
|
31
32
|
status_properties: ThingStatusMessage | None = None
|
|
@@ -15,85 +15,95 @@ class Item(DataClassDictMixin, Generic[DataT]):
|
|
|
15
15
|
|
|
16
16
|
@dataclass
|
|
17
17
|
class BatteryPercentageItems(DataClassORJSONMixin):
|
|
18
|
-
batteryPercentage:
|
|
18
|
+
batteryPercentage: int
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
@dataclass
|
|
22
22
|
class BMSHardwareVersionItems(DataClassORJSONMixin):
|
|
23
|
-
bmsHardwareVersion:
|
|
23
|
+
bmsHardwareVersion: str
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
@dataclass
|
|
27
27
|
class CoordinateItems(DataClassORJSONMixin):
|
|
28
|
-
coordinate:
|
|
28
|
+
coordinate: str # '{"lon":0.303903,"lat":1.051868}'
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
@dataclass
|
|
32
32
|
class DeviceStateItems(DataClassORJSONMixin):
|
|
33
|
-
deviceState:
|
|
33
|
+
deviceState: int
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
@dataclass
|
|
37
37
|
class DeviceVersionItems(DataClassORJSONMixin):
|
|
38
|
-
deviceVersion:
|
|
38
|
+
deviceVersion: str
|
|
39
39
|
|
|
40
40
|
|
|
41
41
|
@dataclass
|
|
42
42
|
class DeviceVersionInfoItems(DataClassORJSONMixin):
|
|
43
|
-
deviceVersionInfo:
|
|
43
|
+
deviceVersionInfo: str
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
@dataclass
|
|
47
47
|
class ESP32VersionItems(DataClassORJSONMixin):
|
|
48
|
-
esp32Version:
|
|
48
|
+
esp32Version: str
|
|
49
49
|
|
|
50
50
|
|
|
51
51
|
@dataclass
|
|
52
52
|
class LeftMotorBootVersionItems(DataClassORJSONMixin):
|
|
53
|
-
leftMotorBootVersion:
|
|
53
|
+
leftMotorBootVersion: str
|
|
54
54
|
|
|
55
55
|
|
|
56
56
|
@dataclass
|
|
57
57
|
class LeftMotorVersionItems(DataClassORJSONMixin):
|
|
58
|
-
leftMotorVersion:
|
|
58
|
+
leftMotorVersion: str
|
|
59
59
|
|
|
60
60
|
|
|
61
61
|
@dataclass
|
|
62
62
|
class MCBootVersionItems(DataClassORJSONMixin):
|
|
63
|
-
mcBootVersion:
|
|
63
|
+
mcBootVersion: str
|
|
64
64
|
|
|
65
65
|
|
|
66
66
|
@dataclass
|
|
67
67
|
class NetworkInfoItems(DataClassORJSONMixin):
|
|
68
|
-
networkInfo:
|
|
68
|
+
networkInfo: str
|
|
69
69
|
|
|
70
70
|
|
|
71
71
|
@dataclass
|
|
72
72
|
class RightMotorBootVersionItems(DataClassORJSONMixin):
|
|
73
|
-
rightMotorBootVersion:
|
|
73
|
+
rightMotorBootVersion: str
|
|
74
74
|
|
|
75
75
|
|
|
76
76
|
@dataclass
|
|
77
77
|
class RightMotorVersionItems(DataClassORJSONMixin):
|
|
78
|
-
rightMotorVersion:
|
|
78
|
+
rightMotorVersion: str
|
|
79
79
|
|
|
80
80
|
|
|
81
81
|
@dataclass
|
|
82
82
|
class RTKVersionItems(DataClassORJSONMixin):
|
|
83
|
-
rtkVersion:
|
|
83
|
+
rtkVersion: str
|
|
84
84
|
|
|
85
85
|
|
|
86
86
|
@dataclass
|
|
87
87
|
class StationRTKVersionItems(DataClassORJSONMixin):
|
|
88
|
-
stationRtkVersion:
|
|
88
|
+
stationRtkVersion: str
|
|
89
89
|
|
|
90
90
|
|
|
91
91
|
@dataclass
|
|
92
92
|
class STM32H7VersionItems(DataClassORJSONMixin):
|
|
93
|
-
stm32H7Version:
|
|
93
|
+
stm32H7Version: str
|
|
94
94
|
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
@dataclass
|
|
97
|
+
class OTAProgressItems(DataClassORJSONMixin):
|
|
98
|
+
result: int
|
|
99
|
+
otaId: str
|
|
100
|
+
progress: int
|
|
101
|
+
message: str
|
|
102
|
+
version: str
|
|
103
|
+
properties: str
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
ItemTypes = Union[
|
|
97
107
|
BatteryPercentageItems,
|
|
98
108
|
BMSHardwareVersionItems,
|
|
99
109
|
CoordinateItems,
|
|
@@ -110,43 +120,45 @@ Items = Union[
|
|
|
110
120
|
RTKVersionItems,
|
|
111
121
|
StationRTKVersionItems,
|
|
112
122
|
STM32H7VersionItems,
|
|
123
|
+
OTAProgressItems,
|
|
113
124
|
]
|
|
114
125
|
|
|
115
126
|
|
|
116
127
|
@dataclass
|
|
117
128
|
class Item:
|
|
118
129
|
time: int
|
|
119
|
-
value: int | float | str | dict[str, Any] # Depending on the type of value
|
|
130
|
+
value: int | float | str | dict[str, Any] | ItemTypes # Depending on the type of value
|
|
120
131
|
|
|
121
132
|
|
|
122
133
|
@dataclass
|
|
123
134
|
class Items:
|
|
124
|
-
iotState: Item
|
|
125
|
-
extMod: Item
|
|
126
|
-
deviceVersionInfo: Item
|
|
127
|
-
leftMotorBootVersion: Item
|
|
128
|
-
knifeHeight: Item
|
|
129
|
-
rtMrMod: Item
|
|
130
|
-
iotMsgHz: Item
|
|
131
|
-
iotMsgTotal: Item
|
|
132
|
-
loraRawConfig: Item
|
|
133
|
-
loraGeneralConfig: Item
|
|
134
|
-
leftMotorVersion: Item
|
|
135
|
-
intMod: Item
|
|
136
|
-
coordinate: Item
|
|
137
|
-
bmsVersion: Item
|
|
138
|
-
rightMotorVersion: Item
|
|
139
|
-
stm32H7Version: Item
|
|
140
|
-
rightMotorBootVersion: Item
|
|
141
|
-
deviceVersion: Item
|
|
142
|
-
rtkVersion: Item
|
|
143
|
-
ltMrMod: Item
|
|
144
|
-
networkInfo: Item
|
|
145
|
-
bmsHardwareVersion: Item
|
|
146
|
-
batteryPercentage: Item
|
|
147
|
-
deviceState: Item
|
|
148
|
-
deviceOtherInfo: Item
|
|
149
|
-
mcBootVersion: Item
|
|
135
|
+
iotState: Item | None = None
|
|
136
|
+
extMod: Item | None = None
|
|
137
|
+
deviceVersionInfo: Item | None = None
|
|
138
|
+
leftMotorBootVersion: Item | None = None
|
|
139
|
+
knifeHeight: Item | None = None
|
|
140
|
+
rtMrMod: Item | None = None
|
|
141
|
+
iotMsgHz: Item | None = None
|
|
142
|
+
iotMsgTotal: Item | None = None
|
|
143
|
+
loraRawConfig: Item | None = None
|
|
144
|
+
loraGeneralConfig: Item | None = None
|
|
145
|
+
leftMotorVersion: Item | None = None
|
|
146
|
+
intMod: Item | None = None
|
|
147
|
+
coordinate: Item | None = None
|
|
148
|
+
bmsVersion: Item | None = None
|
|
149
|
+
rightMotorVersion: Item | None = None
|
|
150
|
+
stm32H7Version: Item | None = None
|
|
151
|
+
rightMotorBootVersion: Item | None = None
|
|
152
|
+
deviceVersion: Item | None = None
|
|
153
|
+
rtkVersion: Item | None = None
|
|
154
|
+
ltMrMod: Item | None = None
|
|
155
|
+
networkInfo: Item | None = None
|
|
156
|
+
bmsHardwareVersion: Item | None = None
|
|
157
|
+
batteryPercentage: Item | None = None
|
|
158
|
+
deviceState: Item | None = None
|
|
159
|
+
deviceOtherInfo: Item | None = None
|
|
160
|
+
mcBootVersion: Item | None = None
|
|
161
|
+
otaProgress: Item | None = None
|
|
150
162
|
|
|
151
163
|
|
|
152
164
|
@dataclass
|
|
@@ -49,8 +49,7 @@ class StateManager:
|
|
|
49
49
|
) = None
|
|
50
50
|
self.cloud_get_plan_callback: Callable[[NavPlanJobSet], Awaitable[None]] | None = None
|
|
51
51
|
self.cloud_on_notification_callback: Callable[[tuple[str, Any | None]], Awaitable[None]] | None = None
|
|
52
|
-
|
|
53
|
-
self.cloud_queue_command_callback: Callable[[str, dict[str, Any]], Awaitable[bytes]] | None = None
|
|
52
|
+
self.cloud_queue_command_callback: Callable[[str, dict[str, Any]], Awaitable[None]] | None = None
|
|
54
53
|
|
|
55
54
|
self.ble_gethash_ack_callback: Callable[[NavGetHashListAck], Awaitable[None]] | None = None
|
|
56
55
|
self.ble_get_commondata_ack_callback: Callable[[NavGetCommDataAck | SvgMessageAckT], Awaitable[None]] | None = (
|
|
@@ -58,8 +57,10 @@ class StateManager:
|
|
|
58
57
|
)
|
|
59
58
|
self.ble_get_plan_callback: Callable[[NavPlanJobSet], Awaitable[None]] | None = None
|
|
60
59
|
self.ble_on_notification_callback: Callable[[tuple[str, Any | None]], Awaitable[None]] | None = None
|
|
60
|
+
self.ble_queue_command_callback: Callable[[str, dict[str, Any]], Awaitable[None]] | None = None
|
|
61
61
|
|
|
62
|
-
self.
|
|
62
|
+
self.properties_callback: Callable[[ThingPropertiesMessage], Awaitable[None]] | None = None
|
|
63
|
+
self.status_callback: Callable[[ThingStatusMessage], Awaitable[None]] | None = None
|
|
63
64
|
|
|
64
65
|
def get_device(self) -> MowingDevice:
|
|
65
66
|
"""Get device."""
|
|
@@ -72,6 +73,7 @@ class StateManager:
|
|
|
72
73
|
def properties(self, thing_properties: ThingPropertiesMessage) -> None:
|
|
73
74
|
# TODO update device based off thing properties
|
|
74
75
|
self._device.mqtt_properties = thing_properties
|
|
76
|
+
self.on_properties_callback(thing_properties)
|
|
75
77
|
|
|
76
78
|
def status(self, thing_status: ThingStatusMessage) -> None:
|
|
77
79
|
if not self._device.online:
|
|
@@ -79,6 +81,7 @@ class StateManager:
|
|
|
79
81
|
self._device.status_properties = thing_status
|
|
80
82
|
if self._device.mower_state.product_key == "":
|
|
81
83
|
self._device.mower_state.product_key = thing_status.params.productKey
|
|
84
|
+
self.on_status_callback(thing_status)
|
|
82
85
|
|
|
83
86
|
@property
|
|
84
87
|
def online(self) -> bool:
|
|
@@ -100,6 +103,16 @@ class StateManager:
|
|
|
100
103
|
elif self.ble_on_notification_callback:
|
|
101
104
|
await self.ble_on_notification_callback(res)
|
|
102
105
|
|
|
106
|
+
async def on_properties_callback(self, thing_properties: ThingPropertiesMessage) -> None:
|
|
107
|
+
"""Check if we have a callback for properties."""
|
|
108
|
+
if self.properties_callback:
|
|
109
|
+
await self.properties_callback(thing_properties)
|
|
110
|
+
|
|
111
|
+
async def on_status_callback(self, thing_status: ThingStatusMessage) -> None:
|
|
112
|
+
"""Check if we have a callback for status."""
|
|
113
|
+
if self.status_callback:
|
|
114
|
+
await self.status_callback(thing_status)
|
|
115
|
+
|
|
103
116
|
async def get_commondata_ack_callback(self, comm_data: NavGetCommDataAck | SvgMessageAckT) -> None:
|
|
104
117
|
if self.cloud_get_commondata_ack_callback:
|
|
105
118
|
await self.cloud_get_commondata_ack_callback(comm_data)
|
|
@@ -6,7 +6,8 @@ from aiohttp import ClientSession
|
|
|
6
6
|
from pymammotion.const import MAMMOTION_API_DOMAIN, MAMMOTION_CLIENT_ID, MAMMOTION_CLIENT_SECRET, MAMMOTION_DOMAIN
|
|
7
7
|
from pymammotion.http.encryption import EncryptionUtils
|
|
8
8
|
from pymammotion.http.model.camera_stream import StreamSubscriptionResponse, VideoResourceResponse
|
|
9
|
-
from pymammotion.http.model.http import ErrorInfo, LoginResponseData, Response
|
|
9
|
+
from pymammotion.http.model.http import CheckDeviceVersion, ErrorInfo, LoginResponseData, Response
|
|
10
|
+
from pymammotion.http.model.response_factory import response_factory
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
class MammotionHTTP:
|
|
@@ -17,7 +18,7 @@ class MammotionHTTP:
|
|
|
17
18
|
self._password = None
|
|
18
19
|
self.response: Response | None = None
|
|
19
20
|
self.login_info: LoginResponseData | None = None
|
|
20
|
-
self._headers = {"User-Agent": "okhttp/
|
|
21
|
+
self._headers = {"User-Agent": "okhttp/4.9.3", "App-Version": "google Pixel 2 XL taimen-Android 11,1.11.332"}
|
|
21
22
|
self.encryption_utils = EncryptionUtils()
|
|
22
23
|
|
|
23
24
|
@staticmethod
|
|
@@ -100,7 +101,7 @@ class MammotionHTTP:
|
|
|
100
101
|
headers={
|
|
101
102
|
"Authorization": f"Bearer {self.login_info.access_token}",
|
|
102
103
|
"Content-Type": "application/json",
|
|
103
|
-
"User-Agent": "okhttp/
|
|
104
|
+
"User-Agent": "okhttp/4.9.3",
|
|
104
105
|
},
|
|
105
106
|
) as resp:
|
|
106
107
|
data = await resp.json()
|
|
@@ -133,7 +134,7 @@ class MammotionHTTP:
|
|
|
133
134
|
headers={
|
|
134
135
|
"Authorization": f"Bearer {self.login_info.access_token}",
|
|
135
136
|
"Content-Type": "application/json",
|
|
136
|
-
"User-Agent": "okhttp/
|
|
137
|
+
"User-Agent": "okhttp/4.9.3",
|
|
137
138
|
},
|
|
138
139
|
) as resp:
|
|
139
140
|
data = await resp.json()
|
|
@@ -153,7 +154,7 @@ class MammotionHTTP:
|
|
|
153
154
|
headers={
|
|
154
155
|
"Authorization": f"Bearer {self.login_info.access_token}",
|
|
155
156
|
"Content-Type": "application/json",
|
|
156
|
-
"User-Agent": "okhttp/
|
|
157
|
+
"User-Agent": "okhttp/4.9.3",
|
|
157
158
|
},
|
|
158
159
|
) as resp:
|
|
159
160
|
data = await resp.json()
|
|
@@ -165,6 +166,40 @@ class MammotionHTTP:
|
|
|
165
166
|
response.data = VideoResourceResponse.from_dict(data.get("data", {}))
|
|
166
167
|
return response
|
|
167
168
|
|
|
169
|
+
async def get_device_ota_firmware(self, iot_ids: list[str]) -> Response[list[CheckDeviceVersion]]:
|
|
170
|
+
"""Device firmware upgrade check."""
|
|
171
|
+
async with ClientSession(MAMMOTION_API_DOMAIN) as session:
|
|
172
|
+
async with session.post(
|
|
173
|
+
"/device-server/v1/devices/version/check",
|
|
174
|
+
json={"deviceIds": iot_ids},
|
|
175
|
+
headers={
|
|
176
|
+
"Authorization": f"Bearer {self.login_info.access_token}",
|
|
177
|
+
"Content-Type": "application/json",
|
|
178
|
+
"User-Agent": "okhttp/4.9.3",
|
|
179
|
+
},
|
|
180
|
+
) as resp:
|
|
181
|
+
data = await resp.json()
|
|
182
|
+
# TODO catch errors from mismatch like token expire etc
|
|
183
|
+
# Assuming the data format matches the expected structure
|
|
184
|
+
return response_factory(Response[list[CheckDeviceVersion]], data)
|
|
185
|
+
|
|
186
|
+
async def start_ota_upgrade(self, iot_id: str, version: str) -> Response[str]:
|
|
187
|
+
"""Device firmware upgrade."""
|
|
188
|
+
async with ClientSession(MAMMOTION_API_DOMAIN) as session:
|
|
189
|
+
async with session.post(
|
|
190
|
+
"/device-server/v1/ota/device/upgrade",
|
|
191
|
+
json={"deviceId": iot_id, "version": version},
|
|
192
|
+
headers={
|
|
193
|
+
"Authorization": f"Bearer {self.login_info.access_token}",
|
|
194
|
+
"Content-Type": "application/json",
|
|
195
|
+
"User-Agent": "okhttp/4.9.3",
|
|
196
|
+
},
|
|
197
|
+
) as resp:
|
|
198
|
+
data = await resp.json()
|
|
199
|
+
# TODO catch errors from mismatch like token expire etc
|
|
200
|
+
# Assuming the data format matches the expected structure
|
|
201
|
+
return response_factory(Response[str], data)
|
|
202
|
+
|
|
168
203
|
async def refresh_login(self, account: str, password: str | None = None) -> Response[LoginResponseData]:
|
|
169
204
|
if self._password is None and password is not None:
|
|
170
205
|
self._password = password
|
|
@@ -179,7 +214,7 @@ class MammotionHTTP:
|
|
|
179
214
|
async with session.post(
|
|
180
215
|
"/oauth/token",
|
|
181
216
|
headers={
|
|
182
|
-
"User-Agent": "okhttp/
|
|
217
|
+
"User-Agent": "okhttp/4.9.3",
|
|
183
218
|
"App-Version": "google Pixel 2 XL taimen-Android 11,1.11.332",
|
|
184
219
|
"Encrypt-Key": self.encryption_utils.encrypt_by_public_key(),
|
|
185
220
|
"Decrypt-Type": "3",
|
|
@@ -197,11 +232,11 @@ class MammotionHTTP:
|
|
|
197
232
|
print(resp.json())
|
|
198
233
|
return Response.from_dict({"code": resp.status, "msg": "Login failed"})
|
|
199
234
|
data = await resp.json()
|
|
200
|
-
login_response = Response[LoginResponseData]
|
|
235
|
+
login_response = response_factory(Response[LoginResponseData], data)
|
|
201
236
|
if login_response.data is None:
|
|
202
237
|
print(login_response)
|
|
203
238
|
return Response.from_dict({"code": resp.status, "msg": "Login failed"})
|
|
204
|
-
self.login_info =
|
|
239
|
+
self.login_info = login_response.data
|
|
205
240
|
self._headers["Authorization"] = (
|
|
206
241
|
f"Bearer {self.login_info.access_token}" if login_response.data else None
|
|
207
242
|
)
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
|
-
from typing import Generic, Literal, TypeVar
|
|
2
|
+
from typing import Annotated, Generic, Literal, TypeVar
|
|
3
3
|
|
|
4
4
|
from mashumaro import DataClassDictMixin
|
|
5
5
|
from mashumaro.config import BaseConfig
|
|
6
6
|
from mashumaro.mixins.orjson import DataClassORJSONMixin
|
|
7
|
+
from mashumaro.types import Alias
|
|
7
8
|
|
|
8
9
|
DataT = TypeVar("DataT")
|
|
9
10
|
|
|
@@ -103,3 +104,47 @@ class LoginResponseData(DataClassORJSONMixin):
|
|
|
103
104
|
|
|
104
105
|
class Config(BaseConfig):
|
|
105
106
|
omit_none = True
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@dataclass
|
|
110
|
+
class FirmwareVersions(DataClassORJSONMixin):
|
|
111
|
+
firmware_version: Annotated[str, Alias("firmwareVersion")] = ""
|
|
112
|
+
firmware_code: Annotated[str, Alias("firmwareCode")] = ""
|
|
113
|
+
firmware_latest_version: Annotated[str, Alias("firmwareLatestVersion")] = ""
|
|
114
|
+
firmware_type: Annotated[str, Alias("firmwareType")] = ""
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@dataclass
|
|
118
|
+
class ProductVersionInfo(DataClassORJSONMixin):
|
|
119
|
+
release_note: Annotated[str, Alias("releaseNote")] = ""
|
|
120
|
+
release_version: Annotated[str, Alias("releaseVersion")] = ""
|
|
121
|
+
data_location: str | None = None
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@dataclass
|
|
125
|
+
class CheckDeviceVersion(DataClassORJSONMixin):
|
|
126
|
+
cause_code: Annotated[int, Alias("causeCode")] = 0
|
|
127
|
+
product_version_info_vo: Annotated[ProductVersionInfo | None, Alias("productVersionInfoVo")] = None
|
|
128
|
+
progress: int | None = 0
|
|
129
|
+
upgradeable: bool = False
|
|
130
|
+
device_id: Annotated[str, Alias("deviceId")] = ""
|
|
131
|
+
device_name: Annotated[str | None, Alias("deviceName")] = ""
|
|
132
|
+
current_version: Annotated[str, Alias("currentVersion")] = ""
|
|
133
|
+
isupgrading: bool | None = False
|
|
134
|
+
cause_msg: Annotated[str, Alias("causeMsg")] = ""
|
|
135
|
+
|
|
136
|
+
def __eq__(self, other):
|
|
137
|
+
if not isinstance(other, CheckDeviceVersion):
|
|
138
|
+
return NotImplemented
|
|
139
|
+
|
|
140
|
+
if self.device_id != other.device_id or self.current_version != other.current_version:
|
|
141
|
+
return False
|
|
142
|
+
|
|
143
|
+
if self.product_version_info_vo and other.product_version_info_vo:
|
|
144
|
+
if self.product_version_info_vo.release_version != other.product_version_info_vo.release_version:
|
|
145
|
+
return False
|
|
146
|
+
return True
|
|
147
|
+
elif self.product_version_info_vo is None and other.product_version_info_vo is None:
|
|
148
|
+
return False
|
|
149
|
+
else:
|
|
150
|
+
return True
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from typing import TypeVar, Union, get_args, get_origin
|
|
2
|
+
|
|
3
|
+
from pymammotion.http.model.http import Response
|
|
4
|
+
|
|
5
|
+
T = TypeVar("T")
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def deserialize_data(value, target_type):
|
|
9
|
+
if value is None:
|
|
10
|
+
return None
|
|
11
|
+
|
|
12
|
+
origin = get_origin(target_type)
|
|
13
|
+
args = get_args(target_type)
|
|
14
|
+
|
|
15
|
+
if origin is list and args:
|
|
16
|
+
item_type = args[0]
|
|
17
|
+
return [deserialize_data(v, item_type) for v in value]
|
|
18
|
+
|
|
19
|
+
if origin is Union:
|
|
20
|
+
# Support Optional[T] = Union[T, None]
|
|
21
|
+
non_none_types = [t for t in args if t is not type(None)]
|
|
22
|
+
if len(non_none_types) == 1:
|
|
23
|
+
return deserialize_data(value, non_none_types[0])
|
|
24
|
+
|
|
25
|
+
if hasattr(target_type, "from_dict"):
|
|
26
|
+
return target_type.from_dict(value)
|
|
27
|
+
|
|
28
|
+
return value # fallback: unknown type, leave as-is
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def response_factory(response_cls: type[Response[T]], raw_dict: dict) -> Response[T]:
|
|
32
|
+
# Extract the type of the generic `data` field
|
|
33
|
+
data_type = get_args(response_cls)[0] if get_args(response_cls) else None
|
|
34
|
+
|
|
35
|
+
if data_type:
|
|
36
|
+
data_value = deserialize_data(raw_dict.get("data"), data_type)
|
|
37
|
+
return Response(code=raw_dict["code"], msg=raw_dict["msg"], data=data_value)
|
|
38
|
+
else:
|
|
39
|
+
return response_cls.from_dict(raw_dict)
|
{pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/mammotion/commands/abstract_message.py
RENAMED
|
@@ -18,9 +18,6 @@ class AbstractMessage:
|
|
|
18
18
|
|
|
19
19
|
def get_msg_device(self, msg_type: MsgCmdType, msg_device: MsgDevice) -> MsgDevice:
|
|
20
20
|
"""Changes the rcver name if it's not a luba1."""
|
|
21
|
-
if (
|
|
22
|
-
not DeviceType.is_luba1(self.get_device_name(), self.get_device_product_key())
|
|
23
|
-
and msg_type == MsgCmdType.NAV
|
|
24
|
-
):
|
|
21
|
+
if DeviceType.is_luba_pro(self.get_device_name(), self.get_device_product_key()) and msg_type == MsgCmdType.NAV:
|
|
25
22
|
return MsgDevice.DEV_NAVIGATION
|
|
26
23
|
return msg_device
|
|
@@ -32,7 +32,6 @@ class MammotionMixedDeviceManager:
|
|
|
32
32
|
name: str,
|
|
33
33
|
iot_id: str,
|
|
34
34
|
cloud_client: CloudIOTGateway,
|
|
35
|
-
mammotion_http: MammotionHTTP,
|
|
36
35
|
cloud_device: Device,
|
|
37
36
|
ble_device: BLEDevice | None = None,
|
|
38
37
|
mqtt: MammotionCloud | None = None,
|
|
@@ -48,16 +47,22 @@ class MammotionMixedDeviceManager:
|
|
|
48
47
|
self._device: Device = cloud_device
|
|
49
48
|
self.add_ble(ble_device)
|
|
50
49
|
self.add_cloud(mqtt)
|
|
51
|
-
self.mammotion_http = mammotion_http
|
|
50
|
+
self.mammotion_http = cloud_client.mammotion_http
|
|
52
51
|
self.preference = preference
|
|
53
52
|
self._state_manager.preference = preference
|
|
54
53
|
|
|
55
54
|
@property
|
|
56
|
-
def
|
|
55
|
+
def state_manager(self) -> StateManager:
|
|
56
|
+
"""Return the state manager."""
|
|
57
|
+
return self._state_manager
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def state(self):
|
|
61
|
+
"""Return the state of the device."""
|
|
57
62
|
return self._state_manager.get_device()
|
|
58
63
|
|
|
59
|
-
@
|
|
60
|
-
def
|
|
64
|
+
@state.setter
|
|
65
|
+
def state(self, value: MowingDevice) -> None:
|
|
61
66
|
self._state_manager.set_device(value)
|
|
62
67
|
|
|
63
68
|
def ble(self) -> MammotionBaseBLEDevice | None:
|
|
@@ -219,13 +224,12 @@ class Mammotion:
|
|
|
219
224
|
name=device.deviceName,
|
|
220
225
|
iot_id=device.iotId,
|
|
221
226
|
cloud_client=mqtt_client.cloud_client,
|
|
222
|
-
mammotion_http=mqtt_client.cloud_client.mammotion_http,
|
|
223
227
|
cloud_device=device,
|
|
224
228
|
mqtt=mqtt_client,
|
|
225
229
|
preference=ConnectionPreference.WIFI,
|
|
226
230
|
)
|
|
227
|
-
mixed_device.
|
|
228
|
-
mixed_device.
|
|
231
|
+
mixed_device.state.mower_state.product_key = device.productKey
|
|
232
|
+
mixed_device.state.mower_state.model = (
|
|
229
233
|
device.productName if device.productModel is None else device.productModel
|
|
230
234
|
)
|
|
231
235
|
self.device_manager.add_device(mixed_device)
|
|
@@ -266,6 +270,18 @@ class Mammotion:
|
|
|
266
270
|
def get_device_by_name(self, name: str) -> MammotionMixedDeviceManager:
|
|
267
271
|
return self.device_manager.get_device(name)
|
|
268
272
|
|
|
273
|
+
def get_or_create_device_by_name(self, device: Device, mqtt_client: MammotionCloud) -> MammotionMixedDeviceManager:
|
|
274
|
+
if mow_device := self.device_manager.get_device(device.deviceName):
|
|
275
|
+
return mow_device
|
|
276
|
+
return MammotionMixedDeviceManager(
|
|
277
|
+
name=device.deviceName,
|
|
278
|
+
iot_id=device.iotId,
|
|
279
|
+
cloud_client=mqtt_client.cloud_client,
|
|
280
|
+
mqtt=mqtt_client,
|
|
281
|
+
cloud_device=device,
|
|
282
|
+
ble_device=None,
|
|
283
|
+
)
|
|
284
|
+
|
|
269
285
|
async def send_command(self, name: str, key: str):
|
|
270
286
|
"""Send a command to the device."""
|
|
271
287
|
device = self.get_device_by_name(name)
|
|
@@ -275,6 +291,7 @@ class Mammotion:
|
|
|
275
291
|
if device.preference is ConnectionPreference.WIFI:
|
|
276
292
|
return await device.cloud().command(key)
|
|
277
293
|
# TODO work with both with EITHER
|
|
294
|
+
return None
|
|
278
295
|
|
|
279
296
|
async def send_command_with_args(self, name: str, key: str, **kwargs: Any):
|
|
280
297
|
"""Send a command with args to the device."""
|
|
@@ -285,6 +302,7 @@ class Mammotion:
|
|
|
285
302
|
if device.preference is ConnectionPreference.WIFI:
|
|
286
303
|
return await device.cloud().command(key, **kwargs)
|
|
287
304
|
# TODO work with both with EITHER
|
|
305
|
+
return None
|
|
288
306
|
|
|
289
307
|
async def start_sync(self, name: str, retry: int):
|
|
290
308
|
device = self.get_device_by_name(name)
|
|
@@ -294,6 +312,7 @@ class Mammotion:
|
|
|
294
312
|
if device.preference is ConnectionPreference.WIFI:
|
|
295
313
|
return await device.cloud().start_sync(retry)
|
|
296
314
|
# TODO work with both with EITHER
|
|
315
|
+
return None
|
|
297
316
|
|
|
298
317
|
async def start_map_sync(self, name: str):
|
|
299
318
|
device = self.get_device_by_name(name)
|
|
@@ -303,6 +322,7 @@ class Mammotion:
|
|
|
303
322
|
if device.preference is ConnectionPreference.WIFI:
|
|
304
323
|
return await device.cloud().start_map_sync()
|
|
305
324
|
# TODO work with both with EITHER
|
|
325
|
+
return None
|
|
306
326
|
|
|
307
327
|
async def get_stream_subscription(self, name: str, iot_id: str) -> Response[StreamSubscriptionResponse] | Any:
|
|
308
328
|
device = self.get_device_by_name(name)
|
|
@@ -329,4 +349,5 @@ class Mammotion:
|
|
|
329
349
|
def mower(self, name: str) -> MowingDevice | None:
|
|
330
350
|
device = self.get_device_by_name(name)
|
|
331
351
|
if device:
|
|
332
|
-
return device.
|
|
352
|
+
return device.state
|
|
353
|
+
return None
|
{pymammotion-0.4.56 → pymammotion-0.4.57}/pymammotion/mammotion/devices/mammotion_bluetooth.py
RENAMED
|
@@ -103,7 +103,7 @@ class MammotionBaseBLEDevice(MammotionBaseDevice):
|
|
|
103
103
|
def set_notification_callback(self, func: Callable[[tuple[str, Any | None]], Awaitable[None]]) -> None:
|
|
104
104
|
self._state_manager.ble_on_notification_callback = func
|
|
105
105
|
|
|
106
|
-
def set_queue_callback(self, func: Callable[[str, dict[str, Any]], Awaitable[
|
|
106
|
+
def set_queue_callback(self, func: Callable[[str, dict[str, Any]], Awaitable[None]]) -> None:
|
|
107
107
|
self._state_manager.ble_queue_command_callback = func
|
|
108
108
|
|
|
109
109
|
def update_device(self, device: BLEDevice) -> None:
|
|
@@ -136,7 +136,7 @@ class MammotionBaseBLEDevice(MammotionBaseDevice):
|
|
|
136
136
|
if self._client is not None and self._client.is_connected:
|
|
137
137
|
await self._client.disconnect()
|
|
138
138
|
|
|
139
|
-
async def queue_command(self, key: str, **kwargs: Any) ->
|
|
139
|
+
async def queue_command(self, key: str, **kwargs: Any) -> None:
|
|
140
140
|
# Create a future to hold the result
|
|
141
141
|
_LOGGER.debug("Queueing command: %s", key)
|
|
142
142
|
future = asyncio.Future()
|
|
@@ -144,7 +144,7 @@ class MammotionBaseBLEDevice(MammotionBaseDevice):
|
|
|
144
144
|
command_bytes = getattr(self._commands, key)(**kwargs)
|
|
145
145
|
await self.command_queue.put((key, command_bytes, future))
|
|
146
146
|
# Wait for the future to be resolved
|
|
147
|
-
|
|
147
|
+
await future
|
|
148
148
|
# return await self._send_command_with_args(key, **kwargs)
|
|
149
149
|
|
|
150
150
|
async def process_queue(self) -> None:
|