pymammotion 0.2.62__py3-none-any.whl → 0.5.51__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.

Files changed (135) hide show
  1. pymammotion/__init__.py +9 -6
  2. pymammotion/aliyun/client.py +235 -0
  3. pymammotion/aliyun/cloud_gateway.py +320 -69
  4. pymammotion/aliyun/model/aep_response.py +1 -2
  5. pymammotion/aliyun/model/dev_by_account_response.py +170 -23
  6. pymammotion/aliyun/model/login_by_oauth_response.py +2 -3
  7. pymammotion/aliyun/model/regions_response.py +3 -3
  8. pymammotion/aliyun/model/session_by_authcode_response.py +2 -2
  9. pymammotion/aliyun/model/thing_response.py +12 -0
  10. pymammotion/aliyun/regions.py +62 -0
  11. pymammotion/aliyun/tea/core.py +297 -0
  12. pymammotion/bluetooth/ble.py +11 -15
  13. pymammotion/bluetooth/ble_message.py +389 -106
  14. pymammotion/bluetooth/model/atomic_integer.py +54 -0
  15. pymammotion/const.py +3 -0
  16. pymammotion/data/model/__init__.py +1 -2
  17. pymammotion/data/model/device.py +92 -240
  18. pymammotion/data/model/device_config.py +10 -24
  19. pymammotion/data/model/device_info.py +35 -0
  20. pymammotion/data/model/device_limits.py +49 -0
  21. pymammotion/data/model/enums.py +12 -2
  22. pymammotion/data/model/errors.py +12 -0
  23. pymammotion/data/model/events.py +14 -0
  24. pymammotion/data/model/generate_geojson.py +521 -0
  25. pymammotion/data/model/generate_route_information.py +3 -4
  26. pymammotion/data/model/hash_list.py +384 -48
  27. pymammotion/data/model/location.py +4 -4
  28. pymammotion/data/model/mowing_modes.py +24 -1
  29. pymammotion/data/model/raw_data.py +215 -0
  30. pymammotion/data/model/region_data.py +10 -11
  31. pymammotion/data/model/report_info.py +62 -6
  32. pymammotion/data/model/work.py +27 -0
  33. pymammotion/data/mower_state_manager.py +316 -0
  34. pymammotion/data/mqtt/event.py +73 -28
  35. pymammotion/data/mqtt/mammotion_properties.py +257 -0
  36. pymammotion/data/mqtt/properties.py +93 -78
  37. pymammotion/data/mqtt/status.py +18 -17
  38. pymammotion/event/event.py +32 -8
  39. pymammotion/homeassistant/__init__.py +3 -0
  40. pymammotion/homeassistant/mower_api.py +484 -0
  41. pymammotion/homeassistant/rtk_api.py +54 -0
  42. pymammotion/http/__init__.py +0 -0
  43. pymammotion/http/encryption.py +220 -0
  44. pymammotion/http/http.py +652 -44
  45. pymammotion/http/model/__init__.py +0 -0
  46. pymammotion/{aliyun/model/stream_subscription_response.py → http/model/camera_stream.py} +14 -2
  47. pymammotion/http/model/http.py +160 -9
  48. pymammotion/http/model/response_factory.py +61 -0
  49. pymammotion/http/model/rtk.py +16 -0
  50. pymammotion/mammotion/commands/abstract_message.py +7 -5
  51. pymammotion/mammotion/commands/mammotion_command.py +32 -3
  52. pymammotion/mammotion/commands/messages/basestation.py +43 -0
  53. pymammotion/mammotion/commands/messages/driver.py +61 -29
  54. pymammotion/mammotion/commands/messages/media.py +68 -15
  55. pymammotion/mammotion/commands/messages/navigation.py +61 -25
  56. pymammotion/mammotion/commands/messages/network.py +93 -100
  57. pymammotion/mammotion/commands/messages/ota.py +18 -18
  58. pymammotion/mammotion/commands/messages/system.py +97 -72
  59. pymammotion/mammotion/commands/messages/video.py +17 -12
  60. pymammotion/mammotion/devices/__init__.py +27 -3
  61. pymammotion/mammotion/devices/base.py +50 -127
  62. pymammotion/mammotion/devices/mammotion.py +447 -212
  63. pymammotion/mammotion/devices/mammotion_bluetooth.py +105 -60
  64. pymammotion/mammotion/devices/mammotion_cloud.py +157 -105
  65. pymammotion/mammotion/devices/mammotion_mower_ble.py +49 -0
  66. pymammotion/mammotion/devices/mammotion_mower_cloud.py +39 -0
  67. pymammotion/mammotion/devices/managers/managers.py +81 -0
  68. pymammotion/mammotion/devices/mower_device.py +124 -0
  69. pymammotion/mammotion/devices/mower_manager.py +107 -0
  70. pymammotion/mammotion/devices/rtk_ble.py +89 -0
  71. pymammotion/mammotion/devices/rtk_cloud.py +113 -0
  72. pymammotion/mammotion/devices/rtk_device.py +50 -0
  73. pymammotion/mammotion/devices/rtk_manager.py +122 -0
  74. pymammotion/mqtt/__init__.py +2 -1
  75. pymammotion/mqtt/aliyun_mqtt.py +232 -0
  76. pymammotion/mqtt/linkkit/__init__.py +5 -0
  77. pymammotion/mqtt/linkkit/h2client.py +585 -0
  78. pymammotion/mqtt/linkkit/linkkit.py +3023 -0
  79. pymammotion/mqtt/mammotion_mqtt.py +176 -169
  80. pymammotion/mqtt/mqtt_models.py +66 -0
  81. pymammotion/proto/__init__.py +4839 -4
  82. pymammotion/proto/basestation.proto +8 -0
  83. pymammotion/proto/basestation_pb2.py +11 -9
  84. pymammotion/proto/basestation_pb2.pyi +16 -2
  85. pymammotion/proto/dev_net.proto +79 -55
  86. pymammotion/proto/dev_net_pb2.py +60 -56
  87. pymammotion/proto/dev_net_pb2.pyi +49 -6
  88. pymammotion/proto/luba_msg.proto +2 -1
  89. pymammotion/proto/luba_msg_pb2.py +6 -6
  90. pymammotion/proto/luba_msg_pb2.pyi +1 -0
  91. pymammotion/proto/luba_mul.proto +62 -1
  92. pymammotion/proto/luba_mul_pb2.py +38 -22
  93. pymammotion/proto/luba_mul_pb2.pyi +94 -7
  94. pymammotion/proto/mctrl_driver.proto +44 -4
  95. pymammotion/proto/mctrl_driver_pb2.py +26 -14
  96. pymammotion/proto/mctrl_driver_pb2.pyi +66 -11
  97. pymammotion/proto/mctrl_nav.proto +97 -51
  98. pymammotion/proto/mctrl_nav_pb2.py +75 -67
  99. pymammotion/proto/mctrl_nav_pb2.pyi +142 -56
  100. pymammotion/proto/mctrl_ota.proto +40 -2
  101. pymammotion/proto/mctrl_ota_pb2.py +23 -13
  102. pymammotion/proto/mctrl_ota_pb2.pyi +67 -4
  103. pymammotion/proto/mctrl_pept.proto +8 -3
  104. pymammotion/proto/mctrl_pept_pb2.py +8 -6
  105. pymammotion/proto/mctrl_pept_pb2.pyi +14 -6
  106. pymammotion/proto/mctrl_sys.proto +325 -86
  107. pymammotion/proto/mctrl_sys_pb2.py +162 -98
  108. pymammotion/proto/mctrl_sys_pb2.pyi +451 -25
  109. pymammotion/proto/message_pool.py +3 -0
  110. pymammotion/proto/py.typed +0 -0
  111. pymammotion/utility/constant/device_constant.py +65 -21
  112. pymammotion/utility/datatype_converter.py +13 -12
  113. pymammotion/utility/device_config.py +755 -0
  114. pymammotion/utility/device_type.py +218 -21
  115. pymammotion/utility/map.py +238 -51
  116. pymammotion/utility/mur_mur_hash.py +159 -0
  117. {pymammotion-0.2.62.dist-info → pymammotion-0.5.51.dist-info}/METADATA +27 -31
  118. pymammotion-0.5.51.dist-info/RECORD +152 -0
  119. {pymammotion-0.2.62.dist-info → pymammotion-0.5.51.dist-info}/WHEEL +1 -1
  120. pymammotion/aliyun/cloud_service.py +0 -65
  121. pymammotion/data/model/plan.py +0 -58
  122. pymammotion/data/state_manager.py +0 -130
  123. pymammotion/proto/basestation.py +0 -59
  124. pymammotion/proto/common.py +0 -12
  125. pymammotion/proto/dev_net.py +0 -381
  126. pymammotion/proto/luba_msg.py +0 -81
  127. pymammotion/proto/luba_mul.py +0 -76
  128. pymammotion/proto/mctrl_driver.py +0 -100
  129. pymammotion/proto/mctrl_nav.py +0 -660
  130. pymammotion/proto/mctrl_ota.py +0 -48
  131. pymammotion/proto/mctrl_pept.py +0 -41
  132. pymammotion/proto/mctrl_sys.py +0 -574
  133. pymammotion-0.2.62.dist-info/RECORD +0 -125
  134. /pymammotion/{http/_init_.py → bluetooth/model/__init__.py} +0 -0
  135. {pymammotion-0.2.62.dist-info → pymammotion-0.5.51.dist-info/licenses}/LICENSE +0 -0
@@ -0,0 +1,257 @@
1
+ from dataclasses import dataclass
2
+ from typing import Annotated
3
+
4
+ from mashumaro.config import BaseConfig
5
+ from mashumaro.mixins.orjson import DataClassORJSONMixin
6
+ from mashumaro.types import Alias
7
+
8
+
9
+ @dataclass
10
+ class FirmwareInfo(DataClassORJSONMixin):
11
+ t: str
12
+ c: str
13
+ v: str
14
+
15
+
16
+ @dataclass
17
+ class DeviceVersionInfo(DataClassORJSONMixin):
18
+ dev_ver: Annotated[str, Alias("devVer")]
19
+ whole: int
20
+ fw_info: Annotated[list[FirmwareInfo], Alias("fwInfo")]
21
+
22
+
23
+ @dataclass
24
+ class Coordinate(DataClassORJSONMixin):
25
+ lon: float
26
+ lat: float
27
+
28
+
29
+ @dataclass
30
+ class InternalNavigation(DataClassORJSONMixin):
31
+ nav: Annotated[str, Alias("NAV")]
32
+ pau: Annotated[str, Alias("Pau")]
33
+ r_pau: Annotated[str, Alias("rPau")]
34
+ mcu: Annotated[str, Alias("MCU")]
35
+ app: Annotated[str, Alias("APP")]
36
+ w_slp: Annotated[str, Alias("wSlp")]
37
+ i_slp: Annotated[str, Alias("iSlp")]
38
+
39
+
40
+ @dataclass
41
+ class BandwidthTraffic(DataClassORJSONMixin):
42
+ iot: Annotated[str, Alias("IoT")]
43
+ roi: Annotated[str, Alias("RoI")]
44
+ fpv: Annotated[str, Alias("FPV")]
45
+ inav: InternalNavigation
46
+
47
+
48
+ @dataclass
49
+ class TrafficPeriod(DataClassORJSONMixin):
50
+ r: str
51
+ t: str
52
+ s: str
53
+
54
+
55
+ @dataclass
56
+ class TrafficData(DataClassORJSONMixin):
57
+ upt: str
58
+ hour: Annotated[dict[str, TrafficPeriod], Alias("Hour")]
59
+ day: Annotated[dict[str, TrafficPeriod], Alias("Day")]
60
+ mon: Annotated[dict[str, TrafficPeriod], Alias("Mon")]
61
+
62
+
63
+ @dataclass
64
+ class NetworkInfo(DataClassORJSONMixin):
65
+ ssid: str
66
+ ip: str
67
+ wifi_sta_mac: str
68
+ wifi_rssi: int
69
+ wifi_available: int
70
+ bt_mac: str
71
+ mnet_model: str
72
+ imei: str
73
+ fw_ver: str
74
+ sim: str
75
+ imsi: str
76
+ iccid: str
77
+ sim_source: str
78
+ mnet_rssi: int
79
+ signal: int
80
+ mnet_link: int
81
+ mnet_option: str
82
+ mnet_ip: str
83
+ mnet_reg: str
84
+ mnet_rsrp: str
85
+ mnet_snr: str
86
+ mnet_enable: int
87
+ apn_num: int
88
+ apn_info: str
89
+ apn_cid: int
90
+ used_net: int
91
+ hub_reset: int
92
+ mnet_dis: int
93
+ airplane_times: int
94
+ lsusb_num: int
95
+ b_tra: Annotated[BandwidthTraffic, Alias("bTra")]
96
+ bw_tra: Annotated[BandwidthTraffic, Alias("bwTra")]
97
+ mnet_rx: str
98
+ mnet_tx: str
99
+ m_tra: Annotated[TrafficData, Alias("mTra")]
100
+ mnet_uniot: int
101
+ mnet_un_getiot: int
102
+ ssh_flag: str
103
+ mileage: str
104
+ work_time: str
105
+ wt_sec: int
106
+ bat_cycles: str
107
+
108
+
109
+ @dataclass
110
+ class DeviceOtherInfo(DataClassORJSONMixin):
111
+ soc_up_time: Annotated[int, Alias("socUpTime")]
112
+ mcu_up_time: Annotated[int, Alias("mcuUpTime")]
113
+ soc_loads: Annotated[str, Alias("socLoads")]
114
+ soc_mem_free: Annotated[int, Alias("socMemFree")]
115
+ soc_mem_total: Annotated[int, Alias("socMemTotal")]
116
+ soc_mmc_life_time: Annotated[int, Alias("socMmcLifeTime")]
117
+ usb_dis_cnt: Annotated[int, Alias("usbDisCnt")]
118
+ soc_pstore: Annotated[int, Alias("socPstore")]
119
+ soc_coredump: Annotated[int, Alias("socCoredump")]
120
+ soc_tmp: Annotated[int, Alias("socTmp")]
121
+ mc_mcu: Annotated[str, Alias("mcMcu")]
122
+ tilt_degree: str
123
+ i_msg_free: Annotated[int, Alias("iMsgFree")]
124
+ i_msg_limit: Annotated[int, Alias("iMsgLimit")]
125
+ i_msg_raw: Annotated[int, Alias("iMsgRaw")]
126
+ i_msg_prop: Annotated[int, Alias("iMsgprop")]
127
+ i_msg_serv: Annotated[int, Alias("iMsgServ")]
128
+ i_msg_info: Annotated[int, Alias("iMsgInfo")]
129
+ i_msg_warn: Annotated[int, Alias("iMsgWarn")]
130
+ i_msg_fault: Annotated[int, Alias("iMsgFault")]
131
+ i_msg_ota_stage: Annotated[int, Alias("iMsgOtaStage")]
132
+ i_msg_protobuf: Annotated[int, Alias("iMsgProtobuf")]
133
+ i_msg_notify: Annotated[int, Alias("iMsgNotify")]
134
+ i_msg_log_prog: Annotated[int, Alias("iMsgLogProg")]
135
+ i_msg_biz_req: Annotated[int, Alias("iMsgBizReq")]
136
+ i_msg_cfg_req: Annotated[int, Alias("iMsgCfgReq")]
137
+ i_msg_voice: Annotated[int, Alias("iMsgVoice")]
138
+ i_msg_warn_code: Annotated[int, Alias("iMsgWarnCode")]
139
+ pb_net: Annotated[int, Alias("pbNet")]
140
+ pb_sys: Annotated[int, Alias("pbSys")]
141
+ pb_nav: Annotated[int, Alias("pbNav")]
142
+ pb_local: Annotated[int, Alias("pbLocal")]
143
+ pb_plan: Annotated[int, Alias("pbPlan")]
144
+ pb_e_drv: Annotated[int, Alias("pbEDrv")]
145
+ pb_e_sys: Annotated[int, Alias("pbESys")]
146
+ pb_midware: Annotated[int, Alias("pbMidware")]
147
+ pb_ota: Annotated[int, Alias("pbOta")]
148
+ pb_appl: Annotated[int, Alias("pbAppl")]
149
+ pb_mul: Annotated[int, Alias("pbMul")]
150
+ pb_other: Annotated[int, Alias("pbOther")]
151
+ lora_connect: Annotated[int, Alias("loraConnect")]
152
+ base_status: Annotated[int, Alias("Basestatus")]
153
+ mqtt_rtk_switch: int
154
+ mqtt_rtk_channel: int
155
+ mqtt_rtk_status: int
156
+ mqtt_rtcm_cnt: int
157
+ mqtt_conn_cnt: int
158
+ mqtt_disconn_cnt: int
159
+ mqtt_rtk_hb_flag: int
160
+ mqtt_rtk_hb_count: int
161
+ mqtt_start_cnt: int
162
+ mqtt_close_cnt: int
163
+ mqtt_rtk_ssl_fail: int
164
+ mqtt_rtk_wifi_config: int
165
+ nrtk_svc_prov: int
166
+ nrtk_svc_err: int
167
+ base_stn_id: int
168
+ rtk_status: int
169
+ charge_status: int
170
+ chassis_state: int
171
+ nav: str
172
+ ins_fusion: str
173
+ perception: str
174
+ vision_proxy: str
175
+ vslam_vio: str
176
+ iot_con_timeout: int
177
+ iot_con: int
178
+ iot_con_fail_max: str
179
+ iot_con_fail_min: Annotated[str, Alias("iot_con__fail_min")]
180
+ iot_url_count: int
181
+ iot_url_max: str
182
+ iot_url_min: str
183
+ iot_cn: int
184
+ iot_ap: int
185
+ iot_us: int
186
+ iot_eu: int
187
+ task_area: float
188
+ task_count: int
189
+ task_hash: str
190
+ systemio_boot_time: Annotated[str, Alias("systemioBootTime")]
191
+ dds_no_gdc: int
192
+
193
+
194
+ @dataclass
195
+ class CheckData(DataClassORJSONMixin):
196
+ result: str
197
+ error: Annotated[list[int], Alias("Error")]
198
+ warn: Annotated[list[int], Alias("Warn")]
199
+ ok: Annotated[list[int], Alias("OK")]
200
+
201
+
202
+ @dataclass
203
+ class DeviceProperties(DataClassORJSONMixin):
204
+ device_state: Annotated[int, Alias("deviceState")]
205
+ battery_percentage: Annotated[int, Alias("batteryPercentage")]
206
+ device_version: Annotated[str, Alias("deviceVersion")]
207
+ knife_height: Annotated[int, Alias("knifeHeight")]
208
+ lora_general_config: Annotated[str, Alias("loraGeneralConfig")]
209
+ ext_mod: Annotated[str, Alias("extMod")]
210
+ int_mod: Annotated[str, Alias("intMod")]
211
+ iot_state: Annotated[int, Alias("iotState")]
212
+ iot_msg_total: Annotated[int, Alias("iotMsgTotal")]
213
+ iot_msg_hz: Annotated[int, Alias("iotMsgHz")]
214
+ lt_mr_mod: Annotated[str, Alias("ltMrMod")]
215
+ rt_mr_mod: Annotated[str, Alias("rtMrMod")]
216
+ bms_hardware_version: Annotated[str, Alias("bmsHardwareVersion")]
217
+ stm32_h7_version: Annotated[str, Alias("stm32H7Version")]
218
+ left_motor_version: Annotated[str, Alias("leftMotorVersion")]
219
+ right_motor_version: Annotated[str, Alias("rightMotorVersion")]
220
+ rtk_version: Annotated[str, Alias("rtkVersion")]
221
+ bms_version: Annotated[str, Alias("bmsVersion")]
222
+ mc_boot_version: Annotated[str, Alias("mcBootVersion")]
223
+ left_motor_boot_version: Annotated[str, Alias("leftMotorBootVersion")]
224
+ right_motor_boot_version: Annotated[str, Alias("rightMotorBootVersion")]
225
+
226
+ # Nested JSON objects
227
+ device_version_info: Annotated[DeviceVersionInfo, Alias("deviceVersionInfo")]
228
+ coordinate: Coordinate
229
+ device_other_info: Annotated[DeviceOtherInfo, Alias("deviceOtherInfo")]
230
+ network_info: Annotated[NetworkInfo, Alias("networkInfo")]
231
+ check_data: Annotated[CheckData, Alias("checkData")]
232
+ iot_id: str = ""
233
+
234
+ class Config(BaseConfig):
235
+ # Custom deserializer for nested JSON strings
236
+ serialization_strategy = {
237
+ DeviceVersionInfo: {
238
+ "deserialize": lambda x: DeviceVersionInfo.from_json(x) if isinstance(x, str) else x,
239
+ "serialize": lambda x: x.to_json() if hasattr(x, "to_json") else x,
240
+ },
241
+ Coordinate: {
242
+ "deserialize": lambda x: Coordinate.from_json(x) if isinstance(x, str) else x,
243
+ "serialize": lambda x: x.to_json() if hasattr(x, "to_json") else x,
244
+ },
245
+ DeviceOtherInfo: {
246
+ "deserialize": lambda x: DeviceOtherInfo.from_json(x) if isinstance(x, str) else x,
247
+ "serialize": lambda x: x.to_json() if hasattr(x, "to_json") else x,
248
+ },
249
+ NetworkInfo: {
250
+ "deserialize": lambda x: NetworkInfo.from_json(x) if isinstance(x, str) else x,
251
+ "serialize": lambda x: x.to_json() if hasattr(x, "to_json") else x,
252
+ },
253
+ CheckData: {
254
+ "deserialize": lambda x: CheckData.from_json(x) if isinstance(x, str) else x,
255
+ "serialize": lambda x: x.to_json() if hasattr(x, "to_json") else x,
256
+ },
257
+ }
@@ -1,99 +1,104 @@
1
1
  from dataclasses import dataclass
2
- from typing import Any, Generic, Literal, TypeVar, Union
2
+ from typing import Annotated, Any, Literal, Union
3
3
 
4
4
  from mashumaro import DataClassDictMixin
5
5
  from mashumaro.mixins.orjson import DataClassORJSONMixin
6
+ from mashumaro.types import Alias
6
7
 
7
- DataT = TypeVar("DataT")
8
-
9
-
10
- @dataclass
11
- class Item(DataClassDictMixin, Generic[DataT]):
12
- time: int
13
- value: DataT
8
+ from pymammotion.data.mqtt.mammotion_properties import DeviceProperties
14
9
 
15
10
 
16
11
  @dataclass
17
12
  class BatteryPercentageItems(DataClassORJSONMixin):
18
- batteryPercentage: Item[int]
13
+ batteryPercentage: int
19
14
 
20
15
 
21
16
  @dataclass
22
17
  class BMSHardwareVersionItems(DataClassORJSONMixin):
23
- bmsHardwareVersion: Item[str]
18
+ bmsHardwareVersion: str
24
19
 
25
20
 
26
21
  @dataclass
27
22
  class CoordinateItems(DataClassORJSONMixin):
28
- coordinate: Item[str] # '{"lon":0.303903,"lat":1.051868}'
23
+ coordinate: str # '{"lon":0.303903,"lat":1.051868}'
29
24
 
30
25
 
31
26
  @dataclass
32
27
  class DeviceStateItems(DataClassORJSONMixin):
33
- deviceState: Item[int]
28
+ deviceState: int
34
29
 
35
30
 
36
31
  @dataclass
37
32
  class DeviceVersionItems(DataClassORJSONMixin):
38
- deviceVersion: Item[str]
33
+ deviceVersion: str
39
34
 
40
35
 
41
36
  @dataclass
42
37
  class DeviceVersionInfoItems(DataClassORJSONMixin):
43
- deviceVersionInfo: Item[str]
38
+ deviceVersionInfo: str
44
39
 
45
40
 
46
41
  @dataclass
47
42
  class ESP32VersionItems(DataClassORJSONMixin):
48
- esp32Version: Item[str]
43
+ esp32Version: str
49
44
 
50
45
 
51
46
  @dataclass
52
47
  class LeftMotorBootVersionItems(DataClassORJSONMixin):
53
- leftMotorBootVersion: Item[str]
48
+ leftMotorBootVersion: str
54
49
 
55
50
 
56
51
  @dataclass
57
52
  class LeftMotorVersionItems(DataClassORJSONMixin):
58
- leftMotorVersion: Item[str]
53
+ leftMotorVersion: str
59
54
 
60
55
 
61
56
  @dataclass
62
57
  class MCBootVersionItems(DataClassORJSONMixin):
63
- mcBootVersion: Item[str]
58
+ mcBootVersion: str
64
59
 
65
60
 
66
61
  @dataclass
67
62
  class NetworkInfoItems(DataClassORJSONMixin):
68
- networkInfo: Item[str]
63
+ networkInfo: str
69
64
 
70
65
 
71
66
  @dataclass
72
67
  class RightMotorBootVersionItems(DataClassORJSONMixin):
73
- rightMotorBootVersion: Item[str]
68
+ rightMotorBootVersion: str
74
69
 
75
70
 
76
71
  @dataclass
77
72
  class RightMotorVersionItems(DataClassORJSONMixin):
78
- rightMotorVersion: Item[str]
73
+ rightMotorVersion: str
79
74
 
80
75
 
81
76
  @dataclass
82
77
  class RTKVersionItems(DataClassORJSONMixin):
83
- rtkVersion: Item[str]
78
+ rtkVersion: str
84
79
 
85
80
 
86
81
  @dataclass
87
82
  class StationRTKVersionItems(DataClassORJSONMixin):
88
- stationRtkVersion: Item[str]
83
+ stationRtkVersion: str
89
84
 
90
85
 
91
86
  @dataclass
92
87
  class STM32H7VersionItems(DataClassORJSONMixin):
93
- stm32H7Version: Item[str]
88
+ stm32H7Version: str
89
+
94
90
 
91
+ @dataclass
92
+ class OTAProgressItems(DataClassORJSONMixin):
93
+ result: int
94
+ otaId: str
95
+ progress: int
96
+ message: str
97
+ version: str
98
+ properties: str
95
99
 
96
- Items = Union[
100
+
101
+ ItemTypes = Union[
97
102
  BatteryPercentageItems,
98
103
  BMSHardwareVersionItems,
99
104
  CoordinateItems,
@@ -110,70 +115,72 @@ Items = Union[
110
115
  RTKVersionItems,
111
116
  StationRTKVersionItems,
112
117
  STM32H7VersionItems,
118
+ OTAProgressItems,
113
119
  ]
114
120
 
115
121
 
116
122
  @dataclass
117
- class Item:
123
+ class Item(DataClassDictMixin):
118
124
  time: int
119
- value: Union[int, float, str, dict[str, Any]] # Depending on the type of value
120
-
121
-
122
- @dataclass
123
- 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
125
+ value: int | float | str | dict[str, Any] | ItemTypes # Depending on the type of value
126
+
127
+
128
+ @dataclass
129
+ class Items(DataClassDictMixin):
130
+ iotState: Item | None = None
131
+ extMod: Item | None = None
132
+ deviceVersionInfo: Item | None = None
133
+ leftMotorBootVersion: Item | None = None
134
+ knifeHeight: Item | None = None
135
+ rtMrMod: Item | None = None
136
+ iotMsgHz: Item | None = None
137
+ iotMsgTotal: Item | None = None
138
+ loraRawConfig: Item | None = None
139
+ loraGeneralConfig: Item | None = None
140
+ leftMotorVersion: Item | None = None
141
+ intMod: Item | None = None
142
+ coordinate: Item | None = None
143
+ bmsVersion: Item | None = None
144
+ rightMotorVersion: Item | None = None
145
+ stm32H7Version: Item | None = None
146
+ rightMotorBootVersion: Item | None = None
147
+ deviceVersion: Item | None = None
148
+ rtkVersion: Item | None = None
149
+ ltMrMod: Item | None = None
150
+ networkInfo: Item | None = None
151
+ bmsHardwareVersion: Item | None = None
152
+ batteryPercentage: Item | None = None
153
+ deviceState: Item | None = None
154
+ deviceOtherInfo: Item | None = None
155
+ mcBootVersion: Item | None = None
156
+ otaProgress: Item | None = None
150
157
 
151
158
 
152
159
  @dataclass
153
160
  class Params(DataClassORJSONMixin):
154
- deviceType: Literal["LawnMower"]
155
- checkFailedData: dict
156
- groupIdList: list[str]
157
- _tenantId: str
158
- groupId: str
159
- categoryKey: Literal["LawnMower"]
160
- batchId: str
161
- gmtCreate: int
162
- productKey: str
163
- generateTime: int
164
- deviceName: str
165
- _traceId: str
166
- iotId: str
167
- JMSXDeliveryCount: int
168
- checkLevel: int
161
+ device_type: Annotated[Literal["LawnMower", "Tracker"], Alias("deviceType")]
162
+ check_failed_data: Annotated[dict[str, Any], Alias("checkFailedData")]
163
+ group_id_list: Annotated[list[str], Alias("groupIdList")]
164
+ _tenant_id: Annotated[str, Alias("_tenantId")]
165
+ group_id: Annotated[str, Alias("groupId")]
166
+ category_key: Annotated[Literal["LawnMower", "Tracker"], Alias("categoryKey")]
167
+ batch_id: Annotated[str, Alias("batchId")]
168
+ gmt_create: Annotated[int, Alias("gmtCreate")]
169
+ product_key: Annotated[str, Alias("productKey")]
170
+ generate_time: Annotated[int, Alias("generateTime")]
171
+ device_name: Annotated[str, Alias("deviceName")]
172
+ _trace_id: Annotated[str, Alias("_traceId")]
173
+ iot_id: Annotated[str, Alias("iotId")]
174
+ jmsx_delivery_count: Annotated[int, Alias("JMSXDeliveryCount")]
175
+ check_level: Annotated[int, Alias("checkLevel")]
169
176
  qos: int
170
- requestId: str
171
- _categoryKey: str
177
+ request_id: Annotated[str, Alias("requestId")]
178
+ _category_key: Annotated[str, Alias("_categoryKey")]
172
179
  namespace: str
173
- tenantId: str
174
- thingType: Literal["DEVICE"]
175
- items: Items
176
- tenantInstanceId: str
180
+ tenant_id: Annotated[str, Alias("tenantId")]
181
+ thing_type: Annotated[Literal["DEVICE"], Alias("thingType")]
182
+ items: Annotated["Items", Alias("items")]
183
+ tenant_instance_id: Annotated[str, Alias("tenantInstanceId")]
177
184
 
178
185
 
179
186
  @dataclass
@@ -182,3 +189,11 @@ class ThingPropertiesMessage(DataClassORJSONMixin):
182
189
  id: str
183
190
  params: Params
184
191
  version: Literal["1.0"]
192
+
193
+
194
+ @dataclass
195
+ class MammotionPropertiesMessage(DataClassORJSONMixin):
196
+ id: str
197
+ version: str
198
+ sys: dict
199
+ params: DeviceProperties
@@ -1,14 +1,15 @@
1
1
  from dataclasses import dataclass
2
2
  from enum import Enum
3
- from typing import Literal
3
+ from typing import Annotated, Literal
4
4
 
5
5
  from mashumaro.mixins.orjson import DataClassORJSONMixin
6
+ from mashumaro.types import Alias
6
7
 
7
8
 
8
9
  @dataclass
9
10
  class GroupIdListItem(DataClassORJSONMixin):
10
11
  groupId: str
11
- groupType: Literal["ISOLATION"]
12
+ groupType: Literal["ISOLATION", "ILOP_APP"]
12
13
 
13
14
 
14
15
  # are there other values?
@@ -25,23 +26,23 @@ class Status(DataClassORJSONMixin):
25
26
 
26
27
  @dataclass
27
28
  class Params(DataClassORJSONMixin):
28
- groupIdList: list[GroupIdListItem]
29
- netType: Literal["NET_WIFI"]
30
- activeTime: int
29
+ group_id_list: Annotated[list[GroupIdListItem], Alias("groupIdList")]
30
+ net_type: Annotated[Literal["NET_WIFI", "NET_MNET"], Alias("netType")]
31
+ active_time: Annotated[int, Alias("activeTime")]
31
32
  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
33
+ aliyun_commodity_code: Annotated[Literal["iothub_senior"], Alias("aliyunCommodityCode")]
34
+ category_key: Annotated[Literal["LawnMower", "Tracker"], Alias("categoryKey")]
35
+ node_type: Annotated[Literal["DEVICE"], Alias("nodeType")]
36
+ product_key: Annotated[str, Alias("productKey")]
37
+ status_last: Annotated[int, Alias("statusLast")]
38
+ device_name: Annotated[str, Alias("deviceName")]
39
+ iot_id: Annotated[str, Alias("iotId")]
39
40
  namespace: str
40
- tenantId: str
41
- thingType: Literal["DEVICE"]
42
- tenantInstanceId: str
43
- categoryId: int
44
- status: Status
41
+ tenant_id: Annotated[str, Alias("tenantId")]
42
+ thing_type: Annotated[Literal["DEVICE"], Alias("thingType")]
43
+ tenant_instance_id: Annotated[str, Alias("tenantInstanceId")]
44
+ category_id: Annotated[int, Alias("categoryId")]
45
+ status: Annotated[Status, Alias("status")]
45
46
 
46
47
 
47
48
  @dataclass
@@ -1,21 +1,42 @@
1
1
  import asyncio
2
+ from collections.abc import Callable
3
+ from types import MethodType
2
4
  from typing import Any
5
+ import weakref
3
6
 
4
7
 
5
8
  class Event:
6
9
  def __init__(self) -> None:
7
- self.__eventhandlers = []
10
+ self.__eventhandlers: list[weakref.ReferenceType] = []
8
11
 
9
- def __iadd__(self, handler):
10
- self.__eventhandlers.append(handler)
12
+ def __iadd__(self, handler: Callable) -> "Event":
13
+ if isinstance(handler, MethodType):
14
+ # Instance method, use WeakMethod
15
+ ref = weakref.WeakMethod(handler)
16
+ else:
17
+ # Function or static method, use weakref.ref
18
+ ref = weakref.ref(handler)
19
+ self.__eventhandlers.append(ref)
11
20
  return self
12
21
 
13
- def __isub__(self, handler):
14
- self.__eventhandlers.remove(handler)
22
+ def __isub__(self, handler: Callable) -> "Event":
23
+ self.__eventhandlers = [ref for ref in self.__eventhandlers if ref() is not handler]
15
24
  return self
16
25
 
17
- async def __call__(self, *args, **kwargs) -> None:
18
- await asyncio.gather(*[handler(*args, **kwargs) for handler in self.__eventhandlers])
26
+ async def __call__(self, *args: Any, **kwargs: Any) -> None:
27
+ live_handlers = []
28
+ for ref in self.__eventhandlers:
29
+ func = ref()
30
+ if func is not None:
31
+ live_handlers.append(func(*args, **kwargs))
32
+ await asyncio.gather(*live_handlers)
33
+
34
+ # Clean up dead references
35
+ self.__eventhandlers = [ref for ref in self.__eventhandlers if ref() is not None]
36
+
37
+ def has_dead_handlers(self) -> bool:
38
+ """Check if any handlers have been garbage collected."""
39
+ return any(ref() is None for ref in self.__eventhandlers)
19
40
 
20
41
 
21
42
  class MoveEvent:
@@ -66,4 +87,7 @@ class DataEvent:
66
87
  self.on_data_event += obj_method
67
88
 
68
89
  def remove_subscribers(self, obj_method) -> None:
69
- self.on_data_event -= obj_method
90
+ try:
91
+ self.on_data_event -= obj_method
92
+ except ValueError:
93
+ """Subscription object no longer there."""
@@ -0,0 +1,3 @@
1
+ from pymammotion.homeassistant.mower_api import HomeAssistantMowerApi
2
+
3
+ __all__ = ["HomeAssistantMowerApi"]