pymammotion 0.2.2__py3-none-any.whl → 0.2.4__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/aliyun/cloud_gateway.py +4 -0
- pymammotion/mammotion/devices/mammotion.py +132 -63
- {pymammotion-0.2.2.dist-info → pymammotion-0.2.4.dist-info}/METADATA +1 -1
- {pymammotion-0.2.2.dist-info → pymammotion-0.2.4.dist-info}/RECORD +6 -6
- {pymammotion-0.2.2.dist-info → pymammotion-0.2.4.dist-info}/LICENSE +0 -0
- {pymammotion-0.2.2.dist-info → pymammotion-0.2.4.dist-info}/WHEEL +0 -0
|
@@ -26,6 +26,7 @@ from bleak_retry_connector import (
|
|
|
26
26
|
)
|
|
27
27
|
|
|
28
28
|
from pymammotion.aliyun.cloud_gateway import CloudIOTGateway
|
|
29
|
+
from pymammotion.aliyun.dataclass.dev_by_account_response import Device
|
|
29
30
|
from pymammotion.bluetooth import BleMessage
|
|
30
31
|
from pymammotion.const import MAMMOTION_DOMAIN
|
|
31
32
|
from pymammotion.data.model import RegionData
|
|
@@ -33,7 +34,7 @@ from pymammotion.data.model.account import Credentials
|
|
|
33
34
|
from pymammotion.data.model.device import MowingDevice
|
|
34
35
|
from pymammotion.data.mqtt.event import ThingEventMessage
|
|
35
36
|
from pymammotion.data.state_manager import StateManager
|
|
36
|
-
from pymammotion.http.http import
|
|
37
|
+
from pymammotion.http.http import connect_http
|
|
37
38
|
from pymammotion.mammotion.commands.mammotion_command import MammotionCommand
|
|
38
39
|
from pymammotion.mqtt import MammotionMQTT
|
|
39
40
|
from pymammotion.proto.luba_msg import LubaMsg
|
|
@@ -125,23 +126,82 @@ class ConnectionPreference(Enum):
|
|
|
125
126
|
WIFI = 1
|
|
126
127
|
BLUETOOTH = 2
|
|
127
128
|
|
|
129
|
+
class MammotionMixedDeviceManager:
|
|
130
|
+
_ble_device: MammotionBaseBLEDevice | None = None
|
|
131
|
+
_cloud_device: MammotionBaseCloudDevice | None = None
|
|
132
|
+
_mowing_state: MowingDevice = MowingDevice()
|
|
133
|
+
|
|
134
|
+
def __init__(self, name: str, cloud_device: Device | None = None,
|
|
135
|
+
ble_device: BLEDevice | None = None, mqtt: MammotionMQTT | None = None) -> None:
|
|
136
|
+
self.name = name
|
|
137
|
+
self.add_ble(ble_device)
|
|
138
|
+
self.add_cloud(cloud_device, mqtt)
|
|
139
|
+
|
|
140
|
+
def mower_state(self):
|
|
141
|
+
return self._mowing_state
|
|
142
|
+
|
|
143
|
+
def ble(self) -> MammotionBaseBLEDevice | None:
|
|
144
|
+
return self._ble_device
|
|
145
|
+
|
|
146
|
+
def cloud(self) -> MammotionBaseCloudDevice | None:
|
|
147
|
+
return self._cloud_device
|
|
148
|
+
|
|
149
|
+
def add_ble(self, ble_device: BLEDevice) -> None:
|
|
150
|
+
if ble_device is not None:
|
|
151
|
+
self._ble_device = MammotionBaseBLEDevice(self._mowing_state, ble_device)
|
|
152
|
+
|
|
153
|
+
def add_cloud(self, cloud_device: Device | None = None, mqtt: MammotionMQTT | None = None) -> None:
|
|
154
|
+
if cloud_device is not None:
|
|
155
|
+
self._cloud_device = MammotionBaseCloudDevice(
|
|
156
|
+
mqtt_client=mqtt,
|
|
157
|
+
cloud_device=cloud_device,
|
|
158
|
+
mowing_state=self._mowing_state)
|
|
159
|
+
|
|
160
|
+
def replace_cloud(self, cloud_device:MammotionBaseCloudDevice) -> None:
|
|
161
|
+
self._cloud_device = cloud_device
|
|
162
|
+
|
|
163
|
+
def replace_ble(self, ble_device:MammotionBaseBLEDevice) -> None:
|
|
164
|
+
self._ble_device = ble_device
|
|
165
|
+
|
|
166
|
+
def has_cloud(self) -> bool:
|
|
167
|
+
return self._cloud_device is not None
|
|
168
|
+
|
|
169
|
+
def has_ble(self) -> bool:
|
|
170
|
+
return self._ble_device is not None
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
class MammotionDevices:
|
|
128
174
|
|
|
129
|
-
|
|
175
|
+
devices: dict[str, MammotionMixedDeviceManager] = {}
|
|
176
|
+
|
|
177
|
+
def add_device(self, mammotion_device: MammotionMixedDeviceManager) -> None:
|
|
178
|
+
exists: MammotionMixedDeviceManager | None = self.devices.get(mammotion_device.name)
|
|
179
|
+
if not exists:
|
|
180
|
+
self.devices[mammotion_device.name] = mammotion_device
|
|
181
|
+
if mammotion_device.has_cloud():
|
|
182
|
+
exists.replace_cloud(mammotion_device.cloud())
|
|
183
|
+
if mammotion_device.has_ble():
|
|
184
|
+
exists.replace_ble(mammotion_device.ble())
|
|
185
|
+
|
|
186
|
+
def get_device(self, mammotion_device_name: str) -> MammotionMixedDeviceManager:
|
|
187
|
+
return self.devices.get(mammotion_device_name)
|
|
188
|
+
|
|
189
|
+
class Mammotion:
|
|
130
190
|
"""Represents a Mammotion device."""
|
|
131
191
|
|
|
132
|
-
|
|
133
|
-
_cloud_device: MammotionBaseCloudDevice | None = None
|
|
134
|
-
_devices_list = []
|
|
192
|
+
devices = MammotionDevices()
|
|
135
193
|
|
|
136
194
|
def __init__(
|
|
137
195
|
self,
|
|
138
196
|
ble_device: BLEDevice,
|
|
139
197
|
cloud_credentials: Credentials | None = None,
|
|
140
|
-
preference: ConnectionPreference = ConnectionPreference.
|
|
198
|
+
preference: ConnectionPreference = ConnectionPreference.BLUETOOTH,
|
|
141
199
|
) -> None:
|
|
142
200
|
"""Initialize MammotionDevice."""
|
|
143
201
|
if ble_device:
|
|
144
|
-
self.
|
|
202
|
+
self.devices.add_device(MammotionMixedDeviceManager(name=ble_device.name, ble_device=ble_device))
|
|
203
|
+
|
|
204
|
+
if preference:
|
|
145
205
|
self._preference = preference
|
|
146
206
|
|
|
147
207
|
if cloud_credentials:
|
|
@@ -160,16 +220,10 @@ class MammotionDevice:
|
|
|
160
220
|
_mammotion_mqtt._cloud_client = cloud_client
|
|
161
221
|
_mammotion_mqtt.connect_async()
|
|
162
222
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
mqtt_client=_mammotion_mqtt,
|
|
168
|
-
iot_id=device.iotId,
|
|
169
|
-
device_name=device.deviceName,
|
|
170
|
-
nick_name=device.nickName
|
|
171
|
-
)
|
|
172
|
-
self._devices_list.append(dev)
|
|
223
|
+
for device in cloud_client.listing_dev_by_account_response.data.data:
|
|
224
|
+
if device.deviceName.startswith(("Luba-", "Yuka-")):
|
|
225
|
+
self.devices.add_device(MammotionMixedDeviceManager(name=device.deviceName, cloud_device=device, mqtt=_mammotion_mqtt))
|
|
226
|
+
|
|
173
227
|
|
|
174
228
|
@staticmethod
|
|
175
229
|
async def login(account: str, password: str) -> CloudIOTGateway:
|
|
@@ -189,36 +243,51 @@ class MammotionDevice:
|
|
|
189
243
|
cloud_client.list_binding_by_account()
|
|
190
244
|
return cloud_client
|
|
191
245
|
|
|
246
|
+
def get_device_by_name(self, name: str) -> MammotionMixedDeviceManager:
|
|
247
|
+
return self.devices.get_device(name)
|
|
192
248
|
|
|
193
|
-
async def send_command(self, key: str):
|
|
249
|
+
async def send_command(self, name: str, key: str):
|
|
194
250
|
"""Send a command to the device."""
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
251
|
+
device = self.get_device_by_name(name)
|
|
252
|
+
if device:
|
|
253
|
+
if self._preference is ConnectionPreference.BLUETOOTH:
|
|
254
|
+
return await device.ble().command(key)
|
|
255
|
+
if self._preference is ConnectionPreference.WIFI:
|
|
256
|
+
return await device.cloud().command(key)
|
|
257
|
+
# TODO work with both with EITHER
|
|
258
|
+
|
|
259
|
+
async def send_command_with_args(self,name: str, key: str, kwargs):
|
|
202
260
|
"""Send a command with args to the device."""
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
261
|
+
device = self.get_device_by_name(name)
|
|
262
|
+
if device:
|
|
263
|
+
if self._preference is ConnectionPreference.BLUETOOTH:
|
|
264
|
+
return await device.ble().command(key, **kwargs)
|
|
265
|
+
if self._preference is ConnectionPreference.WIFI:
|
|
266
|
+
return await device.cloud().command(key, **kwargs)
|
|
267
|
+
# TODO work with both with EITHER
|
|
268
|
+
|
|
269
|
+
async def start_sync(self,name:str, retry: int):
|
|
270
|
+
device = self.get_device_by_name(name)
|
|
271
|
+
if device:
|
|
272
|
+
if self._preference is ConnectionPreference.BLUETOOTH:
|
|
273
|
+
return await device.ble().start_sync(retry)
|
|
274
|
+
if self._preference is ConnectionPreference.WIFI:
|
|
275
|
+
return await device.cloud().start_sync(retry)
|
|
276
|
+
# TODO work with both with EITHER
|
|
277
|
+
|
|
278
|
+
async def start_map_sync(self, name:str):
|
|
279
|
+
device = self.get_device_by_name(name)
|
|
280
|
+
if device:
|
|
281
|
+
if self._preference is ConnectionPreference.BLUETOOTH:
|
|
282
|
+
return await device.ble().start_map_sync()
|
|
283
|
+
if self._preference is ConnectionPreference.WIFI:
|
|
284
|
+
return await device.cloud().start_map_sync()
|
|
285
|
+
# TODO work with both with EITHER
|
|
286
|
+
|
|
287
|
+
def mower(self, name: str):
|
|
288
|
+
device = self.get_device_by_name(name)
|
|
289
|
+
if device:
|
|
290
|
+
return device.mower_state
|
|
222
291
|
|
|
223
292
|
def has_field(message: betterproto.Message) -> bool:
|
|
224
293
|
"""Check if the message has any fields serialized on wire."""
|
|
@@ -228,15 +297,15 @@ def has_field(message: betterproto.Message) -> bool:
|
|
|
228
297
|
class MammotionBaseDevice:
|
|
229
298
|
"""Base class for Mammotion devices."""
|
|
230
299
|
|
|
231
|
-
|
|
300
|
+
_mower: MowingDevice
|
|
232
301
|
_state_manager: StateManager
|
|
233
302
|
|
|
234
|
-
def __init__(self) -> None:
|
|
303
|
+
def __init__(self, device: MowingDevice) -> None:
|
|
235
304
|
"""Initialize MammotionBaseDevice."""
|
|
236
305
|
self.loop = asyncio.get_event_loop()
|
|
237
306
|
self._raw_data = LubaMsg().to_dict(casing=betterproto.Casing.SNAKE)
|
|
238
|
-
self.
|
|
239
|
-
self._state_manager = StateManager(self.
|
|
307
|
+
self._mower = device
|
|
308
|
+
self._state_manager = StateManager(self._mower)
|
|
240
309
|
|
|
241
310
|
self._state_manager.gethash_ack_callback.add_subscribers(self.datahash_response)
|
|
242
311
|
self._state_manager.get_commondata_ack_callback.add_subscribers(self.commdata_response)
|
|
@@ -259,7 +328,7 @@ class MammotionBaseDevice:
|
|
|
259
328
|
if total_frame == current_frame:
|
|
260
329
|
# get next in hash ack list
|
|
261
330
|
|
|
262
|
-
data_hash = find_next_integer(self.
|
|
331
|
+
data_hash = find_next_integer(self._mower.nav.toapp_gethash_ack.data_couple, common_data.hash)
|
|
263
332
|
if data_hash is None:
|
|
264
333
|
return
|
|
265
334
|
result_hash = 0
|
|
@@ -296,7 +365,7 @@ class MammotionBaseDevice:
|
|
|
296
365
|
case "ota":
|
|
297
366
|
self._update_ota_data(tmp_msg)
|
|
298
367
|
|
|
299
|
-
self.
|
|
368
|
+
self._mower.update_raw(self._raw_data)
|
|
300
369
|
|
|
301
370
|
def _update_nav_data(self, tmp_msg):
|
|
302
371
|
"""Update navigation data."""
|
|
@@ -370,9 +439,9 @@ class MammotionBaseDevice:
|
|
|
370
439
|
return self._raw_data
|
|
371
440
|
|
|
372
441
|
@property
|
|
373
|
-
def
|
|
442
|
+
def mower(self) -> MowingDevice:
|
|
374
443
|
"""Get the LubaMsg of the device."""
|
|
375
|
-
return self.
|
|
444
|
+
return self._mower
|
|
376
445
|
|
|
377
446
|
@abstractmethod
|
|
378
447
|
async def _send_command(self, key: str, retry: int | None = None) -> bytes | None:
|
|
@@ -405,7 +474,7 @@ class MammotionBaseDevice:
|
|
|
405
474
|
await self._send_command_with_args("get_hash_response", total_frame=1, current_frame=1)
|
|
406
475
|
|
|
407
476
|
await self._send_command_with_args(
|
|
408
|
-
"get_area_name_list", device_id=self.
|
|
477
|
+
"get_area_name_list", device_id=self._mower.device.net.toapp_wifi_iot_status.devicename
|
|
409
478
|
)
|
|
410
479
|
|
|
411
480
|
# sub_cmd 3 is job hashes??
|
|
@@ -421,13 +490,14 @@ class MammotionBaseDevice:
|
|
|
421
490
|
class MammotionBaseBLEDevice(MammotionBaseDevice):
|
|
422
491
|
"""Base class for Mammotion BLE devices."""
|
|
423
492
|
|
|
424
|
-
def __init__(self, device: BLEDevice, interface: int = 0, **kwargs: Any) -> None:
|
|
493
|
+
def __init__(self, mowing_state: MowingDevice, device: BLEDevice, interface: int = 0, **kwargs: Any) -> None:
|
|
425
494
|
"""Initialize MammotionBaseBLEDevice."""
|
|
426
|
-
super().__init__()
|
|
495
|
+
super().__init__(mowing_state)
|
|
427
496
|
self._ble_sync_task = None
|
|
428
497
|
self._prev_notification = None
|
|
429
498
|
self._interface = f"hci{interface}"
|
|
430
499
|
self._device = device
|
|
500
|
+
self._mower = mowing_state
|
|
431
501
|
self._client: BleakClientWithServiceCache | None = None
|
|
432
502
|
self._read_char: BleakGATTCharacteristic | None = None
|
|
433
503
|
self._write_char: BleakGATTCharacteristic | None = None
|
|
@@ -802,20 +872,19 @@ class MammotionBaseCloudDevice(MammotionBaseDevice):
|
|
|
802
872
|
def __init__(
|
|
803
873
|
self,
|
|
804
874
|
mqtt_client: MammotionMQTT,
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
nick_name: str,
|
|
808
|
-
**kwargs: Any,
|
|
875
|
+
cloud_device: Device,
|
|
876
|
+
mowing_state: MowingDevice
|
|
809
877
|
) -> None:
|
|
810
878
|
"""Initialize MammotionBaseCloudDevice."""
|
|
811
|
-
super().__init__()
|
|
879
|
+
super().__init__(mowing_state)
|
|
812
880
|
self._ble_sync_task = None
|
|
813
881
|
self.is_ready = False
|
|
814
882
|
self._mqtt_client = mqtt_client
|
|
815
|
-
self.iot_id =
|
|
816
|
-
self.
|
|
883
|
+
self.iot_id = cloud_device.iotId
|
|
884
|
+
self.device = cloud_device
|
|
885
|
+
self._mower = mowing_state
|
|
817
886
|
self._command_futures = {}
|
|
818
|
-
self._commands: MammotionCommand = MammotionCommand(
|
|
887
|
+
self._commands: MammotionCommand = MammotionCommand(cloud_device.deviceName)
|
|
819
888
|
self.currentID = ""
|
|
820
889
|
self.on_ready_callback: Optional[Callable[[], None]] = None
|
|
821
890
|
self._operation_lock = asyncio.Lock()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
pymammotion/__init__.py,sha256=kmnjdt3AEMejIz5JK7h1tTJj5ZriAgKwZBa3ScA4-Ao,1516
|
|
2
2
|
pymammotion/aliyun/__init__.py,sha256=T1lkX7TRYiL4nqYanG4l4MImV-SlavSbuooC-W-uUGw,29
|
|
3
|
-
pymammotion/aliyun/cloud_gateway.py,sha256=
|
|
3
|
+
pymammotion/aliyun/cloud_gateway.py,sha256=XbFMWjjvqbsics04EvU-dGfTvlRLALvy075Q53foEzU,18423
|
|
4
4
|
pymammotion/aliyun/cloud_service.py,sha256=YWcKuKK6iRWy5mTnBYgHxcCusiRGGzQt3spSf7dGDss,2183
|
|
5
5
|
pymammotion/aliyun/dataclass/aep_response.py,sha256=8f6GIP58ve8gd6AL3HBoXxsy0n2q4ygWvjELGnoOnVc,452
|
|
6
6
|
pymammotion/aliyun/dataclass/connect_response.py,sha256=Yz-fEbDzgGPTo5Of2oAjmFkSv08T7ze80pQU4k-gKIU,824
|
|
@@ -58,7 +58,7 @@ pymammotion/mammotion/commands/messages/video.py,sha256=_8lJsU4sLm2CGnc7RDkueA0A
|
|
|
58
58
|
pymammotion/mammotion/control/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
59
59
|
pymammotion/mammotion/control/joystick.py,sha256=EWV20MMzQuhbLlNlXbsyZKSEpeM7x1CQL7saU4Pn0-g,6165
|
|
60
60
|
pymammotion/mammotion/devices/__init__.py,sha256=T72jt0ejtMjo1rPmn_FeMF3pmp0LLeRRpc9WcDKEYYY,126
|
|
61
|
-
pymammotion/mammotion/devices/mammotion.py,sha256=
|
|
61
|
+
pymammotion/mammotion/devices/mammotion.py,sha256=6FRNQp0Y5DKfp9XmteB2MdMzAh2HjtT5j1072Ad_RBQ,42129
|
|
62
62
|
pymammotion/mqtt/__init__.py,sha256=Ocs5e-HLJvTuDpVXyECEsWIvwsUaxzj7lZ9mSYutNDY,105
|
|
63
63
|
pymammotion/mqtt/mammotion_mqtt.py,sha256=VU0c8X1DrZSZDLCVAsCaEbLX2zcyrUbEAYaPzOXALNo,7523
|
|
64
64
|
pymammotion/proto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -110,7 +110,7 @@ pymammotion/utility/device_type.py,sha256=KYawu2glZMVlPmxRbA4kVFujXz3miHp3rJiOWR
|
|
|
110
110
|
pymammotion/utility/map.py,sha256=aoi-Luzuph02hKynTofMoq3mnPstanx75MDAVv49CuY,2211
|
|
111
111
|
pymammotion/utility/periodic.py,sha256=9wJMfwXPlx6Mbp3Fws7LLTI34ZDKphH1bva_Ggyk32g,3281
|
|
112
112
|
pymammotion/utility/rocker_util.py,sha256=syPL0QN4zMzHiTIkUKS7RXBBptjdbkfNlPddwUD5V3A,7171
|
|
113
|
-
pymammotion-0.2.
|
|
114
|
-
pymammotion-0.2.
|
|
115
|
-
pymammotion-0.2.
|
|
116
|
-
pymammotion-0.2.
|
|
113
|
+
pymammotion-0.2.4.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
114
|
+
pymammotion-0.2.4.dist-info/METADATA,sha256=BWWTFjszwzs9KHuAlUuKI6M1lCrdGsZw8kY-YbqzVts,3922
|
|
115
|
+
pymammotion-0.2.4.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
116
|
+
pymammotion-0.2.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|