From f73afd71fde471e0ce425216bf0ac02bd925cbbb Mon Sep 17 00:00:00 2001 From: Joost Lekkerkerker Date: Tue, 27 May 2025 08:49:25 +0200 Subject: [PATCH] Fix Amazon devices offline handling (#145656) --- .../components/amazon_devices/entity.py | 6 ++- .../amazon_devices/test_binary_sensor.py | 32 +++++++++++++++ .../components/amazon_devices/test_notify.py | 37 +++++++++++++++++- .../components/amazon_devices/test_switch.py | 39 ++++++++++++++++++- 4 files changed, 110 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/amazon_devices/entity.py b/homeassistant/components/amazon_devices/entity.py index 825a63db476..bab8009ceb0 100644 --- a/homeassistant/components/amazon_devices/entity.py +++ b/homeassistant/components/amazon_devices/entity.py @@ -50,4 +50,8 @@ class AmazonEntity(CoordinatorEntity[AmazonDevicesCoordinator]): @property def available(self) -> bool: """Return True if entity is available.""" - return super().available and self._serial_num in self.coordinator.data + return ( + super().available + and self._serial_num in self.coordinator.data + and self.device.online + ) diff --git a/tests/components/amazon_devices/test_binary_sensor.py b/tests/components/amazon_devices/test_binary_sensor.py index bbe8af17a8e..b31d85e06aa 100644 --- a/tests/components/amazon_devices/test_binary_sensor.py +++ b/tests/components/amazon_devices/test_binary_sensor.py @@ -17,6 +17,7 @@ from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er from . import setup_integration +from .const import TEST_SERIAL_NUMBER from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform @@ -69,3 +70,34 @@ async def test_coordinator_data_update_fails( assert (state := hass.states.get(entity_id)) assert state.state == STATE_UNAVAILABLE + + +async def test_offline_device( + hass: HomeAssistant, + freezer: FrozenDateTimeFactory, + mock_amazon_devices_client: AsyncMock, + mock_config_entry: MockConfigEntry, +) -> None: + """Test offline device handling.""" + + entity_id = "binary_sensor.echo_test_connectivity" + + mock_amazon_devices_client.get_devices_data.return_value[ + TEST_SERIAL_NUMBER + ].online = False + + await setup_integration(hass, mock_config_entry) + + assert (state := hass.states.get(entity_id)) + assert state.state == STATE_UNAVAILABLE + + mock_amazon_devices_client.get_devices_data.return_value[ + TEST_SERIAL_NUMBER + ].online = True + + freezer.tick(SCAN_INTERVAL) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + assert (state := hass.states.get(entity_id)) + assert state.state != STATE_UNAVAILABLE diff --git a/tests/components/amazon_devices/test_notify.py b/tests/components/amazon_devices/test_notify.py index c1147af94c7..b486380fd07 100644 --- a/tests/components/amazon_devices/test_notify.py +++ b/tests/components/amazon_devices/test_notify.py @@ -6,19 +6,21 @@ from freezegun.api import FrozenDateTimeFactory import pytest from syrupy.assertion import SnapshotAssertion +from homeassistant.components.amazon_devices.coordinator import SCAN_INTERVAL from homeassistant.components.notify import ( ATTR_MESSAGE, DOMAIN as NOTIFY_DOMAIN, SERVICE_SEND_MESSAGE, ) -from homeassistant.const import ATTR_ENTITY_ID, Platform +from homeassistant.const import ATTR_ENTITY_ID, STATE_UNAVAILABLE, Platform from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er from homeassistant.util import dt as dt_util from . import setup_integration +from .const import TEST_SERIAL_NUMBER -from tests.common import MockConfigEntry, snapshot_platform +from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform @pytest.mark.usefixtures("entity_registry_enabled_by_default") @@ -68,3 +70,34 @@ async def test_notify_send_message( assert (state := hass.states.get(entity_id)) assert state.state == now.isoformat() + + +async def test_offline_device( + hass: HomeAssistant, + freezer: FrozenDateTimeFactory, + mock_amazon_devices_client: AsyncMock, + mock_config_entry: MockConfigEntry, +) -> None: + """Test offline device handling.""" + + entity_id = "notify.echo_test_announce" + + mock_amazon_devices_client.get_devices_data.return_value[ + TEST_SERIAL_NUMBER + ].online = False + + await setup_integration(hass, mock_config_entry) + + assert (state := hass.states.get(entity_id)) + assert state.state == STATE_UNAVAILABLE + + mock_amazon_devices_client.get_devices_data.return_value[ + TEST_SERIAL_NUMBER + ].online = True + + freezer.tick(SCAN_INTERVAL) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + assert (state := hass.states.get(entity_id)) + assert state.state != STATE_UNAVAILABLE diff --git a/tests/components/amazon_devices/test_switch.py b/tests/components/amazon_devices/test_switch.py index 004d6cce842..24af96db280 100644 --- a/tests/components/amazon_devices/test_switch.py +++ b/tests/components/amazon_devices/test_switch.py @@ -12,7 +12,13 @@ from homeassistant.components.switch import ( SERVICE_TURN_OFF, SERVICE_TURN_ON, ) -from homeassistant.const import ATTR_ENTITY_ID, STATE_OFF, STATE_ON, Platform +from homeassistant.const import ( + ATTR_ENTITY_ID, + STATE_OFF, + STATE_ON, + STATE_UNAVAILABLE, + Platform, +) from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er @@ -89,3 +95,34 @@ async def test_switch_dnd( assert mock_amazon_devices_client.set_do_not_disturb.call_count == 2 assert (state := hass.states.get(entity_id)) assert state.state == STATE_OFF + + +async def test_offline_device( + hass: HomeAssistant, + freezer: FrozenDateTimeFactory, + mock_amazon_devices_client: AsyncMock, + mock_config_entry: MockConfigEntry, +) -> None: + """Test offline device handling.""" + + entity_id = "switch.echo_test_do_not_disturb" + + mock_amazon_devices_client.get_devices_data.return_value[ + TEST_SERIAL_NUMBER + ].online = False + + await setup_integration(hass, mock_config_entry) + + assert (state := hass.states.get(entity_id)) + assert state.state == STATE_UNAVAILABLE + + mock_amazon_devices_client.get_devices_data.return_value[ + TEST_SERIAL_NUMBER + ].online = True + + freezer.tick(SCAN_INTERVAL) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + assert (state := hass.states.get(entity_id)) + assert state.state != STATE_UNAVAILABLE