-
-
Notifications
You must be signed in to change notification settings - Fork 31.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Migrate WAQI to aiowaqi library * Migrate WAQI to aiowaqi library * Migrate WAQI to aiowaqi library * Add config flow to WAQI * Finish config flow * Add tests * Add tests * Fix ruff * Add issues on failing to import * Add issues on failing to import * Add issues on failing to import * Add importing issue * Finish coverage * Remove url from translation string * Fix feedback * Fix feedback
- Loading branch information
Showing
17 changed files
with
825 additions
and
79 deletions.
There are no files selected for viewing
Validating CODEOWNERS rules …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,37 @@ | ||
"""The waqi component.""" | ||
"""The World Air Quality Index (WAQI) integration.""" | ||
from __future__ import annotations | ||
|
||
from aiowaqi import WAQIClient | ||
|
||
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 | ||
|
||
from .const import DOMAIN | ||
from .coordinator import WAQIDataUpdateCoordinator | ||
|
||
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.""" | ||
|
||
client = WAQIClient(session=async_get_clientsession(hass)) | ||
client.authenticate(entry.data[CONF_API_KEY]) | ||
|
||
waqi_coordinator = WAQIDataUpdateCoordinator(hass, client) | ||
await waqi_coordinator.async_config_entry_first_refresh() | ||
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = waqi_coordinator | ||
|
||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) | ||
|
||
return True | ||
|
||
|
||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: | ||
"""Unload a config entry.""" | ||
if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS): | ||
hass.data[DOMAIN].pop(entry.entry_id) | ||
|
||
return unload_ok |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
"""Config flow for World Air Quality Index (WAQI) integration.""" | ||
from __future__ import annotations | ||
|
||
import logging | ||
from typing import Any | ||
|
||
from aiowaqi import ( | ||
WAQIAirQuality, | ||
WAQIAuthenticationError, | ||
WAQIClient, | ||
WAQIConnectionError, | ||
) | ||
import voluptuous as vol | ||
|
||
from homeassistant.config_entries import ConfigFlow | ||
from homeassistant.const import ( | ||
CONF_API_KEY, | ||
CONF_LATITUDE, | ||
CONF_LOCATION, | ||
CONF_LONGITUDE, | ||
CONF_NAME, | ||
) | ||
from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN | ||
from homeassistant.data_entry_flow import AbortFlow, FlowResult | ||
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 | ||
from homeassistant.helpers.typing import ConfigType | ||
|
||
from .const import CONF_STATION_NUMBER, DOMAIN, ISSUE_PLACEHOLDER | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
|
||
|
||
class WAQIConfigFlow(ConfigFlow, domain=DOMAIN): | ||
"""Handle a config flow for World Air Quality Index (WAQI).""" | ||
|
||
VERSION = 1 | ||
|
||
async def async_step_user( | ||
self, user_input: dict[str, Any] | None = None | ||
) -> FlowResult: | ||
"""Handle the initial step.""" | ||
errors: dict[str, str] = {} | ||
if user_input is not None: | ||
async with WAQIClient( | ||
session=async_get_clientsession(self.hass) | ||
) as waqi_client: | ||
waqi_client.authenticate(user_input[CONF_API_KEY]) | ||
location = user_input[CONF_LOCATION] | ||
try: | ||
measuring_station: WAQIAirQuality = ( | ||
await waqi_client.get_by_coordinates( | ||
location[CONF_LATITUDE], location[CONF_LONGITUDE] | ||
) | ||
) | ||
except WAQIAuthenticationError: | ||
errors["base"] = "invalid_auth" | ||
except WAQIConnectionError: | ||
errors["base"] = "cannot_connect" | ||
except Exception as exc: # pylint: disable=broad-except | ||
_LOGGER.exception(exc) | ||
errors["base"] = "unknown" | ||
else: | ||
await self.async_set_unique_id(str(measuring_station.station_id)) | ||
self._abort_if_unique_id_configured() | ||
return self.async_create_entry( | ||
title=measuring_station.city.name, | ||
data={ | ||
CONF_API_KEY: user_input[CONF_API_KEY], | ||
CONF_STATION_NUMBER: measuring_station.station_id, | ||
}, | ||
) | ||
|
||
return self.async_show_form( | ||
step_id="user", | ||
data_schema=self.add_suggested_values_to_schema( | ||
vol.Schema( | ||
{ | ||
vol.Required(CONF_API_KEY): str, | ||
vol.Required( | ||
CONF_LOCATION, | ||
): LocationSelector(), | ||
} | ||
), | ||
user_input | ||
or { | ||
CONF_LOCATION: { | ||
CONF_LATITUDE: self.hass.config.latitude, | ||
CONF_LONGITUDE: self.hass.config.longitude, | ||
} | ||
}, | ||
), | ||
errors=errors, | ||
) | ||
|
||
async def async_step_import(self, import_config: ConfigType) -> FlowResult: | ||
"""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], | ||
}, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
"""Constants for the World Air Quality Index (WAQI) integration.""" | ||
import logging | ||
|
||
DOMAIN = "waqi" | ||
|
||
LOGGER = logging.getLogger(__package__) | ||
|
||
CONF_STATION_NUMBER = "station_number" | ||
|
||
ISSUE_PLACEHOLDER = {"url": "/config/integrations/dashboard/add?domain=waqi"} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
"""Coordinator for the World Air Quality Index (WAQI) integration.""" | ||
from __future__ import annotations | ||
|
||
from datetime import timedelta | ||
|
||
from aiowaqi import WAQIAirQuality, WAQIClient, WAQIError | ||
|
||
from homeassistant.config_entries import ConfigEntry | ||
from homeassistant.core import HomeAssistant | ||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed | ||
|
||
from .const import CONF_STATION_NUMBER, DOMAIN, LOGGER | ||
|
||
|
||
class WAQIDataUpdateCoordinator(DataUpdateCoordinator[WAQIAirQuality]): | ||
"""The WAQI Data Update Coordinator.""" | ||
|
||
config_entry: ConfigEntry | ||
|
||
def __init__(self, hass: HomeAssistant, client: WAQIClient) -> None: | ||
"""Initialize the WAQI data coordinator.""" | ||
super().__init__( | ||
hass, | ||
LOGGER, | ||
name=DOMAIN, | ||
update_interval=timedelta(minutes=5), | ||
) | ||
self._client = client | ||
|
||
async def _async_update_data(self) -> WAQIAirQuality: | ||
try: | ||
return await self._client.get_by_station_number( | ||
self.config_entry.data[CONF_STATION_NUMBER] | ||
) | ||
except WAQIError as exc: | ||
raise UpdateFailed from exc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.