From 2f24fc0fd4a0cd8e1607f5e67548677ba29f8f6e Mon Sep 17 00:00:00 2001 From: "David F. Mulcahey" Date: Mon, 29 Nov 2021 20:00:39 -0500 Subject: [PATCH] Fix Flo returning stale data (#60491) * Fix Flo returning stale data * update tests * update coverage --- homeassistant/components/flo/device.py | 10 +++++++++- homeassistant/components/flo/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/flo/conftest.py | 7 +++++++ tests/components/flo/fixtures/ping_response.json | 8 ++++++++ tests/components/flo/test_device.py | 16 +++++++++++++++- tests/components/flo/test_sensor.py | 2 +- tests/components/flo/test_services.py | 10 +++++----- 9 files changed, 48 insertions(+), 11 deletions(-) create mode 100644 tests/components/flo/fixtures/ping_response.json diff --git a/homeassistant/components/flo/device.py b/homeassistant/components/flo/device.py index f32aa7e6e32..cc32acb485c 100644 --- a/homeassistant/components/flo/device.py +++ b/homeassistant/components/flo/device.py @@ -42,7 +42,11 @@ class FloDeviceDataUpdateCoordinator(DataUpdateCoordinator): try: async with timeout(10): await asyncio.gather( - *[self._update_device(), self._update_consumption_data()] + *[ + self.send_presence_ping(), + self._update_device(), + self._update_consumption_data(), + ] ) except (RequestError) as error: raise UpdateFailed(error) from error @@ -188,6 +192,10 @@ class FloDeviceDataUpdateCoordinator(DataUpdateCoordinator): """Return the battery level for battery-powered device, e.g. leak detectors.""" return self._device_information["battery"]["level"] + async def send_presence_ping(self): + """Send Flo a presence ping.""" + await self.api_client.presence.ping() + async def async_set_mode_home(self): """Set the Flo location to home mode.""" await self.api_client.location.set_mode_home(self._flo_location_id) diff --git a/homeassistant/components/flo/manifest.json b/homeassistant/components/flo/manifest.json index 11972f5056b..6d1e002012c 100644 --- a/homeassistant/components/flo/manifest.json +++ b/homeassistant/components/flo/manifest.json @@ -3,7 +3,7 @@ "name": "Flo", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/flo", - "requirements": ["aioflo==0.4.1"], + "requirements": ["aioflo==2021.11.0"], "codeowners": ["@dmulcahey"], "iot_class": "cloud_polling" } diff --git a/requirements_all.txt b/requirements_all.txt index df0f31ea28a..b010a5128a9 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -164,7 +164,7 @@ aioemonitor==1.0.5 aioesphomeapi==10.3.0 # homeassistant.components.flo -aioflo==0.4.1 +aioflo==2021.11.0 # homeassistant.components.yi aioftp==0.12.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 19df25b2390..8e7d32bfd7c 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -115,7 +115,7 @@ aioemonitor==1.0.5 aioesphomeapi==10.3.0 # homeassistant.components.flo -aioflo==0.4.1 +aioflo==2021.11.0 # homeassistant.components.guardian aioguardian==2021.11.0 diff --git a/tests/components/flo/conftest.py b/tests/components/flo/conftest.py index 6a82c0f4791..1484b10eae2 100644 --- a/tests/components/flo/conftest.py +++ b/tests/components/flo/conftest.py @@ -44,6 +44,13 @@ def aioclient_mock_fixture(aioclient_mock): headers={"Content-Type": CONTENT_TYPE_JSON}, status=HTTPStatus.OK, ) + # Mocks the presence ping response for flo. + aioclient_mock.post( + "https://api-gw.meetflo.com/api/v2/presence/me", + text=load_fixture("flo/ping_response.json"), + headers={"Content-Type": CONTENT_TYPE_JSON}, + status=HTTPStatus.OK, + ) # Mocks the devices for flo. aioclient_mock.get( "https://api-gw.meetflo.com/api/v2/devices/98765", diff --git a/tests/components/flo/fixtures/ping_response.json b/tests/components/flo/fixtures/ping_response.json new file mode 100644 index 00000000000..950519289e6 --- /dev/null +++ b/tests/components/flo/fixtures/ping_response.json @@ -0,0 +1,8 @@ +{ + "ipAddress": "11.111.111.111", + "userId": "12345abcde", + "action": "report", + "type": "user", + "appName": "legacy", + "userData": { "account": { "type": "personal" } } +} diff --git a/tests/components/flo/test_device.py b/tests/components/flo/test_device.py index 5ac31a2bff9..3e08d289aef 100644 --- a/tests/components/flo/test_device.py +++ b/tests/components/flo/test_device.py @@ -1,9 +1,14 @@ """Define tests for device-related endpoints.""" from datetime import timedelta +from unittest.mock import patch + +from aioflo.errors import RequestError +import pytest from homeassistant.components.flo.const import DOMAIN as FLO_DOMAIN from homeassistant.components.flo.device import FloDeviceDataUpdateCoordinator from homeassistant.const import CONF_PASSWORD, CONF_USERNAME +from homeassistant.helpers.update_coordinator import UpdateFailed from homeassistant.setup import async_setup_component from homeassistant.util import dt @@ -67,10 +72,19 @@ async def test_device(hass, config_entry, aioclient_mock_fixture, aioclient_mock assert detector.model == "puck_v1" assert detector.manufacturer == "Flo by Moen" assert detector.device_name == "Kitchen Sink" + assert detector.serial_number == "111111111112" call_count = aioclient_mock.call_count async_fire_time_changed(hass, dt.utcnow() + timedelta(seconds=90)) await hass.async_block_till_done() - assert aioclient_mock.call_count == call_count + 4 + assert aioclient_mock.call_count == call_count + 6 + + # test error sending device ping + with patch( + "homeassistant.components.flo.device.FloDeviceDataUpdateCoordinator.send_presence_ping", + side_effect=RequestError, + ): + with pytest.raises(UpdateFailed): + await valve._async_update_data() diff --git a/tests/components/flo/test_sensor.py b/tests/components/flo/test_sensor.py index f1572dae02c..ec044286b0d 100644 --- a/tests/components/flo/test_sensor.py +++ b/tests/components/flo/test_sensor.py @@ -50,4 +50,4 @@ async def test_manual_update_entity( {ATTR_ENTITY_ID: ["sensor.current_system_mode"]}, blocking=True, ) - assert aioclient_mock.call_count == call_count + 2 + assert aioclient_mock.call_count == call_count + 3 diff --git a/tests/components/flo/test_services.py b/tests/components/flo/test_services.py index 4941a118e48..699bd97ebed 100644 --- a/tests/components/flo/test_services.py +++ b/tests/components/flo/test_services.py @@ -26,7 +26,7 @@ async def test_services(hass, config_entry, aioclient_mock_fixture, aioclient_mo await hass.async_block_till_done() assert len(hass.data[FLO_DOMAIN][config_entry.entry_id]["devices"]) == 2 - assert aioclient_mock.call_count == 6 + assert aioclient_mock.call_count == 8 await hass.services.async_call( FLO_DOMAIN, @@ -35,7 +35,7 @@ async def test_services(hass, config_entry, aioclient_mock_fixture, aioclient_mo blocking=True, ) await hass.async_block_till_done() - assert aioclient_mock.call_count == 7 + assert aioclient_mock.call_count == 9 await hass.services.async_call( FLO_DOMAIN, @@ -44,7 +44,7 @@ async def test_services(hass, config_entry, aioclient_mock_fixture, aioclient_mo blocking=True, ) await hass.async_block_till_done() - assert aioclient_mock.call_count == 8 + assert aioclient_mock.call_count == 10 await hass.services.async_call( FLO_DOMAIN, @@ -53,7 +53,7 @@ async def test_services(hass, config_entry, aioclient_mock_fixture, aioclient_mo blocking=True, ) await hass.async_block_till_done() - assert aioclient_mock.call_count == 9 + assert aioclient_mock.call_count == 11 await hass.services.async_call( FLO_DOMAIN, @@ -66,4 +66,4 @@ async def test_services(hass, config_entry, aioclient_mock_fixture, aioclient_mo blocking=True, ) await hass.async_block_till_done() - assert aioclient_mock.call_count == 10 + assert aioclient_mock.call_count == 12