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
pull/23845/head
Paulus Schoutsen 2019-05-13 01:16:55 -07:00 committed by GitHub
parent b8cbd39985
commit 1e22c8daca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
106 changed files with 742 additions and 440 deletions

View File

@ -1,6 +1,7 @@
{
"domain": "ambiclimate",
"name": "Ambiclimate",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/ambiclimate",
"requirements": [
"ambiclimate==0.1.1"

View File

@ -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"

View File

@ -1,6 +1,7 @@
{
"domain": "axis",
"name": "Axis",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/axis",
"requirements": ["axis==22"],
"dependencies": [],

View File

@ -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)

View File

@ -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)

View File

@ -0,0 +1,3 @@
"""Consts for Cast integration."""
DOMAIN = 'cast'

View File

@ -1,6 +1,7 @@
{
"domain": "cast",
"name": "Cast",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/cast",
"requirements": [
"pychromecast==3.2.1"

View File

@ -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):

View File

@ -1,6 +1,7 @@
{
"domain": "daikin",
"name": "Daikin",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/daikin",
"requirements": [
"pydaikin==1.4.0"

View File

@ -1,6 +1,7 @@
{
"domain": "deconz",
"name": "Deconz",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/deconz",
"requirements": [
"pydeconz==58"

View File

@ -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'])

View File

@ -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/'
}
)

View File

@ -0,0 +1,3 @@
"""Const for DialogFlow."""
DOMAIN = "dialogflow"

View File

@ -1,6 +1,7 @@
{
"domain": "dialogflow",
"name": "Dialogflow",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/dialogflow",
"requirements": [],
"dependencies": [

View File

@ -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"

View File

@ -1,6 +1,7 @@
{
"domain": "esphome",
"name": "ESPHome",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/esphome",
"requirements": [
"aioesphomeapi==2.0.1"

View File

@ -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/'
}
)

View File

@ -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/'
}
)

View File

@ -0,0 +1,3 @@
"""Const for Geofency."""
DOMAIN = 'geofency'

View File

@ -1,6 +1,7 @@
{
"domain": "geofency",
"name": "Geofency",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/geofency",
"requirements": [],
"dependencies": [

View File

@ -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/'
}
)

View File

@ -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/'
}
)

View File

@ -0,0 +1,3 @@
"""Const for GPSLogger."""
DOMAIN = 'gpslogger'

View File

@ -1,6 +1,7 @@
{
"domain": "gpslogger",
"name": "Gpslogger",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/gpslogger",
"requirements": [],
"dependencies": [

View File

@ -1,6 +1,7 @@
{
"domain": "hangouts",
"name": "Hangouts",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/hangouts",
"requirements": [
"hangups==0.4.9"

View File

@ -1,6 +1,7 @@
{
"domain": "heos",
"name": "HEOS",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/heos",
"requirements": [
"pyheos==0.5.2"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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/'
}
)

View File

@ -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/'
}
)

View File

@ -0,0 +1,3 @@
"""Const for IFTTT."""
DOMAIN = "ifttt"

View File

@ -1,6 +1,7 @@
{
"domain": "ifttt",
"name": "Ifttt",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/ifttt",
"requirements": [
"pyfttt==0.3"

View File

@ -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)

View File

@ -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)

View File

@ -0,0 +1,3 @@
"""Const for iOS."""
DOMAIN = "ios"

View File

@ -1,6 +1,7 @@
{
"domain": "ios",
"name": "Ios",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/ios",
"requirements": [],
"dependencies": [

View File

@ -1,6 +1,7 @@
{
"domain": "ipma",
"name": "Ipma",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/ipma",
"requirements": [
"pyipma==1.2.1"

View File

@ -1,6 +1,7 @@
{
"domain": "iqvia",
"name": "IQVIA",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/iqvia",
"requirements": [
"numpy==1.16.3",

View File

@ -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)

View File

@ -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)

View File

@ -0,0 +1,3 @@
"""Const for LIFX."""
DOMAIN = 'lifx'

View File

@ -1,6 +1,7 @@
{
"domain": "lifx",
"name": "Lifx",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/lifx",
"requirements": [
"aiolifx==0.6.7",

View File

@ -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/'
}
)

View File

@ -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/'
}
)

View File

@ -0,0 +1,3 @@
"""Const for Locative."""
DOMAIN = "locative"

View File

@ -1,6 +1,7 @@
{
"domain": "locative",
"name": "Locative",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/locative",
"requirements": [],
"dependencies": [

View File

@ -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"],

View File

@ -1,6 +1,7 @@
{
"domain": "luftdaten",
"name": "Luftdaten",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/luftdaten",
"requirements": [
"luftdaten==0.3.4"

View File

@ -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/'
}
)

View File

@ -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/'
}
)

View File

@ -0,0 +1,3 @@
"""Const for Mailgun."""
DOMAIN = "mailgun"

View File

@ -1,6 +1,7 @@
{
"domain": "mailgun",
"name": "Mailgun",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/mailgun",
"requirements": [
"pymailgunner==1.4"

View File

@ -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)

View File

@ -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)

View File

@ -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"

View File

@ -1,6 +1,7 @@
{
"domain": "mqtt",
"name": "MQTT",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/mqtt",
"requirements": [
"hbmqtt==0.9.4",

View File

@ -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"

View File

@ -1,6 +1,7 @@
{
"domain": "openuv",
"name": "Openuv",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/openuv",
"requirements": [
"pyopenuv==1.0.9"

View File

@ -1,6 +1,7 @@
{
"domain": "owntracks",
"name": "Owntracks",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/owntracks",
"requirements": [
"PyNaCl==1.3.0"

View File

@ -1,6 +1,7 @@
{
"domain": "point",
"name": "Point",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/point",
"requirements": [
"pypoint==1.1.1"

View File

@ -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"

View File

@ -1,6 +1,7 @@
{
"domain": "rainmachine",
"name": "Rainmachine",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/rainmachine",
"requirements": [
"regenmaschine==1.4.0"

View File

@ -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"

View File

@ -1,6 +1,7 @@
{
"domain": "smartthings",
"name": "Smartthings",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/smartthings",
"requirements": [
"pysmartapp==0.3.2",

View File

@ -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"

View File

@ -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)

View File

@ -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)

View File

@ -0,0 +1,3 @@
"""Const for Sonos."""
DOMAIN = "sonos"

View File

@ -1,6 +1,7 @@
{
"domain": "sonos",
"name": "Sonos",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/sonos",
"requirements": [
"pysonos==0.0.12"

View File

@ -1,6 +1,7 @@
{
"domain": "tellduslive",
"name": "Tellduslive",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/tellduslive",
"requirements": [
"tellduslive==0.10.10"

View File

@ -1,6 +1,7 @@
{
"domain": "toon",
"name": "Toon",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/toon",
"requirements": [
"toonapilib==3.2.2"

View File

@ -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)

View File

@ -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)

View File

@ -0,0 +1,3 @@
"""Const for TP-Link."""
DOMAIN = "tplink"

View File

@ -1,6 +1,7 @@
{
"domain": "tplink",
"name": "Tplink",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/tplink",
"requirements": [
"pyHS100==0.3.5",

View File

@ -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"

View File

@ -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/'
}
)

View File

@ -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/'
}
)

View File

@ -0,0 +1,3 @@
"""Const for Twilio."""
DOMAIN = "twilio"

View File

@ -1,6 +1,7 @@
{
"domain": "twilio",
"name": "Twilio",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/twilio",
"requirements": [
"twilio==6.19.1"

View File

@ -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,
)

View File

@ -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,
)

View File

@ -1,6 +1,7 @@
{
"domain": "unifi",
"name": "Unifi",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/unifi",
"requirements": [
"aiounifi==4",

View File

@ -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)

View File

@ -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)

View File

@ -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"

View File

@ -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",

View File

@ -1,6 +1,7 @@
{
"domain": "zone",
"name": "Zone",
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/zone",
"requirements": [],
"dependencies": [],

View File

@ -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",

View File

@ -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

View File

@ -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"
]

View File

@ -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)

View File

@ -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

View File

@ -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,
]

View File

@ -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')

View File

@ -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],

View File

@ -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)

View File

@ -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)

View File

@ -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()

Some files were not shown because too many files have changed in this diff Show More