diff --git a/homeassistant/components/light/mqtt.py b/homeassistant/components/light/mqtt.py index 1c01278197d..92030c8617a 100644 --- a/homeassistant/components/light/mqtt.py +++ b/homeassistant/components/light/mqtt.py @@ -211,7 +211,11 @@ class MqttLight(MqttAvailability, MqttDiscoveryUpdate, Light): self._optimistic_rgb = \ optimistic or topic[CONF_RGB_STATE_TOPIC] is None self._optimistic_brightness = ( - optimistic or topic[CONF_BRIGHTNESS_STATE_TOPIC] is None) + optimistic or + (topic[CONF_BRIGHTNESS_COMMAND_TOPIC] is not None and + topic[CONF_BRIGHTNESS_STATE_TOPIC] is None) or + (topic[CONF_BRIGHTNESS_COMMAND_TOPIC] is None and + topic[CONF_RGB_STATE_TOPIC] is None)) self._optimistic_color_temp = ( optimistic or topic[CONF_COLOR_TEMP_STATE_TOPIC] is None) self._optimistic_effect = ( @@ -233,7 +237,8 @@ class MqttLight(MqttAvailability, MqttDiscoveryUpdate, Light): self._white_value = None self._supported_features = 0 self._supported_features |= ( - topic[CONF_RGB_COMMAND_TOPIC] is not None and SUPPORT_COLOR) + topic[CONF_RGB_COMMAND_TOPIC] is not None and + (SUPPORT_COLOR | SUPPORT_BRIGHTNESS)) self._supported_features |= ( topic[CONF_BRIGHTNESS_COMMAND_TOPIC] is not None and SUPPORT_BRIGHTNESS) @@ -325,6 +330,10 @@ class MqttLight(MqttAvailability, MqttDiscoveryUpdate, Light): rgb = [int(val) for val in payload.split(',')] self._hs = color_util.color_RGB_to_hs(*rgb) + if self._topic[CONF_BRIGHTNESS_STATE_TOPIC] is None: + percent_bright = \ + float(color_util.color_RGB_to_hsv(*rgb)[2]) / 100.0 + self._brightness = int(percent_bright * 255) self.async_schedule_update_ha_state() if self._topic[CONF_RGB_STATE_TOPIC] is not None: @@ -616,6 +625,27 @@ class MqttLight(MqttAvailability, MqttDiscoveryUpdate, Light): if self._optimistic_brightness: self._brightness = kwargs[ATTR_BRIGHTNESS] should_update = True + elif ATTR_BRIGHTNESS in kwargs and ATTR_HS_COLOR not in kwargs and\ + self._topic[CONF_RGB_COMMAND_TOPIC] is not None: + rgb = color_util.color_hsv_to_RGB( + self._hs[0], self._hs[1], kwargs[ATTR_BRIGHTNESS] / 255 * 100) + tpl = self._templates[CONF_RGB_COMMAND_TEMPLATE] + if tpl: + rgb_color_str = tpl.async_render({ + 'red': rgb[0], + 'green': rgb[1], + 'blue': rgb[2], + }) + else: + rgb_color_str = '{},{},{}'.format(*rgb) + + mqtt.async_publish( + self.hass, self._topic[CONF_RGB_COMMAND_TOPIC], + rgb_color_str, self._qos, self._retain) + + if self._optimistic_brightness: + self._brightness = kwargs[ATTR_BRIGHTNESS] + should_update = True if ATTR_COLOR_TEMP in kwargs and \ self._topic[CONF_COLOR_TEMP_COMMAND_TOPIC] is not None: diff --git a/tests/components/light/test_mqtt.py b/tests/components/light/test_mqtt.py index 2b23be101c7..5a768820e18 100644 --- a/tests/components/light/test_mqtt.py +++ b/tests/components/light/test_mqtt.py @@ -393,6 +393,41 @@ class TestLightMQTT(unittest.TestCase): self.assertEqual(255, light_state.attributes['brightness']) + def test_brightness_from_rgb_controlling_scale(self): + """Test the brightness controlling scale.""" + with assert_setup_component(1, light.DOMAIN): + assert setup_component(self.hass, light.DOMAIN, { + light.DOMAIN: { + 'platform': 'mqtt', + 'name': 'test', + 'state_topic': 'test_scale_rgb/status', + 'command_topic': 'test_scale_rgb/set', + 'rgb_state_topic': 'test_scale_rgb/rgb/status', + 'rgb_command_topic': 'test_scale_rgb/rgb/set', + '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('brightness')) + self.assertFalse(state.attributes.get(ATTR_ASSUMED_STATE)) + + fire_mqtt_message(self.hass, 'test_scale_rgb/status', 'on') + fire_mqtt_message(self.hass, 'test_scale_rgb/rgb/status', '255,0,0') + self.hass.block_till_done() + + state = self.hass.states.get('light.test') + self.assertEqual(255, state.attributes.get('brightness')) + + fire_mqtt_message(self.hass, 'test_scale_rgb/rgb/status', '127,0,0') + self.hass.block_till_done() + + state = self.hass.states.get('light.test') + self.assertEqual(127, state.attributes.get('brightness')) + def test_white_value_controlling_scale(self): """Test the white_value controlling scale.""" with assert_setup_component(1, light.DOMAIN): @@ -894,6 +929,39 @@ class TestLightMQTT(unittest.TestCase): mock.call('test_light/bright', 50, 0, False) ], any_order=True) + def test_on_command_rgb(self): + """Test on command in RGB brightness mode.""" + config = {light.DOMAIN: { + 'platform': 'mqtt', + 'name': 'test', + 'command_topic': 'test_light/set', + 'rgb_command_topic': "test_light/rgb", + }} + + 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) + + common.turn_on(self.hass, 'light.test', brightness=127) + self.hass.block_till_done() + + # Should get the following MQTT messages. + # test_light/rgb: '127,127,127' + # test_light/set: 'ON' + self.mock_publish.async_publish.assert_has_calls([ + mock.call('test_light/rgb', '127,127,127', 0, False), + mock.call('test_light/set', 'ON', 0, False), + ], any_order=True) + self.mock_publish.async_publish.reset_mock() + + common.turn_off(self.hass, 'light.test') + self.hass.block_till_done() + + self.mock_publish.async_publish.assert_called_once_with( + 'test_light/set', 'OFF', 0, False) + def test_default_availability_payload(self): """Test availability by default payload with defined topic.""" self.assertTrue(setup_component(self.hass, light.DOMAIN, {