Do not choke on no awair data (#19708)
* awair: do not choke on no data The awair API returns an empty response for various air data queries when a device is offline. The underlying library (python_awair) does not directly inform us that a device is offline, since we really can only infer it from an empty response - there is no online/offline indicator in the graphql API. So - we should just ensure that we do not attempt to update device state from an empty response. This ensures that the platform does not crash when starting up with offline devices, and also ensures that the platform is marked unavailable once devices go offline. * Fix typo Further proof that coding after 10pm is rolling the dice.pull/19747/head
parent
688bdc6532
commit
87a0118082
|
@ -215,6 +215,10 @@ class AwairData:
|
|||
async def _async_update(self):
|
||||
"""Get the data from Awair API."""
|
||||
resp = await self._client.air_data_latest(self._uuid)
|
||||
|
||||
if not resp:
|
||||
return
|
||||
|
||||
timestamp = dt.parse_datetime(resp[0][ATTR_TIMESTAMP])
|
||||
self.attrs[ATTR_LAST_API_UPDATE] = timestamp
|
||||
self.data[ATTR_SCORE] = resp[0][ATTR_SCORE]
|
||||
|
|
|
@ -45,6 +45,7 @@ AIR_DATA_FIXTURE_UPDATED = json.loads(
|
|||
load_fixture("awair_air_data_latest_updated.json")
|
||||
)
|
||||
AIR_DATA_FIXTURE_UPDATED[0][ATTR_TIMESTAMP] = str(NOW + timedelta(minutes=5))
|
||||
AIR_DATA_FIXTURE_EMPTY = []
|
||||
|
||||
|
||||
@contextmanager
|
||||
|
@ -60,13 +61,13 @@ def alter_time(retval):
|
|||
yield
|
||||
|
||||
|
||||
async def setup_awair(hass, config=None):
|
||||
async def setup_awair(hass, config=None, data_fixture=AIR_DATA_FIXTURE):
|
||||
"""Load the Awair platform."""
|
||||
devices_json = json.loads(load_fixture("awair_devices.json"))
|
||||
devices_mock = mock_coro(devices_json)
|
||||
devices_patch = patch(
|
||||
"python_awair.AwairClient.devices", return_value=devices_mock)
|
||||
air_data_mock = mock_coro(AIR_DATA_FIXTURE)
|
||||
air_data_mock = mock_coro(data_fixture)
|
||||
air_data_patch = patch(
|
||||
"python_awair.AwairClient.air_data_latest", return_value=air_data_mock
|
||||
)
|
||||
|
@ -136,6 +137,12 @@ async def test_bad_platform_setup(hass):
|
|||
assert not hass.states.async_all()
|
||||
|
||||
|
||||
async def test_awair_setup_no_data(hass):
|
||||
"""Ensure that we do not crash during setup when no data is returned."""
|
||||
await setup_awair(hass, data_fixture=AIR_DATA_FIXTURE_EMPTY)
|
||||
assert not hass.states.async_all()
|
||||
|
||||
|
||||
async def test_awair_misc_attributes(hass):
|
||||
"""Test that desired attributes are set."""
|
||||
await setup_awair(hass)
|
||||
|
@ -252,6 +259,19 @@ async def test_availability(hass):
|
|||
|
||||
assert hass.states.get("sensor.awair_score").state == "79"
|
||||
|
||||
future = NOW + timedelta(minutes=90)
|
||||
fixture = AIR_DATA_FIXTURE_EMPTY
|
||||
data_patch = patch(
|
||||
"python_awair.AwairClient.air_data_latest",
|
||||
return_value=mock_coro(fixture)
|
||||
)
|
||||
|
||||
with data_patch, alter_time(future):
|
||||
async_fire_time_changed(hass, future)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert hass.states.get("sensor.awair_score").state == STATE_UNAVAILABLE
|
||||
|
||||
|
||||
async def test_async_update(hass):
|
||||
"""Ensure we can update sensors."""
|
||||
|
|
Loading…
Reference in New Issue