pymammotion 0.4.35__py3-none-any.whl → 0.4.36__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.
File without changes
pymammotion/http/http.py CHANGED
@@ -3,9 +3,9 @@ from typing import cast
3
3
 
4
4
  from aiohttp import ClientSession
5
5
 
6
- from pymammotion.aliyun.model.stream_subscription_response import StreamSubscriptionResponse
7
6
  from pymammotion.const import MAMMOTION_API_DOMAIN, MAMMOTION_CLIENT_ID, MAMMOTION_CLIENT_SECRET, MAMMOTION_DOMAIN
8
7
  from pymammotion.http.encryption import EncryptionUtils
8
+ from pymammotion.http.model.camera_stream import StreamSubscriptionResponse, VideoResourceResponse
9
9
  from pymammotion.http.model.http import ErrorInfo, LoginResponseData, Response
10
10
 
11
11
 
@@ -108,6 +108,51 @@ class MammotionHTTP:
108
108
  # Assuming the data format matches the expected structure
109
109
  return Response[StreamSubscriptionResponse].from_dict(data)
110
110
 
111
+ async def get_stream_subscription_mini_or_x_series(
112
+ self, iot_id: str, is_yuka: bool
113
+ ) -> Response[StreamSubscriptionResponse]:
114
+ """Get agora.io data for view camera stream (New models 2025)"""
115
+
116
+ # Prepare the payload with cameraStates based on is_yuka flag
117
+ payload = {"deviceId": iot_id, "mode": 0, "cameraStates": []}
118
+
119
+ # Add appropriate cameraStates based on the is_yuka flag
120
+ if is_yuka:
121
+ payload["cameraStates"] = [{"cameraState": 1}, {"cameraState": 0}, {"cameraState": 1}]
122
+ else:
123
+ payload["cameraStates"] = [{"cameraState": 1}, {"cameraState": 0}, {"cameraState": 0}]
124
+
125
+ async with ClientSession(MAMMOTION_API_DOMAIN) as session:
126
+ async with session.post(
127
+ "/device-server/v1/stream/token",
128
+ json=payload,
129
+ headers={
130
+ "Authorization": f"{self._headers.get('Authorization', "")}",
131
+ "Content-Type": "application/json",
132
+ "User-Agent": "okhttp/3.14.9",
133
+ },
134
+ ) as resp:
135
+ data = await resp.json()
136
+ # TODO catch errors from mismatch like token expire etc
137
+ # Assuming the data format matches the expected structure
138
+ return Response[StreamSubscriptionResponse].from_dict(data)
139
+
140
+ async def get_video_resource(self, iot_id: str) -> Response[VideoResourceResponse]:
141
+ """Get video resource for new models (2025 series)"""
142
+ async with ClientSession(MAMMOTION_API_DOMAIN) as session:
143
+ async with session.get(
144
+ f"/device-server/v1/video-resource/{iot_id}",
145
+ headers={
146
+ "Authorization": f"{self._headers.get('Authorization', '')}",
147
+ "Content-Type": "application/json",
148
+ "User-Agent": "okhttp/3.14.9",
149
+ },
150
+ ) as resp:
151
+ data = await resp.json()
152
+ # TODO catch errors from mismatch like token expire etc
153
+ # Assuming the data format matches the expected structure
154
+ return Response[VideoResourceResponse].from_dict(data)
155
+
111
156
  async def refresh_login(self, account: str, password: str | None = None) -> Response[LoginResponseData]:
112
157
  if self._password is None and password is not None:
113
158
  self._password = password
File without changes
@@ -16,3 +16,16 @@ class StreamSubscriptionResponse(DataClassORJSONMixin):
16
16
  channelName: str
17
17
  token: str
18
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
@@ -3,7 +3,6 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import asyncio
6
- from enum import Enum
7
6
  import logging
8
7
  from typing import Any
9
8
 
@@ -15,31 +14,23 @@ from pymammotion.data.model.device import MowingDevice
15
14
  from pymammotion.data.model.enums import ConnectionPreference
16
15
  from pymammotion.data.state_manager import StateManager
17
16
  from pymammotion.http.http import MammotionHTTP
17
+ from pymammotion.http.model.camera_stream import StreamSubscriptionResponse, VideoResourceResponse
18
+ from pymammotion.http.model.http import Response
18
19
  from pymammotion.mammotion.devices.mammotion_bluetooth import MammotionBaseBLEDevice
19
20
  from pymammotion.mammotion.devices.mammotion_cloud import MammotionBaseCloudDevice, MammotionCloud
20
21
  from pymammotion.mqtt import MammotionMQTT
22
+ from pymammotion.utility.device_type import DeviceType
21
23
 
22
24
  TIMEOUT_CLOUD_RESPONSE = 10
23
25
 
24
26
  _LOGGER = logging.getLogger(__name__)
25
27
 
26
28
 
27
- class ConnectionPreference(Enum):
28
- """Enum for connection preference."""
29
-
30
- EITHER = 0
31
- WIFI = 1
32
- BLUETOOTH = 2
33
-
34
-
35
29
  class MammotionMixedDeviceManager:
36
- preference: ConnectionPreference
37
- _ble_device: MammotionBaseBLEDevice | None = None
38
- _cloud_device: MammotionBaseCloudDevice | None = None
39
-
40
30
  def __init__(
41
31
  self,
42
32
  name: str,
33
+ mammotion_http: MammotionHTTP,
43
34
  cloud_device: Device | None = None,
44
35
  ble_device: BLEDevice | None = None,
45
36
  mqtt: MammotionCloud | None = None,
@@ -50,6 +41,7 @@ class MammotionMixedDeviceManager:
50
41
  self._state_manager.get_device().name = name
51
42
  self.add_ble(cloud_device, ble_device)
52
43
  self.add_cloud(cloud_device, mqtt)
44
+ self.mammotion_http = mammotion_http
53
45
  self.preference = preference
54
46
  self._state_manager.preference = preference
55
47
 
@@ -169,19 +161,6 @@ class Mammotion:
169
161
  """Initialize MammotionDevice."""
170
162
  self._login_lock = asyncio.Lock()
171
163
 
172
- def add_ble_device(
173
- self,
174
- cloud_device: Device,
175
- ble_device: BLEDevice,
176
- preference: ConnectionPreference = ConnectionPreference.BLUETOOTH,
177
- ) -> None:
178
- if ble_device:
179
- self.device_manager.add_device(
180
- MammotionMixedDeviceManager(
181
- name=ble_device.name, cloud_device=cloud_device, ble_device=ble_device, preference=preference
182
- )
183
- )
184
-
185
164
  async def login_and_initiate_cloud(self, account, password, force: bool = False) -> None:
186
165
  async with self._login_lock:
187
166
  exists: MammotionCloud | None = self.mqtt_list.get(account)
@@ -231,6 +210,7 @@ class Mammotion:
231
210
  if device.deviceName.startswith(("Luba-", "Yuka-")) and mower_device is None:
232
211
  mixed_device = MammotionMixedDeviceManager(
233
212
  name=device.deviceName,
213
+ mammotion_http=mqtt_client.cloud_client.mammotion_http,
234
214
  cloud_device=device,
235
215
  mqtt=mqtt_client,
236
216
  preference=ConnectionPreference.WIFI,
@@ -315,15 +295,27 @@ class Mammotion:
315
295
  return await device.cloud().start_map_sync()
316
296
  # TODO work with both with EITHER
317
297
 
318
- async def get_stream_subscription(self, name: str):
298
+ async def get_stream_subscription(self, name: str, iot_id: str) -> Response[StreamSubscriptionResponse] | Any:
319
299
  device = self.get_device_by_name(name)
320
- if device.preference is ConnectionPreference.WIFI:
321
- if device.has_cloud():
322
- _stream_response = await device.cloud().mqtt.cloud_client.mammotion_http.get_stream_subscription(
323
- device.cloud().iot_id
324
- )
325
- _LOGGER.debug(_stream_response)
326
- return _stream_response
300
+ if DeviceType.is_mini_or_x_series(name):
301
+ _stream_response = await device.mammotion_http.get_stream_subscription_mini_or_x_series(
302
+ iot_id, DeviceType.is_yuka(name)
303
+ )
304
+ _LOGGER.debug(_stream_response)
305
+ return _stream_response
306
+ else:
307
+ _stream_response = await device.mammotion_http.get_stream_subscription(iot_id)
308
+ _LOGGER.debug(_stream_response)
309
+ return _stream_response
310
+
311
+ async def get_video_resource(self, name: str, iot_id: str) -> Response[VideoResourceResponse] | None:
312
+ device = self.get_device_by_name(name)
313
+
314
+ if DeviceType.is_mini_or_x_series(name):
315
+ _video_resource_response = await device.mammotion_http.get_video_resource(iot_id)
316
+ _LOGGER.debug(_video_resource_response)
317
+ return _video_resource_response
318
+ return None
327
319
 
328
320
  def mower(self, name: str) -> MowingDevice | None:
329
321
  device = self.get_device_by_name(name)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pymammotion
3
- Version: 0.4.35
3
+ Version: 0.4.36
4
4
  Summary:
5
5
  License: GPL-3.0
6
6
  Author: Michael Arthur
@@ -8,7 +8,6 @@ pymammotion/aliyun/model/dev_by_account_response.py,sha256=P9yYy4Z2tLkJSqXA_5XGa
8
8
  pymammotion/aliyun/model/login_by_oauth_response.py,sha256=g7JnvEjoa3SplHd-UqCuK6x0qtODpHlDyJCHRz7tfDI,1228
9
9
  pymammotion/aliyun/model/regions_response.py,sha256=HSnpPcgpjr6VNXBQHw__gn-xWCkQ-MZ-Tmus9_va9mI,635
10
10
  pymammotion/aliyun/model/session_by_authcode_response.py,sha256=0owdNcGFIP7rsVqLIf9rT-iOtvWmKCt2AW0cUUXwFiQ,427
11
- pymammotion/aliyun/model/stream_subscription_response.py,sha256=7d0i8cNMAMX7aQjd2yebMDdqQkugcCzk-SD6oVtf18M,333
12
11
  pymammotion/aliyun/regions.py,sha256=ctlRGrmdE4-xgItl9slCANYOV502qVN5lkAU4lj92sk,2518
13
12
  pymammotion/aliyun/tea/core.py,sha256=4SjhRkbPMbw-uI0lQnCN0SBNAHAgVFrpHeaauuu6nZY,10200
14
13
  pymammotion/aliyun/tmp_constant.py,sha256=M4Hq_lrGB3LZdX6R2XohRPFoK1NDnNV-pTJwJcJ9838,6650
@@ -49,9 +48,12 @@ pymammotion/data/mqtt/status.py,sha256=SgdrpE1Uldb01hybO6hYhgU1Sp1eILghC0UhMZMHr
49
48
  pymammotion/data/state_manager.py,sha256=ClWwxwO88BLRkox0ljoZNzwdTWiPIBMyLBj-15V0GfI,9828
50
49
  pymammotion/event/__init__.py,sha256=mgATR6vPHACNQ-0zH5fi7NdzeTCDV1CZyaWPmtUusi8,115
51
50
  pymammotion/event/event.py,sha256=bj2RirSIRyBs0QvkcrOtwZWUX_8F3m1sySuHVyKmZLs,2143
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=r8jvdh01OAQEBNYW8QHZ2v5MjzCFkv6FibE3kWRmdSg,7359
54
+ pymammotion/http/http.py,sha256=rVTPyc5PQAsW6dILSfpp4hnnl6k3Tuy0bqC4lvnT0j8,9558
55
+ pymammotion/http/model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
56
+ pymammotion/http/model/camera_stream.py,sha256=ilxQNny_w9Frwt-m8kbHinvyjDv4Bx8C2swfZ2lTEDE,600
55
57
  pymammotion/http/model/http.py,sha256=tM5ikwVkWhRdXc2xi1NOLmWPH2mQEQelpaVgMlAEmlI,2333
56
58
  pymammotion/mammotion/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
59
  pymammotion/mammotion/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -69,7 +71,7 @@ pymammotion/mammotion/control/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5N
69
71
  pymammotion/mammotion/control/joystick.py,sha256=QfBVxM_gxpWsZAGO90whtgxCI2tIZ3TTad9wHIPsU9s,5640
70
72
  pymammotion/mammotion/devices/__init__.py,sha256=f2qQFPgLGmV85W2hSlMUh5BYuht9o_Ar_JEAAMD4fsE,102
71
73
  pymammotion/mammotion/devices/base.py,sha256=bL6aPx5o8sv3BrdgSIkpqaBYtW6yQPJ4rKd9JEr-u6c,11815
72
- pymammotion/mammotion/devices/mammotion.py,sha256=W8LtaZyYa6WhtSPpC7KHBPL3B9OHLlvZTg-Dr1oEFpo,13989
74
+ pymammotion/mammotion/devices/mammotion.py,sha256=Sk3alFzsrtSBKUe-v2x73Jf3MwoVtJ7i5Ap3T3Bj4xs,14202
73
75
  pymammotion/mammotion/devices/mammotion_bluetooth.py,sha256=r-IoqiBsgEUOxcvU0Ryz8RkW1oUJ6LcXLQa710cYmZI,18862
74
76
  pymammotion/mammotion/devices/mammotion_cloud.py,sha256=sVw-McsTJ_8wlkToL5rkjAlN2d3ituvqLona5w5bd1o,14160
75
77
  pymammotion/mqtt/__init__.py,sha256=Ocs5e-HLJvTuDpVXyECEsWIvwsUaxzj7lZ9mSYutNDY,105
@@ -121,7 +123,7 @@ pymammotion/utility/movement.py,sha256=N75oAoAgFydqoaOedYIxGUHmuTCtPzAOtb-d_29tp
121
123
  pymammotion/utility/mur_mur_hash.py,sha256=xEfOZVbqRawJj66eLgtnZ85OauDR47oIPr29OHelzPI,4468
122
124
  pymammotion/utility/periodic.py,sha256=MbeSb9cfhxzYmdT_RiE0dZe3H9IfbQW_zSqhmSX2RUc,3321
123
125
  pymammotion/utility/rocker_util.py,sha256=6tX7sS87qoQC_tsxbx3NLL-HgS08wtzXiZkhDiz7uo0,7179
124
- pymammotion-0.4.35.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
125
- pymammotion-0.4.35.dist-info/METADATA,sha256=UrRNXv4V4GLVp1LAxOXfjRCaCX_-BDWc_3ZPtXTbaQ4,3878
126
- pymammotion-0.4.35.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
127
- pymammotion-0.4.35.dist-info/RECORD,,
126
+ pymammotion-0.4.36.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
127
+ pymammotion-0.4.36.dist-info/METADATA,sha256=v1xqjdNtLHLV0-qOX7MqemhUBy0HqlEUeTcOAqIol5A,3878
128
+ pymammotion-0.4.36.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
129
+ pymammotion-0.4.36.dist-info/RECORD,,