diff --git a/homeassistant/components/asuswrt/manifest.json b/homeassistant/components/asuswrt/manifest.json index fef0c7a14cb..b66c3bb5db9 100644 --- a/homeassistant/components/asuswrt/manifest.json +++ b/homeassistant/components/asuswrt/manifest.json @@ -3,7 +3,7 @@ "name": "ASUSWRT", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/asuswrt", - "requirements": ["aioasuswrt==1.3.1"], + "requirements": ["aioasuswrt==1.3.4"], "codeowners": ["@kennedyshead", "@ollo69"], "iot_class": "local_polling" } diff --git a/homeassistant/components/iqvia/__init__.py b/homeassistant/components/iqvia/__init__.py index f8ccf3c7e29..5d13a2373a6 100644 --- a/homeassistant/components/iqvia/__init__.py +++ b/homeassistant/components/iqvia/__init__.py @@ -9,6 +9,7 @@ from pyiqvia.errors import IQVIAError from homeassistant.components.sensor import SensorEntity from homeassistant.const import ATTR_ATTRIBUTION from homeassistant.core import callback +from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import aiohttp_client from homeassistant.helpers.update_coordinator import ( CoordinatorEntity, @@ -74,9 +75,14 @@ async def async_setup_entry(hass, entry): update_interval=DEFAULT_SCAN_INTERVAL, update_method=partial(async_get_data_from_api, api_coro), ) - init_data_update_tasks.append(coordinator.async_config_entry_first_refresh()) + init_data_update_tasks.append(coordinator.async_refresh()) - await asyncio.gather(*init_data_update_tasks) + results = await asyncio.gather(*init_data_update_tasks, return_exceptions=True) + if all(isinstance(result, Exception) for result in results): + # The IQVIA API can be selectively flaky, meaning that any number of the setup + # API calls could fail. We only retry integration setup if *all* of the initial + # API calls fail: + raise ConfigEntryNotReady() hass.data[DOMAIN].setdefault(DATA_COORDINATOR, {})[entry.entry_id] = coordinators hass.config_entries.async_setup_platforms(entry, PLATFORMS) diff --git a/homeassistant/components/iqvia/sensor.py b/homeassistant/components/iqvia/sensor.py index 48ec1cf97b1..b0420a52ee9 100644 --- a/homeassistant/components/iqvia/sensor.py +++ b/homeassistant/components/iqvia/sensor.py @@ -104,9 +104,12 @@ class ForecastSensor(IQVIAEntity): @callback def update_from_latest_data(self): """Update the sensor.""" - data = self.coordinator.data.get("Location") + if not self.coordinator.data: + return - if not data or not data.get("periods"): + data = self.coordinator.data.get("Location", {}) + + if not data.get("periods"): return indices = [p["Index"] for p in data["periods"]] diff --git a/homeassistant/components/light/__init__.py b/homeassistant/components/light/__init__.py index 0bc68702467..caf3ac209cb 100644 --- a/homeassistant/components/light/__init__.py +++ b/homeassistant/components/light/__init__.py @@ -95,21 +95,21 @@ def valid_supported_color_modes(color_modes: Iterable[str]) -> set[str]: return color_modes -def brightness_supported(color_modes: Iterable[str]) -> bool: +def brightness_supported(color_modes: Iterable[str] | None) -> bool: """Test if brightness is supported.""" if not color_modes: return False return any(mode in COLOR_MODES_BRIGHTNESS for mode in color_modes) -def color_supported(color_modes: Iterable[str]) -> bool: +def color_supported(color_modes: Iterable[str] | None) -> bool: """Test if color is supported.""" if not color_modes: return False return any(mode in COLOR_MODES_COLOR for mode in color_modes) -def color_temp_supported(color_modes: Iterable[str]) -> bool: +def color_temp_supported(color_modes: Iterable[str] | None) -> bool: """Test if color temperature is supported.""" if not color_modes: return False diff --git a/homeassistant/components/light/device_action.py b/homeassistant/components/light/device_action.py index 9cdb5764d70..3de2218d7c7 100644 --- a/homeassistant/components/light/device_action.py +++ b/homeassistant/components/light/device_action.py @@ -13,11 +13,17 @@ from homeassistant.components.light import ( ) from homeassistant.const import ATTR_ENTITY_ID, CONF_DOMAIN, CONF_TYPE, SERVICE_TURN_ON from homeassistant.core import Context, HomeAssistant, HomeAssistantError -from homeassistant.helpers import config_validation as cv, entity_registry +from homeassistant.helpers import config_validation as cv, entity_registry as er from homeassistant.helpers.entity import get_supported_features from homeassistant.helpers.typing import ConfigType, TemplateVarsType -from . import ATTR_BRIGHTNESS_PCT, ATTR_BRIGHTNESS_STEP_PCT, DOMAIN, SUPPORT_BRIGHTNESS +from . import ( + ATTR_BRIGHTNESS_PCT, + ATTR_BRIGHTNESS_STEP_PCT, + ATTR_SUPPORTED_COLOR_MODES, + DOMAIN, + brightness_supported, +) TYPE_BRIGHTNESS_INCREASE = "brightness_increase" TYPE_BRIGHTNESS_DECREASE = "brightness_decrease" @@ -37,6 +43,25 @@ ACTION_SCHEMA = cv.DEVICE_ACTION_BASE_SCHEMA.extend( ) +def get_supported_color_modes(hass: HomeAssistant, entity_id: str) -> set | None: + """Get supported color modes for a light entity. + + First try the statemachine, then entity registry. + """ + state = hass.states.get(entity_id) + if state: + return state.attributes.get(ATTR_SUPPORTED_COLOR_MODES) + + entity_registry = er.async_get(hass) + entry = entity_registry.async_get(entity_id) + if not entry: + raise HomeAssistantError(f"Unknown entity {entity_id}") + if not entry.capabilities: + return None + + return entry.capabilities.get(ATTR_SUPPORTED_COLOR_MODES) + + async def async_call_action_from_config( hass: HomeAssistant, config: ConfigType, @@ -77,15 +102,16 @@ async def async_get_actions(hass: HomeAssistant, device_id: str) -> list[dict]: """List device actions.""" actions = await toggle_entity.async_get_actions(hass, device_id, DOMAIN) - registry = await entity_registry.async_get_registry(hass) + entity_registry = er.async_get(hass) - for entry in entity_registry.async_entries_for_device(registry, device_id): + for entry in er.async_entries_for_device(entity_registry, device_id): if entry.domain != DOMAIN: continue + supported_color_modes = get_supported_color_modes(hass, entry.entity_id) supported_features = get_supported_features(hass, entry.entity_id) - if supported_features & SUPPORT_BRIGHTNESS: + if brightness_supported(supported_color_modes): actions.extend( ( { @@ -123,6 +149,11 @@ async def async_get_action_capabilities(hass: HomeAssistant, config: dict) -> di if config[CONF_TYPE] != toggle_entity.CONF_TURN_ON: return {} + try: + supported_color_modes = get_supported_color_modes(hass, config[ATTR_ENTITY_ID]) + except HomeAssistantError: + supported_color_modes = None + try: supported_features = get_supported_features(hass, config[ATTR_ENTITY_ID]) except HomeAssistantError: @@ -130,7 +161,7 @@ async def async_get_action_capabilities(hass: HomeAssistant, config: dict) -> di extra_fields = {} - if supported_features & SUPPORT_BRIGHTNESS: + if brightness_supported(supported_color_modes): extra_fields[vol.Optional(ATTR_BRIGHTNESS_PCT)] = VALID_BRIGHTNESS_PCT if supported_features & SUPPORT_FLASH: diff --git a/homeassistant/components/light/intent.py b/homeassistant/components/light/intent.py index be9346cf85b..25475ca0cb5 100644 --- a/homeassistant/components/light/intent.py +++ b/homeassistant/components/light/intent.py @@ -2,7 +2,7 @@ import voluptuous as vol from homeassistant.const import ATTR_ENTITY_ID -from homeassistant.core import HomeAssistant +from homeassistant.core import HomeAssistant, State from homeassistant.helpers import intent import homeassistant.helpers.config_validation as cv import homeassistant.util.color as color_util @@ -10,10 +10,11 @@ import homeassistant.util.color as color_util from . import ( ATTR_BRIGHTNESS_PCT, ATTR_RGB_COLOR, + ATTR_SUPPORTED_COLOR_MODES, DOMAIN, SERVICE_TURN_ON, - SUPPORT_BRIGHTNESS, - SUPPORT_COLOR, + brightness_supported, + color_supported, ) INTENT_SET = "HassLightSet" @@ -24,6 +25,24 @@ async def async_setup_intents(hass: HomeAssistant) -> None: hass.helpers.intent.async_register(SetIntentHandler()) +def _test_supports_color(state: State) -> None: + """Test if state supports colors.""" + supported_color_modes = state.attributes.get(ATTR_SUPPORTED_COLOR_MODES) + if not color_supported(supported_color_modes): + raise intent.IntentHandleError( + f"Entity {state.name} does not support changing colors" + ) + + +def _test_supports_brightness(state: State) -> None: + """Test if state supports brightness.""" + supported_color_modes = state.attributes.get(ATTR_SUPPORTED_COLOR_MODES) + if not brightness_supported(supported_color_modes): + raise intent.IntentHandleError( + f"Entity {state.name} does not support changing brightness" + ) + + class SetIntentHandler(intent.IntentHandler): """Handle set color intents.""" @@ -46,14 +65,14 @@ class SetIntentHandler(intent.IntentHandler): speech_parts = [] if "color" in slots: - intent.async_test_feature(state, SUPPORT_COLOR, "changing colors") + _test_supports_color(state) service_data[ATTR_RGB_COLOR] = slots["color"]["value"] # Use original passed in value of the color because we don't have # human readable names for that internally. speech_parts.append(f"the color {intent_obj.slots['color']['value']}") if "brightness" in slots: - intent.async_test_feature(state, SUPPORT_BRIGHTNESS, "changing brightness") + _test_supports_brightness(state) service_data[ATTR_BRIGHTNESS_PCT] = slots["brightness"]["value"] speech_parts.append(f"{slots['brightness']['value']}% brightness") diff --git a/homeassistant/components/netatmo/climate.py b/homeassistant/components/netatmo/climate.py index 3b36e3089a2..dcf4f1bc765 100644 --- a/homeassistant/components/netatmo/climate.py +++ b/homeassistant/components/netatmo/climate.py @@ -506,7 +506,7 @@ class NetatmoThermostat(NetatmoBase, ClimateEntity): self._target_temperature = roomstatus["target_temperature"] self._preset = NETATMO_MAP_PRESET[roomstatus["setpoint_mode"]] self._hvac_mode = HVAC_MAP_NETATMO[self._preset] - self._battery_level = roomstatus.get("battery_level") + self._battery_level = roomstatus.get("battery_state") self._connected = True self._away = self._hvac_mode == HVAC_MAP_NETATMO[STATE_NETATMO_AWAY] @@ -546,7 +546,7 @@ class NetatmoThermostat(NetatmoBase, ClimateEntity): roomstatus["heating_status"] = self._boilerstatus batterylevel = self._home_status.thermostats[ roomstatus["module_id"] - ].get("battery_level") + ].get("battery_state") elif roomstatus["module_type"] == NA_VALVE: roomstatus["heating_power_request"] = self._room_status[ "heating_power_request" @@ -557,16 +557,11 @@ class NetatmoThermostat(NetatmoBase, ClimateEntity): self._boilerstatus and roomstatus["heating_status"] ) batterylevel = self._home_status.valves[roomstatus["module_id"]].get( - "battery_level" + "battery_state" ) if batterylevel: - batterypct = interpolate(batterylevel, roomstatus["module_type"]) - if ( - not roomstatus.get("battery_level") - or batterypct < roomstatus["battery_level"] - ): - roomstatus["battery_level"] = batterypct + roomstatus["battery_state"] = batterylevel return roomstatus @@ -602,48 +597,6 @@ class NetatmoThermostat(NetatmoBase, ClimateEntity): return {**super().device_info, "suggested_area": self._room_data["name"]} -def interpolate(batterylevel: int, module_type: str) -> int: - """Interpolate battery level depending on device type.""" - na_battery_levels = { - NA_THERM: { - "full": 4100, - "high": 3600, - "medium": 3300, - "low": 3000, - "empty": 2800, - }, - NA_VALVE: { - "full": 3200, - "high": 2700, - "medium": 2400, - "low": 2200, - "empty": 2200, - }, - } - - levels = sorted(na_battery_levels[module_type].values()) - steps = [20, 50, 80, 100] - - na_battery_level = na_battery_levels[module_type] - if batterylevel >= na_battery_level["full"]: - return 100 - if batterylevel >= na_battery_level["high"]: - i = 3 - elif batterylevel >= na_battery_level["medium"]: - i = 2 - elif batterylevel >= na_battery_level["low"]: - i = 1 - else: - return 0 - - pct = steps[i - 1] + ( - (steps[i] - steps[i - 1]) - * (batterylevel - levels[i]) - / (levels[i + 1] - levels[i]) - ) - return int(pct) - - def get_all_home_ids(home_data: pyatmo.HomeData) -> list[str]: """Get all the home ids returned by NetAtmo API.""" if home_data is None: diff --git a/homeassistant/components/sonos/media_player.py b/homeassistant/components/sonos/media_player.py index 022beef3219..230948ee894 100644 --- a/homeassistant/components/sonos/media_player.py +++ b/homeassistant/components/sonos/media_player.py @@ -440,6 +440,11 @@ class SonosMediaPlayerEntity(SonosEntity, MediaPlayerEntity): self._media_position = None self._media_position_updated_at = None + async def async_set_favorites(self) -> None: + """Wrap favorites update method with an async lock.""" + async with self.data.topology_condition: + await self.hass.async_add_executor_job(self._set_favorites) + def _set_favorites(self) -> None: """Set available favorites.""" self._favorites = [] @@ -741,7 +746,7 @@ class SonosMediaPlayerEntity(SonosEntity, MediaPlayerEntity): def async_update_content(self, event: SonosEvent | None = None) -> None: """Update information about available content.""" if event and "favorites_update_id" in event.variables: - self.hass.async_add_job(self._set_favorites) + self.hass.async_add_job(self.async_set_favorites) self.async_write_ha_state() @property diff --git a/homeassistant/components/sonos/speaker.py b/homeassistant/components/sonos/speaker.py index 03cce67e4d8..56eba68abe1 100644 --- a/homeassistant/components/sonos/speaker.py +++ b/homeassistant/components/sonos/speaker.py @@ -96,7 +96,7 @@ class SonosSpeaker: self.hass, f"{SONOS_SEEN}-{self.soco.uid}", self.async_seen ) - if (battery_info := fetch_battery_info_or_none(self.soco)) is not None: + if battery_info := fetch_battery_info_or_none(self.soco): # Battery events can be infrequent, polling is still necessary self.battery_info = battery_info self._battery_poll_timer = self.hass.helpers.event.track_time_interval( diff --git a/homeassistant/components/version/manifest.json b/homeassistant/components/version/manifest.json index 880b000bc43..6f36c337a76 100644 --- a/homeassistant/components/version/manifest.json +++ b/homeassistant/components/version/manifest.json @@ -2,8 +2,13 @@ "domain": "version", "name": "Version", "documentation": "https://www.home-assistant.io/integrations/version", - "requirements": ["pyhaversion==21.3.0"], - "codeowners": ["@fabaff", "@ludeeus"], + "requirements": [ + "pyhaversion==21.5.0" + ], + "codeowners": [ + "@fabaff", + "@ludeeus" + ], "quality_scale": "internal", "iot_class": "local_push" -} +} \ No newline at end of file diff --git a/homeassistant/const.py b/homeassistant/const.py index f246d7407fa..6df593e984b 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 2021 MINOR_VERSION = 5 -PATCH_VERSION = "3" +PATCH_VERSION = "4" __short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__ = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER = (3, 8, 0) diff --git a/homeassistant/helpers/intent.py b/homeassistant/helpers/intent.py index 96cfbf0e1b5..cfc89240b78 100644 --- a/homeassistant/helpers/intent.py +++ b/homeassistant/helpers/intent.py @@ -119,7 +119,7 @@ def async_match_state( @callback def async_test_feature(state: State, feature: int, feature_name: str) -> None: - """Test is state supports a feature.""" + """Test if state supports a feature.""" if state.attributes.get(ATTR_SUPPORTED_FEATURES, 0) & feature == 0: raise IntentHandleError(f"Entity {state.name} does not support {feature_name}") diff --git a/requirements_all.txt b/requirements_all.txt index 263c6dc8e1d..af2e557446a 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -138,7 +138,7 @@ aio_georss_gdacs==0.4 aioambient==1.2.4 # homeassistant.components.asuswrt -aioasuswrt==1.3.1 +aioasuswrt==1.3.4 # homeassistant.components.azure_devops aioazuredevops==1.3.5 @@ -1437,7 +1437,7 @@ pygtfs==0.1.5 pygti==0.9.2 # homeassistant.components.version -pyhaversion==21.3.0 +pyhaversion==21.5.0 # homeassistant.components.heos pyheos==0.7.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 8543f74a4f8..91f7c1422ee 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -78,7 +78,7 @@ aio_georss_gdacs==0.4 aioambient==1.2.4 # homeassistant.components.asuswrt -aioasuswrt==1.3.1 +aioasuswrt==1.3.4 # homeassistant.components.azure_devops aioazuredevops==1.3.5 @@ -778,7 +778,7 @@ pygatt[GATTTOOL]==4.0.5 pygti==0.9.2 # homeassistant.components.version -pyhaversion==21.3.0 +pyhaversion==21.5.0 # homeassistant.components.heos pyheos==0.7.2 diff --git a/tests/components/light/test_device_action.py b/tests/components/light/test_device_action.py index 5d6ca2f4a2c..440cae8f0fc 100644 --- a/tests/components/light/test_device_action.py +++ b/tests/components/light/test_device_action.py @@ -3,10 +3,11 @@ import pytest import homeassistant.components.automation as automation from homeassistant.components.light import ( + ATTR_SUPPORTED_COLOR_MODES, + COLOR_MODE_BRIGHTNESS, DOMAIN, FLASH_LONG, FLASH_SHORT, - SUPPORT_BRIGHTNESS, SUPPORT_FLASH, ) from homeassistant.const import CONF_PLATFORM, STATE_OFF, STATE_ON @@ -55,7 +56,8 @@ async def test_get_actions(hass, device_reg, entity_reg): "test", "5678", device_id=device_entry.id, - supported_features=SUPPORT_BRIGHTNESS | SUPPORT_FLASH, + supported_features=SUPPORT_FLASH, + capabilities={"supported_color_modes": ["brightness"]}, ) expected_actions = [ { @@ -132,13 +134,15 @@ async def test_get_action_capabilities(hass, device_reg, entity_reg): @pytest.mark.parametrize( - "set_state,num_actions,supported_features_reg,supported_features_state,expected_capabilities", + "set_state,num_actions,supported_features_reg,supported_features_state,capabilities_reg,attributes_state,expected_capabilities", [ ( False, 5, - SUPPORT_BRIGHTNESS, 0, + 0, + {ATTR_SUPPORTED_COLOR_MODES: [COLOR_MODE_BRIGHTNESS]}, + {}, { "turn_on": [ { @@ -155,7 +159,9 @@ async def test_get_action_capabilities(hass, device_reg, entity_reg): True, 5, 0, - SUPPORT_BRIGHTNESS, + 0, + None, + {ATTR_SUPPORTED_COLOR_MODES: [COLOR_MODE_BRIGHTNESS]}, { "turn_on": [ { @@ -173,6 +179,8 @@ async def test_get_action_capabilities(hass, device_reg, entity_reg): 4, SUPPORT_FLASH, 0, + None, + {}, { "turn_on": [ { @@ -189,6 +197,8 @@ async def test_get_action_capabilities(hass, device_reg, entity_reg): 4, 0, SUPPORT_FLASH, + None, + {}, { "turn_on": [ { @@ -210,6 +220,8 @@ async def test_get_action_capabilities_features( num_actions, supported_features_reg, supported_features_state, + capabilities_reg, + attributes_state, expected_capabilities, ): """Test we get the expected capabilities from a light action.""" @@ -225,10 +237,13 @@ async def test_get_action_capabilities_features( "5678", device_id=device_entry.id, supported_features=supported_features_reg, + capabilities=capabilities_reg, ).entity_id if set_state: hass.states.async_set( - entity_id, None, {"supported_features": supported_features_state} + entity_id, + None, + {"supported_features": supported_features_state, **attributes_state}, ) actions = await async_get_device_automations(hass, "action", device_entry.id) diff --git a/tests/components/light/test_intent.py b/tests/components/light/test_intent.py index 4adba921d5e..6a5add41cff 100644 --- a/tests/components/light/test_intent.py +++ b/tests/components/light/test_intent.py @@ -1,7 +1,11 @@ """Tests for the light intents.""" from homeassistant.components import light -from homeassistant.components.light import intent -from homeassistant.const import ATTR_ENTITY_ID, ATTR_SUPPORTED_FEATURES, SERVICE_TURN_ON +from homeassistant.components.light import ( + ATTR_SUPPORTED_COLOR_MODES, + COLOR_MODE_HS, + intent, +) +from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_ON from homeassistant.helpers.intent import IntentHandleError from tests.common import async_mock_service @@ -10,7 +14,7 @@ from tests.common import async_mock_service async def test_intent_set_color(hass): """Test the set color intent.""" hass.states.async_set( - "light.hello_2", "off", {ATTR_SUPPORTED_FEATURES: light.SUPPORT_COLOR} + "light.hello_2", "off", {ATTR_SUPPORTED_COLOR_MODES: [COLOR_MODE_HS]} ) hass.states.async_set("switch.hello", "off") calls = async_mock_service(hass, light.DOMAIN, light.SERVICE_TURN_ON) @@ -55,9 +59,7 @@ async def test_intent_set_color_tests_feature(hass): async def test_intent_set_color_and_brightness(hass): """Test the set color intent.""" hass.states.async_set( - "light.hello_2", - "off", - {ATTR_SUPPORTED_FEATURES: (light.SUPPORT_COLOR | light.SUPPORT_BRIGHTNESS)}, + "light.hello_2", "off", {ATTR_SUPPORTED_COLOR_MODES: [COLOR_MODE_HS]} ) hass.states.async_set("switch.hello", "off") calls = async_mock_service(hass, light.DOMAIN, light.SERVICE_TURN_ON) diff --git a/tests/components/netatmo/test_climate.py b/tests/components/netatmo/test_climate.py index ecec2871df8..a3cad1e6d81 100644 --- a/tests/components/netatmo/test_climate.py +++ b/tests/components/netatmo/test_climate.py @@ -1,8 +1,6 @@ """The tests for the Netatmo climate platform.""" from unittest.mock import Mock, patch -import pytest - from homeassistant.components.climate import ( DOMAIN as CLIMATE_DOMAIN, SERVICE_SET_HVAC_MODE, @@ -21,12 +19,7 @@ from homeassistant.components.climate.const import ( PRESET_BOOST, ) from homeassistant.components.netatmo import climate -from homeassistant.components.netatmo.climate import ( - NA_THERM, - NA_VALVE, - PRESET_FROST_GUARD, - PRESET_SCHEDULE, -) +from homeassistant.components.netatmo.climate import PRESET_FROST_GUARD, PRESET_SCHEDULE from homeassistant.components.netatmo.const import ( ATTR_SCHEDULE_NAME, SERVICE_SET_SCHEDULE, @@ -653,28 +646,6 @@ async def test_valves_service_turn_on(hass, climate_entry): assert hass.states.get(climate_entity_entrada).state == "auto" -@pytest.mark.parametrize( - "batterylevel, module_type, expected", - [ - (4101, NA_THERM, 100), - (3601, NA_THERM, 80), - (3450, NA_THERM, 65), - (3301, NA_THERM, 50), - (3001, NA_THERM, 20), - (2799, NA_THERM, 0), - (3201, NA_VALVE, 100), - (2701, NA_VALVE, 80), - (2550, NA_VALVE, 65), - (2401, NA_VALVE, 50), - (2201, NA_VALVE, 20), - (2001, NA_VALVE, 0), - ], -) -async def test_interpolate(batterylevel, module_type, expected): - """Test interpolation of battery levels depending on device type.""" - assert climate.interpolate(batterylevel, module_type) == expected - - async def test_get_all_home_ids(): """Test extracting all home ids returned by NetAtmo API.""" # Test with backend returning no data