forked from home-assistant/core
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Switch to config_flow for Environment Canada (home-assistant#57127)
* Add config_flow to Environment Canada * Add unique_id * Remove erroneous directory. * Tests working!! * Add back setup. * First cut of import. * Temp * Tweak names. * Import config.yaml. * Clean up imports. * Import working! Some refactor to clean it up. * Add import test. * Small optimization. * Fix comments from code review. * Remove CONF_NAME and config_flow for it. * Fixup strings to match new config_flow. * Fixes for comments from last review. * Update tests to match new import code. * Clean up use of CONF_TITLE; fix lint error on push. * Phew. More cleanup on import. Really streamlined now! * Update tests. * Fix lint error. * Fix lint error, try 2. * Revert unique_id to use location as part of ID. * Fix code review comments. * Fix review comments.
- Loading branch information
Glenn Waters
authored
Oct 11, 2021
1 parent
8ee6662
commit d0b3722
Showing
16 changed files
with
546 additions
and
92 deletions.
There are no files selected for viewing
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
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,79 @@ | ||
"""A component for Environment Canada weather.""" | ||
"""The Environment Canada (EC) component.""" | ||
from functools import partial | ||
import logging | ||
|
||
from env_canada import ECData, ECRadar | ||
|
||
from homeassistant.config_entries import SOURCE_IMPORT | ||
from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE | ||
|
||
from .const import CONF_LANGUAGE, CONF_STATION, DOMAIN | ||
|
||
PLATFORMS = ["camera", "sensor", "weather"] | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
|
||
|
||
async def async_setup_entry(hass, config_entry): | ||
"""Set up EC as config entry.""" | ||
lat = config_entry.data.get(CONF_LATITUDE) | ||
lon = config_entry.data.get(CONF_LONGITUDE) | ||
station = config_entry.data.get(CONF_STATION) | ||
lang = config_entry.data.get(CONF_LANGUAGE, "English") | ||
|
||
weather_api = {} | ||
|
||
weather_init = partial( | ||
ECData, station_id=station, coordinates=(lat, lon), language=lang.lower() | ||
) | ||
weather_data = await hass.async_add_executor_job(weather_init) | ||
weather_api["weather_data"] = weather_data | ||
|
||
radar_init = partial(ECRadar, coordinates=(lat, lon)) | ||
radar_data = await hass.async_add_executor_job(radar_init) | ||
weather_api["radar_data"] = radar_data | ||
await hass.async_add_executor_job(radar_data.get_loop) | ||
|
||
hass.data.setdefault(DOMAIN, {}) | ||
hass.data[DOMAIN][config_entry.entry_id] = weather_api | ||
|
||
hass.config_entries.async_setup_platforms(config_entry, PLATFORMS) | ||
|
||
return True | ||
|
||
|
||
async def async_unload_entry(hass, config_entry): | ||
"""Unload a config entry.""" | ||
unload_ok = await hass.config_entries.async_unload_platforms( | ||
config_entry, PLATFORMS | ||
) | ||
|
||
hass.data[DOMAIN].pop(config_entry.entry_id) | ||
|
||
return unload_ok | ||
|
||
|
||
def trigger_import(hass, config): | ||
"""Trigger a import of YAML config into a config_entry.""" | ||
_LOGGER.warning( | ||
"Environment Canada YAML configuration is deprecated; your YAML configuration " | ||
"has been imported into the UI and can be safely removed" | ||
) | ||
if not config.get(CONF_LANGUAGE): | ||
config[CONF_LANGUAGE] = "English" | ||
|
||
data = {} | ||
for key in ( | ||
CONF_STATION, | ||
CONF_LATITUDE, | ||
CONF_LONGITUDE, | ||
CONF_LANGUAGE, | ||
): # pylint: disable=consider-using-tuple | ||
if config.get(key): | ||
data[key] = config[key] | ||
|
||
hass.async_create_task( | ||
hass.config_entries.flow.async_init( | ||
DOMAIN, context={"source": SOURCE_IMPORT}, data=data | ||
) | ||
) |
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
108 changes: 108 additions & 0 deletions
108
homeassistant/components/environment_canada/config_flow.py
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,108 @@ | ||
"""Config flow for Environment Canada integration.""" | ||
from functools import partial | ||
import logging | ||
import xml.etree.ElementTree as et | ||
|
||
import aiohttp | ||
from env_canada import ECData | ||
import voluptuous as vol | ||
|
||
from homeassistant import config_entries, exceptions | ||
from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE | ||
from homeassistant.helpers import config_validation as cv | ||
|
||
from .const import CONF_LANGUAGE, CONF_STATION, CONF_TITLE, DOMAIN | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
|
||
|
||
async def validate_input(hass, data): | ||
"""Validate the user input allows us to connect.""" | ||
lat = data.get(CONF_LATITUDE) | ||
lon = data.get(CONF_LONGITUDE) | ||
station = data.get(CONF_STATION) | ||
lang = data.get(CONF_LANGUAGE) | ||
|
||
weather_init = partial( | ||
ECData, station_id=station, coordinates=(lat, lon), language=lang.lower() | ||
) | ||
weather_data = await hass.async_add_executor_job(weather_init) | ||
if weather_data.metadata.get("location") is None: | ||
raise TooManyAttempts | ||
|
||
if lat is None or lon is None: | ||
lat = weather_data.lat | ||
lon = weather_data.lon | ||
|
||
return { | ||
CONF_TITLE: weather_data.metadata.get("location"), | ||
CONF_STATION: weather_data.station_id, | ||
CONF_LATITUDE: lat, | ||
CONF_LONGITUDE: lon, | ||
} | ||
|
||
|
||
class EnvironmentCanadaConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): | ||
"""Handle a config flow for Environment Canada weather.""" | ||
|
||
VERSION = 1 | ||
|
||
async def async_step_user(self, user_input=None): | ||
"""Handle the initial step.""" | ||
errors = {} | ||
if user_input is not None: | ||
try: | ||
info = await validate_input(self.hass, user_input) | ||
except TooManyAttempts: | ||
errors["base"] = "too_many_attempts" | ||
except et.ParseError: | ||
errors["base"] = "bad_station_id" | ||
except aiohttp.ClientConnectionError: | ||
errors["base"] = "cannot_connect" | ||
except aiohttp.ClientResponseError as err: | ||
if err.status == 404: | ||
errors["base"] = "bad_station_id" | ||
else: | ||
errors["base"] = "error_response" | ||
except Exception: # pylint: disable=broad-except | ||
_LOGGER.exception("Unexpected exception") | ||
errors["base"] = "unknown" | ||
|
||
if not errors: | ||
user_input[CONF_STATION] = info[CONF_STATION] | ||
user_input[CONF_LATITUDE] = info[CONF_LATITUDE] | ||
user_input[CONF_LONGITUDE] = info[CONF_LONGITUDE] | ||
|
||
# The combination of station and language are unique for all EC weather reporting | ||
await self.async_set_unique_id( | ||
f"{user_input[CONF_STATION]}-{user_input[CONF_LANGUAGE].lower()}" | ||
) | ||
self._abort_if_unique_id_configured() | ||
return self.async_create_entry(title=info[CONF_TITLE], data=user_input) | ||
|
||
data_schema = vol.Schema( | ||
{ | ||
vol.Optional(CONF_STATION): str, | ||
vol.Optional( | ||
CONF_LATITUDE, default=self.hass.config.latitude | ||
): cv.latitude, | ||
vol.Optional( | ||
CONF_LONGITUDE, default=self.hass.config.longitude | ||
): cv.longitude, | ||
vol.Required(CONF_LANGUAGE, default="English"): vol.In( | ||
["English", "French"] | ||
), | ||
} | ||
) | ||
|
||
return self.async_show_form( | ||
step_id="user", data_schema=data_schema, errors=errors | ||
) | ||
|
||
async def async_step_import(self, import_data): | ||
"""Import entry from configuration.yaml.""" | ||
return await self.async_step_user(import_data) | ||
|
||
|
||
class TooManyAttempts(exceptions.HomeAssistantError): | ||
"""Error to indicate station ID is missing, invalid, or not in EC database.""" |
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,9 @@ | ||
"""Constants for EC component.""" | ||
|
||
ATTR_OBSERVATION_TIME = "observation_time" | ||
ATTR_STATION = "station" | ||
CONF_ATTRIBUTION = "Data provided by Environment Canada" | ||
CONF_LANGUAGE = "language" | ||
CONF_STATION = "station" | ||
CONF_TITLE = "title" | ||
DOMAIN = "environment_canada" |
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.