pymammotion 0.4.35__py3-none-any.whl → 0.4.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.
- pymammotion/http/__init__.py +0 -0
- pymammotion/http/http.py +46 -1
- pymammotion/http/model/__init__.py +0 -0
- pymammotion/{aliyun/model/stream_subscription_response.py → http/model/camera_stream.py} +13 -0
- pymammotion/mammotion/devices/mammotion.py +28 -34
- {pymammotion-0.4.35.dist-info → pymammotion-0.4.37.dist-info}/METADATA +1 -1
- {pymammotion-0.4.35.dist-info → pymammotion-0.4.37.dist-info}/RECORD +9 -7
- {pymammotion-0.4.35.dist-info → pymammotion-0.4.37.dist-info}/LICENSE +0 -0
- {pymammotion-0.4.35.dist-info → pymammotion-0.4.37.dist-info}/WHEEL +0 -0
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,41 +14,36 @@ 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,
|
46
37
|
preference: ConnectionPreference = ConnectionPreference.BLUETOOTH,
|
47
38
|
) -> None:
|
39
|
+
self._ble_device: MammotionBaseBLEDevice | None = None
|
40
|
+
self._cloud_device: MammotionBaseCloudDevice | None = None
|
48
41
|
self.name = name
|
49
42
|
self._state_manager = StateManager(MowingDevice())
|
50
43
|
self._state_manager.get_device().name = name
|
51
44
|
self.add_ble(cloud_device, ble_device)
|
52
45
|
self.add_cloud(cloud_device, mqtt)
|
46
|
+
self.mammotion_http = mammotion_http
|
53
47
|
self.preference = preference
|
54
48
|
self._state_manager.preference = preference
|
55
49
|
|
@@ -169,19 +163,6 @@ class Mammotion:
|
|
169
163
|
"""Initialize MammotionDevice."""
|
170
164
|
self._login_lock = asyncio.Lock()
|
171
165
|
|
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
166
|
async def login_and_initiate_cloud(self, account, password, force: bool = False) -> None:
|
186
167
|
async with self._login_lock:
|
187
168
|
exists: MammotionCloud | None = self.mqtt_list.get(account)
|
@@ -231,6 +212,7 @@ class Mammotion:
|
|
231
212
|
if device.deviceName.startswith(("Luba-", "Yuka-")) and mower_device is None:
|
232
213
|
mixed_device = MammotionMixedDeviceManager(
|
233
214
|
name=device.deviceName,
|
215
|
+
mammotion_http=mqtt_client.cloud_client.mammotion_http,
|
234
216
|
cloud_device=device,
|
235
217
|
mqtt=mqtt_client,
|
236
218
|
preference=ConnectionPreference.WIFI,
|
@@ -315,15 +297,27 @@ class Mammotion:
|
|
315
297
|
return await device.cloud().start_map_sync()
|
316
298
|
# TODO work with both with EITHER
|
317
299
|
|
318
|
-
async def get_stream_subscription(self, name: str):
|
300
|
+
async def get_stream_subscription(self, name: str, iot_id: str) -> Response[StreamSubscriptionResponse] | Any:
|
319
301
|
device = self.get_device_by_name(name)
|
320
|
-
if
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
302
|
+
if DeviceType.is_mini_or_x_series(name):
|
303
|
+
_stream_response = await device.mammotion_http.get_stream_subscription_mini_or_x_series(
|
304
|
+
iot_id, DeviceType.is_yuka(name)
|
305
|
+
)
|
306
|
+
_LOGGER.debug(_stream_response)
|
307
|
+
return _stream_response
|
308
|
+
else:
|
309
|
+
_stream_response = await device.mammotion_http.get_stream_subscription(iot_id)
|
310
|
+
_LOGGER.debug(_stream_response)
|
311
|
+
return _stream_response
|
312
|
+
|
313
|
+
async def get_video_resource(self, name: str, iot_id: str) -> Response[VideoResourceResponse] | None:
|
314
|
+
device = self.get_device_by_name(name)
|
315
|
+
|
316
|
+
if DeviceType.is_mini_or_x_series(name):
|
317
|
+
_video_resource_response = await device.mammotion_http.get_video_resource(iot_id)
|
318
|
+
_LOGGER.debug(_video_resource_response)
|
319
|
+
return _video_resource_response
|
320
|
+
return None
|
327
321
|
|
328
322
|
def mower(self, name: str) -> MowingDevice | None:
|
329
323
|
device = self.get_device_by_name(name)
|
@@ -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=
|
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=
|
74
|
+
pymammotion/mammotion/devices/mammotion.py,sha256=ugzmER_EvSzdZf_1OTYnNy3ynZo4NGX0eqN7SAR1hvM,14332
|
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.
|
125
|
-
pymammotion-0.4.
|
126
|
-
pymammotion-0.4.
|
127
|
-
pymammotion-0.4.
|
126
|
+
pymammotion-0.4.37.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
127
|
+
pymammotion-0.4.37.dist-info/METADATA,sha256=8MqFqYhVRZVIlQg_NR7-yriZo9_1DoN1_zL2CHAsN0o,3878
|
128
|
+
pymammotion-0.4.37.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
129
|
+
pymammotion-0.4.37.dist-info/RECORD,,
|
File without changes
|
File without changes
|