Merge pull request #1703 from jaharkes/config-validation-mqtt

Config validation for MQTT
This commit is contained in:
Paulus Schoutsen 2016-04-07 08:43:01 -07:00
commit 5ff9479f0b
25 changed files with 512 additions and 299 deletions

View file

@ -12,6 +12,7 @@ from homeassistant.const import (
ATTR_CODE, ATTR_CODE_FORMAT, ATTR_ENTITY_ID, SERVICE_ALARM_TRIGGER,
SERVICE_ALARM_DISARM, SERVICE_ALARM_ARM_HOME, SERVICE_ALARM_ARM_AWAY)
from homeassistant.config import load_yaml_config_file
from homeassistant.helpers.config_validation import PLATFORM_SCHEMA # noqa
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity_component import EntityComponent

View file

@ -6,43 +6,55 @@ https://home-assistant.io/components/alarm_control_panel.mqtt/
"""
import logging
import voluptuous as vol
import homeassistant.components.alarm_control_panel as alarm
import homeassistant.components.mqtt as mqtt
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, STATE_ALARM_DISARMED,
STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED, STATE_UNKNOWN)
STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED, STATE_UNKNOWN,
CONF_NAME)
from homeassistant.components.mqtt import (
CONF_STATE_TOPIC, CONF_COMMAND_TOPIC, CONF_QOS)
import homeassistant.helpers.config_validation as cv
_LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = "MQTT Alarm"
DEFAULT_QOS = 0
DEFAULT_PAYLOAD_DISARM = "DISARM"
DEFAULT_PAYLOAD_ARM_HOME = "ARM_HOME"
DEFAULT_PAYLOAD_ARM_AWAY = "ARM_AWAY"
DEPENDENCIES = ['mqtt']
CONF_PAYLOAD_DISARM = 'payload_disarm'
CONF_PAYLOAD_ARM_HOME = 'payload_arm_home'
CONF_PAYLOAD_ARM_AWAY = 'payload_arm_away'
CONF_CODE = 'code'
DEFAULT_NAME = "MQTT Alarm"
DEFAULT_DISARM = "DISARM"
DEFAULT_ARM_HOME = "ARM_HOME"
DEFAULT_ARM_AWAY = "ARM_AWAY"
PLATFORM_SCHEMA = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend({
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Required(CONF_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Required(CONF_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_PAYLOAD_DISARM, default=DEFAULT_DISARM): cv.string,
vol.Optional(CONF_PAYLOAD_ARM_HOME, default=DEFAULT_ARM_HOME): cv.string,
vol.Optional(CONF_PAYLOAD_ARM_AWAY, default=DEFAULT_ARM_AWAY): cv.string,
vol.Optional(CONF_CODE): cv.string,
})
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Setup the MQTT platform."""
if config.get('state_topic') is None:
_LOGGER.error("Missing required variable: state_topic")
return False
if config.get('command_topic') is None:
_LOGGER.error("Missing required variable: command_topic")
return False
add_devices([MqttAlarm(
hass,
config.get('name', DEFAULT_NAME),
config.get('state_topic'),
config.get('command_topic'),
config.get('qos', DEFAULT_QOS),
config.get('payload_disarm', DEFAULT_PAYLOAD_DISARM),
config.get('payload_arm_home', DEFAULT_PAYLOAD_ARM_HOME),
config.get('payload_arm_away', DEFAULT_PAYLOAD_ARM_AWAY),
config.get('code'))])
config[CONF_NAME],
config[CONF_STATE_TOPIC],
config[CONF_COMMAND_TOPIC],
config[CONF_QOS],
config[CONF_PAYLOAD_DISARM],
config[CONF_PAYLOAD_ARM_HOME],
config[CONF_PAYLOAD_ARM_AWAY],
config.get(CONF_CODE))])
# pylint: disable=too-many-arguments, too-many-instance-attributes
@ -62,7 +74,7 @@ class MqttAlarm(alarm.AlarmControlPanel):
self._payload_disarm = payload_disarm
self._payload_arm_home = payload_arm_home
self._payload_arm_away = payload_arm_away
self._code = str(code) if code else None
self._code = code
def message_received(topic, payload, qos):
"""A new MQTT message has been received."""

View file

@ -4,26 +4,29 @@ Offer MQTT listening automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/components/automation/#mqtt-trigger
"""
import logging
import voluptuous as vol
import homeassistant.components.mqtt as mqtt
from homeassistant.const import CONF_PLATFORM
import homeassistant.helpers.config_validation as cv
DEPENDENCIES = ['mqtt']
CONF_TOPIC = 'topic'
CONF_PAYLOAD = 'payload'
TRIGGER_SCHEMA = vol.Schema({
vol.Required(CONF_PLATFORM): mqtt.DOMAIN,
vol.Required(CONF_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_PAYLOAD): cv.string,
})
def trigger(hass, config, action):
"""Listen for state changes based on configuration."""
topic = config.get(CONF_TOPIC)
topic = config[CONF_TOPIC]
payload = config.get(CONF_PAYLOAD)
if topic is None:
logging.getLogger(__name__).error(
"Missing configuration key %s", CONF_TOPIC)
return False
def mqtt_automation_listener(msg_topic, msg_payload, qos):
"""Listen for MQTT messages."""
if payload is None or payload == msg_payload:

View file

@ -6,43 +6,50 @@ https://home-assistant.io/components/binary_sensor.mqtt/
"""
import logging
import voluptuous as vol
import homeassistant.components.mqtt as mqtt
from homeassistant.components.binary_sensor import (BinarySensorDevice,
SENSOR_CLASSES)
from homeassistant.const import CONF_VALUE_TEMPLATE
from homeassistant.const import CONF_NAME, CONF_VALUE_TEMPLATE
from homeassistant.components.mqtt import CONF_STATE_TOPIC, CONF_QOS
from homeassistant.helpers import template
import homeassistant.helpers.config_validation as cv
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['mqtt']
CONF_SENSOR_CLASS = 'sensor_class'
CONF_PAYLOAD_ON = 'payload_on'
CONF_PAYLOAD_OFF = 'payload_off'
DEFAULT_NAME = 'MQTT Binary sensor'
DEFAULT_QOS = 0
DEFAULT_PAYLOAD_ON = 'ON'
DEFAULT_PAYLOAD_OFF = 'OFF'
DEPENDENCIES = ['mqtt']
PLATFORM_SCHEMA = mqtt.MQTT_RO_PLATFORM_SCHEMA.extend({
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_SENSOR_CLASS, default=None):
vol.Any(vol.In(SENSOR_CLASSES), vol.SetTo(None)),
vol.Optional(CONF_PAYLOAD_ON, default=DEFAULT_PAYLOAD_ON): cv.string,
vol.Optional(CONF_PAYLOAD_OFF, default=DEFAULT_PAYLOAD_OFF): cv.string,
})
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Add MQTT binary sensor."""
if config.get('state_topic') is None:
_LOGGER.error('Missing required variable: state_topic')
return False
sensor_class = config.get('sensor_class')
if sensor_class not in SENSOR_CLASSES:
_LOGGER.warning('Unknown sensor class: %s', sensor_class)
sensor_class = None
add_devices([MqttBinarySensor(
hass,
config.get('name', DEFAULT_NAME),
config.get('state_topic', None),
sensor_class,
config.get('qos', DEFAULT_QOS),
config.get('payload_on', DEFAULT_PAYLOAD_ON),
config.get('payload_off', DEFAULT_PAYLOAD_OFF),
config.get(CONF_VALUE_TEMPLATE))])
config[CONF_NAME],
config[CONF_STATE_TOPIC],
config[CONF_SENSOR_CLASS],
config[CONF_QOS],
config[CONF_PAYLOAD_ON],
config[CONF_PAYLOAD_OFF],
config.get(CONF_VALUE_TEMPLATE)
)])
# pylint: disable=too-many-arguments, too-many-instance-attributes

View file

@ -6,28 +6,27 @@ https://home-assistant.io/components/device_tracker.mqtt/
"""
import logging
import voluptuous as vol
import homeassistant.components.mqtt as mqtt
from homeassistant import util
from homeassistant.components.mqtt import CONF_QOS
import homeassistant.helpers.config_validation as cv
DEPENDENCIES = ['mqtt']
CONF_QOS = 'qos'
CONF_DEVICES = 'devices'
DEFAULT_QOS = 0
_LOGGER = logging.getLogger(__name__)
PLATFORM_SCHEMA = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend({
vol.Required(CONF_DEVICES): {cv.string: mqtt.valid_subscribe_topic},
})
def setup_scanner(hass, config, see):
"""Setup the MQTT tracker."""
devices = config.get(CONF_DEVICES)
qos = util.convert(config.get(CONF_QOS), int, DEFAULT_QOS)
if not isinstance(devices, dict):
_LOGGER.error('Expected %s to be a dict, found %s', CONF_DEVICES,
devices)
return False
devices = config[CONF_DEVICES]
qos = config[CONF_QOS]
dev_id_lookup = {}

View file

@ -7,46 +7,85 @@ https://home-assistant.io/components/light.mqtt/
import logging
from functools import partial
import voluptuous as vol
import homeassistant.components.mqtt as mqtt
from homeassistant.components.light import (
ATTR_BRIGHTNESS, ATTR_RGB_COLOR, Light)
from homeassistant.const import CONF_NAME, CONF_OPTIMISTIC, CONF_VALUE_TEMPLATE
from homeassistant.components.mqtt import (
CONF_STATE_TOPIC, CONF_COMMAND_TOPIC, CONF_QOS, CONF_RETAIN)
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.template import render_with_possible_json_value
from homeassistant.util import convert
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['mqtt']
CONF_STATE_VALUE_TEMPLATE = 'state_value_template'
CONF_BRIGHTNESS_STATE_TOPIC = 'brightness_state_topic'
CONF_BRIGHTNESS_COMMAND_TOPIC = 'brightness_command_topic'
CONF_BRIGHTNESS_VALUE_TEMPLATE = 'brightness_value_template'
CONF_RGB_STATE_TOPIC = 'rgb_state_topic'
CONF_RGB_COMMAND_TOPIC = 'rgb_command_topic'
CONF_RGB_VALUE_TEMPLATE = 'rgb_value_template'
CONF_PAYLOAD_ON = 'payload_on'
CONF_PAYLOAD_OFF = 'payload_off'
CONF_BRIGHTNESS_SCALE = 'brightness_scale'
DEFAULT_NAME = 'MQTT Light'
DEFAULT_QOS = 0
DEFAULT_PAYLOAD_ON = 'ON'
DEFAULT_PAYLOAD_OFF = 'OFF'
DEFAULT_OPTIMISTIC = False
DEFAULT_BRIGHTNESS_SCALE = 255
DEPENDENCIES = ['mqtt']
PLATFORM_SCHEMA = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend({
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_STATE_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_BRIGHTNESS_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_BRIGHTNESS_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_BRIGHTNESS_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_RGB_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_RGB_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_RGB_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_PAYLOAD_ON, default=DEFAULT_PAYLOAD_ON): cv.string,
vol.Optional(CONF_PAYLOAD_OFF, default=DEFAULT_PAYLOAD_OFF): cv.string,
vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean,
vol.Optional(CONF_BRIGHTNESS_SCALE, default=DEFAULT_BRIGHTNESS_SCALE):
vol.All(vol.Coerce(int), vol.Range(min=1)),
})
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
"""Add MQTT Light."""
if config.get('command_topic') is None:
_LOGGER.error("Missing required variable: command_topic")
return False
config.setdefault(CONF_STATE_VALUE_TEMPLATE,
config.get(CONF_VALUE_TEMPLATE))
add_devices_callback([MqttLight(
hass,
convert(config.get('name'), str, DEFAULT_NAME),
{key: convert(config.get(key), str) for key in
(typ + topic
for typ in ('', 'brightness_', 'rgb_')
for topic in ('state_topic', 'command_topic'))},
{key: convert(config.get(key + '_value_template'), str)
for key in ('state', 'brightness', 'rgb')},
convert(config.get('qos'), int, DEFAULT_QOS),
config[CONF_NAME],
{
'on': convert(config.get('payload_on'), str, DEFAULT_PAYLOAD_ON),
'off': convert(config.get('payload_off'), str, DEFAULT_PAYLOAD_OFF)
key: config.get(key) for key in (
CONF_STATE_TOPIC,
CONF_COMMAND_TOPIC,
CONF_BRIGHTNESS_STATE_TOPIC,
CONF_BRIGHTNESS_COMMAND_TOPIC,
CONF_RGB_STATE_TOPIC,
CONF_RGB_COMMAND_TOPIC,
)
},
convert(config.get('optimistic'), bool, DEFAULT_OPTIMISTIC),
convert(config.get('brightness_scale'), int, DEFAULT_BRIGHTNESS_SCALE)
{
'state': config.get(CONF_STATE_VALUE_TEMPLATE),
'brightness': config.get(CONF_BRIGHTNESS_VALUE_TEMPLATE),
'rgb': config.get(CONF_RGB_VALUE_TEMPLATE)
},
config[CONF_QOS],
config[CONF_RETAIN],
{
'on': config[CONF_PAYLOAD_ON],
'off': config[CONF_PAYLOAD_OFF],
},
config[CONF_OPTIMISTIC],
config[CONF_BRIGHTNESS_SCALE],
)])
@ -54,13 +93,14 @@ class MqttLight(Light):
"""MQTT light."""
# pylint: disable=too-many-arguments,too-many-instance-attributes
def __init__(self, hass, name, topic, templates, qos, payload, optimistic,
brightness_scale):
def __init__(self, hass, name, topic, templates, qos, retain, payload,
optimistic, brightness_scale):
"""Initialize MQTT light."""
self._hass = hass
self._name = name
self._topic = topic
self._qos = qos
self._retain = retain
self._payload = payload
self._optimistic = optimistic or topic["state_topic"] is None
self._optimistic_rgb = optimistic or topic["rgb_state_topic"] is None
@ -156,7 +196,8 @@ class MqttLight(Light):
self._topic["rgb_command_topic"] is not None:
mqtt.publish(self._hass, self._topic["rgb_command_topic"],
"{},{},{}".format(*kwargs[ATTR_RGB_COLOR]), self._qos)
"{},{},{}".format(*kwargs[ATTR_RGB_COLOR]),
self._qos, self._retain)
if self._optimistic_rgb:
self._rgb = kwargs[ATTR_RGB_COLOR]
@ -167,14 +208,14 @@ class MqttLight(Light):
percent_bright = float(kwargs[ATTR_BRIGHTNESS]) / 255
device_brightness = int(percent_bright * self._brightness_scale)
mqtt.publish(self._hass, self._topic["brightness_command_topic"],
device_brightness, self._qos)
device_brightness, self._qos, self._retain)
if self._optimistic_brightness:
self._brightness = kwargs[ATTR_BRIGHTNESS]
should_update = True
mqtt.publish(self._hass, self._topic["command_topic"],
self._payload["on"], self._qos)
self._payload["on"], self._qos, self._retain)
if self._optimistic:
# Optimistically assume that switch has changed state.
@ -187,7 +228,7 @@ class MqttLight(Light):
def turn_off(self, **kwargs):
"""Turn the device off."""
mqtt.publish(self._hass, self._topic["command_topic"],
self._payload["off"], self._qos)
self._payload["off"], self._qos, self._retain)
if self._optimistic:
# Optimistically assume that switch has changed state.

View file

@ -6,40 +6,51 @@ https://home-assistant.io/components/lock.mqtt/
"""
import logging
import voluptuous as vol
import homeassistant.components.mqtt as mqtt
from homeassistant.components.lock import LockDevice
from homeassistant.const import CONF_VALUE_TEMPLATE
from homeassistant.const import CONF_NAME, CONF_OPTIMISTIC, CONF_VALUE_TEMPLATE
from homeassistant.components.mqtt import (
CONF_STATE_TOPIC, CONF_COMMAND_TOPIC, CONF_QOS, CONF_RETAIN)
from homeassistant.helpers import template
import homeassistant.helpers.config_validation as cv
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['mqtt']
CONF_PAYLOAD_LOCK = 'payload_lock'
CONF_PAYLOAD_UNLOCK = 'payload_unlock'
DEFAULT_NAME = "MQTT Lock"
DEFAULT_PAYLOAD_LOCK = "LOCK"
DEFAULT_PAYLOAD_UNLOCK = "UNLOCK"
DEFAULT_QOS = 0
DEFAULT_OPTIMISTIC = False
DEFAULT_RETAIN = False
DEPENDENCIES = ['mqtt']
PLATFORM_SCHEMA = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend({
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_PAYLOAD_LOCK, default=DEFAULT_PAYLOAD_LOCK):
cv.string,
vol.Optional(CONF_PAYLOAD_UNLOCK, default=DEFAULT_PAYLOAD_UNLOCK):
cv.string,
vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean,
})
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
"""Setup the MQTT lock."""
if config.get('command_topic') is None:
_LOGGER.error("Missing required variable: command_topic")
return False
add_devices_callback([MqttLock(
hass,
config.get('name', DEFAULT_NAME),
config.get('state_topic'),
config.get('command_topic'),
config.get('qos', DEFAULT_QOS),
config.get('retain', DEFAULT_RETAIN),
config.get('payload_lock', DEFAULT_PAYLOAD_LOCK),
config.get('payload_unlock', DEFAULT_PAYLOAD_UNLOCK),
config.get('optimistic', DEFAULT_OPTIMISTIC),
config[CONF_NAME],
config.get(CONF_STATE_TOPIC),
config[CONF_COMMAND_TOPIC],
config[CONF_QOS],
config[CONF_RETAIN],
config[CONF_PAYLOAD_LOCK],
config[CONF_PAYLOAD_UNLOCK],
config[CONF_OPTIMISTIC],
config.get(CONF_VALUE_TEMPLATE))])

View file

@ -14,11 +14,11 @@ import voluptuous as vol
from homeassistant.bootstrap import prepare_setup_platform
from homeassistant.config import load_yaml_config_file
from homeassistant.exceptions import HomeAssistantError
import homeassistant.util as util
from homeassistant.helpers import template
import homeassistant.helpers.config_validation as cv
from homeassistant.const import (
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP)
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP,
CONF_PLATFORM, CONF_SCAN_INTERVAL, CONF_VALUE_TEMPLATE)
_LOGGER = logging.getLogger(__name__)
@ -41,6 +41,11 @@ CONF_PASSWORD = 'password'
CONF_CERTIFICATE = 'certificate'
CONF_PROTOCOL = 'protocol'
CONF_STATE_TOPIC = 'state_topic'
CONF_COMMAND_TOPIC = 'command_topic'
CONF_QOS = 'qos'
CONF_RETAIN = 'retain'
PROTOCOL_31 = '3.1'
PROTOCOL_311 = '3.1.1'
@ -53,25 +58,71 @@ DEFAULT_PROTOCOL = PROTOCOL_311
ATTR_TOPIC = 'topic'
ATTR_PAYLOAD = 'payload'
ATTR_PAYLOAD_TEMPLATE = 'payload_template'
ATTR_QOS = 'qos'
ATTR_RETAIN = 'retain'
ATTR_QOS = CONF_QOS
ATTR_RETAIN = CONF_RETAIN
MAX_RECONNECT_WAIT = 300 # seconds
# Service call validation schema
def mqtt_topic(value):
"""Validate that we can publish using this MQTT topic."""
if isinstance(value, str) and all(c not in value for c in '#+\0'):
def valid_subscribe_topic(value, invalid_chars='\0'):
"""Validate that we can subscribe using this MQTT topic."""
if isinstance(value, str) and all(c not in value for c in invalid_chars):
return vol.Length(min=1, max=65535)(value)
raise vol.Invalid('Invalid MQTT topic name')
def valid_publish_topic(value):
"""Validate that we can publish using this MQTT topic."""
return valid_subscribe_topic(value, invalid_chars='#+\0')
_VALID_QOS_SCHEMA = vol.All(vol.Coerce(int), vol.In([0, 1, 2]))
_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,
}),
}, extra=vol.ALLOW_EXTRA)
MQTT_BASE_PLATFORM_SCHEMA = vol.Schema({
vol.Required(CONF_PLATFORM): DOMAIN,
vol.Optional(CONF_SCAN_INTERVAL):
vol.All(vol.Coerce(int), vol.Range(min=1)),
vol.Optional(CONF_QOS, default=DEFAULT_QOS): _VALID_QOS_SCHEMA,
})
# Sensor type platforms subscribe to mqtt events
MQTT_RO_PLATFORM_SCHEMA = MQTT_BASE_PLATFORM_SCHEMA.extend({
vol.Required(CONF_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
})
# Switch type platforms publish to mqtt and may subscribe
MQTT_RW_PLATFORM_SCHEMA = MQTT_BASE_PLATFORM_SCHEMA.extend({
vol.Required(CONF_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_RETAIN, default=DEFAULT_RETAIN): cv.boolean,
vol.Optional(CONF_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
})
# Service call validation schema
MQTT_PUBLISH_SCHEMA = vol.Schema({
vol.Required(ATTR_TOPIC): mqtt_topic,
vol.Required(ATTR_TOPIC): valid_publish_topic,
vol.Exclusive(ATTR_PAYLOAD, 'payload'): object,
vol.Exclusive(ATTR_PAYLOAD_TEMPLATE, 'payload'): cv.string,
vol.Required(ATTR_QOS, default=DEFAULT_QOS):
vol.All(vol.Coerce(int), vol.In([0, 1, 2])),
vol.Required(ATTR_QOS, default=DEFAULT_QOS): _VALID_QOS_SCHEMA,
vol.Required(ATTR_RETAIN, default=DEFAULT_RETAIN): cv.boolean,
}, required=True)
@ -136,8 +187,8 @@ def setup(hass, config):
# pylint: disable=too-many-locals
conf = config.get(DOMAIN, {})
client_id = util.convert(conf.get(CONF_CLIENT_ID), str)
keepalive = util.convert(conf.get(CONF_KEEPALIVE), int, DEFAULT_KEEPALIVE)
client_id = conf.get(CONF_CLIENT_ID)
keepalive = conf.get(CONF_KEEPALIVE)
broker_config = _setup_server(hass, config)
@ -151,16 +202,11 @@ def setup(hass, config):
if CONF_BROKER in conf:
broker = conf[CONF_BROKER]
port = util.convert(conf.get(CONF_PORT), int, DEFAULT_PORT)
username = util.convert(conf.get(CONF_USERNAME), str)
password = util.convert(conf.get(CONF_PASSWORD), str)
certificate = util.convert(conf.get(CONF_CERTIFICATE), str)
protocol = util.convert(conf.get(CONF_PROTOCOL), str, DEFAULT_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
port = conf[CONF_PORT]
username = conf.get(CONF_USERNAME)
password = conf.get(CONF_PASSWORD)
certificate = conf.get(CONF_CERTIFICATE)
protocol = conf[CONF_PROTOCOL]
# For cloudmqtt.com, secured connection, auto fill in certificate
if certificate is None and 19999 < port < 30000 and \

View file

@ -6,9 +6,11 @@ https://home-assistant.io/components/mqtt_eventstream/
"""
import json
import voluptuous as vol
import homeassistant.loader as loader
from homeassistant.components.mqtt import DOMAIN as MQTT_DOMAIN
from homeassistant.components.mqtt import SERVICE_PUBLISH as MQTT_SVC_PUBLISH
from homeassistant.components.mqtt import (
valid_publish_topic, valid_subscribe_topic)
from homeassistant.const import (
ATTR_SERVICE_DATA, EVENT_CALL_SERVICE, EVENT_SERVICE_EXECUTED,
EVENT_STATE_CHANGED, EVENT_TIME_CHANGED, MATCH_ALL)
@ -18,12 +20,23 @@ from homeassistant.remote import JSONEncoder
DOMAIN = "mqtt_eventstream"
DEPENDENCIES = ['mqtt']
CONF_PUBLISH_TOPIC = 'publish_topic'
CONF_SUBSCRIBE_TOPIC = 'subscribe_topic'
CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({
vol.Optional(CONF_PUBLISH_TOPIC): valid_publish_topic,
vol.Optional(CONF_SUBSCRIBE_TOPIC): valid_subscribe_topic,
}),
}, extra=vol.ALLOW_EXTRA)
def setup(hass, config):
"""Setup th MQTT eventstream component."""
"""Setup the MQTT eventstream component."""
mqtt = loader.get_component('mqtt')
pub_topic = config[DOMAIN].get('publish_topic', None)
sub_topic = config[DOMAIN].get('subscribe_topic', None)
conf = config.get(DOMAIN, {})
pub_topic = conf.get(CONF_PUBLISH_TOPIC)
sub_topic = conf.get(CONF_SUBSCRIBE_TOPIC)
def _event_publisher(event):
"""Handle events by publishing them on the MQTT queue."""
@ -36,8 +49,8 @@ def setup(hass, config):
# to the MQTT topic, or you will end up in an infinite loop.
if event.event_type == EVENT_CALL_SERVICE:
if (
event.data.get('domain') == MQTT_DOMAIN and
event.data.get('service') == MQTT_SVC_PUBLISH and
event.data.get('domain') == mqtt.DOMAIN and
event.data.get('service') == mqtt.SERVICE_PUBLISH and
event.data[ATTR_SERVICE_DATA].get('topic') == pub_topic
):
return

View file

@ -9,7 +9,8 @@ import logging
import homeassistant.bootstrap as bootstrap
from homeassistant.const import (
ATTR_DISCOVERED, ATTR_SERVICE, EVENT_HOMEASSISTANT_START,
EVENT_HOMEASSISTANT_STOP, EVENT_PLATFORM_DISCOVERED, TEMP_CELCIUS)
EVENT_HOMEASSISTANT_STOP, EVENT_PLATFORM_DISCOVERED, TEMP_CELCIUS,
CONF_OPTIMISTIC)
from homeassistant.helpers import validate_config
CONF_GATEWAYS = 'gateways'
@ -19,7 +20,6 @@ CONF_PERSISTENCE = 'persistence'
CONF_PERSISTENCE_FILE = 'persistence_file'
CONF_VERSION = 'version'
CONF_BAUD_RATE = 'baud_rate'
CONF_OPTIMISTIC = 'optimistic'
DEFAULT_VERSION = '1.4'
DEFAULT_BAUD_RATE = 115200

View file

@ -6,38 +6,50 @@ https://home-assistant.io/components/rollershutter.mqtt/
"""
import logging
import voluptuous as vol
import homeassistant.components.mqtt as mqtt
from homeassistant.components.rollershutter import RollershutterDevice
from homeassistant.const import CONF_VALUE_TEMPLATE
from homeassistant.const import CONF_NAME, CONF_VALUE_TEMPLATE
from homeassistant.components.mqtt import (
CONF_STATE_TOPIC, CONF_COMMAND_TOPIC, CONF_QOS)
from homeassistant.helpers import template
import homeassistant.helpers.config_validation as cv
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['mqtt']
CONF_PAYLOAD_UP = 'payload_up'
CONF_PAYLOAD_DOWN = 'payload_down'
CONF_PAYLOAD_STOP = 'payload_stop'
DEFAULT_NAME = "MQTT Rollershutter"
DEFAULT_QOS = 0
DEFAULT_PAYLOAD_UP = "UP"
DEFAULT_PAYLOAD_DOWN = "DOWN"
DEFAULT_PAYLOAD_STOP = "STOP"
PLATFORM_SCHEMA = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend({
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_PAYLOAD_UP, default=DEFAULT_PAYLOAD_UP): cv.string,
vol.Optional(CONF_PAYLOAD_DOWN, default=DEFAULT_PAYLOAD_DOWN): cv.string,
vol.Optional(CONF_PAYLOAD_STOP, default=DEFAULT_PAYLOAD_STOP): cv.string,
})
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
"""Add MQTT Rollershutter."""
if config.get('command_topic') is None:
_LOGGER.error("Missing required variable: command_topic")
return False
add_devices_callback([MqttRollershutter(
hass,
config.get('name', DEFAULT_NAME),
config.get('state_topic'),
config.get('command_topic'),
config.get('qos', DEFAULT_QOS),
config.get('payload_up', DEFAULT_PAYLOAD_UP),
config.get('payload_down', DEFAULT_PAYLOAD_DOWN),
config.get('payload_stop', DEFAULT_PAYLOAD_STOP),
config.get(CONF_VALUE_TEMPLATE))])
config[CONF_NAME],
config.get(CONF_STATE_TOPIC),
config[CONF_COMMAND_TOPIC],
config[CONF_QOS],
config[CONF_PAYLOAD_UP],
config[CONF_PAYLOAD_DOWN],
config[CONF_PAYLOAD_STOP],
config.get(CONF_VALUE_TEMPLATE)
)])
# pylint: disable=too-many-arguments, too-many-instance-attributes

View file

@ -6,33 +6,40 @@ https://home-assistant.io/components/sensor.mqtt/
"""
import logging
import voluptuous as vol
import homeassistant.components.mqtt as mqtt
from homeassistant.const import CONF_VALUE_TEMPLATE, STATE_UNKNOWN
from homeassistant.const import CONF_NAME, CONF_VALUE_TEMPLATE, STATE_UNKNOWN
from homeassistant.components.mqtt import CONF_STATE_TOPIC, CONF_QOS
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity
from homeassistant.helpers import template
_LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = "MQTT Sensor"
DEFAULT_QOS = 0
DEPENDENCIES = ['mqtt']
CONF_UNIT_OF_MEASUREMENT = 'unit_of_measurement'
DEFAULT_NAME = "MQTT Sensor"
PLATFORM_SCHEMA = mqtt.MQTT_RO_PLATFORM_SCHEMA.extend({
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string,
})
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
"""Setup MQTT Sensor."""
if config.get('state_topic') is None:
_LOGGER.error("Missing required variable: state_topic")
return False
add_devices_callback([MqttSensor(
hass,
config.get('name', DEFAULT_NAME),
config.get('state_topic'),
config.get('qos', DEFAULT_QOS),
config.get('unit_of_measurement'),
config.get(CONF_VALUE_TEMPLATE))])
config[CONF_NAME],
config[CONF_STATE_TOPIC],
config[CONF_QOS],
config.get(CONF_UNIT_OF_MEASUREMENT),
config.get(CONF_VALUE_TEMPLATE),
)])
# pylint: disable=too-many-arguments, too-many-instance-attributes

View file

@ -6,41 +6,49 @@ https://home-assistant.io/components/switch.mqtt/
"""
import logging
import voluptuous as vol
import homeassistant.components.mqtt as mqtt
from homeassistant.components.switch import SwitchDevice
from homeassistant.const import CONF_VALUE_TEMPLATE
from homeassistant.const import CONF_NAME, CONF_OPTIMISTIC, CONF_VALUE_TEMPLATE
from homeassistant.components.mqtt import (
CONF_STATE_TOPIC, CONF_COMMAND_TOPIC, CONF_QOS, CONF_RETAIN)
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers import template
from homeassistant.util import convert
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['mqtt']
CONF_PAYLOAD_ON = 'payload_on'
CONF_PAYLOAD_OFF = 'payload_off'
DEFAULT_NAME = "MQTT Switch"
DEFAULT_QOS = 0
DEFAULT_PAYLOAD_ON = "ON"
DEFAULT_PAYLOAD_OFF = "OFF"
DEFAULT_OPTIMISTIC = False
DEFAULT_RETAIN = False
DEPENDENCIES = ['mqtt']
PLATFORM_SCHEMA = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend({
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_PAYLOAD_ON, default=DEFAULT_PAYLOAD_ON): cv.string,
vol.Optional(CONF_PAYLOAD_OFF, default=DEFAULT_PAYLOAD_OFF): cv.string,
vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean,
})
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
"""Add MQTT switch."""
if config.get('command_topic') is None:
_LOGGER.error("Missing required variable: command_topic")
return False
add_devices_callback([MqttSwitch(
hass,
convert(config.get('name'), str, DEFAULT_NAME),
config.get('state_topic'),
config.get('command_topic'),
convert(config.get('qos'), int, DEFAULT_QOS),
convert(config.get('retain'), bool, DEFAULT_RETAIN),
convert(config.get('payload_on'), str, DEFAULT_PAYLOAD_ON),
convert(config.get('payload_off'), str, DEFAULT_PAYLOAD_OFF),
convert(config.get('optimistic'), bool, DEFAULT_OPTIMISTIC),
config[CONF_NAME],
config.get(CONF_STATE_TOPIC),
config[CONF_COMMAND_TOPIC],
config[CONF_QOS],
config[CONF_RETAIN],
config[CONF_PAYLOAD_ON],
config[CONF_PAYLOAD_OFF],
config[CONF_OPTIMISTIC],
config.get(CONF_VALUE_TEMPLATE))])

View file

@ -29,6 +29,7 @@ CONF_PASSWORD = "password"
CONF_API_KEY = "api_key"
CONF_ACCESS_TOKEN = "access_token"
CONF_FILENAME = "filename"
CONF_OPTIMISTIC = 'optimistic'
CONF_SCAN_INTERVAL = "scan_interval"
CONF_VALUE_TEMPLATE = "value_template"

View file

@ -4,6 +4,7 @@ from datetime import timedelta
from unittest import mock
from homeassistant import core as ha, loader
from homeassistant.bootstrap import _setup_component
from homeassistant.helpers.entity import ToggleEntity
from homeassistant.const import (
STATE_ON, STATE_OFF, DEVICE_DEFAULT_NAME, EVENT_TIME_CHANGED,
@ -123,12 +124,11 @@ def mock_http_component(hass):
@mock.patch('homeassistant.components.mqtt.MQTT')
def mock_mqtt_component(hass, mock_mqtt):
"""Mock the MQTT component."""
mqtt.setup(hass, {
_setup_component(hass, mqtt.DOMAIN, {
mqtt.DOMAIN: {
mqtt.CONF_BROKER: 'mock-broker',
}
})
hass.config.components.append(mqtt.DOMAIN)
return mock_mqtt

View file

@ -1,7 +1,7 @@
"""The tests the MQTT alarm control panel component."""
import unittest
from unittest.mock import patch
from homeassistant.bootstrap import _setup_component
from homeassistant.const import (
STATE_ALARM_DISARMED, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_AWAY,
STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED, STATE_UNKNOWN)
@ -25,37 +25,37 @@ class TestAlarmControlPanelMQTT(unittest.TestCase):
"""Stop down stuff we started."""
self.hass.stop()
@patch('homeassistant.components.alarm_control_panel.mqtt._LOGGER.error')
def test_fail_setup_without_state_topic(self, mock_error):
def test_fail_setup_without_state_topic(self):
"""Test for failing with no state topic."""
self.assertTrue(alarm_control_panel.setup(self.hass, {
'alarm_control_panel': {
self.hass.config.components = ['mqtt']
assert not _setup_component(self.hass, alarm_control_panel.DOMAIN, {
alarm_control_panel.DOMAIN: {
'platform': 'mqtt',
'command_topic': 'alarm/command'
}}))
}
})
self.assertEqual(1, mock_error.call_count)
@patch('homeassistant.components.alarm_control_panel.mqtt._LOGGER.error')
def test_fail_setup_without_command_topic(self, mock_error):
def test_fail_setup_without_command_topic(self):
"""Test failing with no command topic."""
self.assertTrue(alarm_control_panel.setup(self.hass, {
'alarm_control_panel': {
self.hass.config.components = ['mqtt']
assert not _setup_component(self.hass, alarm_control_panel.DOMAIN, {
alarm_control_panel.DOMAIN: {
'platform': 'mqtt',
'state_topic': 'alarm/state'
}}))
self.assertEqual(1, mock_error.call_count)
}
})
def test_update_state_via_state_topic(self):
"""Test updating with via state topic."""
self.assertTrue(alarm_control_panel.setup(self.hass, {
'alarm_control_panel': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, alarm_control_panel.DOMAIN, {
alarm_control_panel.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'state_topic': 'alarm/state',
'command_topic': 'alarm/command',
}}))
}
})
entity_id = 'alarm_control_panel.test'
@ -71,13 +71,15 @@ class TestAlarmControlPanelMQTT(unittest.TestCase):
def test_ignore_update_state_if_unknown_via_state_topic(self):
"""Test ignoring updates via state topic."""
self.assertTrue(alarm_control_panel.setup(self.hass, {
'alarm_control_panel': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, alarm_control_panel.DOMAIN, {
alarm_control_panel.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'state_topic': 'alarm/state',
'command_topic': 'alarm/command',
}}))
}
})
entity_id = 'alarm_control_panel.test'
@ -90,13 +92,15 @@ class TestAlarmControlPanelMQTT(unittest.TestCase):
def test_arm_home_publishes_mqtt(self):
"""Test publishing of MQTT messages while armed."""
self.assertTrue(alarm_control_panel.setup(self.hass, {
'alarm_control_panel': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, alarm_control_panel.DOMAIN, {
alarm_control_panel.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'state_topic': 'alarm/state',
'command_topic': 'alarm/command',
}}))
}
})
alarm_control_panel.alarm_arm_home(self.hass)
self.hass.pool.block_till_done()
@ -105,14 +109,16 @@ class TestAlarmControlPanelMQTT(unittest.TestCase):
def test_arm_home_not_publishes_mqtt_with_invalid_code(self):
"""Test not publishing of MQTT messages with invalid code."""
self.assertTrue(alarm_control_panel.setup(self.hass, {
'alarm_control_panel': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, alarm_control_panel.DOMAIN, {
alarm_control_panel.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'state_topic': 'alarm/state',
'command_topic': 'alarm/command',
'code': '1234'
}}))
}
})
call_count = self.mock_publish.call_count
alarm_control_panel.alarm_arm_home(self.hass, 'abcd')
@ -121,13 +127,15 @@ class TestAlarmControlPanelMQTT(unittest.TestCase):
def test_arm_away_publishes_mqtt(self):
"""Test publishing of MQTT messages while armed."""
self.assertTrue(alarm_control_panel.setup(self.hass, {
'alarm_control_panel': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, alarm_control_panel.DOMAIN, {
alarm_control_panel.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'state_topic': 'alarm/state',
'command_topic': 'alarm/command',
}}))
}
})
alarm_control_panel.alarm_arm_away(self.hass)
self.hass.pool.block_till_done()
@ -136,14 +144,16 @@ class TestAlarmControlPanelMQTT(unittest.TestCase):
def test_arm_away_not_publishes_mqtt_with_invalid_code(self):
"""Test not publishing of MQTT messages with invalid code."""
self.assertTrue(alarm_control_panel.setup(self.hass, {
'alarm_control_panel': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, alarm_control_panel.DOMAIN, {
alarm_control_panel.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'state_topic': 'alarm/state',
'command_topic': 'alarm/command',
'code': '1234'
}}))
}
})
call_count = self.mock_publish.call_count
alarm_control_panel.alarm_arm_away(self.hass, 'abcd')
@ -152,13 +162,15 @@ class TestAlarmControlPanelMQTT(unittest.TestCase):
def test_disarm_publishes_mqtt(self):
"""Test publishing of MQTT messages while disarmed."""
self.assertTrue(alarm_control_panel.setup(self.hass, {
'alarm_control_panel': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, alarm_control_panel.DOMAIN, {
alarm_control_panel.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'state_topic': 'alarm/state',
'command_topic': 'alarm/command',
}}))
}
})
alarm_control_panel.alarm_disarm(self.hass)
self.hass.pool.block_till_done()
@ -167,14 +179,16 @@ class TestAlarmControlPanelMQTT(unittest.TestCase):
def test_disarm_not_publishes_mqtt_with_invalid_code(self):
"""Test not publishing of MQTT messages with invalid code."""
self.assertTrue(alarm_control_panel.setup(self.hass, {
'alarm_control_panel': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, alarm_control_panel.DOMAIN, {
alarm_control_panel.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'state_topic': 'alarm/state',
'command_topic': 'alarm/command',
'code': '1234'
}}))
}
})
call_count = self.mock_publish.call_count
alarm_control_panel.alarm_disarm(self.hass, 'abcd')

View file

@ -1,6 +1,7 @@
"""The tests for the MQTT binary sensor platform."""
import unittest
from homeassistant.bootstrap import _setup_component
import homeassistant.components.binary_sensor as binary_sensor
from tests.common import mock_mqtt_component, fire_mqtt_message
from homeassistant.const import (STATE_OFF, STATE_ON)
@ -22,15 +23,16 @@ class TestSensorMQTT(unittest.TestCase):
def test_setting_sensor_value_via_mqtt_message(self):
"""Test the setting of the value via MQTT."""
self.assertTrue(binary_sensor.setup(self.hass, {
'binary_sensor': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, binary_sensor.DOMAIN, {
binary_sensor.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'state_topic': 'test-topic',
'payload_on': 'ON',
'payload_off': 'OFF',
}
}))
})
state = self.hass.states.get('binary_sensor.test')
self.assertEqual(STATE_OFF, state.state)
@ -47,28 +49,30 @@ class TestSensorMQTT(unittest.TestCase):
def test_valid_sensor_class(self):
"""Test the setting of a valid sensor class."""
self.assertTrue(binary_sensor.setup(self.hass, {
'binary_sensor': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, binary_sensor.DOMAIN, {
binary_sensor.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'sensor_class': 'motion',
'state_topic': 'test-topic',
}
}))
})
state = self.hass.states.get('binary_sensor.test')
self.assertEqual('motion', state.attributes.get('sensor_class'))
def test_invalid_sensor_class(self):
"""Test the setting of an invalid sensor class."""
self.assertTrue(binary_sensor.setup(self.hass, {
'binary_sensor': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, binary_sensor.DOMAIN, {
binary_sensor.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'sensor_class': 'abc123',
'state_topic': 'test-topic',
}
}))
})
state = self.hass.states.get('binary_sensor.test')
self.assertIsNone(state.attributes.get('sensor_class'))

View file

@ -2,6 +2,7 @@
import unittest
import os
from homeassistant.bootstrap import _setup_component
from homeassistant.components import device_tracker
from homeassistant.const import CONF_PLATFORM
@ -31,11 +32,13 @@ class TestComponentsDeviceTrackerMQTT(unittest.TestCase):
topic = '/location/paulus'
location = 'work'
self.assertTrue(device_tracker.setup(self.hass, {
self.hass.config.components = ['mqtt', 'zone']
assert _setup_component(self.hass, device_tracker.DOMAIN, {
device_tracker.DOMAIN: {
CONF_PLATFORM: 'mqtt',
'devices': {dev_id: topic}
}}))
}
})
fire_mqtt_message(self.hass, topic, location)
self.hass.pool.block_till_done()
self.assertEqual(location, self.hass.states.get(enttiy_id).state)

View file

@ -58,6 +58,7 @@ light:
"""
import unittest
from homeassistant.bootstrap import _setup_component
from homeassistant.const import STATE_ON, STATE_OFF, ATTR_ASSUMED_STATE
import homeassistant.components.light as light
from tests.common import (
@ -78,24 +79,26 @@ class TestLightMQTT(unittest.TestCase):
def test_fail_setup_if_no_command_topic(self):
"""Test if command fails with command topic."""
self.assertTrue(light.setup(self.hass, {
'light': {
self.hass.config.components = ['mqtt']
assert not _setup_component(self.hass, light.DOMAIN, {
light.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
}
}))
})
self.assertIsNone(self.hass.states.get('light.test'))
def test_no_color_or_brightness_if_no_topics(self):
"""Test if there is no color and brightness if no topic."""
self.assertTrue(light.setup(self.hass, {
'light': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, light.DOMAIN, {
light.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'state_topic': 'test_light_rgb/status',
'command_topic': 'test_light_rgb/set',
}
}))
})
state = self.hass.states.get('light.test')
self.assertEqual(STATE_OFF, state.state)
@ -112,8 +115,9 @@ class TestLightMQTT(unittest.TestCase):
def test_controlling_state_via_topic(self):
"""Test the controlling of the state via topic."""
self.assertTrue(light.setup(self.hass, {
'light': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, light.DOMAIN, {
light.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'state_topic': 'test_light_rgb/status',
@ -126,7 +130,7 @@ class TestLightMQTT(unittest.TestCase):
'payload_on': 1,
'payload_off': 0
}
}))
})
state = self.hass.states.get('light.test')
self.assertEqual(STATE_OFF, state.state)
@ -172,8 +176,9 @@ class TestLightMQTT(unittest.TestCase):
def test_controlling_scale(self):
"""Test the controlling scale."""
self.assertTrue(light.setup(self.hass, {
'light': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, light.DOMAIN, {
light.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'state_topic': 'test_scale/status',
@ -185,7 +190,7 @@ class TestLightMQTT(unittest.TestCase):
'payload_on': 'on',
'payload_off': 'off'
}
}))
})
state = self.hass.states.get('light.test')
self.assertEqual(STATE_OFF, state.state)
@ -218,8 +223,9 @@ class TestLightMQTT(unittest.TestCase):
def test_controlling_state_via_topic_with_templates(self):
"""Test the setting og the state with a template."""
self.assertTrue(light.setup(self.hass, {
'light': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, light.DOMAIN, {
light.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'state_topic': 'test_light_rgb/status',
@ -230,7 +236,7 @@ class TestLightMQTT(unittest.TestCase):
'brightness_value_template': '{{ value_json.hello }}',
'rgb_value_template': '{{ value_json.hello | join(",") }}',
}
}))
})
state = self.hass.states.get('light.test')
self.assertEqual(STATE_OFF, state.state)
@ -252,8 +258,9 @@ class TestLightMQTT(unittest.TestCase):
def test_sending_mqtt_commands_and_optimistic(self):
"""Test the sending of command in optimistic mode."""
self.assertTrue(light.setup(self.hass, {
'light': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, light.DOMAIN, {
light.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'command_topic': 'test_light_rgb/set',
@ -263,7 +270,7 @@ class TestLightMQTT(unittest.TestCase):
'payload_on': 'on',
'payload_off': 'off'
}
}))
})
state = self.hass.states.get('light.test')
self.assertEqual(STATE_OFF, state.state)
@ -310,15 +317,16 @@ class TestLightMQTT(unittest.TestCase):
def test_show_brightness_if_only_command_topic(self):
"""Test the brightness if only a command topic is present."""
self.assertTrue(light.setup(self.hass, {
'light': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, light.DOMAIN, {
light.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'brightness_command_topic': 'test_light_rgb/brightness/set',
'command_topic': 'test_light_rgb/set',
'state_topic': 'test_light_rgb/status',
}
}))
})
state = self.hass.states.get('light.test')
self.assertEqual(STATE_OFF, state.state)

View file

@ -1,6 +1,7 @@
"""The tests for the MQTT lock platform."""
import unittest
from homeassistant.bootstrap import _setup_component
from homeassistant.const import (STATE_LOCKED, STATE_UNLOCKED,
ATTR_ASSUMED_STATE)
import homeassistant.components.lock as lock
@ -22,8 +23,9 @@ class TestLockMQTT(unittest.TestCase):
def test_controlling_state_via_topic(self):
"""Test the controlling state via topic."""
self.assertTrue(lock.setup(self.hass, {
'lock': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, lock.DOMAIN, {
lock.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'state_topic': 'state-topic',
@ -31,7 +33,7 @@ class TestLockMQTT(unittest.TestCase):
'payload_lock': 'LOCK',
'payload_unlock': 'UNLOCK'
}
}))
})
state = self.hass.states.get('lock.test')
self.assertEqual(STATE_UNLOCKED, state.state)
@ -51,8 +53,9 @@ class TestLockMQTT(unittest.TestCase):
def test_sending_mqtt_commands_and_optimistic(self):
"""Test the sending MQTT commands in optimistic mode."""
self.assertTrue(lock.setup(self.hass, {
'lock': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, lock.DOMAIN, {
lock.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'command_topic': 'command-topic',
@ -60,7 +63,7 @@ class TestLockMQTT(unittest.TestCase):
'payload_unlock': 'UNLOCK',
'qos': 2
}
}))
})
state = self.hass.states.get('lock.test')
self.assertEqual(STATE_UNLOCKED, state.state)
@ -84,8 +87,9 @@ class TestLockMQTT(unittest.TestCase):
def test_controlling_state_via_topic_and_json_message(self):
"""Test the controlling state via topic and JSON message."""
self.assertTrue(lock.setup(self.hass, {
'lock': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, lock.DOMAIN, {
lock.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'state_topic': 'state-topic',
@ -94,7 +98,7 @@ class TestLockMQTT(unittest.TestCase):
'payload_unlock': 'UNLOCK',
'value_template': '{{ value_json.val }}'
}
}))
})
state = self.hass.states.get('lock.test')
self.assertEqual(STATE_UNLOCKED, state.state)

View file

@ -4,6 +4,7 @@ import unittest
from unittest import mock
import socket
from homeassistant.bootstrap import _setup_component
import homeassistant.components.mqtt as mqtt
from homeassistant.const import (
EVENT_CALL_SERVICE, ATTR_DOMAIN, ATTR_SERVICE, EVENT_HOMEASSISTANT_START,
@ -48,9 +49,12 @@ class TestMQTT(unittest.TestCase):
"""Test for setup failure if connection to broker is missing."""
with mock.patch('homeassistant.components.mqtt.MQTT',
side_effect=socket.error()):
self.assertFalse(mqtt.setup(self.hass, {mqtt.DOMAIN: {
mqtt.CONF_BROKER: 'test-broker',
}}))
self.hass.config.components = []
assert not _setup_component(self.hass, mqtt.DOMAIN, {
mqtt.DOMAIN: {
mqtt.CONF_BROKER: 'test-broker',
}
})
def test_publish_calls_service(self):
"""Test the publishing of call to services."""
@ -211,12 +215,12 @@ class TestMQTTCallbacks(unittest.TestCase):
# mock_mqtt_component(self.hass)
with mock.patch('paho.mqtt.client.Client'):
mqtt.setup(self.hass, {
self.hass.config.components = []
assert _setup_component(self.hass, mqtt.DOMAIN, {
mqtt.DOMAIN: {
mqtt.CONF_BROKER: 'mock-broker',
}
})
self.hass.config.components.append(mqtt.DOMAIN)
def tearDown(self): # pylint: disable=invalid-name
"""Stop everything that was started."""

View file

@ -1,6 +1,7 @@
"""The tests for the MQTT component embedded server."""
from unittest.mock import MagicMock, patch
from homeassistant.bootstrap import _setup_component
import homeassistant.components.mqtt as mqtt
from tests.common import get_test_home_assistant
@ -27,15 +28,16 @@ class TestMQTT:
password = 'super_secret'
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.mock_calls[0][1][5] == 'homeassistant'
assert mock_mqtt.mock_calls[0][1][6] == password
mock_mqtt.reset_mock()
self.hass.config.components = ['http']
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.mock_calls[0][1][5] is None
assert mock_mqtt.mock_calls[0][1][6] is None
@ -50,6 +52,6 @@ class TestMQTT:
mock_gather.side_effect = BrokerException
self.hass.config.api = MagicMock(api_password=None)
assert not mqtt.setup(self.hass, {
'mqtt': {'embedded': {}}
assert not _setup_component(self.hass, mqtt.DOMAIN, {
mqtt.DOMAIN: {mqtt.CONF_EMBEDDED: {}}
})

View file

@ -1,6 +1,7 @@
"""The tests for the MQTT roller shutter platform."""
import unittest
from homeassistant.bootstrap import _setup_component
from homeassistant.const import STATE_OPEN, STATE_CLOSED, STATE_UNKNOWN
import homeassistant.components.rollershutter as rollershutter
from tests.common import mock_mqtt_component, fire_mqtt_message
@ -22,8 +23,9 @@ class TestRollershutterMQTT(unittest.TestCase):
def test_controlling_state_via_topic(self):
"""Test the controlling state via topic."""
self.assertTrue(rollershutter.setup(self.hass, {
'rollershutter': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, rollershutter.DOMAIN, {
rollershutter.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'state_topic': 'state-topic',
@ -33,7 +35,7 @@ class TestRollershutterMQTT(unittest.TestCase):
'payload_down': 'DOWN',
'payload_stop': 'STOP'
}
}))
})
state = self.hass.states.get('rollershutter.test')
self.assertEqual(STATE_UNKNOWN, state.state)
@ -58,15 +60,16 @@ class TestRollershutterMQTT(unittest.TestCase):
def test_send_move_up_command(self):
"""Test the sending of move_up."""
self.assertTrue(rollershutter.setup(self.hass, {
'rollershutter': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, rollershutter.DOMAIN, {
rollershutter.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'state_topic': 'state-topic',
'command_topic': 'command-topic',
'qos': 2
}
}))
})
state = self.hass.states.get('rollershutter.test')
self.assertEqual(STATE_UNKNOWN, state.state)
@ -81,15 +84,16 @@ class TestRollershutterMQTT(unittest.TestCase):
def test_send_move_down_command(self):
"""Test the sending of move_down."""
self.assertTrue(rollershutter.setup(self.hass, {
'rollershutter': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, rollershutter.DOMAIN, {
rollershutter.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'state_topic': 'state-topic',
'command_topic': 'command-topic',
'qos': 2
}
}))
})
state = self.hass.states.get('rollershutter.test')
self.assertEqual(STATE_UNKNOWN, state.state)
@ -104,15 +108,16 @@ class TestRollershutterMQTT(unittest.TestCase):
def test_send_stop_command(self):
"""Test the sending of stop."""
self.assertTrue(rollershutter.setup(self.hass, {
'rollershutter': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, rollershutter.DOMAIN, {
rollershutter.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'state_topic': 'state-topic',
'command_topic': 'command-topic',
'qos': 2
}
}))
})
state = self.hass.states.get('rollershutter.test')
self.assertEqual(STATE_UNKNOWN, state.state)
@ -127,8 +132,9 @@ class TestRollershutterMQTT(unittest.TestCase):
def test_state_attributes_current_position(self):
"""Test the current position."""
self.assertTrue(rollershutter.setup(self.hass, {
'rollershutter': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, rollershutter.DOMAIN, {
rollershutter.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'state_topic': 'state-topic',
@ -137,7 +143,7 @@ class TestRollershutterMQTT(unittest.TestCase):
'payload_down': 'DOWN',
'payload_stop': 'STOP'
}
}))
})
state_attributes_dict = self.hass.states.get(
'rollershutter.test').attributes

View file

@ -1,6 +1,7 @@
"""The tests for the MQTT sensor platform."""
import unittest
from homeassistant.bootstrap import _setup_component
import homeassistant.components.sensor as sensor
from tests.common import mock_mqtt_component, fire_mqtt_message
@ -21,14 +22,15 @@ class TestSensorMQTT(unittest.TestCase):
def test_setting_sensor_value_via_mqtt_message(self):
"""Test the setting of the value via MQTT."""
self.assertTrue(sensor.setup(self.hass, {
'sensor': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, sensor.DOMAIN, {
sensor.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'state_topic': 'test-topic',
'unit_of_measurement': 'fav unit'
}
}))
})
fire_mqtt_message(self.hass, 'test-topic', '100')
self.hass.pool.block_till_done()
@ -40,15 +42,16 @@ class TestSensorMQTT(unittest.TestCase):
def test_setting_sensor_value_via_mqtt_json_message(self):
"""Test the setting of the value via MQTT with JSON playload."""
self.assertTrue(sensor.setup(self.hass, {
'sensor': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, sensor.DOMAIN, {
sensor.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'state_topic': 'test-topic',
'unit_of_measurement': 'fav unit',
'value_template': '{{ value_json.val }}'
}
}))
})
fire_mqtt_message(self.hass, 'test-topic', '{ "val": "100" }')
self.hass.pool.block_till_done()

View file

@ -1,6 +1,7 @@
"""The tests for the MQTT switch platform."""
import unittest
from homeassistant.bootstrap import _setup_component
from homeassistant.const import STATE_ON, STATE_OFF, ATTR_ASSUMED_STATE
import homeassistant.components.switch as switch
from tests.common import (
@ -21,8 +22,9 @@ class TestSensorMQTT(unittest.TestCase):
def test_controlling_state_via_topic(self):
"""Test the controlling state via topic."""
self.assertTrue(switch.setup(self.hass, {
'switch': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, switch.DOMAIN, {
switch.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'state_topic': 'state-topic',
@ -30,7 +32,7 @@ class TestSensorMQTT(unittest.TestCase):
'payload_on': 1,
'payload_off': 0
}
}))
})
state = self.hass.states.get('switch.test')
self.assertEqual(STATE_OFF, state.state)
@ -50,8 +52,9 @@ class TestSensorMQTT(unittest.TestCase):
def test_sending_mqtt_commands_and_optimistic(self):
"""Test the sending MQTT commands in optimistic mode."""
self.assertTrue(switch.setup(self.hass, {
'switch': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, switch.DOMAIN, {
switch.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'command_topic': 'command-topic',
@ -59,7 +62,7 @@ class TestSensorMQTT(unittest.TestCase):
'payload_off': 'beer off',
'qos': '2'
}
}))
})
state = self.hass.states.get('switch.test')
self.assertEqual(STATE_OFF, state.state)
@ -83,8 +86,9 @@ class TestSensorMQTT(unittest.TestCase):
def test_controlling_state_via_topic_and_json_message(self):
"""Test the controlling state via topic and JSON message."""
self.assertTrue(switch.setup(self.hass, {
'switch': {
self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, switch.DOMAIN, {
switch.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'state_topic': 'state-topic',
@ -93,7 +97,7 @@ class TestSensorMQTT(unittest.TestCase):
'payload_off': 'beer off',
'value_template': '{{ value_json.val }}'
}
}))
})
state = self.hass.states.get('switch.test')
self.assertEqual(STATE_OFF, state.state)