diff --git a/.gitattributes b/.gitattributes index 1e4e6c6a091ccb..caff2fc5c1f7a3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -7,3 +7,4 @@ *.jpg binary *.png binary *.zip binary +*.mp3 binary diff --git a/homeassistant/components/alarm_control_panel/services.yaml b/homeassistant/components/alarm_control_panel/services.yaml index bfd38c902d0a1b..72784c8178c15a 100644 --- a/homeassistant/components/alarm_control_panel/services.yaml +++ b/homeassistant/components/alarm_control_panel/services.yaml @@ -1,71 +1,71 @@ -# Describes the format for available alarm control panel services - -alarm_disarm: - description: Send the alarm the command for disarm. - fields: - entity_id: - description: Name of alarm control panel to disarm. - example: 'alarm_control_panel.downstairs' - code: - description: An optional code to disarm the alarm control panel with. - example: 1234 - -alarm_arm_home: - description: Send the alarm the command for arm home. - fields: - entity_id: - description: Name of alarm control panel to arm home. - example: 'alarm_control_panel.downstairs' - code: - description: An optional code to arm home the alarm control panel with. - example: 1234 - -alarm_arm_away: - description: Send the alarm the command for arm away. - fields: - entity_id: - description: Name of alarm control panel to arm away. - example: 'alarm_control_panel.downstairs' - code: - description: An optional code to arm away the alarm control panel with. - example: 1234 - -alarm_arm_night: - description: Send the alarm the command for arm night. - fields: - entity_id: - description: Name of alarm control panel to arm night. - example: 'alarm_control_panel.downstairs' - code: - description: An optional code to arm night the alarm control panel with. - example: 1234 - -alarm_trigger: - description: Send the alarm the command for trigger. - fields: - entity_id: - description: Name of alarm control panel to trigger. - example: 'alarm_control_panel.downstairs' - code: - description: An optional code to trigger the alarm control panel with. - example: 1234 - -envisalink_alarm_keypress: - description: Send custom keypresses to the alarm. - fields: - entity_id: - description: Name of the alarm control panel to trigger. - example: 'alarm_control_panel.downstairs' - keypress: - description: 'String to send to the alarm panel (1-6 characters).' - example: '*71' - -alarmdecoder_alarm_toggle_chime: - description: Send the alarm the toggle chime command. - fields: - entity_id: - description: Name of the alarm control panel to trigger. - example: 'alarm_control_panel.downstairs' - code: - description: A required code to toggle the alarm control panel chime with. - example: 1234 +# Describes the format for available alarm control panel services + +alarm_disarm: + description: Send the alarm the command for disarm. + fields: + entity_id: + description: Name of alarm control panel to disarm. + example: 'alarm_control_panel.downstairs' + code: + description: An optional code to disarm the alarm control panel with. + example: 1234 + +alarm_arm_home: + description: Send the alarm the command for arm home. + fields: + entity_id: + description: Name of alarm control panel to arm home. + example: 'alarm_control_panel.downstairs' + code: + description: An optional code to arm home the alarm control panel with. + example: 1234 + +alarm_arm_away: + description: Send the alarm the command for arm away. + fields: + entity_id: + description: Name of alarm control panel to arm away. + example: 'alarm_control_panel.downstairs' + code: + description: An optional code to arm away the alarm control panel with. + example: 1234 + +alarm_arm_night: + description: Send the alarm the command for arm night. + fields: + entity_id: + description: Name of alarm control panel to arm night. + example: 'alarm_control_panel.downstairs' + code: + description: An optional code to arm night the alarm control panel with. + example: 1234 + +alarm_trigger: + description: Send the alarm the command for trigger. + fields: + entity_id: + description: Name of alarm control panel to trigger. + example: 'alarm_control_panel.downstairs' + code: + description: An optional code to trigger the alarm control panel with. + example: 1234 + +envisalink_alarm_keypress: + description: Send custom keypresses to the alarm. + fields: + entity_id: + description: Name of the alarm control panel to trigger. + example: 'alarm_control_panel.downstairs' + keypress: + description: 'String to send to the alarm panel (1-6 characters).' + example: '*71' + +alarmdecoder_alarm_toggle_chime: + description: Send the alarm the toggle chime command. + fields: + entity_id: + description: Name of the alarm control panel to trigger. + example: 'alarm_control_panel.downstairs' + code: + description: A required code to toggle the alarm control panel chime with. + example: 1234 diff --git a/homeassistant/components/cover/services.yaml b/homeassistant/components/cover/services.yaml index 1a3e020ed87a13..79f00180a8946d 100644 --- a/homeassistant/components/cover/services.yaml +++ b/homeassistant/components/cover/services.yaml @@ -1,63 +1,63 @@ -# Describes the format for available cover services - -open_cover: - description: Open all or specified cover. - fields: - entity_id: - description: Name(s) of cover(s) to open. - example: 'cover.living_room' - -close_cover: - description: Close all or specified cover. - fields: - entity_id: - description: Name(s) of cover(s) to close. - example: 'cover.living_room' - -set_cover_position: - description: Move to specific position all or specified cover. - fields: - entity_id: - description: Name(s) of cover(s) to set cover position. - example: 'cover.living_room' - position: - description: Position of the cover (0 to 100). - example: 30 - -stop_cover: - description: Stop all or specified cover. - fields: - entity_id: - description: Name(s) of cover(s) to stop. - example: 'cover.living_room' - -open_cover_tilt: - description: Open all or specified cover tilt. - fields: - entity_id: - description: Name(s) of cover(s) tilt to open. - example: 'cover.living_room' - -close_cover_tilt: - description: Close all or specified cover tilt. - fields: - entity_id: - description: Name(s) of cover(s) to close tilt. - example: 'cover.living_room' - -set_cover_tilt_position: - description: Move to specific position all or specified cover tilt. - fields: - entity_id: - description: Name(s) of cover(s) to set cover tilt position. - example: 'cover.living_room' - tilt_position: - description: Tilt position of the cover (0 to 100). - example: 30 - -stop_cover_tilt: - description: Stop all or specified cover. - fields: - entity_id: - description: Name(s) of cover(s) to stop. - example: 'cover.living_room' +# Describes the format for available cover services + +open_cover: + description: Open all or specified cover. + fields: + entity_id: + description: Name(s) of cover(s) to open. + example: 'cover.living_room' + +close_cover: + description: Close all or specified cover. + fields: + entity_id: + description: Name(s) of cover(s) to close. + example: 'cover.living_room' + +set_cover_position: + description: Move to specific position all or specified cover. + fields: + entity_id: + description: Name(s) of cover(s) to set cover position. + example: 'cover.living_room' + position: + description: Position of the cover (0 to 100). + example: 30 + +stop_cover: + description: Stop all or specified cover. + fields: + entity_id: + description: Name(s) of cover(s) to stop. + example: 'cover.living_room' + +open_cover_tilt: + description: Open all or specified cover tilt. + fields: + entity_id: + description: Name(s) of cover(s) tilt to open. + example: 'cover.living_room' + +close_cover_tilt: + description: Close all or specified cover tilt. + fields: + entity_id: + description: Name(s) of cover(s) to close tilt. + example: 'cover.living_room' + +set_cover_tilt_position: + description: Move to specific position all or specified cover tilt. + fields: + entity_id: + description: Name(s) of cover(s) to set cover tilt position. + example: 'cover.living_room' + tilt_position: + description: Tilt position of the cover (0 to 100). + example: 30 + +stop_cover_tilt: + description: Stop all or specified cover. + fields: + entity_id: + description: Name(s) of cover(s) to stop. + example: 'cover.living_room' diff --git a/tests/components/light/test_mqtt_json.py b/tests/components/light/test_mqtt_json.py index d7eb80980ca365..ba306a81a34eda 100644 --- a/tests/components/light/test_mqtt_json.py +++ b/tests/components/light/test_mqtt_json.py @@ -1,597 +1,597 @@ -"""The tests for the MQTT JSON light platform. - -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 - name: mqtt_json_light_1 - state_topic: "home/rgb1" - command_topic: "home/rgb1/set" - brightness: true - rgb: true - -Config without RGB: - -light: - platform: mqtt_json - name: mqtt_json_light_1 - state_topic: "home/rgb1" - command_topic: "home/rgb1/set" - brightness: true - -Config without RGB and brightness: - -light: - platform: mqtt_json - name: mqtt_json_light_1 - state_topic: "home/rgb1" - command_topic: "home/rgb1/set" - -Config with brightness and scale: - -light: - platform: mqtt_json - name: test - state_topic: "mqtt_json_light_1" - command_topic: "mqtt_json_light_1/set" - brightness: true - brightness_scale: 99 -""" - -import json -import unittest - -from homeassistant.setup import setup_component -from homeassistant.const import ( - STATE_ON, STATE_OFF, STATE_UNAVAILABLE, ATTR_ASSUMED_STATE, - ATTR_SUPPORTED_FEATURES) -import homeassistant.components.light as light -from tests.common import ( - get_test_home_assistant, mock_mqtt_component, fire_mqtt_message, - assert_setup_component) - - -class TestLightMQTTJSON(unittest.TestCase): - """Test the MQTT JSON light.""" - - def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" - self.hass = get_test_home_assistant() - self.mock_publish = mock_mqtt_component(self.hass) - - def tearDown(self): # pylint: disable=invalid-name - """Stop everything that was started.""" - self.hass.stop() - - def test_fail_setup_if_no_command_topic(self): \ - # pylint: disable=invalid-name - """Test if setup fails with no command topic.""" - with assert_setup_component(0, light.DOMAIN): - assert setup_component(self.hass, light.DOMAIN, { - light.DOMAIN: { - 'platform': 'mqtt_json', - 'name': 'test', - } - }) - self.assertIsNone(self.hass.states.get('light.test')) - - def test_no_color_brightness_color_temp_white_val_if_no_topics(self): \ - # pylint: disable=invalid-name - """Test for no RGB, brightness, color temp, effect, white val or XY.""" - assert setup_component(self.hass, light.DOMAIN, { - light.DOMAIN: { - 'platform': 'mqtt_json', - 'name': 'test', - 'state_topic': 'test_light_rgb', - 'command_topic': 'test_light_rgb/set', - } - }) - - state = self.hass.states.get('light.test') - self.assertEqual(STATE_OFF, state.state) - self.assertEqual(40, state.attributes.get(ATTR_SUPPORTED_FEATURES)) - 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() - - state = self.hass.states.get('light.test') - 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 - """Test the controlling of the state via topic.""" - assert setup_component(self.hass, light.DOMAIN, { - light.DOMAIN: { - 'platform': 'mqtt_json', - 'name': 'test', - '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' - } - }) - - state = self.hass.states.get('light.test') - self.assertEqual(STATE_OFF, state.state) - self.assertEqual(255, state.attributes.get(ATTR_SUPPORTED_FEATURES)) - 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.assertFalse(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,' - '"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"}') - self.hass.block_till_done() - - state = self.hass.states.get('light.test') - self.assertEqual(STATE_OFF, state.state) - - fire_mqtt_message(self.hass, 'test_light_rgb', - '{"state":"ON",' - '"brightness":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['brightness']) - - fire_mqtt_message(self.hass, 'test_light_rgb', - '{"state":"ON",' - '"color":{"r":125,"g":125,"b":125}}') - self.hass.block_till_done() - - light_state = self.hass.states.get('light.test') - 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.""" - assert setup_component(self.hass, light.DOMAIN, { - light.DOMAIN: { - 'platform': 'mqtt_json', - 'name': 'test', - 'command_topic': 'test_light_rgb/set', - 'brightness': True, - 'color_temp': True, - 'effect': True, - 'rgb': True, - 'white_value': True, - 'qos': 2 - } - }) - - state = self.hass.states.get('light.test') - self.assertEqual(STATE_OFF, state.state) - self.assertEqual(191, state.attributes.get(ATTR_SUPPORTED_FEATURES)) - self.assertTrue(state.attributes.get(ATTR_ASSUMED_STATE)) - - light.turn_on(self.hass, 'light.test') - self.hass.block_till_done() - - self.mock_publish.async_publish.assert_called_once_with( - 'test_light_rgb/set', '{"state": "ON"}', 2, False) - self.mock_publish.async_publish.reset_mock() - state = self.hass.states.get('light.test') - self.assertEqual(STATE_ON, state.state) - - light.turn_off(self.hass, 'light.test') - self.hass.block_till_done() - - self.mock_publish.async_publish.assert_called_once_with( - 'test_light_rgb/set', '{"state": "OFF"}', 2, False) - self.mock_publish.async_publish.reset_mock() - state = self.hass.states.get('light.test') - self.assertEqual(STATE_OFF, state.state) - - light.turn_on(self.hass, 'light.test', - brightness=50, color_temp=155, effect='colorloop', - white_value=170) - self.hass.block_till_done() - - self.assertEqual('test_light_rgb/set', - self.mock_publish.async_publish.mock_calls[0][1][0]) - self.assertEqual(2, - self.mock_publish.async_publish.mock_calls[0][1][2]) - self.assertEqual(False, - self.mock_publish.async_publish.mock_calls[0][1][3]) - # Get the sent message - message_json = json.loads( - self.mock_publish.async_publish.mock_calls[0][1][1]) - self.assertEqual(50, message_json["brightness"]) - self.assertEqual(155, message_json["color_temp"]) - self.assertEqual('colorloop', message_json["effect"]) - 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(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 - """Test for flash length being sent when included.""" - assert setup_component(self.hass, light.DOMAIN, { - light.DOMAIN: { - 'platform': 'mqtt_json', - 'name': 'test', - 'state_topic': 'test_light_rgb', - 'command_topic': 'test_light_rgb/set', - 'flash_time_short': 5, - 'flash_time_long': 15, - 'qos': 0 - } - }) - - state = self.hass.states.get('light.test') - self.assertEqual(STATE_OFF, state.state) - self.assertEqual(40, state.attributes.get(ATTR_SUPPORTED_FEATURES)) - - light.turn_on(self.hass, 'light.test', flash="short") - self.hass.block_till_done() - - self.assertEqual('test_light_rgb/set', - self.mock_publish.async_publish.mock_calls[0][1][0]) - self.assertEqual(0, - self.mock_publish.async_publish.mock_calls[0][1][2]) - self.assertEqual(False, - self.mock_publish.async_publish.mock_calls[0][1][3]) - # Get the sent message - message_json = json.loads( - self.mock_publish.async_publish.mock_calls[0][1][1]) - self.assertEqual(5, message_json["flash"]) - self.assertEqual("ON", message_json["state"]) - - self.mock_publish.async_publish.reset_mock() - light.turn_on(self.hass, 'light.test', flash="long") - self.hass.block_till_done() - - self.assertEqual('test_light_rgb/set', - self.mock_publish.async_publish.mock_calls[0][1][0]) - self.assertEqual(0, - self.mock_publish.async_publish.mock_calls[0][1][2]) - self.assertEqual(False, - self.mock_publish.async_publish.mock_calls[0][1][3]) - # Get the sent message - message_json = json.loads( - self.mock_publish.async_publish.mock_calls[0][1][1]) - self.assertEqual(15, message_json["flash"]) - self.assertEqual("ON", message_json["state"]) - - def test_transition(self): - """Test for transition time being sent when included.""" - assert setup_component(self.hass, light.DOMAIN, { - light.DOMAIN: { - 'platform': 'mqtt_json', - 'name': 'test', - 'state_topic': 'test_light_rgb', - 'command_topic': 'test_light_rgb/set', - 'qos': 0 - } - }) - - state = self.hass.states.get('light.test') - self.assertEqual(STATE_OFF, state.state) - self.assertEqual(40, state.attributes.get(ATTR_SUPPORTED_FEATURES)) - - light.turn_on(self.hass, 'light.test', transition=10) - self.hass.block_till_done() - - self.assertEqual('test_light_rgb/set', - self.mock_publish.async_publish.mock_calls[0][1][0]) - self.assertEqual(0, - self.mock_publish.async_publish.mock_calls[0][1][2]) - self.assertEqual(False, - self.mock_publish.async_publish.mock_calls[0][1][3]) - # Get the sent message - message_json = json.loads( - self.mock_publish.async_publish.mock_calls[0][1][1]) - self.assertEqual(10, message_json["transition"]) - self.assertEqual("ON", message_json["state"]) - - # Transition back off - light.turn_off(self.hass, 'light.test', transition=10) - self.hass.block_till_done() - - self.assertEqual('test_light_rgb/set', - self.mock_publish.async_publish.mock_calls[1][1][0]) - self.assertEqual(0, - self.mock_publish.async_publish.mock_calls[1][1][2]) - self.assertEqual(False, - self.mock_publish.async_publish.mock_calls[1][1][3]) - # Get the sent message - message_json = json.loads( - self.mock_publish.async_publish.mock_calls[1][1][1]) - self.assertEqual(10, message_json["transition"]) - self.assertEqual("OFF", message_json["state"]) - - def test_brightness_scale(self): - """Test for brightness scaling.""" - assert setup_component(self.hass, light.DOMAIN, { - light.DOMAIN: { - 'platform': 'mqtt_json', - 'name': 'test', - 'state_topic': 'test_light_bright_scale', - 'command_topic': 'test_light_bright_scale/set', - 'brightness': True, - 'brightness_scale': 99 - } - }) - - 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)) - - # Turn on the light - fire_mqtt_message(self.hass, 'test_light_bright_scale', - '{"state":"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('brightness')) - - # Turn on the light with brightness - fire_mqtt_message(self.hass, 'test_light_bright_scale', - '{"state":"ON",' - '"brightness": 99}') - 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')) - - def test_invalid_color_brightness_and_white_values(self): \ - # pylint: disable=invalid-name - """Test that invalid color/brightness/white values are ignored.""" - assert setup_component(self.hass, light.DOMAIN, { - light.DOMAIN: { - 'platform': 'mqtt_json', - 'name': 'test', - 'state_topic': 'test_light_rgb', - 'command_topic': 'test_light_rgb/set', - 'brightness': True, - 'rgb': True, - 'white_value': True, - 'qos': '0' - } - }) - - state = self.hass.states.get('light.test') - self.assertEqual(STATE_OFF, state.state) - self.assertEqual(185, state.attributes.get(ATTR_SUPPORTED_FEATURES)) - self.assertIsNone(state.attributes.get('rgb_color')) - self.assertIsNone(state.attributes.get('brightness')) - self.assertIsNone(state.attributes.get('white_value')) - self.assertFalse(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,' - '"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', - '{"state":"ON",' - '"color":{"r":"bad","g":"val","b":"test"}}') - self.hass.block_till_done() - - # Color should not have changed - state = self.hass.states.get('light.test') - self.assertEqual(STATE_ON, state.state) - self.assertEqual([255, 255, 255], state.attributes.get('rgb_color')) - - # Bad brightness values - fire_mqtt_message(self.hass, 'test_light_rgb', - '{"state":"ON",' - '"brightness": "badValue"}') - self.hass.block_till_done() - - # Brightness should not have changed - 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')) - - def test_default_availability_payload(self): - """Test availability by default payload with defined topic.""" - self.assertTrue(setup_component(self.hass, light.DOMAIN, { - light.DOMAIN: { - 'platform': 'mqtt_json', - 'name': 'test', - 'state_topic': 'test_light_rgb', - 'command_topic': 'test_light_rgb/set', - 'availability_topic': 'availability-topic' - } - })) - - state = self.hass.states.get('light.test') - self.assertEqual(STATE_UNAVAILABLE, state.state) - - fire_mqtt_message(self.hass, 'availability-topic', 'online') - self.hass.block_till_done() - - state = self.hass.states.get('light.test') - self.assertNotEqual(STATE_UNAVAILABLE, state.state) - - fire_mqtt_message(self.hass, 'availability-topic', 'offline') - self.hass.block_till_done() - - state = self.hass.states.get('light.test') - self.assertEqual(STATE_UNAVAILABLE, state.state) - - def test_custom_availability_payload(self): - """Test availability by custom payload with defined topic.""" - self.assertTrue(setup_component(self.hass, light.DOMAIN, { - light.DOMAIN: { - 'platform': 'mqtt_json', - 'name': 'test', - 'state_topic': 'test_light_rgb', - 'command_topic': 'test_light_rgb/set', - 'availability_topic': 'availability-topic', - 'payload_available': 'good', - 'payload_not_available': 'nogood' - } - })) - - state = self.hass.states.get('light.test') - self.assertEqual(STATE_UNAVAILABLE, state.state) - - fire_mqtt_message(self.hass, 'availability-topic', 'good') - self.hass.block_till_done() - - state = self.hass.states.get('light.test') - self.assertNotEqual(STATE_UNAVAILABLE, state.state) - - fire_mqtt_message(self.hass, 'availability-topic', 'nogood') - self.hass.block_till_done() - - state = self.hass.states.get('light.test') - self.assertEqual(STATE_UNAVAILABLE, state.state) +"""The tests for the MQTT JSON light platform. + +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 + name: mqtt_json_light_1 + state_topic: "home/rgb1" + command_topic: "home/rgb1/set" + brightness: true + rgb: true + +Config without RGB: + +light: + platform: mqtt_json + name: mqtt_json_light_1 + state_topic: "home/rgb1" + command_topic: "home/rgb1/set" + brightness: true + +Config without RGB and brightness: + +light: + platform: mqtt_json + name: mqtt_json_light_1 + state_topic: "home/rgb1" + command_topic: "home/rgb1/set" + +Config with brightness and scale: + +light: + platform: mqtt_json + name: test + state_topic: "mqtt_json_light_1" + command_topic: "mqtt_json_light_1/set" + brightness: true + brightness_scale: 99 +""" + +import json +import unittest + +from homeassistant.setup import setup_component +from homeassistant.const import ( + STATE_ON, STATE_OFF, STATE_UNAVAILABLE, ATTR_ASSUMED_STATE, + ATTR_SUPPORTED_FEATURES) +import homeassistant.components.light as light +from tests.common import ( + get_test_home_assistant, mock_mqtt_component, fire_mqtt_message, + assert_setup_component) + + +class TestLightMQTTJSON(unittest.TestCase): + """Test the MQTT JSON light.""" + + def setUp(self): # pylint: disable=invalid-name + """Setup things to be run when tests are started.""" + self.hass = get_test_home_assistant() + self.mock_publish = mock_mqtt_component(self.hass) + + def tearDown(self): # pylint: disable=invalid-name + """Stop everything that was started.""" + self.hass.stop() + + def test_fail_setup_if_no_command_topic(self): \ + # pylint: disable=invalid-name + """Test if setup fails with no command topic.""" + with assert_setup_component(0, light.DOMAIN): + assert setup_component(self.hass, light.DOMAIN, { + light.DOMAIN: { + 'platform': 'mqtt_json', + 'name': 'test', + } + }) + self.assertIsNone(self.hass.states.get('light.test')) + + def test_no_color_brightness_color_temp_white_val_if_no_topics(self): \ + # pylint: disable=invalid-name + """Test for no RGB, brightness, color temp, effect, white val or XY.""" + assert setup_component(self.hass, light.DOMAIN, { + light.DOMAIN: { + 'platform': 'mqtt_json', + 'name': 'test', + 'state_topic': 'test_light_rgb', + 'command_topic': 'test_light_rgb/set', + } + }) + + state = self.hass.states.get('light.test') + self.assertEqual(STATE_OFF, state.state) + self.assertEqual(40, state.attributes.get(ATTR_SUPPORTED_FEATURES)) + 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() + + state = self.hass.states.get('light.test') + 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 + """Test the controlling of the state via topic.""" + assert setup_component(self.hass, light.DOMAIN, { + light.DOMAIN: { + 'platform': 'mqtt_json', + 'name': 'test', + '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' + } + }) + + state = self.hass.states.get('light.test') + self.assertEqual(STATE_OFF, state.state) + self.assertEqual(255, state.attributes.get(ATTR_SUPPORTED_FEATURES)) + 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.assertFalse(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,' + '"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"}') + self.hass.block_till_done() + + state = self.hass.states.get('light.test') + self.assertEqual(STATE_OFF, state.state) + + fire_mqtt_message(self.hass, 'test_light_rgb', + '{"state":"ON",' + '"brightness":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['brightness']) + + fire_mqtt_message(self.hass, 'test_light_rgb', + '{"state":"ON",' + '"color":{"r":125,"g":125,"b":125}}') + self.hass.block_till_done() + + light_state = self.hass.states.get('light.test') + 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.""" + assert setup_component(self.hass, light.DOMAIN, { + light.DOMAIN: { + 'platform': 'mqtt_json', + 'name': 'test', + 'command_topic': 'test_light_rgb/set', + 'brightness': True, + 'color_temp': True, + 'effect': True, + 'rgb': True, + 'white_value': True, + 'qos': 2 + } + }) + + state = self.hass.states.get('light.test') + self.assertEqual(STATE_OFF, state.state) + self.assertEqual(191, state.attributes.get(ATTR_SUPPORTED_FEATURES)) + self.assertTrue(state.attributes.get(ATTR_ASSUMED_STATE)) + + light.turn_on(self.hass, 'light.test') + self.hass.block_till_done() + + self.mock_publish.async_publish.assert_called_once_with( + 'test_light_rgb/set', '{"state": "ON"}', 2, False) + self.mock_publish.async_publish.reset_mock() + state = self.hass.states.get('light.test') + self.assertEqual(STATE_ON, state.state) + + light.turn_off(self.hass, 'light.test') + self.hass.block_till_done() + + self.mock_publish.async_publish.assert_called_once_with( + 'test_light_rgb/set', '{"state": "OFF"}', 2, False) + self.mock_publish.async_publish.reset_mock() + state = self.hass.states.get('light.test') + self.assertEqual(STATE_OFF, state.state) + + light.turn_on(self.hass, 'light.test', + brightness=50, color_temp=155, effect='colorloop', + white_value=170) + self.hass.block_till_done() + + self.assertEqual('test_light_rgb/set', + self.mock_publish.async_publish.mock_calls[0][1][0]) + self.assertEqual(2, + self.mock_publish.async_publish.mock_calls[0][1][2]) + self.assertEqual(False, + self.mock_publish.async_publish.mock_calls[0][1][3]) + # Get the sent message + message_json = json.loads( + self.mock_publish.async_publish.mock_calls[0][1][1]) + self.assertEqual(50, message_json["brightness"]) + self.assertEqual(155, message_json["color_temp"]) + self.assertEqual('colorloop', message_json["effect"]) + 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(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 + """Test for flash length being sent when included.""" + assert setup_component(self.hass, light.DOMAIN, { + light.DOMAIN: { + 'platform': 'mqtt_json', + 'name': 'test', + 'state_topic': 'test_light_rgb', + 'command_topic': 'test_light_rgb/set', + 'flash_time_short': 5, + 'flash_time_long': 15, + 'qos': 0 + } + }) + + state = self.hass.states.get('light.test') + self.assertEqual(STATE_OFF, state.state) + self.assertEqual(40, state.attributes.get(ATTR_SUPPORTED_FEATURES)) + + light.turn_on(self.hass, 'light.test', flash="short") + self.hass.block_till_done() + + self.assertEqual('test_light_rgb/set', + self.mock_publish.async_publish.mock_calls[0][1][0]) + self.assertEqual(0, + self.mock_publish.async_publish.mock_calls[0][1][2]) + self.assertEqual(False, + self.mock_publish.async_publish.mock_calls[0][1][3]) + # Get the sent message + message_json = json.loads( + self.mock_publish.async_publish.mock_calls[0][1][1]) + self.assertEqual(5, message_json["flash"]) + self.assertEqual("ON", message_json["state"]) + + self.mock_publish.async_publish.reset_mock() + light.turn_on(self.hass, 'light.test', flash="long") + self.hass.block_till_done() + + self.assertEqual('test_light_rgb/set', + self.mock_publish.async_publish.mock_calls[0][1][0]) + self.assertEqual(0, + self.mock_publish.async_publish.mock_calls[0][1][2]) + self.assertEqual(False, + self.mock_publish.async_publish.mock_calls[0][1][3]) + # Get the sent message + message_json = json.loads( + self.mock_publish.async_publish.mock_calls[0][1][1]) + self.assertEqual(15, message_json["flash"]) + self.assertEqual("ON", message_json["state"]) + + def test_transition(self): + """Test for transition time being sent when included.""" + assert setup_component(self.hass, light.DOMAIN, { + light.DOMAIN: { + 'platform': 'mqtt_json', + 'name': 'test', + 'state_topic': 'test_light_rgb', + 'command_topic': 'test_light_rgb/set', + 'qos': 0 + } + }) + + state = self.hass.states.get('light.test') + self.assertEqual(STATE_OFF, state.state) + self.assertEqual(40, state.attributes.get(ATTR_SUPPORTED_FEATURES)) + + light.turn_on(self.hass, 'light.test', transition=10) + self.hass.block_till_done() + + self.assertEqual('test_light_rgb/set', + self.mock_publish.async_publish.mock_calls[0][1][0]) + self.assertEqual(0, + self.mock_publish.async_publish.mock_calls[0][1][2]) + self.assertEqual(False, + self.mock_publish.async_publish.mock_calls[0][1][3]) + # Get the sent message + message_json = json.loads( + self.mock_publish.async_publish.mock_calls[0][1][1]) + self.assertEqual(10, message_json["transition"]) + self.assertEqual("ON", message_json["state"]) + + # Transition back off + light.turn_off(self.hass, 'light.test', transition=10) + self.hass.block_till_done() + + self.assertEqual('test_light_rgb/set', + self.mock_publish.async_publish.mock_calls[1][1][0]) + self.assertEqual(0, + self.mock_publish.async_publish.mock_calls[1][1][2]) + self.assertEqual(False, + self.mock_publish.async_publish.mock_calls[1][1][3]) + # Get the sent message + message_json = json.loads( + self.mock_publish.async_publish.mock_calls[1][1][1]) + self.assertEqual(10, message_json["transition"]) + self.assertEqual("OFF", message_json["state"]) + + def test_brightness_scale(self): + """Test for brightness scaling.""" + assert setup_component(self.hass, light.DOMAIN, { + light.DOMAIN: { + 'platform': 'mqtt_json', + 'name': 'test', + 'state_topic': 'test_light_bright_scale', + 'command_topic': 'test_light_bright_scale/set', + 'brightness': True, + 'brightness_scale': 99 + } + }) + + 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)) + + # Turn on the light + fire_mqtt_message(self.hass, 'test_light_bright_scale', + '{"state":"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('brightness')) + + # Turn on the light with brightness + fire_mqtt_message(self.hass, 'test_light_bright_scale', + '{"state":"ON",' + '"brightness": 99}') + 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')) + + def test_invalid_color_brightness_and_white_values(self): \ + # pylint: disable=invalid-name + """Test that invalid color/brightness/white values are ignored.""" + assert setup_component(self.hass, light.DOMAIN, { + light.DOMAIN: { + 'platform': 'mqtt_json', + 'name': 'test', + 'state_topic': 'test_light_rgb', + 'command_topic': 'test_light_rgb/set', + 'brightness': True, + 'rgb': True, + 'white_value': True, + 'qos': '0' + } + }) + + state = self.hass.states.get('light.test') + self.assertEqual(STATE_OFF, state.state) + self.assertEqual(185, state.attributes.get(ATTR_SUPPORTED_FEATURES)) + self.assertIsNone(state.attributes.get('rgb_color')) + self.assertIsNone(state.attributes.get('brightness')) + self.assertIsNone(state.attributes.get('white_value')) + self.assertFalse(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,' + '"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', + '{"state":"ON",' + '"color":{"r":"bad","g":"val","b":"test"}}') + self.hass.block_till_done() + + # Color should not have changed + state = self.hass.states.get('light.test') + self.assertEqual(STATE_ON, state.state) + self.assertEqual([255, 255, 255], state.attributes.get('rgb_color')) + + # Bad brightness values + fire_mqtt_message(self.hass, 'test_light_rgb', + '{"state":"ON",' + '"brightness": "badValue"}') + self.hass.block_till_done() + + # Brightness should not have changed + 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')) + + def test_default_availability_payload(self): + """Test availability by default payload with defined topic.""" + self.assertTrue(setup_component(self.hass, light.DOMAIN, { + light.DOMAIN: { + 'platform': 'mqtt_json', + 'name': 'test', + 'state_topic': 'test_light_rgb', + 'command_topic': 'test_light_rgb/set', + 'availability_topic': 'availability-topic' + } + })) + + state = self.hass.states.get('light.test') + self.assertEqual(STATE_UNAVAILABLE, state.state) + + fire_mqtt_message(self.hass, 'availability-topic', 'online') + self.hass.block_till_done() + + state = self.hass.states.get('light.test') + self.assertNotEqual(STATE_UNAVAILABLE, state.state) + + fire_mqtt_message(self.hass, 'availability-topic', 'offline') + self.hass.block_till_done() + + state = self.hass.states.get('light.test') + self.assertEqual(STATE_UNAVAILABLE, state.state) + + def test_custom_availability_payload(self): + """Test availability by custom payload with defined topic.""" + self.assertTrue(setup_component(self.hass, light.DOMAIN, { + light.DOMAIN: { + 'platform': 'mqtt_json', + 'name': 'test', + 'state_topic': 'test_light_rgb', + 'command_topic': 'test_light_rgb/set', + 'availability_topic': 'availability-topic', + 'payload_available': 'good', + 'payload_not_available': 'nogood' + } + })) + + state = self.hass.states.get('light.test') + self.assertEqual(STATE_UNAVAILABLE, state.state) + + fire_mqtt_message(self.hass, 'availability-topic', 'good') + self.hass.block_till_done() + + state = self.hass.states.get('light.test') + self.assertNotEqual(STATE_UNAVAILABLE, state.state) + + fire_mqtt_message(self.hass, 'availability-topic', 'nogood') + self.hass.block_till_done() + + state = self.hass.states.get('light.test') + self.assertEqual(STATE_UNAVAILABLE, state.state) diff --git a/tests/components/light/test_mqtt_template.py b/tests/components/light/test_mqtt_template.py index 62947c052270ef..5a01aa15fa2bf6 100644 --- a/tests/components/light/test_mqtt_template.py +++ b/tests/components/light/test_mqtt_template.py @@ -1,498 +1,498 @@ -"""The tests for the MQTT Template light platform. - -Configuration example with all features: - -light: - platform: mqtt_template - name: mqtt_template_light_1 - state_topic: 'home/rgb1' - command_topic: 'home/rgb1/set' - command_on_template: > - on,{{ brightness|d }},{{ red|d }}-{{ green|d }}-{{ blue|d }} - command_off_template: 'off' - state_template: '{{ value.split(",")[0] }}' - brightness_template: '{{ value.split(",")[1] }}' - 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 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 - -from homeassistant.setup import setup_component -from homeassistant.const import ( - STATE_ON, STATE_OFF, STATE_UNAVAILABLE, ATTR_ASSUMED_STATE) -import homeassistant.components.light as light -from tests.common import ( - get_test_home_assistant, mock_mqtt_component, fire_mqtt_message, - assert_setup_component) - - -class TestLightMQTTTemplate(unittest.TestCase): - """Test the MQTT Template light.""" - - def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" - self.hass = get_test_home_assistant() - self.mock_publish = mock_mqtt_component(self.hass) - - def tearDown(self): # pylint: disable=invalid-name - """Stop everything that was started.""" - self.hass.stop() - - def test_setup_fails(self): \ - # pylint: disable=invalid-name - """Test that setup fails with missing required configuration items.""" - with assert_setup_component(0, light.DOMAIN): - assert setup_component(self.hass, light.DOMAIN, { - light.DOMAIN: { - 'platform': 'mqtt_template', - 'name': 'test', - } - }) - self.assertIsNone(self.hass.states.get('light.test')) - - def test_state_change_via_topic(self): \ - # pylint: disable=invalid-name - """Test state change via topic.""" - with assert_setup_component(1, light.DOMAIN): - assert setup_component(self.hass, light.DOMAIN, { - light.DOMAIN: { - 'platform': 'mqtt_template', - 'name': 'test', - 'state_topic': 'test_light_rgb', - 'command_topic': 'test_light_rgb/set', - 'command_on_template': 'on,' - '{{ brightness|d }},' - '{{ color_temp|d }},' - '{{ white_value|d }},' - '{{ red|d }}-' - '{{ green|d }}-' - '{{ blue|d }}', - 'command_off_template': 'off', - 'state_template': '{{ value.split(",")[0] }}' - } - }) - - state = self.hass.states.get('light.test') - 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.assertFalse(state.attributes.get(ATTR_ASSUMED_STATE)) - - fire_mqtt_message(self.hass, 'test_light_rgb', 'on') - self.hass.block_till_done() - - state = self.hass.states.get('light.test') - 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_temp_white_change_via_topic(self): \ - # pylint: disable=invalid-name - """Test state, bri, color, effect, color temp, white val change.""" - with assert_setup_component(1, light.DOMAIN): - assert setup_component(self.hass, light.DOMAIN, { - light.DOMAIN: { - 'platform': 'mqtt_template', - 'name': 'test', - 'effect_list': ['rainbow', 'colorloop'], - 'state_topic': 'test_light_rgb', - 'command_topic': 'test_light_rgb/set', - 'command_on_template': 'on,' - '{{ brightness|d }},' - '{{ color_temp|d }},' - '{{ white_value|d }},' - '{{ red|d }}-' - '{{ green|d }}-' - '{{ blue|d }},' - '{{ effect|d }}', - 'command_off_template': 'off', - 'state_template': '{{ value.split(",")[0] }}', - 'brightness_template': '{{ value.split(",")[1] }}', - '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] }}', - 'effect_template': '{{ value.split(",")[5] }}' - } - }) - - state = self.hass.states.get('light.test') - self.assertEqual(STATE_OFF, state.state) - 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.assertFalse(state.attributes.get(ATTR_ASSUMED_STATE)) - - # turn on the light, full white - fire_mqtt_message(self.hass, 'test_light_rgb', - 'on,255,145,123,255-128-64,') - self.hass.block_till_done() - - state = self.hass.states.get('light.test') - self.assertEqual(STATE_ON, state.state) - self.assertEqual([255, 128, 64], 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 - fire_mqtt_message(self.hass, 'test_light_rgb', 'off') - self.hass.block_till_done() - - state = self.hass.states.get('light.test') - self.assertEqual(STATE_OFF, state.state) - - # lower the brightness - fire_mqtt_message(self.hass, 'test_light_rgb', 'on,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['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') - 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') - self.hass.block_till_done() - - light_state = self.hass.states.get('light.test') - self.assertEqual('rainbow', light_state.attributes.get('effect')) - - def test_optimistic(self): \ - # pylint: disable=invalid-name - """Test optimistic mode.""" - with assert_setup_component(1, light.DOMAIN): - assert setup_component(self.hass, light.DOMAIN, { - light.DOMAIN: { - 'platform': 'mqtt_template', - 'name': 'test', - 'command_topic': 'test_light_rgb/set', - 'command_on_template': 'on,' - '{{ brightness|d }},' - '{{ color_temp|d }},' - '{{ white_value|d }},' - '{{ red|d }}-' - '{{ green|d }}-' - '{{ blue|d }}', - 'command_off_template': 'off', - 'qos': 2 - } - }) - - state = self.hass.states.get('light.test') - self.assertEqual(STATE_OFF, state.state) - self.assertTrue(state.attributes.get(ATTR_ASSUMED_STATE)) - - # turn on the light - light.turn_on(self.hass, 'light.test') - self.hass.block_till_done() - - self.mock_publish.async_publish.assert_called_once_with( - 'test_light_rgb/set', 'on,,,,--', 2, False) - self.mock_publish.async_publish.reset_mock() - state = self.hass.states.get('light.test') - self.assertEqual(STATE_ON, state.state) - - # turn the light off - light.turn_off(self.hass, 'light.test') - self.hass.block_till_done() - - self.mock_publish.async_publish.assert_called_once_with( - 'test_light_rgb/set', 'off', 2, False) - self.mock_publish.async_publish.reset_mock() - state = self.hass.states.get('light.test') - self.assertEqual(STATE_OFF, state.state) - - # turn on the light with brightness, color - light.turn_on(self.hass, 'light.test', brightness=50, - rgb_color=[75, 75, 75]) - self.hass.block_till_done() - - self.mock_publish.async_publish.assert_called_once_with( - 'test_light_rgb/set', 'on,50,,,75-75-75', 2, False) - self.mock_publish.async_publish.reset_mock() - - # turn on the light with color temp and white val - light.turn_on(self.hass, 'light.test', color_temp=200, white_value=139) - self.hass.block_till_done() - - self.mock_publish.async_publish.assert_called_once_with( - 'test_light_rgb/set', 'on,,200,139,--', 2, False) - - # 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 - """Test flash.""" - with assert_setup_component(1, light.DOMAIN): - assert setup_component(self.hass, light.DOMAIN, { - light.DOMAIN: { - 'platform': 'mqtt_template', - 'name': 'test', - 'command_topic': 'test_light_rgb/set', - 'command_on_template': 'on,{{ flash }}', - 'command_off_template': 'off', - 'qos': 0 - } - }) - - state = self.hass.states.get('light.test') - self.assertEqual(STATE_OFF, state.state) - - # short flash - light.turn_on(self.hass, 'light.test', flash='short') - self.hass.block_till_done() - - self.mock_publish.async_publish.assert_called_once_with( - 'test_light_rgb/set', 'on,short', 0, False) - self.mock_publish.async_publish.reset_mock() - - # long flash - light.turn_on(self.hass, 'light.test', flash='long') - self.hass.block_till_done() - - self.mock_publish.async_publish.assert_called_once_with( - 'test_light_rgb/set', 'on,long', 0, False) - - def test_transition(self): - """Test for transition time being sent when included.""" - with assert_setup_component(1, light.DOMAIN): - assert setup_component(self.hass, light.DOMAIN, { - light.DOMAIN: { - 'platform': 'mqtt_template', - 'name': 'test', - 'command_topic': 'test_light_rgb/set', - 'command_on_template': 'on,{{ transition }}', - 'command_off_template': 'off,{{ transition|d }}' - } - }) - - state = self.hass.states.get('light.test') - self.assertEqual(STATE_OFF, state.state) - - # transition on - light.turn_on(self.hass, 'light.test', transition=10) - self.hass.block_till_done() - - self.mock_publish.async_publish.assert_called_once_with( - 'test_light_rgb/set', 'on,10', 0, False) - self.mock_publish.async_publish.reset_mock() - - # transition off - light.turn_off(self.hass, 'light.test', transition=4) - self.hass.block_till_done() - - self.mock_publish.async_publish.assert_called_once_with( - 'test_light_rgb/set', 'off,4', 0, False) - - def test_invalid_values(self): \ - # pylint: disable=invalid-name - """Test that invalid values are ignored.""" - with assert_setup_component(1, light.DOMAIN): - assert setup_component(self.hass, light.DOMAIN, { - light.DOMAIN: { - 'platform': 'mqtt_template', - 'name': 'test', - 'effect_list': ['rainbow', 'colorloop'], - 'state_topic': 'test_light_rgb', - 'command_topic': 'test_light_rgb/set', - 'command_on_template': 'on,' - '{{ brightness|d }},' - '{{ color_temp|d }},' - '{{ red|d }}-' - '{{ green|d }}-' - '{{ blue|d }},' - '{{ effect|d }}', - 'command_off_template': 'off', - 'state_template': '{{ value.split(",")[0] }}', - 'brightness_template': '{{ value.split(",")[1] }}', - '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] }}', - 'effect_template': '{{ value.split(",")[5] }}', - } - }) - - state = self.hass.states.get('light.test') - 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.assertFalse(state.attributes.get(ATTR_ASSUMED_STATE)) - - # turn on the light, full white - fire_mqtt_message(self.hass, 'test_light_rgb', - '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 - fire_mqtt_message(self.hass, 'test_light_rgb', 'offf') - self.hass.block_till_done() - - # state should not have changed - state = self.hass.states.get('light.test') - self.assertEqual(STATE_ON, state.state) - - # bad brightness values - fire_mqtt_message(self.hass, 'test_light_rgb', 'on,off,255-255-255') - self.hass.block_till_done() - - # brightness should not have changed - 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() - - # color should not have changed - 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() - - # effect should not have changed - state = self.hass.states.get('light.test') - self.assertEqual('rainbow', state.attributes.get('effect')) - - def test_default_availability_payload(self): - """Test availability by default payload with defined topic.""" - self.assertTrue(setup_component(self.hass, light.DOMAIN, { - light.DOMAIN: { - 'platform': 'mqtt_template', - 'name': 'test', - 'command_topic': 'test_light_rgb/set', - 'command_on_template': 'on,{{ transition }}', - 'command_off_template': 'off,{{ transition|d }}', - 'availability_topic': 'availability-topic' - } - })) - - state = self.hass.states.get('light.test') - self.assertEqual(STATE_UNAVAILABLE, state.state) - - fire_mqtt_message(self.hass, 'availability-topic', 'online') - self.hass.block_till_done() - - state = self.hass.states.get('light.test') - self.assertNotEqual(STATE_UNAVAILABLE, state.state) - - fire_mqtt_message(self.hass, 'availability-topic', 'offline') - self.hass.block_till_done() - - state = self.hass.states.get('light.test') - self.assertEqual(STATE_UNAVAILABLE, state.state) - - def test_custom_availability_payload(self): - """Test availability by custom payload with defined topic.""" - self.assertTrue(setup_component(self.hass, light.DOMAIN, { - light.DOMAIN: { - 'platform': 'mqtt_template', - 'name': 'test', - 'command_topic': 'test_light_rgb/set', - 'command_on_template': 'on,{{ transition }}', - 'command_off_template': 'off,{{ transition|d }}', - 'availability_topic': 'availability-topic', - 'payload_available': 'good', - 'payload_not_available': 'nogood' - } - })) - - state = self.hass.states.get('light.test') - self.assertEqual(STATE_UNAVAILABLE, state.state) - - fire_mqtt_message(self.hass, 'availability-topic', 'good') - self.hass.block_till_done() - - state = self.hass.states.get('light.test') - self.assertNotEqual(STATE_UNAVAILABLE, state.state) - - fire_mqtt_message(self.hass, 'availability-topic', 'nogood') - self.hass.block_till_done() - - state = self.hass.states.get('light.test') - self.assertEqual(STATE_UNAVAILABLE, state.state) +"""The tests for the MQTT Template light platform. + +Configuration example with all features: + +light: + platform: mqtt_template + name: mqtt_template_light_1 + state_topic: 'home/rgb1' + command_topic: 'home/rgb1/set' + command_on_template: > + on,{{ brightness|d }},{{ red|d }}-{{ green|d }}-{{ blue|d }} + command_off_template: 'off' + state_template: '{{ value.split(",")[0] }}' + brightness_template: '{{ value.split(",")[1] }}' + 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 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 + +from homeassistant.setup import setup_component +from homeassistant.const import ( + STATE_ON, STATE_OFF, STATE_UNAVAILABLE, ATTR_ASSUMED_STATE) +import homeassistant.components.light as light +from tests.common import ( + get_test_home_assistant, mock_mqtt_component, fire_mqtt_message, + assert_setup_component) + + +class TestLightMQTTTemplate(unittest.TestCase): + """Test the MQTT Template light.""" + + def setUp(self): # pylint: disable=invalid-name + """Setup things to be run when tests are started.""" + self.hass = get_test_home_assistant() + self.mock_publish = mock_mqtt_component(self.hass) + + def tearDown(self): # pylint: disable=invalid-name + """Stop everything that was started.""" + self.hass.stop() + + def test_setup_fails(self): \ + # pylint: disable=invalid-name + """Test that setup fails with missing required configuration items.""" + with assert_setup_component(0, light.DOMAIN): + assert setup_component(self.hass, light.DOMAIN, { + light.DOMAIN: { + 'platform': 'mqtt_template', + 'name': 'test', + } + }) + self.assertIsNone(self.hass.states.get('light.test')) + + def test_state_change_via_topic(self): \ + # pylint: disable=invalid-name + """Test state change via topic.""" + with assert_setup_component(1, light.DOMAIN): + assert setup_component(self.hass, light.DOMAIN, { + light.DOMAIN: { + 'platform': 'mqtt_template', + 'name': 'test', + 'state_topic': 'test_light_rgb', + 'command_topic': 'test_light_rgb/set', + 'command_on_template': 'on,' + '{{ brightness|d }},' + '{{ color_temp|d }},' + '{{ white_value|d }},' + '{{ red|d }}-' + '{{ green|d }}-' + '{{ blue|d }}', + 'command_off_template': 'off', + 'state_template': '{{ value.split(",")[0] }}' + } + }) + + state = self.hass.states.get('light.test') + 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.assertFalse(state.attributes.get(ATTR_ASSUMED_STATE)) + + fire_mqtt_message(self.hass, 'test_light_rgb', 'on') + self.hass.block_till_done() + + state = self.hass.states.get('light.test') + 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_temp_white_change_via_topic(self): \ + # pylint: disable=invalid-name + """Test state, bri, color, effect, color temp, white val change.""" + with assert_setup_component(1, light.DOMAIN): + assert setup_component(self.hass, light.DOMAIN, { + light.DOMAIN: { + 'platform': 'mqtt_template', + 'name': 'test', + 'effect_list': ['rainbow', 'colorloop'], + 'state_topic': 'test_light_rgb', + 'command_topic': 'test_light_rgb/set', + 'command_on_template': 'on,' + '{{ brightness|d }},' + '{{ color_temp|d }},' + '{{ white_value|d }},' + '{{ red|d }}-' + '{{ green|d }}-' + '{{ blue|d }},' + '{{ effect|d }}', + 'command_off_template': 'off', + 'state_template': '{{ value.split(",")[0] }}', + 'brightness_template': '{{ value.split(",")[1] }}', + '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] }}', + 'effect_template': '{{ value.split(",")[5] }}' + } + }) + + state = self.hass.states.get('light.test') + self.assertEqual(STATE_OFF, state.state) + 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.assertFalse(state.attributes.get(ATTR_ASSUMED_STATE)) + + # turn on the light, full white + fire_mqtt_message(self.hass, 'test_light_rgb', + 'on,255,145,123,255-128-64,') + self.hass.block_till_done() + + state = self.hass.states.get('light.test') + self.assertEqual(STATE_ON, state.state) + self.assertEqual([255, 128, 64], 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 + fire_mqtt_message(self.hass, 'test_light_rgb', 'off') + self.hass.block_till_done() + + state = self.hass.states.get('light.test') + self.assertEqual(STATE_OFF, state.state) + + # lower the brightness + fire_mqtt_message(self.hass, 'test_light_rgb', 'on,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['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') + 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') + self.hass.block_till_done() + + light_state = self.hass.states.get('light.test') + self.assertEqual('rainbow', light_state.attributes.get('effect')) + + def test_optimistic(self): \ + # pylint: disable=invalid-name + """Test optimistic mode.""" + with assert_setup_component(1, light.DOMAIN): + assert setup_component(self.hass, light.DOMAIN, { + light.DOMAIN: { + 'platform': 'mqtt_template', + 'name': 'test', + 'command_topic': 'test_light_rgb/set', + 'command_on_template': 'on,' + '{{ brightness|d }},' + '{{ color_temp|d }},' + '{{ white_value|d }},' + '{{ red|d }}-' + '{{ green|d }}-' + '{{ blue|d }}', + 'command_off_template': 'off', + 'qos': 2 + } + }) + + state = self.hass.states.get('light.test') + self.assertEqual(STATE_OFF, state.state) + self.assertTrue(state.attributes.get(ATTR_ASSUMED_STATE)) + + # turn on the light + light.turn_on(self.hass, 'light.test') + self.hass.block_till_done() + + self.mock_publish.async_publish.assert_called_once_with( + 'test_light_rgb/set', 'on,,,,--', 2, False) + self.mock_publish.async_publish.reset_mock() + state = self.hass.states.get('light.test') + self.assertEqual(STATE_ON, state.state) + + # turn the light off + light.turn_off(self.hass, 'light.test') + self.hass.block_till_done() + + self.mock_publish.async_publish.assert_called_once_with( + 'test_light_rgb/set', 'off', 2, False) + self.mock_publish.async_publish.reset_mock() + state = self.hass.states.get('light.test') + self.assertEqual(STATE_OFF, state.state) + + # turn on the light with brightness, color + light.turn_on(self.hass, 'light.test', brightness=50, + rgb_color=[75, 75, 75]) + self.hass.block_till_done() + + self.mock_publish.async_publish.assert_called_once_with( + 'test_light_rgb/set', 'on,50,,,75-75-75', 2, False) + self.mock_publish.async_publish.reset_mock() + + # turn on the light with color temp and white val + light.turn_on(self.hass, 'light.test', color_temp=200, white_value=139) + self.hass.block_till_done() + + self.mock_publish.async_publish.assert_called_once_with( + 'test_light_rgb/set', 'on,,200,139,--', 2, False) + + # 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 + """Test flash.""" + with assert_setup_component(1, light.DOMAIN): + assert setup_component(self.hass, light.DOMAIN, { + light.DOMAIN: { + 'platform': 'mqtt_template', + 'name': 'test', + 'command_topic': 'test_light_rgb/set', + 'command_on_template': 'on,{{ flash }}', + 'command_off_template': 'off', + 'qos': 0 + } + }) + + state = self.hass.states.get('light.test') + self.assertEqual(STATE_OFF, state.state) + + # short flash + light.turn_on(self.hass, 'light.test', flash='short') + self.hass.block_till_done() + + self.mock_publish.async_publish.assert_called_once_with( + 'test_light_rgb/set', 'on,short', 0, False) + self.mock_publish.async_publish.reset_mock() + + # long flash + light.turn_on(self.hass, 'light.test', flash='long') + self.hass.block_till_done() + + self.mock_publish.async_publish.assert_called_once_with( + 'test_light_rgb/set', 'on,long', 0, False) + + def test_transition(self): + """Test for transition time being sent when included.""" + with assert_setup_component(1, light.DOMAIN): + assert setup_component(self.hass, light.DOMAIN, { + light.DOMAIN: { + 'platform': 'mqtt_template', + 'name': 'test', + 'command_topic': 'test_light_rgb/set', + 'command_on_template': 'on,{{ transition }}', + 'command_off_template': 'off,{{ transition|d }}' + } + }) + + state = self.hass.states.get('light.test') + self.assertEqual(STATE_OFF, state.state) + + # transition on + light.turn_on(self.hass, 'light.test', transition=10) + self.hass.block_till_done() + + self.mock_publish.async_publish.assert_called_once_with( + 'test_light_rgb/set', 'on,10', 0, False) + self.mock_publish.async_publish.reset_mock() + + # transition off + light.turn_off(self.hass, 'light.test', transition=4) + self.hass.block_till_done() + + self.mock_publish.async_publish.assert_called_once_with( + 'test_light_rgb/set', 'off,4', 0, False) + + def test_invalid_values(self): \ + # pylint: disable=invalid-name + """Test that invalid values are ignored.""" + with assert_setup_component(1, light.DOMAIN): + assert setup_component(self.hass, light.DOMAIN, { + light.DOMAIN: { + 'platform': 'mqtt_template', + 'name': 'test', + 'effect_list': ['rainbow', 'colorloop'], + 'state_topic': 'test_light_rgb', + 'command_topic': 'test_light_rgb/set', + 'command_on_template': 'on,' + '{{ brightness|d }},' + '{{ color_temp|d }},' + '{{ red|d }}-' + '{{ green|d }}-' + '{{ blue|d }},' + '{{ effect|d }}', + 'command_off_template': 'off', + 'state_template': '{{ value.split(",")[0] }}', + 'brightness_template': '{{ value.split(",")[1] }}', + '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] }}', + 'effect_template': '{{ value.split(",")[5] }}', + } + }) + + state = self.hass.states.get('light.test') + 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.assertFalse(state.attributes.get(ATTR_ASSUMED_STATE)) + + # turn on the light, full white + fire_mqtt_message(self.hass, 'test_light_rgb', + '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 + fire_mqtt_message(self.hass, 'test_light_rgb', 'offf') + self.hass.block_till_done() + + # state should not have changed + state = self.hass.states.get('light.test') + self.assertEqual(STATE_ON, state.state) + + # bad brightness values + fire_mqtt_message(self.hass, 'test_light_rgb', 'on,off,255-255-255') + self.hass.block_till_done() + + # brightness should not have changed + 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() + + # color should not have changed + 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() + + # effect should not have changed + state = self.hass.states.get('light.test') + self.assertEqual('rainbow', state.attributes.get('effect')) + + def test_default_availability_payload(self): + """Test availability by default payload with defined topic.""" + self.assertTrue(setup_component(self.hass, light.DOMAIN, { + light.DOMAIN: { + 'platform': 'mqtt_template', + 'name': 'test', + 'command_topic': 'test_light_rgb/set', + 'command_on_template': 'on,{{ transition }}', + 'command_off_template': 'off,{{ transition|d }}', + 'availability_topic': 'availability-topic' + } + })) + + state = self.hass.states.get('light.test') + self.assertEqual(STATE_UNAVAILABLE, state.state) + + fire_mqtt_message(self.hass, 'availability-topic', 'online') + self.hass.block_till_done() + + state = self.hass.states.get('light.test') + self.assertNotEqual(STATE_UNAVAILABLE, state.state) + + fire_mqtt_message(self.hass, 'availability-topic', 'offline') + self.hass.block_till_done() + + state = self.hass.states.get('light.test') + self.assertEqual(STATE_UNAVAILABLE, state.state) + + def test_custom_availability_payload(self): + """Test availability by custom payload with defined topic.""" + self.assertTrue(setup_component(self.hass, light.DOMAIN, { + light.DOMAIN: { + 'platform': 'mqtt_template', + 'name': 'test', + 'command_topic': 'test_light_rgb/set', + 'command_on_template': 'on,{{ transition }}', + 'command_off_template': 'off,{{ transition|d }}', + 'availability_topic': 'availability-topic', + 'payload_available': 'good', + 'payload_not_available': 'nogood' + } + })) + + state = self.hass.states.get('light.test') + self.assertEqual(STATE_UNAVAILABLE, state.state) + + fire_mqtt_message(self.hass, 'availability-topic', 'good') + self.hass.block_till_done() + + state = self.hass.states.get('light.test') + self.assertNotEqual(STATE_UNAVAILABLE, state.state) + + fire_mqtt_message(self.hass, 'availability-topic', 'nogood') + self.hass.block_till_done() + + state = self.hass.states.get('light.test') + self.assertEqual(STATE_UNAVAILABLE, state.state) diff --git a/tests/fixtures/pushbullet_devices.json b/tests/fixtures/pushbullet_devices.json index 04f336c8adf4d9..576e748471acb8 100755 --- a/tests/fixtures/pushbullet_devices.json +++ b/tests/fixtures/pushbullet_devices.json @@ -1,43 +1,43 @@ -{ - "accounts": [], - "blocks": [], - "channels": [], - "chats": [], - "clients": [], - "contacts": [], - "devices": [{ - "active": true, - "iden": "identity1", - "created": 1.514520333770855e+09, - "modified": 1.5151951594363022e+09, - "type": "windows", - "kind": "windows", - "nickname": "DESKTOP", - "manufacturer": "Microsoft", - "model": "Windows 10 Home", - "app_version": 396, - "fingerprint": "{\"cpu\":\"AMD\",\"computer_name\":\"DESKTOP\"}", - "pushable": true, - "icon": "desktop", - "remote_files": "disabled" - }, { - "active": true, - "iden": "identity2", - "created": 1.5144974875448499e+09, - "modified": 1.514574792288634e+09, - "type": "ios", - "kind": "ios", - "nickname": "My iPhone", - "manufacturer": "Apple", - "model": "iPhone", - "app_version": 8646, - "push_token": "production:mytoken", - "pushable": true, - "icon": "phone" - }], - "grants": [], - "pushes": [], - "profiles": [], - "subscriptions": [], - "texts": [] -} +{ + "accounts": [], + "blocks": [], + "channels": [], + "chats": [], + "clients": [], + "contacts": [], + "devices": [{ + "active": true, + "iden": "identity1", + "created": 1.514520333770855e+09, + "modified": 1.5151951594363022e+09, + "type": "windows", + "kind": "windows", + "nickname": "DESKTOP", + "manufacturer": "Microsoft", + "model": "Windows 10 Home", + "app_version": 396, + "fingerprint": "{\"cpu\":\"AMD\",\"computer_name\":\"DESKTOP\"}", + "pushable": true, + "icon": "desktop", + "remote_files": "disabled" + }, { + "active": true, + "iden": "identity2", + "created": 1.5144974875448499e+09, + "modified": 1.514574792288634e+09, + "type": "ios", + "kind": "ios", + "nickname": "My iPhone", + "manufacturer": "Apple", + "model": "iPhone", + "app_version": 8646, + "push_token": "production:mytoken", + "pushable": true, + "icon": "phone" + }], + "grants": [], + "pushes": [], + "profiles": [], + "subscriptions": [], + "texts": [] +} diff --git a/tests/fixtures/yahooweather.json b/tests/fixtures/yahooweather.json index f6ab2980618865..7d8188764dfa10 100644 --- a/tests/fixtures/yahooweather.json +++ b/tests/fixtures/yahooweather.json @@ -1,138 +1,138 @@ -{ - "query": { - "count": 1, - "created": "2017-11-17T13:40:47Z", - "lang": "en-US", - "results": { - "channel": { - "units": { - "distance": "km", - "pressure": "mb", - "speed": "km/h", - "temperature": "C" - }, - "title": "Yahoo! Weather - San Diego, CA, US", - "link": "http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-23511632/", - "description": "Yahoo! Weather for San Diego, CA, US", - "language": "en-us", - "lastBuildDate": "Fri, 17 Nov 2017 05:40 AM PST", - "ttl": "60", - "location": { - "city": "San Diego", - "country": "United States", - "region": " CA" - }, - "wind": { - "chill": "56", - "direction": "0", - "speed": "6.34" - }, - "atmosphere": { - "humidity": "71", - "pressure": "33863.75", - "rising": "0", - "visibility": "22.91" - }, - "astronomy": { - "sunrise": "6:21 am", - "sunset": "4:47 pm" - }, - "image": { - "title": "Yahoo! Weather", - "width": "142", - "height": "18", - "link": "http://weather.yahoo.com", - "url": "http://l.yimg.com/a/i/brand/purplelogo//uh/us/news-wea.gif" - }, - "item": { - "title": "Conditions for San Diego, CA, US at 05:00 AM PST", - "lat": "32.878101", - "long": "-117.23497", - "link": "http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-23511632/", - "pubDate": "Fri, 17 Nov 2017 05:00 AM PST", - "condition": { - "code": "26", - "date": "Fri, 17 Nov 2017 05:00 AM PST", - "temp": "18", - "text": "Cloudy" - }, - "forecast": [{ - "code": "28", - "date": "17 Nov 2017", - "day": "Fri", - "high": "23", - "low": "16", - "text": "Mostly Cloudy" - }, { - "code": "30", - "date": "18 Nov 2017", - "day": "Sat", - "high": "22", - "low": "13", - "text": "Partly Cloudy" - }, { - "code": "30", - "date": "19 Nov 2017", - "day": "Sun", - "high": "22", - "low": "12", - "text": "Partly Cloudy" - }, { - "code": "28", - "date": "20 Nov 2017", - "day": "Mon", - "high": "21", - "low": "11", - "text": "Mostly Cloudy" - }, { - "code": "28", - "date": "21 Nov 2017", - "day": "Tue", - "high": "24", - "low": "14", - "text": "Mostly Cloudy" - }, { - "code": "30", - "date": "22 Nov 2017", - "day": "Wed", - "high": "27", - "low": "15", - "text": "Partly Cloudy" - }, { - "code": "34", - "date": "23 Nov 2017", - "day": "Thu", - "high": "27", - "low": "15", - "text": "Mostly Sunny" - }, { - "code": "30", - "date": "24 Nov 2017", - "day": "Fri", - "high": "23", - "low": "16", - "text": "Partly Cloudy" - }, { - "code": "30", - "date": "25 Nov 2017", - "day": "Sat", - "high": "22", - "low": "15", - "text": "Partly Cloudy" - }, { - "code": "28", - "date": "26 Nov 2017", - "day": "Sun", - "high": "24", - "low": "13", - "text": "Mostly Cloudy" - }], - "description": "\n
\nCurrent Conditions:\n
Cloudy\n
\n
\nForecast:\n
Fri - Mostly Cloudy. High: 23Low: 16\n
Sat - Partly Cloudy. High: 22Low: 13\n
Sun - Partly Cloudy. High: 22Low: 12\n
Mon - Mostly Cloudy. High: 21Low: 11\n
Tue - Mostly Cloudy. High: 24Low: 14\n
\n
\nFull Forecast at Yahoo! Weather\n
\n
\n
\n]]>", - "guid": { - "isPermaLink": "false" - } - } - } - } - } -} +{ + "query": { + "count": 1, + "created": "2017-11-17T13:40:47Z", + "lang": "en-US", + "results": { + "channel": { + "units": { + "distance": "km", + "pressure": "mb", + "speed": "km/h", + "temperature": "C" + }, + "title": "Yahoo! Weather - San Diego, CA, US", + "link": "http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-23511632/", + "description": "Yahoo! Weather for San Diego, CA, US", + "language": "en-us", + "lastBuildDate": "Fri, 17 Nov 2017 05:40 AM PST", + "ttl": "60", + "location": { + "city": "San Diego", + "country": "United States", + "region": " CA" + }, + "wind": { + "chill": "56", + "direction": "0", + "speed": "6.34" + }, + "atmosphere": { + "humidity": "71", + "pressure": "33863.75", + "rising": "0", + "visibility": "22.91" + }, + "astronomy": { + "sunrise": "6:21 am", + "sunset": "4:47 pm" + }, + "image": { + "title": "Yahoo! Weather", + "width": "142", + "height": "18", + "link": "http://weather.yahoo.com", + "url": "http://l.yimg.com/a/i/brand/purplelogo//uh/us/news-wea.gif" + }, + "item": { + "title": "Conditions for San Diego, CA, US at 05:00 AM PST", + "lat": "32.878101", + "long": "-117.23497", + "link": "http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-23511632/", + "pubDate": "Fri, 17 Nov 2017 05:00 AM PST", + "condition": { + "code": "26", + "date": "Fri, 17 Nov 2017 05:00 AM PST", + "temp": "18", + "text": "Cloudy" + }, + "forecast": [{ + "code": "28", + "date": "17 Nov 2017", + "day": "Fri", + "high": "23", + "low": "16", + "text": "Mostly Cloudy" + }, { + "code": "30", + "date": "18 Nov 2017", + "day": "Sat", + "high": "22", + "low": "13", + "text": "Partly Cloudy" + }, { + "code": "30", + "date": "19 Nov 2017", + "day": "Sun", + "high": "22", + "low": "12", + "text": "Partly Cloudy" + }, { + "code": "28", + "date": "20 Nov 2017", + "day": "Mon", + "high": "21", + "low": "11", + "text": "Mostly Cloudy" + }, { + "code": "28", + "date": "21 Nov 2017", + "day": "Tue", + "high": "24", + "low": "14", + "text": "Mostly Cloudy" + }, { + "code": "30", + "date": "22 Nov 2017", + "day": "Wed", + "high": "27", + "low": "15", + "text": "Partly Cloudy" + }, { + "code": "34", + "date": "23 Nov 2017", + "day": "Thu", + "high": "27", + "low": "15", + "text": "Mostly Sunny" + }, { + "code": "30", + "date": "24 Nov 2017", + "day": "Fri", + "high": "23", + "low": "16", + "text": "Partly Cloudy" + }, { + "code": "30", + "date": "25 Nov 2017", + "day": "Sat", + "high": "22", + "low": "15", + "text": "Partly Cloudy" + }, { + "code": "28", + "date": "26 Nov 2017", + "day": "Sun", + "high": "24", + "low": "13", + "text": "Mostly Cloudy" + }], + "description": "\n
\nCurrent Conditions:\n
Cloudy\n
\n
\nForecast:\n
Fri - Mostly Cloudy. High: 23Low: 16\n
Sat - Partly Cloudy. High: 22Low: 13\n
Sun - Partly Cloudy. High: 22Low: 12\n
Mon - Mostly Cloudy. High: 21Low: 11\n
Tue - Mostly Cloudy. High: 24Low: 14\n
\n
\nFull Forecast at Yahoo! Weather\n
\n
\n
\n]]>", + "guid": { + "isPermaLink": "false" + } + } + } + } + } +}