Skip to content

Commit fcb48e2

Browse files
committed
fix(#140): increase rotation cooldown and add rotation lock to prevent concurrent rotations
1 parent e307919 commit fcb48e2

1 file changed

Lines changed: 29 additions & 13 deletions

File tree

custom_components/petlibro/devices/feeders/polar_wet_food_feeder.py

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@ def next_feeding_end_time(self) -> str:
117117
except ValueError:
118118
return "Invalid time"
119119

120+
def __init__(self, *args, **kwargs):
121+
super().__init__(*args, **kwargs)
122+
self._rotating = False
123+
120124
@property
121125
def manual_feed_id(self) -> int:
122126
"""Returns the manual feed ID."""
@@ -187,50 +191,62 @@ async def set_manual_feed_now(self, start: bool, plate: int) -> None:
187191
await self.api.set_manual_feed_now(self.serial, plate)
188192
else:
189193
_LOGGER.debug(f"Triggering stop feed now for {self.serial}")
190-
await self.api.set_stop_feed_now(self.serial, self.manual_feed_id)
194+
if self.manual_feed_id is None:
195+
_LOGGER.warning("No manual feed ID available to stop for %s", self.serial)
196+
else:
197+
await self.api.set_stop_feed_now(self.serial, self.manual_feed_id)
191198

192-
await self.refresh() # Refresh the state after the action
199+
await self.refresh()
193200
except aiohttp.ClientError as err:
194201
_LOGGER.error(f"Failed to trigger manual feed now for {self.serial} with plate no.{plate}: {err}")
195202
raise PetLibroAPIError(f"Error triggering manual feed now: {err}")
196203

197204
async def set_plate_position(self, value: str | int) -> None:
198205
"""Rotate bowl to requested plate (1-3)"""
206+
if self._rotating:
207+
_LOGGER.warning("Rotation already in progress for %s", self.serial)
208+
return
199209
try:
200210
target = int(value)
201211
except (TypeError, ValueError):
202212
raise PetLibroAPIError(f"Invalid plate value: {value!r}")
203213
if target not in (1, 2, 3):
204-
# Raise an error if plate count somehow became less than 1 or more than 3.
205214
raise PetLibroAPIError(f"Plate must be 1, 2, or 3, got {target}")
206215

207-
# Ensure we know current position
208216
if not self.plate_position:
209217
await self.refresh()
210218
curr = self.plate_position or 1
211219

212220
steps = (target - curr) % 3
213221
_LOGGER.debug("Rotate-to-plate: curr=%s target=%s steps=%s for %s", curr, target, steps, self.serial)
214222

215-
# didnt test other cooldowns, may be able reduce.
216-
ROTATE_COOLDOWN = 0.6
217-
for _ in range(steps):
218-
await self.api.set_rotate_food_bowl(self.serial)
219-
await asyncio.sleep(ROTATE_COOLDOWN)
220-
await self.refresh()
223+
self._rotating = True
224+
try:
225+
ROTATE_COOLDOWN = 2.0
226+
for _ in range(steps):
227+
await self.api.set_rotate_food_bowl(self.serial)
228+
await asyncio.sleep(ROTATE_COOLDOWN)
229+
await self.refresh()
221230

222-
# Final refresh so sensor/current_option show the target
223-
await self.refresh()
231+
await self.refresh()
232+
finally:
233+
self._rotating = False
224234

225235
async def rotate_food_bowl(self) -> None:
236+
if self._rotating:
237+
_LOGGER.warning("Rotation already in progress for %s", self.serial)
238+
return
226239
_LOGGER.debug(f"Triggering rotate food bowl for {self.serial}")
227240

241+
self._rotating = True
228242
try:
229243
await self.api.set_rotate_food_bowl(self.serial)
230-
await self.refresh() # Refresh the state after the action
244+
await self.refresh()
231245
except aiohttp.ClientError as err:
232246
_LOGGER.error(f"Failed to trigger rotate food bowl for {self.serial}: {err}")
233247
raise PetLibroAPIError(f"Error triggering rotate food bowl: {err}")
248+
finally:
249+
self._rotating = False
234250

235251
async def feed_audio(self) -> None:
236252
_LOGGER.debug(f"Triggering feed audio for {self.serial}")

0 commit comments

Comments
 (0)