From 90c705354aa1d6d13403869795dfda33b5fcfd49 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 19 Dec 2015 19:15:05 -0800 Subject: [PATCH] Add template support to MQTT lights --- homeassistant/components/light/mqtt.py | 41 +++++++++++++++----------- tests/components/light/test_mqtt.py | 35 +++++++++++++++++++++- 2 files changed, 58 insertions(+), 18 deletions(-) diff --git a/homeassistant/components/light/mqtt.py b/homeassistant/components/light/mqtt.py index 30f968d758f..05de40b0b0e 100644 --- a/homeassistant/components/light/mqtt.py +++ b/homeassistant/components/light/mqtt.py @@ -6,23 +6,29 @@ Allows to configure a MQTT light. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/light.mqtt/ """ +from functools import partial import logging import homeassistant.components.mqtt as mqtt from homeassistant.components.light import (Light, ATTR_BRIGHTNESS, ATTR_RGB_COLOR) +from homeassistant.util.template import render_with_possible_json_value _LOGGER = logging.getLogger(__name__) -DEFAULT_NAME = "MQTT Light" +DEFAULT_NAME = 'MQTT Light' DEFAULT_QOS = 0 -DEFAULT_PAYLOAD_ON = "on" -DEFAULT_PAYLOAD_OFF = "off" +DEFAULT_PAYLOAD_ON = 'ON' +DEFAULT_PAYLOAD_OFF = 'OFF' DEFAULT_OPTIMISTIC = False DEPENDENCIES = ['mqtt'] -# pylint: disable=unused-argument +CONF_TOPICS = [typ + topic + for typ in ('', 'brightness_', 'rgb_') + for topic in ('state_topic', 'command_topic')] +CONF_VALUE_TEMPLATES = [typ + '_value_template' + for typ in ('state', 'brightness', 'rgb')] def setup_platform(hass, config, add_devices_callback, discovery_info=None): @@ -35,18 +41,13 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): add_devices_callback([MqttLight( hass, config.get('name', DEFAULT_NAME), - { - "state_topic": config.get('state_topic'), - "command_topic": config.get('command_topic'), - "brightness_state_topic": config.get('brightness_state_topic'), - "brightness_command_topic": config.get('brightness_command_topic'), - "rgb_state_topic": config.get('rgb_state_topic'), - "rgb_command_topic": config.get('rgb_command_topic') - }, + {key: config.get(key) for key in CONF_TOPICS}, + {key: config.get(key + '_value_template') + for key in ('state', 'brightness', 'rgb')}, config.get('qos', DEFAULT_QOS), { - "on": config.get('payload_on', DEFAULT_PAYLOAD_ON), - "off": config.get('payload_off', DEFAULT_PAYLOAD_OFF) + 'on': config.get('payload_on', DEFAULT_PAYLOAD_ON), + 'off': config.get('payload_off', DEFAULT_PAYLOAD_OFF) }, config.get('optimistic', DEFAULT_OPTIMISTIC))]) @@ -55,7 +56,7 @@ class MqttLight(Light): """ Provides a MQTT light. """ # pylint: disable=too-many-arguments,too-many-instance-attributes - def __init__(self, hass, name, topic, qos, payload, optimistic): + def __init__(self, hass, name, topic, templates, qos, payload, optimistic): self._hass = hass self._name = name @@ -68,8 +69,13 @@ class MqttLight(Light): topic["brightness_state_topic"] is None) self._state = False + templates = {key: ((lambda value: value) if tpl is None else + partial(render_with_possible_json_value, hass, tpl)) + for key, tpl in templates.items()} + def state_received(topic, payload, qos): """ A new MQTT message has been received. """ + payload = templates['state'](payload) if payload == self._payload["on"]: self._state = True elif payload == self._payload["off"]: @@ -83,7 +89,7 @@ class MqttLight(Light): def brightness_received(topic, payload, qos): """ A new MQTT message for the brightness has been received. """ - self._brightness = int(payload) + self._brightness = int(templates['brightness'](payload)) self.update_ha_state() if self._topic["brightness_state_topic"] is not None: @@ -95,7 +101,8 @@ class MqttLight(Light): def rgb_received(topic, payload, qos): """ A new MQTT message has been received. """ - self._rgb = [int(val) for val in payload.split(',')] + self._rgb = [int(val) for val in + templates['rgb'](payload).split(',')] self.update_ha_state() if self._topic["rgb_state_topic"] is not None: diff --git a/tests/components/light/test_mqtt.py b/tests/components/light/test_mqtt.py index 8172a6c7c63..321d904fc87 100644 --- a/tests/components/light/test_mqtt.py +++ b/tests/components/light/test_mqtt.py @@ -77,7 +77,7 @@ class TestLightMQTT(unittest.TestCase): self.assertIsNone(state.attributes.get('rgb_color')) self.assertIsNone(state.attributes.get('brightness')) - fire_mqtt_message(self.hass, 'test_light_rgb/status', 'on') + fire_mqtt_message(self.hass, 'test_light_rgb/status', 'ON') self.hass.pool.block_till_done() state = self.hass.states.get('light.test') @@ -143,6 +143,39 @@ class TestLightMQTT(unittest.TestCase): self.assertEqual([125, 125, 125], light_state.attributes.get('rgb_color')) + def test_controlling_state_via_topic_with_templates(self): + self.assertTrue(light.setup(self.hass, { + 'light': { + 'platform': 'mqtt', + 'name': 'test', + 'state_topic': 'test_light_rgb/status', + 'command_topic': 'test_light_rgb/set', + 'brightness_state_topic': 'test_light_rgb/brightness/status', + 'rgb_state_topic': 'test_light_rgb/rgb/status', + 'state_value_template': '{{ value_json.hello }}', + '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) + self.assertIsNone(state.attributes.get('brightness')) + self.assertIsNone(state.attributes.get('rgb_color')) + + fire_mqtt_message(self.hass, 'test_light_rgb/status', + '{"hello": "ON"}') + fire_mqtt_message(self.hass, 'test_light_rgb/brightness/status', + '{"hello": "50"}') + fire_mqtt_message(self.hass, 'test_light_rgb/rgb/status', + '{"hello": [1, 2, 3]}') + self.hass.pool.block_till_done() + + state = self.hass.states.get('light.test') + self.assertEqual(STATE_ON, state.state) + self.assertEqual(50, state.attributes.get('brightness')) + self.assertEqual([1, 2, 3], state.attributes.get('rgb_color')) + def test_sending_mqtt_commands_and_optimistic(self): self.assertTrue(light.setup(self.hass, { 'light': {