"""Configflow for the emoncms integration.""" from typing import Any from pyemoncms import EmoncmsClient import voluptuous as vol from homeassistant.config_entries import ( ConfigEntry, ConfigFlow, ConfigFlowResult, OptionsFlowWithConfigEntry, ) from homeassistant.const import CONF_API_KEY, CONF_URL from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.selector import selector from homeassistant.helpers.typing import ConfigType from .const import ( CONF_MESSAGE, CONF_ONLY_INCLUDE_FEEDID, CONF_SUCCESS, DOMAIN, FEED_ID, FEED_NAME, FEED_TAG, LOGGER, ) def get_options(feeds: list[dict[str, Any]]) -> list[dict[str, Any]]: """Build the selector options with the feed list.""" return [ { "value": feed[FEED_ID], "label": f"{feed[FEED_ID]}|{feed[FEED_TAG]}|{feed[FEED_NAME]}", } for feed in feeds ] def sensor_name(url: str) -> str: """Return sensor name.""" sensorip = url.rsplit("//", maxsplit=1)[-1] return f"emoncms@{sensorip}" async def get_feed_list(hass: HomeAssistant, url: str, api_key: str) -> dict[str, Any]: """Check connection to emoncms and return feed list if successful.""" emoncms_client = EmoncmsClient( url, api_key, session=async_get_clientsession(hass), ) return await emoncms_client.async_request("/feed/list.json") class EmoncmsConfigFlow(ConfigFlow, domain=DOMAIN): """emoncms integration UI config flow.""" url: str api_key: str include_only_feeds: list | None = None dropdown: dict = {} @staticmethod @callback def async_get_options_flow( config_entry: ConfigEntry, ) -> OptionsFlowWithConfigEntry: """Get the options flow for this handler.""" return EmoncmsOptionsFlow(config_entry) async def async_step_user( self, user_input: dict[str, Any] | None = None ) -> ConfigFlowResult: """Initiate a flow via the UI.""" errors: dict[str, str] = {} if user_input is not None: self._async_abort_entries_match( { CONF_API_KEY: user_input[CONF_API_KEY], CONF_URL: user_input[CONF_URL], } ) result = await get_feed_list( self.hass, user_input[CONF_URL], user_input[CONF_API_KEY] ) if not result[CONF_SUCCESS]: errors["base"] = result[CONF_MESSAGE] else: self.include_only_feeds = user_input.get(CONF_ONLY_INCLUDE_FEEDID) self.url = user_input[CONF_URL] self.api_key = user_input[CONF_API_KEY] options = get_options(result[CONF_MESSAGE]) self.dropdown = { "options": options, "mode": "dropdown", "multiple": True, } return await self.async_step_choose_feeds() return self.async_show_form( step_id="user", data_schema=self.add_suggested_values_to_schema( vol.Schema( { vol.Required(CONF_URL): str, vol.Required(CONF_API_KEY): str, } ), user_input, ), errors=errors, ) async def async_step_choose_feeds( self, user_input: dict[str, Any] | None = None, ) -> ConfigFlowResult: """Choose feeds to import.""" errors: dict[str, str] = {} include_only_feeds: list = [] if user_input or self.include_only_feeds is not None: if self.include_only_feeds is not None: include_only_feeds = self.include_only_feeds elif user_input: include_only_feeds = user_input[CONF_ONLY_INCLUDE_FEEDID] return self.async_create_entry( title=sensor_name(self.url), data={ CONF_URL: self.url, CONF_API_KEY: self.api_key, CONF_ONLY_INCLUDE_FEEDID: include_only_feeds, }, ) return self.async_show_form( step_id="choose_feeds", data_schema=vol.Schema( { vol.Required( CONF_ONLY_INCLUDE_FEEDID, default=include_only_feeds, ): selector({"select": self.dropdown}), } ), errors=errors, ) async def async_step_import(self, import_info: ConfigType) -> ConfigFlowResult: """Import config from yaml.""" url = import_info[CONF_URL] api_key = import_info[CONF_API_KEY] include_only_feeds = None if import_info.get(CONF_ONLY_INCLUDE_FEEDID) is not None: include_only_feeds = list(map(str, import_info[CONF_ONLY_INCLUDE_FEEDID])) config = { CONF_API_KEY: api_key, CONF_ONLY_INCLUDE_FEEDID: include_only_feeds, CONF_URL: url, } LOGGER.debug(config) result = await self.async_step_user(config) if errors := result.get("errors"): return self.async_abort(reason=errors["base"]) return result class EmoncmsOptionsFlow(OptionsFlowWithConfigEntry): """Emoncms Options flow handler.""" async def async_step_init( self, user_input: dict[str, Any] | None = None ) -> ConfigFlowResult: """Manage the options.""" errors: dict[str, str] = {} data = self.options if self.options else self._config_entry.data url = data[CONF_URL] api_key = data[CONF_API_KEY] include_only_feeds = data.get(CONF_ONLY_INCLUDE_FEEDID, []) options: list = include_only_feeds result = await get_feed_list(self.hass, url, api_key) if not result[CONF_SUCCESS]: errors["base"] = result[CONF_MESSAGE] else: options = get_options(result[CONF_MESSAGE]) dropdown = {"options": options, "mode": "dropdown", "multiple": True} if user_input: include_only_feeds = user_input[CONF_ONLY_INCLUDE_FEEDID] return self.async_create_entry( title=sensor_name(url), data={ CONF_URL: url, CONF_API_KEY: api_key, CONF_ONLY_INCLUDE_FEEDID: include_only_feeds, }, ) return self.async_show_form( step_id="init", data_schema=vol.Schema( { vol.Required( CONF_ONLY_INCLUDE_FEEDID, default=include_only_feeds ): selector({"select": dropdown}), } ), errors=errors, )