core/homeassistant/components/mqtt/config_flow.py

156 lines
4.8 KiB
Python
Raw Normal View History

"""Config flow for MQTT."""
from collections import OrderedDict
import queue
import voluptuous as vol
import paho.mqtt.client as mqtt
from homeassistant import config_entries
from homeassistant.const import (
2019-07-31 19:25:30 +00:00
CONF_HOST,
CONF_PASSWORD,
CONF_PORT,
CONF_PROTOCOL,
CONF_USERNAME,
)
2018-09-25 10:22:14 +00:00
from .const import CONF_BROKER, CONF_DISCOVERY, DEFAULT_DISCOVERY
2019-07-31 19:25:30 +00:00
@config_entries.HANDLERS.register("mqtt")
class FlowHandler(config_entries.ConfigFlow):
"""Handle a config flow."""
VERSION = 1
CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_PUSH
_hassio_discovery = None
async def async_step_user(self, user_input=None):
"""Handle a flow initialized by the user."""
if self._async_current_entries():
2019-07-31 19:25:30 +00:00
return self.async_abort(reason="single_instance_allowed")
return await self.async_step_broker()
async def async_step_broker(self, user_input=None):
2018-09-18 12:59:39 +00:00
"""Confirm the setup."""
errors = {}
if user_input is not None:
can_connect = await self.hass.async_add_executor_job(
2019-07-31 19:25:30 +00:00
try_connection,
user_input[CONF_BROKER],
user_input[CONF_PORT],
user_input.get(CONF_USERNAME),
user_input.get(CONF_PASSWORD),
)
if can_connect:
return self.async_create_entry(
2019-07-31 19:25:30 +00:00
title=user_input[CONF_BROKER], data=user_input
)
2019-07-31 19:25:30 +00:00
errors["base"] = "cannot_connect"
fields = OrderedDict()
fields[vol.Required(CONF_BROKER)] = str
fields[vol.Required(CONF_PORT, default=1883)] = vol.Coerce(int)
fields[vol.Optional(CONF_USERNAME)] = str
fields[vol.Optional(CONF_PASSWORD)] = str
2018-09-25 10:22:14 +00:00
fields[vol.Optional(CONF_DISCOVERY, default=DEFAULT_DISCOVERY)] = bool
return self.async_show_form(
2019-07-31 19:25:30 +00:00
step_id="broker", data_schema=vol.Schema(fields), errors=errors
)
async def async_step_import(self, user_input):
"""Import a config entry.
Special type of import, we're not actually going to store any data.
Instead, we're going to rely on the values that are in config file.
"""
if self._async_current_entries():
2019-07-31 19:25:30 +00:00
return self.async_abort(reason="single_instance_allowed")
2018-09-18 12:59:39 +00:00
2019-07-31 19:25:30 +00:00
return self.async_create_entry(title="configuration.yaml", data={})
async def async_step_hassio(self, user_input=None):
"""Receive a Hass.io discovery."""
if self._async_current_entries():
2019-07-31 19:25:30 +00:00
return self.async_abort(reason="single_instance_allowed")
self._hassio_discovery = user_input
return await self.async_step_hassio_confirm()
async def async_step_hassio_confirm(self, user_input=None):
"""Confirm a Hass.io discovery."""
errors = {}
if user_input is not None:
data = self._hassio_discovery
can_connect = await self.hass.async_add_executor_job(
try_connection,
data[CONF_HOST],
data[CONF_PORT],
data.get(CONF_USERNAME),
data.get(CONF_PASSWORD),
2019-07-31 19:25:30 +00:00
data.get(CONF_PROTOCOL),
)
if can_connect:
return self.async_create_entry(
2019-07-31 19:25:30 +00:00
title=data["addon"],
data={
CONF_BROKER: data[CONF_HOST],
CONF_PORT: data[CONF_PORT],
CONF_USERNAME: data.get(CONF_USERNAME),
CONF_PASSWORD: data.get(CONF_PASSWORD),
CONF_PROTOCOL: data.get(CONF_PROTOCOL),
CONF_DISCOVERY: user_input[CONF_DISCOVERY],
2019-07-31 19:25:30 +00:00
},
)
2019-07-31 19:25:30 +00:00
errors["base"] = "cannot_connect"
return self.async_show_form(
2019-07-31 19:25:30 +00:00
step_id="hassio_confirm",
description_placeholders={"addon": self._hassio_discovery["addon"]},
data_schema=vol.Schema(
{vol.Optional(CONF_DISCOVERY, default=DEFAULT_DISCOVERY): bool}
),
errors=errors,
)
2019-07-31 19:25:30 +00:00
def try_connection(broker, port, username, password, protocol="3.1"):
"""Test if we can connect to an MQTT broker."""
2019-07-31 19:25:30 +00:00
if protocol == "3.1":
proto = mqtt.MQTTv31
else:
proto = mqtt.MQTTv311
client = mqtt.Client(protocol=proto)
if username and password:
client.username_pw_set(username, password)
result = queue.Queue(maxsize=1)
def on_connect(client_, userdata, flags, result_code):
"""Handle connection result."""
result.put(result_code == mqtt.CONNACK_ACCEPTED)
client.on_connect = on_connect
client.connect_async(broker, port)
client.loop_start()
try:
return result.get(timeout=5)
except queue.Empty:
return False
finally:
client.disconnect()
client.loop_stop()