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

@@ -691,8 +691,22 @@ class CloudIOTGateway:
691
691
  return self._devices_by_account_response
692
692
 
693
693
  async def send_cloud_command(self, iot_id: str, command: bytes) -> str:
694
- """Send a cloud command to the specified IoT device."""
695
694
 
695
+ """Sends a cloud command to a specified IoT device.
696
+
697
+ This function checks if the IoT token is expired and attempts to refresh it if
698
+ possible. It then constructs a request using the provided command and sends it
699
+ to the IoT device via an asynchronous HTTP POST request. The function handles
700
+ various error codes and exceptions based on the response from the cloud
701
+ service.
702
+
703
+ Args:
704
+ iot_id (str): The unique identifier of the IoT device.
705
+ command (bytes): The command to be sent to the IoT device in binary format.
706
+
707
+ Returns:
708
+ str: A unique message ID for the sent command.
709
+ """
696
710
  if command is None:
697
711
  raise Exception("Command is missing / None")
698
712
 
@@ -71,18 +71,18 @@ class StateManager:
71
71
  """Set device."""
72
72
  self._device = device
73
73
 
74
- def properties(self, thing_properties: ThingPropertiesMessage) -> None:
74
+ async def properties(self, thing_properties: ThingPropertiesMessage) -> None:
75
75
  # TODO update device based off thing properties
76
76
  self._device.mqtt_properties = thing_properties
77
- self.on_properties_callback(thing_properties)
77
+ await self.on_properties_callback(thing_properties)
78
78
 
79
- def status(self, thing_status: ThingStatusMessage) -> None:
79
+ async def status(self, thing_status: ThingStatusMessage) -> None:
80
80
  if not self._device.online:
81
81
  self._device.online = True
82
82
  self._device.status_properties = thing_status
83
83
  if self._device.mower_state.product_key == "":
84
84
  self._device.mower_state.product_key = thing_status.params.productKey
85
- self.on_status_callback(thing_status)
85
+ await self.on_status_callback(thing_status)
86
86
 
87
87
  @property
88
88
  def online(self) -> bool:
@@ -105,16 +105,17 @@ class StateManager:
105
105
  await self.ble_on_notification_callback.data_event(res)
106
106
 
107
107
  async def on_properties_callback(self, thing_properties: ThingPropertiesMessage) -> None:
108
- """Check if we have a callback for properties."""
108
+ """Call properties callback if it exists."""
109
109
  if self.properties_callback:
110
110
  await self.properties_callback.data_event(thing_properties)
111
111
 
112
112
  async def on_status_callback(self, thing_status: ThingStatusMessage) -> None:
113
- """Check if we have a callback for status."""
113
+ """Execute the status callback if it is set."""
114
114
  if self.status_callback:
115
115
  await self.status_callback.data_event(thing_status)
116
116
 
117
117
  async def get_commondata_ack_callback(self, comm_data: NavGetCommDataAck | SvgMessageAckT) -> None:
118
+ """Asynchronously calls the appropriate callback based on available handlers."""
118
119
  if self.cloud_get_commondata_ack_callback:
119
120
  await self.cloud_get_commondata_ack_callback(comm_data)
120
121
  elif self.ble_get_commondata_ack_callback:
pymammotion/http/http.py CHANGED
@@ -18,7 +18,7 @@ class MammotionHTTP:
18
18
  self._password = None
19
19
  self.response: Response | None = None
20
20
  self.login_info: LoginResponseData | None = None
21
- self._headers = {"User-Agent": "okhttp/4.9.3", "App-Version": "google Pixel 2 XL taimen-Android 11,1.11.332"}
21
+ self._headers = {"User-Agent": "okhttp/4.9.3", "App-Version": "Home Assistant,1.14.2.29"}
22
22
  self.encryption_utils = EncryptionUtils()
23
23
 
24
24
  @staticmethod
@@ -93,12 +93,13 @@ class MammotionHTTP:
93
93
  print(data)
94
94
 
95
95
  async def get_stream_subscription(self, iot_id: str) -> Response[StreamSubscriptionResponse]:
96
- """Get agora.io data for view camera stream"""
96
+ """Fetches stream subscription data from agora.io for a given IoT device."""
97
97
  async with ClientSession(MAMMOTION_API_DOMAIN) as session:
98
98
  async with session.post(
99
99
  "/device-server/v1/stream/subscription",
100
100
  json={"deviceId": iot_id},
101
101
  headers={
102
+ **self._headers,
102
103
  "Authorization": f"Bearer {self.login_info.access_token}",
103
104
  "Content-Type": "application/json",
104
105
  "User-Agent": "okhttp/4.9.3",
@@ -116,9 +117,8 @@ class MammotionHTTP:
116
117
  async def get_stream_subscription_mini_or_x_series(
117
118
  self, iot_id: str, is_yuka: bool
118
119
  ) -> Response[StreamSubscriptionResponse]:
119
- """Get agora.io data for view camera stream (New models 2025)"""
120
-
121
120
  # Prepare the payload with cameraStates based on is_yuka flag
121
+ """Fetches stream subscription data for a given IoT device."""
122
122
  payload = {"deviceId": iot_id, "mode": 0, "cameraStates": []}
123
123
 
124
124
  # Add appropriate cameraStates based on the is_yuka flag
@@ -132,6 +132,7 @@ class MammotionHTTP:
132
132
  "/device-server/v1/stream/token",
133
133
  json=payload,
134
134
  headers={
135
+ **self._headers,
135
136
  "Authorization": f"Bearer {self.login_info.access_token}",
136
137
  "Content-Type": "application/json",
137
138
  "User-Agent": "okhttp/4.9.3",
@@ -147,7 +148,7 @@ class MammotionHTTP:
147
148
  return response
148
149
 
149
150
  async def get_video_resource(self, iot_id: str) -> Response[VideoResourceResponse]:
150
- """Get video resource for new models (2025 series)"""
151
+ """Fetch video resource for a given IoT ID."""
151
152
  async with ClientSession(MAMMOTION_API_DOMAIN) as session:
152
153
  async with session.get(
153
154
  f"/device-server/v1/video-resource/{iot_id}",
@@ -167,12 +168,13 @@ class MammotionHTTP:
167
168
  return response
168
169
 
169
170
  async def get_device_ota_firmware(self, iot_ids: list[str]) -> Response[list[CheckDeviceVersion]]:
170
- """Device firmware upgrade check."""
171
+ """Checks device firmware versions for a list of IoT IDs."""
171
172
  async with ClientSession(MAMMOTION_API_DOMAIN) as session:
172
173
  async with session.post(
173
174
  "/device-server/v1/devices/version/check",
174
175
  json={"deviceIds": iot_ids},
175
176
  headers={
177
+ **self._headers,
176
178
  "Authorization": f"Bearer {self.login_info.access_token}",
177
179
  "Content-Type": "application/json",
178
180
  "User-Agent": "okhttp/4.9.3",
@@ -184,12 +186,13 @@ class MammotionHTTP:
184
186
  return response_factory(Response[list[CheckDeviceVersion]], data)
185
187
 
186
188
  async def start_ota_upgrade(self, iot_id: str, version: str) -> Response[str]:
187
- """Device firmware upgrade."""
189
+ """Initiates an OTA upgrade for a device."""
188
190
  async with ClientSession(MAMMOTION_API_DOMAIN) as session:
189
191
  async with session.post(
190
192
  "/device-server/v1/ota/device/upgrade",
191
193
  json={"deviceId": iot_id, "version": version},
192
194
  headers={
195
+ **self._headers,
193
196
  "Authorization": f"Bearer {self.login_info.access_token}",
194
197
  "Content-Type": "application/json",
195
198
  "User-Agent": "okhttp/4.9.3",
@@ -208,14 +211,14 @@ class MammotionHTTP:
208
211
  return await self.login(account, self._password)
209
212
 
210
213
  async def login(self, account: str, password: str) -> Response[LoginResponseData]:
214
+ """Logs in to the service using provided account and password."""
211
215
  self.account = account
212
216
  self._password = password
213
217
  async with ClientSession(MAMMOTION_DOMAIN) as session:
214
218
  async with session.post(
215
219
  "/oauth/token",
216
220
  headers={
217
- "User-Agent": "okhttp/4.9.3",
218
- "App-Version": "google Pixel 2 XL taimen-Android 11,1.11.332",
221
+ **self._headers,
219
222
  "Encrypt-Key": self.encryption_utils.encrypt_by_public_key(),
220
223
  "Decrypt-Type": "3",
221
224
  "Ec-Version": "v1",
@@ -6,6 +6,21 @@ T = TypeVar("T")
6
6
 
7
7
 
8
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
+ """
9
24
  if value is None:
10
25
  return None
11
26
 
@@ -30,6 +45,7 @@ def deserialize_data(value, target_type):
30
45
 
31
46
  def response_factory(response_cls: type[Response[T]], raw_dict: dict) -> Response[T]:
32
47
  # Extract the type of the generic `data` field
48
+ """Create a Response instance from a dictionary."""
33
49
  data_type = get_args(response_cls)[0] if get_args(response_cls) else None
34
50
 
35
51
  if data_type:
@@ -310,12 +310,12 @@ class MammotionBaseCloudDevice(MammotionBaseDevice):
310
310
  async def _parse_message_properties_for_device(self, event: ThingPropertiesMessage) -> None:
311
311
  if event.params.iotId != self.iot_id:
312
312
  return
313
- self.state_manager.properties(event)
313
+ await self.state_manager.properties(event)
314
314
 
315
315
  async def _parse_message_status_for_device(self, status: ThingStatusMessage) -> None:
316
316
  if status.params.iotId != self.iot_id:
317
317
  return
318
- self.state_manager.status(status)
318
+ await self.state_manager.status(status)
319
319
 
320
320
  async def _parse_message_for_device(self, event: ThingEventMessage) -> None:
321
321
  params = event.params
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pymammotion
3
- Version: 0.5.0
3
+ Version: 0.5.2
4
4
  Summary:
5
5
  License: GPL-3.0
6
6
  Author: Michael Arthur
@@ -1,7 +1,7 @@
1
1
  pymammotion/__init__.py,sha256=H-U94bNLp0LPC6hkRopVEUlUsZSR97n7WfKGPjK1GMg,1638
2
2
  pymammotion/aliyun/__init__.py,sha256=T1lkX7TRYiL4nqYanG4l4MImV-SlavSbuooC-W-uUGw,29
3
3
  pymammotion/aliyun/client.py,sha256=GCpAnLOVWW_W0c8UvdRpWVzZH5oLto8JZnb82stJi-8,9662
4
- pymammotion/aliyun/cloud_gateway.py,sha256=xJN0GiR4-qMIBXUfGUFyKwqlRIAPGvbFi6GSoO3NfiM,29080
4
+ pymammotion/aliyun/cloud_gateway.py,sha256=dRsxFOm_ou1X0VjU-i5B5hee3ay3q6HK1bqEP0oK0EE,29717
5
5
  pymammotion/aliyun/model/aep_response.py,sha256=EY4uMTJ4F9rvbcXnAOc5YKi7q__9kIVgfDwfyr65Gk0,421
6
6
  pymammotion/aliyun/model/connect_response.py,sha256=Yz-fEbDzgGPTo5Of2oAjmFkSv08T7ze80pQU4k-gKIU,824
7
7
  pymammotion/aliyun/model/dev_by_account_response.py,sha256=P9yYy4Z2tLkJSqXA_5XGaCUliSSVa5ILl7VoMtL_tCA,977
@@ -45,17 +45,17 @@ pymammotion/data/mqtt/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdr
45
45
  pymammotion/data/mqtt/event.py,sha256=C8TGRJs9wNxwg9FFmr9qcsweDnl5v5kcVcwiHxtYzJw,5384
46
46
  pymammotion/data/mqtt/properties.py,sha256=FMZHDwKO-vZeaMP0ewVZ22wgBVhi244l2ZAWb9wFANQ,4259
47
47
  pymammotion/data/mqtt/status.py,sha256=SgdrpE1Uldb01hybO6hYhgU1Sp1eILghC0UhMZMHrdQ,1091
48
- pymammotion/data/state_manager.py,sha256=Of7S5jt53J-kUjJ30NWKsuLs5m9vXd_PJbUpXGtR-Vk,11398
48
+ pymammotion/data/state_manager.py,sha256=Q0WTI-ehXH50bQEroXibzGK5MLRx5OThGZ86NNCPJjc,11508
49
49
  pymammotion/event/__init__.py,sha256=mgATR6vPHACNQ-0zH5fi7NdzeTCDV1CZyaWPmtUusi8,115
50
50
  pymammotion/event/event.py,sha256=Z8WYxv_-5khEqKjL1w4c_Et24G1Kdm8QFuIBylD3h3U,3021
51
51
  pymammotion/http/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
52
52
  pymammotion/http/_init_.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
53
53
  pymammotion/http/encryption.py,sha256=lzXu3WwBdQlzjXxWnlJuRgkCrKdPbxx5drhMitVKIEk,8287
54
- pymammotion/http/http.py,sha256=wb2Jef_dHEG_TjJeDxTLTKfySp6KPjacv2ElJpLdY8Y,11939
54
+ pymammotion/http/http.py,sha256=_Umuj6DKnTiDZ_y6C6DqPvHMRxKvqHqM0G_1QlsmHN8,12103
55
55
  pymammotion/http/model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
56
56
  pymammotion/http/model/camera_stream.py,sha256=ilxQNny_w9Frwt-m8kbHinvyjDv4Bx8C2swfZ2lTEDE,600
57
57
  pymammotion/http/model/http.py,sha256=VDBmi9nyY5Y2ns_HYvKIyzbkKRxhZ5elpq0lWXWzbGw,4123
58
- pymammotion/http/model/response_factory.py,sha256=lM5yfwlv2IZGn4Fk84BG3cmfXPd6dxQUnhXzRKn2Moc,1236
58
+ pymammotion/http/model/response_factory.py,sha256=f5_ZR0-4sLOU-q28BVy5sQOReSoND2A8UvpOOwnwrzA,1936
59
59
  pymammotion/mammotion/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
60
60
  pymammotion/mammotion/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
61
61
  pymammotion/mammotion/commands/abstract_message.py,sha256=P5FcjGkfoQ1O4Q9JKdq306TisQnJ40xDXufR-juNn8k,792
@@ -74,7 +74,7 @@ pymammotion/mammotion/devices/__init__.py,sha256=f2qQFPgLGmV85W2hSlMUh5BYuht9o_A
74
74
  pymammotion/mammotion/devices/base.py,sha256=qDh7P7fnakDKgxTqjNLcQg8eE-6gHJaXAV0ONjhy_IU,12038
75
75
  pymammotion/mammotion/devices/mammotion.py,sha256=iXXV_jqv8w35ugaMRev3lEp_oKJTob54LZ6ZF659h-Y,15087
76
76
  pymammotion/mammotion/devices/mammotion_bluetooth.py,sha256=dSDw8xLUfAU2c9vKX65w87Rm2E78284WjJ72CKniPt4,19349
77
- pymammotion/mammotion/devices/mammotion_cloud.py,sha256=YvBtuYoWPaNKrcDQWS2pj2lxhuJqmhDUWb8epQUCeXE,14816
77
+ pymammotion/mammotion/devices/mammotion_cloud.py,sha256=sj13Z08mhuinsAExSlZ1f_u8FWh8OH43Lt2hzzfvNdI,14828
78
78
  pymammotion/mqtt/__init__.py,sha256=Ocs5e-HLJvTuDpVXyECEsWIvwsUaxzj7lZ9mSYutNDY,105
79
79
  pymammotion/mqtt/linkkit/__init__.py,sha256=ENgc3ynd2kd9gMQR3-kgmCu6Ed9Y6XCIzU0zFReUlkk,80
80
80
  pymammotion/mqtt/linkkit/h2client.py,sha256=w9Nvi_nY4CLD_fw-pHtYChwQf7e2TiAGeqkY_sF4cf0,19659
@@ -124,7 +124,7 @@ pymammotion/utility/movement.py,sha256=N75oAoAgFydqoaOedYIxGUHmuTCtPzAOtb-d_29tp
124
124
  pymammotion/utility/mur_mur_hash.py,sha256=xEfOZVbqRawJj66eLgtnZ85OauDR47oIPr29OHelzPI,4468
125
125
  pymammotion/utility/periodic.py,sha256=MbeSb9cfhxzYmdT_RiE0dZe3H9IfbQW_zSqhmSX2RUc,3321
126
126
  pymammotion/utility/rocker_util.py,sha256=6tX7sS87qoQC_tsxbx3NLL-HgS08wtzXiZkhDiz7uo0,7179
127
- pymammotion-0.5.0.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
128
- pymammotion-0.5.0.dist-info/METADATA,sha256=DVc6j1Fq5v8zkHrROnvptgNkC_XNI8yjy_MnUrUzlX0,3870
129
- pymammotion-0.5.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
130
- pymammotion-0.5.0.dist-info/RECORD,,
127
+ pymammotion-0.5.2.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
128
+ pymammotion-0.5.2.dist-info/METADATA,sha256=-Qj7lhgHAoIQzfB2NlfbFXOUpQkkVYqI6Q2D00dZleg,3870
129
+ pymammotion-0.5.2.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
130
+ pymammotion-0.5.2.dist-info/RECORD,,