Expand MQTT lights (#6481)

* Add effect support to MQTT Light

* Use effect state topic for supported_features

* Dont use rainbow as default color

* Add color_temp support to MQTT JSON Light

* Add effect to MQTT JSON light

* Support lights in MQTT discovery

* Allow discovered devices to set their platform

* Add white value support to MQTT Light

* Add white value support to MQTT JSON Light

* Remove blank line

* Add color_temp support to MQTT Template light

* Add white value support to MQTT Template Light

* Remove unused SUPPORT_MQTT_TEMPLATE and stale unused flash and transition code from MQTT Template

* Add XY Color to MQTT Light Platform

* Fix syntax

* Fix more syntax errors

* Revert "Remove unused SUPPORT_MQTT_TEMPLATE and stale unused flash and transition code from MQTT Template"

This reverts commit c03798cb63.

* MQTT Template supports flash and transition but doesnt allow templating of the values

* Add XY color support to MQTT JSON

* Proper variable names

* Only allow whitelisted MQTT platforms to be loaded via MQTT Discovery

* Minor tweaks.
pull/6488/head
Robbie Trencheny 2017-03-07 23:01:36 -08:00 committed by Paulus Schoutsen
parent c937a7bcb0
commit 2b97449d98
8 changed files with 945 additions and 136 deletions

View File

@ -12,55 +12,81 @@ import voluptuous as vol
from homeassistant.core import callback
import homeassistant.components.mqtt as mqtt
from homeassistant.components.light import (
ATTR_BRIGHTNESS, ATTR_RGB_COLOR, ATTR_COLOR_TEMP, SUPPORT_BRIGHTNESS,
SUPPORT_RGB_COLOR, SUPPORT_COLOR_TEMP, Light)
ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_EFFECT, ATTR_RGB_COLOR,
ATTR_WHITE_VALUE, ATTR_XY_COLOR, Light, SUPPORT_BRIGHTNESS,
SUPPORT_COLOR_TEMP, SUPPORT_EFFECT, SUPPORT_RGB_COLOR,
SUPPORT_WHITE_VALUE, SUPPORT_XY_COLOR)
from homeassistant.const import (
CONF_NAME, CONF_OPTIMISTIC, CONF_VALUE_TEMPLATE, CONF_PAYLOAD_OFF,
CONF_PAYLOAD_ON, CONF_STATE, CONF_BRIGHTNESS, CONF_RGB,
CONF_COLOR_TEMP)
CONF_BRIGHTNESS, CONF_COLOR_TEMP, CONF_EFFECT, CONF_NAME,
CONF_OPTIMISTIC, CONF_PAYLOAD_OFF, CONF_PAYLOAD_ON,
CONF_RGB, CONF_STATE, CONF_VALUE_TEMPLATE, CONF_WHITE_VALUE, CONF_XY)
from homeassistant.components.mqtt import (
CONF_STATE_TOPIC, CONF_COMMAND_TOPIC, CONF_QOS, CONF_RETAIN)
CONF_COMMAND_TOPIC, CONF_QOS, CONF_RETAIN, CONF_STATE_TOPIC)
import homeassistant.helpers.config_validation as cv
_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_BRIGHTNESS_SCALE = 'brightness_scale'
CONF_COLOR_TEMP_STATE_TOPIC = 'color_temp_state_topic'
CONF_BRIGHTNESS_STATE_TOPIC = 'brightness_state_topic'
CONF_BRIGHTNESS_VALUE_TEMPLATE = 'brightness_value_template'
CONF_COLOR_TEMP_COMMAND_TOPIC = 'color_temp_command_topic'
CONF_COLOR_TEMP_STATE_TOPIC = 'color_temp_state_topic'
CONF_COLOR_TEMP_VALUE_TEMPLATE = 'color_temp_value_template'
CONF_EFFECT_COMMAND_TOPIC = 'effect_command_topic'
CONF_EFFECT_LIST = 'effect_list'
CONF_EFFECT_STATE_TOPIC = 'effect_state_topic'
CONF_EFFECT_VALUE_TEMPLATE = 'effect_value_template'
CONF_RGB_COMMAND_TOPIC = 'rgb_command_topic'
CONF_RGB_STATE_TOPIC = 'rgb_state_topic'
CONF_RGB_VALUE_TEMPLATE = 'rgb_value_template'
CONF_STATE_VALUE_TEMPLATE = 'state_value_template'
CONF_XY_COMMAND_TOPIC = 'xy_command_topic'
CONF_XY_STATE_TOPIC = 'xy_state_topic'
CONF_XY_VALUE_TEMPLATE = 'xy_value_template'
CONF_WHITE_VALUE_COMMAND_TOPIC = 'white_value_command_topic'
CONF_WHITE_VALUE_SCALE = 'white_value_scale'
CONF_WHITE_VALUE_STATE_TOPIC = 'white_value_state_topic'
CONF_WHITE_VALUE_TEMPLATE = 'white_value_template'
DEFAULT_NAME = 'MQTT Light'
DEFAULT_PAYLOAD_ON = 'ON'
DEFAULT_PAYLOAD_OFF = 'OFF'
DEFAULT_OPTIMISTIC = False
DEFAULT_BRIGHTNESS_SCALE = 255
DEFAULT_NAME = 'MQTT Light'
DEFAULT_OPTIMISTIC = False
DEFAULT_PAYLOAD_OFF = 'OFF'
DEFAULT_PAYLOAD_ON = 'ON'
DEFAULT_WHITE_VALUE_SCALE = 255
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_COLOR_TEMP_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_COLOR_TEMP_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_COLOR_TEMP_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)),
vol.Optional(CONF_BRIGHTNESS_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_BRIGHTNESS_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_COLOR_TEMP_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_COLOR_TEMP_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_COLOR_TEMP_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_EFFECT_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_EFFECT_LIST): vol.All(cv.ensure_list, [cv.string]),
vol.Optional(CONF_EFFECT_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_EFFECT_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean,
vol.Optional(CONF_PAYLOAD_OFF, default=DEFAULT_PAYLOAD_OFF): cv.string,
vol.Optional(CONF_PAYLOAD_ON, default=DEFAULT_PAYLOAD_ON): cv.string,
vol.Optional(CONF_RGB_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_RGB_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_RGB_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_STATE_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_WHITE_VALUE_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_WHITE_VALUE_SCALE, default=DEFAULT_WHITE_VALUE_SCALE):
vol.All(vol.Coerce(int), vol.Range(min=1)),
vol.Optional(CONF_WHITE_VALUE_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_WHITE_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_XY_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_XY_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_XY_VALUE_TEMPLATE): cv.template,
})
@ -72,23 +98,33 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
async_add_devices([MqttLight(
config.get(CONF_NAME),
config.get(CONF_EFFECT_LIST),
{
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,
CONF_BRIGHTNESS_STATE_TOPIC,
CONF_COLOR_TEMP_COMMAND_TOPIC,
CONF_COLOR_TEMP_STATE_TOPIC,
CONF_COLOR_TEMP_COMMAND_TOPIC
CONF_COMMAND_TOPIC,
CONF_EFFECT_COMMAND_TOPIC,
CONF_EFFECT_STATE_TOPIC,
CONF_RGB_COMMAND_TOPIC,
CONF_RGB_STATE_TOPIC,
CONF_STATE_TOPIC,
CONF_WHITE_VALUE_COMMAND_TOPIC,
CONF_WHITE_VALUE_STATE_TOPIC,
CONF_XY_COMMAND_TOPIC,
CONF_XY_STATE_TOPIC,
)
},
{
CONF_STATE: config.get(CONF_STATE_VALUE_TEMPLATE),
CONF_BRIGHTNESS: config.get(CONF_BRIGHTNESS_VALUE_TEMPLATE),
CONF_COLOR_TEMP: config.get(CONF_COLOR_TEMP_VALUE_TEMPLATE),
CONF_EFFECT: config.get(CONF_EFFECT_VALUE_TEMPLATE),
CONF_RGB: config.get(CONF_RGB_VALUE_TEMPLATE),
CONF_COLOR_TEMP: config.get(CONF_COLOR_TEMP_VALUE_TEMPLATE)
CONF_STATE: config.get(CONF_STATE_VALUE_TEMPLATE),
CONF_WHITE_VALUE: config.get(CONF_WHITE_VALUE_TEMPLATE),
CONF_XY: config.get(CONF_XY_VALUE_TEMPLATE),
},
config.get(CONF_QOS),
config.get(CONF_RETAIN),
@ -98,16 +134,19 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
},
config.get(CONF_OPTIMISTIC),
config.get(CONF_BRIGHTNESS_SCALE),
config.get(CONF_WHITE_VALUE_SCALE),
)])
class MqttLight(Light):
"""MQTT light."""
def __init__(self, name, topic, templates, qos, retain, payload,
optimistic, brightness_scale):
def __init__(self, name, effect_list, topic, templates, qos,
retain, payload, optimistic, brightness_scale,
white_value_scale):
"""Initialize MQTT light."""
self._name = name
self._effect_list = effect_list
self._topic = topic
self._qos = qos
self._retain = retain
@ -120,11 +159,21 @@ class MqttLight(Light):
optimistic or topic[CONF_BRIGHTNESS_STATE_TOPIC] is None)
self._optimistic_color_temp = (
optimistic or topic[CONF_COLOR_TEMP_STATE_TOPIC] is None)
self._optimistic_effect = (
optimistic or topic[CONF_EFFECT_STATE_TOPIC] is None)
self._optimistic_white_value = (
optimistic or topic[CONF_WHITE_VALUE_STATE_TOPIC] is None)
self._optimistic_xy = \
optimistic or topic[CONF_XY_STATE_TOPIC] is None
self._brightness_scale = brightness_scale
self._white_value_scale = white_value_scale
self._state = False
self._brightness = None
self._rgb = None
self._color_temp = None
self._effect = None
self._white_value = None
self._xy = None
self._supported_features = 0
self._supported_features |= (
topic[CONF_RGB_COMMAND_TOPIC] is not None and SUPPORT_RGB_COLOR)
@ -134,6 +183,14 @@ class MqttLight(Light):
self._supported_features |= (
topic[CONF_COLOR_TEMP_COMMAND_TOPIC] is not None and
SUPPORT_COLOR_TEMP)
self._supported_features |= (
topic[CONF_EFFECT_STATE_TOPIC] is not None and
SUPPORT_EFFECT)
self._supported_features |= (
topic[CONF_WHITE_VALUE_COMMAND_TOPIC] is not None and
SUPPORT_WHITE_VALUE)
self._supported_features |= (
topic[CONF_XY_COMMAND_TOPIC] is not None and SUPPORT_XY_COLOR)
@asyncio.coroutine
def async_added_to_hass(self):
@ -215,6 +272,57 @@ class MqttLight(Light):
else:
self._color_temp = None
@callback
def effect_received(topic, payload, qos):
"""A new MQTT message for effect has been received."""
self._effect = templates[CONF_EFFECT](payload)
self.hass.async_add_job(self.async_update_ha_state())
if self._topic[CONF_EFFECT_STATE_TOPIC] is not None:
yield from mqtt.async_subscribe(
self.hass, self._topic[CONF_EFFECT_STATE_TOPIC],
effect_received, self._qos)
self._effect = 'none'
if self._topic[CONF_EFFECT_COMMAND_TOPIC] is not None:
self._effect = 'none'
else:
self._effect = None
@callback
def white_value_received(topic, payload, qos):
"""A new MQTT message for the white value has been received."""
device_value = float(templates[CONF_WHITE_VALUE](payload))
percent_white = device_value / self._white_value_scale
self._white_value = int(percent_white * 255)
self.hass.async_add_job(self.async_update_ha_state())
if self._topic[CONF_WHITE_VALUE_STATE_TOPIC] is not None:
yield from mqtt.async_subscribe(
self.hass, self._topic[CONF_WHITE_VALUE_STATE_TOPIC],
white_value_received, self._qos)
self._white_value = 255
elif self._topic[CONF_WHITE_VALUE_COMMAND_TOPIC] is not None:
self._white_value = 255
else:
self._white_value = None
@callback
def xy_received(topic, payload, qos):
"""A new MQTT message has been received."""
self._xy = [float(val) for val in
templates[CONF_XY](payload).split(',')]
self.hass.async_add_job(self.async_update_ha_state())
if self._topic[CONF_XY_STATE_TOPIC] is not None:
yield from mqtt.async_subscribe(
self.hass, self._topic[CONF_XY_STATE_TOPIC], xy_received,
self._qos)
self._xy = [1, 1]
if self._topic[CONF_XY_COMMAND_TOPIC] is not None:
self._xy = [1, 1]
else:
self._xy = None
@property
def brightness(self):
"""Return the brightness of this light between 0..255."""
@ -230,6 +338,16 @@ class MqttLight(Light):
"""Return the color temperature in mired."""
return self._color_temp
@property
def white_value(self):
"""Return the white property."""
return self._white_value
@property
def xy_color(self):
"""Return the RGB color value."""
return self._xy
@property
def should_poll(self):
"""No polling needed for a MQTT light."""
@ -250,6 +368,16 @@ class MqttLight(Light):
"""Return true if we do optimistic updates."""
return self._optimistic
@property
def effect_list(self):
"""Return the list of supported effects."""
return self._effect_list
@property
def effect(self):
"""Return the current effect."""
return self._effect
@property
def supported_features(self):
"""Flag supported features."""
@ -297,6 +425,41 @@ class MqttLight(Light):
self._color_temp = kwargs[ATTR_COLOR_TEMP]
should_update = True
if ATTR_EFFECT in kwargs and \
self._topic[CONF_EFFECT_COMMAND_TOPIC] is not None:
effect = kwargs[ATTR_EFFECT]
if effect in self._effect_list:
mqtt.async_publish(
self.hass, self._topic[CONF_EFFECT_COMMAND_TOPIC],
effect, self._qos, self._retain)
if self._optimistic_effect:
self._effect = kwargs[ATTR_EFFECT]
should_update = True
if ATTR_WHITE_VALUE in kwargs and \
self._topic[CONF_WHITE_VALUE_COMMAND_TOPIC] is not None:
percent_white = float(kwargs[ATTR_WHITE_VALUE]) / 255
device_white_value = int(percent_white * self._white_value_scale)
mqtt.async_publish(
self.hass, self._topic[CONF_WHITE_VALUE_COMMAND_TOPIC],
device_white_value, self._qos, self._retain)
if self._optimistic_white_value:
self._white_value = kwargs[ATTR_WHITE_VALUE]
should_update = True
if ATTR_XY_COLOR in kwargs and \
self._topic[CONF_XY_COMMAND_TOPIC] is not None:
mqtt.async_publish(
self.hass, self._topic[CONF_XY_COMMAND_TOPIC],
'{},{}'.format(*kwargs[ATTR_XY_COLOR]), self._qos,
self._retain)
if self._optimistic_xy:
self._xy = kwargs[ATTR_XY_COLOR]
should_update = True
mqtt.async_publish(
self.hass, self._topic[CONF_COMMAND_TOPIC], self._payload['on'],
self._qos, self._retain)

View File

@ -12,11 +12,14 @@ import voluptuous as vol
from homeassistant.core import callback
import homeassistant.components.mqtt as mqtt
from homeassistant.components.light import (
ATTR_BRIGHTNESS, ATTR_RGB_COLOR, ATTR_TRANSITION, PLATFORM_SCHEMA,
ATTR_FLASH, FLASH_LONG, FLASH_SHORT, SUPPORT_BRIGHTNESS, SUPPORT_FLASH,
SUPPORT_RGB_COLOR, SUPPORT_TRANSITION, Light)
ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_EFFECT, ATTR_FLASH,
ATTR_RGB_COLOR, ATTR_TRANSITION, ATTR_WHITE_VALUE, ATTR_XY_COLOR,
FLASH_LONG, FLASH_SHORT, Light, PLATFORM_SCHEMA, SUPPORT_BRIGHTNESS,
SUPPORT_COLOR_TEMP, SUPPORT_EFFECT, SUPPORT_FLASH, SUPPORT_RGB_COLOR,
SUPPORT_TRANSITION, SUPPORT_WHITE_VALUE, SUPPORT_XY_COLOR)
from homeassistant.const import (
CONF_NAME, CONF_OPTIMISTIC, CONF_BRIGHTNESS, CONF_RGB)
CONF_BRIGHTNESS, CONF_COLOR_TEMP, CONF_EFFECT,
CONF_NAME, CONF_OPTIMISTIC, CONF_RGB, CONF_WHITE_VALUE, CONF_XY)
from homeassistant.components.mqtt import (
CONF_STATE_TOPIC, CONF_COMMAND_TOPIC, CONF_QOS, CONF_RETAIN)
import homeassistant.helpers.config_validation as cv
@ -27,34 +30,42 @@ DOMAIN = 'mqtt_json'
DEPENDENCIES = ['mqtt']
DEFAULT_BRIGHTNESS = False
DEFAULT_COLOR_TEMP = False
DEFAULT_EFFECT = False
DEFAULT_FLASH_TIME_LONG = 10
DEFAULT_FLASH_TIME_SHORT = 2
DEFAULT_NAME = 'MQTT JSON Light'
DEFAULT_OPTIMISTIC = False
DEFAULT_BRIGHTNESS = False
DEFAULT_RGB = False
DEFAULT_FLASH_TIME_SHORT = 2
DEFAULT_FLASH_TIME_LONG = 10
DEFAULT_WHITE_VALUE = False
DEFAULT_XY = False
CONF_EFFECT_LIST = 'effect_list'
CONF_FLASH_TIME_SHORT = 'flash_time_short'
CONF_FLASH_TIME_LONG = 'flash_time_long'
SUPPORT_MQTT_JSON = (SUPPORT_BRIGHTNESS | SUPPORT_FLASH | SUPPORT_RGB_COLOR |
SUPPORT_TRANSITION)
CONF_FLASH_TIME_SHORT = 'flash_time_short'
# Stealing some of these from the base MQTT configs.
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_QOS, default=mqtt.DEFAULT_QOS):
vol.All(vol.Coerce(int), vol.In([0, 1, 2])),
vol.Required(CONF_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_RETAIN, default=mqtt.DEFAULT_RETAIN): cv.boolean,
vol.Optional(CONF_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean,
vol.Optional(CONF_BRIGHTNESS, default=DEFAULT_BRIGHTNESS): cv.boolean,
vol.Optional(CONF_RGB, default=DEFAULT_RGB): cv.boolean,
vol.Optional(CONF_COLOR_TEMP, default=DEFAULT_COLOR_TEMP): cv.boolean,
vol.Optional(CONF_EFFECT, default=DEFAULT_EFFECT): cv.boolean,
vol.Optional(CONF_EFFECT_LIST): vol.All(cv.ensure_list, [cv.string]),
vol.Optional(CONF_FLASH_TIME_SHORT, default=DEFAULT_FLASH_TIME_SHORT):
cv.positive_int,
vol.Optional(CONF_FLASH_TIME_LONG, default=DEFAULT_FLASH_TIME_LONG):
cv.positive_int
cv.positive_int,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean,
vol.Optional(CONF_QOS, default=mqtt.DEFAULT_QOS):
vol.All(vol.Coerce(int), vol.In([0, 1, 2])),
vol.Optional(CONF_RETAIN, default=mqtt.DEFAULT_RETAIN): cv.boolean,
vol.Optional(CONF_RGB, default=DEFAULT_RGB): cv.boolean,
vol.Optional(CONF_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_WHITE_VALUE, default=DEFAULT_WHITE_VALUE): cv.boolean,
vol.Optional(CONF_XY, default=DEFAULT_XY): cv.boolean,
vol.Required(CONF_COMMAND_TOPIC): mqtt.valid_publish_topic,
})
@ -63,6 +74,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
"""Setup a MQTT JSON Light."""
async_add_devices([MqttJson(
config.get(CONF_NAME),
config.get(CONF_EFFECT_LIST),
{
key: config.get(key) for key in (
CONF_STATE_TOPIC,
@ -73,7 +85,11 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
config.get(CONF_RETAIN),
config.get(CONF_OPTIMISTIC),
config.get(CONF_BRIGHTNESS),
config.get(CONF_COLOR_TEMP),
config.get(CONF_EFFECT),
config.get(CONF_RGB),
config.get(CONF_WHITE_VALUE),
config.get(CONF_XY),
{
key: config.get(key) for key in (
CONF_FLASH_TIME_SHORT,
@ -86,10 +102,12 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
class MqttJson(Light):
"""Representation of a MQTT JSON light."""
def __init__(self, name, topic, qos, retain, optimistic, brightness, rgb,
def __init__(self, name, effect_list, topic, qos, retain, optimistic,
brightness, color_temp, effect, rgb, white_value, xy,
flash_times):
"""Initialize MQTT JSON light."""
self._name = name
self._effect_list = effect_list
self._topic = topic
self._qos = qos
self._retain = retain
@ -100,13 +118,45 @@ class MqttJson(Light):
else:
self._brightness = None
if color_temp:
self._color_temp = 150
else:
self._color_temp = None
if effect:
self._effect = 'none'
else:
self._effect = None
if rgb:
self._rgb = [0, 0, 0]
else:
self._rgb = None
if white_value:
self._white_value = 255
else:
self._white_value = None
if xy:
self._xy = [1, 1]
else:
self._xy = None
self._flash_times = flash_times
self._supported_features = (SUPPORT_TRANSITION | SUPPORT_FLASH)
self._supported_features |= (rgb is not None and SUPPORT_RGB_COLOR)
self._supported_features |= (brightness is not None and
SUPPORT_BRIGHTNESS)
self._supported_features |= (color_temp is not None and
SUPPORT_COLOR_TEMP)
self._supported_features |= (effect is not None and
SUPPORT_EFFECT)
self._supported_features |= (white_value is not None and
SUPPORT_WHITE_VALUE)
self._supported_features |= (xy is not None and SUPPORT_XY_COLOR)
@asyncio.coroutine
def async_added_to_hass(self):
"""Subscribe mqtt events.
@ -133,7 +183,7 @@ class MqttJson(Light):
except KeyError:
pass
except ValueError:
_LOGGER.warning("Invalid color value received")
_LOGGER.warning("Invalid RGB color value received")
if self._brightness is not None:
try:
@ -143,6 +193,41 @@ class MqttJson(Light):
except ValueError:
_LOGGER.warning('Invalid brightness value received')
if self._color_temp is not None:
try:
self._color_temp = int(values['color_temp'])
except KeyError:
pass
except ValueError:
_LOGGER.warning('Invalid color temp value received')
if self._effect is not None:
try:
self._effect = values['effect']
except KeyError:
pass
except ValueError:
_LOGGER.warning('Invalid effect value received')
if self._white_value is not None:
try:
self._white_value = int(values['white_value'])
except KeyError:
pass
except ValueError:
_LOGGER.warning('Invalid white value value received')
if self._xy is not None:
try:
x_color = float(values['color']['x'])
y_color = float(values['color']['y'])
self._xy = [x_color, y_color]
except KeyError:
pass
except ValueError:
_LOGGER.warning("Invalid XY color value received")
self.hass.async_add_job(self.async_update_ha_state())
if self._topic[CONF_STATE_TOPIC] is not None:
@ -155,11 +240,36 @@ class MqttJson(Light):
"""Return the brightness of this light between 0..255."""
return self._brightness
@property
def color_temp(self):
"""Return the color temperature in mired."""
return self._color_temp
@property
def effect(self):
"""Return the current effect."""
return self._effect
@property
def effect_list(self):
"""Return the list of supported effects."""
return self._effect_list
@property
def rgb_color(self):
"""Return the RGB color value."""
return self._rgb
@property
def white_value(self):
"""Return the white property."""
return self._white_value
@property
def xy_color(self):
"""Return the XY color value."""
return self._xy
@property
def should_poll(self):
"""No polling needed for a MQTT light."""
@ -183,7 +293,7 @@ class MqttJson(Light):
@property
def supported_features(self):
"""Flag supported features."""
return SUPPORT_MQTT_JSON
return self._supported_features
@asyncio.coroutine
def async_turn_on(self, **kwargs):
@ -224,6 +334,37 @@ class MqttJson(Light):
self._brightness = kwargs[ATTR_BRIGHTNESS]
should_update = True
if ATTR_COLOR_TEMP in kwargs:
message['color_temp'] = int(kwargs[ATTR_COLOR_TEMP])
if self._optimistic:
self._color_temp = kwargs[ATTR_COLOR_TEMP]
should_update = True
if ATTR_EFFECT in kwargs:
message['effect'] = kwargs[ATTR_EFFECT]
if self._optimistic:
self._effect = kwargs[ATTR_EFFECT]
should_update = True
if ATTR_WHITE_VALUE in kwargs:
message['white_value'] = int(kwargs[ATTR_WHITE_VALUE])
if self._optimistic:
self._white_value = kwargs[ATTR_WHITE_VALUE]
should_update = True
if ATTR_XY_COLOR in kwargs:
message['color'] = {
'x': kwargs[ATTR_XY_COLOR][0],
'y': kwargs[ATTR_XY_COLOR][1]
}
if self._optimistic:
self._xy = kwargs[ATTR_XY_COLOR]
should_update = True
mqtt.async_publish(
self.hass, self._topic[CONF_COMMAND_TOPIC], json.dumps(message),
self._qos, self._retain)

View File

@ -11,9 +11,10 @@ import voluptuous as vol
from homeassistant.core import callback
import homeassistant.components.mqtt as mqtt
from homeassistant.components.light import (
ATTR_BRIGHTNESS, ATTR_EFFECT, ATTR_FLASH, ATTR_RGB_COLOR, ATTR_TRANSITION,
PLATFORM_SCHEMA, SUPPORT_BRIGHTNESS, SUPPORT_EFFECT, SUPPORT_FLASH,
SUPPORT_RGB_COLOR, SUPPORT_TRANSITION, Light)
ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_EFFECT, ATTR_FLASH,
ATTR_RGB_COLOR, ATTR_TRANSITION, ATTR_WHITE_VALUE, Light, PLATFORM_SCHEMA,
SUPPORT_BRIGHTNESS, SUPPORT_COLOR_TEMP, SUPPORT_EFFECT, SUPPORT_FLASH,
SUPPORT_RGB_COLOR, SUPPORT_TRANSITION, SUPPORT_WHITE_VALUE)
from homeassistant.const import CONF_NAME, CONF_OPTIMISTIC, STATE_ON, STATE_OFF
from homeassistant.components.mqtt import (
CONF_STATE_TOPIC, CONF_COMMAND_TOPIC, CONF_QOS, CONF_RETAIN)
@ -28,36 +29,37 @@ DEPENDENCIES = ['mqtt']
DEFAULT_NAME = 'MQTT Template Light'
DEFAULT_OPTIMISTIC = False
CONF_EFFECT_LIST = "effect_list"
CONF_COMMAND_ON_TEMPLATE = 'command_on_template'
CONF_COMMAND_OFF_TEMPLATE = 'command_off_template'
CONF_STATE_TEMPLATE = 'state_template'
CONF_BRIGHTNESS_TEMPLATE = 'brightness_template'
CONF_RED_TEMPLATE = 'red_template'
CONF_GREEN_TEMPLATE = 'green_template'
CONF_BLUE_TEMPLATE = 'blue_template'
CONF_BRIGHTNESS_TEMPLATE = 'brightness_template'
CONF_COLOR_TEMP_TEMPLATE = 'color_temp_template'
CONF_COMMAND_OFF_TEMPLATE = 'command_off_template'
CONF_COMMAND_ON_TEMPLATE = 'command_on_template'
CONF_EFFECT_LIST = 'effect_list'
CONF_EFFECT_TEMPLATE = 'effect_template'
SUPPORT_MQTT_TEMPLATE = (SUPPORT_BRIGHTNESS | SUPPORT_EFFECT | SUPPORT_FLASH |
SUPPORT_RGB_COLOR | SUPPORT_TRANSITION)
CONF_GREEN_TEMPLATE = 'green_template'
CONF_RED_TEMPLATE = 'red_template'
CONF_STATE_TEMPLATE = 'state_template'
CONF_WHITE_VALUE_TEMPLATE = 'white_value_template'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_EFFECT_LIST): vol.All(cv.ensure_list, [cv.string]),
vol.Required(CONF_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Required(CONF_COMMAND_ON_TEMPLATE): cv.template,
vol.Required(CONF_COMMAND_OFF_TEMPLATE): cv.template,
vol.Optional(CONF_STATE_TEMPLATE): cv.template,
vol.Optional(CONF_BRIGHTNESS_TEMPLATE): cv.template,
vol.Optional(CONF_RED_TEMPLATE): cv.template,
vol.Optional(CONF_GREEN_TEMPLATE): cv.template,
vol.Optional(CONF_BLUE_TEMPLATE): cv.template,
vol.Optional(CONF_BRIGHTNESS_TEMPLATE): cv.template,
vol.Optional(CONF_COLOR_TEMP_TEMPLATE): cv.template,
vol.Optional(CONF_EFFECT_LIST): vol.All(cv.ensure_list, [cv.string]),
vol.Optional(CONF_EFFECT_TEMPLATE): cv.template,
vol.Optional(CONF_GREEN_TEMPLATE): cv.template,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean,
vol.Optional(CONF_RED_TEMPLATE): cv.template,
vol.Optional(CONF_RETAIN, default=mqtt.DEFAULT_RETAIN): cv.boolean,
vol.Optional(CONF_STATE_TEMPLATE): cv.template,
vol.Optional(CONF_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_WHITE_VALUE_TEMPLATE): cv.template,
vol.Required(CONF_COMMAND_OFF_TEMPLATE): cv.template,
vol.Required(CONF_COMMAND_ON_TEMPLATE): cv.template,
vol.Required(CONF_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_QOS, default=mqtt.DEFAULT_QOS):
vol.All(vol.Coerce(int), vol.In([0, 1, 2])),
vol.Optional(CONF_RETAIN, default=mqtt.DEFAULT_RETAIN): cv.boolean
})
@ -76,14 +78,16 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
},
{
key: config.get(key) for key in (
CONF_COMMAND_ON_TEMPLATE,
CONF_COMMAND_OFF_TEMPLATE,
CONF_STATE_TEMPLATE,
CONF_BRIGHTNESS_TEMPLATE,
CONF_RED_TEMPLATE,
CONF_GREEN_TEMPLATE,
CONF_BLUE_TEMPLATE,
CONF_EFFECT_TEMPLATE
CONF_BRIGHTNESS_TEMPLATE,
CONF_COLOR_TEMP_TEMPLATE,
CONF_COMMAND_OFF_TEMPLATE,
CONF_COMMAND_ON_TEMPLATE,
CONF_EFFECT_TEMPLATE,
CONF_GREEN_TEMPLATE,
CONF_RED_TEMPLATE,
CONF_STATE_TEMPLATE,
CONF_WHITE_VALUE_TEMPLATE,
)
},
config.get(CONF_OPTIMISTIC),
@ -114,6 +118,16 @@ class MqttTemplate(Light):
else:
self._brightness = None
if self._templates[CONF_COLOR_TEMP_TEMPLATE] is not None:
self._color_temp = 255
else:
self._color_temp = None
if self._templates[CONF_WHITE_VALUE_TEMPLATE] is not None:
self._white_value = 255
else:
self._white_value = None
if (self._templates[CONF_RED_TEMPLATE] is not None and
self._templates[CONF_GREEN_TEMPLATE] is not None and
self._templates[CONF_BLUE_TEMPLATE] is not None):
@ -156,6 +170,16 @@ class MqttTemplate(Light):
except ValueError:
_LOGGER.warning('Invalid brightness value received')
# read color temperature
if self._color_temp is not None:
try:
self._color_temp = int(
self._templates[CONF_COLOR_TEMP_TEMPLATE].
async_render_with_possible_json_value(payload)
)
except ValueError:
_LOGGER.warning('Invalid color temperature value received')
# read color
if self._rgb is not None:
try:
@ -171,6 +195,16 @@ class MqttTemplate(Light):
except ValueError:
_LOGGER.warning('Invalid color value received')
# read white value
if self._white_value is not None:
try:
self._white_value = int(
self._templates[CONF_WHITE_VALUE_TEMPLATE].
async_render_with_possible_json_value(payload)
)
except ValueError:
_LOGGER.warning('Invalid white value received')
# read effect
if self._templates[CONF_EFFECT_TEMPLATE] is not None:
effect = self._templates[CONF_EFFECT_TEMPLATE].\
@ -194,11 +228,21 @@ class MqttTemplate(Light):
"""Return the brightness of this light between 0..255."""
return self._brightness
@property
def color_temp(self):
"""Return the color temperature in mired."""
return self._color_temp
@property
def rgb_color(self):
"""Return the RGB color value [int, int, int]."""
return self._rgb
@property
def white_value(self):
"""Return the white property."""
return self._white_value
@property
def should_poll(self):
"""Return True if entity has to be polled for state.
@ -250,6 +294,13 @@ class MqttTemplate(Light):
if self._optimistic:
self._brightness = kwargs[ATTR_BRIGHTNESS]
# color_temp
if ATTR_COLOR_TEMP in kwargs:
values['color_temp'] = int(kwargs[ATTR_COLOR_TEMP])
if self._optimistic:
self._color_temp = kwargs[ATTR_COLOR_TEMP]
# color
if ATTR_RGB_COLOR in kwargs:
values['red'] = kwargs[ATTR_RGB_COLOR][0]
@ -259,6 +310,13 @@ class MqttTemplate(Light):
if self._optimistic:
self._rgb = kwargs[ATTR_RGB_COLOR]
# white value
if ATTR_WHITE_VALUE in kwargs:
values['white_value'] = int(kwargs[ATTR_WHITE_VALUE])
if self._optimistic:
self._white_value = kwargs[ATTR_WHITE_VALUE]
# effect
if ATTR_EFFECT in kwargs:
values['effect'] = kwargs.get(ATTR_EFFECT)
@ -307,12 +365,16 @@ class MqttTemplate(Light):
@property
def supported_features(self):
"""Flag supported features."""
features = 0
features = (SUPPORT_FLASH | SUPPORT_TRANSITION)
if self._brightness is not None:
features = features | SUPPORT_BRIGHTNESS
if self._rgb is not None:
features = features | SUPPORT_RGB_COLOR
if self._effect_list is not None:
features = features | SUPPORT_EFFECT
if self._color_temp is not None:
features = features | SUPPORT_COLOR_TEMP
if self._white_value is not None:
features = features | SUPPORT_WHITE_VALUE
return features

View File

@ -20,7 +20,13 @@ _LOGGER = logging.getLogger(__name__)
TOPIC_MATCHER = re.compile(
r'(?P<prefix_topic>\w+)/(?P<component>\w+)/(?P<object_id>\w+)/config')
SUPPORTED_COMPONENTS = ['binary_sensor', 'sensor']
SUPPORTED_COMPONENTS = ['binary_sensor', 'light', 'sensor']
ALLOWED_PLATFORMS = {
'binary_sensor': ['mqtt'],
'light': ['mqtt', 'mqtt_json', 'mqtt_template'],
'sensor': ['mqtt']
}
@asyncio.coroutine
@ -48,7 +54,13 @@ def async_start(hass, discovery_topic, hass_config):
return
payload = dict(payload)
payload[CONF_PLATFORM] = 'mqtt'
platform = payload.get(CONF_PLATFORM, 'mqtt')
if platform not in ALLOWED_PLATFORMS.get(component, []):
_LOGGER.warning("Platform %s (component %s) is not allowed",
platform, component)
return
payload[CONF_PLATFORM] = platform
if CONF_STATE_TOPIC not in payload:
payload[CONF_STATE_TOPIC] = '{}/{}/{}/state'.format(
discovery_topic, component, object_id)

View File

@ -87,6 +87,7 @@ CONF_DISCOVERY = 'discovery'
CONF_DISPLAY_OPTIONS = 'display_options'
CONF_DOMAIN = 'domain'
CONF_DOMAINS = 'domains'
CONF_EFFECT = 'effect'
CONF_ELEVATION = 'elevation'
CONF_EMAIL = 'email'
CONF_ENTITIES = 'entities'
@ -153,6 +154,8 @@ CONF_VALUE_TEMPLATE = 'value_template'
CONF_VERIFY_SSL = 'verify_ssl'
CONF_WEEKDAY = 'weekday'
CONF_WHITELIST = 'whitelist'
CONF_WHITE_VALUE = 'white_value'
CONF_XY = 'xy'
CONF_ZONE = 'zone'
# #### EVENTS ####

View File

@ -15,6 +15,21 @@ light:
payload_on: "on"
payload_off: "off"
Configuration for XY Version with brightness:
light:
platform: mqtt
name: "Office Light XY"
state_topic: "office/xy1/light/status"
command_topic: "office/xy1/light/switch"
brightness_state_topic: "office/xy1/brightness/status"
brightness_command_topic: "office/xy1/brightness/set"
xy_state_topic: "office/xy1/xy/status"
xy_command_topic: "office/xy1/xy/set"
qos: 0
payload_on: "on"
payload_off: "off"
config without RGB:
light:
@ -72,6 +87,42 @@ light:
payload_on: "on"
payload_off: "off"
config with brightness and effect
light:
platform: mqtt
name: "Office Light Color Temp"
state_topic: "office/rgb1/light/status"
command_topic: "office/rgb1/light/switch"
brightness_state_topic: "office/rgb1/brightness/status"
brightness_command_topic: "office/rgb1/brightness/set"
brightness_scale: 99
effect_state_topic: "office/rgb1/effect/status"
effect_command_topic: "office/rgb1/effect/set"
effect_list:
- rainbow
- colorloop
qos: 0
payload_on: "on"
payload_off: "off"
config for RGB Version with white value and scale:
light:
platform: mqtt
name: "Office Light RGB"
state_topic: "office/rgb1/light/status"
command_topic: "office/rgb1/light/switch"
white_value_state_topic: "office/rgb1/white_value/status"
white_value_command_topic: "office/rgb1/white_value/set"
white_value_scale: 99
rgb_state_topic: "office/rgb1/rgb/status"
rgb_command_topic: "office/rgb1/rgb/set"
rgb_scale: 99
qos: 0
payload_on: "on"
payload_off: "off"
"""
import unittest
from unittest import mock
@ -109,7 +160,7 @@ class TestLightMQTT(unittest.TestCase):
})
self.assertIsNone(self.hass.states.get('light.test'))
def test_no_color_or_brightness_or_color_temp_if_no_topics(self): \
def test_no_color_brightness_color_temp_white_xy_if_no_topics(self): \
# pylint: disable=invalid-name
"""Test if there is no color and brightness if no topic."""
with assert_setup_component(1):
@ -127,6 +178,8 @@ class TestLightMQTT(unittest.TestCase):
self.assertIsNone(state.attributes.get('rgb_color'))
self.assertIsNone(state.attributes.get('brightness'))
self.assertIsNone(state.attributes.get('color_temp'))
self.assertIsNone(state.attributes.get('white_value'))
self.assertIsNone(state.attributes.get('xy_color'))
fire_mqtt_message(self.hass, 'test_light_rgb/status', 'ON')
self.hass.block_till_done()
@ -136,6 +189,8 @@ class TestLightMQTT(unittest.TestCase):
self.assertIsNone(state.attributes.get('rgb_color'))
self.assertIsNone(state.attributes.get('brightness'))
self.assertIsNone(state.attributes.get('color_temp'))
self.assertIsNone(state.attributes.get('white_value'))
self.assertIsNone(state.attributes.get('xy_color'))
def test_controlling_state_via_topic(self): \
# pylint: disable=invalid-name
@ -151,6 +206,12 @@ class TestLightMQTT(unittest.TestCase):
'rgb_command_topic': 'test_light_rgb/rgb/set',
'color_temp_state_topic': 'test_light_rgb/color_temp/status',
'color_temp_command_topic': 'test_light_rgb/color_temp/set',
'effect_state_topic': 'test_light_rgb/effect/status',
'effect_command_topic': 'test_light_rgb/effect/set',
'white_value_state_topic': 'test_light_rgb/white_value/status',
'white_value_command_topic': 'test_light_rgb/white_value/set',
'xy_state_topic': 'test_light_rgb/xy/status',
'xy_command_topic': 'test_light_rgb/xy/set',
'qos': '0',
'payload_on': 1,
'payload_off': 0
@ -164,6 +225,9 @@ class TestLightMQTT(unittest.TestCase):
self.assertIsNone(state.attributes.get('rgb_color'))
self.assertIsNone(state.attributes.get('brightness'))
self.assertIsNone(state.attributes.get('color_temp'))
self.assertIsNone(state.attributes.get('effect'))
self.assertIsNone(state.attributes.get('white_value'))
self.assertIsNone(state.attributes.get('xy_color'))
self.assertIsNone(state.attributes.get(ATTR_ASSUMED_STATE))
fire_mqtt_message(self.hass, 'test_light_rgb/status', '1')
@ -174,6 +238,9 @@ class TestLightMQTT(unittest.TestCase):
self.assertEqual([255, 255, 255], state.attributes.get('rgb_color'))
self.assertEqual(255, state.attributes.get('brightness'))
self.assertEqual(150, state.attributes.get('color_temp'))
self.assertEqual('none', state.attributes.get('effect'))
self.assertEqual(255, state.attributes.get('white_value'))
self.assertEqual([1, 1], state.attributes.get('xy_color'))
fire_mqtt_message(self.hass, 'test_light_rgb/status', '0')
self.hass.block_till_done()
@ -198,6 +265,21 @@ class TestLightMQTT(unittest.TestCase):
self.hass.block_till_done()
self.assertEqual(300, light_state.attributes['color_temp'])
fire_mqtt_message(self.hass, 'test_light_rgb/effect/status', 'rainbow')
self.hass.block_till_done()
light_state = self.hass.states.get('light.test')
self.hass.block_till_done()
self.assertEqual('rainbow', light_state.attributes['effect'])
fire_mqtt_message(self.hass, 'test_light_rgb/white_value/status',
'100')
self.hass.block_till_done()
light_state = self.hass.states.get('light.test')
self.hass.block_till_done()
self.assertEqual(100,
light_state.attributes['white_value'])
fire_mqtt_message(self.hass, 'test_light_rgb/status', '1')
self.hass.block_till_done()
@ -209,8 +291,16 @@ class TestLightMQTT(unittest.TestCase):
self.assertEqual([125, 125, 125],
light_state.attributes.get('rgb_color'))
def test_controlling_scale(self):
"""Test the controlling scale."""
fire_mqtt_message(self.hass, 'test_light_rgb/xy/status',
'0.675,0.322')
self.hass.block_till_done()
light_state = self.hass.states.get('light.test')
self.assertEqual([0.675, 0.322],
light_state.attributes.get('xy_color'))
def test_brightness_controlling_scale(self):
"""Test the brightness controlling scale."""
with assert_setup_component(1):
assert setup_component(self.hass, light.DOMAIN, {
light.DOMAIN: {
@ -256,6 +346,53 @@ class TestLightMQTT(unittest.TestCase):
self.assertEqual(255,
light_state.attributes['brightness'])
def test_white_value_controlling_scale(self):
"""Test the white_value controlling scale."""
with assert_setup_component(1):
assert setup_component(self.hass, light.DOMAIN, {
light.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'state_topic': 'test_scale/status',
'command_topic': 'test_scale/set',
'white_value_state_topic': 'test_scale/white_value/status',
'white_value_command_topic': 'test_scale/white_value/set',
'white_value_scale': '99',
'qos': 0,
'payload_on': 'on',
'payload_off': 'off'
}
})
state = self.hass.states.get('light.test')
self.assertEqual(STATE_OFF, state.state)
self.assertIsNone(state.attributes.get('white_value'))
self.assertIsNone(state.attributes.get(ATTR_ASSUMED_STATE))
fire_mqtt_message(self.hass, 'test_scale/status', 'on')
self.hass.block_till_done()
state = self.hass.states.get('light.test')
self.assertEqual(STATE_ON, state.state)
self.assertEqual(255, state.attributes.get('white_value'))
fire_mqtt_message(self.hass, 'test_scale/status', 'off')
self.hass.block_till_done()
state = self.hass.states.get('light.test')
self.assertEqual(STATE_OFF, state.state)
fire_mqtt_message(self.hass, 'test_scale/status', 'on')
self.hass.block_till_done()
fire_mqtt_message(self.hass, 'test_scale/white_value/status', '99')
self.hass.block_till_done()
light_state = self.hass.states.get('light.test')
self.hass.block_till_done()
self.assertEqual(255,
light_state.attributes['white_value'])
def test_controlling_state_via_topic_with_templates(self): \
# pylint: disable=invalid-name
"""Test the setting og the state with a template."""
@ -266,11 +403,17 @@ class TestLightMQTT(unittest.TestCase):
'command_topic': 'test_light_rgb/set',
'brightness_state_topic': 'test_light_rgb/brightness/status',
'color_temp_state_topic': 'test_light_rgb/color_temp/status',
'effect_state_topic': 'test_light_rgb/effect/status',
'rgb_state_topic': 'test_light_rgb/rgb/status',
'white_value_state_topic': 'test_light_rgb/white_value/status',
'xy_state_topic': 'test_light_rgb/xy/status',
'state_value_template': '{{ value_json.hello }}',
'brightness_value_template': '{{ value_json.hello }}',
'color_temp_value_template': '{{ value_json.hello }}',
'effect_value_template': '{{ value_json.hello }}',
'rgb_value_template': '{{ value_json.hello | join(",") }}',
'white_value_template': '{{ value_json.hello }}',
'xy_value_template': '{{ value_json.hello | join(",") }}',
}}
with assert_setup_component(1):
@ -289,6 +432,12 @@ class TestLightMQTT(unittest.TestCase):
'{"hello": "50"}')
fire_mqtt_message(self.hass, 'test_light_rgb/color_temp/status',
'{"hello": "300"}')
fire_mqtt_message(self.hass, 'test_light_rgb/effect/status',
'{"hello": "rainbow"}')
fire_mqtt_message(self.hass, 'test_light_rgb/white_value/status',
'{"hello": "75"}')
fire_mqtt_message(self.hass, 'test_light_rgb/xy/status',
'{"hello": [0.123,0.123]}')
self.hass.block_till_done()
state = self.hass.states.get('light.test')
@ -296,6 +445,9 @@ class TestLightMQTT(unittest.TestCase):
self.assertEqual(50, state.attributes.get('brightness'))
self.assertEqual([1, 2, 3], state.attributes.get('rgb_color'))
self.assertEqual(300, state.attributes.get('color_temp'))
self.assertEqual('rainbow', state.attributes.get('effect'))
self.assertEqual(75, state.attributes.get('white_value'))
self.assertEqual([0.123, 0.123], state.attributes.get('xy_color'))
def test_sending_mqtt_commands_and_optimistic(self): \
# pylint: disable=invalid-name
@ -307,6 +459,9 @@ class TestLightMQTT(unittest.TestCase):
'brightness_command_topic': 'test_light_rgb/brightness/set',
'rgb_command_topic': 'test_light_rgb/rgb/set',
'color_temp_command_topic': 'test_light_rgb/color_temp/set',
'effect_command_topic': 'test_light_rgb/effect/set',
'white_value_command_topic': 'test_light_rgb/white_value/set',
'xy_command_topic': 'test_light_rgb/xy/set',
'qos': 2,
'payload_on': 'on',
'payload_off': 'off'
@ -337,19 +492,23 @@ class TestLightMQTT(unittest.TestCase):
self.mock_publish.reset_mock()
light.turn_on(self.hass, 'light.test', rgb_color=[75, 75, 75],
brightness=50)
brightness=50, white_value=80, xy_color=[0.123, 0.123])
self.hass.block_till_done()
self.mock_publish().async_publish.assert_has_calls([
mock.call('test_light_rgb/set', 'on', 2, False),
mock.call('test_light_rgb/rgb/set', '75,75,75', 2, False),
mock.call('test_light_rgb/brightness/set', 50, 2, False),
], any_order=True)
mock.call('test_light_rgb/set', 'on', 2, False),
mock.call('test_light_rgb/rgb/set', '75,75,75', 2, False),
mock.call('test_light_rgb/brightness/set', 50, 2, False),
mock.call('test_light_rgb/white_value/set', 80, 2, False),
mock.call('test_light_rgb/xy/set', '0.123,0.123', 2, False),
], any_order=True)
state = self.hass.states.get('light.test')
self.assertEqual(STATE_ON, state.state)
self.assertEqual((75, 75, 75), state.attributes['rgb_color'])
self.assertEqual(50, state.attributes['brightness'])
self.assertEqual(80, state.attributes['white_value'])
self.assertEqual((0.123, 0.123), state.attributes['xy_color'])
def test_show_brightness_if_only_command_topic(self):
"""Test the brightness if only a command topic is present."""
@ -398,3 +557,75 @@ class TestLightMQTT(unittest.TestCase):
state = self.hass.states.get('light.test')
self.assertEqual(STATE_ON, state.state)
self.assertEqual(150, state.attributes.get('color_temp'))
def test_show_effect_only_if_command_topic(self):
"""Test the color temp only if a command topic is present."""
config = {light.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'effect_command_topic': 'test_light_rgb/effect/set',
'command_topic': 'test_light_rgb/set',
'state_topic': 'test_light_rgb/status'
}}
with assert_setup_component(1):
assert setup_component(self.hass, light.DOMAIN, config)
state = self.hass.states.get('light.test')
self.assertEqual(STATE_OFF, state.state)
self.assertIsNone(state.attributes.get('effect'))
fire_mqtt_message(self.hass, 'test_light_rgb/status', 'ON')
self.hass.block_till_done()
state = self.hass.states.get('light.test')
self.assertEqual(STATE_ON, state.state)
self.assertEqual('none', state.attributes.get('effect'))
def test_show_white_value_if_only_command_topic(self):
"""Test the white_value if only a command topic is present."""
config = {light.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'white_value_command_topic': 'test_light_rgb/white_value/set',
'command_topic': 'test_light_rgb/set',
'state_topic': 'test_light_rgb/status',
}}
with assert_setup_component(1):
assert setup_component(self.hass, light.DOMAIN, config)
state = self.hass.states.get('light.test')
self.assertEqual(STATE_OFF, state.state)
self.assertIsNone(state.attributes.get('white_value'))
fire_mqtt_message(self.hass, 'test_light_rgb/status', 'ON')
self.hass.block_till_done()
state = self.hass.states.get('light.test')
self.assertEqual(STATE_ON, state.state)
self.assertEqual(255, state.attributes.get('white_value'))
def test_show_xy_if_only_command_topic(self):
"""Test the xy if only a command topic is present."""
config = {light.DOMAIN: {
'platform': 'mqtt',
'name': 'test',
'xy_command_topic': 'test_light_rgb/xy/set',
'command_topic': 'test_light_rgb/set',
'state_topic': 'test_light_rgb/status',
}}
with assert_setup_component(1):
assert setup_component(self.hass, light.DOMAIN, config)
state = self.hass.states.get('light.test')
self.assertEqual(STATE_OFF, state.state)
self.assertIsNone(state.attributes.get('xy_color'))
fire_mqtt_message(self.hass, 'test_light_rgb/status', 'ON')
self.hass.block_till_done()
state = self.hass.states.get('light.test')
self.assertEqual(STATE_ON, state.state)
self.assertEqual([1, 1], state.attributes.get('xy_color'))

View File

@ -1,6 +1,56 @@
"""The tests for the MQTT JSON light platform.
Configuration for RGB Version with brightness:
Configuration with RGB, brightness, color temp, effect, white value and XY:
light:
platform: mqtt_json
name: mqtt_json_light_1
state_topic: "home/rgb1"
command_topic: "home/rgb1/set"
brightness: true
color_temp: true
effect: true
rgb: true
white_value: true
xy: true
Configuration with RGB, brightness, color temp, effect, white value:
light:
platform: mqtt_json
name: mqtt_json_light_1
state_topic: "home/rgb1"
command_topic: "home/rgb1/set"
brightness: true
color_temp: true
effect: true
rgb: true
white_value: true
Configuration with RGB, brightness, color temp and effect:
light:
platform: mqtt_json
name: mqtt_json_light_1
state_topic: "home/rgb1"
command_topic: "home/rgb1/set"
brightness: true
color_temp: true
effect: true
rgb: true
Configuration with RGB, brightness and color temp:
light:
platform: mqtt_json
name: mqtt_json_light_1
state_topic: "home/rgb1"
command_topic: "home/rgb1/set"
brightness: true
rgb: true
color_temp: true
Configuration with RGB, brightness:
light:
platform: mqtt_json
@ -62,9 +112,9 @@ class TestLightMQTTJSON(unittest.TestCase):
})
self.assertIsNone(self.hass.states.get('light.test'))
def test_no_color_or_brightness_if_no_config(self): \
def test_no_color_brightness_color_temp_white_val_if_no_topics(self): \
# pylint: disable=invalid-name
"""Test if there is no color and brightness if they aren't defined."""
"""Test for no RGB, brightness, color temp, effect, white val or XY."""
assert setup_component(self.hass, light.DOMAIN, {
light.DOMAIN: {
'platform': 'mqtt_json',
@ -78,6 +128,10 @@ class TestLightMQTTJSON(unittest.TestCase):
self.assertEqual(STATE_OFF, state.state)
self.assertIsNone(state.attributes.get('rgb_color'))
self.assertIsNone(state.attributes.get('brightness'))
self.assertIsNone(state.attributes.get('color_temp'))
self.assertIsNone(state.attributes.get('effect'))
self.assertIsNone(state.attributes.get('white_value'))
self.assertIsNone(state.attributes.get('xy_color'))
fire_mqtt_message(self.hass, 'test_light_rgb', '{"state":"ON"}')
self.hass.block_till_done()
@ -86,6 +140,10 @@ class TestLightMQTTJSON(unittest.TestCase):
self.assertEqual(STATE_ON, state.state)
self.assertIsNone(state.attributes.get('rgb_color'))
self.assertIsNone(state.attributes.get('brightness'))
self.assertIsNone(state.attributes.get('color_temp'))
self.assertIsNone(state.attributes.get('effect'))
self.assertIsNone(state.attributes.get('white_value'))
self.assertIsNone(state.attributes.get('xy_color'))
def test_controlling_state_via_topic(self): \
# pylint: disable=invalid-name
@ -97,7 +155,11 @@ class TestLightMQTTJSON(unittest.TestCase):
'state_topic': 'test_light_rgb',
'command_topic': 'test_light_rgb/set',
'brightness': True,
'color_temp': True,
'effect': True,
'rgb': True,
'white_value': True,
'xy': True,
'qos': '0'
}
})
@ -106,19 +168,31 @@ class TestLightMQTTJSON(unittest.TestCase):
self.assertEqual(STATE_OFF, state.state)
self.assertIsNone(state.attributes.get('rgb_color'))
self.assertIsNone(state.attributes.get('brightness'))
self.assertIsNone(state.attributes.get('color_temp'))
self.assertIsNone(state.attributes.get('effect'))
self.assertIsNone(state.attributes.get('white_value'))
self.assertIsNone(state.attributes.get('xy_color'))
self.assertIsNone(state.attributes.get(ATTR_ASSUMED_STATE))
# Turn on the light, full white
fire_mqtt_message(self.hass, 'test_light_rgb',
'{"state":"ON",'
'"color":{"r":255,"g":255,"b":255},'
'"brightness":255}')
'"color":{"r":255,"g":255,"b":255,'
'"x":0.123,"y":0.123},'
'"brightness":255,'
'"color_temp":155,'
'"effect":"colorloop",'
'"white_value":150}')
self.hass.block_till_done()
state = self.hass.states.get('light.test')
self.assertEqual(STATE_ON, state.state)
self.assertEqual([255, 255, 255], state.attributes.get('rgb_color'))
self.assertEqual(255, state.attributes.get('brightness'))
self.assertEqual(155, state.attributes.get('color_temp'))
self.assertEqual('colorloop', state.attributes.get('effect'))
self.assertEqual(150, state.attributes.get('white_value'))
self.assertEqual([0.123, 0.123], state.attributes.get('xy_color'))
# Turn the light off
fire_mqtt_message(self.hass, 'test_light_rgb', '{"state":"OFF"}')
@ -146,6 +220,39 @@ class TestLightMQTTJSON(unittest.TestCase):
self.assertEqual([125, 125, 125],
light_state.attributes.get('rgb_color'))
fire_mqtt_message(self.hass, 'test_light_rgb',
'{"state":"ON",'
'"color":{"x":0.135,"y":0.135}}')
self.hass.block_till_done()
light_state = self.hass.states.get('light.test')
self.assertEqual([0.135, 0.135],
light_state.attributes.get('xy_color'))
fire_mqtt_message(self.hass, 'test_light_rgb',
'{"state":"ON",'
'"color_temp":155}')
self.hass.block_till_done()
light_state = self.hass.states.get('light.test')
self.assertEqual(155, light_state.attributes.get('color_temp'))
fire_mqtt_message(self.hass, 'test_light_rgb',
'{"state":"ON",'
'"effect":"colorloop"}')
self.hass.block_till_done()
light_state = self.hass.states.get('light.test')
self.assertEqual('colorloop', light_state.attributes.get('effect'))
fire_mqtt_message(self.hass, 'test_light_rgb',
'{"state":"ON",'
'"white_value":155}')
self.hass.block_till_done()
light_state = self.hass.states.get('light.test')
self.assertEqual(155, light_state.attributes.get('white_value'))
def test_sending_mqtt_commands_and_optimistic(self): \
# pylint: disable=invalid-name
"""Test the sending of command in optimistic mode."""
@ -155,7 +262,10 @@ class TestLightMQTTJSON(unittest.TestCase):
'name': 'test',
'command_topic': 'test_light_rgb/set',
'brightness': True,
'color_temp': True,
'effect': True,
'rgb': True,
'white_value': True,
'qos': 2
}
})
@ -181,7 +291,8 @@ class TestLightMQTTJSON(unittest.TestCase):
self.assertEqual(STATE_OFF, state.state)
light.turn_on(self.hass, 'light.test', rgb_color=[75, 75, 75],
brightness=50)
brightness=50, color_temp=155, effect='colorloop',
white_value=170)
self.hass.block_till_done()
self.assertEqual('test_light_rgb/set',
@ -191,15 +302,21 @@ class TestLightMQTTJSON(unittest.TestCase):
# Get the sent message
message_json = json.loads(self.mock_publish.mock_calls[-2][1][1])
self.assertEqual(50, message_json["brightness"])
self.assertEqual(155, message_json["color_temp"])
self.assertEqual('colorloop', message_json["effect"])
self.assertEqual(75, message_json["color"]["r"])
self.assertEqual(75, message_json["color"]["g"])
self.assertEqual(75, message_json["color"]["b"])
self.assertEqual(170, message_json["white_value"])
self.assertEqual("ON", message_json["state"])
state = self.hass.states.get('light.test')
self.assertEqual(STATE_ON, state.state)
self.assertEqual((75, 75, 75), state.attributes['rgb_color'])
self.assertEqual(50, state.attributes['brightness'])
self.assertEqual(155, state.attributes['color_temp'])
self.assertEqual('colorloop', state.attributes['effect'])
self.assertEqual(170, state.attributes['white_value'])
def test_flash_short_and_long(self): \
# pylint: disable=invalid-name
@ -283,9 +400,9 @@ class TestLightMQTTJSON(unittest.TestCase):
self.assertEqual(10, message_json["transition"])
self.assertEqual("OFF", message_json["state"])
def test_invalid_color_and_brightness_values(self): \
def test_invalid_color_brightness_and_white_values(self): \
# pylint: disable=invalid-name
"""Test that invalid color/brightness values are ignored."""
"""Test that invalid color/brightness/white values are ignored."""
assert setup_component(self.hass, light.DOMAIN, {
light.DOMAIN: {
'platform': 'mqtt_json',
@ -294,6 +411,7 @@ class TestLightMQTTJSON(unittest.TestCase):
'command_topic': 'test_light_rgb/set',
'brightness': True,
'rgb': True,
'white_value': True,
'qos': '0'
}
})
@ -302,19 +420,22 @@ class TestLightMQTTJSON(unittest.TestCase):
self.assertEqual(STATE_OFF, state.state)
self.assertIsNone(state.attributes.get('rgb_color'))
self.assertIsNone(state.attributes.get('brightness'))
self.assertIsNone(state.attributes.get('white_value'))
self.assertIsNone(state.attributes.get(ATTR_ASSUMED_STATE))
# Turn on the light
fire_mqtt_message(self.hass, 'test_light_rgb',
'{"state":"ON",'
'"color":{"r":255,"g":255,"b":255},'
'"brightness": 255}')
'"brightness": 255,'
'"white_value": 255}')
self.hass.block_till_done()
state = self.hass.states.get('light.test')
self.assertEqual(STATE_ON, state.state)
self.assertEqual([255, 255, 255], state.attributes.get('rgb_color'))
self.assertEqual(255, state.attributes.get('brightness'))
self.assertEqual(255, state.attributes.get('white_value'))
# Bad color values
fire_mqtt_message(self.hass, 'test_light_rgb',
@ -337,3 +458,14 @@ class TestLightMQTTJSON(unittest.TestCase):
state = self.hass.states.get('light.test')
self.assertEqual(STATE_ON, state.state)
self.assertEqual(255, state.attributes.get('brightness'))
# Bad white value
fire_mqtt_message(self.hass, 'test_light_rgb',
'{"state":"ON",'
'"white_value": "badValue"}')
self.hass.block_till_done()
# White value should not have changed
state = self.hass.states.get('light.test')
self.assertEqual(STATE_ON, state.state)
self.assertEqual(255, state.attributes.get('white_value'))

View File

@ -12,13 +12,19 @@ light:
command_off_template: 'off'
state_template: '{{ value.split(",")[0] }}'
brightness_template: '{{ value.split(",")[1] }}'
red_template: '{{ value.split(",")[2].split("-")[0] }}'
green_template: '{{ value.split(",")[2].split("-")[1] }}'
blue_template: '{{ value.split(",")[2].split("-")[2] }}'
color_temp_template: '{{ value.split(",")[2] }}'
white_value_template: '{{ value.split(",")[3] }}'
red_template: '{{ value.split(",")[4].split("-")[0] }}'
green_template: '{{ value.split(",")[4].split("-")[1] }}'
blue_template: '{{ value.split(",")[4].split("-")[2] }}'
If your light doesn't support brightness feature, omit `brightness_template`.
If your light doesn't support rgb feature, omit `(red|green|blue)_template`.
If your light doesn't support color temp feature, omit `color_temp_template`.
If your light doesn't support white value feature, omit `white_value_template`.
If your light doesn't support RGB feature, omit `(red|green|blue)_template`.
"""
import unittest
@ -66,6 +72,8 @@ class TestLightMQTTTemplate(unittest.TestCase):
'command_topic': 'test_light_rgb/set',
'command_on_template': 'on,'
'{{ brightness|d }},'
'{{ color_temp|d }},'
'{{ white_value|d }},'
'{{ red|d }}-'
'{{ green|d }}-'
'{{ blue|d }}',
@ -78,6 +86,8 @@ class TestLightMQTTTemplate(unittest.TestCase):
self.assertEqual(STATE_OFF, state.state)
self.assertIsNone(state.attributes.get('rgb_color'))
self.assertIsNone(state.attributes.get('brightness'))
self.assertIsNone(state.attributes.get('color_temp'))
self.assertIsNone(state.attributes.get('white_value'))
self.assertIsNone(state.attributes.get(ATTR_ASSUMED_STATE))
fire_mqtt_message(self.hass, 'test_light_rgb', 'on')
@ -87,10 +97,12 @@ class TestLightMQTTTemplate(unittest.TestCase):
self.assertEqual(STATE_ON, state.state)
self.assertIsNone(state.attributes.get('rgb_color'))
self.assertIsNone(state.attributes.get('brightness'))
self.assertIsNone(state.attributes.get('color_temp'))
self.assertIsNone(state.attributes.get('white_value'))
def test_state_brightness_color_effect_change_via_topic(self): \
def test_state_brightness_color_effect_temp_white_change_via_topic(self): \
# pylint: disable=invalid-name
"""Test state, brightness, color and effect change via topic."""
"""Test state, bri, color, effect, color temp, white val change."""
with assert_setup_component(1):
assert setup_component(self.hass, light.DOMAIN, {
light.DOMAIN: {
@ -101,6 +113,8 @@ class TestLightMQTTTemplate(unittest.TestCase):
'command_topic': 'test_light_rgb/set',
'command_on_template': 'on,'
'{{ brightness|d }},'
'{{ color_temp|d }},'
'{{ white_value|d }},'
'{{ red|d }}-'
'{{ green|d }}-'
'{{ blue|d }},'
@ -108,13 +122,15 @@ class TestLightMQTTTemplate(unittest.TestCase):
'command_off_template': 'off',
'state_template': '{{ value.split(",")[0] }}',
'brightness_template': '{{ value.split(",")[1] }}',
'red_template': '{{ value.split(",")[2].'
'color_temp_template': '{{ value.split(",")[2] }}',
'white_value_template': '{{ value.split(",")[3] }}',
'red_template': '{{ value.split(",")[4].'
'split("-")[0] }}',
'green_template': '{{ value.split(",")[2].'
'green_template': '{{ value.split(",")[4].'
'split("-")[1] }}',
'blue_template': '{{ value.split(",")[2].'
'blue_template': '{{ value.split(",")[4].'
'split("-")[2] }}',
'effect_template': '{{ value.split(",")[3] }}'
'effect_template': '{{ value.split(",")[5] }}'
}
})
@ -123,16 +139,21 @@ class TestLightMQTTTemplate(unittest.TestCase):
self.assertIsNone(state.attributes.get('rgb_color'))
self.assertIsNone(state.attributes.get('brightness'))
self.assertIsNone(state.attributes.get('effect'))
self.assertIsNone(state.attributes.get('color_temp'))
self.assertIsNone(state.attributes.get('white_value'))
self.assertIsNone(state.attributes.get(ATTR_ASSUMED_STATE))
# turn on the light, full white
fire_mqtt_message(self.hass, 'test_light_rgb', 'on,255,255-255-255,')
fire_mqtt_message(self.hass, 'test_light_rgb',
'on,255,145,123,255-255-255,')
self.hass.block_till_done()
state = self.hass.states.get('light.test')
self.assertEqual(STATE_ON, state.state)
self.assertEqual([255, 255, 255], state.attributes.get('rgb_color'))
self.assertEqual(255, state.attributes.get('brightness'))
self.assertEqual(145, state.attributes.get('color_temp'))
self.assertEqual(123, state.attributes.get('white_value'))
self.assertIsNone(state.attributes.get('effect'))
# turn the light off
@ -150,15 +171,32 @@ class TestLightMQTTTemplate(unittest.TestCase):
self.hass.block_till_done()
self.assertEqual(100, light_state.attributes['brightness'])
# change the color temp
fire_mqtt_message(self.hass, 'test_light_rgb', 'on,,195')
self.hass.block_till_done()
light_state = self.hass.states.get('light.test')
self.hass.block_till_done()
self.assertEqual(195, light_state.attributes['color_temp'])
# change the color
fire_mqtt_message(self.hass, 'test_light_rgb', 'on,,41-42-43')
fire_mqtt_message(self.hass, 'test_light_rgb', 'on,,,,41-42-43')
self.hass.block_till_done()
light_state = self.hass.states.get('light.test')
self.assertEqual([41, 42, 43], light_state.attributes.get('rgb_color'))
# change the white value
fire_mqtt_message(self.hass, 'test_light_rgb', 'on,,,134')
self.hass.block_till_done()
light_state = self.hass.states.get('light.test')
self.hass.block_till_done()
self.assertEqual(134, light_state.attributes['white_value'])
# change the effect
fire_mqtt_message(self.hass, 'test_light_rgb', 'on,,41-42-43,rainbow')
fire_mqtt_message(self.hass, 'test_light_rgb',
'on,,,,41-42-43,rainbow')
self.hass.block_till_done()
light_state = self.hass.states.get('light.test')
@ -175,6 +213,8 @@ class TestLightMQTTTemplate(unittest.TestCase):
'command_topic': 'test_light_rgb/set',
'command_on_template': 'on,'
'{{ brightness|d }},'
'{{ color_temp|d }},'
'{{ white_value|d }},'
'{{ red|d }}-'
'{{ green|d }}-'
'{{ blue|d }}',
@ -191,7 +231,7 @@ class TestLightMQTTTemplate(unittest.TestCase):
light.turn_on(self.hass, 'light.test')
self.hass.block_till_done()
self.assertEqual(('test_light_rgb/set', 'on,,--', 2, False),
self.assertEqual(('test_light_rgb/set', 'on,,,,--', 2, False),
self.mock_publish.mock_calls[-2][1])
state = self.hass.states.get('light.test')
self.assertEqual(STATE_ON, state.state)
@ -205,9 +245,9 @@ class TestLightMQTTTemplate(unittest.TestCase):
state = self.hass.states.get('light.test')
self.assertEqual(STATE_OFF, state.state)
# turn on the light with brightness and color
# turn on the light with brightness, color, color temp and white val
light.turn_on(self.hass, 'light.test', brightness=50,
rgb_color=[75, 75, 75])
rgb_color=[75, 75, 75], color_temp=200, white_value=139)
self.hass.block_till_done()
self.assertEqual('test_light_rgb/set',
@ -217,13 +257,15 @@ class TestLightMQTTTemplate(unittest.TestCase):
# check the payload
payload = self.mock_publish.mock_calls[-2][1][1]
self.assertEqual('on,50,75-75-75', payload)
self.assertEqual('on,50,200,139,75-75-75', payload)
# check the state
state = self.hass.states.get('light.test')
self.assertEqual(STATE_ON, state.state)
self.assertEqual((75, 75, 75), state.attributes['rgb_color'])
self.assertEqual(50, state.attributes['brightness'])
self.assertEqual(200, state.attributes['color_temp'])
self.assertEqual(139, state.attributes['white_value'])
def test_flash(self): \
# pylint: disable=invalid-name
@ -324,6 +366,7 @@ class TestLightMQTTTemplate(unittest.TestCase):
'command_topic': 'test_light_rgb/set',
'command_on_template': 'on,'
'{{ brightness|d }},'
'{{ color_temp|d }},'
'{{ red|d }}-'
'{{ green|d }}-'
'{{ blue|d }},'
@ -331,13 +374,15 @@ class TestLightMQTTTemplate(unittest.TestCase):
'command_off_template': 'off',
'state_template': '{{ value.split(",")[0] }}',
'brightness_template': '{{ value.split(",")[1] }}',
'red_template': '{{ value.split(",")[2].'
'color_temp_template': '{{ value.split(",")[2] }}',
'white_value_template': '{{ value.split(",")[3] }}',
'red_template': '{{ value.split(",")[4].'
'split("-")[0] }}',
'green_template': '{{ value.split(",")[2].'
'green_template': '{{ value.split(",")[4].'
'split("-")[1] }}',
'blue_template': '{{ value.split(",")[2].'
'blue_template': '{{ value.split(",")[4].'
'split("-")[2] }}',
'effect_template': '{{ value.split(",")[3] }}',
'effect_template': '{{ value.split(",")[5] }}',
}
})
@ -345,18 +390,22 @@ class TestLightMQTTTemplate(unittest.TestCase):
self.assertEqual(STATE_OFF, state.state)
self.assertIsNone(state.attributes.get('rgb_color'))
self.assertIsNone(state.attributes.get('brightness'))
self.assertIsNone(state.attributes.get('color_temp'))
self.assertIsNone(state.attributes.get('effect'))
self.assertIsNone(state.attributes.get('white_value'))
self.assertIsNone(state.attributes.get(ATTR_ASSUMED_STATE))
# turn on the light, full white
fire_mqtt_message(self.hass, 'test_light_rgb',
'on,255,255-255-255,rainbow')
'on,255,215,222,255-255-255,rainbow')
self.hass.block_till_done()
state = self.hass.states.get('light.test')
self.assertEqual(STATE_ON, state.state)
self.assertEqual(255, state.attributes.get('brightness'))
self.assertEqual(215, state.attributes.get('color_temp'))
self.assertEqual([255, 255, 255], state.attributes.get('rgb_color'))
self.assertEqual(222, state.attributes.get('white_value'))
self.assertEqual('rainbow', state.attributes.get('effect'))
# bad state value
@ -375,6 +424,14 @@ class TestLightMQTTTemplate(unittest.TestCase):
state = self.hass.states.get('light.test')
self.assertEqual(255, state.attributes.get('brightness'))
# bad color temp values
fire_mqtt_message(self.hass, 'test_light_rgb', 'on,,off,255-255-255')
self.hass.block_till_done()
# color temp should not have changed
state = self.hass.states.get('light.test')
self.assertEqual(215, state.attributes.get('color_temp'))
# bad color values
fire_mqtt_message(self.hass, 'test_light_rgb', 'on,255,a-b-c')
self.hass.block_till_done()
@ -383,6 +440,14 @@ class TestLightMQTTTemplate(unittest.TestCase):
state = self.hass.states.get('light.test')
self.assertEqual([255, 255, 255], state.attributes.get('rgb_color'))
# bad white value values
fire_mqtt_message(self.hass, 'test_light_rgb', 'on,,,off,255-255-255')
self.hass.block_till_done()
# white value should not have changed
state = self.hass.states.get('light.test')
self.assertEqual(222, state.attributes.get('white_value'))
# bad effect value
fire_mqtt_message(self.hass, 'test_light_rgb', 'on,255,a-b-c,white')
self.hass.block_till_done()