-
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3 from FaserF/feature/config-flow
Add support for HA config Flow
- Loading branch information
Showing
7 changed files
with
341 additions
and
94 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,84 @@ | ||
"""The deutschebahn component.""" | ||
"""Bahn.de Custom Component.""" | ||
import asyncio | ||
import logging | ||
from datetime import timedelta | ||
|
||
from homeassistant import config_entries, core | ||
|
||
from homeassistant.helpers.update_coordinator import ( | ||
CoordinatorEntity, | ||
DataUpdateCoordinator, | ||
UpdateFailed, | ||
) | ||
|
||
from .const import DOMAIN | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
SCAN_INTERVAL = timedelta(minutes=2) | ||
|
||
async def async_setup_entry( | ||
hass: core.HomeAssistant, entry: config_entries.ConfigEntry | ||
) -> bool: | ||
"""Set up platform from a ConfigEntry.""" | ||
hass.data.setdefault(DOMAIN, {}) | ||
hass_data = dict(entry.data) | ||
# Registers update listener to update config entry when options are updated. | ||
unsub_options_update_listener = entry.add_update_listener(options_update_listener) | ||
# Store a reference to the unsubscribe function to cleanup if an entry is unloaded. | ||
hass_data["unsub_options_update_listener"] = unsub_options_update_listener | ||
hass.data[DOMAIN][entry.entry_id] = hass_data | ||
|
||
# Forward the setup to the sensor platform. | ||
hass.async_create_task( | ||
hass.config_entries.async_forward_entry_setup(entry, "sensor") | ||
) | ||
|
||
config = hass.data[DOMAIN][entry.entry_id] | ||
async def async_update_data(): | ||
"""Fetch data from Schiene.""" | ||
update_interval=timedelta(minutes=config[CONF_SCAN_INTERVAL]) | ||
async with async_timeout.timeout(update_interval - 1): | ||
await hass.async_add_executor_job(lambda: data.update()) | ||
|
||
if not data.state: | ||
raise UpdateFailed(f"Error fetching {entry.entry_id} Schiene state") | ||
|
||
return data.state | ||
|
||
coordinator = DataUpdateCoordinator( | ||
hass, | ||
_LOGGER, | ||
name=f"{entry.entry_id} Schiene state", | ||
update_method=async_update_data, | ||
) | ||
|
||
return True | ||
|
||
|
||
async def options_update_listener( | ||
hass: core.HomeAssistant, config_entry: config_entries.ConfigEntry | ||
): | ||
"""Handle options update.""" | ||
await hass.config_entries.async_reload(config_entry.entry_id) | ||
|
||
async def async_update(self): | ||
"""Async wrapper for update method.""" | ||
return await self._hass.async_add_executor_job(self._update) | ||
|
||
async def async_unload_entry( | ||
hass: core.HomeAssistant, entry: config_entries.ConfigEntry | ||
) -> bool: | ||
"""Unload a config entry.""" | ||
unload_ok = all( | ||
await asyncio.gather( | ||
*[hass.config_entries.async_forward_entry_unload(entry, "sensor")] | ||
) | ||
) | ||
# Remove options_update_listener. | ||
hass.data[DOMAIN][entry.entry_id]["unsub_options_update_listener"]() | ||
|
||
# Remove config entry from domain. | ||
if unload_ok: | ||
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,97 @@ | ||
"""Config flow""" | ||
import logging | ||
|
||
import voluptuous as vol | ||
|
||
from homeassistant import config_entries | ||
from homeassistant.const import CONF_NAME | ||
from homeassistant.core import callback | ||
import homeassistant.helpers.config_validation as cv | ||
|
||
from .const import ( # pylint: disable=unused-import | ||
CONF_DESTINATION, | ||
CONF_START, | ||
CONF_OFFSET, | ||
CONF_ONLY_DIRECT, | ||
) | ||
DOMAIN = "deutschebahn" | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
|
||
|
||
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): | ||
"""Handle a config flow""" | ||
|
||
VERSION = 1 | ||
CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_POLL | ||
|
||
async def async_step_user(self, user_input=None): | ||
"""Handle the initial step.""" | ||
errors = {} | ||
|
||
if user_input is not None: | ||
await self.async_set_unique_id(user_input[CONF_START]) | ||
self._abort_if_unique_id_configured() | ||
return self.async_create_entry(title=user_input[CONF_START] + "-" + user_input[CONF_DESTINATION], data=user_input) | ||
|
||
_LOGGER.debug( | ||
"Initialized new deutschebahn with id: {unique_id}" | ||
) | ||
|
||
data_schema = vol.Schema( | ||
{ | ||
vol.Required(CONF_START): str, | ||
vol.Required(CONF_DESTINATION): str, | ||
vol.Required(CONF_OFFSET, default=0): cv.positive_int, | ||
vol.Required(CONF_ONLY_DIRECT, default=False): cv.boolean, | ||
}, | ||
) | ||
|
||
return self.async_show_form( | ||
step_id="user", data_schema=data_schema, errors=errors | ||
) | ||
|
||
|
||
def validate_options(user_input, errors): | ||
"""Validate the options in the OptionsFlow. | ||
This is an extra validation step because the validators | ||
in `EXTRA_VALIDATION` cannot be serialized to json. | ||
""" | ||
for key, (validate, _) in EXTRA_VALIDATION.items(): | ||
# these are unserializable validators | ||
value = user_input.get(key) | ||
try: | ||
if value is not None and value != NONE_STR: | ||
validate(value) | ||
except vol.Invalid: | ||
_LOGGER.exception("Configuration option %s=%s is incorrect", key, value) | ||
errors["base"] = "option_error" | ||
|
||
|
||
class OptionsFlowHandler(config_entries.OptionsFlow): | ||
"""Handle a option flow""" | ||
|
||
def __init__(self, config_entry: config_entries.ConfigEntry): | ||
"""Initialize options flow.""" | ||
self.config_entry = config_entry | ||
|
||
async def async_step_init(self, user_input=None): | ||
"""Handle options flow.""" | ||
conf = self.config_entry | ||
if conf.source == config_entries.SOURCE_IMPORT: | ||
return self.async_show_form(step_id="init", data_schema=None) | ||
errors = {} | ||
if user_input is not None: | ||
validate_options(user_input, errors) | ||
if not errors: | ||
return self.async_create_entry(title="", data=user_input) | ||
|
||
options_schema = {} | ||
for name, default, validation in VALIDATION_TUPLES: | ||
key = vol.Optional(name, default=conf.options.get(name, default)) | ||
value = to_replace.get(name, validation) | ||
options_schema[key] = value | ||
|
||
return self.async_show_form( | ||
step_id="init", data_schema=vol.Schema(options_schema), errors=errors | ||
) |
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 @@ | ||
"""German Train System - Deutsche Bahn""" | ||
DOMAIN = "deutschebahn" | ||
ATTRIBUTION = "Data provided by bahn.de api" | ||
|
||
CONF_DESTINATION = "to" | ||
CONF_START = "from" | ||
CONF_OFFSET = "offset" | ||
CONF_ONLY_DIRECT = "only_direct" | ||
|
||
ATTR_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
Oops, something went wrong.