diff --git a/custom_components/openei/__init__.py b/custom_components/openei/__init__.py index 1fe8c22..fb92de9 100644 --- a/custom_components/openei/__init__.py +++ b/custom_components/openei/__init__.py @@ -103,6 +103,9 @@ async def _async_update_data(self) -> dict: self._data = await self.hass.async_add_executor_job( get_sensors, self.hass, self._config ) + except openeihttp.RateLimit: + _LOGGER.error("API Rate limit exceded, retrying later.") + self._data = {} except Exception as exception: raise UpdateFailed() from exception return self._data @@ -120,11 +123,15 @@ async def _async_refresh_data(self, data=None) -> None: self._data = await self.hass.async_add_executor_job( get_sensors, self.hass, self._config ) + except openeihttp.RateLimit: + _LOGGER.error("API Rate limit exceded, retrying later.") + self._data = {} except Exception as exception: raise UpdateFailed() from exception def get_sensors(hass, config) -> dict: + """Update sensor data.""" api = config.data.get(CONF_API_KEY) plan = config.data.get(CONF_PLAN) meter = config.data.get(CONF_SENSOR) diff --git a/custom_components/openei/const.py b/custom_components/openei/const.py index 4a00ab4..4c3701a 100644 --- a/custom_components/openei/const.py +++ b/custom_components/openei/const.py @@ -54,6 +54,11 @@ name="Current Energy Rate", icon="mdi:cash-multiple", ), + "current_adjustment": SensorEntityDescription( + key="current_adjustment", + name="Current Energy Adjustment", + icon="mdi:cash-multiple", + ), "distributed_generation": SensorEntityDescription( key="distributed_generation", name="Distributed Generation", @@ -69,7 +74,6 @@ key="all_rates", name="All Listed Rates", icon="mdi:format-list-bulleted", - entity_category=EntityCategory.DIAGNOSTIC, ), "monthly_tier_rate": SensorEntityDescription( key="monthly_tier_rate", diff --git a/custom_components/openei/sensor.py b/custom_components/openei/sensor.py index e6fad48..195e9f8 100644 --- a/custom_components/openei/sensor.py +++ b/custom_components/openei/sensor.py @@ -20,6 +20,8 @@ async def async_setup_entry(hass, entry, async_add_devices): sensors = [] for sensor in SENSOR_TYPES: + if sensor == "all_rates": + continue sensors.append(OpenEISensor(hass, SENSOR_TYPES[sensor], entry, coordinator)) async_add_devices(sensors, False) @@ -56,7 +58,7 @@ def native_value(self) -> Any: @property def native_unit_of_measurement(self) -> Any: """Return the unit of measurement.""" - if self._key in ["current_rate", "monthly_tier_rate"]: + if self._key in ["current_adjustment","current_rate", "monthly_tier_rate"]: return f"{self.hass.config.currency}/kWh" if f"{self._key}_uom" in self.coordinator.data: return self.coordinator.data.get(f"{self._key}_uom") @@ -72,6 +74,8 @@ def extra_state_attributes(self) -> Optional[dict]: """Return sesnsor attributes.""" attrs = {} attrs[ATTR_ATTRIBUTION] = ATTRIBUTION + if self._key == "current_rate": + attrs["all_rates"] = self.coordinator.data.get("all_rates") return attrs @property diff --git a/requirements_tests.txt b/requirements_tests.txt index dcf3804..77078f4 100644 --- a/requirements_tests.txt +++ b/requirements_tests.txt @@ -1,5 +1,5 @@ -r requirements_dev.txt -python-openei +python-openei==0.1.22 pytest pytest-cov -pytest-homeassistant-custom-component \ No newline at end of file +pytest-homeassistant-custom-component diff --git a/tests/conftest.py b/tests/conftest.py index 4a0ea9d..b63dafe 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,6 @@ """Test configurations.""" from unittest.mock import patch +import openeihttp import pytest @@ -25,6 +26,7 @@ def mock_api(): mock_api.return_value.lookup_plans = ( '"Fake Utility Co": [{"name": "Fake Plan Name", "label": "randomstring"}]' ) + mock_api.return_value.all_rates = [ 0.24477, 0.007 ] yield mock_api @@ -52,5 +54,13 @@ def mock_get_sensors(): "rate_name": "Fake Test Rate", "mincharge": 10, "mincharge_uom": "$/month", + "all_rates": [ 0.24477, 0.007 ], } yield mock_sensors + +@pytest.fixture(name="mock_sensors_err") +def mock_sensors_api_error(): + """Mock of get sensors function.""" + with patch("custom_components.openei.get_sensors") as mock_sensors: + mock_sensors.side_effect = openeihttp.RateLimit("Error") + yield mock_sensors diff --git a/tests/test_config_flow.py b/tests/test_config_flow.py index eb96c97..ee30cd5 100644 --- a/tests/test_config_flow.py +++ b/tests/test_config_flow.py @@ -7,6 +7,8 @@ from custom_components.openei.const import DOMAIN +pytestmark = pytest.mark.asyncio + @pytest.mark.parametrize( "input_1,step_id_2,input_2,step_id_3,input_3,title,data", diff --git a/tests/test_init.py b/tests/test_init.py index 65a6a8d..ba92d16 100644 --- a/tests/test_init.py +++ b/tests/test_init.py @@ -7,9 +7,12 @@ from openeihttp import APIError from pytest_homeassistant_custom_component.common import MockConfigEntry +from openeihttp import RateLimit + from custom_components.openei.const import DOMAIN from tests.const import CONFIG_DATA, CONFIG_DATA_MISSING_PLAN, CONFIG_DATA_WITH_SENSOR +pytestmark = pytest.mark.asyncio async def test_setup_entry(hass, mock_sensors, mock_api): """Test settting up entities.""" @@ -102,3 +105,16 @@ async def test_setup_entry_sensor_plan_error(hass, mock_api, caplog): assert not await hass.config_entries.async_setup(entry.entry_id) await hass.async_block_till_done() assert "Plan configuration missing." in caplog.text + +async def test_rate_limit_error(hass, mock_sensors_err, caplog): + """Test settting up entities.""" + entry = MockConfigEntry( + domain=DOMAIN, + title="Fake Utility Co", + data=CONFIG_DATA, + ) + + entry.add_to_hass(hass) + assert await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + assert "API Rate limit exceded, retrying later." in caplog.text diff --git a/tests/test_sensors.py b/tests/test_sensors.py index 785521f..3eeb4e8 100644 --- a/tests/test_sensors.py +++ b/tests/test_sensors.py @@ -1,4 +1,5 @@ """Tests for sensors.""" +import pytest from pytest_homeassistant_custom_component.common import MockConfigEntry @@ -6,6 +7,9 @@ from tests.const import CONFIG_DATA FAKE_MINCHARGE_SENSOR = "sensor.fake_utility_co_minimum_charge" +FAKE_CURRENT_RATE_SENSOR = "sensor.fake_utility_co_current_energy_rate" + +pytestmark = pytest.mark.asyncio async def test_sensors(hass, mock_sensors, mock_api): @@ -24,3 +28,8 @@ async def test_sensors(hass, mock_sensors, mock_api): assert state is not None assert state.state == "10" assert state.attributes["unit_of_measurement"] == "$/month" + + state = hass.states.get(FAKE_CURRENT_RATE_SENSOR) + assert state is not None + assert state.state == "0.24477" + assert state.attributes["all_rates"] == [ 0.24477, 0.007 ]