python-roborock 7.3.0__py3-none-any.whl → 7.4.0__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: python-roborock
3
- Version: 7.3.0
3
+ Version: 7.4.0
4
4
  Summary: A package to control Roborock vacuums.
5
5
  Project-URL: Repository, https://github.com/python-roborock/python-roborock
6
6
  Project-URL: Documentation, https://python-roborock.readthedocs.io/
@@ -11,10 +11,10 @@ roborock/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
11
  roborock/roborock_message.py,sha256=VWsytnm7nQqOMBj7oYbiqPPqwE9qClDSI03CFuHXsds,11822
12
12
  roborock/roborock_typing.py,sha256=xppavdf57-Cu6elj3MP403uT75Tjw5Zs6bLGPLQmZf4,15483
13
13
  roborock/util.py,sha256=mjw329ujLjoWPPAr9mG0VZstaVL06dmVvNnYACB-Pxk,1650
14
- roborock/web_api.py,sha256=M_A4PiRK5cwkoT3oS8fvglOU97s1jpWKuuCxeeCiF_E,37507
14
+ roborock/web_api.py,sha256=ypW9e11U0jNXnyIQO9UN0DnIdz4c6AxtJlUJmjuEl-o,40514
15
15
  roborock/data/__init__.py,sha256=jSZHOrd-LfVN-TdBkjNW334ef99rGBz4-hPT_7KvoLs,278
16
16
  roborock/data/code_mappings.py,sha256=SGLJvHSdibUsXqCbQcqCGKm3x09JqhRKLoCgMCN1_s0,9769
17
- roborock/data/containers.py,sha256=r46o2Xf6gfpw2SHBZnkVbfJIYYbpgTPYWDmAHWdgL8E,17228
17
+ roborock/data/containers.py,sha256=ISfVcuDYFqMUiYa0V7NaMDH6snjYjJqOg6oKp-URghg,17900
18
18
  roborock/data/b01_q10/__init__.py,sha256=E4lwJcz4AI1z92FcYOJ-cY3fcfHSoXqvYVgfA-TgaRk,71
19
19
  roborock/data/b01_q10/b01_q10_code_mappings.py,sha256=UBFkxCWLYCGQatENmNwR0owkXrcB8AosnD-hICfS2AY,15203
20
20
  roborock/data/b01_q10/b01_q10_containers.py,sha256=HE1qAhYKDTz35oRgekYItNfD1iWTi7605-wpETcDzxU,11823
@@ -125,8 +125,8 @@ roborock/testing/channel.py,sha256=vjulT5MHBe8lAq6XITUqcxJVcCILWx7ZEcw5imTx0Tk,7
125
125
  roborock/testing/cloud.py,sha256=L2L0KlZDYaMuoV19KUQUoq5EAUDeNQ1lJ8Ew5YaOgjo,11946
126
126
  roborock/testing/simulator.py,sha256=g8ZUWVSjgAzuRRxWOCeOq-7deodyEItwUpqEw9RzCmQ,4347
127
127
  roborock/testing/v1_simulator.py,sha256=TQ2PsRoP_4kJvVn-Tm532ByHuaCKltsVjvTa2Ju4PAo,14407
128
- python_roborock-7.3.0.dist-info/METADATA,sha256=-UHI17_l7Ty6Txpqlc7NcpxYnkhKNsFsb3u4L3qxn7k,5278
129
- python_roborock-7.3.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
130
- python_roborock-7.3.0.dist-info/entry_points.txt,sha256=EvC1nMqi9ZXKgZnqlNXA33v_3nzgPNjnM0mzWlrehnY,47
131
- python_roborock-7.3.0.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
132
- python_roborock-7.3.0.dist-info/RECORD,,
128
+ python_roborock-7.4.0.dist-info/METADATA,sha256=L14mFPjco7QQODUZ4-_dCwKtLQ6cOgHQVyg6UMlitsg,5278
129
+ python_roborock-7.4.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
130
+ python_roborock-7.4.0.dist-info/entry_points.txt,sha256=EvC1nMqi9ZXKgZnqlNXA33v_3nzgPNjnM0mzWlrehnY,47
131
+ python_roborock-7.4.0.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
132
+ python_roborock-7.4.0.dist-info/RECORD,,
@@ -348,6 +348,24 @@ class HomeDataScene(RoborockBase):
348
348
  name: str
349
349
 
350
350
 
351
+ @dataclass
352
+ class FirmwareInfo(RoborockBase):
353
+ """Firmware/OTA info from the cloud (`ota/firmware/{duid}/updatev2`)."""
354
+
355
+ version: str | None = None
356
+ """Latest available firmware version."""
357
+ current_version: str | None = None
358
+ """Currently installed firmware version."""
359
+ updatable: bool | None = None
360
+ """Whether a newer firmware is available to install."""
361
+ desc: str | None = None
362
+ """Release notes / description."""
363
+ release_time: str | None = None
364
+ """Release date of the available firmware as an ISO-8601 date (``YYYY-MM-DD``)."""
365
+ force_update: bool | None = None
366
+ """Whether the update is mandatory (cannot be skipped)."""
367
+
368
+
351
369
  @dataclass
352
370
  class HomeDataSchedule(RoborockBase):
353
371
  id: int
roborock/web_api.py CHANGED
@@ -15,7 +15,7 @@ from aiohttp import ContentTypeError, FormData
15
15
  from pyrate_limiter import Duration, Limiter, Rate
16
16
 
17
17
  from roborock import HomeDataSchedule
18
- from roborock.data import HomeData, HomeDataRoom, HomeDataScene, ProductResponse, RRiot, UserData
18
+ from roborock.data import FirmwareInfo, HomeData, HomeDataRoom, HomeDataScene, ProductResponse, RRiot, UserData
19
19
  from roborock.exceptions import (
20
20
  RoborockAccountDoesNotExist,
21
21
  RoborockException,
@@ -608,6 +608,73 @@ class RoborockApiClient:
608
608
  else:
609
609
  raise RoborockException("scene_response result was an unexpected type")
610
610
 
611
+ async def get_firmware_info(self, user_data: UserData, device_id: str) -> FirmwareInfo:
612
+ """Get firmware/OTA info for a device (latest version + updatable flag)."""
613
+ rriot = user_data.rriot
614
+ if rriot is None:
615
+ raise RoborockException("rriot is none")
616
+ if rriot.r.a is None:
617
+ raise RoborockException("Missing field 'a' in rriot reference")
618
+ path = f"/ota/firmware/{device_id}/updatev2"
619
+ params = {"lang": "en"}
620
+ firmware_request = PreparedRequest(
621
+ rriot.r.a,
622
+ self.session,
623
+ {
624
+ "Authorization": _get_hawk_authentication(rriot, path, params=params),
625
+ },
626
+ )
627
+ firmware_response = await firmware_request.request("get", path, params=params)
628
+ if not firmware_response or not firmware_response.get("success"):
629
+ raise RoborockException(firmware_response)
630
+ return FirmwareInfo.from_dict(firmware_response.get("result") or {})
631
+
632
+ async def start_firmware_update(self, user_data: UserData, device_id: str) -> None:
633
+ """Trigger the (irreversible) firmware update for a device.
634
+
635
+ The device downloads and flashes the latest firmware reported by
636
+ :meth:`get_firmware_info`.
637
+ """
638
+ rriot = user_data.rriot
639
+ if rriot is None:
640
+ raise RoborockException("rriot is none")
641
+ if rriot.r.a is None:
642
+ raise RoborockException("Missing field 'a' in rriot reference")
643
+ path = f"/ota/device/{device_id}/upgrade"
644
+ upgrade_request = PreparedRequest(
645
+ rriot.r.a,
646
+ self.session,
647
+ {
648
+ "Authorization": _get_hawk_authentication(rriot, path),
649
+ },
650
+ )
651
+ upgrade_response = await upgrade_request.request("post", path)
652
+ if not upgrade_response or not upgrade_response.get("success"):
653
+ raise RoborockException(upgrade_response)
654
+
655
+ async def set_silent_ota(self, user_data: UserData, device_id: str, enabled: bool) -> None:
656
+ """Enable/disable automatic (silent) firmware updates for a device.
657
+
658
+ The current value is reported as ``silent_ota_switch`` on the home-data device.
659
+ """
660
+ rriot = user_data.rriot
661
+ if rriot is None:
662
+ raise RoborockException("rriot is none")
663
+ if rriot.r.a is None:
664
+ raise RoborockException("Missing field 'a' in rriot reference")
665
+ path = f"/user/devices/{device_id}"
666
+ formdata = {"silentOtaSwitch": "true" if enabled else "false"}
667
+ silent_ota_request = PreparedRequest(
668
+ rriot.r.a,
669
+ self.session,
670
+ {
671
+ "Authorization": _get_hawk_authentication(rriot, path, formdata=formdata),
672
+ },
673
+ )
674
+ silent_ota_response = await silent_ota_request.request("put", path, data=formdata)
675
+ if not silent_ota_response or not silent_ota_response.get("success"):
676
+ raise RoborockException(silent_ota_response)
677
+
611
678
  async def execute_scene(self, user_data: UserData, scene_id: int) -> None:
612
679
  rriot = user_data.rriot
613
680
  if rriot is None: