Config validation for MQTT
This commit is contained in:
parent
2e9bf42688
commit
8cca2bb344
4 changed files with 47 additions and 24 deletions
|
@ -14,7 +14,6 @@ import voluptuous as vol
|
||||||
from homeassistant.bootstrap import prepare_setup_platform
|
from homeassistant.bootstrap import prepare_setup_platform
|
||||||
from homeassistant.config import load_yaml_config_file
|
from homeassistant.config import load_yaml_config_file
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
import homeassistant.util as util
|
|
||||||
from homeassistant.helpers import template
|
from homeassistant.helpers import template
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
|
@ -58,6 +57,25 @@ ATTR_RETAIN = 'retain'
|
||||||
|
|
||||||
MAX_RECONNECT_WAIT = 300 # seconds
|
MAX_RECONNECT_WAIT = 300 # seconds
|
||||||
|
|
||||||
|
_HBMQTT_CONFIG_SCHEMA = vol.Schema(dict)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = vol.Schema({
|
||||||
|
DOMAIN: vol.Schema({
|
||||||
|
vol.Optional(CONF_CLIENT_ID): cv.string,
|
||||||
|
vol.Optional(CONF_KEEPALIVE, default=DEFAULT_KEEPALIVE):
|
||||||
|
vol.All(vol.Coerce(int), vol.Range(min=15)),
|
||||||
|
vol.Optional(CONF_BROKER): cv.string,
|
||||||
|
vol.Optional(CONF_PORT, default=DEFAULT_PORT):
|
||||||
|
vol.All(vol.Coerce(int), vol.Range(min=1, max=65535)),
|
||||||
|
vol.Optional(CONF_USERNAME): cv.string,
|
||||||
|
vol.Optional(CONF_PASSWORD): cv.string,
|
||||||
|
vol.Optional(CONF_CERTIFICATE): vol.IsFile,
|
||||||
|
vol.Optional(CONF_PROTOCOL, default=DEFAULT_PROTOCOL):
|
||||||
|
[PROTOCOL_31, PROTOCOL_311],
|
||||||
|
vol.Optional(CONF_EMBEDDED): _HBMQTT_CONFIG_SCHEMA,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
# Service call validation schema
|
# Service call validation schema
|
||||||
def mqtt_topic(value):
|
def mqtt_topic(value):
|
||||||
|
@ -136,8 +154,8 @@ def setup(hass, config):
|
||||||
# pylint: disable=too-many-locals
|
# pylint: disable=too-many-locals
|
||||||
conf = config.get(DOMAIN, {})
|
conf = config.get(DOMAIN, {})
|
||||||
|
|
||||||
client_id = util.convert(conf.get(CONF_CLIENT_ID), str)
|
client_id = conf.get(CONF_CLIENT_ID)
|
||||||
keepalive = util.convert(conf.get(CONF_KEEPALIVE), int, DEFAULT_KEEPALIVE)
|
keepalive = conf.get(CONF_KEEPALIVE)
|
||||||
|
|
||||||
broker_config = _setup_server(hass, config)
|
broker_config = _setup_server(hass, config)
|
||||||
|
|
||||||
|
@ -151,16 +169,11 @@ def setup(hass, config):
|
||||||
|
|
||||||
if CONF_BROKER in conf:
|
if CONF_BROKER in conf:
|
||||||
broker = conf[CONF_BROKER]
|
broker = conf[CONF_BROKER]
|
||||||
port = util.convert(conf.get(CONF_PORT), int, DEFAULT_PORT)
|
port = conf[CONF_PORT]
|
||||||
username = util.convert(conf.get(CONF_USERNAME), str)
|
username = conf.get(CONF_USERNAME)
|
||||||
password = util.convert(conf.get(CONF_PASSWORD), str)
|
password = conf.get(CONF_PASSWORD)
|
||||||
certificate = util.convert(conf.get(CONF_CERTIFICATE), str)
|
certificate = conf.get(CONF_CERTIFICATE)
|
||||||
protocol = util.convert(conf.get(CONF_PROTOCOL), str, DEFAULT_PROTOCOL)
|
protocol = conf[CONF_PROTOCOL]
|
||||||
|
|
||||||
if protocol not in (PROTOCOL_31, PROTOCOL_311):
|
|
||||||
_LOGGER.error('Invalid protocol specified: %s. Allowed values: %s, %s',
|
|
||||||
protocol, PROTOCOL_31, PROTOCOL_311)
|
|
||||||
return False
|
|
||||||
|
|
||||||
# For cloudmqtt.com, secured connection, auto fill in certificate
|
# For cloudmqtt.com, secured connection, auto fill in certificate
|
||||||
if certificate is None and 19999 < port < 30000 and \
|
if certificate is None and 19999 < port < 30000 and \
|
||||||
|
|
|
@ -4,6 +4,7 @@ from datetime import timedelta
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
from homeassistant import core as ha, loader
|
from homeassistant import core as ha, loader
|
||||||
|
from homeassistant.bootstrap import _setup_component
|
||||||
from homeassistant.helpers.entity import ToggleEntity
|
from homeassistant.helpers.entity import ToggleEntity
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
STATE_ON, STATE_OFF, DEVICE_DEFAULT_NAME, EVENT_TIME_CHANGED,
|
STATE_ON, STATE_OFF, DEVICE_DEFAULT_NAME, EVENT_TIME_CHANGED,
|
||||||
|
@ -123,7 +124,7 @@ def mock_http_component(hass):
|
||||||
@mock.patch('homeassistant.components.mqtt.MQTT')
|
@mock.patch('homeassistant.components.mqtt.MQTT')
|
||||||
def mock_mqtt_component(hass, mock_mqtt):
|
def mock_mqtt_component(hass, mock_mqtt):
|
||||||
"""Mock the MQTT component."""
|
"""Mock the MQTT component."""
|
||||||
mqtt.setup(hass, {
|
_setup_component(hass, mqtt.DOMAIN, {
|
||||||
mqtt.DOMAIN: {
|
mqtt.DOMAIN: {
|
||||||
mqtt.CONF_BROKER: 'mock-broker',
|
mqtt.CONF_BROKER: 'mock-broker',
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import unittest
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
|
from homeassistant.bootstrap import _setup_component
|
||||||
import homeassistant.components.mqtt as mqtt
|
import homeassistant.components.mqtt as mqtt
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
EVENT_CALL_SERVICE, ATTR_DOMAIN, ATTR_SERVICE, EVENT_HOMEASSISTANT_START,
|
EVENT_CALL_SERVICE, ATTR_DOMAIN, ATTR_SERVICE, EVENT_HOMEASSISTANT_START,
|
||||||
|
@ -48,9 +49,11 @@ class TestMQTT(unittest.TestCase):
|
||||||
"""Test for setup failure if connection to broker is missing."""
|
"""Test for setup failure if connection to broker is missing."""
|
||||||
with mock.patch('homeassistant.components.mqtt.MQTT',
|
with mock.patch('homeassistant.components.mqtt.MQTT',
|
||||||
side_effect=socket.error()):
|
side_effect=socket.error()):
|
||||||
self.assertFalse(mqtt.setup(self.hass, {mqtt.DOMAIN: {
|
assert not _setup_component(self.hass, mqtt.DOMAIN, {
|
||||||
mqtt.CONF_BROKER: 'test-broker',
|
mqtt.DOMAIN: {
|
||||||
}}))
|
mqtt.CONF_BROKER: 'test-broker',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
def test_publish_calls_service(self):
|
def test_publish_calls_service(self):
|
||||||
"""Test the publishing of call to services."""
|
"""Test the publishing of call to services."""
|
||||||
|
@ -211,7 +214,7 @@ class TestMQTTCallbacks(unittest.TestCase):
|
||||||
# mock_mqtt_component(self.hass)
|
# mock_mqtt_component(self.hass)
|
||||||
|
|
||||||
with mock.patch('paho.mqtt.client.Client'):
|
with mock.patch('paho.mqtt.client.Client'):
|
||||||
mqtt.setup(self.hass, {
|
_setup_component(self.hass, mqtt.DOMAIN, {
|
||||||
mqtt.DOMAIN: {
|
mqtt.DOMAIN: {
|
||||||
mqtt.CONF_BROKER: 'mock-broker',
|
mqtt.CONF_BROKER: 'mock-broker',
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
"""The tests for the MQTT component embedded server."""
|
"""The tests for the MQTT component embedded server."""
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
|
from homeassistant.bootstrap import _setup_component
|
||||||
import homeassistant.components.mqtt as mqtt
|
import homeassistant.components.mqtt as mqtt
|
||||||
|
|
||||||
from tests.common import get_test_home_assistant
|
from tests.common import get_test_home_assistant
|
||||||
|
@ -27,15 +28,20 @@ class TestMQTT:
|
||||||
password = 'super_secret'
|
password = 'super_secret'
|
||||||
|
|
||||||
self.hass.config.api = MagicMock(api_password=password)
|
self.hass.config.api = MagicMock(api_password=password)
|
||||||
assert mqtt.setup(self.hass, {})
|
assert _setup_component(self.hass, mqtt.DOMAIN, {})
|
||||||
assert mock_mqtt.called
|
assert mock_mqtt.called
|
||||||
assert mock_mqtt.mock_calls[0][1][5] == 'homeassistant'
|
assert mock_mqtt.mock_calls[0][1][5] == 'homeassistant'
|
||||||
assert mock_mqtt.mock_calls[0][1][6] == password
|
assert mock_mqtt.mock_calls[0][1][6] == password
|
||||||
|
|
||||||
mock_mqtt.reset_mock()
|
@patch('homeassistant.components.mqtt.MQTT')
|
||||||
|
@patch('asyncio.gather')
|
||||||
|
@patch('asyncio.new_event_loop')
|
||||||
|
def test_creating_config_no_http_pass(self, mock_new_loop, mock_gather,
|
||||||
|
mock_mqtt):
|
||||||
|
"""Test if the MQTT server gets started and subscribe/publish msg."""
|
||||||
|
self.hass.config.components.append('http')
|
||||||
self.hass.config.api = MagicMock(api_password=None)
|
self.hass.config.api = MagicMock(api_password=None)
|
||||||
assert mqtt.setup(self.hass, {})
|
assert _setup_component(self.hass, mqtt.DOMAIN, {})
|
||||||
assert mock_mqtt.called
|
assert mock_mqtt.called
|
||||||
assert mock_mqtt.mock_calls[0][1][5] is None
|
assert mock_mqtt.mock_calls[0][1][5] is None
|
||||||
assert mock_mqtt.mock_calls[0][1][6] is None
|
assert mock_mqtt.mock_calls[0][1][6] is None
|
||||||
|
@ -50,6 +56,6 @@ class TestMQTT:
|
||||||
mock_gather.side_effect = BrokerException
|
mock_gather.side_effect = BrokerException
|
||||||
|
|
||||||
self.hass.config.api = MagicMock(api_password=None)
|
self.hass.config.api = MagicMock(api_password=None)
|
||||||
assert not mqtt.setup(self.hass, {
|
assert not _setup_component(self.hass, mqtt.DOMAIN, {
|
||||||
'mqtt': {'embedded': {}}
|
mqtt.DOMAIN: {mqtt.CONF_EMBEDDED: {}}
|
||||||
})
|
})
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue