diff --git a/homeassistant/components/light/mqtt.py b/homeassistant/components/light/mqtt.py index a66cecd3ef8..1e5c0f743bb 100644 --- a/homeassistant/components/light/mqtt.py +++ b/homeassistant/components/light/mqtt.py @@ -51,6 +51,7 @@ 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' +CONF_ON_COMMAND_TYPE = 'on_command_type' DEFAULT_BRIGHTNESS_SCALE = 255 DEFAULT_NAME = 'MQTT Light' @@ -58,6 +59,9 @@ DEFAULT_OPTIMISTIC = False DEFAULT_PAYLOAD_OFF = 'OFF' DEFAULT_PAYLOAD_ON = 'ON' DEFAULT_WHITE_VALUE_SCALE = 255 +DEFAULT_ON_COMMAND_TYPE = 'last' + +VALUES_ON_COMMAND_TYPE = ['first', 'last', 'brightness'] PLATFORM_SCHEMA = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend({ vol.Optional(CONF_BRIGHTNESS_COMMAND_TOPIC): mqtt.valid_publish_topic, @@ -89,6 +93,8 @@ PLATFORM_SCHEMA = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend({ 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, + vol.Optional(CONF_ON_COMMAND_TYPE, default=DEFAULT_ON_COMMAND_TYPE): + vol.In(VALUES_ON_COMMAND_TYPE), }) @@ -141,6 +147,7 @@ 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), + config.get(CONF_ON_COMMAND_TYPE), )]) @@ -149,7 +156,7 @@ class MqttLight(Light): def __init__(self, name, effect_list, topic, templates, qos, retain, payload, optimistic, brightness_scale, - white_value_scale): + white_value_scale, on_command_type): """Initialize MQTT light.""" self._name = name self._effect_list = effect_list @@ -173,6 +180,7 @@ class MqttLight(Light): optimistic or topic[CONF_XY_STATE_TOPIC] is None self._brightness_scale = brightness_scale self._white_value_scale = white_value_scale + self._on_command_type = on_command_type self._state = False self._brightness = None self._rgb = None @@ -397,6 +405,20 @@ class MqttLight(Light): """ should_update = False + if self._on_command_type == 'first': + mqtt.async_publish( + self.hass, self._topic[CONF_COMMAND_TOPIC], + self._payload['on'], self._qos, self._retain) + should_update = True + + # If brightness is being used instead of an on command, make sure + # there is a brightness input. Either set the brightness to our + # saved value or the maximum value if this is the first call + elif self._on_command_type == 'brightness': + if ATTR_BRIGHTNESS not in kwargs: + kwargs[ATTR_BRIGHTNESS] = self._brightness if \ + self._brightness else 255 + if ATTR_RGB_COLOR in kwargs and \ self._topic[CONF_RGB_COMMAND_TOPIC] is not None: @@ -408,6 +430,7 @@ class MqttLight(Light): rgb_color_str = tpl.async_render(variables) else: rgb_color_str = '{},{},{}'.format(*kwargs[ATTR_RGB_COLOR]) + mqtt.async_publish( self.hass, self._topic[CONF_RGB_COMMAND_TOPIC], rgb_color_str, self._qos, self._retain) @@ -434,6 +457,7 @@ class MqttLight(Light): mqtt.async_publish( self.hass, self._topic[CONF_COLOR_TEMP_COMMAND_TOPIC], color_temp, self._qos, self._retain) + if self._optimistic_color_temp: self._color_temp = kwargs[ATTR_COLOR_TEMP] should_update = True @@ -445,6 +469,7 @@ class MqttLight(Light): 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 @@ -473,9 +498,10 @@ class MqttLight(Light): 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) + if self._on_command_type == 'last': + mqtt.async_publish(self.hass, self._topic[CONF_COMMAND_TOPIC], + self._payload['on'], self._qos, self._retain) + should_update = True if self._optimistic: # Optimistically assume that switch has changed state. diff --git a/tests/components/light/test_mqtt.py b/tests/components/light/test_mqtt.py index e111fc3aa49..db7c35107d8 100644 --- a/tests/components/light/test_mqtt.py +++ b/tests/components/light/test_mqtt.py @@ -677,3 +677,120 @@ class TestLightMQTT(unittest.TestCase): state = self.hass.states.get('light.test') self.assertEqual(STATE_ON, state.state) self.assertEqual([1, 1], state.attributes.get('xy_color')) + + def test_on_command_first(self): + """Test on command being sent before brightness.""" + config = {light.DOMAIN: { + 'platform': 'mqtt', + 'name': 'test', + 'command_topic': 'test_light/set', + 'brightness_command_topic': 'test_light/bright', + 'on_command_type': 'first', + }} + + with assert_setup_component(1, light.DOMAIN): + assert setup_component(self.hass, light.DOMAIN, config) + + state = self.hass.states.get('light.test') + self.assertEqual(STATE_OFF, state.state) + + light.turn_on(self.hass, 'light.test', brightness=50) + self.hass.block_till_done() + + # Should get the following MQTT messages. + # test_light/set: 'ON' + # test_light/bright: 50 + self.assertEqual(('test_light/set', 'ON', 0, False), + self.mock_publish.mock_calls[-4][1]) + self.assertEqual(('test_light/bright', 50, 0, False), + self.mock_publish.mock_calls[-2][1]) + + light.turn_off(self.hass, 'light.test') + self.hass.block_till_done() + + self.assertEqual(('test_light/set', 'OFF', 0, False), + self.mock_publish.mock_calls[-2][1]) + + def test_on_command_last(self): + """Test on command being sent after brightness.""" + config = {light.DOMAIN: { + 'platform': 'mqtt', + 'name': 'test', + 'command_topic': 'test_light/set', + 'brightness_command_topic': 'test_light/bright', + }} + + with assert_setup_component(1, light.DOMAIN): + assert setup_component(self.hass, light.DOMAIN, config) + + state = self.hass.states.get('light.test') + self.assertEqual(STATE_OFF, state.state) + + light.turn_on(self.hass, 'light.test', brightness=50) + self.hass.block_till_done() + + # Should get the following MQTT messages. + # test_light/bright: 50 + # test_light/set: 'ON' + self.assertEqual(('test_light/bright', 50, 0, False), + self.mock_publish.mock_calls[-4][1]) + self.assertEqual(('test_light/set', 'ON', 0, False), + self.mock_publish.mock_calls[-2][1]) + + light.turn_off(self.hass, 'light.test') + self.hass.block_till_done() + + self.assertEqual(('test_light/set', 'OFF', 0, False), + self.mock_publish.mock_calls[-2][1]) + + def test_on_command_brightness(self): + """Test on command being sent as only brightness.""" + config = {light.DOMAIN: { + 'platform': 'mqtt', + 'name': 'test', + 'command_topic': 'test_light/set', + 'brightness_command_topic': 'test_light/bright', + 'rgb_command_topic': "test_light/rgb", + 'on_command_type': 'brightness', + }} + + with assert_setup_component(1, light.DOMAIN): + assert setup_component(self.hass, light.DOMAIN, config) + + state = self.hass.states.get('light.test') + self.assertEqual(STATE_OFF, state.state) + + # Turn on w/ no brightness - should set to max + light.turn_on(self.hass, 'light.test') + self.hass.block_till_done() + + # Should get the following MQTT messages. + # test_light/bright: 255 + self.assertEqual(('test_light/bright', 255, 0, False), + self.mock_publish.mock_calls[-2][1]) + + light.turn_off(self.hass, 'light.test') + self.hass.block_till_done() + + self.assertEqual(('test_light/set', 'OFF', 0, False), + self.mock_publish.mock_calls[-2][1]) + + # Turn on w/ brightness + light.turn_on(self.hass, 'light.test', brightness=50) + self.hass.block_till_done() + + self.assertEqual(('test_light/bright', 50, 0, False), + self.mock_publish.mock_calls[-2][1]) + + light.turn_off(self.hass, 'light.test') + self.hass.block_till_done() + + # Turn on w/ just a color to insure brightness gets + # added and sent. + light.turn_on(self.hass, 'light.test', rgb_color=[75, 75, 75]) + self.hass.block_till_done() + + self.assertEqual(('test_light/rgb', '75,75,75', 0, False), + self.mock_publish.mock_calls[-4][1]) + self.assertEqual(('test_light/bright', 50, 0, False), + self.mock_publish.mock_calls[-2][1])