diff --git a/homeassistant/components/rainforest_eagle/__init__.py b/homeassistant/components/rainforest_eagle/__init__.py index 67baa4dbd99..5be2e778c5d 100644 --- a/homeassistant/components/rainforest_eagle/__init__.py +++ b/homeassistant/components/rainforest_eagle/__init__.py @@ -6,15 +6,15 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.const import Platform from homeassistant.core import HomeAssistant -from . import data from .const import DOMAIN +from .coordinator import EagleDataCoordinator PLATFORMS = [Platform.SENSOR] async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up Rainforest Eagle from a config entry.""" - coordinator = data.EagleDataCoordinator(hass, entry) + coordinator = EagleDataCoordinator(hass, entry) await coordinator.async_config_entry_first_refresh() hass.data.setdefault(DOMAIN, {})[entry.entry_id] = coordinator await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) diff --git a/homeassistant/components/rainforest_eagle/config_flow.py b/homeassistant/components/rainforest_eagle/config_flow.py index b1867fae333..867bc5886db 100644 --- a/homeassistant/components/rainforest_eagle/config_flow.py +++ b/homeassistant/components/rainforest_eagle/config_flow.py @@ -10,8 +10,8 @@ import voluptuous as vol from homeassistant.config_entries import ConfigFlow, ConfigFlowResult from homeassistant.const import CONF_HOST, CONF_TYPE -from . import data from .const import CONF_CLOUD_ID, CONF_HARDWARE_ADDRESS, CONF_INSTALL_CODE, DOMAIN +from .data import CannotConnect, InvalidAuth, async_get_type _LOGGER = logging.getLogger(__name__) @@ -49,15 +49,15 @@ class RainforestEagleConfigFlow(ConfigFlow, domain=DOMAIN): errors = {} try: - eagle_type, hardware_address = await data.async_get_type( + eagle_type, hardware_address = await async_get_type( self.hass, user_input[CONF_CLOUD_ID], user_input[CONF_INSTALL_CODE], user_input[CONF_HOST], ) - except data.CannotConnect: + except CannotConnect: errors["base"] = "cannot_connect" - except data.InvalidAuth: + except InvalidAuth: errors["base"] = "invalid_auth" except Exception: _LOGGER.exception("Unexpected exception") diff --git a/homeassistant/components/rainforest_eagle/coordinator.py b/homeassistant/components/rainforest_eagle/coordinator.py new file mode 100644 index 00000000000..9c714a291ee --- /dev/null +++ b/homeassistant/components/rainforest_eagle/coordinator.py @@ -0,0 +1,131 @@ +"""Rainforest data.""" + +from __future__ import annotations + +import asyncio +from datetime import timedelta +import logging + +import aioeagle +from eagle100 import Eagle as Eagle100Reader + +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import CONF_HOST, CONF_TYPE +from homeassistant.core import HomeAssistant +from homeassistant.helpers import aiohttp_client +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed + +from .const import ( + CONF_CLOUD_ID, + CONF_HARDWARE_ADDRESS, + CONF_INSTALL_CODE, + TYPE_EAGLE_100, +) +from .data import UPDATE_100_ERRORS + +_LOGGER = logging.getLogger(__name__) + + +class EagleDataCoordinator(DataUpdateCoordinator): + """Get the latest data from the Eagle device.""" + + eagle100_reader: Eagle100Reader | None = None + eagle200_meter: aioeagle.ElectricMeter | None = None + + def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None: + """Initialize the data object.""" + self.entry = entry + if self.type == TYPE_EAGLE_100: + self.model = "EAGLE-100" + update_method = self._async_update_data_100 + else: + self.model = "EAGLE-200" + update_method = self._async_update_data_200 + + super().__init__( + hass, + _LOGGER, + name=entry.data[CONF_CLOUD_ID], + update_interval=timedelta(seconds=30), + update_method=update_method, + ) + + @property + def cloud_id(self): + """Return the cloud ID.""" + return self.entry.data[CONF_CLOUD_ID] + + @property + def type(self): + """Return entry type.""" + return self.entry.data[CONF_TYPE] + + @property + def hardware_address(self): + """Return hardware address of meter.""" + return self.entry.data[CONF_HARDWARE_ADDRESS] + + @property + def is_connected(self): + """Return if the hub is connected to the electric meter.""" + if self.eagle200_meter: + return self.eagle200_meter.is_connected + + return True + + async def _async_update_data_200(self): + """Get the latest data from the Eagle-200 device.""" + if (eagle200_meter := self.eagle200_meter) is None: + hub = aioeagle.EagleHub( + aiohttp_client.async_get_clientsession(self.hass), + self.cloud_id, + self.entry.data[CONF_INSTALL_CODE], + host=self.entry.data[CONF_HOST], + ) + eagle200_meter = aioeagle.ElectricMeter.create_instance( + hub, self.hardware_address + ) + is_connected = True + else: + is_connected = eagle200_meter.is_connected + + async with asyncio.timeout(30): + data = await eagle200_meter.get_device_query() + + if self.eagle200_meter is None: + self.eagle200_meter = eagle200_meter + elif is_connected and not eagle200_meter.is_connected: + _LOGGER.warning("Lost connection with electricity meter") + + _LOGGER.debug("API data: %s", data) + return {var["Name"]: var["Value"] for var in data.values()} + + async def _async_update_data_100(self): + """Get the latest data from the Eagle-100 device.""" + try: + data = await self.hass.async_add_executor_job(self._fetch_data_100) + except UPDATE_100_ERRORS as error: + raise UpdateFailed from error + + _LOGGER.debug("API data: %s", data) + return data + + def _fetch_data_100(self): + """Fetch and return the four sensor values in a dict.""" + if self.eagle100_reader is None: + self.eagle100_reader = Eagle100Reader( + self.cloud_id, + self.entry.data[CONF_INSTALL_CODE], + self.entry.data[CONF_HOST], + ) + + out = {} + + resp = self.eagle100_reader.get_instantaneous_demand()["InstantaneousDemand"] + out["zigbee:InstantaneousDemand"] = resp["Demand"] + + resp = self.eagle100_reader.get_current_summation()["CurrentSummation"] + out["zigbee:CurrentSummationDelivered"] = resp["SummationDelivered"] + out["zigbee:CurrentSummationReceived"] = resp["SummationReceived"] + + return out diff --git a/homeassistant/components/rainforest_eagle/data.py b/homeassistant/components/rainforest_eagle/data.py index 879aa467d9b..bd2f63fc56a 100644 --- a/homeassistant/components/rainforest_eagle/data.py +++ b/homeassistant/components/rainforest_eagle/data.py @@ -3,7 +3,6 @@ from __future__ import annotations import asyncio -from datetime import timedelta import logging import aioeagle @@ -11,20 +10,10 @@ import aiohttp from eagle100 import Eagle as Eagle100Reader from requests.exceptions import ConnectionError as ConnectError, HTTPError, Timeout -from homeassistant.config_entries import ConfigEntry -from homeassistant.const import CONF_HOST, CONF_TYPE -from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import aiohttp_client -from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed -from .const import ( - CONF_CLOUD_ID, - CONF_HARDWARE_ADDRESS, - CONF_INSTALL_CODE, - TYPE_EAGLE_100, - TYPE_EAGLE_200, -) +from .const import TYPE_EAGLE_100, TYPE_EAGLE_200 _LOGGER = logging.getLogger(__name__) @@ -86,108 +75,3 @@ async def async_get_type(hass, cloud_id, install_code, host): return TYPE_EAGLE_100, None return None, None - - -class EagleDataCoordinator(DataUpdateCoordinator): # pylint: disable=hass-enforce-coordinator-module - """Get the latest data from the Eagle device.""" - - eagle100_reader: Eagle100Reader | None = None - eagle200_meter: aioeagle.ElectricMeter | None = None - - def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None: - """Initialize the data object.""" - self.entry = entry - if self.type == TYPE_EAGLE_100: - self.model = "EAGLE-100" - update_method = self._async_update_data_100 - else: - self.model = "EAGLE-200" - update_method = self._async_update_data_200 - - super().__init__( - hass, - _LOGGER, - name=entry.data[CONF_CLOUD_ID], - update_interval=timedelta(seconds=30), - update_method=update_method, - ) - - @property - def cloud_id(self): - """Return the cloud ID.""" - return self.entry.data[CONF_CLOUD_ID] - - @property - def type(self): - """Return entry type.""" - return self.entry.data[CONF_TYPE] - - @property - def hardware_address(self): - """Return hardware address of meter.""" - return self.entry.data[CONF_HARDWARE_ADDRESS] - - @property - def is_connected(self): - """Return if the hub is connected to the electric meter.""" - if self.eagle200_meter: - return self.eagle200_meter.is_connected - - return True - - async def _async_update_data_200(self): - """Get the latest data from the Eagle-200 device.""" - if (eagle200_meter := self.eagle200_meter) is None: - hub = aioeagle.EagleHub( - aiohttp_client.async_get_clientsession(self.hass), - self.cloud_id, - self.entry.data[CONF_INSTALL_CODE], - host=self.entry.data[CONF_HOST], - ) - eagle200_meter = aioeagle.ElectricMeter.create_instance( - hub, self.hardware_address - ) - is_connected = True - else: - is_connected = eagle200_meter.is_connected - - async with asyncio.timeout(30): - data = await eagle200_meter.get_device_query() - - if self.eagle200_meter is None: - self.eagle200_meter = eagle200_meter - elif is_connected and not eagle200_meter.is_connected: - _LOGGER.warning("Lost connection with electricity meter") - - _LOGGER.debug("API data: %s", data) - return {var["Name"]: var["Value"] for var in data.values()} - - async def _async_update_data_100(self): - """Get the latest data from the Eagle-100 device.""" - try: - data = await self.hass.async_add_executor_job(self._fetch_data_100) - except UPDATE_100_ERRORS as error: - raise UpdateFailed from error - - _LOGGER.debug("API data: %s", data) - return data - - def _fetch_data_100(self): - """Fetch and return the four sensor values in a dict.""" - if self.eagle100_reader is None: - self.eagle100_reader = Eagle100Reader( - self.cloud_id, - self.entry.data[CONF_INSTALL_CODE], - self.entry.data[CONF_HOST], - ) - - out = {} - - resp = self.eagle100_reader.get_instantaneous_demand()["InstantaneousDemand"] - out["zigbee:InstantaneousDemand"] = resp["Demand"] - - resp = self.eagle100_reader.get_current_summation()["CurrentSummation"] - out["zigbee:CurrentSummationDelivered"] = resp["SummationDelivered"] - out["zigbee:CurrentSummationReceived"] = resp["SummationReceived"] - - return out diff --git a/homeassistant/components/rainforest_eagle/diagnostics.py b/homeassistant/components/rainforest_eagle/diagnostics.py index 14c980bad7d..ec40f2515b1 100644 --- a/homeassistant/components/rainforest_eagle/diagnostics.py +++ b/homeassistant/components/rainforest_eagle/diagnostics.py @@ -9,7 +9,7 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from .const import CONF_CLOUD_ID, CONF_INSTALL_CODE, DOMAIN -from .data import EagleDataCoordinator +from .coordinator import EagleDataCoordinator TO_REDACT = {CONF_CLOUD_ID, CONF_INSTALL_CODE} diff --git a/homeassistant/components/rainforest_eagle/sensor.py b/homeassistant/components/rainforest_eagle/sensor.py index 27eae0e3e8e..8c4c5927998 100644 --- a/homeassistant/components/rainforest_eagle/sensor.py +++ b/homeassistant/components/rainforest_eagle/sensor.py @@ -17,7 +17,7 @@ from homeassistant.helpers.typing import StateType from homeassistant.helpers.update_coordinator import CoordinatorEntity from .const import DOMAIN -from .data import EagleDataCoordinator +from .coordinator import EagleDataCoordinator SENSORS = ( SensorEntityDescription( diff --git a/tests/components/rainforest_eagle/conftest.py b/tests/components/rainforest_eagle/conftest.py index 9ea607b1db4..1aff693e61f 100644 --- a/tests/components/rainforest_eagle/conftest.py +++ b/tests/components/rainforest_eagle/conftest.py @@ -66,7 +66,7 @@ async def setup_rainforest_100(hass): }, ).add_to_hass(hass) with patch( - "homeassistant.components.rainforest_eagle.data.Eagle100Reader", + "homeassistant.components.rainforest_eagle.coordinator.Eagle100Reader", return_value=Mock( get_instantaneous_demand=Mock( return_value={"InstantaneousDemand": {"Demand": "1.152000"}} diff --git a/tests/components/rainforest_eagle/test_config_flow.py b/tests/components/rainforest_eagle/test_config_flow.py index d3df44fb4fe..0d3b477b3d5 100644 --- a/tests/components/rainforest_eagle/test_config_flow.py +++ b/tests/components/rainforest_eagle/test_config_flow.py @@ -27,7 +27,7 @@ async def test_form(hass: HomeAssistant) -> None: with ( patch( - "homeassistant.components.rainforest_eagle.data.async_get_type", + "homeassistant.components.rainforest_eagle.config_flow.async_get_type", return_value=(TYPE_EAGLE_200, "mock-hw"), ), patch(