diff --git a/homeassistant/components/litterrobot/entity.py b/homeassistant/components/litterrobot/entity.py index 064c9bcf8f1..206358201c3 100644 --- a/homeassistant/components/litterrobot/entity.py +++ b/homeassistant/components/litterrobot/entity.py @@ -67,19 +67,21 @@ class LitterRobotControlEntity(LitterRobotEntity): self, action: MethodType, *args: Any, **kwargs: Any ) -> bool: """Perform an action and initiates a refresh of the robot data after a few seconds.""" + success = False try: - await action(*args, **kwargs) + success = await action(*args, **kwargs) except InvalidCommandException as ex: # pragma: no cover # this exception should only occur if the underlying API for commands changes _LOGGER.error(ex) - return False + success = False - self.async_cancel_refresh_callback() - self._refresh_callback = async_call_later( - self.hass, REFRESH_WAIT_TIME_SECONDS, self.async_call_later_callback - ) - return True + if success: + self.async_cancel_refresh_callback() + self._refresh_callback = async_call_later( + self.hass, REFRESH_WAIT_TIME_SECONDS, self.async_call_later_callback + ) + return success async def async_call_later_callback(self, *_) -> None: """Perform refresh request on callback.""" @@ -118,3 +120,16 @@ class LitterRobotConfigEntity(LitterRobotControlEntity): """A Litter-Robot entity that can control configuration of the unit.""" _attr_entity_category = ENTITY_CATEGORY_CONFIG + + def __init__(self, robot: Robot, entity_type: str, hub: LitterRobotHub) -> None: + """Init a Litter-Robot control entity.""" + super().__init__(robot=robot, entity_type=entity_type, hub=hub) + self._assumed_state: Any = None + + async def perform_action_and_assume_state( + self, action: MethodType, assumed_state: Any + ) -> bool: + """Perform an action and assume the state passed in if call is successful.""" + if await self.perform_action_and_refresh(action, assumed_state): + self._assumed_state = assumed_state + self.async_write_ha_state() diff --git a/homeassistant/components/litterrobot/hub.py b/homeassistant/components/litterrobot/hub.py index 6a9155b9eaf..3aa86dcc93a 100644 --- a/homeassistant/components/litterrobot/hub.py +++ b/homeassistant/components/litterrobot/hub.py @@ -13,7 +13,7 @@ from .const import DOMAIN _LOGGER = logging.getLogger(__name__) -UPDATE_INTERVAL_SECONDS = 10 +UPDATE_INTERVAL_SECONDS = 20 class LitterRobotHub: diff --git a/homeassistant/components/litterrobot/manifest.json b/homeassistant/components/litterrobot/manifest.json index 7b864948569..0d76e8df09c 100644 --- a/homeassistant/components/litterrobot/manifest.json +++ b/homeassistant/components/litterrobot/manifest.json @@ -3,7 +3,11 @@ "name": "Litter-Robot", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/litterrobot", - "requirements": ["pylitterbot==2021.10.1"], - "codeowners": ["@natekspencer"], + "requirements": [ + "pylitterbot==2021.11.0" + ], + "codeowners": [ + "@natekspencer" + ], "iot_class": "cloud_polling" -} +} \ No newline at end of file diff --git a/homeassistant/components/litterrobot/switch.py b/homeassistant/components/litterrobot/switch.py index 9a08a008d96..4d302a0d4ae 100644 --- a/homeassistant/components/litterrobot/switch.py +++ b/homeassistant/components/litterrobot/switch.py @@ -19,6 +19,8 @@ class LitterRobotNightLightModeSwitch(LitterRobotConfigEntity, SwitchEntity): @property def is_on(self) -> bool: """Return true if switch is on.""" + if self._refresh_callback is not None: + return self._assumed_state return self.robot.night_light_mode_enabled @property @@ -28,11 +30,11 @@ class LitterRobotNightLightModeSwitch(LitterRobotConfigEntity, SwitchEntity): async def async_turn_on(self, **kwargs: Any) -> None: """Turn the switch on.""" - await self.perform_action_and_refresh(self.robot.set_night_light, True) + await self.perform_action_and_assume_state(self.robot.set_night_light, True) async def async_turn_off(self, **kwargs: Any) -> None: """Turn the switch off.""" - await self.perform_action_and_refresh(self.robot.set_night_light, False) + await self.perform_action_and_assume_state(self.robot.set_night_light, False) class LitterRobotPanelLockoutSwitch(LitterRobotConfigEntity, SwitchEntity): @@ -41,6 +43,8 @@ class LitterRobotPanelLockoutSwitch(LitterRobotConfigEntity, SwitchEntity): @property def is_on(self) -> bool: """Return true if switch is on.""" + if self._refresh_callback is not None: + return self._assumed_state return self.robot.panel_lock_enabled @property @@ -50,11 +54,11 @@ class LitterRobotPanelLockoutSwitch(LitterRobotConfigEntity, SwitchEntity): async def async_turn_on(self, **kwargs: Any) -> None: """Turn the switch on.""" - await self.perform_action_and_refresh(self.robot.set_panel_lockout, True) + await self.perform_action_and_assume_state(self.robot.set_panel_lockout, True) async def async_turn_off(self, **kwargs: Any) -> None: """Turn the switch off.""" - await self.perform_action_and_refresh(self.robot.set_panel_lockout, False) + await self.perform_action_and_assume_state(self.robot.set_panel_lockout, False) ROBOT_SWITCHES: list[tuple[type[LitterRobotConfigEntity], str]] = [ diff --git a/requirements_all.txt b/requirements_all.txt index 41d8ac0201d..24162ca05bb 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1604,7 +1604,7 @@ pylibrespot-java==0.1.0 pylitejet==0.3.0 # homeassistant.components.litterrobot -pylitterbot==2021.10.1 +pylitterbot==2021.11.0 # homeassistant.components.loopenergy pyloopenergy==0.2.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index ef8605a6530..c0b4a99dfdf 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -971,7 +971,7 @@ pylibrespot-java==0.1.0 pylitejet==0.3.0 # homeassistant.components.litterrobot -pylitterbot==2021.10.1 +pylitterbot==2021.11.0 # homeassistant.components.lutron_caseta pylutron-caseta==0.11.0 diff --git a/tests/components/litterrobot/test_switch.py b/tests/components/litterrobot/test_switch.py index d651b09fadc..99c34e4273f 100644 --- a/tests/components/litterrobot/test_switch.py +++ b/tests/components/litterrobot/test_switch.py @@ -1,5 +1,6 @@ """Test the Litter-Robot switch entity.""" from datetime import timedelta +from unittest.mock import MagicMock import pytest @@ -9,7 +10,13 @@ from homeassistant.components.switch import ( SERVICE_TURN_OFF, SERVICE_TURN_ON, ) -from homeassistant.const import ATTR_ENTITY_ID, ENTITY_CATEGORY_CONFIG, STATE_ON +from homeassistant.const import ( + ATTR_ENTITY_ID, + ENTITY_CATEGORY_CONFIG, + STATE_OFF, + STATE_ON, +) +from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry from homeassistant.util.dt import utcnow @@ -21,13 +28,13 @@ NIGHT_LIGHT_MODE_ENTITY_ID = "switch.test_night_light_mode" PANEL_LOCKOUT_ENTITY_ID = "switch.test_panel_lockout" -async def test_switch(hass, mock_account): +async def test_switch(hass: HomeAssistant, mock_account: MagicMock): """Tests the switch entity was set up.""" await setup_integration(hass, mock_account, PLATFORM_DOMAIN) - switch = hass.states.get(NIGHT_LIGHT_MODE_ENTITY_ID) - assert switch - assert switch.state == STATE_ON + state = hass.states.get(NIGHT_LIGHT_MODE_ENTITY_ID) + assert state + assert state.state == STATE_ON ent_reg = entity_registry.async_get(hass) entity_entry = ent_reg.async_get(NIGHT_LIGHT_MODE_ENTITY_ID) @@ -42,12 +49,14 @@ async def test_switch(hass, mock_account): (PANEL_LOCKOUT_ENTITY_ID, "set_panel_lockout"), ], ) -async def test_on_off_commands(hass, mock_account, entity_id, robot_command): +async def test_on_off_commands( + hass: HomeAssistant, mock_account: MagicMock, entity_id: str, robot_command: str +): """Test sending commands to the switch.""" await setup_integration(hass, mock_account, PLATFORM_DOMAIN) - switch = hass.states.get(entity_id) - assert switch + state = hass.states.get(entity_id) + assert state data = {ATTR_ENTITY_ID: entity_id} @@ -65,3 +74,6 @@ async def test_on_off_commands(hass, mock_account, entity_id, robot_command): future = utcnow() + timedelta(seconds=REFRESH_WAIT_TIME_SECONDS) async_fire_time_changed(hass, future) assert getattr(mock_account.robots[0], robot_command).call_count == count + state = hass.states.get(entity_id) + assert state + assert state.state == STATE_ON if service == SERVICE_TURN_ON else STATE_OFF