diff --git a/homeassistant/components/waqi/__init__.py b/homeassistant/components/waqi/__init__.py index 387d06da1a1..e9feca75ee7 100644 --- a/homeassistant/components/waqi/__init__.py +++ b/homeassistant/components/waqi/__init__.py @@ -8,7 +8,6 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_API_KEY, Platform from homeassistant.core import HomeAssistant from homeassistant.helpers.aiohttp_client import async_get_clientsession -import homeassistant.helpers.entity_registry as er from .const import DOMAIN from .coordinator import WAQIDataUpdateCoordinator @@ -19,8 +18,6 @@ PLATFORMS: list[Platform] = [Platform.SENSOR] async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up World Air Quality Index (WAQI) from a config entry.""" - await _migrate_unique_ids(hass, entry) - client = WAQIClient(session=async_get_clientsession(hass)) client.authenticate(entry.data[CONF_API_KEY]) @@ -39,16 +36,3 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: hass.data[DOMAIN].pop(entry.entry_id) return unload_ok - - -async def _migrate_unique_ids(hass: HomeAssistant, entry: ConfigEntry) -> None: - """Migrate pre-config flow unique ids.""" - entity_registry = er.async_get(hass) - registry_entries = er.async_entries_for_config_entry( - entity_registry, entry.entry_id - ) - for reg_entry in registry_entries: - if isinstance(reg_entry.unique_id, int): # type: ignore[unreachable] - entity_registry.async_update_entity( # type: ignore[unreachable] - reg_entry.entity_id, new_unique_id=f"{reg_entry.unique_id}_air_quality" - ) diff --git a/homeassistant/components/waqi/config_flow.py b/homeassistant/components/waqi/config_flow.py index b8c6cdf57a3..068cb1a5020 100644 --- a/homeassistant/components/waqi/config_flow.py +++ b/homeassistant/components/waqi/config_flow.py @@ -20,20 +20,15 @@ from homeassistant.const import ( CONF_LOCATION, CONF_LONGITUDE, CONF_METHOD, - CONF_NAME, ) -from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN -from homeassistant.data_entry_flow import AbortFlow from homeassistant.helpers.aiohttp_client import async_get_clientsession -from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue from homeassistant.helpers.selector import ( LocationSelector, SelectSelector, SelectSelectorConfig, ) -from homeassistant.helpers.typing import ConfigType -from .const import CONF_STATION_NUMBER, DOMAIN, ISSUE_PLACEHOLDER +from .const import CONF_STATION_NUMBER, DOMAIN _LOGGER = logging.getLogger(__name__) @@ -193,43 +188,3 @@ class WAQIConfigFlow(ConfigFlow, domain=DOMAIN): CONF_STATION_NUMBER: measuring_station.station_id, }, ) - - async def async_step_import(self, import_config: ConfigType) -> ConfigFlowResult: - """Handle importing from yaml.""" - await self.async_set_unique_id(str(import_config[CONF_STATION_NUMBER])) - try: - self._abort_if_unique_id_configured() - except AbortFlow as exc: - async_create_issue( - self.hass, - DOMAIN, - "deprecated_yaml_import_issue_already_configured", - breaks_in_ha_version="2024.4.0", - is_fixable=False, - severity=IssueSeverity.ERROR, - translation_key="deprecated_yaml_import_issue_already_configured", - translation_placeholders=ISSUE_PLACEHOLDER, - ) - raise exc - - async_create_issue( - self.hass, - HOMEASSISTANT_DOMAIN, - f"deprecated_yaml_{DOMAIN}", - breaks_in_ha_version="2024.4.0", - is_fixable=False, - issue_domain=DOMAIN, - severity=IssueSeverity.WARNING, - translation_key="deprecated_yaml", - translation_placeholders={ - "domain": DOMAIN, - "integration_title": "World Air Quality Index", - }, - ) - return self.async_create_entry( - title=import_config[CONF_NAME], - data={ - CONF_API_KEY: import_config[CONF_API_KEY], - CONF_STATION_NUMBER: import_config[CONF_STATION_NUMBER], - }, - ) diff --git a/homeassistant/components/waqi/sensor.py b/homeassistant/components/waqi/sensor.py index 198eaef536b..ce967a9b538 100644 --- a/homeassistant/components/waqi/sensor.py +++ b/homeassistant/components/waqi/sensor.py @@ -7,14 +7,8 @@ from dataclasses import dataclass import logging from typing import Any -from aiowaqi import ( - WAQIAirQuality, - WAQIAuthenticationError, - WAQIClient, - WAQIConnectionError, -) +from aiowaqi import WAQIAirQuality from aiowaqi.models import Pollutant -import voluptuous as vol from homeassistant.components.sensor import ( SensorDeviceClass, @@ -22,28 +16,21 @@ from homeassistant.components.sensor import ( SensorEntityDescription, SensorStateClass, ) -from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry +from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( ATTR_TEMPERATURE, ATTR_TIME, - CONF_API_KEY, - CONF_NAME, - CONF_TOKEN, PERCENTAGE, UnitOfPressure, UnitOfTemperature, ) from homeassistant.core import HomeAssistant -from homeassistant.exceptions import PlatformNotReady -from homeassistant.helpers.aiohttp_client import async_get_clientsession -import homeassistant.helpers.config_validation as cv from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue -from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType, StateType +from homeassistant.helpers.typing import StateType from homeassistant.helpers.update_coordinator import CoordinatorEntity -from .const import CONF_STATION_NUMBER, DOMAIN, ISSUE_PLACEHOLDER +from .const import DOMAIN from .coordinator import WAQIDataUpdateCoordinator _LOGGER = logging.getLogger(__name__) @@ -57,102 +44,6 @@ ATTR_PM2_5 = "pm_2_5" ATTR_PRESSURE = "pressure" ATTR_SULFUR_DIOXIDE = "sulfur_dioxide" -ATTRIBUTION = "Data provided by the World Air Quality Index project" - -ATTR_ICON = "mdi:cloud" - -CONF_LOCATIONS = "locations" -CONF_STATIONS = "stations" - -TIMEOUT = 10 - -PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend( - { - vol.Optional(CONF_STATIONS): cv.ensure_list, - vol.Required(CONF_TOKEN): cv.string, - vol.Required(CONF_LOCATIONS): cv.ensure_list, - } -) - - -async def async_setup_platform( - hass: HomeAssistant, - config: ConfigType, - async_add_entities: AddEntitiesCallback, - discovery_info: DiscoveryInfoType | None = None, -) -> None: - """Set up the requested World Air Quality Index locations.""" - - token = config[CONF_TOKEN] - station_filter = config.get(CONF_STATIONS) - locations = config[CONF_LOCATIONS] - - client = WAQIClient(session=async_get_clientsession(hass), request_timeout=TIMEOUT) - client.authenticate(token) - station_count = 0 - try: - for location_name in locations: - stations = await client.search(location_name) - _LOGGER.debug("The following stations were returned: %s", stations) - for station in stations: - station_count = station_count + 1 - if not station_filter or { - station.station_id, - station.station.external_url, - station.station.name, - } & set(station_filter): - hass.async_create_task( - hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_IMPORT}, - data={ - CONF_STATION_NUMBER: station.station_id, - CONF_NAME: station.station.name, - CONF_API_KEY: config[CONF_TOKEN], - }, - ) - ) - except WAQIAuthenticationError as err: - async_create_issue( - hass, - DOMAIN, - "deprecated_yaml_import_issue_invalid_auth", - breaks_in_ha_version="2024.4.0", - is_fixable=False, - issue_domain=DOMAIN, - severity=IssueSeverity.WARNING, - translation_key="deprecated_yaml_import_issue_invalid_auth", - translation_placeholders=ISSUE_PLACEHOLDER, - ) - _LOGGER.exception("Could not authenticate with WAQI") - raise PlatformNotReady from err - except WAQIConnectionError as err: - async_create_issue( - hass, - DOMAIN, - "deprecated_yaml_import_issue_cannot_connect", - breaks_in_ha_version="2024.4.0", - is_fixable=False, - issue_domain=DOMAIN, - severity=IssueSeverity.WARNING, - translation_key="deprecated_yaml_import_issue_cannot_connect", - translation_placeholders=ISSUE_PLACEHOLDER, - ) - _LOGGER.exception("Failed to connect to WAQI servers") - raise PlatformNotReady from err - if station_count == 0: - async_create_issue( - hass, - DOMAIN, - "deprecated_yaml_import_issue_none_found", - breaks_in_ha_version="2024.4.0", - is_fixable=False, - issue_domain=DOMAIN, - severity=IssueSeverity.WARNING, - translation_key="deprecated_yaml_import_issue_none_found", - translation_placeholders=ISSUE_PLACEHOLDER, - ) - @dataclass(frozen=True, kw_only=True) class WAQISensorEntityDescription(SensorEntityDescription): @@ -301,6 +192,7 @@ class WaqiSensor(CoordinatorEntity[WAQIDataUpdateCoordinator], SensorEntity): @property def extra_state_attributes(self) -> Mapping[str, Any] | None: """Return old state attributes if the entity is AQI entity.""" + # These are deprecated and will be removed in 2024.5 if self.entity_description.key != "air_quality": return None attrs: dict[str, Any] = {} diff --git a/tests/components/waqi/test_sensor.py b/tests/components/waqi/test_sensor.py index 7b19fbee083..328fe99330e 100644 --- a/tests/components/waqi/test_sensor.py +++ b/tests/components/waqi/test_sensor.py @@ -3,125 +3,20 @@ import json from unittest.mock import patch -from aiowaqi import WAQIAirQuality, WAQIError, WAQISearchResult +from aiowaqi import WAQIAirQuality, WAQIError import pytest from syrupy import SnapshotAssertion from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN -from homeassistant.components.waqi.const import CONF_STATION_NUMBER, DOMAIN -from homeassistant.components.waqi.sensor import CONF_LOCATIONS, CONF_STATIONS, SENSORS -from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntryState -from homeassistant.const import ( - CONF_API_KEY, - CONF_NAME, - CONF_PLATFORM, - CONF_TOKEN, - Platform, -) +from homeassistant.components.waqi.const import DOMAIN +from homeassistant.components.waqi.sensor import SENSORS +from homeassistant.config_entries import ConfigEntryState from homeassistant.core import HomeAssistant -from homeassistant.helpers import entity_registry as er, issue_registry as ir +from homeassistant.helpers import entity_registry as er from homeassistant.setup import async_setup_component from tests.common import MockConfigEntry, load_fixture -LEGACY_CONFIG = { - Platform.SENSOR: [ - { - CONF_PLATFORM: DOMAIN, - CONF_TOKEN: "asd", - CONF_LOCATIONS: ["utrecht"], - CONF_STATIONS: [6332], - } - ] -} - - -async def test_legacy_migration(hass: HomeAssistant) -> None: - """Test migration from yaml to config flow.""" - search_result_json = json.loads(load_fixture("waqi/search_result.json")) - search_results = [ - WAQISearchResult.from_dict(search_result) - for search_result in search_result_json - ] - with patch( - "aiowaqi.WAQIClient.search", - return_value=search_results, - ), patch( - "aiowaqi.WAQIClient.get_by_station_number", - return_value=WAQIAirQuality.from_dict( - json.loads(load_fixture("waqi/air_quality_sensor.json")) - ), - ): - assert await async_setup_component(hass, Platform.SENSOR, LEGACY_CONFIG) - await hass.async_block_till_done() - entries = hass.config_entries.async_entries(DOMAIN) - assert len(entries) == 1 - assert entries[0].state is ConfigEntryState.LOADED - issue_registry = ir.async_get(hass) - assert len(issue_registry.issues) == 1 - - -async def test_legacy_migration_already_imported( - hass: HomeAssistant, mock_config_entry: MockConfigEntry -) -> None: - """Test migration from yaml to config flow after already imported.""" - mock_config_entry.add_to_hass(hass) - with patch( - "aiowaqi.WAQIClient.get_by_station_number", - return_value=WAQIAirQuality.from_dict( - json.loads(load_fixture("waqi/air_quality_sensor.json")) - ), - ): - assert await async_setup_component(hass, DOMAIN, {}) - await hass.async_block_till_done() - - state = hass.states.get("sensor.de_jongweg_utrecht_air_quality_index") - assert state.state == "29" - - hass.async_create_task( - hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_IMPORT}, - data={ - CONF_STATION_NUMBER: 4584, - CONF_NAME: "xyz", - CONF_API_KEY: "asd", - }, - ) - ) - await hass.async_block_till_done() - entries = hass.config_entries.async_entries(DOMAIN) - assert len(entries) == 1 - assert entries[0].state is ConfigEntryState.LOADED - issue_registry = ir.async_get(hass) - assert len(issue_registry.issues) == 1 - - -async def test_sensor_id_migration( - hass: HomeAssistant, mock_config_entry: MockConfigEntry -) -> None: - """Test migrating unique id for original sensor.""" - mock_config_entry.add_to_hass(hass) - entity_registry = er.async_get(hass) - entity_registry.async_get_or_create( - SENSOR_DOMAIN, DOMAIN, 4584, config_entry=mock_config_entry - ) - with patch( - "aiowaqi.WAQIClient.get_by_station_number", - return_value=WAQIAirQuality.from_dict( - json.loads(load_fixture("waqi/air_quality_sensor.json")) - ), - ): - assert await async_setup_component(hass, DOMAIN, {}) - await hass.async_block_till_done() - entities = er.async_entries_for_config_entry( - entity_registry, mock_config_entry.entry_id - ) - assert len(entities) == 12 - assert hass.states.get("sensor.waqi_4584") - assert hass.states.get("sensor.de_jongweg_utrecht_air_quality_index") is None - assert entities[0].unique_id == "4584_air_quality" - @pytest.mark.usefixtures("entity_registry_enabled_by_default") async def test_sensor(