pymammotion 0.0.37__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.
Potentially problematic release.
This version of pymammotion might be problematic. Click here for more details.
- pymammotion/__init__.py +43 -0
- pymammotion/aliyun/cloud_gateway.py +549 -0
- pymammotion/aliyun/cloud_service.py +65 -0
- pymammotion/aliyun/dataclass/aep_response.py +18 -0
- pymammotion/aliyun/dataclass/connect_response.py +51 -0
- pymammotion/aliyun/dataclass/dev_by_account_response.py +43 -0
- pymammotion/aliyun/dataclass/login_by_oauth_response.py +65 -0
- pymammotion/aliyun/dataclass/regions_response.py +26 -0
- pymammotion/aliyun/dataclass/session_by_authcode_response.py +18 -0
- pymammotion/aliyun/tmp_constant.py +175 -0
- pymammotion/bluetooth/__init__.py +1 -0
- pymammotion/bluetooth/ble.py +74 -0
- pymammotion/bluetooth/ble_message.py +430 -0
- pymammotion/bluetooth/const.py +27 -0
- pymammotion/bluetooth/data/__init__.py +0 -0
- pymammotion/bluetooth/data/convert.py +26 -0
- pymammotion/bluetooth/data/framectrldata.py +40 -0
- pymammotion/bluetooth/data/notifydata.py +63 -0
- pymammotion/const.py +9 -0
- pymammotion/data/__init__.py +0 -0
- pymammotion/data/model/__init__.py +8 -0
- pymammotion/data/model/device.py +157 -0
- pymammotion/data/model/enums.py +67 -0
- pymammotion/data/model/excute_boarder_params.py +48 -0
- pymammotion/data/model/execute_boarder.py +36 -0
- pymammotion/data/model/generate_route_information.py +133 -0
- pymammotion/data/model/hash_list.py +17 -0
- pymammotion/data/model/mowing_modes.py +37 -0
- pymammotion/data/model/plan.py +58 -0
- pymammotion/data/model/rapid_state.py +45 -0
- pymammotion/data/model/region_data.py +99 -0
- pymammotion/data/mqtt/__init__.py +1 -0
- pymammotion/data/mqtt/event.py +90 -0
- pymammotion/data/mqtt/properties.py +140 -0
- pymammotion/data/mqtt/status.py +52 -0
- pymammotion/event/__init__.py +6 -0
- pymammotion/event/event.py +50 -0
- pymammotion/http/_init_.py +0 -0
- pymammotion/http/http.py +76 -0
- pymammotion/luba/_init_.py +0 -0
- pymammotion/luba/base.py +52 -0
- pymammotion/mammotion/__init__.py +0 -0
- pymammotion/mammotion/commands/__init__.py +0 -0
- pymammotion/mammotion/commands/abstract_message.py +7 -0
- pymammotion/mammotion/commands/mammotion_command.py +34 -0
- pymammotion/mammotion/commands/messages/__init__.py +0 -0
- pymammotion/mammotion/commands/messages/driver.py +108 -0
- pymammotion/mammotion/commands/messages/media.py +36 -0
- pymammotion/mammotion/commands/messages/navigation.py +535 -0
- pymammotion/mammotion/commands/messages/network.py +236 -0
- pymammotion/mammotion/commands/messages/ota.py +34 -0
- pymammotion/mammotion/commands/messages/system.py +266 -0
- pymammotion/mammotion/commands/messages/video.py +27 -0
- pymammotion/mammotion/control/__init__.py +0 -0
- pymammotion/mammotion/control/joystick.py +184 -0
- pymammotion/mammotion/devices/__init__.py +1 -0
- pymammotion/mammotion/devices/luba.py +564 -0
- pymammotion/mqtt/mqtt.py +230 -0
- pymammotion/proto/__init__.py +0 -0
- pymammotion/proto/common.proto +7 -0
- pymammotion/proto/common.py +12 -0
- pymammotion/proto/common_pb2.py +25 -0
- pymammotion/proto/common_pb2.pyi +13 -0
- pymammotion/proto/dev_net.proto +297 -0
- pymammotion/proto/dev_net.py +381 -0
- pymammotion/proto/dev_net_pb2.py +107 -0
- pymammotion/proto/dev_net_pb2.pyi +472 -0
- pymammotion/proto/luba_msg.proto +73 -0
- pymammotion/proto/luba_msg.py +80 -0
- pymammotion/proto/luba_msg_pb2.py +40 -0
- pymammotion/proto/luba_msg_pb2.pyi +93 -0
- pymammotion/proto/luba_mul.proto +68 -0
- pymammotion/proto/luba_mul.py +76 -0
- pymammotion/proto/luba_mul_pb2.py +45 -0
- pymammotion/proto/luba_mul_pb2.pyi +91 -0
- pymammotion/proto/mctrl_driver.proto +67 -0
- pymammotion/proto/mctrl_driver.py +100 -0
- pymammotion/proto/mctrl_driver_pb2.py +45 -0
- pymammotion/proto/mctrl_driver_pb2.pyi +112 -0
- pymammotion/proto/mctrl_nav.proto +485 -0
- pymammotion/proto/mctrl_nav.py +589 -0
- pymammotion/proto/mctrl_nav_pb2.py +116 -0
- pymammotion/proto/mctrl_nav_pb2.pyi +875 -0
- pymammotion/proto/mctrl_ota.proto +42 -0
- pymammotion/proto/mctrl_ota.py +48 -0
- pymammotion/proto/mctrl_ota_pb2.py +35 -0
- pymammotion/proto/mctrl_ota_pb2.pyi +65 -0
- pymammotion/proto/mctrl_pept.proto +29 -0
- pymammotion/proto/mctrl_pept.py +41 -0
- pymammotion/proto/mctrl_pept_pb2.py +31 -0
- pymammotion/proto/mctrl_pept_pb2.pyi +50 -0
- pymammotion/proto/mctrl_sys.proto +487 -0
- pymammotion/proto/mctrl_sys.py +574 -0
- pymammotion/proto/mctrl_sys_pb2.py +142 -0
- pymammotion/proto/mctrl_sys_pb2.pyi +787 -0
- pymammotion/py.typed +0 -0
- pymammotion/utility/constant/__init__.py +1 -0
- pymammotion/utility/constant/device_constant.py +238 -0
- pymammotion/utility/datatype_converter.py +80 -0
- pymammotion/utility/device_type.py +152 -0
- pymammotion/utility/periodic.py +41 -0
- pymammotion/utility/rocker_util.py +135 -0
- pymammotion-0.0.37.dist-info/LICENSE +674 -0
- pymammotion-0.0.37.dist-info/METADATA +92 -0
- pymammotion-0.0.37.dist-info/RECORD +106 -0
- pymammotion-0.0.37.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
from typing import List, Optional
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class RegionData:
|
|
5
|
+
def __init__(self):
|
|
6
|
+
self.hash: Optional[int] = None
|
|
7
|
+
self.action: int = 0
|
|
8
|
+
self.current_frame: int = 0
|
|
9
|
+
self.data_hash: Optional[int] = None
|
|
10
|
+
self.data_len: int = 0
|
|
11
|
+
self.p_hash_a: Optional[int] = None
|
|
12
|
+
self.p_hash_b: Optional[int] = None
|
|
13
|
+
self.path: Optional[List[List[float]]] = None
|
|
14
|
+
self.pver: int = 0
|
|
15
|
+
self.result: int = 0
|
|
16
|
+
self.sub_cmd: int = 0
|
|
17
|
+
self.total_frame: int = 0
|
|
18
|
+
self.type: int = 0
|
|
19
|
+
|
|
20
|
+
def set_hash(self, hash: int) -> None:
|
|
21
|
+
self.hash = hash
|
|
22
|
+
|
|
23
|
+
def get_data_len(self) -> int:
|
|
24
|
+
return self.data_len
|
|
25
|
+
|
|
26
|
+
def set_data_len(self, data_len: int) -> None:
|
|
27
|
+
self.data_len = data_len
|
|
28
|
+
|
|
29
|
+
def get_pver(self) -> int:
|
|
30
|
+
return self.pver
|
|
31
|
+
|
|
32
|
+
def set_pver(self, pver: int) -> None:
|
|
33
|
+
self.pver = pver
|
|
34
|
+
|
|
35
|
+
def get_sub_cmd(self) -> int:
|
|
36
|
+
return self.sub_cmd
|
|
37
|
+
|
|
38
|
+
def set_sub_cmd(self, sub_cmd: int) -> None:
|
|
39
|
+
self.sub_cmd = sub_cmd
|
|
40
|
+
|
|
41
|
+
def get_result(self) -> int:
|
|
42
|
+
return self.result
|
|
43
|
+
|
|
44
|
+
def set_result(self, result: int) -> None:
|
|
45
|
+
self.result = result
|
|
46
|
+
|
|
47
|
+
def get_action(self) -> int:
|
|
48
|
+
return self.action
|
|
49
|
+
|
|
50
|
+
def set_action(self, action: int) -> None:
|
|
51
|
+
self.action = action
|
|
52
|
+
|
|
53
|
+
def get_type(self) -> int:
|
|
54
|
+
return self.type
|
|
55
|
+
|
|
56
|
+
def set_type(self, type: int) -> None:
|
|
57
|
+
self.type = type
|
|
58
|
+
|
|
59
|
+
def get_total_frame(self) -> int:
|
|
60
|
+
return self.total_frame
|
|
61
|
+
|
|
62
|
+
def set_total_frame(self, total_frame: int) -> None:
|
|
63
|
+
self.total_frame = total_frame
|
|
64
|
+
|
|
65
|
+
def get_current_frame(self) -> int:
|
|
66
|
+
return self.current_frame
|
|
67
|
+
|
|
68
|
+
def set_current_frame(self, current_frame: int) -> None:
|
|
69
|
+
self.current_frame = current_frame
|
|
70
|
+
|
|
71
|
+
def get_path(self) -> Optional[List[List[float]]]:
|
|
72
|
+
return self.path
|
|
73
|
+
|
|
74
|
+
def set_path(self, path: List[List[float]]) -> None:
|
|
75
|
+
self.path = path
|
|
76
|
+
|
|
77
|
+
def get_hash(self) -> Optional[int]:
|
|
78
|
+
return self.hash
|
|
79
|
+
|
|
80
|
+
def set_data_hash(self, data_hash: int) -> None:
|
|
81
|
+
self.data_hash = data_hash
|
|
82
|
+
|
|
83
|
+
def get_data_hash(self) -> Optional[int]:
|
|
84
|
+
return self.data_hash
|
|
85
|
+
|
|
86
|
+
def set_p_hash_a(self, p_hash_a: int) -> None:
|
|
87
|
+
self.p_hash_a = p_hash_a
|
|
88
|
+
|
|
89
|
+
def get_p_hash_a(self) -> Optional[int]:
|
|
90
|
+
return self.p_hash_a
|
|
91
|
+
|
|
92
|
+
def set_p_hash_b(self, p_hash_b: int) -> None:
|
|
93
|
+
self.p_hash_b = p_hash_b
|
|
94
|
+
|
|
95
|
+
def get_p_hash_b(self) -> Optional[int]:
|
|
96
|
+
return self.p_hash_b
|
|
97
|
+
|
|
98
|
+
def __str__(self) -> str:
|
|
99
|
+
return f"RegionData{{pver={self.pver}, sub_cmd={self.sub_cmd}, result={self.result}, action={self.action}, type={self.type}, Hash={self.hash}, total_frame={self.total_frame}, current_frame={self.current_frame}, data_hash={self.data_hash}, p_hash_a={self.p_hash_a}, p_hash_b={self.p_hash_b}, data_len={self.data_len}, path={self.path}}}"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
from base64 import b64decode
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import Any, Literal, Union
|
|
4
|
+
|
|
5
|
+
from google.protobuf import json_format
|
|
6
|
+
from mashumaro.mixins.orjson import DataClassORJSONMixin
|
|
7
|
+
from mashumaro.types import SerializableType
|
|
8
|
+
|
|
9
|
+
from pyluba.proto import luba_msg_pb2
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Base64EncodedProtobuf(SerializableType):
|
|
13
|
+
def __init__(self, proto: str):
|
|
14
|
+
self.proto = proto
|
|
15
|
+
|
|
16
|
+
def _serialize(self):
|
|
17
|
+
return self.proto
|
|
18
|
+
|
|
19
|
+
@classmethod
|
|
20
|
+
def _deserialize(cls, value):
|
|
21
|
+
return cls(*value)
|
|
22
|
+
|
|
23
|
+
@classmethod
|
|
24
|
+
def __get_validators__(cls):
|
|
25
|
+
yield cls.validate
|
|
26
|
+
|
|
27
|
+
@classmethod
|
|
28
|
+
def validate(cls, v: str):
|
|
29
|
+
if not isinstance(v, str):
|
|
30
|
+
raise TypeError("string required")
|
|
31
|
+
binary = b64decode(v, validate=True)
|
|
32
|
+
data = luba_msg_pb2.LubaMsg()
|
|
33
|
+
data.ParseFromString(binary)
|
|
34
|
+
return json_format.MessageToDict(data)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class DeviceProtobufMsgEventValue(DataClassORJSONMixin):
|
|
39
|
+
content: Base64EncodedProtobuf
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclass
|
|
43
|
+
class DeviceWarningEventValue(DataClassORJSONMixin):
|
|
44
|
+
# TODO: enum for error codes
|
|
45
|
+
# (see resources/res/values-en-rUS/strings.xml in APK)
|
|
46
|
+
code: int
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@dataclass
|
|
50
|
+
class GeneralParams(DataClassORJSONMixin):
|
|
51
|
+
identifier: str
|
|
52
|
+
groupIdList: list[str]
|
|
53
|
+
groupId: str
|
|
54
|
+
categoryKey: Literal["LawnMower"]
|
|
55
|
+
batchId: str
|
|
56
|
+
gmtCreate: int
|
|
57
|
+
productKey: str
|
|
58
|
+
type: str
|
|
59
|
+
deviceName: str
|
|
60
|
+
iotId: str
|
|
61
|
+
checkLevel: int
|
|
62
|
+
namespace: str
|
|
63
|
+
tenantId: str
|
|
64
|
+
name: str
|
|
65
|
+
thingType: Literal["DEVICE"]
|
|
66
|
+
time: int
|
|
67
|
+
tenantInstanceId: str
|
|
68
|
+
value: Any
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@dataclass
|
|
72
|
+
class DeviceProtobufMsgEventParams(GeneralParams):
|
|
73
|
+
identifier: Literal["device_protobuf_msg_event"]
|
|
74
|
+
type: Literal["info"]
|
|
75
|
+
value: DeviceProtobufMsgEventValue
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@dataclass
|
|
79
|
+
class DeviceWarningEventParams(GeneralParams):
|
|
80
|
+
identifier: Literal["device_warning_event"]
|
|
81
|
+
type: Literal["alert"]
|
|
82
|
+
value: DeviceWarningEventValue
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@dataclass
|
|
86
|
+
class ThingEventMessage(DataClassORJSONMixin):
|
|
87
|
+
method: Literal["thing.events"]
|
|
88
|
+
id: str
|
|
89
|
+
params: Union[DeviceProtobufMsgEventParams, DeviceWarningEventParams]
|
|
90
|
+
version: Literal["1.0"]
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Generic, Literal, TypeVar, Union
|
|
3
|
+
|
|
4
|
+
from mashumaro import DataClassDictMixin
|
|
5
|
+
from mashumaro.mixins.orjson import DataClassORJSONMixin
|
|
6
|
+
|
|
7
|
+
DataT = TypeVar("DataT")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class Item(DataClassDictMixin, Generic[DataT]):
|
|
12
|
+
time: int
|
|
13
|
+
value: DataT
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class BatteryPercentageItems(DataClassORJSONMixin):
|
|
18
|
+
batteryPercentage: Item[int]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass
|
|
22
|
+
class BMSHardwareVersionItems(DataClassORJSONMixin):
|
|
23
|
+
bmsHardwareVersion: Item[str]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class CoordinateItems(DataClassORJSONMixin):
|
|
28
|
+
coordinate: Item[str] # '{"lon":0.303903,"lat":1.051868}'
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass
|
|
32
|
+
class DeviceStateItems(DataClassORJSONMixin):
|
|
33
|
+
deviceState: Item[int]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass
|
|
37
|
+
class DeviceVersionItems(DataClassORJSONMixin):
|
|
38
|
+
deviceVersion: Item[str]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass
|
|
42
|
+
class DeviceVersionInfoItems(DataClassORJSONMixin):
|
|
43
|
+
deviceVersionInfo: Item[str]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass
|
|
47
|
+
class ESP32VersionItems(DataClassORJSONMixin):
|
|
48
|
+
esp32Version: Item[str]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass
|
|
52
|
+
class LeftMotorBootVersionItems(DataClassORJSONMixin):
|
|
53
|
+
leftMotorBootVersion: Item[str]
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@dataclass
|
|
57
|
+
class LeftMotorVersionItems(DataClassORJSONMixin):
|
|
58
|
+
leftMotorVersion: Item[str]
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@dataclass
|
|
62
|
+
class MCBootVersionItems(DataClassORJSONMixin):
|
|
63
|
+
mcBootVersion: Item[str]
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@dataclass
|
|
67
|
+
class NetworkInfoItems(DataClassORJSONMixin):
|
|
68
|
+
networkInfo: Item[str]
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@dataclass
|
|
72
|
+
class RightMotorBootVersionItems(DataClassORJSONMixin):
|
|
73
|
+
rightMotorBootVersion: Item[str]
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@dataclass
|
|
77
|
+
class RightMotorVersionItems(DataClassORJSONMixin):
|
|
78
|
+
rightMotorVersion: Item[str]
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@dataclass
|
|
82
|
+
class RTKVersionItems(DataClassORJSONMixin):
|
|
83
|
+
rtkVersion: Item[str]
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@dataclass
|
|
87
|
+
class StationRTKVersionItems(DataClassORJSONMixin):
|
|
88
|
+
stationRtkVersion: Item[str]
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@dataclass
|
|
92
|
+
class STM32H7VersionItems(DataClassORJSONMixin):
|
|
93
|
+
stm32H7Version: Item[str]
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
Items = Union[
|
|
97
|
+
BatteryPercentageItems,
|
|
98
|
+
BMSHardwareVersionItems,
|
|
99
|
+
CoordinateItems,
|
|
100
|
+
DeviceStateItems,
|
|
101
|
+
DeviceVersionItems,
|
|
102
|
+
DeviceVersionInfoItems,
|
|
103
|
+
ESP32VersionItems,
|
|
104
|
+
LeftMotorBootVersionItems,
|
|
105
|
+
LeftMotorVersionItems,
|
|
106
|
+
MCBootVersionItems,
|
|
107
|
+
NetworkInfoItems,
|
|
108
|
+
RightMotorBootVersionItems,
|
|
109
|
+
RightMotorVersionItems,
|
|
110
|
+
RTKVersionItems,
|
|
111
|
+
StationRTKVersionItems,
|
|
112
|
+
STM32H7VersionItems,
|
|
113
|
+
]
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@dataclass
|
|
117
|
+
class Params(DataClassORJSONMixin):
|
|
118
|
+
checkFailedData: dict
|
|
119
|
+
groupIdList: list[str]
|
|
120
|
+
groupId: str
|
|
121
|
+
categoryKey: Literal["LawnMower"]
|
|
122
|
+
batchId: str
|
|
123
|
+
gmtCreate: int
|
|
124
|
+
productKey: str
|
|
125
|
+
deviceName: str
|
|
126
|
+
iotId: str
|
|
127
|
+
checkLevel: int
|
|
128
|
+
namespace: str
|
|
129
|
+
tenantId: str
|
|
130
|
+
thingType: Literal["DEVICE"]
|
|
131
|
+
items: Items
|
|
132
|
+
tenantInstanceId: str
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@dataclass
|
|
136
|
+
class ThingPropertiesMessage(DataClassORJSONMixin):
|
|
137
|
+
method: Literal["thing.properties"]
|
|
138
|
+
id: str
|
|
139
|
+
params: Params
|
|
140
|
+
version: Literal["1.0"]
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from typing import Literal
|
|
4
|
+
|
|
5
|
+
from mashumaro.mixins.orjson import DataClassORJSONMixin
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class GroupIdListItem(DataClassORJSONMixin):
|
|
10
|
+
groupId: str
|
|
11
|
+
groupType: Literal["ISOLATION"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# are there other values?
|
|
15
|
+
class StatusType(Enum):
|
|
16
|
+
CONNECTED = 1
|
|
17
|
+
DISCONNECTED = 3
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class Status(DataClassORJSONMixin):
|
|
22
|
+
time: int
|
|
23
|
+
value: StatusType
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class Params(DataClassORJSONMixin):
|
|
28
|
+
groupIdList: list[GroupIdListItem]
|
|
29
|
+
netType: Literal["NET_WIFI"]
|
|
30
|
+
activeTime: int
|
|
31
|
+
ip: str
|
|
32
|
+
aliyunCommodityCode: Literal["iothub_senior"]
|
|
33
|
+
categoryKey: Literal["LawnMower"]
|
|
34
|
+
nodeType: Literal["DEVICE"]
|
|
35
|
+
productKey: str
|
|
36
|
+
statusLast: int
|
|
37
|
+
deviceName: str
|
|
38
|
+
iotId: str
|
|
39
|
+
namespace: str
|
|
40
|
+
tenantId: str
|
|
41
|
+
thingType: Literal["DEVICE"]
|
|
42
|
+
tenantInstanceId: str
|
|
43
|
+
categoryId: int
|
|
44
|
+
status: Status
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@dataclass
|
|
48
|
+
class ThingStatusMessage(DataClassORJSONMixin):
|
|
49
|
+
method: Literal["thing.status"]
|
|
50
|
+
id: str
|
|
51
|
+
params: Params
|
|
52
|
+
version: Literal["1.0"]
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Event:
|
|
5
|
+
def __init__(self):
|
|
6
|
+
self.__eventhandlers = []
|
|
7
|
+
|
|
8
|
+
def __iadd__(self, handler):
|
|
9
|
+
self.__eventhandlers.append(handler)
|
|
10
|
+
return self
|
|
11
|
+
|
|
12
|
+
def __isub__(self, handler):
|
|
13
|
+
self.__eventhandlers.remove(handler)
|
|
14
|
+
return self
|
|
15
|
+
|
|
16
|
+
async def __call__(self, *args, **kwargs):
|
|
17
|
+
await asyncio.gather(
|
|
18
|
+
*[handler(*args, **kwargs) for handler in self.__eventhandlers]
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class MoveEvent:
|
|
23
|
+
def __init__(self):
|
|
24
|
+
self.OnMoveFinished = Event()
|
|
25
|
+
|
|
26
|
+
async def MoveFinished(self):
|
|
27
|
+
# This function will be executed once blufi finishes after a movement command and will
|
|
28
|
+
# raise an event
|
|
29
|
+
await self.OnMoveFinished()
|
|
30
|
+
|
|
31
|
+
def AddSubscribersForMoveFinishedEvent(self, objMethod):
|
|
32
|
+
self.OnMoveFinished += objMethod
|
|
33
|
+
|
|
34
|
+
def RemoveSubscribersForMoveFinishedEvent(self, objMethod):
|
|
35
|
+
self.OnMoveFinished -= objMethod
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class BleNotificationEvent:
|
|
39
|
+
def __init__(self):
|
|
40
|
+
self.OnBleNotification = Event()
|
|
41
|
+
|
|
42
|
+
async def BleNotification(self, data: bytearray):
|
|
43
|
+
# This function will be executed when data is received.
|
|
44
|
+
await self.OnBleNotification(data)
|
|
45
|
+
|
|
46
|
+
def AddSubscribersForBleNotificationEvent(self, objMethod):
|
|
47
|
+
self.OnBleNotification += objMethod
|
|
48
|
+
|
|
49
|
+
def RemoveSubscribersForBleNotificationEvent(self, objMethod):
|
|
50
|
+
self.OnBleNotification -= objMethod
|
|
File without changes
|
pymammotion/http/http.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Generic, Literal, TypeVar
|
|
3
|
+
|
|
4
|
+
from aiohttp import ClientSession
|
|
5
|
+
from mashumaro import DataClassDictMixin
|
|
6
|
+
from mashumaro.mixins.orjson import DataClassORJSONMixin
|
|
7
|
+
|
|
8
|
+
from pyluba.const import MAMMOTION_CLIENT_ID, MAMMOTION_CLIENT_SECRET, MAMMOTION_DOMAIN
|
|
9
|
+
|
|
10
|
+
DataT = TypeVar("DataT")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class Response(DataClassDictMixin, Generic[DataT]):
|
|
15
|
+
data: DataT
|
|
16
|
+
code: int
|
|
17
|
+
msg: str
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class LoginResponseUserInformation(DataClassORJSONMixin):
|
|
22
|
+
areaCode: str
|
|
23
|
+
domainAbbreviation: str
|
|
24
|
+
email: str
|
|
25
|
+
userId: str
|
|
26
|
+
userAccount: str
|
|
27
|
+
authType: str
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class LoginResponseData(DataClassORJSONMixin):
|
|
32
|
+
access_token: str
|
|
33
|
+
token_type: Literal["bearer"]
|
|
34
|
+
refresh_token: str
|
|
35
|
+
expires_in: int
|
|
36
|
+
scope: Literal["read"]
|
|
37
|
+
grant_type: Literal["password"]
|
|
38
|
+
authorization_code: str
|
|
39
|
+
userInformation: LoginResponseUserInformation
|
|
40
|
+
jti: str
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class LubaHTTP:
|
|
44
|
+
def __init__(self, session: ClientSession, login: LoginResponseData):
|
|
45
|
+
self._session = session
|
|
46
|
+
self._session.headers["Authorization"] = f"Bearer {login.access_token}"
|
|
47
|
+
self._login = login
|
|
48
|
+
|
|
49
|
+
@classmethod
|
|
50
|
+
async def login(
|
|
51
|
+
cls, session: ClientSession, username: str, password: str
|
|
52
|
+
) -> Response[LoginResponseData]:
|
|
53
|
+
async with session.post(
|
|
54
|
+
"/user-server/v1/user/oauth/token",
|
|
55
|
+
params=dict(
|
|
56
|
+
username=username,
|
|
57
|
+
password=password,
|
|
58
|
+
client_id=MAMMOTION_CLIENT_ID,
|
|
59
|
+
client_secret=MAMMOTION_CLIENT_SECRET,
|
|
60
|
+
grant_type="password",
|
|
61
|
+
),
|
|
62
|
+
) as resp:
|
|
63
|
+
data = await resp.json()
|
|
64
|
+
print(data)
|
|
65
|
+
# TODO catch errors from mismatch user / password
|
|
66
|
+
# Assuming the data format matches the expected structure
|
|
67
|
+
login_response_data = LoginResponseData.from_dict(data["data"])
|
|
68
|
+
return Response(
|
|
69
|
+
data=login_response_data, code=data["code"], msg=data["msg"]
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
async def connect_http(username: str, password: str) -> LubaHTTP:
|
|
74
|
+
async with ClientSession(MAMMOTION_DOMAIN) as session:
|
|
75
|
+
login_response = await LubaHTTP.login(session, username, password)
|
|
76
|
+
return LubaHTTP(session, login_response.data)
|
|
File without changes
|
pymammotion/luba/base.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from typing import Callable, Optional
|
|
2
|
+
|
|
3
|
+
from pyluba.data.model.rapid_state import RapidState, RTKStatus
|
|
4
|
+
from pyluba.data.mqtt.status import StatusType
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BaseLuba:
|
|
8
|
+
def __init__(self):
|
|
9
|
+
self._rapid_state: Optional[RapidState] = None
|
|
10
|
+
self.on_pos_change: Optional[Callable[[float, float, float], None]] = None
|
|
11
|
+
self.on_rtk_change: Optional[Callable[[RTKStatus, float, int, int], None]] = (
|
|
12
|
+
None
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
self.on_warning: Optional[Callable[[int], None]] = None
|
|
16
|
+
|
|
17
|
+
self._status: Optional[StatusType] = None
|
|
18
|
+
self.on_status_change: Optional[Callable[[StatusType], None]] = None
|
|
19
|
+
|
|
20
|
+
def _set_rapid_state(self, state: RapidState):
|
|
21
|
+
old_state = self._rapid_state
|
|
22
|
+
self._rapid_state = state
|
|
23
|
+
if old_state:
|
|
24
|
+
if (
|
|
25
|
+
old_state.pos_x != state.pos_x
|
|
26
|
+
or old_state.pos_y != state.pos_y
|
|
27
|
+
or old_state.toward != state.toward
|
|
28
|
+
):
|
|
29
|
+
if self.on_pos_change:
|
|
30
|
+
self.on_pos_change(state.pos_x, state.pos_y, state.toward)
|
|
31
|
+
if (
|
|
32
|
+
old_state.rtk_status != state.rtk_status
|
|
33
|
+
or old_state.rtk_age != state.rtk_age
|
|
34
|
+
or old_state.satellites_total != state.satellites_total
|
|
35
|
+
or old_state.satellites_l2 != state.satellites_l2
|
|
36
|
+
):
|
|
37
|
+
if self.on_rtk_change:
|
|
38
|
+
self.on_rtk_change(
|
|
39
|
+
state.rtk_status,
|
|
40
|
+
state.rtk_age,
|
|
41
|
+
state.satellites_total,
|
|
42
|
+
state.satellites_l2,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
def _set_status(self, status: StatusType):
|
|
46
|
+
self._status = status
|
|
47
|
+
if self.on_status_change:
|
|
48
|
+
self.on_status_change(status)
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def status(self) -> Optional[StatusType]:
|
|
52
|
+
return self._status
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from pyluba.mammotion.commands.messages.navigation import MessageNavigation
|
|
2
|
+
from pyluba.mammotion.commands.messages.network import MessageNetwork
|
|
3
|
+
from pyluba.mammotion.commands.messages.ota import MessageOta
|
|
4
|
+
from pyluba.mammotion.commands.messages.system import MessageSystem
|
|
5
|
+
from pyluba.mammotion.commands.messages.video import MessageVideo
|
|
6
|
+
from pyluba.proto import dev_net_pb2, luba_msg_pb2
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class MammotionCommand(
|
|
10
|
+
MessageSystem, MessageNavigation, MessageNetwork, MessageOta, MessageVideo
|
|
11
|
+
):
|
|
12
|
+
"""MQTT commands for Luba."""
|
|
13
|
+
|
|
14
|
+
def __init__(self, device_name: str) -> None:
|
|
15
|
+
self._device_name = device_name
|
|
16
|
+
|
|
17
|
+
def get_device_name(self) -> str:
|
|
18
|
+
"""Get device name."""
|
|
19
|
+
return self._device_name
|
|
20
|
+
|
|
21
|
+
"""BLE commands for Luba."""
|
|
22
|
+
|
|
23
|
+
def send_todev_ble_sync(self, sync_type: int) -> bytes:
|
|
24
|
+
commEsp = dev_net_pb2.DevNet(todev_ble_sync=sync_type)
|
|
25
|
+
|
|
26
|
+
lubaMsg = luba_msg_pb2.LubaMsg()
|
|
27
|
+
lubaMsg.msgtype = luba_msg_pb2.MSG_CMD_TYPE_ESP
|
|
28
|
+
lubaMsg.sender = luba_msg_pb2.DEV_MOBILEAPP
|
|
29
|
+
lubaMsg.msgattr = luba_msg_pb2.MSG_ATTR_REQ
|
|
30
|
+
lubaMsg.seqs = 1
|
|
31
|
+
lubaMsg.version = 1
|
|
32
|
+
lubaMsg.subtype = 1
|
|
33
|
+
lubaMsg.net.CopyFrom(commEsp)
|
|
34
|
+
return lubaMsg.SerializeToString()
|
|
File without changes
|