Make Hydrawise poll non-critical data less frequently (#130289)

This commit is contained in:
David Knowles 2024-11-15 04:30:37 -05:00 committed by GitHub
parent 35bf584a9c
commit 027a643f24
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 177 additions and 78 deletions

View File

@ -7,8 +7,12 @@ from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, Platform
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed from homeassistant.exceptions import ConfigEntryAuthFailed
from .const import DOMAIN, SCAN_INTERVAL from .const import DOMAIN
from .coordinator import HydrawiseDataUpdateCoordinator from .coordinator import (
HydrawiseMainDataUpdateCoordinator,
HydrawiseUpdateCoordinators,
HydrawiseWaterUseDataUpdateCoordinator,
)
PLATFORMS: list[Platform] = [ PLATFORMS: list[Platform] = [
Platform.BINARY_SENSOR, Platform.BINARY_SENSOR,
@ -29,9 +33,18 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
auth.Auth(config_entry.data[CONF_USERNAME], config_entry.data[CONF_PASSWORD]) auth.Auth(config_entry.data[CONF_USERNAME], config_entry.data[CONF_PASSWORD])
) )
coordinator = HydrawiseDataUpdateCoordinator(hass, hydrawise, SCAN_INTERVAL) main_coordinator = HydrawiseMainDataUpdateCoordinator(hass, hydrawise)
await coordinator.async_config_entry_first_refresh() await main_coordinator.async_config_entry_first_refresh()
hass.data.setdefault(DOMAIN, {})[config_entry.entry_id] = coordinator water_use_coordinator = HydrawiseWaterUseDataUpdateCoordinator(
hass, hydrawise, main_coordinator
)
await water_use_coordinator.async_config_entry_first_refresh()
hass.data.setdefault(DOMAIN, {})[config_entry.entry_id] = (
HydrawiseUpdateCoordinators(
main=main_coordinator,
water_use=water_use_coordinator,
)
)
await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS) await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS)
return True return True

View File

@ -21,7 +21,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import VolDictType from homeassistant.helpers.typing import VolDictType
from .const import DOMAIN, SERVICE_RESUME, SERVICE_START_WATERING, SERVICE_SUSPEND from .const import DOMAIN, SERVICE_RESUME, SERVICE_START_WATERING, SERVICE_SUSPEND
from .coordinator import HydrawiseDataUpdateCoordinator from .coordinator import HydrawiseUpdateCoordinators
from .entity import HydrawiseEntity from .entity import HydrawiseEntity
@ -81,18 +81,16 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up the Hydrawise binary_sensor platform.""" """Set up the Hydrawise binary_sensor platform."""
coordinator: HydrawiseDataUpdateCoordinator = hass.data[DOMAIN][ coordinators: HydrawiseUpdateCoordinators = hass.data[DOMAIN][config_entry.entry_id]
config_entry.entry_id
]
entities: list[HydrawiseBinarySensor] = [] entities: list[HydrawiseBinarySensor] = []
for controller in coordinator.data.controllers.values(): for controller in coordinators.main.data.controllers.values():
entities.extend( entities.extend(
HydrawiseBinarySensor(coordinator, description, controller) HydrawiseBinarySensor(coordinators.main, description, controller)
for description in CONTROLLER_BINARY_SENSORS for description in CONTROLLER_BINARY_SENSORS
) )
entities.extend( entities.extend(
HydrawiseBinarySensor( HydrawiseBinarySensor(
coordinator, coordinators.main,
description, description,
controller, controller,
sensor_id=sensor.id, sensor_id=sensor.id,
@ -103,7 +101,7 @@ async def async_setup_entry(
) )
entities.extend( entities.extend(
HydrawiseZoneBinarySensor( HydrawiseZoneBinarySensor(
coordinator, description, controller, zone_id=zone.id coordinators.main, description, controller, zone_id=zone.id
) )
for zone in controller.zones for zone in controller.zones
for description in ZONE_BINARY_SENSORS for description in ZONE_BINARY_SENSORS

View File

@ -10,7 +10,8 @@ DEFAULT_WATERING_TIME = timedelta(minutes=15)
MANUFACTURER = "Hydrawise" MANUFACTURER = "Hydrawise"
SCAN_INTERVAL = timedelta(seconds=60) MAIN_SCAN_INTERVAL = timedelta(seconds=60)
WATER_USE_SCAN_INTERVAL = timedelta(minutes=60)
SIGNAL_UPDATE_HYDRAWISE = "hydrawise_update" SIGNAL_UPDATE_HYDRAWISE = "hydrawise_update"

View File

@ -2,8 +2,7 @@
from __future__ import annotations from __future__ import annotations
from dataclasses import dataclass from dataclasses import dataclass, field
from datetime import timedelta
from pydrawise import Hydrawise from pydrawise import Hydrawise
from pydrawise.schema import Controller, ControllerWaterUseSummary, Sensor, User, Zone from pydrawise.schema import Controller, ControllerWaterUseSummary, Sensor, User, Zone
@ -12,7 +11,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from homeassistant.util.dt import now from homeassistant.util.dt import now
from .const import DOMAIN, LOGGER from .const import DOMAIN, LOGGER, MAIN_SCAN_INTERVAL, WATER_USE_SCAN_INTERVAL
@dataclass @dataclass
@ -20,22 +19,39 @@ class HydrawiseData:
"""Container for data fetched from the Hydrawise API.""" """Container for data fetched from the Hydrawise API."""
user: User user: User
controllers: dict[int, Controller] controllers: dict[int, Controller] = field(default_factory=dict)
zones: dict[int, Zone] zones: dict[int, Zone] = field(default_factory=dict)
sensors: dict[int, Sensor] sensors: dict[int, Sensor] = field(default_factory=dict)
daily_water_summary: dict[int, ControllerWaterUseSummary] daily_water_summary: dict[int, ControllerWaterUseSummary] = field(
default_factory=dict
)
@dataclass
class HydrawiseUpdateCoordinators:
"""Container for all Hydrawise DataUpdateCoordinator instances."""
main: HydrawiseMainDataUpdateCoordinator
water_use: HydrawiseWaterUseDataUpdateCoordinator
class HydrawiseDataUpdateCoordinator(DataUpdateCoordinator[HydrawiseData]): class HydrawiseDataUpdateCoordinator(DataUpdateCoordinator[HydrawiseData]):
"""The Hydrawise Data Update Coordinator.""" """Base class for Hydrawise Data Update Coordinators."""
api: Hydrawise api: Hydrawise
def __init__(
self, hass: HomeAssistant, api: Hydrawise, scan_interval: timedelta class HydrawiseMainDataUpdateCoordinator(HydrawiseDataUpdateCoordinator):
) -> None: """The main Hydrawise Data Update Coordinator.
This fetches the primary state data for Hydrawise controllers and zones
at a relatively frequent interval so that the primary functions of the
integration are updated in a timely manner.
"""
def __init__(self, hass: HomeAssistant, api: Hydrawise) -> None:
"""Initialize HydrawiseDataUpdateCoordinator.""" """Initialize HydrawiseDataUpdateCoordinator."""
super().__init__(hass, LOGGER, name=DOMAIN, update_interval=scan_interval) super().__init__(hass, LOGGER, name=DOMAIN, update_interval=MAIN_SCAN_INTERVAL)
self.api = api self.api = api
async def _async_update_data(self) -> HydrawiseData: async def _async_update_data(self) -> HydrawiseData:
@ -43,28 +59,56 @@ class HydrawiseDataUpdateCoordinator(DataUpdateCoordinator[HydrawiseData]):
# Don't fetch zones. We'll fetch them for each controller later. # Don't fetch zones. We'll fetch them for each controller later.
# This is to prevent 502 errors in some cases. # This is to prevent 502 errors in some cases.
# See: https://github.com/home-assistant/core/issues/120128 # See: https://github.com/home-assistant/core/issues/120128
user = await self.api.get_user(fetch_zones=False) data = HydrawiseData(user=await self.api.get_user(fetch_zones=False))
controllers = {} for controller in data.user.controllers:
zones = {} data.controllers[controller.id] = controller
sensors = {}
daily_water_summary: dict[int, ControllerWaterUseSummary] = {}
for controller in user.controllers:
controllers[controller.id] = controller
controller.zones = await self.api.get_zones(controller) controller.zones = await self.api.get_zones(controller)
for zone in controller.zones: for zone in controller.zones:
zones[zone.id] = zone data.zones[zone.id] = zone
for sensor in controller.sensors: for sensor in controller.sensors:
sensors[sensor.id] = sensor data.sensors[sensor.id] = sensor
return data
class HydrawiseWaterUseDataUpdateCoordinator(HydrawiseDataUpdateCoordinator):
"""Data Update Coordinator for Hydrawise Water Use.
This fetches data that is more expensive for the Hydrawise API to compute
at a less frequent interval as to not overload the Hydrawise servers.
"""
_main_coordinator: HydrawiseMainDataUpdateCoordinator
def __init__(
self,
hass: HomeAssistant,
api: Hydrawise,
main_coordinator: HydrawiseMainDataUpdateCoordinator,
) -> None:
"""Initialize HydrawiseWaterUseDataUpdateCoordinator."""
super().__init__(
hass,
LOGGER,
name=f"{DOMAIN} water use",
update_interval=WATER_USE_SCAN_INTERVAL,
)
self.api = api
self._main_coordinator = main_coordinator
async def _async_update_data(self) -> HydrawiseData:
"""Fetch the latest data from Hydrawise."""
daily_water_summary: dict[int, ControllerWaterUseSummary] = {}
for controller in self._main_coordinator.data.controllers.values():
daily_water_summary[controller.id] = await self.api.get_water_use_summary( daily_water_summary[controller.id] = await self.api.get_water_use_summary(
controller, controller,
now().replace(hour=0, minute=0, second=0, microsecond=0), now().replace(hour=0, minute=0, second=0, microsecond=0),
now(), now(),
) )
main_data = self._main_coordinator.data
return HydrawiseData( return HydrawiseData(
user=user, user=main_data.user,
controllers=controllers, controllers=main_data.controllers,
zones=zones, zones=main_data.zones,
sensors=sensors, sensors=main_data.sensors,
daily_water_summary=daily_water_summary, daily_water_summary=daily_water_summary,
) )

View File

@ -19,7 +19,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.util import dt as dt_util from homeassistant.util import dt as dt_util
from .const import DOMAIN from .const import DOMAIN
from .coordinator import HydrawiseDataUpdateCoordinator from .coordinator import HydrawiseUpdateCoordinators
from .entity import HydrawiseEntity from .entity import HydrawiseEntity
@ -92,7 +92,7 @@ def _get_controller_daily_total_water_use(sensor: HydrawiseSensor) -> float | No
return daily_water_summary.total_use return daily_water_summary.total_use
CONTROLLER_SENSORS: tuple[HydrawiseSensorEntityDescription, ...] = ( WATER_USE_CONTROLLER_SENSORS: tuple[HydrawiseSensorEntityDescription, ...] = (
HydrawiseSensorEntityDescription( HydrawiseSensorEntityDescription(
key="daily_active_water_time", key="daily_active_water_time",
translation_key="daily_active_water_time", translation_key="daily_active_water_time",
@ -103,6 +103,16 @@ CONTROLLER_SENSORS: tuple[HydrawiseSensorEntityDescription, ...] = (
) )
WATER_USE_ZONE_SENSORS: tuple[HydrawiseSensorEntityDescription, ...] = (
HydrawiseSensorEntityDescription(
key="daily_active_water_time",
translation_key="daily_active_water_time",
device_class=SensorDeviceClass.DURATION,
native_unit_of_measurement=UnitOfTime.SECONDS,
value_fn=_get_zone_daily_active_water_time,
),
)
FLOW_CONTROLLER_SENSORS: tuple[HydrawiseSensorEntityDescription, ...] = ( FLOW_CONTROLLER_SENSORS: tuple[HydrawiseSensorEntityDescription, ...] = (
HydrawiseSensorEntityDescription( HydrawiseSensorEntityDescription(
key="daily_total_water_use", key="daily_total_water_use",
@ -150,13 +160,6 @@ ZONE_SENSORS: tuple[HydrawiseSensorEntityDescription, ...] = (
native_unit_of_measurement=UnitOfTime.MINUTES, native_unit_of_measurement=UnitOfTime.MINUTES,
value_fn=_get_zone_watering_time, value_fn=_get_zone_watering_time,
), ),
HydrawiseSensorEntityDescription(
key="daily_active_water_time",
translation_key="daily_active_water_time",
device_class=SensorDeviceClass.DURATION,
native_unit_of_measurement=UnitOfTime.SECONDS,
value_fn=_get_zone_daily_active_water_time,
),
) )
FLOW_MEASUREMENT_KEYS = [x.key for x in FLOW_CONTROLLER_SENSORS] FLOW_MEASUREMENT_KEYS = [x.key for x in FLOW_CONTROLLER_SENSORS]
@ -168,29 +171,37 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up the Hydrawise sensor platform.""" """Set up the Hydrawise sensor platform."""
coordinator: HydrawiseDataUpdateCoordinator = hass.data[DOMAIN][ coordinators: HydrawiseUpdateCoordinators = hass.data[DOMAIN][config_entry.entry_id]
config_entry.entry_id
]
entities: list[HydrawiseSensor] = [] entities: list[HydrawiseSensor] = []
for controller in coordinator.data.controllers.values(): for controller in coordinators.main.data.controllers.values():
entities.extend( entities.extend(
HydrawiseSensor(coordinator, description, controller) HydrawiseSensor(coordinators.water_use, description, controller)
for description in CONTROLLER_SENSORS for description in WATER_USE_CONTROLLER_SENSORS
) )
entities.extend( entities.extend(
HydrawiseSensor(coordinator, description, controller, zone_id=zone.id) HydrawiseSensor(
coordinators.water_use, description, controller, zone_id=zone.id
)
for zone in controller.zones
for description in WATER_USE_ZONE_SENSORS
)
entities.extend(
HydrawiseSensor(coordinators.main, description, controller, zone_id=zone.id)
for zone in controller.zones for zone in controller.zones
for description in ZONE_SENSORS for description in ZONE_SENSORS
) )
if coordinator.data.daily_water_summary[controller.id].total_use is not None: if (
coordinators.water_use.data.daily_water_summary[controller.id].total_use
is not None
):
# we have a flow sensor for this controller # we have a flow sensor for this controller
entities.extend( entities.extend(
HydrawiseSensor(coordinator, description, controller) HydrawiseSensor(coordinators.water_use, description, controller)
for description in FLOW_CONTROLLER_SENSORS for description in FLOW_CONTROLLER_SENSORS
) )
entities.extend( entities.extend(
HydrawiseSensor( HydrawiseSensor(
coordinator, coordinators.water_use,
description, description,
controller, controller,
zone_id=zone.id, zone_id=zone.id,

View File

@ -20,7 +20,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.util import dt as dt_util from homeassistant.util import dt as dt_util
from .const import DEFAULT_WATERING_TIME, DOMAIN from .const import DEFAULT_WATERING_TIME, DOMAIN
from .coordinator import HydrawiseDataUpdateCoordinator from .coordinator import HydrawiseUpdateCoordinators
from .entity import HydrawiseEntity from .entity import HydrawiseEntity
@ -66,12 +66,10 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up the Hydrawise switch platform.""" """Set up the Hydrawise switch platform."""
coordinator: HydrawiseDataUpdateCoordinator = hass.data[DOMAIN][ coordinators: HydrawiseUpdateCoordinators = hass.data[DOMAIN][config_entry.entry_id]
config_entry.entry_id
]
async_add_entities( async_add_entities(
HydrawiseSwitch(coordinator, description, controller, zone_id=zone.id) HydrawiseSwitch(coordinators.main, description, controller, zone_id=zone.id)
for controller in coordinator.data.controllers.values() for controller in coordinators.main.data.controllers.values()
for zone in controller.zones for zone in controller.zones
for description in SWITCH_TYPES for description in SWITCH_TYPES
) )

View File

@ -17,7 +17,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN from .const import DOMAIN
from .coordinator import HydrawiseDataUpdateCoordinator from .coordinator import HydrawiseUpdateCoordinators
from .entity import HydrawiseEntity from .entity import HydrawiseEntity
VALVE_TYPES: tuple[ValveEntityDescription, ...] = ( VALVE_TYPES: tuple[ValveEntityDescription, ...] = (
@ -34,12 +34,10 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up the Hydrawise valve platform.""" """Set up the Hydrawise valve platform."""
coordinator: HydrawiseDataUpdateCoordinator = hass.data[DOMAIN][ coordinators: HydrawiseUpdateCoordinators = hass.data[DOMAIN][config_entry.entry_id]
config_entry.entry_id
]
async_add_entities( async_add_entities(
HydrawiseValve(coordinator, description, controller, zone_id=zone.id) HydrawiseValve(coordinators.main, description, controller, zone_id=zone.id)
for controller in coordinator.data.controllers.values() for controller in coordinators.main.data.controllers.values()
for zone in controller.zones for zone in controller.zones
for description in VALVE_TYPES for description in VALVE_TYPES
) )

View File

@ -9,7 +9,7 @@ from freezegun.api import FrozenDateTimeFactory
from pydrawise.schema import Controller from pydrawise.schema import Controller
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
from homeassistant.components.hydrawise.const import SCAN_INTERVAL from homeassistant.components.hydrawise.const import MAIN_SCAN_INTERVAL
from homeassistant.const import STATE_OFF, Platform from homeassistant.const import STATE_OFF, Platform
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er from homeassistant.helpers import entity_registry as er
@ -42,7 +42,8 @@ async def test_update_data_fails(
# Make the coordinator refresh data. # Make the coordinator refresh data.
mock_pydrawise.get_user.reset_mock(return_value=True) mock_pydrawise.get_user.reset_mock(return_value=True)
mock_pydrawise.get_user.side_effect = ClientError mock_pydrawise.get_user.side_effect = ClientError
freezer.tick(SCAN_INTERVAL + timedelta(seconds=30)) mock_pydrawise.get_water_use_summary.side_effect = ClientError
freezer.tick(MAIN_SCAN_INTERVAL + timedelta(seconds=30))
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done()
@ -61,7 +62,7 @@ async def test_controller_offline(
"""Test the binary_sensor for the controller being online.""" """Test the binary_sensor for the controller being online."""
# Make the coordinator refresh data. # Make the coordinator refresh data.
controller.online = False controller.online = False
freezer.tick(SCAN_INTERVAL + timedelta(seconds=30)) freezer.tick(MAIN_SCAN_INTERVAL + timedelta(seconds=30))
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done()

View File

@ -8,7 +8,7 @@ from aiohttp import ClientError
from freezegun.api import FrozenDateTimeFactory from freezegun.api import FrozenDateTimeFactory
from pydrawise.schema import Controller from pydrawise.schema import Controller
from homeassistant.components.hydrawise.const import SCAN_INTERVAL from homeassistant.components.hydrawise.const import WATER_USE_SCAN_INTERVAL
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import STATE_OFF, STATE_UNAVAILABLE from homeassistant.const import STATE_OFF, STATE_UNAVAILABLE
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -42,7 +42,8 @@ async def test_api_offline(
config_entry = await mock_add_config_entry() config_entry = await mock_add_config_entry()
mock_pydrawise.get_user.reset_mock(return_value=True) mock_pydrawise.get_user.reset_mock(return_value=True)
mock_pydrawise.get_user.side_effect = ClientError mock_pydrawise.get_user.side_effect = ClientError
freezer.tick(SCAN_INTERVAL + timedelta(seconds=30)) mock_pydrawise.get_water_use_summary.side_effect = ClientError
freezer.tick(WATER_USE_SCAN_INTERVAL + timedelta(seconds=30))
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done()
_test_availability(hass, config_entry, entity_registry) _test_availability(hass, config_entry, entity_registry)

View File

@ -1,12 +1,18 @@
"""Test Hydrawise sensor.""" """Test Hydrawise sensor."""
from collections.abc import Awaitable, Callable from collections.abc import Awaitable, Callable
from unittest.mock import patch from datetime import timedelta
from unittest.mock import AsyncMock, patch
from freezegun.api import FrozenDateTimeFactory
from pydrawise.schema import Controller, ControllerWaterUseSummary, User, Zone from pydrawise.schema import Controller, ControllerWaterUseSummary, User, Zone
import pytest import pytest
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
from homeassistant.components.hydrawise.const import (
MAIN_SCAN_INTERVAL,
WATER_USE_SCAN_INTERVAL,
)
from homeassistant.const import Platform from homeassistant.const import Platform
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er from homeassistant.helpers import entity_registry as er
@ -16,7 +22,7 @@ from homeassistant.util.unit_system import (
UnitSystem, UnitSystem,
) )
from tests.common import MockConfigEntry, snapshot_platform from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform
@pytest.mark.freeze_time("2023-10-01 00:00:00+00:00") @pytest.mark.freeze_time("2023-10-01 00:00:00+00:00")
@ -50,6 +56,34 @@ async def test_suspended_state(
assert next_cycle.state == "unknown" assert next_cycle.state == "unknown"
@pytest.mark.freeze_time("2024-11-01 00:00:00+00:00")
async def test_usage_refresh(
hass: HomeAssistant,
mock_added_config_entry: MockConfigEntry,
mock_pydrawise: AsyncMock,
controller_water_use_summary: ControllerWaterUseSummary,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test that water usage summaries refresh less frequently than other data."""
assert hass.states.get("sensor.zone_one_daily_active_water_use") is not None
mock_pydrawise.get_water_use_summary.assert_called_once()
# Make the coordinator refresh data.
mock_pydrawise.get_water_use_summary.reset_mock()
freezer.tick(MAIN_SCAN_INTERVAL + timedelta(seconds=30))
async_fire_time_changed(hass)
await hass.async_block_till_done()
# Make sure we didn't fetch water use summary again.
mock_pydrawise.get_water_use_summary.assert_not_called()
# Wait for enough time to pass for a water use summary fetch.
mock_pydrawise.get_water_use_summary.return_value = controller_water_use_summary
freezer.tick(WATER_USE_SCAN_INTERVAL + timedelta(seconds=30))
async_fire_time_changed(hass)
await hass.async_block_till_done()
mock_pydrawise.get_water_use_summary.assert_called_once()
async def test_no_sensor_and_water_state( async def test_no_sensor_and_water_state(
hass: HomeAssistant, hass: HomeAssistant,
controller: Controller, controller: Controller,