diff --git a/homeassistant/components/reolink/host.py b/homeassistant/components/reolink/host.py index a23f53ff9cd..2f646ba9090 100644 --- a/homeassistant/components/reolink/host.py +++ b/homeassistant/components/reolink/host.py @@ -158,10 +158,10 @@ class ReolinkHost: store: Store[str] | None = None if self._config_entry_id is not None: store = get_store(self._hass, self._config_entry_id) - if self._config.get(CONF_SUPPORTS_PRIVACY_MODE): - data = await store.async_load() - if data: - self._api.set_raw_host_data(data) + if self._config.get(CONF_SUPPORTS_PRIVACY_MODE) and ( + data := await store.async_load() + ): + self._api.set_raw_host_data(data) await self._api.get_host_data() diff --git a/tests/components/reolink/test_init.py b/tests/components/reolink/test_init.py index 25029375eb6..28d8c542f4f 100644 --- a/tests/components/reolink/test_init.py +++ b/tests/components/reolink/test_init.py @@ -860,6 +860,21 @@ async def test_privacy_mode_change_callback( assert reolink_connect.get_states.call_count >= 1 assert hass.states.get(entity_id).state == STATE_ON + # test cleanup during unloading, first reset to privacy mode ON + reolink_connect.baichuan.privacy_mode.return_value = True + callback_mock.callback_func() + freezer.tick(5) + async_fire_time_changed(hass) + await hass.async_block_till_done() + # now fire the callback again, but unload before refresh took place + reolink_connect.baichuan.privacy_mode.return_value = False + callback_mock.callback_func() + await hass.async_block_till_done() + + await hass.config_entries.async_unload(config_entry.entry_id) + await hass.async_block_till_done() + assert config_entry.state is ConfigEntryState.NOT_LOADED + async def test_remove( hass: HomeAssistant, diff --git a/tests/components/reolink/test_switch.py b/tests/components/reolink/test_switch.py index 2e7c1556201..2b2c33f0e8f 100644 --- a/tests/components/reolink/test_switch.py +++ b/tests/components/reolink/test_switch.py @@ -29,6 +29,211 @@ from .conftest import TEST_CAM_NAME, TEST_NVR_NAME, TEST_UID from tests.common import MockConfigEntry, async_fire_time_changed +async def test_switch( + hass: HomeAssistant, + config_entry: MockConfigEntry, + freezer: FrozenDateTimeFactory, + reolink_connect: MagicMock, +) -> None: + """Test switch entity.""" + reolink_connect.camera_name.return_value = TEST_CAM_NAME + reolink_connect.audio_record.return_value = True + + with patch("homeassistant.components.reolink.PLATFORMS", [Platform.SWITCH]): + assert await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + assert config_entry.state is ConfigEntryState.LOADED + + entity_id = f"{Platform.SWITCH}.{TEST_CAM_NAME}_record_audio" + assert hass.states.get(entity_id).state == STATE_ON + + reolink_connect.audio_record.return_value = False + freezer.tick(DEVICE_UPDATE_INTERVAL) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + assert hass.states.get(entity_id).state == STATE_OFF + + # test switch turn on + await hass.services.async_call( + SWITCH_DOMAIN, + SERVICE_TURN_ON, + {ATTR_ENTITY_ID: entity_id}, + blocking=True, + ) + reolink_connect.set_audio.assert_called_with(0, True) + + reolink_connect.set_audio.side_effect = ReolinkError("Test error") + with pytest.raises(HomeAssistantError): + await hass.services.async_call( + SWITCH_DOMAIN, + SERVICE_TURN_ON, + {ATTR_ENTITY_ID: entity_id}, + blocking=True, + ) + + # test switch turn off + reolink_connect.set_audio.reset_mock(side_effect=True) + await hass.services.async_call( + SWITCH_DOMAIN, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: entity_id}, + blocking=True, + ) + reolink_connect.set_audio.assert_called_with(0, False) + + reolink_connect.set_audio.side_effect = ReolinkError("Test error") + with pytest.raises(HomeAssistantError): + await hass.services.async_call( + SWITCH_DOMAIN, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: entity_id}, + blocking=True, + ) + + reolink_connect.set_audio.reset_mock(side_effect=True) + + reolink_connect.camera_online.return_value = False + freezer.tick(DEVICE_UPDATE_INTERVAL) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + assert hass.states.get(entity_id).state == STATE_UNAVAILABLE + + reolink_connect.camera_online.return_value = True + + +async def test_host_switch( + hass: HomeAssistant, + config_entry: MockConfigEntry, + freezer: FrozenDateTimeFactory, + reolink_connect: MagicMock, +) -> None: + """Test host switch entity.""" + reolink_connect.camera_name.return_value = TEST_CAM_NAME + reolink_connect.email_enabled.return_value = True + reolink_connect.is_hub = False + reolink_connect.supported.return_value = True + + with patch("homeassistant.components.reolink.PLATFORMS", [Platform.SWITCH]): + assert await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + assert config_entry.state is ConfigEntryState.LOADED + + entity_id = f"{Platform.SWITCH}.{TEST_NVR_NAME}_email_on_event" + assert hass.states.get(entity_id).state == STATE_ON + + reolink_connect.email_enabled.return_value = False + freezer.tick(DEVICE_UPDATE_INTERVAL) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + assert hass.states.get(entity_id).state == STATE_OFF + + # test switch turn on + await hass.services.async_call( + SWITCH_DOMAIN, + SERVICE_TURN_ON, + {ATTR_ENTITY_ID: entity_id}, + blocking=True, + ) + reolink_connect.set_email.assert_called_with(None, True) + + reolink_connect.set_email.side_effect = ReolinkError("Test error") + with pytest.raises(HomeAssistantError): + await hass.services.async_call( + SWITCH_DOMAIN, + SERVICE_TURN_ON, + {ATTR_ENTITY_ID: entity_id}, + blocking=True, + ) + + # test switch turn off + reolink_connect.set_email.reset_mock(side_effect=True) + await hass.services.async_call( + SWITCH_DOMAIN, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: entity_id}, + blocking=True, + ) + reolink_connect.set_email.assert_called_with(None, False) + + reolink_connect.set_email.side_effect = ReolinkError("Test error") + with pytest.raises(HomeAssistantError): + await hass.services.async_call( + SWITCH_DOMAIN, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: entity_id}, + blocking=True, + ) + + reolink_connect.set_email.reset_mock(side_effect=True) + + +async def test_chime_switch( + hass: HomeAssistant, + config_entry: MockConfigEntry, + freezer: FrozenDateTimeFactory, + reolink_connect: MagicMock, + test_chime: Chime, +) -> None: + """Test host switch entity.""" + with patch("homeassistant.components.reolink.PLATFORMS", [Platform.SWITCH]): + assert await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + assert config_entry.state is ConfigEntryState.LOADED + + entity_id = f"{Platform.SWITCH}.test_chime_led" + assert hass.states.get(entity_id).state == STATE_ON + + test_chime.led_state = False + freezer.tick(DEVICE_UPDATE_INTERVAL) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + assert hass.states.get(entity_id).state == STATE_OFF + + # test switch turn on + test_chime.set_option = AsyncMock() + await hass.services.async_call( + SWITCH_DOMAIN, + SERVICE_TURN_ON, + {ATTR_ENTITY_ID: entity_id}, + blocking=True, + ) + test_chime.set_option.assert_called_with(led=True) + + test_chime.set_option.side_effect = ReolinkError("Test error") + with pytest.raises(HomeAssistantError): + await hass.services.async_call( + SWITCH_DOMAIN, + SERVICE_TURN_ON, + {ATTR_ENTITY_ID: entity_id}, + blocking=True, + ) + + # test switch turn off + test_chime.set_option.reset_mock(side_effect=True) + await hass.services.async_call( + SWITCH_DOMAIN, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: entity_id}, + blocking=True, + ) + test_chime.set_option.assert_called_with(led=False) + + test_chime.set_option.side_effect = ReolinkError("Test error") + with pytest.raises(HomeAssistantError): + await hass.services.async_call( + SWITCH_DOMAIN, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: entity_id}, + blocking=True, + ) + + test_chime.set_option.reset_mock(side_effect=True) + + @pytest.mark.parametrize( ( "original_id", @@ -171,206 +376,3 @@ async def test_hub_switches_repair_issue( reolink_connect.is_hub = False reolink_connect.supported.return_value = True - - -async def test_switch( - hass: HomeAssistant, - config_entry: MockConfigEntry, - freezer: FrozenDateTimeFactory, - reolink_connect: MagicMock, -) -> None: - """Test switch entity.""" - reolink_connect.camera_name.return_value = TEST_CAM_NAME - reolink_connect.audio_record.return_value = True - - with patch("homeassistant.components.reolink.PLATFORMS", [Platform.SWITCH]): - assert await hass.config_entries.async_setup(config_entry.entry_id) - await hass.async_block_till_done() - assert config_entry.state is ConfigEntryState.LOADED - - entity_id = f"{Platform.SWITCH}.{TEST_CAM_NAME}_record_audio" - assert hass.states.get(entity_id).state == STATE_ON - - reolink_connect.audio_record.return_value = False - freezer.tick(DEVICE_UPDATE_INTERVAL) - async_fire_time_changed(hass) - await hass.async_block_till_done() - - assert hass.states.get(entity_id).state == STATE_OFF - - # test switch turn on - await hass.services.async_call( - SWITCH_DOMAIN, - SERVICE_TURN_ON, - {ATTR_ENTITY_ID: entity_id}, - blocking=True, - ) - reolink_connect.set_audio.assert_called_with(0, True) - - reolink_connect.set_audio.side_effect = ReolinkError("Test error") - with pytest.raises(HomeAssistantError): - await hass.services.async_call( - SWITCH_DOMAIN, - SERVICE_TURN_ON, - {ATTR_ENTITY_ID: entity_id}, - blocking=True, - ) - - # test switch turn off - reolink_connect.set_audio.reset_mock(side_effect=True) - await hass.services.async_call( - SWITCH_DOMAIN, - SERVICE_TURN_OFF, - {ATTR_ENTITY_ID: entity_id}, - blocking=True, - ) - reolink_connect.set_audio.assert_called_with(0, False) - - reolink_connect.set_audio.side_effect = ReolinkError("Test error") - with pytest.raises(HomeAssistantError): - await hass.services.async_call( - SWITCH_DOMAIN, - SERVICE_TURN_OFF, - {ATTR_ENTITY_ID: entity_id}, - blocking=True, - ) - - reolink_connect.set_audio.reset_mock(side_effect=True) - - reolink_connect.camera_online.return_value = False - freezer.tick(DEVICE_UPDATE_INTERVAL) - async_fire_time_changed(hass) - await hass.async_block_till_done() - - assert hass.states.get(entity_id).state == STATE_UNAVAILABLE - - reolink_connect.camera_online.return_value = True - - -async def test_host_switch( - hass: HomeAssistant, - config_entry: MockConfigEntry, - freezer: FrozenDateTimeFactory, - reolink_connect: MagicMock, -) -> None: - """Test host switch entity.""" - reolink_connect.camera_name.return_value = TEST_CAM_NAME - reolink_connect.email_enabled.return_value = True - - with patch("homeassistant.components.reolink.PLATFORMS", [Platform.SWITCH]): - assert await hass.config_entries.async_setup(config_entry.entry_id) - await hass.async_block_till_done() - assert config_entry.state is ConfigEntryState.LOADED - - entity_id = f"{Platform.SWITCH}.{TEST_NVR_NAME}_email_on_event" - assert hass.states.get(entity_id).state == STATE_ON - - reolink_connect.email_enabled.return_value = False - freezer.tick(DEVICE_UPDATE_INTERVAL) - async_fire_time_changed(hass) - await hass.async_block_till_done() - - assert hass.states.get(entity_id).state == STATE_OFF - - # test switch turn on - await hass.services.async_call( - SWITCH_DOMAIN, - SERVICE_TURN_ON, - {ATTR_ENTITY_ID: entity_id}, - blocking=True, - ) - reolink_connect.set_email.assert_called_with(None, True) - - reolink_connect.set_email.side_effect = ReolinkError("Test error") - with pytest.raises(HomeAssistantError): - await hass.services.async_call( - SWITCH_DOMAIN, - SERVICE_TURN_ON, - {ATTR_ENTITY_ID: entity_id}, - blocking=True, - ) - - # test switch turn off - reolink_connect.set_email.reset_mock(side_effect=True) - await hass.services.async_call( - SWITCH_DOMAIN, - SERVICE_TURN_OFF, - {ATTR_ENTITY_ID: entity_id}, - blocking=True, - ) - reolink_connect.set_email.assert_called_with(None, False) - - reolink_connect.set_email.side_effect = ReolinkError("Test error") - with pytest.raises(HomeAssistantError): - await hass.services.async_call( - SWITCH_DOMAIN, - SERVICE_TURN_OFF, - {ATTR_ENTITY_ID: entity_id}, - blocking=True, - ) - - reolink_connect.set_email.reset_mock(side_effect=True) - - -async def test_chime_switch( - hass: HomeAssistant, - config_entry: MockConfigEntry, - freezer: FrozenDateTimeFactory, - reolink_connect: MagicMock, - test_chime: Chime, -) -> None: - """Test host switch entity.""" - with patch("homeassistant.components.reolink.PLATFORMS", [Platform.SWITCH]): - assert await hass.config_entries.async_setup(config_entry.entry_id) - await hass.async_block_till_done() - assert config_entry.state is ConfigEntryState.LOADED - - entity_id = f"{Platform.SWITCH}.test_chime_led" - assert hass.states.get(entity_id).state == STATE_ON - - test_chime.led_state = False - freezer.tick(DEVICE_UPDATE_INTERVAL) - async_fire_time_changed(hass) - await hass.async_block_till_done() - - assert hass.states.get(entity_id).state == STATE_OFF - - # test switch turn on - test_chime.set_option = AsyncMock() - await hass.services.async_call( - SWITCH_DOMAIN, - SERVICE_TURN_ON, - {ATTR_ENTITY_ID: entity_id}, - blocking=True, - ) - test_chime.set_option.assert_called_with(led=True) - - test_chime.set_option.side_effect = ReolinkError("Test error") - with pytest.raises(HomeAssistantError): - await hass.services.async_call( - SWITCH_DOMAIN, - SERVICE_TURN_ON, - {ATTR_ENTITY_ID: entity_id}, - blocking=True, - ) - - # test switch turn off - test_chime.set_option.reset_mock(side_effect=True) - await hass.services.async_call( - SWITCH_DOMAIN, - SERVICE_TURN_OFF, - {ATTR_ENTITY_ID: entity_id}, - blocking=True, - ) - test_chime.set_option.assert_called_with(led=False) - - test_chime.set_option.side_effect = ReolinkError("Test error") - with pytest.raises(HomeAssistantError): - await hass.services.async_call( - SWITCH_DOMAIN, - SERVICE_TURN_OFF, - {ATTR_ENTITY_ID: entity_id}, - blocking=True, - ) - - test_chime.set_option.reset_mock(side_effect=True)