pymammotion 0.5.69__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 +53 -0
- pymammotion/agora/__init__.py +0 -0
- pymammotion/agora/agora_api.py +755 -0
- pymammotion/agora/agora_rtc_capabilities.py +748 -0
- pymammotion/agora/agora_websockets.py +1175 -0
- pymammotion/aliyun/__init__.py +1 -0
- pymammotion/aliyun/client.py +235 -0
- pymammotion/aliyun/cloud_gateway.py +982 -0
- pymammotion/aliyun/model/aep_response.py +21 -0
- pymammotion/aliyun/model/connect_response.py +51 -0
- pymammotion/aliyun/model/dev_by_account_response.py +195 -0
- pymammotion/aliyun/model/login_by_oauth_response.py +64 -0
- pymammotion/aliyun/model/regions_response.py +29 -0
- pymammotion/aliyun/model/session_by_authcode_response.py +19 -0
- pymammotion/aliyun/model/thing_response.py +12 -0
- pymammotion/aliyun/regions.py +62 -0
- pymammotion/aliyun/tea/core.py +297 -0
- pymammotion/aliyun/tmp_constant.py +171 -0
- pymammotion/bluetooth/__init__.py +1 -0
- pymammotion/bluetooth/ble.py +62 -0
- pymammotion/bluetooth/ble_message.py +676 -0
- pymammotion/bluetooth/const.py +27 -0
- pymammotion/bluetooth/data/__init__.py +0 -0
- pymammotion/bluetooth/data/convert.py +25 -0
- pymammotion/bluetooth/data/framectrldata.py +40 -0
- pymammotion/bluetooth/data/notifydata.py +62 -0
- pymammotion/bluetooth/model/__init__.py +0 -0
- pymammotion/bluetooth/model/atomic_integer.py +54 -0
- pymammotion/const.py +13 -0
- pymammotion/data/__init__.py +0 -0
- pymammotion/data/model/__init__.py +8 -0
- pymammotion/data/model/account.py +8 -0
- pymammotion/data/model/device.py +192 -0
- pymammotion/data/model/device_config.py +72 -0
- pymammotion/data/model/device_info.py +60 -0
- pymammotion/data/model/device_limits.py +49 -0
- pymammotion/data/model/enums.py +77 -0
- pymammotion/data/model/errors.py +12 -0
- pymammotion/data/model/events.py +14 -0
- pymammotion/data/model/generate_geojson.py +565 -0
- pymammotion/data/model/generate_route_information.py +26 -0
- pymammotion/data/model/hash_list.py +475 -0
- pymammotion/data/model/location.py +36 -0
- pymammotion/data/model/mowing_modes.py +77 -0
- pymammotion/data/model/rapid_state.py +45 -0
- pymammotion/data/model/raw_data.py +215 -0
- pymammotion/data/model/region_data.py +102 -0
- pymammotion/data/model/report_info.py +182 -0
- pymammotion/data/model/work.py +27 -0
- pymammotion/data/mower_state_manager.py +369 -0
- pymammotion/data/mqtt/__init__.py +1 -0
- pymammotion/data/mqtt/event.py +227 -0
- pymammotion/data/mqtt/mammotion_properties.py +276 -0
- pymammotion/data/mqtt/properties.py +203 -0
- pymammotion/data/mqtt/status.py +57 -0
- pymammotion/event/__init__.py +6 -0
- pymammotion/event/event.py +96 -0
- pymammotion/homeassistant/__init__.py +3 -0
- pymammotion/homeassistant/mower_api.py +514 -0
- pymammotion/homeassistant/rtk_api.py +54 -0
- pymammotion/http/__init__.py +0 -0
- pymammotion/http/encryption.py +220 -0
- pymammotion/http/http.py +673 -0
- pymammotion/http/model/__init__.py +0 -0
- pymammotion/http/model/camera_stream.py +31 -0
- pymammotion/http/model/http.py +249 -0
- pymammotion/http/model/response_factory.py +61 -0
- pymammotion/http/model/rtk.py +16 -0
- pymammotion/mammotion/__init__.py +0 -0
- pymammotion/mammotion/commands/__init__.py +0 -0
- pymammotion/mammotion/commands/abstract_message.py +24 -0
- pymammotion/mammotion/commands/mammotion_command.py +81 -0
- pymammotion/mammotion/commands/messages/__init__.py +0 -0
- pymammotion/mammotion/commands/messages/basestation.py +43 -0
- pymammotion/mammotion/commands/messages/driver.py +122 -0
- pymammotion/mammotion/commands/messages/media.py +87 -0
- pymammotion/mammotion/commands/messages/navigation.py +564 -0
- pymammotion/mammotion/commands/messages/network.py +205 -0
- pymammotion/mammotion/commands/messages/ota.py +38 -0
- pymammotion/mammotion/commands/messages/system.py +330 -0
- pymammotion/mammotion/commands/messages/video.py +33 -0
- pymammotion/mammotion/control/__init__.py +0 -0
- pymammotion/mammotion/control/joystick.py +145 -0
- pymammotion/mammotion/devices/__init__.py +29 -0
- pymammotion/mammotion/devices/base.py +163 -0
- pymammotion/mammotion/devices/mammotion.py +571 -0
- pymammotion/mammotion/devices/mammotion_bluetooth.py +496 -0
- pymammotion/mammotion/devices/mammotion_cloud.py +355 -0
- pymammotion/mammotion/devices/mammotion_mower_ble.py +48 -0
- pymammotion/mammotion/devices/mammotion_mower_cloud.py +39 -0
- pymammotion/mammotion/devices/managers/managers.py +81 -0
- pymammotion/mammotion/devices/mower_device.py +120 -0
- pymammotion/mammotion/devices/mower_manager.py +107 -0
- pymammotion/mammotion/devices/rtk_ble.py +89 -0
- pymammotion/mammotion/devices/rtk_cloud.py +115 -0
- pymammotion/mammotion/devices/rtk_device.py +50 -0
- pymammotion/mammotion/devices/rtk_manager.py +125 -0
- pymammotion/mqtt/__init__.py +6 -0
- pymammotion/mqtt/aliyun_mqtt.py +237 -0
- pymammotion/mqtt/linkkit/__init__.py +5 -0
- pymammotion/mqtt/linkkit/h2client.py +585 -0
- pymammotion/mqtt/linkkit/linkkit.py +3025 -0
- pymammotion/mqtt/mammotion_future.py +26 -0
- pymammotion/mqtt/mammotion_mqtt.py +214 -0
- pymammotion/mqtt/mqtt_models.py +66 -0
- pymammotion/proto/__init__.py +4841 -0
- pymammotion/proto/basestation.proto +51 -0
- pymammotion/proto/basestation_pb2.py +35 -0
- pymammotion/proto/basestation_pb2.pyi +89 -0
- pymammotion/proto/common.proto +7 -0
- pymammotion/proto/common_pb2.py +25 -0
- pymammotion/proto/common_pb2.pyi +13 -0
- pymammotion/proto/dev_net.proto +321 -0
- pymammotion/proto/dev_net_pb2.py +111 -0
- pymammotion/proto/dev_net_pb2.pyi +515 -0
- pymammotion/proto/luba_msg.proto +76 -0
- pymammotion/proto/luba_msg_pb2.py +41 -0
- pymammotion/proto/luba_msg_pb2.pyi +97 -0
- pymammotion/proto/luba_mul.proto +129 -0
- pymammotion/proto/luba_mul_pb2.py +61 -0
- pymammotion/proto/luba_mul_pb2.pyi +178 -0
- pymammotion/proto/mctrl_driver.proto +107 -0
- pymammotion/proto/mctrl_driver_pb2.py +57 -0
- pymammotion/proto/mctrl_driver_pb2.pyi +167 -0
- pymammotion/proto/mctrl_nav.proto +591 -0
- pymammotion/proto/mctrl_nav_pb2.py +136 -0
- pymammotion/proto/mctrl_nav_pb2.pyi +1067 -0
- pymammotion/proto/mctrl_ota.proto +80 -0
- pymammotion/proto/mctrl_ota_pb2.py +45 -0
- pymammotion/proto/mctrl_ota_pb2.pyi +128 -0
- pymammotion/proto/mctrl_pept.proto +34 -0
- pymammotion/proto/mctrl_pept_pb2.py +33 -0
- pymammotion/proto/mctrl_pept_pb2.pyi +58 -0
- pymammotion/proto/mctrl_sys.proto +741 -0
- pymammotion/proto/mctrl_sys_pb2.py +206 -0
- pymammotion/proto/mctrl_sys_pb2.pyi +1213 -0
- pymammotion/proto/message_pool.py +3 -0
- pymammotion/proto/py.typed +0 -0
- pymammotion/py.typed +0 -0
- pymammotion/utility/constant/__init__.py +3 -0
- pymammotion/utility/constant/device_constant.py +315 -0
- pymammotion/utility/conversions.py +5 -0
- pymammotion/utility/datatype_converter.py +124 -0
- pymammotion/utility/device_config.py +755 -0
- pymammotion/utility/device_type.py +489 -0
- pymammotion/utility/map.py +259 -0
- pymammotion/utility/movement.py +18 -0
- pymammotion/utility/mur_mur_hash.py +159 -0
- pymammotion/utility/periodic.py +106 -0
- pymammotion/utility/rocker_util.py +194 -0
- pymammotion-0.5.69.dist-info/METADATA +93 -0
- pymammotion-0.5.69.dist-info/RECORD +154 -0
- pymammotion-0.5.69.dist-info/WHEEL +4 -0
- pymammotion-0.5.69.dist-info/licenses/LICENSE +674 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
from mashumaro.mixins.orjson import DataClassORJSONMixin
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass
|
|
7
|
+
class Camera(DataClassORJSONMixin):
|
|
8
|
+
cameraId: int
|
|
9
|
+
token: str
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class StreamSubscriptionResponse(DataClassORJSONMixin):
|
|
14
|
+
appid: str
|
|
15
|
+
cameras: list[Camera]
|
|
16
|
+
channelName: str
|
|
17
|
+
token: str
|
|
18
|
+
uid: int
|
|
19
|
+
license: str | None = None
|
|
20
|
+
availableTime: int | None = None
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class VideoResourceResponse(DataClassORJSONMixin):
|
|
25
|
+
id: str
|
|
26
|
+
deviceId: str
|
|
27
|
+
deviceName: str
|
|
28
|
+
cycleType: int
|
|
29
|
+
usageYearMonth: str
|
|
30
|
+
totalTime: int
|
|
31
|
+
availableTime: int
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import Annotated, Generic, Literal, TypeVar
|
|
3
|
+
|
|
4
|
+
from mashumaro import DataClassDictMixin
|
|
5
|
+
from mashumaro.config import BaseConfig
|
|
6
|
+
from mashumaro.mixins.orjson import DataClassORJSONMixin
|
|
7
|
+
from mashumaro.types import Alias
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class UnauthorizedException(Exception):
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
DataT = TypeVar("DataT")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class ErrorInfo(DataClassDictMixin):
|
|
19
|
+
code: str
|
|
20
|
+
platform: str
|
|
21
|
+
module: str
|
|
22
|
+
variant: str
|
|
23
|
+
level: str
|
|
24
|
+
description: str
|
|
25
|
+
en_implication: str
|
|
26
|
+
en_solution: str
|
|
27
|
+
zh_implication: str
|
|
28
|
+
zh_solution: str
|
|
29
|
+
de_implication: str
|
|
30
|
+
de_solution: str
|
|
31
|
+
fr_implication: str
|
|
32
|
+
fr_solution: str
|
|
33
|
+
it_implication: str
|
|
34
|
+
it_solution: str
|
|
35
|
+
ja_implication: str
|
|
36
|
+
ja_solution: str
|
|
37
|
+
es_implication: str
|
|
38
|
+
es_solution: str
|
|
39
|
+
cs_implication: str
|
|
40
|
+
cs_solution: str
|
|
41
|
+
ko_implication: str
|
|
42
|
+
ko_solution: str
|
|
43
|
+
sk_implication: str
|
|
44
|
+
sk_solution: str
|
|
45
|
+
pl_implication: str
|
|
46
|
+
pl_solution: str
|
|
47
|
+
nl_implication: str
|
|
48
|
+
nl_solution: str
|
|
49
|
+
da_implication: str
|
|
50
|
+
da_solution: str
|
|
51
|
+
sr_implication: str
|
|
52
|
+
sr_solution: str
|
|
53
|
+
sv_implication: str
|
|
54
|
+
sv_solution: str
|
|
55
|
+
sl_implication: str
|
|
56
|
+
sl_solution: str
|
|
57
|
+
pt_implication: str
|
|
58
|
+
pt_solution: str
|
|
59
|
+
hu_implication: str
|
|
60
|
+
hu_solution: str
|
|
61
|
+
hr_implication: str
|
|
62
|
+
hr_solution: str
|
|
63
|
+
no_implication: str
|
|
64
|
+
no_solution: str
|
|
65
|
+
fi_implication: str
|
|
66
|
+
fi_solution: str
|
|
67
|
+
ro_implication: str
|
|
68
|
+
ro_solution: str
|
|
69
|
+
bg_implication: str
|
|
70
|
+
bg_solution: str
|
|
71
|
+
et_implication: str
|
|
72
|
+
et_solution: str
|
|
73
|
+
lv_implication: str
|
|
74
|
+
lv_solution: str
|
|
75
|
+
lt_implication: str
|
|
76
|
+
lt_solution: str
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@dataclass
|
|
80
|
+
class SettingVo(DataClassORJSONMixin):
|
|
81
|
+
"""Device setting configuration."""
|
|
82
|
+
|
|
83
|
+
type: int = 0
|
|
84
|
+
is_switch: Annotated[int, Alias("isSwitch")] = 0
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@dataclass
|
|
88
|
+
class LocationVo(DataClassORJSONMixin):
|
|
89
|
+
"""Device location information."""
|
|
90
|
+
|
|
91
|
+
date_time: Annotated[str, Alias("dateTime")] = ""
|
|
92
|
+
date_timestamp: Annotated[int, Alias("dateTimestamp")] = 0
|
|
93
|
+
location: list[float] = field(default_factory=lambda: [0.0, 0.0])
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@dataclass
|
|
97
|
+
class DeviceInfo:
|
|
98
|
+
"""Complete device information."""
|
|
99
|
+
|
|
100
|
+
iot_id: Annotated[str, Alias("iotId")] = ""
|
|
101
|
+
device_id: Annotated[str, Alias("deviceId")] = ""
|
|
102
|
+
device_name: Annotated[str, Alias("deviceName")] = ""
|
|
103
|
+
device_type: Annotated[str, Alias("deviceType")] = ""
|
|
104
|
+
series: str = ""
|
|
105
|
+
product_series: Annotated[str, Alias("productSeries")] = ""
|
|
106
|
+
icon_code: Annotated[str, Alias("iconCode")] = ""
|
|
107
|
+
generation: int = 0
|
|
108
|
+
status: int = 0
|
|
109
|
+
is_subscribe: Annotated[int, Alias("isSubscribe")] = 0
|
|
110
|
+
setting_vos: Annotated[list[SettingVo], Alias("settingVos")] = field(default_factory=list)
|
|
111
|
+
active_time: Annotated[str, Alias("activeTime")] = ""
|
|
112
|
+
active_timestamp: Annotated[int, Alias("activeTimestamp")] = 0
|
|
113
|
+
location_vo: Annotated[LocationVo | None, Alias("locationVo")] = None
|
|
114
|
+
|
|
115
|
+
class Config(BaseConfig):
|
|
116
|
+
allow_deserialization_not_by_alias = True
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@dataclass
|
|
120
|
+
class DeviceRecord(DataClassORJSONMixin):
|
|
121
|
+
identity_id: Annotated[str, Alias("identityId")]
|
|
122
|
+
iot_id: Annotated[str, Alias("iotId")]
|
|
123
|
+
product_key: Annotated[str, Alias("productKey")]
|
|
124
|
+
device_name: Annotated[str, Alias("deviceName")]
|
|
125
|
+
owned: int
|
|
126
|
+
status: int
|
|
127
|
+
bind_time: Annotated[int, Alias("bindTime")]
|
|
128
|
+
create_time: Annotated[str, Alias("createTime")]
|
|
129
|
+
|
|
130
|
+
class Config(BaseConfig):
|
|
131
|
+
allow_deserialization_not_by_alias = True
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@dataclass
|
|
135
|
+
class DeviceRecords(DataClassORJSONMixin):
|
|
136
|
+
records: list[DeviceRecord]
|
|
137
|
+
total: int
|
|
138
|
+
size: int
|
|
139
|
+
current: int
|
|
140
|
+
pages: int
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@dataclass
|
|
144
|
+
class MQTTConnection(DataClassORJSONMixin):
|
|
145
|
+
host: str
|
|
146
|
+
jwt: str
|
|
147
|
+
client_id: Annotated[str, Alias("clientId")]
|
|
148
|
+
username: str
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
@dataclass
|
|
152
|
+
class Response(DataClassORJSONMixin, Generic[DataT]):
|
|
153
|
+
code: int
|
|
154
|
+
msg: str
|
|
155
|
+
request_id: Annotated[str, Alias("requestId")] | None = None
|
|
156
|
+
data: DataT | None = None
|
|
157
|
+
|
|
158
|
+
class Config(BaseConfig):
|
|
159
|
+
omit_default = True
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
@dataclass
|
|
163
|
+
class LoginResponseUserInformation(DataClassORJSONMixin):
|
|
164
|
+
areaCode: str
|
|
165
|
+
domainAbbreviation: str
|
|
166
|
+
userId: str
|
|
167
|
+
userAccount: str
|
|
168
|
+
authType: str
|
|
169
|
+
email: str | None = None
|
|
170
|
+
|
|
171
|
+
class Config(BaseConfig):
|
|
172
|
+
omit_none = True
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
@dataclass
|
|
176
|
+
class JWTTokenInfo(DataClassORJSONMixin):
|
|
177
|
+
"""specifically for newer devices and mqtt"""
|
|
178
|
+
|
|
179
|
+
iot: str # iot domain e.g api-iot-business-eu-dcdn.mammotion.com
|
|
180
|
+
robot: str # e.g api-robot-eu.mammotion.com
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
@dataclass
|
|
184
|
+
class LoginResponseData(DataClassORJSONMixin):
|
|
185
|
+
access_token: str
|
|
186
|
+
token_type: Literal["bearer", "Bearer"]
|
|
187
|
+
refresh_token: str
|
|
188
|
+
expires_in: int
|
|
189
|
+
authorization_code: str
|
|
190
|
+
userInformation: LoginResponseUserInformation
|
|
191
|
+
jti: str = None
|
|
192
|
+
grant_type: Literal["password", "Password"] = None
|
|
193
|
+
scope: Literal["read", "Read"] = None
|
|
194
|
+
|
|
195
|
+
class Config(BaseConfig):
|
|
196
|
+
omit_none = True
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
@dataclass
|
|
200
|
+
class FirmwareVersions(DataClassORJSONMixin):
|
|
201
|
+
firmware_version: Annotated[str, Alias("firmwareVersion")] = ""
|
|
202
|
+
firmware_code: Annotated[str, Alias("firmwareCode")] = ""
|
|
203
|
+
firmware_latest_version: Annotated[str, Alias("firmwareLatestVersion")] = ""
|
|
204
|
+
firmware_type: Annotated[str, Alias("firmwareType")] = ""
|
|
205
|
+
|
|
206
|
+
class Config(BaseConfig):
|
|
207
|
+
allow_deserialization_not_by_alias = True
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
@dataclass
|
|
211
|
+
class ProductVersionInfo(DataClassORJSONMixin):
|
|
212
|
+
release_note: Annotated[str, Alias("releaseNote")] = ""
|
|
213
|
+
release_version: Annotated[str, Alias("releaseVersion")] = ""
|
|
214
|
+
data_location: str | None = None
|
|
215
|
+
|
|
216
|
+
class Config(BaseConfig):
|
|
217
|
+
allow_deserialization_not_by_alias = True
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
@dataclass
|
|
221
|
+
class CheckDeviceVersion(DataClassORJSONMixin):
|
|
222
|
+
cause_code: Annotated[int, Alias("causeCode")] = 0
|
|
223
|
+
product_version_info_vo: Annotated[ProductVersionInfo | None, Alias("productVersionInfoVo")] = None
|
|
224
|
+
progress: int | None = 0
|
|
225
|
+
upgradeable: bool = False
|
|
226
|
+
device_id: Annotated[str, Alias("deviceId")] = ""
|
|
227
|
+
device_name: Annotated[str | None, Alias("deviceName")] = ""
|
|
228
|
+
current_version: Annotated[str, Alias("currentVersion")] = ""
|
|
229
|
+
isupgrading: bool | None = False
|
|
230
|
+
cause_msg: Annotated[str, Alias("causeMsg")] = ""
|
|
231
|
+
|
|
232
|
+
class Config(BaseConfig):
|
|
233
|
+
allow_deserialization_not_by_alias = True
|
|
234
|
+
|
|
235
|
+
def __eq__(self, other):
|
|
236
|
+
if not isinstance(other, CheckDeviceVersion):
|
|
237
|
+
return NotImplemented
|
|
238
|
+
|
|
239
|
+
if self.device_id != other.device_id or self.current_version != other.current_version:
|
|
240
|
+
return False
|
|
241
|
+
|
|
242
|
+
if self.product_version_info_vo and other.product_version_info_vo:
|
|
243
|
+
if self.product_version_info_vo.release_version != other.product_version_info_vo.release_version:
|
|
244
|
+
return False
|
|
245
|
+
return True
|
|
246
|
+
elif self.product_version_info_vo is None and other.product_version_info_vo is None:
|
|
247
|
+
return False
|
|
248
|
+
else:
|
|
249
|
+
return True
|
|
@@ -0,0 +1,61 @@
|
|
|
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
|
+
"""Deserialize data into a specified target type.
|
|
10
|
+
|
|
11
|
+
The function handles deserialization of basic types, lists, and unions. It
|
|
12
|
+
recursively processes list elements and supports optional types by handling
|
|
13
|
+
Union[T, None]. For custom types with a `from_dict` method, it calls this
|
|
14
|
+
method for deserialization. If the target type is unknown or unsupported, it
|
|
15
|
+
returns the value unchanged.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
value: The data to be deserialized.
|
|
19
|
+
target_type (type): The desired type into which the data should be deserialized.
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
The deserialized data in the specified target type.
|
|
23
|
+
|
|
24
|
+
"""
|
|
25
|
+
if value is None:
|
|
26
|
+
return None
|
|
27
|
+
|
|
28
|
+
origin = get_origin(target_type)
|
|
29
|
+
args = get_args(target_type)
|
|
30
|
+
|
|
31
|
+
if origin is list and args:
|
|
32
|
+
item_type = args[0]
|
|
33
|
+
return [deserialize_data(v, item_type) for v in value]
|
|
34
|
+
|
|
35
|
+
if origin is Union:
|
|
36
|
+
# Support Optional[T] = Union[T, None]
|
|
37
|
+
non_none_types = [t for t in args if t is not type(None)]
|
|
38
|
+
if len(non_none_types) == 1:
|
|
39
|
+
target = non_none_types[0]
|
|
40
|
+
# Handle Response[list[type]] case
|
|
41
|
+
if get_origin(target) is list and get_args(target):
|
|
42
|
+
item_type = get_args(target)[0]
|
|
43
|
+
return [deserialize_data(v, item_type) for v in value]
|
|
44
|
+
return deserialize_data(value, target)
|
|
45
|
+
|
|
46
|
+
if hasattr(target_type, "from_dict"):
|
|
47
|
+
return target_type.from_dict(value)
|
|
48
|
+
|
|
49
|
+
return value # fallback: unknown type, leave as-is
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def response_factory(response_cls: type[Response[T]], raw_dict: dict) -> Response[T]:
|
|
53
|
+
# Extract the type of the generic `data` field
|
|
54
|
+
"""Create a Response instance from a dictionary."""
|
|
55
|
+
data_type = get_args(response_cls)[0] if get_args(response_cls) else None
|
|
56
|
+
|
|
57
|
+
if data_type:
|
|
58
|
+
data_value = deserialize_data(raw_dict.get("data"), data_type)
|
|
59
|
+
return Response(code=raw_dict["code"], msg=raw_dict["msg"], data=data_value)
|
|
60
|
+
else:
|
|
61
|
+
return response_cls.from_dict(raw_dict)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""RTK device information."""
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
|
+
|
|
4
|
+
from mashumaro import field_options
|
|
5
|
+
from mashumaro.mixins.orjson import DataClassORJSONMixin
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class RTK(DataClassORJSONMixin):
|
|
10
|
+
"""RTK device information."""
|
|
11
|
+
|
|
12
|
+
device_id: str = field(metadata=field_options(alias="deviceId"))
|
|
13
|
+
device_name: str = field(metadata=field_options(alias="deviceName"))
|
|
14
|
+
product_key: str = field(metadata=field_options(alias="productKey"))
|
|
15
|
+
status: int
|
|
16
|
+
lora: str
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
|
|
3
|
+
from pymammotion.bluetooth.model.atomic_integer import AtomicInteger
|
|
4
|
+
from pymammotion.proto import MsgCmdType, MsgDevice
|
|
5
|
+
from pymammotion.utility.device_type import DeviceType
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class AbstractMessage:
|
|
9
|
+
seqs = AtomicInteger(0)
|
|
10
|
+
user_account: int
|
|
11
|
+
|
|
12
|
+
@abstractmethod
|
|
13
|
+
def get_device_name(self) -> str:
|
|
14
|
+
"""Get device name."""
|
|
15
|
+
|
|
16
|
+
@abstractmethod
|
|
17
|
+
def get_device_product_key(self) -> str:
|
|
18
|
+
"""Get device name."""
|
|
19
|
+
|
|
20
|
+
def get_msg_device(self, msg_type: MsgCmdType, msg_device: MsgDevice) -> MsgDevice:
|
|
21
|
+
"""Changes the rcver name if it's not a luba1."""
|
|
22
|
+
if DeviceType.is_luba_pro(self.get_device_name(), self.get_device_product_key()) and msg_type == MsgCmdType.NAV:
|
|
23
|
+
return MsgDevice.DEV_NAVIGATION
|
|
24
|
+
return msg_device
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
from pymammotion.mammotion.commands.messages.driver import MessageDriver
|
|
2
|
+
from pymammotion.mammotion.commands.messages.media import MessageMedia
|
|
3
|
+
from pymammotion.mammotion.commands.messages.navigation import MessageNavigation
|
|
4
|
+
from pymammotion.mammotion.commands.messages.network import MessageNetwork
|
|
5
|
+
from pymammotion.mammotion.commands.messages.ota import MessageOta
|
|
6
|
+
from pymammotion.mammotion.commands.messages.system import MessageSystem
|
|
7
|
+
from pymammotion.mammotion.commands.messages.video import MessageVideo
|
|
8
|
+
from pymammotion.utility.device_type import DeviceType
|
|
9
|
+
from pymammotion.utility.movement import get_percent, transform_both_speeds
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class MammotionCommand(
|
|
13
|
+
MessageSystem, MessageNavigation, MessageNetwork, MessageOta, MessageVideo, MessageMedia, MessageDriver
|
|
14
|
+
):
|
|
15
|
+
"""MQTT commands for Luba."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, device_name: str, user_account: int) -> None:
|
|
18
|
+
self._device_name = device_name
|
|
19
|
+
self._product_key = ""
|
|
20
|
+
self.user_account = user_account
|
|
21
|
+
|
|
22
|
+
def get_device_name(self) -> str:
|
|
23
|
+
"""Get device name."""
|
|
24
|
+
return self._device_name
|
|
25
|
+
|
|
26
|
+
def read_write_device(self, rw_id: int, context: int, rw: int):
|
|
27
|
+
if (
|
|
28
|
+
rw_id == 6 or rw_id == 3 or rw_id == 7 or rw_id == 8 or rw_id == 10 or rw_id == 11
|
|
29
|
+
) and DeviceType.is_luba_pro(self.get_device_name()):
|
|
30
|
+
return self.allpowerfull_rw_adapter_x3(rw_id, context, rw)
|
|
31
|
+
return self.allpowerfull_rw(rw_id, context, rw)
|
|
32
|
+
|
|
33
|
+
def traverse_mode(self, context: int) -> bytes:
|
|
34
|
+
"""Sets the traversal mode back to charger."""
|
|
35
|
+
# setReChargeMode
|
|
36
|
+
# 0 direct
|
|
37
|
+
# 1 follow the perimeter
|
|
38
|
+
return self.read_write_device(7, context, 1)
|
|
39
|
+
|
|
40
|
+
def turning_mode(self, context: int) -> bytes:
|
|
41
|
+
"""Sets the traversal mode back to charger."""
|
|
42
|
+
# setTurnAroundMode
|
|
43
|
+
# 0 zero turn
|
|
44
|
+
# 1 multipoint turn
|
|
45
|
+
return self.read_write_device(6, context, 1)
|
|
46
|
+
|
|
47
|
+
def get_error_code(self) -> bytes:
|
|
48
|
+
return self.read_write_device(5, 2, 1)
|
|
49
|
+
|
|
50
|
+
def get_error_timestamp(self) -> bytes:
|
|
51
|
+
return self.read_write_device(5, 3, 1)
|
|
52
|
+
|
|
53
|
+
def get_device_product_key(self) -> str:
|
|
54
|
+
return self._product_key
|
|
55
|
+
|
|
56
|
+
def set_device_product_key(self, product_key: str) -> None:
|
|
57
|
+
self._product_key = product_key
|
|
58
|
+
|
|
59
|
+
def move_forward(self, linear: float) -> bytes:
|
|
60
|
+
"""Move forward. values 0.0 1.0."""
|
|
61
|
+
linear_percent = get_percent(abs(linear * 100))
|
|
62
|
+
(linear_speed, angular_speed) = transform_both_speeds(90.0, 0.0, linear_percent, 0.0)
|
|
63
|
+
return self.send_movement(linear_speed=linear_speed, angular_speed=angular_speed)
|
|
64
|
+
|
|
65
|
+
def move_back(self, linear: float) -> bytes:
|
|
66
|
+
"""Move back. values 0.0 1.0."""
|
|
67
|
+
linear_percent = get_percent(abs(linear * 100))
|
|
68
|
+
(linear_speed, angular_speed) = transform_both_speeds(270.0, 0.0, linear_percent, 0.0)
|
|
69
|
+
return self.send_movement(linear_speed=linear_speed, angular_speed=angular_speed)
|
|
70
|
+
|
|
71
|
+
def move_left(self, angular: float) -> bytes:
|
|
72
|
+
"""Move forward. values 0.0 1.0."""
|
|
73
|
+
angular_percent = get_percent(abs(angular * 100))
|
|
74
|
+
(linear_speed, angular_speed) = transform_both_speeds(0.0, 180.0, 0.0, angular_percent)
|
|
75
|
+
return self.send_movement(linear_speed=linear_speed, angular_speed=angular_speed)
|
|
76
|
+
|
|
77
|
+
def move_right(self, angular: float) -> bytes:
|
|
78
|
+
"""Move back. values 0.0 1.0."""
|
|
79
|
+
angular_percent = get_percent(abs(angular * 100))
|
|
80
|
+
(linear_speed, angular_speed) = transform_both_speeds(0.0, 0.0, 0.0, angular_percent)
|
|
81
|
+
return self.send_movement(linear_speed=linear_speed, angular_speed=angular_speed)
|
|
File without changes
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""RTK protobuf commands."""
|
|
2
|
+
|
|
3
|
+
from abc import ABC
|
|
4
|
+
from logging import getLogger
|
|
5
|
+
import time
|
|
6
|
+
|
|
7
|
+
from pymammotion.mammotion.commands.abstract_message import AbstractMessage
|
|
8
|
+
from pymammotion.proto import (
|
|
9
|
+
AppToBaseMqttRtkT,
|
|
10
|
+
BaseStation,
|
|
11
|
+
LubaMsg,
|
|
12
|
+
MsgAttr,
|
|
13
|
+
MsgCmdType,
|
|
14
|
+
MsgDevice,
|
|
15
|
+
RequestBasestationInfoT,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
logger = getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class MessageBasestation(AbstractMessage, ABC):
|
|
22
|
+
def send_order_msg_basestation(self, driver) -> bytes:
|
|
23
|
+
return LubaMsg(
|
|
24
|
+
msgtype=MsgCmdType.BASESTATION,
|
|
25
|
+
sender=MsgDevice.DEV_MOBILEAPP,
|
|
26
|
+
rcver=self.get_msg_device(MsgCmdType.BASESTATION, MsgDevice.DEV_MAINCTL),
|
|
27
|
+
msgattr=MsgAttr.REQ,
|
|
28
|
+
timestamp=round(time.time() * 1000),
|
|
29
|
+
seqs=self.seqs.increment_and_get() & 255,
|
|
30
|
+
version=1,
|
|
31
|
+
subtype=self.user_account,
|
|
32
|
+
driver=driver,
|
|
33
|
+
).SerializeToString()
|
|
34
|
+
|
|
35
|
+
def basestation_info(self) -> bytes:
|
|
36
|
+
"""Build and send a request to get basestation info (request_type=1)."""
|
|
37
|
+
base = BaseStation(to_dev=RequestBasestationInfoT(request_type=1))
|
|
38
|
+
return self.send_order_msg_basestation(base)
|
|
39
|
+
|
|
40
|
+
def set_base_net_rtk_switch(self, rtk_switch: int) -> bytes:
|
|
41
|
+
"""Set RTK switch via app_to_base_mqtt_rtk_t."""
|
|
42
|
+
base = BaseStation(app_to_base_mqtt_rtk_msg=AppToBaseMqttRtkT(rtk_switch=rtk_switch))
|
|
43
|
+
return self.send_order_msg_basestation(base)
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# === sendOrderMsg_Driver ===
|
|
2
|
+
from abc import ABC
|
|
3
|
+
from logging import getLogger
|
|
4
|
+
import time
|
|
5
|
+
|
|
6
|
+
from pymammotion.mammotion.commands.abstract_message import AbstractMessage
|
|
7
|
+
from pymammotion.proto import (
|
|
8
|
+
AppGetCutterWorkMode,
|
|
9
|
+
AppSetCutterWorkMode,
|
|
10
|
+
DrvKnifeHeight,
|
|
11
|
+
DrvMotionCtrl,
|
|
12
|
+
DrvMowCtrlByHand,
|
|
13
|
+
DrvSrSpeed,
|
|
14
|
+
LubaMsg,
|
|
15
|
+
MctlDriver,
|
|
16
|
+
MsgAttr,
|
|
17
|
+
MsgCmdType,
|
|
18
|
+
MsgDevice,
|
|
19
|
+
RtkCfgReqT,
|
|
20
|
+
RtkSysMaskQueryT,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
logger = getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class MessageDriver(AbstractMessage, ABC):
|
|
27
|
+
def send_order_msg_driver(self, driver) -> bytes:
|
|
28
|
+
"""Build and serialize a driver command message."""
|
|
29
|
+
return LubaMsg(
|
|
30
|
+
msgtype=MsgCmdType.EMBED_DRIVER,
|
|
31
|
+
sender=MsgDevice.DEV_MOBILEAPP,
|
|
32
|
+
rcver=self.get_msg_device(MsgCmdType.EMBED_DRIVER, MsgDevice.DEV_MAINCTL),
|
|
33
|
+
msgattr=MsgAttr.REQ,
|
|
34
|
+
timestamp=round(time.time() * 1000),
|
|
35
|
+
seqs=self.seqs.increment_and_get() & 255,
|
|
36
|
+
version=1,
|
|
37
|
+
subtype=self.user_account,
|
|
38
|
+
driver=driver,
|
|
39
|
+
).SerializeToString()
|
|
40
|
+
|
|
41
|
+
def set_blade_height(self, height: int) -> bytes:
|
|
42
|
+
"""Set mower blade height."""
|
|
43
|
+
logger.debug(f"Send knife height height={height}")
|
|
44
|
+
build = MctlDriver(todev_knife_height_set=DrvKnifeHeight(knife_height=height))
|
|
45
|
+
logger.debug(f"Send command--Knife motor height setting height={height}")
|
|
46
|
+
return self.send_order_msg_driver(build)
|
|
47
|
+
|
|
48
|
+
def set_speed(self, speed: float) -> bytes:
|
|
49
|
+
"""Set the device speed."""
|
|
50
|
+
logger.debug(f"{self.get_device_name()} set speed, {speed}")
|
|
51
|
+
build = MctlDriver(bidire_speed_read_set=DrvSrSpeed(speed=speed, rw=1))
|
|
52
|
+
logger.debug(f"Send command--Speed setting speed={speed}")
|
|
53
|
+
return self.send_order_msg_driver(build)
|
|
54
|
+
|
|
55
|
+
def get_cutter_mode(self) -> bytes:
|
|
56
|
+
"""Request the current cutter mode."""
|
|
57
|
+
build = MctlDriver(current_cutter_mode=AppGetCutterWorkMode())
|
|
58
|
+
return self.send_order_msg_driver(build)
|
|
59
|
+
|
|
60
|
+
def set_cutter_mode(self, cutter_mode: int) -> bytes:
|
|
61
|
+
"""Set blade speed."""
|
|
62
|
+
"""
|
|
63
|
+
1 slow
|
|
64
|
+
0 normal
|
|
65
|
+
2 fast
|
|
66
|
+
"""
|
|
67
|
+
build = MctlDriver(cutter_mode_ctrl_by_hand=AppSetCutterWorkMode(cutter_mode=cutter_mode))
|
|
68
|
+
return self.send_order_msg_driver(build)
|
|
69
|
+
|
|
70
|
+
def syn_nav_star_point_data(self, sat_system: int) -> bytes:
|
|
71
|
+
"""Synchronize navigation satellite frequency points."""
|
|
72
|
+
build = MctlDriver(rtk_sys_mask_query=RtkSysMaskQueryT(sat_system=sat_system))
|
|
73
|
+
logger.debug(f"Send command--Navigation satellite frequency point synchronization={sat_system}")
|
|
74
|
+
return self.send_order_msg_driver(build)
|
|
75
|
+
|
|
76
|
+
def set_nav_star_point(self, cmd_req: str) -> bytes:
|
|
77
|
+
"""Configure navigation satellite frequency points."""
|
|
78
|
+
build = MctlDriver(rtk_cfg_req=RtkCfgReqT(cmd_req=cmd_req, cmd_length=len(cmd_req) - 1))
|
|
79
|
+
logger.debug(f"Send command--Navigation satellite frequency point setting={cmd_req}")
|
|
80
|
+
logger.debug(
|
|
81
|
+
f"Navigation satellite setting, Send command--Navigation satellite frequency point setting={cmd_req}"
|
|
82
|
+
)
|
|
83
|
+
return self.send_order_msg_driver(build)
|
|
84
|
+
|
|
85
|
+
def get_speed(self) -> bytes:
|
|
86
|
+
"""Request the current speed value."""
|
|
87
|
+
build = MctlDriver(bidire_speed_read_set=DrvSrSpeed(rw=0))
|
|
88
|
+
logger.debug("Send command--Get speed value")
|
|
89
|
+
return self.send_order_msg_driver(build)
|
|
90
|
+
|
|
91
|
+
def operate_on_device(
|
|
92
|
+
self,
|
|
93
|
+
main_ctrl: int,
|
|
94
|
+
cut_knife_ctrl: int,
|
|
95
|
+
cut_knife_height: int,
|
|
96
|
+
max_run_speed: float,
|
|
97
|
+
) -> bytes:
|
|
98
|
+
"""Send manual mowing control command."""
|
|
99
|
+
build = MctlDriver(
|
|
100
|
+
mow_ctrl_by_hand=DrvMowCtrlByHand(
|
|
101
|
+
main_ctrl=main_ctrl,
|
|
102
|
+
cut_knife_ctrl=cut_knife_ctrl,
|
|
103
|
+
cut_knife_height=cut_knife_height,
|
|
104
|
+
max_run_speed=max_run_speed,
|
|
105
|
+
)
|
|
106
|
+
)
|
|
107
|
+
logger.debug(
|
|
108
|
+
f"Send command--Manual mowing command, main_ctrl:{main_ctrl}, cut_knife_ctrl:{cut_knife_ctrl}, "
|
|
109
|
+
f"cut_knife_height:{cut_knife_height}, max_run_speed:{max_run_speed}"
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
return self.send_order_msg_driver(build)
|
|
113
|
+
|
|
114
|
+
def send_movement(self, linear_speed: int, angular_speed: int) -> bytes:
|
|
115
|
+
"""Send motion command with linear and angular speeds."""
|
|
116
|
+
logger.debug(f"Control command print, linearSpeed={
|
|
117
|
+
linear_speed} // angularSpeed={angular_speed}")
|
|
118
|
+
return self.send_order_msg_driver(
|
|
119
|
+
MctlDriver(
|
|
120
|
+
todev_devmotion_ctrl=DrvMotionCtrl(set_linear_speed=linear_speed, set_angular_speed=angular_speed)
|
|
121
|
+
)
|
|
122
|
+
)
|