Skip to content

Commit ffd82c5

Browse files
committed
Limit firmware check to every 15 minutes unless forced
1 parent 2479719 commit ffd82c5

File tree

3 files changed

+44
-31
lines changed

3 files changed

+44
-31
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
# pylitterbot
77

8-
Python package for controlling Whisker automatic robots.
8+
Python package for controlling a Whisker connected self-cleaning litter boxes and feeders.
99

1010
This is an unofficial API for controlling various Whisker automated robots. It currently supports Litter-Robot 3, Litter-Robot 4 and Feeder-Robot.
1111

pylitterbot/robot/litterrobot4.py

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ class LitterRobot4(LitterRobot): # pylint: disable=abstract-method
9898
_litter_level = LITTER_LEVEL_EMPTY
9999
_litter_level_exp: datetime | None = None
100100

101+
_firmware_details: dict[str, bool | dict[str, str]] | None = None
102+
_firmware_details_requested: datetime | None = None
103+
101104
def __init__(self, data: dict, account: Account) -> None:
102105
"""Initialize a Litter-Robot 4."""
103106
super().__init__(data, account)
@@ -496,46 +499,58 @@ async def get_insight(
496499
],
497500
)
498501

499-
async def get_firmware_details(self) -> dict[str, bool | dict[str, str]] | None:
502+
async def get_firmware_details(
503+
self, force_check: bool = False
504+
) -> dict[str, bool | dict[str, str]] | None:
500505
"""Get the firmware details."""
501-
data = await self._post(
502-
json={
503-
"query": """
504-
query getFirmwareDetails($serial: String!) {
505-
litterRobot4CompareFirmwareVersion(serial: $serial) {
506-
isEspFirmwareUpdateNeeded
507-
isPicFirmwareUpdateNeeded
508-
isLaserboardFirmwareUpdateNeeded
509-
latestFirmware {
510-
espFirmwareVersion
511-
picFirmwareVersion
512-
laserBoardFirmwareVersion
506+
if (
507+
force_check
508+
or not self._firmware_details
509+
or (requested := self._firmware_details_requested) is None
510+
or requested + timedelta(minutes=15) < utcnow()
511+
):
512+
data = await self._post(
513+
json={
514+
"query": """
515+
query getFirmwareDetails($serial: String!) {
516+
litterRobot4CompareFirmwareVersion(serial: $serial) {
517+
isEspFirmwareUpdateNeeded
518+
isPicFirmwareUpdateNeeded
519+
isLaserboardFirmwareUpdateNeeded
520+
latestFirmware {
521+
espFirmwareVersion
522+
picFirmwareVersion
523+
laserBoardFirmwareVersion
524+
}
513525
}
514526
}
515-
}
516-
""",
517-
"variables": {"serial": self.serial},
518-
}
519-
)
520-
data = cast(Dict[str, Dict[str, Dict[str, Union[bool, Dict[str, str]]]]], data)
521-
return data.get("data", {}).get("litterRobot4CompareFirmwareVersion", {})
527+
""",
528+
"variables": {"serial": self.serial},
529+
}
530+
)
531+
self._firmware_details = (
532+
cast(Dict[str, Dict[str, Dict[str, Union[bool, Dict[str, str]]]]], data)
533+
.get("data", {})
534+
.get("litterRobot4CompareFirmwareVersion", {})
535+
)
536+
self._firmware_details_requested = utcnow()
537+
return self._firmware_details
522538

523-
async def get_latest_firmware(self) -> str | None:
539+
async def get_latest_firmware(self, force_check: bool = False) -> str | None:
524540
"""Get the latest firmware available."""
525-
if (firmware := await self.get_firmware_details()) is None:
541+
if (firmware := await self.get_firmware_details(force_check)) is None:
526542
return None
527543

528-
latest_firmware = (firmware).get("latestFirmware", {})
529-
latest_firmware = cast(Dict[str, str], latest_firmware)
544+
latest_firmware = cast(Dict[str, str], firmware.get("latestFirmware", {}))
530545
return (
531546
f"ESP: {latest_firmware.get('espFirmwareVersion')} / "
532547
f"PIC: {latest_firmware.get('picFirmwareVersion')} / "
533548
f"TOF: {latest_firmware.get('laserBoardFirmwareVersion')}"
534549
)
535550

536-
async def has_firmware_update(self) -> bool:
551+
async def has_firmware_update(self, force_check: bool = False) -> bool:
537552
"""Check if a firmware update is available."""
538-
if (firmware := await self.get_firmware_details()) is None:
553+
if (firmware := await self.get_firmware_details(force_check)) is None:
539554
return False
540555
return any(value for value in firmware.values() if isinstance(value, bool))
541556

tests/test_litterrobot4.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -256,9 +256,7 @@ async def test_litter_robot_4(
256256
version_info["isEspFirmwareUpdateNeeded"] = False
257257
version_info["isPicFirmwareUpdateNeeded"] = False
258258
mock_aioresponse.post(LR4_ENDPOINT, payload=firmware_response)
259-
assert not await robot.has_firmware_update()
260-
261-
mock_aioresponse.post(LR4_ENDPOINT, payload=firmware_response)
259+
assert not await robot.has_firmware_update(True)
262260
latest_firmware = await robot.get_latest_firmware()
263261
assert latest_firmware == "ESP: 1.1.54 / PIC: 10512.2560.2.66 / TOF: 4.0.65.4"
264262

@@ -302,7 +300,7 @@ async def test_litter_robot_4(
302300
],
303301
}
304302
mock_aioresponse.post(LR4_ENDPOINT, payload=firmware_response, repeat=True)
305-
assert not await robot.has_firmware_update()
303+
assert not await robot.has_firmware_update(True)
306304
assert not await robot.get_latest_firmware()
307305

308306
await robot._account.disconnect()

0 commit comments

Comments
 (0)