From 1e22c8dacac252e41c152b1b0ce1b9d47ba8c7ec Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 13 May 2019 01:16:55 -0700 Subject: [PATCH] Automatically generate config flow list (#23802) * Add config flow to manifest.json * Still load config flows via config flow platform * Fix typo * Lint * Update config_flows.py" * Catch import error when setting up entry * Lint * Fix tests * Fix imports * Lint * Fix Unifi tests * Fix translation test * Add homekit_controller config flow --- .../components/ambiclimate/manifest.json | 1 + .../components/ambient_station/manifest.json | 1 + homeassistant/components/axis/manifest.json | 1 + homeassistant/components/cast/__init__.py | 15 +- homeassistant/components/cast/config_flow.py | 16 +++ homeassistant/components/cast/const.py | 3 + homeassistant/components/cast/manifest.json | 1 + .../components/config/config_entries.py | 3 +- homeassistant/components/daikin/manifest.json | 1 + homeassistant/components/deconz/manifest.json | 1 + .../components/dialogflow/__init__.py | 15 +- .../components/dialogflow/config_flow.py | 13 ++ homeassistant/components/dialogflow/const.py | 3 + .../components/dialogflow/manifest.json | 1 + .../components/emulated_roku/manifest.json | 1 + .../components/esphome/manifest.json | 1 + homeassistant/components/geofency/__init__.py | 12 +- .../components/geofency/config_flow.py | 12 ++ homeassistant/components/geofency/const.py | 3 + .../components/geofency/manifest.json | 1 + .../components/gpslogger/__init__.py | 11 +- .../components/gpslogger/config_flow.py | 12 ++ homeassistant/components/gpslogger/const.py | 3 + .../components/gpslogger/manifest.json | 1 + .../components/hangouts/manifest.json | 1 + homeassistant/components/heos/manifest.json | 1 + .../homekit_controller/manifest.json | 1 + .../homematicip_cloud/manifest.json | 1 + homeassistant/components/hue/manifest.json | 1 + homeassistant/components/ifttt/__init__.py | 13 +- homeassistant/components/ifttt/config_flow.py | 13 ++ homeassistant/components/ifttt/const.py | 3 + homeassistant/components/ifttt/manifest.json | 1 + homeassistant/components/ios/__init__.py | 8 +- homeassistant/components/ios/config_flow.py | 9 ++ homeassistant/components/ios/const.py | 3 + homeassistant/components/ios/manifest.json | 1 + homeassistant/components/ipma/manifest.json | 1 + homeassistant/components/iqvia/manifest.json | 1 + homeassistant/components/lifx/__init__.py | 16 +-- homeassistant/components/lifx/config_flow.py | 16 +++ homeassistant/components/lifx/const.py | 3 + homeassistant/components/lifx/manifest.json | 1 + homeassistant/components/locative/__init__.py | 9 -- .../components/locative/config_flow.py | 12 ++ homeassistant/components/locative/const.py | 3 + .../components/locative/manifest.json | 1 + .../components/logi_circle/manifest.json | 1 + .../components/luftdaten/manifest.json | 1 + homeassistant/components/mailgun/__init__.py | 14 +- .../components/mailgun/config_flow.py | 13 ++ homeassistant/components/mailgun/const.py | 3 + .../components/mailgun/manifest.json | 1 + .../components/mobile_app/__init__.py | 24 ---- .../components/mobile_app/config_flow.py | 26 ++++ .../components/mobile_app/manifest.json | 1 + homeassistant/components/mqtt/manifest.json | 1 + homeassistant/components/nest/manifest.json | 1 + homeassistant/components/openuv/manifest.json | 1 + .../components/owntracks/manifest.json | 1 + homeassistant/components/point/manifest.json | 1 + homeassistant/components/ps4/manifest.json | 1 + .../components/rainmachine/manifest.json | 1 + .../components/simplisafe/manifest.json | 1 + .../components/smartthings/manifest.json | 1 + homeassistant/components/smhi/manifest.json | 1 + homeassistant/components/sonos/__init__.py | 16 +-- homeassistant/components/sonos/config_flow.py | 15 ++ homeassistant/components/sonos/const.py | 3 + homeassistant/components/sonos/manifest.json | 1 + .../components/tellduslive/manifest.json | 1 + homeassistant/components/toon/manifest.json | 1 + homeassistant/components/tplink/__init__.py | 24 +--- .../components/tplink/config_flow.py | 20 +++ homeassistant/components/tplink/const.py | 3 + homeassistant/components/tplink/manifest.json | 1 + .../components/tradfri/manifest.json | 1 + homeassistant/components/twilio/__init__.py | 14 +- .../components/twilio/config_flow.py | 15 ++ homeassistant/components/twilio/const.py | 3 + homeassistant/components/twilio/manifest.json | 1 + homeassistant/components/unifi/__init__.py | 130 +----------------- homeassistant/components/unifi/config_flow.py | 130 ++++++++++++++++++ homeassistant/components/unifi/manifest.json | 1 + homeassistant/components/upnp/__init__.py | 8 -- homeassistant/components/upnp/config_flow.py | 13 ++ homeassistant/components/upnp/manifest.json | 1 + homeassistant/components/zha/manifest.json | 1 + homeassistant/components/zone/manifest.json | 1 + homeassistant/components/zwave/manifest.json | 1 + homeassistant/config_entries.py | 76 +++------- homeassistant/generated/config_flows.py | 55 ++++++++ homeassistant/helpers/translation.py | 4 +- pylintrc | 6 + script/hassfest/__main__.py | 3 +- script/hassfest/config_flow.py | 85 ++++++++++++ script/hassfest/manifest.py | 1 + script/hassfest/model.py | 8 ++ tests/common.py | 2 +- .../components/config/test_config_entries.py | 20 ++- tests/components/unifi/test_controller.py | 27 ++-- tests/components/unifi/test_init.py | 97 ++++++------- tests/components/unifi/test_switch.py | 20 +-- tests/helpers/test_config_entry_flow.py | 8 +- tests/helpers/test_translation.py | 4 +- tests/test_config_entries.py | 16 +++ 106 files changed, 742 insertions(+), 440 deletions(-) create mode 100644 homeassistant/components/cast/config_flow.py create mode 100644 homeassistant/components/cast/const.py create mode 100644 homeassistant/components/dialogflow/config_flow.py create mode 100644 homeassistant/components/dialogflow/const.py create mode 100644 homeassistant/components/geofency/config_flow.py create mode 100644 homeassistant/components/geofency/const.py create mode 100644 homeassistant/components/gpslogger/config_flow.py create mode 100644 homeassistant/components/gpslogger/const.py create mode 100644 homeassistant/components/ifttt/config_flow.py create mode 100644 homeassistant/components/ifttt/const.py create mode 100644 homeassistant/components/ios/config_flow.py create mode 100644 homeassistant/components/ios/const.py create mode 100644 homeassistant/components/lifx/config_flow.py create mode 100644 homeassistant/components/lifx/const.py create mode 100644 homeassistant/components/locative/config_flow.py create mode 100644 homeassistant/components/locative/const.py create mode 100644 homeassistant/components/mailgun/config_flow.py create mode 100644 homeassistant/components/mailgun/const.py create mode 100644 homeassistant/components/mobile_app/config_flow.py create mode 100644 homeassistant/components/sonos/config_flow.py create mode 100644 homeassistant/components/sonos/const.py create mode 100644 homeassistant/components/tplink/config_flow.py create mode 100644 homeassistant/components/tplink/const.py create mode 100644 homeassistant/components/twilio/config_flow.py create mode 100644 homeassistant/components/twilio/const.py create mode 100644 homeassistant/components/unifi/config_flow.py create mode 100644 homeassistant/components/upnp/config_flow.py create mode 100644 homeassistant/generated/config_flows.py create mode 100644 script/hassfest/config_flow.py diff --git a/homeassistant/components/ambiclimate/manifest.json b/homeassistant/components/ambiclimate/manifest.json index f3b3450f163..bd1117d86bc 100644 --- a/homeassistant/components/ambiclimate/manifest.json +++ b/homeassistant/components/ambiclimate/manifest.json @@ -1,6 +1,7 @@ { "domain": "ambiclimate", "name": "Ambiclimate", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/ambiclimate", "requirements": [ "ambiclimate==0.1.1" diff --git a/homeassistant/components/ambient_station/manifest.json b/homeassistant/components/ambient_station/manifest.json index 11d2ad3668e..3e9bbf6a5b8 100644 --- a/homeassistant/components/ambient_station/manifest.json +++ b/homeassistant/components/ambient_station/manifest.json @@ -1,6 +1,7 @@ { "domain": "ambient_station", "name": "Ambient station", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/ambient_station", "requirements": [ "aioambient==0.3.0" diff --git a/homeassistant/components/axis/manifest.json b/homeassistant/components/axis/manifest.json index f87718bfddd..0379ee3b03c 100644 --- a/homeassistant/components/axis/manifest.json +++ b/homeassistant/components/axis/manifest.json @@ -1,6 +1,7 @@ { "domain": "axis", "name": "Axis", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/axis", "requirements": ["axis==22"], "dependencies": [], diff --git a/homeassistant/components/cast/__init__.py b/homeassistant/components/cast/__init__.py index 1a93020c229..f91b90c1e08 100644 --- a/homeassistant/components/cast/__init__.py +++ b/homeassistant/components/cast/__init__.py @@ -1,8 +1,7 @@ """Component to embed Google Cast.""" from homeassistant import config_entries -from homeassistant.helpers import config_entry_flow -DOMAIN = 'cast' +from .const import DOMAIN async def async_setup(hass, config): @@ -23,15 +22,3 @@ async def async_setup_entry(hass, entry): hass.async_create_task(hass.config_entries.async_forward_entry_setup( entry, 'media_player')) return True - - -async def _async_has_devices(hass): - """Return if there are devices that can be discovered.""" - from pychromecast.discovery import discover_chromecasts - - return await hass.async_add_executor_job(discover_chromecasts) - - -config_entry_flow.register_discovery_flow( - DOMAIN, 'Google Cast', _async_has_devices, - config_entries.CONN_CLASS_LOCAL_PUSH) diff --git a/homeassistant/components/cast/config_flow.py b/homeassistant/components/cast/config_flow.py new file mode 100644 index 00000000000..0f8696cf29c --- /dev/null +++ b/homeassistant/components/cast/config_flow.py @@ -0,0 +1,16 @@ +"""Config flow for Cast.""" +from homeassistant.helpers import config_entry_flow +from homeassistant import config_entries +from .const import DOMAIN + + +async def _async_has_devices(hass): + """Return if there are devices that can be discovered.""" + from pychromecast.discovery import discover_chromecasts + + return await hass.async_add_executor_job(discover_chromecasts) + + +config_entry_flow.register_discovery_flow( + DOMAIN, 'Google Cast', _async_has_devices, + config_entries.CONN_CLASS_LOCAL_PUSH) diff --git a/homeassistant/components/cast/const.py b/homeassistant/components/cast/const.py new file mode 100644 index 00000000000..48bb87ca5d7 --- /dev/null +++ b/homeassistant/components/cast/const.py @@ -0,0 +1,3 @@ +"""Consts for Cast integration.""" + +DOMAIN = 'cast' diff --git a/homeassistant/components/cast/manifest.json b/homeassistant/components/cast/manifest.json index dd189ac91e7..2d310cdda8f 100644 --- a/homeassistant/components/cast/manifest.json +++ b/homeassistant/components/cast/manifest.json @@ -1,6 +1,7 @@ { "domain": "cast", "name": "Cast", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/cast", "requirements": [ "pychromecast==3.2.1" diff --git a/homeassistant/components/config/config_entries.py b/homeassistant/components/config/config_entries.py index 8865ff39cea..45e1df5907c 100644 --- a/homeassistant/components/config/config_entries.py +++ b/homeassistant/components/config/config_entries.py @@ -6,6 +6,7 @@ from homeassistant.components.http import HomeAssistantView from homeassistant.exceptions import Unauthorized from homeassistant.helpers.data_entry_flow import ( FlowManagerIndexView, FlowManagerResourceView) +from homeassistant.generated import config_flows async def async_setup(hass): @@ -172,7 +173,7 @@ class ConfigManagerAvailableFlowView(HomeAssistantView): async def get(self, request): """List available flow handlers.""" - return self.json(config_entries.FLOWS) + return self.json(config_flows.FLOWS) class OptionManagerFlowIndexView(FlowManagerIndexView): diff --git a/homeassistant/components/daikin/manifest.json b/homeassistant/components/daikin/manifest.json index ab842950e24..9891cce3b3e 100644 --- a/homeassistant/components/daikin/manifest.json +++ b/homeassistant/components/daikin/manifest.json @@ -1,6 +1,7 @@ { "domain": "daikin", "name": "Daikin", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/daikin", "requirements": [ "pydaikin==1.4.0" diff --git a/homeassistant/components/deconz/manifest.json b/homeassistant/components/deconz/manifest.json index 22947d40fb1..0692bd444b8 100644 --- a/homeassistant/components/deconz/manifest.json +++ b/homeassistant/components/deconz/manifest.json @@ -1,6 +1,7 @@ { "domain": "deconz", "name": "Deconz", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/deconz", "requirements": [ "pydeconz==58" diff --git a/homeassistant/components/dialogflow/__init__.py b/homeassistant/components/dialogflow/__init__.py index a6134d4b19c..3bf11a46098 100644 --- a/homeassistant/components/dialogflow/__init__.py +++ b/homeassistant/components/dialogflow/__init__.py @@ -8,9 +8,10 @@ from homeassistant.const import CONF_WEBHOOK_ID from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import intent, template, config_entry_flow -_LOGGER = logging.getLogger(__name__) +from .const import DOMAIN -DOMAIN = 'dialogflow' + +_LOGGER = logging.getLogger(__name__) SOURCE = "Home Assistant Dialogflow" @@ -83,16 +84,6 @@ async def async_unload_entry(hass, entry): async_remove_entry = config_entry_flow.webhook_async_remove_entry -config_entry_flow.register_webhook_flow( - DOMAIN, - 'Dialogflow Webhook', - { - 'dialogflow_url': 'https://dialogflow.com/docs/fulfillment#webhook', - 'docs_url': 'https://www.home-assistant.io/components/dialogflow/' - } -) - - def dialogflow_error_response(message, error): """Return a response saying the error message.""" dialogflow_response = DialogflowResponse(message['result']['parameters']) diff --git a/homeassistant/components/dialogflow/config_flow.py b/homeassistant/components/dialogflow/config_flow.py new file mode 100644 index 00000000000..aa6f9f6f515 --- /dev/null +++ b/homeassistant/components/dialogflow/config_flow.py @@ -0,0 +1,13 @@ +"""Config flow for DialogFlow.""" +from homeassistant.helpers import config_entry_flow +from .const import DOMAIN + + +config_entry_flow.register_webhook_flow( + DOMAIN, + 'Dialogflow Webhook', + { + 'dialogflow_url': 'https://dialogflow.com/docs/fulfillment#webhook', + 'docs_url': 'https://www.home-assistant.io/components/dialogflow/' + } +) diff --git a/homeassistant/components/dialogflow/const.py b/homeassistant/components/dialogflow/const.py new file mode 100644 index 00000000000..476cb480d94 --- /dev/null +++ b/homeassistant/components/dialogflow/const.py @@ -0,0 +1,3 @@ +"""Const for DialogFlow.""" + +DOMAIN = "dialogflow" diff --git a/homeassistant/components/dialogflow/manifest.json b/homeassistant/components/dialogflow/manifest.json index d136b8a984d..aa8b584aeca 100644 --- a/homeassistant/components/dialogflow/manifest.json +++ b/homeassistant/components/dialogflow/manifest.json @@ -1,6 +1,7 @@ { "domain": "dialogflow", "name": "Dialogflow", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/dialogflow", "requirements": [], "dependencies": [ diff --git a/homeassistant/components/emulated_roku/manifest.json b/homeassistant/components/emulated_roku/manifest.json index 3b8eba396ec..ba68ce94951 100644 --- a/homeassistant/components/emulated_roku/manifest.json +++ b/homeassistant/components/emulated_roku/manifest.json @@ -1,6 +1,7 @@ { "domain": "emulated_roku", "name": "Emulated roku", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/emulated_roku", "requirements": [ "emulated_roku==0.1.8" diff --git a/homeassistant/components/esphome/manifest.json b/homeassistant/components/esphome/manifest.json index 9d25ec6d034..b50d11dbd12 100644 --- a/homeassistant/components/esphome/manifest.json +++ b/homeassistant/components/esphome/manifest.json @@ -1,6 +1,7 @@ { "domain": "esphome", "name": "ESPHome", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/esphome", "requirements": [ "aioesphomeapi==2.0.1" diff --git a/homeassistant/components/geofency/__init__.py b/homeassistant/components/geofency/__init__.py index 0b4b757ce9e..37d32a8860d 100644 --- a/homeassistant/components/geofency/__init__.py +++ b/homeassistant/components/geofency/__init__.py @@ -12,10 +12,11 @@ from homeassistant.helpers import config_entry_flow import homeassistant.helpers.config_validation as cv from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.util import slugify +from .const import DOMAIN + _LOGGER = logging.getLogger(__name__) -DOMAIN = 'geofency' CONF_MOBILE_BEACONS = 'mobile_beacons' CONFIG_SCHEMA = vol.Schema({ @@ -134,12 +135,3 @@ async def async_unload_entry(hass, entry): # pylint: disable=invalid-name async_remove_entry = config_entry_flow.webhook_async_remove_entry - - -config_entry_flow.register_webhook_flow( - DOMAIN, - 'Geofency Webhook', - { - 'docs_url': 'https://www.home-assistant.io/components/geofency/' - } -) diff --git a/homeassistant/components/geofency/config_flow.py b/homeassistant/components/geofency/config_flow.py new file mode 100644 index 00000000000..422343b16bb --- /dev/null +++ b/homeassistant/components/geofency/config_flow.py @@ -0,0 +1,12 @@ +"""Config flow for Geofency.""" +from homeassistant.helpers import config_entry_flow +from .const import DOMAIN + + +config_entry_flow.register_webhook_flow( + DOMAIN, + 'Geofency Webhook', + { + 'docs_url': 'https://www.home-assistant.io/components/geofency/' + } +) diff --git a/homeassistant/components/geofency/const.py b/homeassistant/components/geofency/const.py new file mode 100644 index 00000000000..f42fb97f168 --- /dev/null +++ b/homeassistant/components/geofency/const.py @@ -0,0 +1,3 @@ +"""Const for Geofency.""" + +DOMAIN = 'geofency' diff --git a/homeassistant/components/geofency/manifest.json b/homeassistant/components/geofency/manifest.json index 576d0e419a7..d593aec46a4 100644 --- a/homeassistant/components/geofency/manifest.json +++ b/homeassistant/components/geofency/manifest.json @@ -1,6 +1,7 @@ { "domain": "geofency", "name": "Geofency", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/geofency", "requirements": [], "dependencies": [ diff --git a/homeassistant/components/gpslogger/__init__.py b/homeassistant/components/gpslogger/__init__.py index 6887b85d02d..016de66e9fd 100644 --- a/homeassistant/components/gpslogger/__init__.py +++ b/homeassistant/components/gpslogger/__init__.py @@ -11,10 +11,10 @@ from homeassistant.const import HTTP_UNPROCESSABLE_ENTITY, \ from homeassistant.helpers import config_entry_flow from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.components.device_tracker import DOMAIN as DEVICE_TRACKER +from .const import DOMAIN _LOGGER = logging.getLogger(__name__) -DOMAIN = 'gpslogger' TRACKER_UPDATE = '{}_tracker_update'.format(DOMAIN) ATTR_ALTITUDE = 'altitude' @@ -105,12 +105,3 @@ async def async_unload_entry(hass, entry): # pylint: disable=invalid-name async_remove_entry = config_entry_flow.webhook_async_remove_entry - - -config_entry_flow.register_webhook_flow( - DOMAIN, - 'GPSLogger Webhook', - { - 'docs_url': 'https://www.home-assistant.io/components/gpslogger/' - } -) diff --git a/homeassistant/components/gpslogger/config_flow.py b/homeassistant/components/gpslogger/config_flow.py new file mode 100644 index 00000000000..f48d9abc680 --- /dev/null +++ b/homeassistant/components/gpslogger/config_flow.py @@ -0,0 +1,12 @@ +"""Config flow for GPSLogger.""" +from homeassistant.helpers import config_entry_flow +from .const import DOMAIN + + +config_entry_flow.register_webhook_flow( + DOMAIN, + 'GPSLogger Webhook', + { + 'docs_url': 'https://www.home-assistant.io/components/gpslogger/' + } +) diff --git a/homeassistant/components/gpslogger/const.py b/homeassistant/components/gpslogger/const.py new file mode 100644 index 00000000000..e37c7f0d77b --- /dev/null +++ b/homeassistant/components/gpslogger/const.py @@ -0,0 +1,3 @@ +"""Const for GPSLogger.""" + +DOMAIN = 'gpslogger' diff --git a/homeassistant/components/gpslogger/manifest.json b/homeassistant/components/gpslogger/manifest.json index 2d2166c1bb1..f039e50914b 100644 --- a/homeassistant/components/gpslogger/manifest.json +++ b/homeassistant/components/gpslogger/manifest.json @@ -1,6 +1,7 @@ { "domain": "gpslogger", "name": "Gpslogger", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/gpslogger", "requirements": [], "dependencies": [ diff --git a/homeassistant/components/hangouts/manifest.json b/homeassistant/components/hangouts/manifest.json index 5d9bf3c7612..4a90e9c977e 100644 --- a/homeassistant/components/hangouts/manifest.json +++ b/homeassistant/components/hangouts/manifest.json @@ -1,6 +1,7 @@ { "domain": "hangouts", "name": "Hangouts", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/hangouts", "requirements": [ "hangups==0.4.9" diff --git a/homeassistant/components/heos/manifest.json b/homeassistant/components/heos/manifest.json index f3a2ff4eccf..a1fc8030318 100644 --- a/homeassistant/components/heos/manifest.json +++ b/homeassistant/components/heos/manifest.json @@ -1,6 +1,7 @@ { "domain": "heos", "name": "HEOS", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/heos", "requirements": [ "pyheos==0.5.2" diff --git a/homeassistant/components/homekit_controller/manifest.json b/homeassistant/components/homekit_controller/manifest.json index 53476b8ba6d..8b0dfd199bb 100644 --- a/homeassistant/components/homekit_controller/manifest.json +++ b/homeassistant/components/homekit_controller/manifest.json @@ -1,6 +1,7 @@ { "domain": "homekit_controller", "name": "Homekit controller", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/homekit_controller", "requirements": [ "homekit[IP]==0.14.0" diff --git a/homeassistant/components/homematicip_cloud/manifest.json b/homeassistant/components/homematicip_cloud/manifest.json index 030b4d5b79b..6ba04bfe3c0 100644 --- a/homeassistant/components/homematicip_cloud/manifest.json +++ b/homeassistant/components/homematicip_cloud/manifest.json @@ -1,6 +1,7 @@ { "domain": "homematicip_cloud", "name": "Homematicip cloud", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/homematicip_cloud", "requirements": [ "homematicip==0.10.7" diff --git a/homeassistant/components/hue/manifest.json b/homeassistant/components/hue/manifest.json index 54a3a11a189..d035e4468e4 100644 --- a/homeassistant/components/hue/manifest.json +++ b/homeassistant/components/hue/manifest.json @@ -1,6 +1,7 @@ { "domain": "hue", "name": "Philips Hue", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/hue", "requirements": [ "aiohue==1.9.1" diff --git a/homeassistant/components/ifttt/__init__.py b/homeassistant/components/ifttt/__init__.py index 6b5934702aa..e6926ff0fb5 100644 --- a/homeassistant/components/ifttt/__init__.py +++ b/homeassistant/components/ifttt/__init__.py @@ -8,6 +8,7 @@ import voluptuous as vol from homeassistant.const import CONF_WEBHOOK_ID from homeassistant.helpers import config_entry_flow import homeassistant.helpers.config_validation as cv +from .const import DOMAIN _LOGGER = logging.getLogger(__name__) @@ -21,8 +22,6 @@ ATTR_VALUE3 = 'value3' CONF_KEY = 'key' -DOMAIN = 'ifttt' - SERVICE_TRIGGER = 'trigger' SERVICE_TRIGGER_SCHEMA = vol.Schema({ @@ -108,13 +107,3 @@ async def async_unload_entry(hass, entry): # pylint: disable=invalid-name async_remove_entry = config_entry_flow.webhook_async_remove_entry - - -config_entry_flow.register_webhook_flow( - DOMAIN, - 'IFTTT Webhook', - { - 'applet_url': 'https://ifttt.com/maker_webhooks', - 'docs_url': 'https://www.home-assistant.io/components/ifttt/' - } -) diff --git a/homeassistant/components/ifttt/config_flow.py b/homeassistant/components/ifttt/config_flow.py new file mode 100644 index 00000000000..887a5c88013 --- /dev/null +++ b/homeassistant/components/ifttt/config_flow.py @@ -0,0 +1,13 @@ +"""Config flow for IFTTT.""" +from homeassistant.helpers import config_entry_flow +from .const import DOMAIN + + +config_entry_flow.register_webhook_flow( + DOMAIN, + 'IFTTT Webhook', + { + 'applet_url': 'https://ifttt.com/maker_webhooks', + 'docs_url': 'https://www.home-assistant.io/components/ifttt/' + } +) diff --git a/homeassistant/components/ifttt/const.py b/homeassistant/components/ifttt/const.py new file mode 100644 index 00000000000..03b948fc83a --- /dev/null +++ b/homeassistant/components/ifttt/const.py @@ -0,0 +1,3 @@ +"""Const for IFTTT.""" + +DOMAIN = "ifttt" diff --git a/homeassistant/components/ifttt/manifest.json b/homeassistant/components/ifttt/manifest.json index 007e0870023..58490569e65 100644 --- a/homeassistant/components/ifttt/manifest.json +++ b/homeassistant/components/ifttt/manifest.json @@ -1,6 +1,7 @@ { "domain": "ifttt", "name": "Ifttt", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/ifttt", "requirements": [ "pyfttt==0.3" diff --git a/homeassistant/components/ios/__init__.py b/homeassistant/components/ios/__init__.py index a9395ed5f5d..3fc09781cd7 100644 --- a/homeassistant/components/ios/__init__.py +++ b/homeassistant/components/ios/__init__.py @@ -9,8 +9,7 @@ from homeassistant.components.http import HomeAssistantView from homeassistant.const import HTTP_BAD_REQUEST, HTTP_INTERNAL_SERVER_ERROR from homeassistant.core import callback from homeassistant.exceptions import HomeAssistantError -from homeassistant.helpers import ( - config_entry_flow, config_validation as cv, discovery) +from homeassistant.helpers import config_validation as cv, discovery from homeassistant.util.json import load_json, save_json _LOGGER = logging.getLogger(__name__) @@ -279,8 +278,3 @@ class iOSIdentifyDeviceView(HomeAssistantView): HTTP_INTERNAL_SERVER_ERROR) return self.json({"status": "registered"}) - - -config_entry_flow.register_discovery_flow( - DOMAIN, 'Home Assistant iOS', lambda *_: True, - config_entries.CONN_CLASS_CLOUD_PUSH) diff --git a/homeassistant/components/ios/config_flow.py b/homeassistant/components/ios/config_flow.py new file mode 100644 index 00000000000..c85d5066128 --- /dev/null +++ b/homeassistant/components/ios/config_flow.py @@ -0,0 +1,9 @@ +"""Config flow for iOS.""" +from homeassistant.helpers import config_entry_flow +from homeassistant import config_entries +from .const import DOMAIN + + +config_entry_flow.register_discovery_flow( + DOMAIN, 'Home Assistant iOS', lambda *_: True, + config_entries.CONN_CLASS_CLOUD_PUSH) diff --git a/homeassistant/components/ios/const.py b/homeassistant/components/ios/const.py new file mode 100644 index 00000000000..5fc921b7a44 --- /dev/null +++ b/homeassistant/components/ios/const.py @@ -0,0 +1,3 @@ +"""Const for iOS.""" + +DOMAIN = "ios" diff --git a/homeassistant/components/ios/manifest.json b/homeassistant/components/ios/manifest.json index 97c2e2ae28f..28c9ea1e952 100644 --- a/homeassistant/components/ios/manifest.json +++ b/homeassistant/components/ios/manifest.json @@ -1,6 +1,7 @@ { "domain": "ios", "name": "Ios", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/ios", "requirements": [], "dependencies": [ diff --git a/homeassistant/components/ipma/manifest.json b/homeassistant/components/ipma/manifest.json index 29fc0429e86..093ccbf6a5b 100644 --- a/homeassistant/components/ipma/manifest.json +++ b/homeassistant/components/ipma/manifest.json @@ -1,6 +1,7 @@ { "domain": "ipma", "name": "Ipma", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/ipma", "requirements": [ "pyipma==1.2.1" diff --git a/homeassistant/components/iqvia/manifest.json b/homeassistant/components/iqvia/manifest.json index 1757ffc2a22..a59caa1654c 100644 --- a/homeassistant/components/iqvia/manifest.json +++ b/homeassistant/components/iqvia/manifest.json @@ -1,6 +1,7 @@ { "domain": "iqvia", "name": "IQVIA", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/iqvia", "requirements": [ "numpy==1.16.3", diff --git a/homeassistant/components/lifx/__init__.py b/homeassistant/components/lifx/__init__.py index 849fecad487..ceea489614a 100644 --- a/homeassistant/components/lifx/__init__.py +++ b/homeassistant/components/lifx/__init__.py @@ -4,10 +4,10 @@ import homeassistant.helpers.config_validation as cv from homeassistant import config_entries from homeassistant.const import CONF_PORT -from homeassistant.helpers import config_entry_flow from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN +from .const import DOMAIN + -DOMAIN = 'lifx' CONF_SERVER = 'server' CONF_BROADCAST = 'broadcast' @@ -55,15 +55,3 @@ async def async_unload_entry(hass, entry): await hass.config_entries.async_forward_entry_unload(entry, LIGHT_DOMAIN) return True - - -async def _async_has_devices(hass): - """Return if there are devices that can be discovered.""" - import aiolifx - - lifx_ip_addresses = await aiolifx.LifxScan(hass.loop).scan() - return len(lifx_ip_addresses) > 0 - - -config_entry_flow.register_discovery_flow( - DOMAIN, 'LIFX', _async_has_devices, config_entries.CONN_CLASS_LOCAL_POLL) diff --git a/homeassistant/components/lifx/config_flow.py b/homeassistant/components/lifx/config_flow.py new file mode 100644 index 00000000000..b701c4e4391 --- /dev/null +++ b/homeassistant/components/lifx/config_flow.py @@ -0,0 +1,16 @@ +"""Config flow flow LIFX.""" +from homeassistant.helpers import config_entry_flow +from homeassistant import config_entries +from .const import DOMAIN + + +async def _async_has_devices(hass): + """Return if there are devices that can be discovered.""" + import aiolifx + + lifx_ip_addresses = await aiolifx.LifxScan(hass.loop).scan() + return len(lifx_ip_addresses) > 0 + + +config_entry_flow.register_discovery_flow( + DOMAIN, 'LIFX', _async_has_devices, config_entries.CONN_CLASS_LOCAL_POLL) diff --git a/homeassistant/components/lifx/const.py b/homeassistant/components/lifx/const.py new file mode 100644 index 00000000000..fa54433e58f --- /dev/null +++ b/homeassistant/components/lifx/const.py @@ -0,0 +1,3 @@ +"""Const for LIFX.""" + +DOMAIN = 'lifx' diff --git a/homeassistant/components/lifx/manifest.json b/homeassistant/components/lifx/manifest.json index a8b1fd58afe..ca9b578432b 100644 --- a/homeassistant/components/lifx/manifest.json +++ b/homeassistant/components/lifx/manifest.json @@ -1,6 +1,7 @@ { "domain": "lifx", "name": "Lifx", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/lifx", "requirements": [ "aiolifx==0.6.7", diff --git a/homeassistant/components/locative/__init__.py b/homeassistant/components/locative/__init__.py index f21c55af28a..c44b12c87d2 100644 --- a/homeassistant/components/locative/__init__.py +++ b/homeassistant/components/locative/__init__.py @@ -145,12 +145,3 @@ async def async_unload_entry(hass, entry): # pylint: disable=invalid-name async_remove_entry = config_entry_flow.webhook_async_remove_entry - - -config_entry_flow.register_webhook_flow( - DOMAIN, - 'Locative Webhook', - { - 'docs_url': 'https://www.home-assistant.io/components/locative/' - } -) diff --git a/homeassistant/components/locative/config_flow.py b/homeassistant/components/locative/config_flow.py new file mode 100644 index 00000000000..4a238e95358 --- /dev/null +++ b/homeassistant/components/locative/config_flow.py @@ -0,0 +1,12 @@ +"""Config flow for Locative.""" +from homeassistant.helpers import config_entry_flow +from .const import DOMAIN + + +config_entry_flow.register_webhook_flow( + DOMAIN, + 'Locative Webhook', + { + 'docs_url': 'https://www.home-assistant.io/components/locative/' + } +) diff --git a/homeassistant/components/locative/const.py b/homeassistant/components/locative/const.py new file mode 100644 index 00000000000..4dfaa54de78 --- /dev/null +++ b/homeassistant/components/locative/const.py @@ -0,0 +1,3 @@ +"""Const for Locative.""" + +DOMAIN = "locative" diff --git a/homeassistant/components/locative/manifest.json b/homeassistant/components/locative/manifest.json index afe2850caf8..be2eb07a23c 100644 --- a/homeassistant/components/locative/manifest.json +++ b/homeassistant/components/locative/manifest.json @@ -1,6 +1,7 @@ { "domain": "locative", "name": "Locative", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/locative", "requirements": [], "dependencies": [ diff --git a/homeassistant/components/logi_circle/manifest.json b/homeassistant/components/logi_circle/manifest.json index 8cf6a157a01..b1767748395 100644 --- a/homeassistant/components/logi_circle/manifest.json +++ b/homeassistant/components/logi_circle/manifest.json @@ -1,6 +1,7 @@ { "domain": "logi_circle", "name": "Logi Circle", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/logi_circle", "requirements": ["logi_circle==0.2.2"], "dependencies": ["ffmpeg"], diff --git a/homeassistant/components/luftdaten/manifest.json b/homeassistant/components/luftdaten/manifest.json index 0e6a46a5c5d..d0a3d48b60f 100644 --- a/homeassistant/components/luftdaten/manifest.json +++ b/homeassistant/components/luftdaten/manifest.json @@ -1,6 +1,7 @@ { "domain": "luftdaten", "name": "Luftdaten", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/luftdaten", "requirements": [ "luftdaten==0.3.4" diff --git a/homeassistant/components/mailgun/__init__.py b/homeassistant/components/mailgun/__init__.py index 2f89904f12b..f74d105d98f 100644 --- a/homeassistant/components/mailgun/__init__.py +++ b/homeassistant/components/mailgun/__init__.py @@ -10,12 +10,14 @@ import homeassistant.helpers.config_validation as cv from homeassistant.const import CONF_API_KEY, CONF_DOMAIN, CONF_WEBHOOK_ID from homeassistant.helpers import config_entry_flow +from .const import DOMAIN + + _LOGGER = logging.getLogger(__name__) CONF_SANDBOX = 'sandbox' DEFAULT_SANDBOX = False -DOMAIN = 'mailgun' MESSAGE_RECEIVED = '{}_message_received'.format(DOMAIN) @@ -90,13 +92,3 @@ async def async_unload_entry(hass, entry): # pylint: disable=invalid-name async_remove_entry = config_entry_flow.webhook_async_remove_entry - - -config_entry_flow.register_webhook_flow( - DOMAIN, - 'Mailgun Webhook', - { - 'mailgun_url': 'https://documentation.mailgun.com/en/latest/user_manual.html#webhooks', # noqa: E501 pylint: disable=line-too-long - 'docs_url': 'https://www.home-assistant.io/components/mailgun/' - } -) diff --git a/homeassistant/components/mailgun/config_flow.py b/homeassistant/components/mailgun/config_flow.py new file mode 100644 index 00000000000..aeccd9a506f --- /dev/null +++ b/homeassistant/components/mailgun/config_flow.py @@ -0,0 +1,13 @@ +"""Config flow for Mailgun.""" +from homeassistant.helpers import config_entry_flow +from .const import DOMAIN + + +config_entry_flow.register_webhook_flow( + DOMAIN, + 'Mailgun Webhook', + { + 'mailgun_url': 'https://documentation.mailgun.com/en/latest/user_manual.html#webhooks', # noqa: E501 pylint: disable=line-too-long + 'docs_url': 'https://www.home-assistant.io/components/mailgun/' + } +) diff --git a/homeassistant/components/mailgun/const.py b/homeassistant/components/mailgun/const.py new file mode 100644 index 00000000000..4532c1cbc46 --- /dev/null +++ b/homeassistant/components/mailgun/const.py @@ -0,0 +1,3 @@ +"""Const for Mailgun.""" + +DOMAIN = "mailgun" diff --git a/homeassistant/components/mailgun/manifest.json b/homeassistant/components/mailgun/manifest.json index 2979b391ec2..9ed7a50a8e3 100644 --- a/homeassistant/components/mailgun/manifest.json +++ b/homeassistant/components/mailgun/manifest.json @@ -1,6 +1,7 @@ { "domain": "mailgun", "name": "Mailgun", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/mailgun", "requirements": [ "pymailgunner==1.4" diff --git a/homeassistant/components/mobile_app/__init__.py b/homeassistant/components/mobile_app/__init__.py index 711963a0b24..abb7bcb7628 100644 --- a/homeassistant/components/mobile_app/__init__.py +++ b/homeassistant/components/mobile_app/__init__.py @@ -1,5 +1,4 @@ """Integrates Native Apps to Home Assistant.""" -from homeassistant import config_entries from homeassistant.const import CONF_WEBHOOK_ID from homeassistant.components.webhook import async_register as webhook_register from homeassistant.helpers import device_registry as dr, discovery @@ -91,26 +90,3 @@ async def async_setup_entry(hass, entry): hass.config_entries.async_forward_entry_setup(entry, DATA_SENSOR)) return True - - -@config_entries.HANDLERS.register(DOMAIN) -class MobileAppFlowHandler(config_entries.ConfigFlow): - """Handle a Mobile App config flow.""" - - VERSION = 1 - CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_PUSH - - async def async_step_user(self, user_input=None): - """Handle a flow initialized by the user.""" - placeholders = { - 'apps_url': - 'https://www.home-assistant.io/components/mobile_app/#apps' - } - - return self.async_abort(reason='install_app', - description_placeholders=placeholders) - - async def async_step_registration(self, user_input=None): - """Handle a flow initialized during registration.""" - return self.async_create_entry(title=user_input[ATTR_DEVICE_NAME], - data=user_input) diff --git a/homeassistant/components/mobile_app/config_flow.py b/homeassistant/components/mobile_app/config_flow.py new file mode 100644 index 00000000000..02fea3c6593 --- /dev/null +++ b/homeassistant/components/mobile_app/config_flow.py @@ -0,0 +1,26 @@ +"""Config flow for Mobile App.""" +from homeassistant import config_entries +from .const import DOMAIN, ATTR_DEVICE_NAME + + +@config_entries.HANDLERS.register(DOMAIN) +class MobileAppFlowHandler(config_entries.ConfigFlow): + """Handle a Mobile App config flow.""" + + VERSION = 1 + CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_PUSH + + async def async_step_user(self, user_input=None): + """Handle a flow initialized by the user.""" + placeholders = { + 'apps_url': + 'https://www.home-assistant.io/components/mobile_app/#apps' + } + + return self.async_abort(reason='install_app', + description_placeholders=placeholders) + + async def async_step_registration(self, user_input=None): + """Handle a flow initialized during registration.""" + return self.async_create_entry(title=user_input[ATTR_DEVICE_NAME], + data=user_input) diff --git a/homeassistant/components/mobile_app/manifest.json b/homeassistant/components/mobile_app/manifest.json index 9c21858df1d..969817b62c7 100644 --- a/homeassistant/components/mobile_app/manifest.json +++ b/homeassistant/components/mobile_app/manifest.json @@ -1,6 +1,7 @@ { "domain": "mobile_app", "name": "Home Assistant Mobile App Support", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/mobile_app", "requirements": [ "PyNaCl==1.3.0" diff --git a/homeassistant/components/mqtt/manifest.json b/homeassistant/components/mqtt/manifest.json index dd4d0323a51..d63d1707fac 100644 --- a/homeassistant/components/mqtt/manifest.json +++ b/homeassistant/components/mqtt/manifest.json @@ -1,6 +1,7 @@ { "domain": "mqtt", "name": "MQTT", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/mqtt", "requirements": [ "hbmqtt==0.9.4", diff --git a/homeassistant/components/nest/manifest.json b/homeassistant/components/nest/manifest.json index 9f2e4202f93..8a6e8ec611a 100644 --- a/homeassistant/components/nest/manifest.json +++ b/homeassistant/components/nest/manifest.json @@ -1,6 +1,7 @@ { "domain": "nest", "name": "Nest", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/nest", "requirements": [ "python-nest==4.1.0" diff --git a/homeassistant/components/openuv/manifest.json b/homeassistant/components/openuv/manifest.json index b94a409aa71..0cfb02e81d6 100644 --- a/homeassistant/components/openuv/manifest.json +++ b/homeassistant/components/openuv/manifest.json @@ -1,6 +1,7 @@ { "domain": "openuv", "name": "Openuv", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/openuv", "requirements": [ "pyopenuv==1.0.9" diff --git a/homeassistant/components/owntracks/manifest.json b/homeassistant/components/owntracks/manifest.json index 60bce1bca3d..bc4fe97bc7f 100644 --- a/homeassistant/components/owntracks/manifest.json +++ b/homeassistant/components/owntracks/manifest.json @@ -1,6 +1,7 @@ { "domain": "owntracks", "name": "Owntracks", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/owntracks", "requirements": [ "PyNaCl==1.3.0" diff --git a/homeassistant/components/point/manifest.json b/homeassistant/components/point/manifest.json index 8b888a3647a..fcc9265ce9b 100644 --- a/homeassistant/components/point/manifest.json +++ b/homeassistant/components/point/manifest.json @@ -1,6 +1,7 @@ { "domain": "point", "name": "Point", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/point", "requirements": [ "pypoint==1.1.1" diff --git a/homeassistant/components/ps4/manifest.json b/homeassistant/components/ps4/manifest.json index 087f1618378..1cf613bf9b9 100644 --- a/homeassistant/components/ps4/manifest.json +++ b/homeassistant/components/ps4/manifest.json @@ -1,6 +1,7 @@ { "domain": "ps4", "name": "Ps4", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/ps4", "requirements": [ "pyps4-homeassistant==0.7.3" diff --git a/homeassistant/components/rainmachine/manifest.json b/homeassistant/components/rainmachine/manifest.json index ad7bdada321..b99798bb4b6 100644 --- a/homeassistant/components/rainmachine/manifest.json +++ b/homeassistant/components/rainmachine/manifest.json @@ -1,6 +1,7 @@ { "domain": "rainmachine", "name": "Rainmachine", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/rainmachine", "requirements": [ "regenmaschine==1.4.0" diff --git a/homeassistant/components/simplisafe/manifest.json b/homeassistant/components/simplisafe/manifest.json index eac586b355d..b6bb1285daa 100644 --- a/homeassistant/components/simplisafe/manifest.json +++ b/homeassistant/components/simplisafe/manifest.json @@ -1,6 +1,7 @@ { "domain": "simplisafe", "name": "Simplisafe", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/simplisafe", "requirements": [ "simplisafe-python==3.4.1" diff --git a/homeassistant/components/smartthings/manifest.json b/homeassistant/components/smartthings/manifest.json index d31a90c6eb8..75b113354ff 100644 --- a/homeassistant/components/smartthings/manifest.json +++ b/homeassistant/components/smartthings/manifest.json @@ -1,6 +1,7 @@ { "domain": "smartthings", "name": "Smartthings", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/smartthings", "requirements": [ "pysmartapp==0.3.2", diff --git a/homeassistant/components/smhi/manifest.json b/homeassistant/components/smhi/manifest.json index e4ad478e033..421eadca51c 100644 --- a/homeassistant/components/smhi/manifest.json +++ b/homeassistant/components/smhi/manifest.json @@ -1,6 +1,7 @@ { "domain": "smhi", "name": "Smhi", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/smhi", "requirements": [ "smhi-pkg==1.0.10" diff --git a/homeassistant/components/sonos/__init__.py b/homeassistant/components/sonos/__init__.py index 5f7b2d04431..4d3df055bbf 100644 --- a/homeassistant/components/sonos/__init__.py +++ b/homeassistant/components/sonos/__init__.py @@ -5,10 +5,11 @@ import voluptuous as vol from homeassistant import config_entries from homeassistant.components.media_player import DOMAIN as MP_DOMAIN from homeassistant.const import CONF_HOSTS, ATTR_ENTITY_ID, ATTR_TIME -from homeassistant.helpers import config_entry_flow, config_validation as cv +from homeassistant.helpers import config_validation as cv from homeassistant.helpers.dispatcher import async_dispatcher_send -DOMAIN = 'sonos' +from .const import DOMAIN + CONF_ADVERTISE_ADDR = 'advertise_addr' CONF_INTERFACE_ADDR = 'interface_addr' @@ -141,14 +142,3 @@ async def async_setup_entry(hass, entry): hass.async_create_task(hass.config_entries.async_forward_entry_setup( entry, MP_DOMAIN)) return True - - -async def _async_has_devices(hass): - """Return if there are devices that can be discovered.""" - import pysonos - - return await hass.async_add_executor_job(pysonos.discover) - - -config_entry_flow.register_discovery_flow( - DOMAIN, 'Sonos', _async_has_devices, config_entries.CONN_CLASS_LOCAL_PUSH) diff --git a/homeassistant/components/sonos/config_flow.py b/homeassistant/components/sonos/config_flow.py new file mode 100644 index 00000000000..ca3932a76c2 --- /dev/null +++ b/homeassistant/components/sonos/config_flow.py @@ -0,0 +1,15 @@ +"""Config flow for SONOS.""" +from homeassistant.helpers import config_entry_flow +from homeassistant import config_entries +from .const import DOMAIN + + +async def _async_has_devices(hass): + """Return if there are devices that can be discovered.""" + import pysonos + + return await hass.async_add_executor_job(pysonos.discover) + + +config_entry_flow.register_discovery_flow( + DOMAIN, 'Sonos', _async_has_devices, config_entries.CONN_CLASS_LOCAL_PUSH) diff --git a/homeassistant/components/sonos/const.py b/homeassistant/components/sonos/const.py new file mode 100644 index 00000000000..5858f2bca9b --- /dev/null +++ b/homeassistant/components/sonos/const.py @@ -0,0 +1,3 @@ +"""Const for Sonos.""" + +DOMAIN = "sonos" diff --git a/homeassistant/components/sonos/manifest.json b/homeassistant/components/sonos/manifest.json index 5eac580313e..58fa7b49f88 100644 --- a/homeassistant/components/sonos/manifest.json +++ b/homeassistant/components/sonos/manifest.json @@ -1,6 +1,7 @@ { "domain": "sonos", "name": "Sonos", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/sonos", "requirements": [ "pysonos==0.0.12" diff --git a/homeassistant/components/tellduslive/manifest.json b/homeassistant/components/tellduslive/manifest.json index 2e6233f426c..7f431ba92b1 100644 --- a/homeassistant/components/tellduslive/manifest.json +++ b/homeassistant/components/tellduslive/manifest.json @@ -1,6 +1,7 @@ { "domain": "tellduslive", "name": "Tellduslive", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/tellduslive", "requirements": [ "tellduslive==0.10.10" diff --git a/homeassistant/components/toon/manifest.json b/homeassistant/components/toon/manifest.json index 7dbf6768db6..eccaf7df9bc 100644 --- a/homeassistant/components/toon/manifest.json +++ b/homeassistant/components/toon/manifest.json @@ -1,6 +1,7 @@ { "domain": "toon", "name": "Toon", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/toon", "requirements": [ "toonapilib==3.2.2" diff --git a/homeassistant/components/tplink/__init__.py b/homeassistant/components/tplink/__init__.py index 2ebf342c38d..4173c1aaa60 100644 --- a/homeassistant/components/tplink/__init__.py +++ b/homeassistant/components/tplink/__init__.py @@ -5,14 +5,12 @@ import voluptuous as vol from homeassistant.const import CONF_HOST from homeassistant import config_entries -from homeassistant.helpers import config_entry_flow import homeassistant.helpers.config_validation as cv - +from .config_flow import async_get_devices +from .const import DOMAIN _LOGGER = logging.getLogger(__name__) -DOMAIN = 'tplink' - TPLINK_HOST_SCHEMA = vol.Schema({ vol.Required(CONF_HOST): cv.string }) @@ -34,16 +32,6 @@ CONFIG_SCHEMA = vol.Schema({ }, extra=vol.ALLOW_EXTRA) -async def _async_has_devices(hass): - """Return if there are devices that can be discovered.""" - from pyHS100 import Discover - - def discover(): - devs = Discover.discover() - return devs - return await hass.async_add_executor_job(discover) - - async def async_setup(hass, config): """Set up the TP-Link component.""" conf = config.get(DOMAIN) @@ -74,7 +62,7 @@ async def async_setup_entry(hass, config_entry): # If initialized from configure integrations, there's no config # so we default here to True if config_data is None or config_data[CONF_DISCOVERY]: - devs = await _async_has_devices(hass) + devs = await async_get_devices(hass) _LOGGER.info("Discovered %s TP-Link smart home device(s)", len(devs)) devices.update(devs) @@ -149,9 +137,3 @@ async def async_unload_entry(hass, entry): # We were not able to unload the platforms, either because there # were none or one of the forward_unloads failed. return False - - -config_entry_flow.register_discovery_flow(DOMAIN, - 'TP-Link Smart Home', - _async_has_devices, - config_entries.CONN_CLASS_LOCAL_POLL) diff --git a/homeassistant/components/tplink/config_flow.py b/homeassistant/components/tplink/config_flow.py new file mode 100644 index 00000000000..86b1acf4ff1 --- /dev/null +++ b/homeassistant/components/tplink/config_flow.py @@ -0,0 +1,20 @@ +"""Config flow for TP-Link.""" +from homeassistant.helpers import config_entry_flow +from homeassistant import config_entries +from .const import DOMAIN + + +async def async_get_devices(hass): + """Return if there are devices that can be discovered.""" + from pyHS100 import Discover + + def discover(): + devs = Discover.discover() + return devs + return await hass.async_add_executor_job(discover) + + +config_entry_flow.register_discovery_flow(DOMAIN, + 'TP-Link Smart Home', + async_get_devices, + config_entries.CONN_CLASS_LOCAL_POLL) diff --git a/homeassistant/components/tplink/const.py b/homeassistant/components/tplink/const.py new file mode 100644 index 00000000000..583c25e285c --- /dev/null +++ b/homeassistant/components/tplink/const.py @@ -0,0 +1,3 @@ +"""Const for TP-Link.""" + +DOMAIN = "tplink" diff --git a/homeassistant/components/tplink/manifest.json b/homeassistant/components/tplink/manifest.json index d164a526fc0..e0f85757afd 100644 --- a/homeassistant/components/tplink/manifest.json +++ b/homeassistant/components/tplink/manifest.json @@ -1,6 +1,7 @@ { "domain": "tplink", "name": "Tplink", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/tplink", "requirements": [ "pyHS100==0.3.5", diff --git a/homeassistant/components/tradfri/manifest.json b/homeassistant/components/tradfri/manifest.json index 19e8348e987..c9a4fca3dc9 100644 --- a/homeassistant/components/tradfri/manifest.json +++ b/homeassistant/components/tradfri/manifest.json @@ -1,6 +1,7 @@ { "domain": "tradfri", "name": "Tradfri", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/tradfri", "requirements": [ "pytradfri[async]==6.0.1" diff --git a/homeassistant/components/twilio/__init__.py b/homeassistant/components/twilio/__init__.py index 82011f499ba..8a1babaf1eb 100644 --- a/homeassistant/components/twilio/__init__.py +++ b/homeassistant/components/twilio/__init__.py @@ -4,8 +4,7 @@ import voluptuous as vol import homeassistant.helpers.config_validation as cv from homeassistant.const import CONF_WEBHOOK_ID from homeassistant.helpers import config_entry_flow - -DOMAIN = 'twilio' +from .const import DOMAIN CONF_ACCOUNT_SID = 'account_sid' CONF_AUTH_TOKEN = 'auth_token' @@ -60,14 +59,3 @@ async def async_unload_entry(hass, entry): # pylint: disable=invalid-name async_remove_entry = config_entry_flow.webhook_async_remove_entry - - -config_entry_flow.register_webhook_flow( - DOMAIN, - 'Twilio Webhook', - { - 'twilio_url': - 'https://www.twilio.com/docs/glossary/what-is-a-webhook', - 'docs_url': 'https://www.home-assistant.io/components/twilio/' - } -) diff --git a/homeassistant/components/twilio/config_flow.py b/homeassistant/components/twilio/config_flow.py new file mode 100644 index 00000000000..686b6391b05 --- /dev/null +++ b/homeassistant/components/twilio/config_flow.py @@ -0,0 +1,15 @@ +"""Config flow for Twilio.""" +from homeassistant.helpers import config_entry_flow + +from .const import DOMAIN + + +config_entry_flow.register_webhook_flow( + DOMAIN, + 'Twilio Webhook', + { + 'twilio_url': + 'https://www.twilio.com/docs/glossary/what-is-a-webhook', + 'docs_url': 'https://www.home-assistant.io/components/twilio/' + } +) diff --git a/homeassistant/components/twilio/const.py b/homeassistant/components/twilio/const.py new file mode 100644 index 00000000000..7ca44590d6a --- /dev/null +++ b/homeassistant/components/twilio/const.py @@ -0,0 +1,3 @@ +"""Const for Twilio.""" + +DOMAIN = "twilio" diff --git a/homeassistant/components/twilio/manifest.json b/homeassistant/components/twilio/manifest.json index dfb7dd4b14d..f96afa18115 100644 --- a/homeassistant/components/twilio/manifest.json +++ b/homeassistant/components/twilio/manifest.json @@ -1,6 +1,7 @@ { "domain": "twilio", "name": "Twilio", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/twilio", "requirements": [ "twilio==6.19.1" diff --git a/homeassistant/components/unifi/__init__.py b/homeassistant/components/unifi/__init__.py index 3af450acdbf..33b687bd178 100644 --- a/homeassistant/components/unifi/__init__.py +++ b/homeassistant/components/unifi/__init__.py @@ -1,20 +1,9 @@ """Support for devices connected to UniFi POE.""" -import voluptuous as vol - -from homeassistant import config_entries -from homeassistant.const import ( - CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_USERNAME, CONF_VERIFY_SSL) +from homeassistant.const import CONF_HOST from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC -from .const import (CONF_CONTROLLER, CONF_POE_CONTROL, CONF_SITE_ID, - CONTROLLER_ID, DOMAIN, LOGGER) -from .controller import UniFiController, get_controller -from .errors import ( - AlreadyConfigured, AuthenticationRequired, CannotConnect, UserLevel) - -DEFAULT_PORT = 8443 -DEFAULT_SITE_ID = 'default' -DEFAULT_VERIFY_SSL = False +from .const import CONF_CONTROLLER, CONF_SITE_ID, CONTROLLER_ID, DOMAIN +from .controller import UniFiController async def async_setup(hass, config): @@ -64,116 +53,3 @@ async def async_unload_entry(hass, config_entry): ) controller = hass.data[DOMAIN].pop(controller_id) return await controller.async_reset() - - -@config_entries.HANDLERS.register(DOMAIN) -class UnifiFlowHandler(config_entries.ConfigFlow): - """Handle a UniFi config flow.""" - - VERSION = 1 - CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL - - def __init__(self): - """Initialize the UniFi flow.""" - self.config = None - self.desc = None - self.sites = None - - async def async_step_user(self, user_input=None): - """Handle a flow initialized by the user.""" - errors = {} - - if user_input is not None: - - try: - self.config = { - CONF_HOST: user_input[CONF_HOST], - CONF_USERNAME: user_input[CONF_USERNAME], - CONF_PASSWORD: user_input[CONF_PASSWORD], - CONF_PORT: user_input.get(CONF_PORT), - CONF_VERIFY_SSL: user_input.get(CONF_VERIFY_SSL), - CONF_SITE_ID: DEFAULT_SITE_ID, - } - controller = await get_controller(self.hass, **self.config) - - self.sites = await controller.sites() - - return await self.async_step_site() - - except AuthenticationRequired: - errors['base'] = 'faulty_credentials' - - except CannotConnect: - errors['base'] = 'service_unavailable' - - except Exception: # pylint: disable=broad-except - LOGGER.error( - 'Unknown error connecting with UniFi Controller at %s', - user_input[CONF_HOST]) - return self.async_abort(reason='unknown') - - return self.async_show_form( - step_id='user', - data_schema=vol.Schema({ - vol.Required(CONF_HOST): str, - vol.Required(CONF_USERNAME): str, - vol.Required(CONF_PASSWORD): str, - vol.Optional(CONF_PORT, default=DEFAULT_PORT): int, - vol.Optional( - CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL): bool, - }), - errors=errors, - ) - - async def async_step_site(self, user_input=None): - """Select site to control.""" - errors = {} - - if user_input is not None: - - try: - desc = user_input.get(CONF_SITE_ID, self.desc) - for site in self.sites.values(): - if desc == site['desc']: - if site['role'] != 'admin': - raise UserLevel - self.config[CONF_SITE_ID] = site['name'] - break - - for entry in self._async_current_entries(): - controller = entry.data[CONF_CONTROLLER] - if controller[CONF_HOST] == self.config[CONF_HOST] and \ - controller[CONF_SITE_ID] == self.config[CONF_SITE_ID]: - raise AlreadyConfigured - - data = { - CONF_CONTROLLER: self.config, - CONF_POE_CONTROL: True - } - - return self.async_create_entry( - title=desc, - data=data - ) - - except AlreadyConfigured: - return self.async_abort(reason='already_configured') - - except UserLevel: - return self.async_abort(reason='user_privilege') - - if len(self.sites) == 1: - self.desc = next(iter(self.sites.values()))['desc'] - return await self.async_step_site(user_input={}) - - sites = [] - for site in self.sites.values(): - sites.append(site['desc']) - - return self.async_show_form( - step_id='site', - data_schema=vol.Schema({ - vol.Required(CONF_SITE_ID): vol.In(sites) - }), - errors=errors, - ) diff --git a/homeassistant/components/unifi/config_flow.py b/homeassistant/components/unifi/config_flow.py new file mode 100644 index 00000000000..b784aaa705a --- /dev/null +++ b/homeassistant/components/unifi/config_flow.py @@ -0,0 +1,130 @@ +"""Config flow for Unifi.""" +import voluptuous as vol + +from homeassistant import config_entries +from homeassistant.const import ( + CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_USERNAME, CONF_VERIFY_SSL) + +from .const import (CONF_CONTROLLER, CONF_POE_CONTROL, CONF_SITE_ID, + DOMAIN, LOGGER) +from .controller import get_controller +from .errors import ( + AlreadyConfigured, AuthenticationRequired, CannotConnect, UserLevel) + + +DEFAULT_PORT = 8443 +DEFAULT_SITE_ID = 'default' +DEFAULT_VERIFY_SSL = False + + +@config_entries.HANDLERS.register(DOMAIN) +class UnifiFlowHandler(config_entries.ConfigFlow): + """Handle a UniFi config flow.""" + + VERSION = 1 + CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL + + def __init__(self): + """Initialize the UniFi flow.""" + self.config = None + self.desc = None + self.sites = None + + async def async_step_user(self, user_input=None): + """Handle a flow initialized by the user.""" + errors = {} + + if user_input is not None: + + try: + self.config = { + CONF_HOST: user_input[CONF_HOST], + CONF_USERNAME: user_input[CONF_USERNAME], + CONF_PASSWORD: user_input[CONF_PASSWORD], + CONF_PORT: user_input.get(CONF_PORT), + CONF_VERIFY_SSL: user_input.get(CONF_VERIFY_SSL), + CONF_SITE_ID: DEFAULT_SITE_ID, + } + controller = await get_controller(self.hass, **self.config) + + self.sites = await controller.sites() + + return await self.async_step_site() + + except AuthenticationRequired: + errors['base'] = 'faulty_credentials' + + except CannotConnect: + errors['base'] = 'service_unavailable' + + except Exception: # pylint: disable=broad-except + LOGGER.error( + 'Unknown error connecting with UniFi Controller at %s', + user_input[CONF_HOST]) + return self.async_abort(reason='unknown') + + return self.async_show_form( + step_id='user', + data_schema=vol.Schema({ + vol.Required(CONF_HOST): str, + vol.Required(CONF_USERNAME): str, + vol.Required(CONF_PASSWORD): str, + vol.Optional(CONF_PORT, default=DEFAULT_PORT): int, + vol.Optional( + CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL): bool, + }), + errors=errors, + ) + + async def async_step_site(self, user_input=None): + """Select site to control.""" + errors = {} + + if user_input is not None: + + try: + desc = user_input.get(CONF_SITE_ID, self.desc) + for site in self.sites.values(): + if desc == site['desc']: + if site['role'] != 'admin': + raise UserLevel + self.config[CONF_SITE_ID] = site['name'] + break + + for entry in self._async_current_entries(): + controller = entry.data[CONF_CONTROLLER] + if controller[CONF_HOST] == self.config[CONF_HOST] and \ + controller[CONF_SITE_ID] == self.config[CONF_SITE_ID]: + raise AlreadyConfigured + + data = { + CONF_CONTROLLER: self.config, + CONF_POE_CONTROL: True + } + + return self.async_create_entry( + title=desc, + data=data + ) + + except AlreadyConfigured: + return self.async_abort(reason='already_configured') + + except UserLevel: + return self.async_abort(reason='user_privilege') + + if len(self.sites) == 1: + self.desc = next(iter(self.sites.values()))['desc'] + return await self.async_step_site(user_input={}) + + sites = [] + for site in self.sites.values(): + sites.append(site['desc']) + + return self.async_show_form( + step_id='site', + data_schema=vol.Schema({ + vol.Required(CONF_SITE_ID): vol.In(sites) + }), + errors=errors, + ) diff --git a/homeassistant/components/unifi/manifest.json b/homeassistant/components/unifi/manifest.json index 85a84539663..22ece5addaf 100644 --- a/homeassistant/components/unifi/manifest.json +++ b/homeassistant/components/unifi/manifest.json @@ -1,6 +1,7 @@ { "domain": "unifi", "name": "Unifi", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/unifi", "requirements": [ "aiounifi==4", diff --git a/homeassistant/components/upnp/__init__.py b/homeassistant/components/upnp/__init__.py index fd2aa994ca4..219167366a5 100644 --- a/homeassistant/components/upnp/__init__.py +++ b/homeassistant/components/upnp/__init__.py @@ -7,7 +7,6 @@ import voluptuous as vol from homeassistant import config_entries from homeassistant.config_entries import ConfigEntry from homeassistant.const import EVENT_HOMEASSISTANT_STOP -from homeassistant.helpers import config_entry_flow from homeassistant.helpers import config_validation as cv from homeassistant.helpers import device_registry as dr from homeassistant.helpers import dispatcher @@ -204,10 +203,3 @@ async def async_unload_entry(hass: HomeAssistantType, dispatcher.async_dispatcher_send(hass, SIGNAL_REMOVE_SENSOR, device) return True - - -config_entry_flow.register_discovery_flow( - DOMAIN, - 'UPnP/IGD', - Device.async_discover, - config_entries.CONN_CLASS_LOCAL_POLL) diff --git a/homeassistant/components/upnp/config_flow.py b/homeassistant/components/upnp/config_flow.py new file mode 100644 index 00000000000..65a91858b57 --- /dev/null +++ b/homeassistant/components/upnp/config_flow.py @@ -0,0 +1,13 @@ +"""Config flow for UPNP.""" +from homeassistant.helpers import config_entry_flow +from homeassistant import config_entries + +from .const import DOMAIN +from .device import Device + + +config_entry_flow.register_discovery_flow( + DOMAIN, + 'UPnP/IGD', + Device.async_discover, + config_entries.CONN_CLASS_LOCAL_POLL) diff --git a/homeassistant/components/upnp/manifest.json b/homeassistant/components/upnp/manifest.json index 75213ecc9b9..4a189dc6dd1 100644 --- a/homeassistant/components/upnp/manifest.json +++ b/homeassistant/components/upnp/manifest.json @@ -1,6 +1,7 @@ { "domain": "upnp", "name": "Upnp", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/upnp", "requirements": [ "async-upnp-client==0.14.7" diff --git a/homeassistant/components/zha/manifest.json b/homeassistant/components/zha/manifest.json index a8b459e9e96..a44550100f9 100644 --- a/homeassistant/components/zha/manifest.json +++ b/homeassistant/components/zha/manifest.json @@ -1,6 +1,7 @@ { "domain": "zha", "name": "Zigbee Home Automation", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/zha", "requirements": [ "bellows-homeassistant==0.7.3", diff --git a/homeassistant/components/zone/manifest.json b/homeassistant/components/zone/manifest.json index 897908b61da..e9281fec3f7 100644 --- a/homeassistant/components/zone/manifest.json +++ b/homeassistant/components/zone/manifest.json @@ -1,6 +1,7 @@ { "domain": "zone", "name": "Zone", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/zone", "requirements": [], "dependencies": [], diff --git a/homeassistant/components/zwave/manifest.json b/homeassistant/components/zwave/manifest.json index 598af58ad17..f88945fa281 100644 --- a/homeassistant/components/zwave/manifest.json +++ b/homeassistant/components/zwave/manifest.json @@ -1,6 +1,7 @@ { "domain": "zwave", "name": "Z-Wave", + "config_flow": true, "documentation": "https://www.home-assistant.io/components/zwave", "requirements": [ "homeassistant-pyozw==0.1.4", diff --git a/homeassistant/config_entries.py b/homeassistant/config_entries.py index 6f4e57203f1..e96c10e17fa 100644 --- a/homeassistant/config_entries.py +++ b/homeassistant/config_entries.py @@ -140,57 +140,6 @@ SOURCE_DISCOVERY = 'discovery' SOURCE_IMPORT = 'import' HANDLERS = Registry() -# Components that have config flows. In future we will auto-generate this list. -FLOWS = [ - 'ambiclimate', - 'ambient_station', - 'axis', - 'cast', - 'daikin', - 'deconz', - 'dialogflow', - 'esphome', - 'emulated_roku', - 'geofency', - 'gpslogger', - 'hangouts', - 'heos', - 'homekit_controller', - 'homematicip_cloud', - 'hue', - 'ifttt', - 'ios', - 'ipma', - 'iqvia', - 'lifx', - 'locative', - 'logi_circle', - 'luftdaten', - 'mailgun', - 'mobile_app', - 'mqtt', - 'nest', - 'openuv', - 'owntracks', - 'point', - 'ps4', - 'rainmachine', - 'simplisafe', - 'smartthings', - 'smhi', - 'sonos', - 'tellduslive', - 'toon', - 'tplink', - 'tradfri', - 'twilio', - 'unifi', - 'upnp', - 'zha', - 'zone', - 'zwave', -] - STORAGE_KEY = 'core.config_entries' STORAGE_VERSION = 1 @@ -299,7 +248,17 @@ class ConfigEntry: if integration is None: integration = await loader.async_get_integration(hass, self.domain) - component = integration.get_component() + try: + component = integration.get_component() + if self.domain == integration.domain: + integration.get_platform('config_flow') + except ImportError as err: + _LOGGER.error( + 'Error importing integration %s to set up %s config entry: %s', + integration.domain, self.domain, err) + if self.domain == integration.domain: + self.state = ENTRY_STATE_SETUP_ERROR + return # Perform migration if integration.domain == self.domain: @@ -422,7 +381,8 @@ class ConfigEntry: if self.version == handler.VERSION: return True - component = getattr(hass.components, self.domain) + integration = await loader.async_get_integration(hass, self.domain) + component = integration.get_component() supports_migrate = hasattr(component, 'async_migrate_entry') if not supports_migrate: _LOGGER.error("Migration handler not found for entry %s for %s", @@ -430,7 +390,9 @@ class ConfigEntry: return False try: - result = await component.async_migrate_entry(hass, self) + result = await component.async_migrate_entry( # type: ignore + hass, self + ) if not isinstance(result, bool): _LOGGER.error('%s.async_migrate_entry did not return boolean', self.domain) @@ -441,7 +403,7 @@ class ConfigEntry: return result except Exception: # pylint: disable=broad-except _LOGGER.exception('Error migrating entry %s for %s', - self.title, component.DOMAIN) + self.title, self.domain) return False def add_update_listener(self, listener: Callable) -> Callable: @@ -714,10 +676,10 @@ class ConfigEntries: self.hass, self._hass_config, integration) try: - integration.get_component() + integration.get_platform('config_flow') except ImportError as err: _LOGGER.error( - 'Error occurred while loading integration %s: %s', + 'Error occurred loading config flow for integration %s: %s', handler_key, err) raise data_entry_flow.UnknownHandler diff --git a/homeassistant/generated/config_flows.py b/homeassistant/generated/config_flows.py new file mode 100644 index 00000000000..c9a8c593b27 --- /dev/null +++ b/homeassistant/generated/config_flows.py @@ -0,0 +1,55 @@ +"""Automatically generated by hassfest. + +To update, run python3 -m hassfest +""" + + +FLOWS = [ + "ambiclimate", + "ambient_station", + "axis", + "cast", + "daikin", + "deconz", + "dialogflow", + "emulated_roku", + "esphome", + "geofency", + "gpslogger", + "hangouts", + "heos", + "homekit_controller", + "homematicip_cloud", + "hue", + "ifttt", + "ios", + "ipma", + "iqvia", + "lifx", + "locative", + "logi_circle", + "luftdaten", + "mailgun", + "mobile_app", + "mqtt", + "nest", + "openuv", + "owntracks", + "point", + "ps4", + "rainmachine", + "simplisafe", + "smartthings", + "smhi", + "sonos", + "tellduslive", + "toon", + "tplink", + "tradfri", + "twilio", + "unifi", + "upnp", + "zha", + "zone", + "zwave" +] diff --git a/homeassistant/helpers/translation.py b/homeassistant/helpers/translation.py index 4f655e692f7..f008551c0fa 100644 --- a/homeassistant/helpers/translation.py +++ b/homeassistant/helpers/translation.py @@ -2,9 +2,9 @@ import logging from typing import Any, Dict, Iterable, Optional -from homeassistant import config_entries from homeassistant.loader import async_get_integration, bind_hass from homeassistant.util.json import load_json +from homeassistant.generated import config_flows from .typing import HomeAssistantType _LOGGER = logging.getLogger(__name__) @@ -106,7 +106,7 @@ async def async_get_component_resources(hass: HomeAssistantType, translation_cache = hass.data[TRANSLATION_STRING_CACHE][language] # Get the set of components - components = hass.config.components | set(config_entries.FLOWS) + components = hass.config.components | set(config_flows.FLOWS) # Calculate the missing components missing_components = components - set(translation_cache) diff --git a/pylintrc b/pylintrc index 7d349033f70..1ba0bf2c82a 100644 --- a/pylintrc +++ b/pylintrc @@ -1,3 +1,9 @@ +[MASTER] +ignore=tests + +[BASIC] +good-names=i,j,k,ex,Run,_,fp + [MESSAGES CONTROL] # Reasons disabled: # locally-disabled - it spams too much diff --git a/script/hassfest/__main__.py b/script/hassfest/__main__.py index bca419126db..9e7797201ea 100644 --- a/script/hassfest/__main__.py +++ b/script/hassfest/__main__.py @@ -3,13 +3,14 @@ import pathlib import sys from .model import Integration, Config -from . import dependencies, manifest, codeowners, services +from . import dependencies, manifest, codeowners, services, config_flow PLUGINS = [ manifest, dependencies, codeowners, services, + config_flow, ] diff --git a/script/hassfest/config_flow.py b/script/hassfest/config_flow.py new file mode 100644 index 00000000000..2f204227f25 --- /dev/null +++ b/script/hassfest/config_flow.py @@ -0,0 +1,85 @@ +"""Generate config flow file.""" +import json +from typing import Dict + +from .model import Integration, Config + +BASE = """ +\"\"\"Automatically generated by hassfest. + +To update, run python3 -m hassfest +\"\"\" + + +FLOWS = {} +""".strip() + + +def validate_integration(integration: Integration): + """Validate we can load config flow without installing requirements.""" + if not (integration.path / "config_flow.py").is_file(): + integration.add_error( + 'config_flow', + "Config flows need to be defined in the file config_flow.py") + + # Currently not require being able to load config flow without + # installing requirements. + # try: + # integration.import_pkg('config_flow') + # except ImportError as err: + # integration.add_error( + # 'config_flow', + # "Unable to import config flow: {}. Config flows should be able " + # "to be imported without installing requirements.".format(err)) + # return + + # if integration.domain not in config_entries.HANDLERS: + # integration.add_error( + # 'config_flow', + # "Importing the config flow platform did not register a config " + # "flow handler.") + + +def generate_and_validate(integrations: Dict[str, Integration]): + """Validate and generate config flow data.""" + domains = [] + + for domain in sorted(integrations): + integration = integrations[domain] + + if not integration.manifest: + continue + + config_flow = integration.manifest.get('config_flow') + + if not config_flow: + continue + + validate_integration(integration) + + domains.append(domain) + + return BASE.format(json.dumps(domains, indent=4)) + + +def validate(integrations: Dict[str, Integration], config: Config): + """Validate config flow file.""" + config_flow_path = config.root / 'homeassistant/generated/config_flows.py' + config.cache['config_flow'] = content = generate_and_validate(integrations) + + with open(str(config_flow_path), 'r') as fp: + if fp.read().strip() != content: + config.add_error( + "config_flow", + "File config_flows.py is not up to date. " + "Run python3 -m script.hassfest", + fixable=True + ) + return + + +def generate(integrations: Dict[str, Integration], config: Config): + """Generate config flow file.""" + config_flow_path = config.root / 'homeassistant/generated/config_flows.py' + with open(str(config_flow_path), 'w') as fp: + fp.write(config.cache['config_flow'] + '\n') diff --git a/script/hassfest/manifest.py b/script/hassfest/manifest.py index 30f89231299..789b5fc0b41 100644 --- a/script/hassfest/manifest.py +++ b/script/hassfest/manifest.py @@ -10,6 +10,7 @@ from .model import Integration MANIFEST_SCHEMA = vol.Schema({ vol.Required('domain'): str, vol.Required('name'): str, + vol.Optional('config_flow'): bool, vol.Required('documentation'): str, vol.Required('requirements'): [str], vol.Required('dependencies'): [str], diff --git a/script/hassfest/model.py b/script/hassfest/model.py index de252715992..4815522cf94 100644 --- a/script/hassfest/model.py +++ b/script/hassfest/model.py @@ -2,6 +2,7 @@ import json from typing import List, Dict, Any import pathlib +import importlib import attr @@ -92,3 +93,10 @@ class Integration: return self.manifest = manifest + + def import_pkg(self, platform=None): + """Import the Python file.""" + pkg = "homeassistant.components.{}".format(self.domain) + if platform is not None: + pkg += ".{}".format(platform) + return importlib.import_module(pkg) diff --git a/tests/common.py b/tests/common.py index f5a2b1327fe..572cd19a006 100644 --- a/tests/common.py +++ b/tests/common.py @@ -926,7 +926,7 @@ async def get_system_health_info(hass, domain): def mock_integration(hass, module): """Mock an integration.""" integration = loader.Integration( - hass, 'homeassisant.components.{}'.format(module.DOMAIN), None, + hass, 'homeassistant.components.{}'.format(module.DOMAIN), None, module.mock_manifest()) _LOGGER.info("Adding mock integration: %s", module.DOMAIN) diff --git a/tests/components/config/test_config_entries.py b/tests/components/config/test_config_entries.py index 1b5a40ade8a..cdce7433398 100644 --- a/tests/components/config/test_config_entries.py +++ b/tests/components/config/test_config_entries.py @@ -12,9 +12,11 @@ from homeassistant.config_entries import HANDLERS from homeassistant.core import callback from homeassistant.setup import async_setup_component from homeassistant.components.config import config_entries +from homeassistant.generated import config_flows from tests.common import ( - MockConfigEntry, MockModule, mock_coro_func, mock_integration) + MockConfigEntry, MockModule, mock_coro_func, mock_integration, + mock_entity_platform) @pytest.fixture(autouse=True) @@ -121,7 +123,7 @@ async def test_remove_entry_unauth(hass, client, hass_admin_user): @asyncio.coroutine def test_available_flows(hass, client): """Test querying the available flows.""" - with patch.object(core_ce, 'FLOWS', ['hello', 'world']): + with patch.object(config_flows, 'FLOWS', ['hello', 'world']): resp = yield from client.get( '/api/config/config_entries/flow_handlers') assert resp.status == 200 @@ -137,6 +139,8 @@ def test_available_flows(hass, client): @asyncio.coroutine def test_initialize_flow(hass, client): """Test we can initialize a flow.""" + mock_entity_platform(hass, 'config_flow.test', None) + class TestFlow(core_ce.ConfigFlow): @asyncio.coroutine def async_step_user(self, user_input=None): @@ -221,6 +225,8 @@ async def test_initialize_flow_unauth(hass, client, hass_admin_user): @asyncio.coroutine def test_abort(hass, client): """Test a flow that aborts.""" + mock_entity_platform(hass, 'config_flow.test', None) + class TestFlow(core_ce.ConfigFlow): @asyncio.coroutine def async_step_user(self, user_input=None): @@ -244,6 +250,8 @@ def test_abort(hass, client): @asyncio.coroutine def test_create_account(hass, client): """Test a flow that creates an account.""" + mock_entity_platform(hass, 'config_flow.test', None) + mock_integration( hass, MockModule('test', async_setup_entry=mock_coro_func(True))) @@ -286,6 +294,7 @@ def test_two_step_flow(hass, client): mock_integration( hass, MockModule('test', async_setup_entry=mock_coro_func(True))) + mock_entity_platform(hass, 'config_flow.test', None) class TestFlow(core_ce.ConfigFlow): VERSION = 1 @@ -352,6 +361,7 @@ async def test_continue_flow_unauth(hass, client, hass_admin_user): mock_integration( hass, MockModule('test', async_setup_entry=mock_coro_func(True))) + mock_entity_platform(hass, 'config_flow.test', None) class TestFlow(core_ce.ConfigFlow): VERSION = 1 @@ -402,6 +412,8 @@ async def test_continue_flow_unauth(hass, client, hass_admin_user): @asyncio.coroutine def test_get_progress_index(hass, client): """Test querying for the flows that are in progress.""" + mock_entity_platform(hass, 'config_flow.test', None) + class TestFlow(core_ce.ConfigFlow): VERSION = 5 @@ -441,6 +453,8 @@ async def test_get_progress_index_unauth(hass, client, hass_admin_user): @asyncio.coroutine def test_get_progress_flow(hass, client): """Test we can query the API for same result as we get from init a flow.""" + mock_entity_platform(hass, 'config_flow.test', None) + class TestFlow(core_ce.ConfigFlow): @asyncio.coroutine def async_step_user(self, user_input=None): @@ -474,6 +488,8 @@ def test_get_progress_flow(hass, client): async def test_get_progress_flow_unauth(hass, client, hass_admin_user): """Test we can can't query the API for result of flow.""" + mock_entity_platform(hass, 'config_flow.test', None) + class TestFlow(core_ce.ConfigFlow): async def async_step_user(self, user_input=None): schema = OrderedDict() diff --git a/tests/components/unifi/test_controller.py b/tests/components/unifi/test_controller.py index e5e1d84bfcd..d1db25a23cd 100644 --- a/tests/components/unifi/test_controller.py +++ b/tests/components/unifi/test_controller.py @@ -4,24 +4,27 @@ from unittest.mock import Mock, patch import pytest from homeassistant.exceptions import ConfigEntryNotReady -from homeassistant.components import unifi +from homeassistant.components.unifi.const import ( + CONF_POE_CONTROL, CONF_CONTROLLER, CONF_SITE_ID) +from homeassistant.const import ( + CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_USERNAME, CONF_VERIFY_SSL) from homeassistant.components.unifi import controller, errors from tests.common import mock_coro CONTROLLER_DATA = { - unifi.CONF_HOST: '1.2.3.4', - unifi.CONF_USERNAME: 'username', - unifi.CONF_PASSWORD: 'password', - unifi.CONF_PORT: 1234, - unifi.CONF_SITE_ID: 'site', - unifi.CONF_VERIFY_SSL: True + CONF_HOST: '1.2.3.4', + CONF_USERNAME: 'username', + CONF_PASSWORD: 'password', + CONF_PORT: 1234, + CONF_SITE_ID: 'site', + CONF_VERIFY_SSL: True } ENTRY_CONFIG = { - unifi.CONF_CONTROLLER: CONTROLLER_DATA, - unifi.CONF_POE_CONTROL: True - } + CONF_CONTROLLER: CONTROLLER_DATA, + CONF_POE_CONTROL: True +} async def test_controller_setup(): @@ -173,7 +176,7 @@ async def test_reset_unloads_entry_without_poe_control(): hass = Mock() entry = Mock() entry.data = dict(ENTRY_CONFIG) - entry.data[unifi.CONF_POE_CONTROL] = False + entry.data[CONF_POE_CONTROL] = False api = Mock() api.initialize.return_value = mock_coro(True) @@ -201,7 +204,7 @@ async def test_get_controller(hass): async def test_get_controller_verify_ssl_false(hass): """Successful call with verify ssl set to false.""" controller_data = dict(CONTROLLER_DATA) - controller_data[unifi.CONF_VERIFY_SSL] = False + controller_data[CONF_VERIFY_SSL] = False with patch('aiounifi.Controller.login', return_value=mock_coro()): assert await controller.get_controller(hass, **controller_data) diff --git a/tests/components/unifi/test_init.py b/tests/components/unifi/test_init.py index 0115801eec6..d2d19204b40 100644 --- a/tests/components/unifi/test_init.py +++ b/tests/components/unifi/test_init.py @@ -2,7 +2,12 @@ from unittest.mock import Mock, patch from homeassistant.components import unifi +from homeassistant.components.unifi import config_flow from homeassistant.setup import async_setup_component +from homeassistant.components.unifi.const import ( + CONF_POE_CONTROL, CONF_CONTROLLER, CONF_SITE_ID) +from homeassistant.const import ( + CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_USERNAME, CONF_VERIFY_SSL) from tests.common import mock_coro, MockConfigEntry @@ -137,7 +142,7 @@ async def test_unload_entry(hass): async def test_flow_works(hass, aioclient_mock): """Test config flow.""" - flow = unifi.UnifiFlowHandler() + flow = config_flow.UnifiFlowHandler() flow.hass = hass with patch('aiounifi.Controller') as mock_controller: @@ -157,11 +162,11 @@ async def test_flow_works(hass, aioclient_mock): }) await flow.async_step_user(user_input={ - unifi.CONF_HOST: '1.2.3.4', - unifi.CONF_USERNAME: 'username', - unifi.CONF_PASSWORD: 'password', - unifi.CONF_PORT: 1234, - unifi.CONF_VERIFY_SSL: True + CONF_HOST: '1.2.3.4', + CONF_USERNAME: 'username', + CONF_PASSWORD: 'password', + CONF_PORT: 1234, + CONF_VERIFY_SSL: True }) result = await flow.async_step_site(user_input={}) @@ -173,27 +178,27 @@ async def test_flow_works(hass, aioclient_mock): assert result['type'] == 'create_entry' assert result['title'] == 'site name' assert result['data'] == { - unifi.CONF_CONTROLLER: { - unifi.CONF_HOST: '1.2.3.4', - unifi.CONF_USERNAME: 'username', - unifi.CONF_PASSWORD: 'password', - unifi.CONF_PORT: 1234, - unifi.CONF_SITE_ID: 'default', - unifi.CONF_VERIFY_SSL: True + CONF_CONTROLLER: { + CONF_HOST: '1.2.3.4', + CONF_USERNAME: 'username', + CONF_PASSWORD: 'password', + CONF_PORT: 1234, + CONF_SITE_ID: 'default', + CONF_VERIFY_SSL: True }, - unifi.CONF_POE_CONTROL: True + CONF_POE_CONTROL: True } async def test_controller_multiple_sites(hass): """Test config flow.""" - flow = unifi.UnifiFlowHandler() + flow = config_flow.UnifiFlowHandler() flow.hass = hass flow.config = { - unifi.CONF_HOST: '1.2.3.4', - unifi.CONF_USERNAME: 'username', - unifi.CONF_PASSWORD: 'password', + CONF_HOST: '1.2.3.4', + CONF_USERNAME: 'username', + CONF_PASSWORD: 'password', } flow.sites = { 'site1': { @@ -215,7 +220,7 @@ async def test_controller_multiple_sites(hass): async def test_controller_site_already_configured(hass): """Test config flow.""" - flow = unifi.UnifiFlowHandler() + flow = config_flow.UnifiFlowHandler() flow.hass = hass entry = MockConfigEntry(domain=unifi.DOMAIN, data={ @@ -227,9 +232,9 @@ async def test_controller_site_already_configured(hass): entry.add_to_hass(hass) flow.config = { - unifi.CONF_HOST: '1.2.3.4', - unifi.CONF_USERNAME: 'username', - unifi.CONF_PASSWORD: 'password', + CONF_HOST: '1.2.3.4', + CONF_USERNAME: 'username', + CONF_PASSWORD: 'password', } flow.desc = 'site name' flow.sites = { @@ -245,7 +250,7 @@ async def test_controller_site_already_configured(hass): async def test_user_permissions_low(hass, aioclient_mock): """Test config flow.""" - flow = unifi.UnifiFlowHandler() + flow = config_flow.UnifiFlowHandler() flow.hass = hass with patch('aiounifi.Controller') as mock_controller: @@ -265,11 +270,11 @@ async def test_user_permissions_low(hass, aioclient_mock): }) await flow.async_step_user(user_input={ - unifi.CONF_HOST: '1.2.3.4', - unifi.CONF_USERNAME: 'username', - unifi.CONF_PASSWORD: 'password', - unifi.CONF_PORT: 1234, - unifi.CONF_VERIFY_SSL: True + CONF_HOST: '1.2.3.4', + CONF_USERNAME: 'username', + CONF_PASSWORD: 'password', + CONF_PORT: 1234, + CONF_VERIFY_SSL: True }) result = await flow.async_step_site(user_input={}) @@ -279,16 +284,16 @@ async def test_user_permissions_low(hass, aioclient_mock): async def test_user_credentials_faulty(hass, aioclient_mock): """Test config flow.""" - flow = unifi.UnifiFlowHandler() + flow = config_flow.UnifiFlowHandler() flow.hass = hass - with patch.object(unifi, 'get_controller', + with patch.object(config_flow, 'get_controller', side_effect=unifi.errors.AuthenticationRequired): result = await flow.async_step_user({ - unifi.CONF_HOST: '1.2.3.4', - unifi.CONF_USERNAME: 'username', - unifi.CONF_PASSWORD: 'password', - unifi.CONF_SITE_ID: 'default', + CONF_HOST: '1.2.3.4', + CONF_USERNAME: 'username', + CONF_PASSWORD: 'password', + CONF_SITE_ID: 'default', }) assert result['type'] == 'form' @@ -297,16 +302,16 @@ async def test_user_credentials_faulty(hass, aioclient_mock): async def test_controller_is_unavailable(hass, aioclient_mock): """Test config flow.""" - flow = unifi.UnifiFlowHandler() + flow = config_flow.UnifiFlowHandler() flow.hass = hass - with patch.object(unifi, 'get_controller', + with patch.object(config_flow, 'get_controller', side_effect=unifi.errors.CannotConnect): result = await flow.async_step_user({ - unifi.CONF_HOST: '1.2.3.4', - unifi.CONF_USERNAME: 'username', - unifi.CONF_PASSWORD: 'password', - unifi.CONF_SITE_ID: 'default', + CONF_HOST: '1.2.3.4', + CONF_USERNAME: 'username', + CONF_PASSWORD: 'password', + CONF_SITE_ID: 'default', }) assert result['type'] == 'form' @@ -315,16 +320,16 @@ async def test_controller_is_unavailable(hass, aioclient_mock): async def test_controller_unkown_problem(hass, aioclient_mock): """Test config flow.""" - flow = unifi.UnifiFlowHandler() + flow = config_flow.UnifiFlowHandler() flow.hass = hass - with patch.object(unifi, 'get_controller', + with patch.object(config_flow, 'get_controller', side_effect=Exception): result = await flow.async_step_user({ - unifi.CONF_HOST: '1.2.3.4', - unifi.CONF_USERNAME: 'username', - unifi.CONF_PASSWORD: 'password', - unifi.CONF_SITE_ID: 'default', + CONF_HOST: '1.2.3.4', + CONF_USERNAME: 'username', + CONF_PASSWORD: 'password', + CONF_SITE_ID: 'default', }) assert result['type'] == 'abort' diff --git a/tests/components/unifi/test_switch.py b/tests/components/unifi/test_switch.py index 67f1e416cf1..5a04b415f5d 100644 --- a/tests/components/unifi/test_switch.py +++ b/tests/components/unifi/test_switch.py @@ -10,7 +10,11 @@ from aiounifi.devices import Devices from homeassistant import config_entries from homeassistant.components import unifi +from homeassistant.components.unifi.const import ( + CONF_POE_CONTROL, CONF_CONTROLLER, CONF_SITE_ID) from homeassistant.setup import async_setup_component +from homeassistant.const import ( + CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_USERNAME, CONF_VERIFY_SSL) import homeassistant.components.switch as switch @@ -167,17 +171,17 @@ DEVICE_1 = { } CONTROLLER_DATA = { - unifi.CONF_HOST: 'mock-host', - unifi.CONF_USERNAME: 'mock-user', - unifi.CONF_PASSWORD: 'mock-pswd', - unifi.CONF_PORT: 1234, - unifi.CONF_SITE_ID: 'mock-site', - unifi.CONF_VERIFY_SSL: True + CONF_HOST: 'mock-host', + CONF_USERNAME: 'mock-user', + CONF_PASSWORD: 'mock-pswd', + CONF_PORT: 1234, + CONF_SITE_ID: 'mock-site', + CONF_VERIFY_SSL: True } ENTRY_CONFIG = { - unifi.CONF_CONTROLLER: CONTROLLER_DATA, - unifi.CONF_POE_CONTROL: True + CONF_CONTROLLER: CONTROLLER_DATA, + CONF_POE_CONTROL: True } CONTROLLER_ID = unifi.CONTROLLER_ID.format(host='mock-host', site='mock-site') diff --git a/tests/helpers/test_config_entry_flow.py b/tests/helpers/test_config_entry_flow.py index 04c91cfdc08..5f8a642333a 100644 --- a/tests/helpers/test_config_entry_flow.py +++ b/tests/helpers/test_config_entry_flow.py @@ -6,7 +6,8 @@ import pytest from homeassistant import config_entries, data_entry_flow, setup from homeassistant.helpers import config_entry_flow from tests.common import ( - MockConfigEntry, MockModule, mock_coro, mock_integration) + MockConfigEntry, MockModule, mock_coro, mock_integration, + mock_entity_platform) @pytest.fixture @@ -102,7 +103,7 @@ async def test_discovery_confirmation(hass, discovery_flow_conf): async def test_multiple_discoveries(hass, discovery_flow_conf): """Test we only create one instance for multiple discoveries.""" - mock_integration(hass, MockModule('test')) + mock_entity_platform(hass, 'config_flow.test', None) result = await hass.config_entries.flow.async_init( 'test', context={'source': config_entries.SOURCE_DISCOVERY}, data={}) @@ -116,7 +117,7 @@ async def test_multiple_discoveries(hass, discovery_flow_conf): async def test_only_one_in_progress(hass, discovery_flow_conf): """Test a user initialized one will finish and cancel discovered one.""" - mock_integration(hass, MockModule('test')) + mock_entity_platform(hass, 'config_flow.test', None) # Discovery starts flow result = await hass.config_entries.flow.async_init( @@ -209,6 +210,7 @@ async def test_webhook_create_cloudhook(hass, webhook_flow_conf): async_unload_entry=async_unload_entry, async_remove_entry=config_entry_flow.webhook_async_remove_entry, )) + mock_entity_platform(hass, 'config_flow.test_single', None) result = await hass.config_entries.flow.async_init( 'test_single', context={'source': config_entries.SOURCE_USER}) diff --git a/tests/helpers/test_translation.py b/tests/helpers/test_translation.py index ebf883bfe12..de871c6f474 100644 --- a/tests/helpers/test_translation.py +++ b/tests/helpers/test_translation.py @@ -5,9 +5,9 @@ from unittest.mock import patch import pytest -from homeassistant import config_entries import homeassistant.helpers.translation as translation from homeassistant.setup import async_setup_component +from homeassistant.generated import config_flows from tests.common import mock_coro @@ -15,7 +15,7 @@ from tests.common import mock_coro def mock_config_flows(): """Mock the config flows.""" flows = [] - with patch.object(config_entries, 'FLOWS', flows): + with patch.object(config_flows, 'FLOWS', flows): yield flows diff --git a/tests/test_config_entries.py b/tests/test_config_entries.py index a8a1211f4c2..9de31a6d5ca 100644 --- a/tests/test_config_entries.py +++ b/tests/test_config_entries.py @@ -53,6 +53,7 @@ async def test_call_setup_entry(hass): hass, MockModule('comp', async_setup_entry=mock_setup_entry, async_migrate_entry=mock_migrate_entry)) + mock_entity_platform(hass, 'config_flow.comp', None) result = await async_setup_component(hass, 'comp', {}) assert result @@ -74,6 +75,7 @@ async def test_call_async_migrate_entry(hass): hass, MockModule('comp', async_setup_entry=mock_setup_entry, async_migrate_entry=mock_migrate_entry)) + mock_entity_platform(hass, 'config_flow.comp', None) result = await async_setup_component(hass, 'comp', {}) assert result @@ -95,6 +97,7 @@ async def test_call_async_migrate_entry_failure_false(hass): hass, MockModule('comp', async_setup_entry=mock_setup_entry, async_migrate_entry=mock_migrate_entry)) + mock_entity_platform(hass, 'config_flow.comp', None) result = await async_setup_component(hass, 'comp', {}) assert result @@ -117,6 +120,7 @@ async def test_call_async_migrate_entry_failure_exception(hass): hass, MockModule('comp', async_setup_entry=mock_setup_entry, async_migrate_entry=mock_migrate_entry)) + mock_entity_platform(hass, 'config_flow.comp', None) result = await async_setup_component(hass, 'comp', {}) assert result @@ -139,6 +143,7 @@ async def test_call_async_migrate_entry_failure_not_bool(hass): hass, MockModule('comp', async_setup_entry=mock_setup_entry, async_migrate_entry=mock_migrate_entry)) + mock_entity_platform(hass, 'config_flow.comp', None) result = await async_setup_component(hass, 'comp', {}) assert result @@ -158,6 +163,7 @@ async def test_call_async_migrate_entry_failure_not_supported(hass): mock_integration( hass, MockModule('comp', async_setup_entry=mock_setup_entry)) + mock_entity_platform(hass, 'config_flow.comp', None) result = await async_setup_component(hass, 'comp', {}) assert result @@ -201,6 +207,7 @@ async def test_remove_entry(hass, manager): mock_entity_platform( hass, 'light.test', MockPlatform(async_setup_entry=mock_setup_entry_platform)) + mock_entity_platform(hass, 'config_flow.test', None) MockConfigEntry( domain='test_other', entry_id='test1' @@ -361,6 +368,7 @@ def test_add_entry_calls_setup_entry(hass, manager): mock_integration( hass, MockModule('comp', async_setup_entry=mock_setup_entry)) + mock_entity_platform(hass, 'config_flow.comp', None) class TestFlow(config_entries.ConfigFlow): @@ -416,6 +424,7 @@ async def test_saving_and_loading(hass): """Test that we're saving and loading correctly.""" mock_integration(hass, MockModule( 'test', async_setup_entry=lambda *args: mock_coro(True))) + mock_entity_platform(hass, 'config_flow.test', None) class TestFlow(config_entries.ConfigFlow): VERSION = 5 @@ -511,6 +520,7 @@ async def test_forward_entry_does_not_setup_entry_if_setup_fails(hass): async def test_discovery_notification(hass): """Test that we create/dismiss a notification when source is discovery.""" mock_integration(hass, MockModule('test')) + mock_entity_platform(hass, 'config_flow.test', None) await async_setup_component(hass, 'persistent_notification', {}) class TestFlow(config_entries.ConfigFlow): @@ -548,6 +558,7 @@ async def test_discovery_notification(hass): async def test_discovery_notification_not_created(hass): """Test that we not create a notification when discovery is aborted.""" mock_integration(hass, MockModule('test')) + mock_entity_platform(hass, 'config_flow.test', None) await async_setup_component(hass, 'persistent_notification', {}) class TestFlow(config_entries.ConfigFlow): @@ -629,6 +640,7 @@ async def test_setup_raise_not_ready(hass, caplog): mock_setup_entry = MagicMock(side_effect=ConfigEntryNotReady) mock_integration( hass, MockModule('test', async_setup_entry=mock_setup_entry)) + mock_entity_platform(hass, 'config_flow.test', None) with patch('homeassistant.helpers.event.async_call_later') as mock_call: await entry.async_setup(hass) @@ -655,6 +667,7 @@ async def test_setup_retrying_during_unload(hass): mock_setup_entry = MagicMock(side_effect=ConfigEntryNotReady) mock_integration( hass, MockModule('test', async_setup_entry=mock_setup_entry)) + mock_entity_platform(hass, 'config_flow.test', None) with patch('homeassistant.helpers.event.async_call_later') as mock_call: await entry.async_setup(hass) @@ -720,6 +733,7 @@ async def test_entry_setup_succeed(hass, manager): async_setup=mock_setup, async_setup_entry=mock_setup_entry )) + mock_entity_platform(hass, 'config_flow.comp', None) assert await manager.async_setup(entry.entry_id) assert len(mock_setup.mock_calls) == 1 @@ -848,6 +862,7 @@ async def test_entry_reload_succeed(hass, manager): async_setup_entry=async_setup_entry, async_unload_entry=async_unload_entry )) + mock_entity_platform(hass, 'config_flow.comp', None) assert await manager.async_reload(entry.entry_id) assert len(async_unload_entry.mock_calls) == 1 @@ -879,6 +894,7 @@ async def test_entry_reload_not_loaded(hass, manager, state): async_setup_entry=async_setup_entry, async_unload_entry=async_unload_entry )) + mock_entity_platform(hass, 'config_flow.comp', None) assert await manager.async_reload(entry.entry_id) assert len(async_unload_entry.mock_calls) == 0