From a4792998a2354e88ad8d4dc3ffd9935e156cf9d5 Mon Sep 17 00:00:00 2001 From: Jan Bouwhuis <jbouwh@users.noreply.github.com> Date: Tue, 6 Sep 2022 11:02:15 +0200 Subject: [PATCH] Refactor MQTT tests to use modern platform schema part 1 (#77387) * Tests alarm_control_panel * Tests binary_sensor * Tests button * Tests camera * Tests Climate + corrections default config * Tests cover * Tests device_tracker * Tests fan * Tests humidifier * Fix test_supported_features test fan * Tests init * Tests legacy vacuum * Derive DEFAULT_CONFIG_LEGACY from DEFAULT_CONFIG * Commit suggestion comment changes --- .../mqtt/test_alarm_control_panel.py | 265 +-- tests/components/mqtt/test_binary_sensor.py | 341 ++-- tests/components/mqtt/test_button.py | 169 +- tests/components/mqtt/test_camera.py | 131 +- tests/components/mqtt/test_climate.py | 290 +-- tests/components/mqtt/test_cover.py | 1566 +++++++++-------- tests/components/mqtt/test_device_tracker.py | 122 +- .../mqtt/test_device_tracker_discovery.py | 39 +- tests/components/mqtt/test_fan.py | 954 +++++----- tests/components/mqtt/test_humidifier.py | 659 +++---- tests/components/mqtt/test_init.py | 35 +- tests/components/mqtt/test_legacy_vacuum.py | 284 +-- 12 files changed, 2659 insertions(+), 2196 deletions(-) diff --git a/tests/components/mqtt/test_alarm_control_panel.py b/tests/components/mqtt/test_alarm_control_panel.py index 7d127902f3d..e51ed9aeae9 100644 --- a/tests/components/mqtt/test_alarm_control_panel.py +++ b/tests/components/mqtt/test_alarm_control_panel.py @@ -5,7 +5,7 @@ from unittest.mock import patch import pytest -from homeassistant.components import alarm_control_panel +from homeassistant.components import alarm_control_panel, mqtt from homeassistant.components.mqtt.alarm_control_panel import ( MQTT_ALARM_ATTRIBUTES_BLOCKED, ) @@ -65,54 +65,65 @@ from .test_common import ( help_test_update_with_json_attrs_not_dict, ) -from tests.common import assert_setup_component, async_fire_mqtt_message +from tests.common import async_fire_mqtt_message from tests.components.alarm_control_panel import common CODE_NUMBER = "1234" CODE_TEXT = "HELLO_CODE" DEFAULT_CONFIG = { - alarm_control_panel.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "alarm/state", - "command_topic": "alarm/command", + mqtt.DOMAIN: { + alarm_control_panel.DOMAIN: { + "name": "test", + "state_topic": "alarm/state", + "command_topic": "alarm/command", + } } } DEFAULT_CONFIG_CODE = { - alarm_control_panel.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "alarm/state", - "command_topic": "alarm/command", - "code": "0123", - "code_arm_required": True, + mqtt.DOMAIN: { + alarm_control_panel.DOMAIN: { + "name": "test", + "state_topic": "alarm/state", + "command_topic": "alarm/command", + "code": "0123", + "code_arm_required": True, + } } } DEFAULT_CONFIG_REMOTE_CODE = { - alarm_control_panel.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "alarm/state", - "command_topic": "alarm/command", - "code": "REMOTE_CODE", - "code_arm_required": True, + mqtt.DOMAIN: { + alarm_control_panel.DOMAIN: { + "name": "test", + "state_topic": "alarm/state", + "command_topic": "alarm/command", + "code": "REMOTE_CODE", + "code_arm_required": True, + } } } DEFAULT_CONFIG_REMOTE_CODE_TEXT = { - alarm_control_panel.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "alarm/state", - "command_topic": "alarm/command", - "code": "REMOTE_CODE_TEXT", - "code_arm_required": True, + mqtt.DOMAIN: { + alarm_control_panel.DOMAIN: { + "name": "test", + "state_topic": "alarm/state", + "command_topic": "alarm/command", + "code": "REMOTE_CODE_TEXT", + "code_arm_required": True, + } } } +# Test deprecated YAML configuration under the platform key +# Scheduled to be removed in HA core 2022.12 +DEFAULT_CONFIG_LEGACY = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) +DEFAULT_CONFIG_LEGACY[alarm_control_panel.DOMAIN]["platform"] = mqtt.DOMAIN +DEFAULT_CONFIG_CODE_LEGACY = copy.deepcopy(DEFAULT_CONFIG_CODE[mqtt.DOMAIN]) +DEFAULT_CONFIG_CODE_LEGACY[alarm_control_panel.DOMAIN]["platform"] = mqtt.DOMAIN + @pytest.fixture(autouse=True) def alarm_control_panel_platform_only(): @@ -123,47 +134,62 @@ def alarm_control_panel_platform_only(): yield -async def test_fail_setup_without_state_topic(hass, mqtt_mock_entry_no_yaml_config): - """Test for failing with no state topic.""" - with assert_setup_component(0, alarm_control_panel.DOMAIN) as config: - assert await async_setup_component( - hass, - alarm_control_panel.DOMAIN, +@pytest.mark.parametrize( + "config,valid", + [ + ( { - alarm_control_panel.DOMAIN: { - "platform": "mqtt", - "command_topic": "alarm/command", + mqtt.DOMAIN: { + alarm_control_panel.DOMAIN: { + "name": "test", + "command_topic": "alarm/command", + } } }, - ) - await hass.async_block_till_done() - await mqtt_mock_entry_no_yaml_config() - assert not config[alarm_control_panel.DOMAIN] - - -async def test_fail_setup_without_command_topic(hass, mqtt_mock_entry_no_yaml_config): - """Test failing with no command topic.""" - with assert_setup_component(0, alarm_control_panel.DOMAIN) as config: - assert await async_setup_component( - hass, - alarm_control_panel.DOMAIN, + False, + ), + ( { - alarm_control_panel.DOMAIN: { - "platform": "mqtt", - "state_topic": "alarm/state", + mqtt.DOMAIN: { + alarm_control_panel.DOMAIN: { + "name": "test", + "state_topic": "alarm/state", + } } }, + False, + ), + ( + { + mqtt.DOMAIN: { + alarm_control_panel.DOMAIN: { + "name": "test", + "command_topic": "alarm/command", + "state_topic": "alarm/state", + } + } + }, + True, + ), + ], +) +async def test_fail_setup_without_state_or_command_topic(hass, config, valid): + """Test for failing setup with no state or command topic.""" + assert ( + await async_setup_component( + hass, + mqtt.DOMAIN, + config, ) - await hass.async_block_till_done() - await mqtt_mock_entry_no_yaml_config() - assert not config[alarm_control_panel.DOMAIN] + is valid + ) async def test_update_state_via_state_topic(hass, mqtt_mock_entry_with_yaml_config): """Test updating with via state topic.""" assert await async_setup_component( hass, - alarm_control_panel.DOMAIN, + mqtt.DOMAIN, DEFAULT_CONFIG, ) await hass.async_block_till_done() @@ -195,7 +221,7 @@ async def test_ignore_update_state_if_unknown_via_state_topic( """Test ignoring updates via state topic.""" assert await async_setup_component( hass, - alarm_control_panel.DOMAIN, + mqtt.DOMAIN, DEFAULT_CONFIG, ) await hass.async_block_till_done() @@ -227,7 +253,7 @@ async def test_publish_mqtt_no_code( """Test publishing of MQTT messages when no code is configured.""" assert await async_setup_component( hass, - alarm_control_panel.DOMAIN, + mqtt.DOMAIN, DEFAULT_CONFIG, ) await hass.async_block_till_done() @@ -261,7 +287,7 @@ async def test_publish_mqtt_with_code( """Test publishing of MQTT messages when code is configured.""" assert await async_setup_component( hass, - alarm_control_panel.DOMAIN, + mqtt.DOMAIN, DEFAULT_CONFIG_CODE, ) await hass.async_block_till_done() @@ -314,7 +340,7 @@ async def test_publish_mqtt_with_remote_code( """Test publishing of MQTT messages when remode code is configured.""" assert await async_setup_component( hass, - alarm_control_panel.DOMAIN, + mqtt.DOMAIN, DEFAULT_CONFIG_REMOTE_CODE, ) await hass.async_block_till_done() @@ -358,7 +384,7 @@ async def test_publish_mqtt_with_remote_code_text( """Test publishing of MQTT messages when remote text code is configured.""" assert await async_setup_component( hass, - alarm_control_panel.DOMAIN, + mqtt.DOMAIN, DEFAULT_CONFIG_REMOTE_CODE_TEXT, ) await hass.async_block_till_done() @@ -405,10 +431,10 @@ async def test_publish_mqtt_with_code_required_false( code_trigger_required = False """ config = copy.deepcopy(DEFAULT_CONFIG_CODE) - config[alarm_control_panel.DOMAIN][disable_code] = False + config[mqtt.DOMAIN][alarm_control_panel.DOMAIN][disable_code] = False assert await async_setup_component( hass, - alarm_control_panel.DOMAIN, + mqtt.DOMAIN, config, ) await hass.async_block_till_done() @@ -453,13 +479,13 @@ async def test_disarm_publishes_mqtt_with_template( When command_template set to output json """ config = copy.deepcopy(DEFAULT_CONFIG_CODE) - config[alarm_control_panel.DOMAIN]["code"] = "0123" - config[alarm_control_panel.DOMAIN][ + config[mqtt.DOMAIN][alarm_control_panel.DOMAIN]["code"] = "0123" + config[mqtt.DOMAIN][alarm_control_panel.DOMAIN][ "command_template" ] = '{"action":"{{ action }}","code":"{{ code }}"}' assert await async_setup_component( hass, - alarm_control_panel.DOMAIN, + mqtt.DOMAIN, config, ) await hass.async_block_till_done() @@ -477,19 +503,20 @@ async def test_update_state_via_state_topic_template( """Test updating with template_value via state topic.""" assert await async_setup_component( hass, - alarm_control_panel.DOMAIN, + mqtt.DOMAIN, { - alarm_control_panel.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "test-topic", - "state_topic": "test-topic", - "value_template": "\ + mqtt.DOMAIN: { + alarm_control_panel.DOMAIN: { + "name": "test", + "command_topic": "test-topic", + "state_topic": "test-topic", + "value_template": "\ {% if (value | int) == 100 %}\ armed_away\ {% else %}\ disarmed\ {% endif %}", + } } }, ) @@ -508,9 +535,9 @@ async def test_update_state_via_state_topic_template( async def test_attributes_code_number(hass, mqtt_mock_entry_with_yaml_config): """Test attributes which are not supported by the vacuum.""" config = copy.deepcopy(DEFAULT_CONFIG) - config[alarm_control_panel.DOMAIN]["code"] = CODE_NUMBER + config[mqtt.DOMAIN][alarm_control_panel.DOMAIN]["code"] = CODE_NUMBER - assert await async_setup_component(hass, alarm_control_panel.DOMAIN, config) + assert await async_setup_component(hass, mqtt.DOMAIN, config) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -524,9 +551,9 @@ async def test_attributes_code_number(hass, mqtt_mock_entry_with_yaml_config): async def test_attributes_remote_code_number(hass, mqtt_mock_entry_with_yaml_config): """Test attributes which are not supported by the vacuum.""" config = copy.deepcopy(DEFAULT_CONFIG_REMOTE_CODE) - config[alarm_control_panel.DOMAIN]["code"] = "REMOTE_CODE" + config[mqtt.DOMAIN][alarm_control_panel.DOMAIN]["code"] = "REMOTE_CODE" - assert await async_setup_component(hass, alarm_control_panel.DOMAIN, config) + assert await async_setup_component(hass, mqtt.DOMAIN, config) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -540,9 +567,9 @@ async def test_attributes_remote_code_number(hass, mqtt_mock_entry_with_yaml_con async def test_attributes_code_text(hass, mqtt_mock_entry_with_yaml_config): """Test attributes which are not supported by the vacuum.""" config = copy.deepcopy(DEFAULT_CONFIG) - config[alarm_control_panel.DOMAIN]["code"] = CODE_TEXT + config[mqtt.DOMAIN][alarm_control_panel.DOMAIN]["code"] = CODE_TEXT - assert await async_setup_component(hass, alarm_control_panel.DOMAIN, config) + assert await async_setup_component(hass, mqtt.DOMAIN, config) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -561,7 +588,7 @@ async def test_availability_when_connection_lost( hass, mqtt_mock_entry_with_yaml_config, alarm_control_panel.DOMAIN, - DEFAULT_CONFIG_CODE, + DEFAULT_CONFIG_CODE_LEGACY, ) @@ -571,7 +598,7 @@ async def test_availability_without_topic(hass, mqtt_mock_entry_with_yaml_config hass, mqtt_mock_entry_with_yaml_config, alarm_control_panel.DOMAIN, - DEFAULT_CONFIG_CODE, + DEFAULT_CONFIG_CODE_LEGACY, ) @@ -581,7 +608,7 @@ async def test_default_availability_payload(hass, mqtt_mock_entry_with_yaml_conf hass, mqtt_mock_entry_with_yaml_config, alarm_control_panel.DOMAIN, - DEFAULT_CONFIG_CODE, + DEFAULT_CONFIG_CODE_LEGACY, ) @@ -591,7 +618,7 @@ async def test_custom_availability_payload(hass, mqtt_mock_entry_with_yaml_confi hass, mqtt_mock_entry_with_yaml_config, alarm_control_panel.DOMAIN, - DEFAULT_CONFIG_CODE, + DEFAULT_CONFIG_CODE_LEGACY, ) @@ -603,7 +630,7 @@ async def test_setting_attribute_via_mqtt_json_message( hass, mqtt_mock_entry_with_yaml_config, alarm_control_panel.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, ) @@ -615,7 +642,7 @@ async def test_setting_blocked_attribute_via_mqtt_json_message( hass, mqtt_mock_entry_no_yaml_config, alarm_control_panel.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, MQTT_ALARM_ATTRIBUTES_BLOCKED, ) @@ -626,7 +653,7 @@ async def test_setting_attribute_with_template(hass, mqtt_mock_entry_with_yaml_c hass, mqtt_mock_entry_with_yaml_config, alarm_control_panel.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, ) @@ -639,7 +666,7 @@ async def test_update_with_json_attrs_not_dict( mqtt_mock_entry_with_yaml_config, caplog, alarm_control_panel.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, ) @@ -652,7 +679,7 @@ async def test_update_with_json_attrs_bad_JSON( mqtt_mock_entry_with_yaml_config, caplog, alarm_control_panel.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, ) @@ -663,7 +690,7 @@ async def test_discovery_update_attr(hass, mqtt_mock_entry_no_yaml_config, caplo mqtt_mock_entry_no_yaml_config, caplog, alarm_control_panel.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, ) @@ -694,7 +721,7 @@ async def test_unique_id(hass, mqtt_mock_entry_with_yaml_config): async def test_discovery_removal_alarm(hass, mqtt_mock_entry_no_yaml_config, caplog): """Test removal of discovered alarm_control_panel.""" - data = json.dumps(DEFAULT_CONFIG[alarm_control_panel.DOMAIN]) + data = json.dumps(DEFAULT_CONFIG_LEGACY[alarm_control_panel.DOMAIN]) await help_test_discovery_removal( hass, mqtt_mock_entry_no_yaml_config, caplog, alarm_control_panel.DOMAIN, data ) @@ -704,8 +731,8 @@ async def test_discovery_update_alarm_topic_and_template( hass, mqtt_mock_entry_no_yaml_config, caplog ): """Test update of discovered alarm_control_panel.""" - config1 = copy.deepcopy(DEFAULT_CONFIG[alarm_control_panel.DOMAIN]) - config2 = copy.deepcopy(DEFAULT_CONFIG[alarm_control_panel.DOMAIN]) + config1 = copy.deepcopy(DEFAULT_CONFIG_LEGACY[alarm_control_panel.DOMAIN]) + config2 = copy.deepcopy(DEFAULT_CONFIG_LEGACY[alarm_control_panel.DOMAIN]) config1["name"] = "Beer" config2["name"] = "Milk" config1["state_topic"] = "alarm/state1" @@ -739,8 +766,8 @@ async def test_discovery_update_alarm_template( hass, mqtt_mock_entry_no_yaml_config, caplog ): """Test update of discovered alarm_control_panel.""" - config1 = copy.deepcopy(DEFAULT_CONFIG[alarm_control_panel.DOMAIN]) - config2 = copy.deepcopy(DEFAULT_CONFIG[alarm_control_panel.DOMAIN]) + config1 = copy.deepcopy(DEFAULT_CONFIG_LEGACY[alarm_control_panel.DOMAIN]) + config2 = copy.deepcopy(DEFAULT_CONFIG_LEGACY[alarm_control_panel.DOMAIN]) config1["name"] = "Beer" config2["name"] = "Milk" config1["state_topic"] = "alarm/state1" @@ -772,7 +799,7 @@ async def test_discovery_update_unchanged_alarm( hass, mqtt_mock_entry_no_yaml_config, caplog ): """Test update of discovered alarm_control_panel.""" - config1 = copy.deepcopy(DEFAULT_CONFIG[alarm_control_panel.DOMAIN]) + config1 = copy.deepcopy(DEFAULT_CONFIG_LEGACY[alarm_control_panel.DOMAIN]) config1["name"] = "Beer" data1 = json.dumps(config1) @@ -824,7 +851,7 @@ async def test_encoding_subscribable_topics( mqtt_mock_entry_with_yaml_config, caplog, alarm_control_panel.DOMAIN, - DEFAULT_CONFIG[alarm_control_panel.DOMAIN], + DEFAULT_CONFIG_LEGACY[alarm_control_panel.DOMAIN], topic, value, ) @@ -836,7 +863,7 @@ async def test_entity_device_info_with_connection(hass, mqtt_mock_entry_no_yaml_ hass, mqtt_mock_entry_no_yaml_config, alarm_control_panel.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, ) @@ -846,21 +873,27 @@ async def test_entity_device_info_with_identifier(hass, mqtt_mock_entry_no_yaml_ hass, mqtt_mock_entry_no_yaml_config, alarm_control_panel.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, ) async def test_entity_device_info_update(hass, mqtt_mock_entry_no_yaml_config): """Test device registry update.""" await help_test_entity_device_info_update( - hass, mqtt_mock_entry_no_yaml_config, alarm_control_panel.DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_no_yaml_config, + alarm_control_panel.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) async def test_entity_device_info_remove(hass, mqtt_mock_entry_no_yaml_config): """Test device registry remove.""" await help_test_entity_device_info_remove( - hass, mqtt_mock_entry_no_yaml_config, alarm_control_panel.DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_no_yaml_config, + alarm_control_panel.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) @@ -870,14 +903,17 @@ async def test_entity_id_update_subscriptions(hass, mqtt_mock_entry_with_yaml_co hass, mqtt_mock_entry_with_yaml_config, alarm_control_panel.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, ) async def test_entity_id_update_discovery_update(hass, mqtt_mock_entry_no_yaml_config): """Test MQTT discovery update when entity_id is updated.""" await help_test_entity_id_update_discovery_update( - hass, mqtt_mock_entry_no_yaml_config, alarm_control_panel.DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_no_yaml_config, + alarm_control_panel.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) @@ -887,7 +923,7 @@ async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config): hass, mqtt_mock_entry_no_yaml_config, alarm_control_panel.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, alarm_control_panel.SERVICE_ALARM_DISARM, command_payload="DISARM", ) @@ -930,7 +966,7 @@ async def test_publishing_with_custom_encoding( ): """Test publishing MQTT payload with different encoding.""" domain = alarm_control_panel.DOMAIN - config = DEFAULT_CONFIG[domain] + config = DEFAULT_CONFIG_LEGACY[domain] await help_test_publishing_with_custom_encoding( hass, @@ -951,7 +987,7 @@ async def test_publishing_with_custom_encoding( async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path): """Test reloading the MQTT platform.""" domain = alarm_control_panel.DOMAIN - config = DEFAULT_CONFIG[domain] + config = DEFAULT_CONFIG_LEGACY[domain] await help_test_reloadable( hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config ) @@ -960,14 +996,14 @@ async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_pa async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path): """Test reloading the MQTT platform with late entry setup.""" domain = alarm_control_panel.DOMAIN - config = DEFAULT_CONFIG[domain] + config = DEFAULT_CONFIG_LEGACY[domain] await help_test_reloadable_late(hass, caplog, tmp_path, domain, config) async def test_setup_manual_entity_from_yaml(hass): """Test setup manual configured MQTT entity.""" platform = alarm_control_panel.DOMAIN - config = copy.deepcopy(DEFAULT_CONFIG[platform]) + config = copy.deepcopy(DEFAULT_CONFIG_LEGACY[platform]) config["name"] = "test" del config["platform"] await help_test_setup_manual_entity_from_yaml(hass, platform, config) @@ -977,7 +1013,20 @@ async def test_setup_manual_entity_from_yaml(hass): async def test_unload_entry(hass, mqtt_mock_entry_with_yaml_config, tmp_path): """Test unloading the config entry.""" domain = alarm_control_panel.DOMAIN - config = DEFAULT_CONFIG[domain] + config = DEFAULT_CONFIG_LEGACY[domain] await help_test_unload_config_entry_with_platform( hass, mqtt_mock_entry_with_yaml_config, tmp_path, domain, config ) + + +# Test deprecated YAML configuration under the platform key +# Scheduled to be removed in HA core 2022.12 +async def test_setup_with_legacy_schema(hass, mqtt_mock_entry_with_yaml_config): + """Test a setup with deprecated yaml platform schema.""" + domain = alarm_control_panel.DOMAIN + config = copy.deepcopy(DEFAULT_CONFIG_LEGACY[domain]) + config["name"] = "test" + assert await async_setup_component(hass, domain, {domain: config}) + await hass.async_block_till_done() + await mqtt_mock_entry_with_yaml_config() + assert hass.states.get(f"{domain}.test") is not None diff --git a/tests/components/mqtt/test_binary_sensor.py b/tests/components/mqtt/test_binary_sensor.py index 7d4edace988..bbe8b978707 100644 --- a/tests/components/mqtt/test_binary_sensor.py +++ b/tests/components/mqtt/test_binary_sensor.py @@ -6,7 +6,7 @@ from unittest.mock import patch import pytest -from homeassistant.components import binary_sensor +from homeassistant.components import binary_sensor, mqtt from homeassistant.const import ( EVENT_STATE_CHANGED, STATE_OFF, @@ -50,20 +50,25 @@ from .test_common import ( ) from tests.common import ( - assert_setup_component, async_fire_mqtt_message, async_fire_time_changed, mock_restore_cache, ) DEFAULT_CONFIG = { - binary_sensor.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "test-topic", + mqtt.DOMAIN: { + binary_sensor.DOMAIN: { + "name": "test", + "state_topic": "test-topic", + } } } +# Test deprecated YAML configuration under the platform key +# Scheduled to be removed in HA core 2022.12 +DEFAULT_CONFIG_LEGACY = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) +DEFAULT_CONFIG_LEGACY[binary_sensor.DOMAIN]["platform"] = mqtt.DOMAIN + @pytest.fixture(autouse=True) def binary_sensor_platform_only(): @@ -78,15 +83,16 @@ async def test_setting_sensor_value_expires_availability_topic( """Test the expiration of the value.""" assert await async_setup_component( hass, - binary_sensor.DOMAIN, + mqtt.DOMAIN, { - binary_sensor.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "test-topic", - "expire_after": 4, - "force_update": True, - "availability_topic": "availability-topic", + mqtt.DOMAIN: { + binary_sensor.DOMAIN: { + "name": "test", + "state_topic": "test-topic", + "expire_after": 4, + "force_update": True, + "availability_topic": "availability-topic", + } } }, ) @@ -270,14 +276,15 @@ async def test_setting_sensor_value_via_mqtt_message( """Test the setting of the value via MQTT.""" assert await async_setup_component( hass, - binary_sensor.DOMAIN, + mqtt.DOMAIN, { - binary_sensor.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "test-topic", - "payload_on": "ON", - "payload_off": "OFF", + mqtt.DOMAIN: { + binary_sensor.DOMAIN: { + "name": "test", + "state_topic": "test-topic", + "payload_on": "ON", + "payload_off": "OFF", + } } }, ) @@ -307,14 +314,15 @@ async def test_invalid_sensor_value_via_mqtt_message( """Test the setting of the value via MQTT.""" assert await async_setup_component( hass, - binary_sensor.DOMAIN, + mqtt.DOMAIN, { - binary_sensor.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "test-topic", - "payload_on": "ON", - "payload_off": "OFF", + mqtt.DOMAIN: { + binary_sensor.DOMAIN: { + "name": "test", + "state_topic": "test-topic", + "payload_on": "ON", + "payload_off": "OFF", + } } }, ) @@ -348,16 +356,17 @@ async def test_setting_sensor_value_via_mqtt_message_and_template( """Test the setting of the value via MQTT.""" assert await async_setup_component( hass, - binary_sensor.DOMAIN, + mqtt.DOMAIN, { - binary_sensor.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "test-topic", - "payload_on": "ON", - "payload_off": "OFF", - "value_template": '{%if is_state(entity_id,"on")-%}OFF' - "{%-else-%}ON{%-endif%}", + mqtt.DOMAIN: { + binary_sensor.DOMAIN: { + "name": "test", + "state_topic": "test-topic", + "payload_on": "ON", + "payload_off": "OFF", + "value_template": '{%if is_state(entity_id,"on")-%}OFF' + "{%-else-%}ON{%-endif%}", + } } }, ) @@ -382,15 +391,16 @@ async def test_setting_sensor_value_via_mqtt_message_and_template2( """Test the setting of the value via MQTT.""" assert await async_setup_component( hass, - binary_sensor.DOMAIN, + mqtt.DOMAIN, { - binary_sensor.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "test-topic", - "payload_on": "ON", - "payload_off": "OFF", - "value_template": "{{value | upper}}", + mqtt.DOMAIN: { + binary_sensor.DOMAIN: { + "name": "test", + "state_topic": "test-topic", + "payload_on": "ON", + "payload_off": "OFF", + "value_template": "{{value | upper}}", + } } }, ) @@ -420,16 +430,17 @@ async def test_setting_sensor_value_via_mqtt_message_and_template_and_raw_state_ """Test processing a raw value via MQTT.""" assert await async_setup_component( hass, - binary_sensor.DOMAIN, + mqtt.DOMAIN, { - binary_sensor.DOMAIN: { - "platform": "mqtt", - "name": "test", - "encoding": "", - "state_topic": "test-topic", - "payload_on": "ON", - "payload_off": "OFF", - "value_template": "{%if value|unpack('b')-%}ON{%else%}OFF{%-endif-%}", + mqtt.DOMAIN: { + binary_sensor.DOMAIN: { + "name": "test", + "encoding": "", + "state_topic": "test-topic", + "payload_on": "ON", + "payload_off": "OFF", + "value_template": "{%if value|unpack('b')-%}ON{%else%}OFF{%-endif-%}", + } } }, ) @@ -454,15 +465,16 @@ async def test_setting_sensor_value_via_mqtt_message_empty_template( """Test the setting of the value via MQTT.""" assert await async_setup_component( hass, - binary_sensor.DOMAIN, + mqtt.DOMAIN, { - binary_sensor.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "test-topic", - "payload_on": "ON", - "payload_off": "OFF", - "value_template": '{%if value == "ABC"%}ON{%endif%}', + mqtt.DOMAIN: { + binary_sensor.DOMAIN: { + "name": "test", + "state_topic": "test-topic", + "payload_on": "ON", + "payload_off": "OFF", + "value_template": '{%if value == "ABC"%}ON{%endif%}', + } } }, ) @@ -486,13 +498,14 @@ async def test_valid_device_class(hass, mqtt_mock_entry_with_yaml_config): """Test the setting of a valid sensor class.""" assert await async_setup_component( hass, - binary_sensor.DOMAIN, + mqtt.DOMAIN, { - binary_sensor.DOMAIN: { - "platform": "mqtt", - "name": "test", - "device_class": "motion", - "state_topic": "test-topic", + mqtt.DOMAIN: { + binary_sensor.DOMAIN: { + "name": "test", + "device_class": "motion", + "state_topic": "test-topic", + } } }, ) @@ -503,25 +516,22 @@ async def test_valid_device_class(hass, mqtt_mock_entry_with_yaml_config): assert state.attributes.get("device_class") == "motion" -async def test_invalid_device_class(hass, mqtt_mock_entry_no_yaml_config): +async def test_invalid_device_class(hass, caplog): """Test the setting of an invalid sensor class.""" - assert await async_setup_component( + assert not await async_setup_component( hass, - binary_sensor.DOMAIN, + mqtt.DOMAIN, { - binary_sensor.DOMAIN: { - "platform": "mqtt", - "name": "test", - "device_class": "abc123", - "state_topic": "test-topic", + mqtt.DOMAIN: { + binary_sensor.DOMAIN: { + "name": "test", + "device_class": "abc123", + "state_topic": "test-topic", + } } }, ) - await hass.async_block_till_done() - await mqtt_mock_entry_no_yaml_config() - - state = hass.states.get("binary_sensor.test") - assert state is None + assert "Invalid config for [mqtt]: expected BinarySensorDeviceClass" in caplog.text async def test_availability_when_connection_lost( @@ -529,28 +539,40 @@ async def test_availability_when_connection_lost( ): """Test availability after MQTT disconnection.""" await help_test_availability_when_connection_lost( - hass, mqtt_mock_entry_with_yaml_config, binary_sensor.DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_with_yaml_config, + binary_sensor.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) async def test_availability_without_topic(hass, mqtt_mock_entry_with_yaml_config): """Test availability without defined availability topic.""" await help_test_availability_without_topic( - hass, mqtt_mock_entry_with_yaml_config, binary_sensor.DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_with_yaml_config, + binary_sensor.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) async def test_default_availability_payload(hass, mqtt_mock_entry_with_yaml_config): """Test availability by default payload with defined topic.""" await help_test_default_availability_payload( - hass, mqtt_mock_entry_with_yaml_config, binary_sensor.DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_with_yaml_config, + binary_sensor.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) async def test_custom_availability_payload(hass, mqtt_mock_entry_with_yaml_config): """Test availability by custom payload with defined topic.""" await help_test_custom_availability_payload( - hass, mqtt_mock_entry_with_yaml_config, binary_sensor.DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_with_yaml_config, + binary_sensor.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) @@ -558,14 +580,15 @@ async def test_force_update_disabled(hass, mqtt_mock_entry_with_yaml_config): """Test force update option.""" assert await async_setup_component( hass, - binary_sensor.DOMAIN, + mqtt.DOMAIN, { - binary_sensor.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "test-topic", - "payload_on": "ON", - "payload_off": "OFF", + mqtt.DOMAIN: { + binary_sensor.DOMAIN: { + "name": "test", + "state_topic": "test-topic", + "payload_on": "ON", + "payload_off": "OFF", + } } }, ) @@ -594,15 +617,16 @@ async def test_force_update_enabled(hass, mqtt_mock_entry_with_yaml_config): """Test force update option.""" assert await async_setup_component( hass, - binary_sensor.DOMAIN, + mqtt.DOMAIN, { - binary_sensor.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "test-topic", - "payload_on": "ON", - "payload_off": "OFF", - "force_update": True, + mqtt.DOMAIN: { + binary_sensor.DOMAIN: { + "name": "test", + "state_topic": "test-topic", + "payload_on": "ON", + "payload_off": "OFF", + "force_update": True, + } } }, ) @@ -631,16 +655,17 @@ async def test_off_delay(hass, mqtt_mock_entry_with_yaml_config): """Test off_delay option.""" assert await async_setup_component( hass, - binary_sensor.DOMAIN, + mqtt.DOMAIN, { - binary_sensor.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "test-topic", - "payload_on": "ON", - "payload_off": "OFF", - "off_delay": 30, - "force_update": True, + mqtt.DOMAIN: { + binary_sensor.DOMAIN: { + "name": "test", + "state_topic": "test-topic", + "payload_on": "ON", + "payload_off": "OFF", + "off_delay": 30, + "force_update": True, + } } }, ) @@ -680,14 +705,20 @@ async def test_setting_attribute_via_mqtt_json_message( ): """Test the setting of attribute via MQTT with JSON payload.""" await help_test_setting_attribute_via_mqtt_json_message( - hass, mqtt_mock_entry_with_yaml_config, binary_sensor.DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_with_yaml_config, + binary_sensor.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) async def test_setting_attribute_with_template(hass, mqtt_mock_entry_with_yaml_config): """Test the setting of attribute via MQTT with JSON payload.""" await help_test_setting_attribute_with_template( - hass, mqtt_mock_entry_with_yaml_config, binary_sensor.DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_with_yaml_config, + binary_sensor.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) @@ -700,7 +731,7 @@ async def test_update_with_json_attrs_not_dict( mqtt_mock_entry_with_yaml_config, caplog, binary_sensor.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, ) @@ -713,7 +744,7 @@ async def test_update_with_json_attrs_bad_JSON( mqtt_mock_entry_with_yaml_config, caplog, binary_sensor.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, ) @@ -724,7 +755,7 @@ async def test_discovery_update_attr(hass, mqtt_mock_entry_no_yaml_config, caplo mqtt_mock_entry_no_yaml_config, caplog, binary_sensor.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, ) @@ -755,7 +786,7 @@ async def test_discovery_removal_binary_sensor( hass, mqtt_mock_entry_no_yaml_config, caplog ): """Test removal of discovered binary_sensor.""" - data = json.dumps(DEFAULT_CONFIG[binary_sensor.DOMAIN]) + data = json.dumps(DEFAULT_CONFIG_LEGACY[binary_sensor.DOMAIN]) await help_test_discovery_removal( hass, mqtt_mock_entry_no_yaml_config, caplog, binary_sensor.DOMAIN, data ) @@ -765,8 +796,8 @@ async def test_discovery_update_binary_sensor_topic_template( hass, mqtt_mock_entry_no_yaml_config, caplog ): """Test update of discovered binary_sensor.""" - config1 = copy.deepcopy(DEFAULT_CONFIG[binary_sensor.DOMAIN]) - config2 = copy.deepcopy(DEFAULT_CONFIG[binary_sensor.DOMAIN]) + config1 = copy.deepcopy(DEFAULT_CONFIG_LEGACY[binary_sensor.DOMAIN]) + config2 = copy.deepcopy(DEFAULT_CONFIG_LEGACY[binary_sensor.DOMAIN]) config1["name"] = "Beer" config2["name"] = "Milk" config1["state_topic"] = "sensor/state1" @@ -802,8 +833,8 @@ async def test_discovery_update_binary_sensor_template( hass, mqtt_mock_entry_no_yaml_config, caplog ): """Test update of discovered binary_sensor.""" - config1 = copy.deepcopy(DEFAULT_CONFIG[binary_sensor.DOMAIN]) - config2 = copy.deepcopy(DEFAULT_CONFIG[binary_sensor.DOMAIN]) + config1 = copy.deepcopy(DEFAULT_CONFIG_LEGACY[binary_sensor.DOMAIN]) + config2 = copy.deepcopy(DEFAULT_CONFIG_LEGACY[binary_sensor.DOMAIN]) config1["name"] = "Beer" config2["name"] = "Milk" config1["state_topic"] = "sensor/state1" @@ -861,7 +892,7 @@ async def test_encoding_subscribable_topics( mqtt_mock_entry_with_yaml_config, caplog, binary_sensor.DOMAIN, - DEFAULT_CONFIG[binary_sensor.DOMAIN], + DEFAULT_CONFIG_LEGACY[binary_sensor.DOMAIN], topic, value, attribute, @@ -873,7 +904,7 @@ async def test_discovery_update_unchanged_binary_sensor( hass, mqtt_mock_entry_no_yaml_config, caplog ): """Test update of discovered binary_sensor.""" - config1 = copy.deepcopy(DEFAULT_CONFIG[binary_sensor.DOMAIN]) + config1 = copy.deepcopy(DEFAULT_CONFIG_LEGACY[binary_sensor.DOMAIN]) config1["name"] = "Beer" data1 = json.dumps(config1) @@ -908,42 +939,60 @@ async def test_discovery_broken(hass, mqtt_mock_entry_no_yaml_config, caplog): async def test_entity_device_info_with_connection(hass, mqtt_mock_entry_no_yaml_config): """Test MQTT binary sensor device registry integration.""" await help_test_entity_device_info_with_connection( - hass, mqtt_mock_entry_no_yaml_config, binary_sensor.DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_no_yaml_config, + binary_sensor.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) async def test_entity_device_info_with_identifier(hass, mqtt_mock_entry_no_yaml_config): """Test MQTT binary sensor device registry integration.""" await help_test_entity_device_info_with_identifier( - hass, mqtt_mock_entry_no_yaml_config, binary_sensor.DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_no_yaml_config, + binary_sensor.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) async def test_entity_device_info_update(hass, mqtt_mock_entry_no_yaml_config): """Test device registry update.""" await help_test_entity_device_info_update( - hass, mqtt_mock_entry_no_yaml_config, binary_sensor.DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_no_yaml_config, + binary_sensor.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) async def test_entity_device_info_remove(hass, mqtt_mock_entry_no_yaml_config): """Test device registry remove.""" await help_test_entity_device_info_remove( - hass, mqtt_mock_entry_no_yaml_config, binary_sensor.DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_no_yaml_config, + binary_sensor.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) async def test_entity_id_update_subscriptions(hass, mqtt_mock_entry_with_yaml_config): """Test MQTT subscriptions are managed when entity_id is updated.""" await help_test_entity_id_update_subscriptions( - hass, mqtt_mock_entry_with_yaml_config, binary_sensor.DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_with_yaml_config, + binary_sensor.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) async def test_entity_id_update_discovery_update(hass, mqtt_mock_entry_no_yaml_config): """Test MQTT discovery update when entity_id is updated.""" await help_test_entity_id_update_discovery_update( - hass, mqtt_mock_entry_no_yaml_config, binary_sensor.DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_no_yaml_config, + binary_sensor.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) @@ -953,7 +1002,7 @@ async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config): hass, mqtt_mock_entry_no_yaml_config, binary_sensor.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, None, ) @@ -961,7 +1010,7 @@ async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config): async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path): """Test reloading the MQTT platform.""" domain = binary_sensor.DOMAIN - config = DEFAULT_CONFIG[domain] + config = DEFAULT_CONFIG_LEGACY[domain] await help_test_reloadable( hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config ) @@ -970,7 +1019,7 @@ async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_pa async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path): """Test reloading the MQTT platform with late entry setup.""" domain = binary_sensor.DOMAIN - config = DEFAULT_CONFIG[domain] + config = DEFAULT_CONFIG_LEGACY[domain] await help_test_reloadable_late(hass, caplog, tmp_path, domain, config) @@ -991,11 +1040,11 @@ async def test_cleanup_triggers_and_restoring_state( ): """Test cleanup old triggers at reloading and restoring the state.""" domain = binary_sensor.DOMAIN - config1 = copy.deepcopy(DEFAULT_CONFIG[domain]) + config1 = copy.deepcopy(DEFAULT_CONFIG_LEGACY[domain]) config1["name"] = "test1" config1["expire_after"] = 30 config1["state_topic"] = "test-topic1" - config2 = copy.deepcopy(DEFAULT_CONFIG[domain]) + config2 = copy.deepcopy(DEFAULT_CONFIG_LEGACY[domain]) config2["name"] = "test2" config2["expire_after"] = 5 config2["state_topic"] = "test-topic2" @@ -1053,7 +1102,7 @@ async def test_skip_restoring_state_with_over_due_expire_trigger( freezer.move_to("2022-02-02 12:02:00+01:00") domain = binary_sensor.DOMAIN - config3 = copy.deepcopy(DEFAULT_CONFIG[domain]) + config3 = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][domain]) config3["name"] = "test3" config3["expire_after"] = 10 config3["state_topic"] = "test-topic3" @@ -1065,17 +1114,18 @@ async def test_skip_restoring_state_with_over_due_expire_trigger( ) mock_restore_cache(hass, (fake_state,)) - with assert_setup_component(1, domain): - assert await async_setup_component(hass, domain, {domain: config3}) - await hass.async_block_till_done() - await mqtt_mock_entry_with_yaml_config() + assert await async_setup_component( + hass, mqtt.DOMAIN, {mqtt.DOMAIN: {domain: config3}} + ) + await hass.async_block_till_done() + await mqtt_mock_entry_with_yaml_config() assert "Skip state recovery after reload for binary_sensor.test3" in caplog.text async def test_setup_manual_entity_from_yaml(hass): """Test setup manual configured MQTT entity.""" platform = binary_sensor.DOMAIN - config = copy.deepcopy(DEFAULT_CONFIG[platform]) + config = copy.deepcopy(DEFAULT_CONFIG_LEGACY[platform]) config["name"] = "test" del config["platform"] await help_test_setup_manual_entity_from_yaml(hass, platform, config) @@ -1085,7 +1135,20 @@ async def test_setup_manual_entity_from_yaml(hass): async def test_unload_entry(hass, mqtt_mock_entry_with_yaml_config, tmp_path): """Test unloading the config entry.""" domain = binary_sensor.DOMAIN - config = DEFAULT_CONFIG[domain] + config = DEFAULT_CONFIG_LEGACY[domain] await help_test_unload_config_entry_with_platform( hass, mqtt_mock_entry_with_yaml_config, tmp_path, domain, config ) + + +# Test deprecated YAML configuration under the platform key +# Scheduled to be removed in HA core 2022.12 +async def test_setup_with_legacy_schema(hass, mqtt_mock_entry_with_yaml_config): + """Test a setup with deprecated yaml platform schema.""" + domain = binary_sensor.DOMAIN + config = copy.deepcopy(DEFAULT_CONFIG_LEGACY[domain]) + config["name"] = "test" + assert await async_setup_component(hass, domain, {domain: config}) + await hass.async_block_till_done() + await mqtt_mock_entry_with_yaml_config() + assert hass.states.get(f"{domain}.test") is not None diff --git a/tests/components/mqtt/test_button.py b/tests/components/mqtt/test_button.py index 68db846c91c..1274c700800 100644 --- a/tests/components/mqtt/test_button.py +++ b/tests/components/mqtt/test_button.py @@ -4,7 +4,7 @@ from unittest.mock import patch import pytest -from homeassistant.components import button +from homeassistant.components import button, mqtt from homeassistant.const import ( ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME, @@ -43,9 +43,14 @@ from .test_common import ( ) DEFAULT_CONFIG = { - button.DOMAIN: {"platform": "mqtt", "name": "test", "command_topic": "test-topic"} + mqtt.DOMAIN: {button.DOMAIN: {"name": "test", "command_topic": "test-topic"}} } +# Test deprecated YAML configuration under the platform key +# Scheduled to be removed in HA core 2022.12 +DEFAULT_CONFIG_LEGACY = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) +DEFAULT_CONFIG_LEGACY[button.DOMAIN]["platform"] = mqtt.DOMAIN + @pytest.fixture(autouse=True) def button_platform_only(): @@ -59,15 +64,16 @@ async def test_sending_mqtt_commands(hass, mqtt_mock_entry_with_yaml_config): """Test the sending MQTT commands.""" assert await async_setup_component( hass, - button.DOMAIN, + mqtt.DOMAIN, { - button.DOMAIN: { - "command_topic": "command-topic", - "name": "test", - "object_id": "test_button", - "payload_press": "beer press", - "platform": "mqtt", - "qos": "2", + mqtt.DOMAIN: { + button.DOMAIN: { + "command_topic": "command-topic", + "name": "test", + "object_id": "test_button", + "payload_press": "beer press", + "qos": "2", + } } }, ) @@ -97,14 +103,15 @@ async def test_command_template(hass, mqtt_mock_entry_with_yaml_config): """Test the sending of MQTT commands through a command template.""" assert await async_setup_component( hass, - button.DOMAIN, + mqtt.DOMAIN, { - button.DOMAIN: { - "command_topic": "command-topic", - "command_template": '{ "{{ value }}": "{{ entity_id }}" }', - "name": "test", - "payload_press": "milky_way_press", - "platform": "mqtt", + mqtt.DOMAIN: { + button.DOMAIN: { + "command_topic": "command-topic", + "command_template": '{ "{{ value }}": "{{ entity_id }}" }', + "name": "test", + "payload_press": "milky_way_press", + } } }, ) @@ -133,14 +140,14 @@ async def test_availability_when_connection_lost( ): """Test availability after MQTT disconnection.""" await help_test_availability_when_connection_lost( - hass, mqtt_mock_entry_with_yaml_config, button.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, button.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_availability_without_topic(hass, mqtt_mock_entry_with_yaml_config): """Test availability without defined availability topic.""" await help_test_availability_without_topic( - hass, mqtt_mock_entry_with_yaml_config, button.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, button.DOMAIN, DEFAULT_CONFIG_LEGACY ) @@ -193,7 +200,7 @@ async def test_setting_attribute_via_mqtt_json_message( ): """Test the setting of attribute via MQTT with JSON payload.""" await help_test_setting_attribute_via_mqtt_json_message( - hass, mqtt_mock_entry_with_yaml_config, button.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, button.DOMAIN, DEFAULT_CONFIG_LEGACY ) @@ -202,14 +209,14 @@ async def test_setting_blocked_attribute_via_mqtt_json_message( ): """Test the setting of attribute via MQTT with JSON payload.""" await help_test_setting_blocked_attribute_via_mqtt_json_message( - hass, mqtt_mock_entry_no_yaml_config, button.DOMAIN, DEFAULT_CONFIG, None + hass, mqtt_mock_entry_no_yaml_config, button.DOMAIN, DEFAULT_CONFIG_LEGACY, None ) async def test_setting_attribute_with_template(hass, mqtt_mock_entry_with_yaml_config): """Test the setting of attribute via MQTT with JSON payload.""" await help_test_setting_attribute_with_template( - hass, mqtt_mock_entry_with_yaml_config, button.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, button.DOMAIN, DEFAULT_CONFIG_LEGACY ) @@ -218,7 +225,11 @@ async def test_update_with_json_attrs_not_dict( ): """Test attributes get extracted from a JSON result.""" await help_test_update_with_json_attrs_not_dict( - hass, mqtt_mock_entry_with_yaml_config, caplog, button.DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_with_yaml_config, + caplog, + button.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) @@ -227,14 +238,22 @@ async def test_update_with_json_attrs_bad_JSON( ): """Test attributes get extracted from a JSON result.""" await help_test_update_with_json_attrs_bad_JSON( - hass, mqtt_mock_entry_with_yaml_config, caplog, button.DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_with_yaml_config, + caplog, + button.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) async def test_discovery_update_attr(hass, mqtt_mock_entry_no_yaml_config, caplog): """Test update of discovered MQTTAttributes.""" await help_test_discovery_update_attr( - hass, mqtt_mock_entry_no_yaml_config, caplog, button.DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_no_yaml_config, + caplog, + button.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) @@ -271,8 +290,8 @@ async def test_discovery_removal_button(hass, mqtt_mock_entry_no_yaml_config, ca async def test_discovery_update_button(hass, mqtt_mock_entry_no_yaml_config, caplog): """Test update of discovered button.""" - config1 = copy.deepcopy(DEFAULT_CONFIG[button.DOMAIN]) - config2 = copy.deepcopy(DEFAULT_CONFIG[button.DOMAIN]) + config1 = copy.deepcopy(DEFAULT_CONFIG_LEGACY[button.DOMAIN]) + config2 = copy.deepcopy(DEFAULT_CONFIG_LEGACY[button.DOMAIN]) config1["name"] = "Beer" config2["name"] = "Milk" @@ -321,35 +340,35 @@ async def test_discovery_broken(hass, mqtt_mock_entry_no_yaml_config, caplog): async def test_entity_device_info_with_connection(hass, mqtt_mock_entry_no_yaml_config): """Test MQTT button device registry integration.""" await help_test_entity_device_info_with_connection( - hass, mqtt_mock_entry_no_yaml_config, button.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, button.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_entity_device_info_with_identifier(hass, mqtt_mock_entry_no_yaml_config): """Test MQTT button device registry integration.""" await help_test_entity_device_info_with_identifier( - hass, mqtt_mock_entry_no_yaml_config, button.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, button.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_entity_device_info_update(hass, mqtt_mock_entry_no_yaml_config): """Test device registry update.""" await help_test_entity_device_info_update( - hass, mqtt_mock_entry_no_yaml_config, button.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, button.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_entity_device_info_remove(hass, mqtt_mock_entry_no_yaml_config): """Test device registry remove.""" await help_test_entity_device_info_remove( - hass, mqtt_mock_entry_no_yaml_config, button.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, button.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_entity_id_update_discovery_update(hass, mqtt_mock_entry_no_yaml_config): """Test MQTT discovery update when entity_id is updated.""" await help_test_entity_id_update_discovery_update( - hass, mqtt_mock_entry_no_yaml_config, button.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, button.DOMAIN, DEFAULT_CONFIG_LEGACY ) @@ -359,59 +378,54 @@ async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config): hass, mqtt_mock_entry_no_yaml_config, button.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, button.SERVICE_PRESS, command_payload="PRESS", state_topic=None, ) -async def test_invalid_device_class(hass, mqtt_mock_entry_no_yaml_config): +async def test_invalid_device_class(hass): """Test device_class option with invalid value.""" - assert await async_setup_component( + assert not await async_setup_component( hass, - button.DOMAIN, + mqtt.DOMAIN, { - button.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "test-topic", - "device_class": "foobarnotreal", + mqtt.DOMAIN: { + button.DOMAIN: { + "name": "test", + "state_topic": "test-topic", + "device_class": "foobarnotreal", + } } }, ) - await hass.async_block_till_done() - await mqtt_mock_entry_no_yaml_config() - - state = hass.states.get("button.test") - assert state is None async def test_valid_device_class(hass, mqtt_mock_entry_with_yaml_config): """Test device_class option with valid values.""" assert await async_setup_component( hass, - button.DOMAIN, + mqtt.DOMAIN, { - button.DOMAIN: [ - { - "platform": "mqtt", - "name": "Test 1", - "command_topic": "test-topic", - "device_class": "update", - }, - { - "platform": "mqtt", - "name": "Test 2", - "command_topic": "test-topic", - "device_class": "restart", - }, - { - "platform": "mqtt", - "name": "Test 3", - "command_topic": "test-topic", - }, - ] + mqtt.DOMAIN: { + button.DOMAIN: [ + { + "name": "Test 1", + "command_topic": "test-topic", + "device_class": "update", + }, + { + "name": "Test 2", + "command_topic": "test-topic", + "device_class": "restart", + }, + { + "name": "Test 3", + "command_topic": "test-topic", + }, + ] + } }, ) await hass.async_block_till_done() @@ -443,7 +457,7 @@ async def test_publishing_with_custom_encoding( ): """Test publishing MQTT payload with different encoding.""" domain = button.DOMAIN - config = DEFAULT_CONFIG[domain] + config = DEFAULT_CONFIG_LEGACY[domain] await help_test_publishing_with_custom_encoding( hass, @@ -462,7 +476,7 @@ async def test_publishing_with_custom_encoding( async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path): """Test reloading the MQTT platform.""" domain = button.DOMAIN - config = DEFAULT_CONFIG[domain] + config = DEFAULT_CONFIG_LEGACY[domain] await help_test_reloadable( hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config ) @@ -471,14 +485,14 @@ async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_pa async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path): """Test reloading the MQTT platform with late entry setup.""" domain = button.DOMAIN - config = DEFAULT_CONFIG[domain] + config = DEFAULT_CONFIG_LEGACY[domain] await help_test_reloadable_late(hass, caplog, tmp_path, domain, config) async def test_setup_manual_entity_from_yaml(hass): """Test setup manual configured MQTT entity.""" platform = button.DOMAIN - config = copy.deepcopy(DEFAULT_CONFIG[platform]) + config = copy.deepcopy(DEFAULT_CONFIG_LEGACY[platform]) config["name"] = "test" del config["platform"] await help_test_setup_manual_entity_from_yaml(hass, platform, config) @@ -488,7 +502,20 @@ async def test_setup_manual_entity_from_yaml(hass): async def test_unload_entry(hass, mqtt_mock_entry_with_yaml_config, tmp_path): """Test unloading the config entry.""" domain = button.DOMAIN - config = DEFAULT_CONFIG[domain] + config = DEFAULT_CONFIG_LEGACY[domain] await help_test_unload_config_entry_with_platform( hass, mqtt_mock_entry_with_yaml_config, tmp_path, domain, config ) + + +# Test deprecated YAML configuration under the platform key +# Scheduled to be removed in HA core 2022.12 +async def test_setup_with_legacy_schema(hass, mqtt_mock_entry_with_yaml_config): + """Test a setup with deprecated yaml platform schema.""" + domain = button.DOMAIN + config = copy.deepcopy(DEFAULT_CONFIG_LEGACY[domain]) + config["name"] = "test" + assert await async_setup_component(hass, domain, {domain: config}) + await hass.async_block_till_done() + await mqtt_mock_entry_with_yaml_config() + assert hass.states.get(f"{domain}.test") is not None diff --git a/tests/components/mqtt/test_camera.py b/tests/components/mqtt/test_camera.py index a76025a608a..4d0b2fbfca0 100644 --- a/tests/components/mqtt/test_camera.py +++ b/tests/components/mqtt/test_camera.py @@ -7,7 +7,7 @@ from unittest.mock import patch import pytest -from homeassistant.components import camera +from homeassistant.components import camera, mqtt from homeassistant.components.mqtt.camera import MQTT_CAMERA_ATTRIBUTES_BLOCKED from homeassistant.const import Platform from homeassistant.setup import async_setup_component @@ -43,9 +43,12 @@ from .test_common import ( from tests.common import async_fire_mqtt_message -DEFAULT_CONFIG = { - camera.DOMAIN: {"platform": "mqtt", "name": "test", "topic": "test_topic"} -} +DEFAULT_CONFIG = {mqtt.DOMAIN: {camera.DOMAIN: {"name": "test", "topic": "test_topic"}}} + +# Test deprecated YAML configuration under the platform key +# Scheduled to be removed in HA core 2022.12 +DEFAULT_CONFIG_LEGACY = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) +DEFAULT_CONFIG_LEGACY[camera.DOMAIN]["platform"] = mqtt.DOMAIN @pytest.fixture(autouse=True) @@ -62,8 +65,8 @@ async def test_run_camera_setup( topic = "test/camera" await async_setup_component( hass, - "camera", - {"camera": {"platform": "mqtt", "topic": topic, "name": "Test Camera"}}, + mqtt.DOMAIN, + {mqtt.DOMAIN: {camera.DOMAIN: {"topic": topic, "name": "Test Camera"}}}, ) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -86,13 +89,14 @@ async def test_run_camera_b64_encoded( topic = "test/camera" await async_setup_component( hass, - "camera", + mqtt.DOMAIN, { - "camera": { - "platform": "mqtt", - "topic": topic, - "name": "Test Camera", - "encoding": "b64", + mqtt.DOMAIN: { + camera.DOMAIN: { + "topic": topic, + "name": "Test Camera", + "encoding": "b64", + } } }, ) @@ -110,7 +114,7 @@ async def test_run_camera_b64_encoded( assert body == "grass" -# Using CONF_ENCODING to set b64 encoding for images is deprecated Home Assistant 2022.9, use CONF_IMAGE_ENCODING instead +# Using CONF_ENCODING to set b64 encoding for images is deprecated in Home Assistant 2022.9, use CONF_IMAGE_ENCODING instead async def test_legacy_camera_b64_encoded_with_availability( hass, hass_client_no_auth, mqtt_mock_entry_with_yaml_config ): @@ -119,14 +123,15 @@ async def test_legacy_camera_b64_encoded_with_availability( topic_availability = "test/camera_availability" await async_setup_component( hass, - "camera", + mqtt.DOMAIN, { - "camera": { - "platform": "mqtt", - "topic": topic, - "name": "Test Camera", - "encoding": "b64", - "availability": {"topic": topic_availability}, + mqtt.DOMAIN: { + camera.DOMAIN: { + "topic": topic, + "name": "Test Camera", + "encoding": "b64", + "availability": {"topic": topic_availability}, + } } }, ) @@ -155,15 +160,16 @@ async def test_camera_b64_encoded_with_availability( topic_availability = "test/camera_availability" await async_setup_component( hass, - "camera", + mqtt.DOMAIN, { - "camera": { - "platform": "mqtt", - "topic": topic, - "name": "Test Camera", - "encoding": "utf-8", - "image_encoding": "b64", - "availability": {"topic": topic_availability}, + mqtt.DOMAIN: { + "camera": { + "topic": topic, + "name": "Test Camera", + "encoding": "utf-8", + "image_encoding": "b64", + "availability": {"topic": topic_availability}, + } } }, ) @@ -189,28 +195,28 @@ async def test_availability_when_connection_lost( ): """Test availability after MQTT disconnection.""" await help_test_availability_when_connection_lost( - hass, mqtt_mock_entry_with_yaml_config, camera.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, camera.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_availability_without_topic(hass, mqtt_mock_entry_with_yaml_config): """Test availability without defined availability topic.""" await help_test_availability_without_topic( - hass, mqtt_mock_entry_with_yaml_config, camera.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, camera.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_default_availability_payload(hass, mqtt_mock_entry_with_yaml_config): """Test availability by default payload with defined topic.""" await help_test_default_availability_payload( - hass, mqtt_mock_entry_with_yaml_config, camera.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, camera.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_custom_availability_payload(hass, mqtt_mock_entry_with_yaml_config): """Test availability by custom payload with defined topic.""" await help_test_custom_availability_payload( - hass, mqtt_mock_entry_with_yaml_config, camera.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, camera.DOMAIN, DEFAULT_CONFIG_LEGACY ) @@ -219,7 +225,7 @@ async def test_setting_attribute_via_mqtt_json_message( ): """Test the setting of attribute via MQTT with JSON payload.""" await help_test_setting_attribute_via_mqtt_json_message( - hass, mqtt_mock_entry_with_yaml_config, camera.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, camera.DOMAIN, DEFAULT_CONFIG_LEGACY ) @@ -231,7 +237,7 @@ async def test_setting_blocked_attribute_via_mqtt_json_message( hass, mqtt_mock_entry_no_yaml_config, camera.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, MQTT_CAMERA_ATTRIBUTES_BLOCKED, ) @@ -239,7 +245,7 @@ async def test_setting_blocked_attribute_via_mqtt_json_message( async def test_setting_attribute_with_template(hass, mqtt_mock_entry_with_yaml_config): """Test the setting of attribute via MQTT with JSON payload.""" await help_test_setting_attribute_with_template( - hass, mqtt_mock_entry_with_yaml_config, camera.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, camera.DOMAIN, DEFAULT_CONFIG_LEGACY ) @@ -248,7 +254,11 @@ async def test_update_with_json_attrs_not_dict( ): """Test attributes get extracted from a JSON result.""" await help_test_update_with_json_attrs_not_dict( - hass, mqtt_mock_entry_with_yaml_config, caplog, camera.DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_with_yaml_config, + caplog, + camera.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) @@ -257,14 +267,22 @@ async def test_update_with_json_attrs_bad_JSON( ): """Test attributes get extracted from a JSON result.""" await help_test_update_with_json_attrs_bad_JSON( - hass, mqtt_mock_entry_with_yaml_config, caplog, camera.DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_with_yaml_config, + caplog, + camera.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) async def test_discovery_update_attr(hass, mqtt_mock_entry_no_yaml_config, caplog): """Test update of discovered MQTTAttributes.""" await help_test_discovery_update_attr( - hass, mqtt_mock_entry_no_yaml_config, caplog, camera.DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_no_yaml_config, + caplog, + camera.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) @@ -293,7 +311,7 @@ async def test_unique_id(hass, mqtt_mock_entry_with_yaml_config): async def test_discovery_removal_camera(hass, mqtt_mock_entry_no_yaml_config, caplog): """Test removal of discovered camera.""" - data = json.dumps(DEFAULT_CONFIG[camera.DOMAIN]) + data = json.dumps(DEFAULT_CONFIG_LEGACY[camera.DOMAIN]) await help_test_discovery_removal( hass, mqtt_mock_entry_no_yaml_config, caplog, camera.DOMAIN, data ) @@ -341,28 +359,28 @@ async def test_discovery_broken(hass, mqtt_mock_entry_no_yaml_config, caplog): async def test_entity_device_info_with_connection(hass, mqtt_mock_entry_no_yaml_config): """Test MQTT camera device registry integration.""" await help_test_entity_device_info_with_connection( - hass, mqtt_mock_entry_no_yaml_config, camera.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, camera.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_entity_device_info_with_identifier(hass, mqtt_mock_entry_no_yaml_config): """Test MQTT camera device registry integration.""" await help_test_entity_device_info_with_identifier( - hass, mqtt_mock_entry_no_yaml_config, camera.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, camera.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_entity_device_info_update(hass, mqtt_mock_entry_no_yaml_config): """Test device registry update.""" await help_test_entity_device_info_update( - hass, mqtt_mock_entry_no_yaml_config, camera.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, camera.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_entity_device_info_remove(hass, mqtt_mock_entry_no_yaml_config): """Test device registry remove.""" await help_test_entity_device_info_remove( - hass, mqtt_mock_entry_no_yaml_config, camera.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, camera.DOMAIN, DEFAULT_CONFIG_LEGACY ) @@ -372,7 +390,7 @@ async def test_entity_id_update_subscriptions(hass, mqtt_mock_entry_with_yaml_co hass, mqtt_mock_entry_with_yaml_config, camera.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, ["test_topic"], ) @@ -380,7 +398,7 @@ async def test_entity_id_update_subscriptions(hass, mqtt_mock_entry_with_yaml_co async def test_entity_id_update_discovery_update(hass, mqtt_mock_entry_no_yaml_config): """Test MQTT discovery update when entity_id is updated.""" await help_test_entity_id_update_discovery_update( - hass, mqtt_mock_entry_no_yaml_config, camera.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, camera.DOMAIN, DEFAULT_CONFIG_LEGACY ) @@ -390,7 +408,7 @@ async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config): hass, mqtt_mock_entry_no_yaml_config, camera.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, None, state_topic="test_topic", state_payload=b"ON", @@ -400,7 +418,7 @@ async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config): async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path): """Test reloading the MQTT platform.""" domain = camera.DOMAIN - config = DEFAULT_CONFIG[domain] + config = DEFAULT_CONFIG_LEGACY[domain] await help_test_reloadable( hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config ) @@ -409,14 +427,14 @@ async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_pa async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path): """Test reloading the MQTT platform with late entry setup.""" domain = camera.DOMAIN - config = DEFAULT_CONFIG[domain] + config = DEFAULT_CONFIG_LEGACY[domain] await help_test_reloadable_late(hass, caplog, tmp_path, domain, config) async def test_setup_manual_entity_from_yaml(hass): """Test setup manual configured MQTT entity.""" platform = camera.DOMAIN - config = copy.deepcopy(DEFAULT_CONFIG[platform]) + config = copy.deepcopy(DEFAULT_CONFIG_LEGACY[platform]) config["name"] = "test" del config["platform"] await help_test_setup_manual_entity_from_yaml(hass, platform, config) @@ -426,7 +444,20 @@ async def test_setup_manual_entity_from_yaml(hass): async def test_unload_entry(hass, mqtt_mock_entry_with_yaml_config, tmp_path): """Test unloading the config entry.""" domain = camera.DOMAIN - config = DEFAULT_CONFIG[domain] + config = DEFAULT_CONFIG_LEGACY[domain] await help_test_unload_config_entry_with_platform( hass, mqtt_mock_entry_with_yaml_config, tmp_path, domain, config ) + + +# Test deprecated YAML configuration under the platform key +# Scheduled to be removed in HA core 2022.12 +async def test_setup_with_legacy_schema(hass, mqtt_mock_entry_with_yaml_config): + """Test a setup with deprecated yaml platform schema.""" + domain = camera.DOMAIN + config = copy.deepcopy(DEFAULT_CONFIG_LEGACY[domain]) + config["name"] = "test" + assert await async_setup_component(hass, domain, {domain: config}) + await hass.async_block_till_done() + await mqtt_mock_entry_with_yaml_config() + assert hass.states.get(f"{domain}.test") is not None diff --git a/tests/components/mqtt/test_climate.py b/tests/components/mqtt/test_climate.py index d5164e85718..14bd9084abe 100644 --- a/tests/components/mqtt/test_climate.py +++ b/tests/components/mqtt/test_climate.py @@ -6,7 +6,7 @@ from unittest.mock import call, patch import pytest import voluptuous as vol -from homeassistant.components import climate +from homeassistant.components import climate, mqtt from homeassistant.components.climate import DEFAULT_MAX_TEMP, DEFAULT_MIN_TEMP from homeassistant.components.climate.const import ( ATTR_AUX_HEAT, @@ -16,10 +16,9 @@ from homeassistant.components.climate.const import ( ATTR_SWING_MODE, ATTR_TARGET_TEMP_HIGH, ATTR_TARGET_TEMP_LOW, - CURRENT_HVAC_ACTIONS, - DOMAIN as CLIMATE_DOMAIN, PRESET_ECO, ClimateEntityFeature, + HVACAction, HVACMode, ) from homeassistant.components.mqtt.climate import MQTT_CLIMATE_ATTRIBUTES_BLOCKED @@ -62,30 +61,37 @@ from tests.components.climate import common ENTITY_CLIMATE = "climate.test" + DEFAULT_CONFIG = { - CLIMATE_DOMAIN: { - "platform": "mqtt", - "name": "test", - "mode_command_topic": "mode-topic", - "temperature_command_topic": "temperature-topic", - "temperature_low_command_topic": "temperature-low-topic", - "temperature_high_command_topic": "temperature-high-topic", - "fan_mode_command_topic": "fan-mode-topic", - "swing_mode_command_topic": "swing-mode-topic", - "aux_command_topic": "aux-topic", - "preset_mode_command_topic": "preset-mode-topic", - "preset_modes": [ - "eco", - "away", - "boost", - "comfort", - "home", - "sleep", - "activity", - ], + mqtt.DOMAIN: { + climate.DOMAIN: { + "name": "test", + "mode_command_topic": "mode-topic", + "temperature_command_topic": "temperature-topic", + "temperature_low_command_topic": "temperature-low-topic", + "temperature_high_command_topic": "temperature-high-topic", + "fan_mode_command_topic": "fan-mode-topic", + "swing_mode_command_topic": "swing-mode-topic", + "aux_command_topic": "aux-topic", + "preset_mode_command_topic": "preset-mode-topic", + "preset_modes": [ + "eco", + "away", + "boost", + "comfort", + "home", + "sleep", + "activity", + ], + } } } +# Test deprecated YAML configuration under the platform key +# Scheduled to be removed in HA core 2022.12 +DEFAULT_CONFIG_LEGACY = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) +DEFAULT_CONFIG_LEGACY[climate.DOMAIN]["platform"] = mqtt.DOMAIN + @pytest.fixture(autouse=True) def climate_platform_only(): @@ -96,7 +102,7 @@ def climate_platform_only(): async def test_setup_params(hass, mqtt_mock_entry_with_yaml_config): """Test the initial parameters.""" - assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_CONFIG) + assert await async_setup_component(hass, mqtt.DOMAIN, DEFAULT_CONFIG) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -109,18 +115,14 @@ async def test_setup_params(hass, mqtt_mock_entry_with_yaml_config): assert state.attributes.get("max_temp") == DEFAULT_MAX_TEMP -async def test_preset_none_in_preset_modes( - hass, mqtt_mock_entry_no_yaml_config, caplog -): +async def test_preset_none_in_preset_modes(hass, caplog): """Test the preset mode payload reset configuration.""" - config = copy.deepcopy(DEFAULT_CONFIG[CLIMATE_DOMAIN]) + config = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][climate.DOMAIN]) config["preset_modes"].append("none") - assert await async_setup_component(hass, CLIMATE_DOMAIN, {CLIMATE_DOMAIN: config}) - await hass.async_block_till_done() - await mqtt_mock_entry_no_yaml_config() - assert "Invalid config for [climate.mqtt]: not a valid value" in caplog.text - state = hass.states.get(ENTITY_CLIMATE) - assert state is None + assert not await async_setup_component( + hass, mqtt.DOMAIN, {mqtt.DOMAIN: {climate.DOMAIN: config}} + ) + assert "Invalid config for [mqtt]: not a valid value" in caplog.text # AWAY and HOLD mode topics and templates are deprecated, support will be removed with release 2022.9 @@ -136,22 +138,19 @@ async def test_preset_none_in_preset_modes( ("hold_mode_state_template", "{{ value_json }}"), ], ) -async def test_preset_modes_deprecation_guard( - hass, mqtt_mock_entry_no_yaml_config, caplog, parameter, config_value -): +async def test_preset_modes_deprecation_guard(hass, caplog, parameter, config_value): """Test the configuration for invalid legacy parameters.""" - config = copy.deepcopy(DEFAULT_CONFIG[CLIMATE_DOMAIN]) + config = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][climate.DOMAIN]) config[parameter] = config_value - assert await async_setup_component(hass, CLIMATE_DOMAIN, {CLIMATE_DOMAIN: config}) - await hass.async_block_till_done() - await mqtt_mock_entry_no_yaml_config() - state = hass.states.get(ENTITY_CLIMATE) - assert state is None + assert not await async_setup_component( + hass, mqtt.DOMAIN, {mqtt.DOMAIN: {climate.DOMAIN: config}} + ) + assert f"[{parameter}] is an invalid option for [mqtt]. Check: mqtt->mqtt->climate->0->{parameter}" async def test_supported_features(hass, mqtt_mock_entry_with_yaml_config): """Test the supported_features.""" - assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_CONFIG) + assert await async_setup_component(hass, mqtt.DOMAIN, DEFAULT_CONFIG) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -170,7 +169,7 @@ async def test_supported_features(hass, mqtt_mock_entry_with_yaml_config): async def test_get_hvac_modes(hass, mqtt_mock_entry_with_yaml_config): """Test that the operation list returns the correct modes.""" - assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_CONFIG) + assert await async_setup_component(hass, mqtt.DOMAIN, DEFAULT_CONFIG) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -193,7 +192,7 @@ async def test_set_operation_bad_attr_and_state( Also check the state. """ - assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_CONFIG) + assert await async_setup_component(hass, mqtt.DOMAIN, DEFAULT_CONFIG) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -210,7 +209,7 @@ async def test_set_operation_bad_attr_and_state( async def test_set_operation(hass, mqtt_mock_entry_with_yaml_config): """Test setting of new operation mode.""" - assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_CONFIG) + assert await async_setup_component(hass, mqtt.DOMAIN, DEFAULT_CONFIG) await hass.async_block_till_done() mqtt_mock = await mqtt_mock_entry_with_yaml_config() @@ -225,9 +224,9 @@ async def test_set_operation(hass, mqtt_mock_entry_with_yaml_config): async def test_set_operation_pessimistic(hass, mqtt_mock_entry_with_yaml_config): """Test setting operation mode in pessimistic mode.""" - config = copy.deepcopy(DEFAULT_CONFIG) + config = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) config["climate"]["mode_state_topic"] = "mode-state" - assert await async_setup_component(hass, CLIMATE_DOMAIN, config) + assert await async_setup_component(hass, mqtt.DOMAIN, {mqtt.DOMAIN: config}) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -249,9 +248,9 @@ async def test_set_operation_pessimistic(hass, mqtt_mock_entry_with_yaml_config) async def test_set_operation_with_power_command(hass, mqtt_mock_entry_with_yaml_config): """Test setting of new operation mode with power command enabled.""" - config = copy.deepcopy(DEFAULT_CONFIG) + config = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) config["climate"]["power_command_topic"] = "power-command" - assert await async_setup_component(hass, CLIMATE_DOMAIN, config) + assert await async_setup_component(hass, mqtt.DOMAIN, {mqtt.DOMAIN: config}) await hass.async_block_till_done() mqtt_mock = await mqtt_mock_entry_with_yaml_config() @@ -276,7 +275,7 @@ async def test_set_operation_with_power_command(hass, mqtt_mock_entry_with_yaml_ async def test_set_fan_mode_bad_attr(hass, mqtt_mock_entry_with_yaml_config, caplog): """Test setting fan mode without required attribute.""" - assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_CONFIG) + assert await async_setup_component(hass, mqtt.DOMAIN, DEFAULT_CONFIG) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -293,9 +292,9 @@ async def test_set_fan_mode_bad_attr(hass, mqtt_mock_entry_with_yaml_config, cap async def test_set_fan_mode_pessimistic(hass, mqtt_mock_entry_with_yaml_config): """Test setting of new fan mode in pessimistic mode.""" - config = copy.deepcopy(DEFAULT_CONFIG) + config = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) config["climate"]["fan_mode_state_topic"] = "fan-state" - assert await async_setup_component(hass, CLIMATE_DOMAIN, config) + assert await async_setup_component(hass, mqtt.DOMAIN, {mqtt.DOMAIN: config}) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -317,7 +316,7 @@ async def test_set_fan_mode_pessimistic(hass, mqtt_mock_entry_with_yaml_config): async def test_set_fan_mode(hass, mqtt_mock_entry_with_yaml_config): """Test setting of new fan mode.""" - assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_CONFIG) + assert await async_setup_component(hass, mqtt.DOMAIN, DEFAULT_CONFIG) await hass.async_block_till_done() mqtt_mock = await mqtt_mock_entry_with_yaml_config() @@ -331,7 +330,7 @@ async def test_set_fan_mode(hass, mqtt_mock_entry_with_yaml_config): async def test_set_swing_mode_bad_attr(hass, mqtt_mock_entry_with_yaml_config, caplog): """Test setting swing mode without required attribute.""" - assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_CONFIG) + assert await async_setup_component(hass, mqtt.DOMAIN, DEFAULT_CONFIG) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -348,9 +347,9 @@ async def test_set_swing_mode_bad_attr(hass, mqtt_mock_entry_with_yaml_config, c async def test_set_swing_pessimistic(hass, mqtt_mock_entry_with_yaml_config): """Test setting swing mode in pessimistic mode.""" - config = copy.deepcopy(DEFAULT_CONFIG) + config = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) config["climate"]["swing_mode_state_topic"] = "swing-state" - assert await async_setup_component(hass, CLIMATE_DOMAIN, config) + assert await async_setup_component(hass, mqtt.DOMAIN, {mqtt.DOMAIN: config}) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -372,7 +371,7 @@ async def test_set_swing_pessimistic(hass, mqtt_mock_entry_with_yaml_config): async def test_set_swing(hass, mqtt_mock_entry_with_yaml_config): """Test setting of new swing mode.""" - assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_CONFIG) + assert await async_setup_component(hass, mqtt.DOMAIN, DEFAULT_CONFIG) await hass.async_block_till_done() mqtt_mock = await mqtt_mock_entry_with_yaml_config() @@ -386,7 +385,7 @@ async def test_set_swing(hass, mqtt_mock_entry_with_yaml_config): async def test_set_target_temperature(hass, mqtt_mock_entry_with_yaml_config): """Test setting the target temperature.""" - assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_CONFIG) + assert await async_setup_component(hass, mqtt.DOMAIN, DEFAULT_CONFIG) await hass.async_block_till_done() mqtt_mock = await mqtt_mock_entry_with_yaml_config() @@ -425,9 +424,9 @@ async def test_set_target_temperature_pessimistic( hass, mqtt_mock_entry_with_yaml_config ): """Test setting the target temperature.""" - config = copy.deepcopy(DEFAULT_CONFIG) + config = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) config["climate"]["temperature_state_topic"] = "temperature-state" - assert await async_setup_component(hass, CLIMATE_DOMAIN, config) + assert await async_setup_component(hass, mqtt.DOMAIN, {mqtt.DOMAIN: config}) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -449,7 +448,7 @@ async def test_set_target_temperature_pessimistic( async def test_set_target_temperature_low_high(hass, mqtt_mock_entry_with_yaml_config): """Test setting the low/high target temperature.""" - assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_CONFIG) + assert await async_setup_component(hass, mqtt.DOMAIN, DEFAULT_CONFIG) await hass.async_block_till_done() mqtt_mock = await mqtt_mock_entry_with_yaml_config() @@ -467,10 +466,10 @@ async def test_set_target_temperature_low_highpessimistic( hass, mqtt_mock_entry_with_yaml_config ): """Test setting the low/high target temperature.""" - config = copy.deepcopy(DEFAULT_CONFIG) + config = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) config["climate"]["temperature_low_state_topic"] = "temperature-low-state" config["climate"]["temperature_high_state_topic"] = "temperature-high-state" - assert await async_setup_component(hass, CLIMATE_DOMAIN, config) + assert await async_setup_component(hass, mqtt.DOMAIN, {mqtt.DOMAIN: config}) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -505,9 +504,9 @@ async def test_set_target_temperature_low_highpessimistic( async def test_receive_mqtt_temperature(hass, mqtt_mock_entry_with_yaml_config): """Test getting the current temperature via MQTT.""" - config = copy.deepcopy(DEFAULT_CONFIG) + config = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) config["climate"]["current_temperature_topic"] = "current_temperature" - assert await async_setup_component(hass, CLIMATE_DOMAIN, config) + assert await async_setup_component(hass, mqtt.DOMAIN, {mqtt.DOMAIN: config}) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -518,9 +517,9 @@ async def test_receive_mqtt_temperature(hass, mqtt_mock_entry_with_yaml_config): async def test_handle_action_received(hass, mqtt_mock_entry_with_yaml_config): """Test getting the action received via MQTT.""" - config = copy.deepcopy(DEFAULT_CONFIG) + config = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) config["climate"]["action_topic"] = "action" - assert await async_setup_component(hass, CLIMATE_DOMAIN, config) + assert await async_setup_component(hass, mqtt.DOMAIN, {mqtt.DOMAIN: config}) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -531,7 +530,7 @@ async def test_handle_action_received(hass, mqtt_mock_entry_with_yaml_config): assert hvac_action is None # Redefine actions according to https://developers.home-assistant.io/docs/core/entity/climate/#hvac-action actions = ["off", "heating", "cooling", "drying", "idle", "fan"] - assert all(elem in actions for elem in CURRENT_HVAC_ACTIONS) + assert all(elem in actions for elem in HVACAction) for action in actions: async_fire_mqtt_message(hass, "action", action) state = hass.states.get(ENTITY_CLIMATE) @@ -543,8 +542,8 @@ async def test_set_preset_mode_optimistic( hass, mqtt_mock_entry_with_yaml_config, caplog ): """Test setting of the preset mode.""" - config = copy.deepcopy(DEFAULT_CONFIG) - assert await async_setup_component(hass, CLIMATE_DOMAIN, config) + config = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) + assert await async_setup_component(hass, mqtt.DOMAIN, {mqtt.DOMAIN: config}) await hass.async_block_till_done() mqtt_mock = await mqtt_mock_entry_with_yaml_config() @@ -591,9 +590,9 @@ async def test_set_preset_mode_pessimistic( hass, mqtt_mock_entry_with_yaml_config, caplog ): """Test setting of the preset mode.""" - config = copy.deepcopy(DEFAULT_CONFIG) + config = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) config["climate"]["preset_mode_state_topic"] = "preset-mode-state" - assert await async_setup_component(hass, CLIMATE_DOMAIN, config) + assert await async_setup_component(hass, mqtt.DOMAIN, {mqtt.DOMAIN: config}) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -636,9 +635,9 @@ async def test_set_preset_mode_pessimistic( async def test_set_aux_pessimistic(hass, mqtt_mock_entry_with_yaml_config): """Test setting of the aux heating in pessimistic mode.""" - config = copy.deepcopy(DEFAULT_CONFIG) + config = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) config["climate"]["aux_state_topic"] = "aux-state" - assert await async_setup_component(hass, CLIMATE_DOMAIN, config) + assert await async_setup_component(hass, mqtt.DOMAIN, {mqtt.DOMAIN: config}) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -664,7 +663,7 @@ async def test_set_aux_pessimistic(hass, mqtt_mock_entry_with_yaml_config): async def test_set_aux(hass, mqtt_mock_entry_with_yaml_config): """Test setting of the aux heating.""" - assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_CONFIG) + assert await async_setup_component(hass, mqtt.DOMAIN, DEFAULT_CONFIG) await hass.async_block_till_done() mqtt_mock = await mqtt_mock_entry_with_yaml_config() @@ -687,28 +686,28 @@ async def test_availability_when_connection_lost( ): """Test availability after MQTT disconnection.""" await help_test_availability_when_connection_lost( - hass, mqtt_mock_entry_with_yaml_config, CLIMATE_DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, climate.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_availability_without_topic(hass, mqtt_mock_entry_with_yaml_config): """Test availability without defined availability topic.""" await help_test_availability_without_topic( - hass, mqtt_mock_entry_with_yaml_config, CLIMATE_DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, climate.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_default_availability_payload(hass, mqtt_mock_entry_with_yaml_config): """Test availability by default payload with defined topic.""" await help_test_default_availability_payload( - hass, mqtt_mock_entry_with_yaml_config, CLIMATE_DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, climate.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_custom_availability_payload(hass, mqtt_mock_entry_with_yaml_config): """Test availability by custom payload with defined topic.""" await help_test_custom_availability_payload( - hass, mqtt_mock_entry_with_yaml_config, CLIMATE_DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, climate.DOMAIN, DEFAULT_CONFIG_LEGACY ) @@ -716,13 +715,13 @@ async def test_get_target_temperature_low_high_with_templates( hass, mqtt_mock_entry_with_yaml_config, caplog ): """Test getting temperature high/low with templates.""" - config = copy.deepcopy(DEFAULT_CONFIG) + config = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) config["climate"]["temperature_low_state_topic"] = "temperature-state" config["climate"]["temperature_high_state_topic"] = "temperature-state" config["climate"]["temperature_low_state_template"] = "{{ value_json.temp_low }}" config["climate"]["temperature_high_state_template"] = "{{ value_json.temp_high }}" - assert await async_setup_component(hass, CLIMATE_DOMAIN, config) + assert await async_setup_component(hass, mqtt.DOMAIN, {mqtt.DOMAIN: config}) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -751,7 +750,7 @@ async def test_get_target_temperature_low_high_with_templates( async def test_get_with_templates(hass, mqtt_mock_entry_with_yaml_config, caplog): """Test getting various attributes with templates.""" - config = copy.deepcopy(DEFAULT_CONFIG) + config = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) # By default, just unquote the JSON-strings config["climate"]["value_template"] = "{{ value_json }}" config["climate"]["action_template"] = "{{ value_json }}" @@ -768,7 +767,7 @@ async def test_get_with_templates(hass, mqtt_mock_entry_with_yaml_config, caplog config["climate"]["aux_state_topic"] = "aux-state" config["climate"]["current_temperature_topic"] = "current-temperature" config["climate"]["preset_mode_state_topic"] = "current-preset-mode" - assert await async_setup_component(hass, CLIMATE_DOMAIN, config) + assert await async_setup_component(hass, mqtt.DOMAIN, {mqtt.DOMAIN: config}) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -850,7 +849,7 @@ async def test_get_with_templates(hass, mqtt_mock_entry_with_yaml_config, caplog async def test_set_and_templates(hass, mqtt_mock_entry_with_yaml_config, caplog): """Test setting various attributes with templates.""" - config = copy.deepcopy(DEFAULT_CONFIG) + config = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) # Create simple templates config["climate"]["fan_mode_command_template"] = "fan_mode: {{ value }}" config["climate"]["preset_mode_command_template"] = "preset_mode: {{ value }}" @@ -860,7 +859,7 @@ async def test_set_and_templates(hass, mqtt_mock_entry_with_yaml_config, caplog) config["climate"]["temperature_high_command_template"] = "temp_hi: {{ value }}" config["climate"]["temperature_low_command_template"] = "temp_lo: {{ value }}" - assert await async_setup_component(hass, CLIMATE_DOMAIN, config) + assert await async_setup_component(hass, mqtt.DOMAIN, {mqtt.DOMAIN: config}) await hass.async_block_till_done() mqtt_mock = await mqtt_mock_entry_with_yaml_config() @@ -928,10 +927,10 @@ async def test_set_and_templates(hass, mqtt_mock_entry_with_yaml_config, caplog) async def test_min_temp_custom(hass, mqtt_mock_entry_with_yaml_config): """Test a custom min temp.""" - config = copy.deepcopy(DEFAULT_CONFIG) + config = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) config["climate"]["min_temp"] = 26 - assert await async_setup_component(hass, CLIMATE_DOMAIN, config) + assert await async_setup_component(hass, mqtt.DOMAIN, {mqtt.DOMAIN: config}) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -944,10 +943,10 @@ async def test_min_temp_custom(hass, mqtt_mock_entry_with_yaml_config): async def test_max_temp_custom(hass, mqtt_mock_entry_with_yaml_config): """Test a custom max temp.""" - config = copy.deepcopy(DEFAULT_CONFIG) + config = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) config["climate"]["max_temp"] = 60 - assert await async_setup_component(hass, CLIMATE_DOMAIN, config) + assert await async_setup_component(hass, mqtt.DOMAIN, {mqtt.DOMAIN: config}) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -960,10 +959,10 @@ async def test_max_temp_custom(hass, mqtt_mock_entry_with_yaml_config): async def test_temp_step_custom(hass, mqtt_mock_entry_with_yaml_config): """Test a custom temp step.""" - config = copy.deepcopy(DEFAULT_CONFIG) + config = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) config["climate"]["temp_step"] = 0.01 - assert await async_setup_component(hass, CLIMATE_DOMAIN, config) + assert await async_setup_component(hass, mqtt.DOMAIN, {mqtt.DOMAIN: config}) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -976,11 +975,11 @@ async def test_temp_step_custom(hass, mqtt_mock_entry_with_yaml_config): async def test_temperature_unit(hass, mqtt_mock_entry_with_yaml_config): """Test that setting temperature unit converts temperature values.""" - config = copy.deepcopy(DEFAULT_CONFIG) + config = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) config["climate"]["temperature_unit"] = "F" config["climate"]["current_temperature_topic"] = "current_temperature" - assert await async_setup_component(hass, CLIMATE_DOMAIN, config) + assert await async_setup_component(hass, mqtt.DOMAIN, {mqtt.DOMAIN: config}) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -995,7 +994,7 @@ async def test_setting_attribute_via_mqtt_json_message( ): """Test the setting of attribute via MQTT with JSON payload.""" await help_test_setting_attribute_via_mqtt_json_message( - hass, mqtt_mock_entry_with_yaml_config, CLIMATE_DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, climate.DOMAIN, DEFAULT_CONFIG_LEGACY ) @@ -1006,8 +1005,8 @@ async def test_setting_blocked_attribute_via_mqtt_json_message( await help_test_setting_blocked_attribute_via_mqtt_json_message( hass, mqtt_mock_entry_no_yaml_config, - CLIMATE_DOMAIN, - DEFAULT_CONFIG, + climate.DOMAIN, + DEFAULT_CONFIG_LEGACY, MQTT_CLIMATE_ATTRIBUTES_BLOCKED, ) @@ -1015,7 +1014,7 @@ async def test_setting_blocked_attribute_via_mqtt_json_message( async def test_setting_attribute_with_template(hass, mqtt_mock_entry_with_yaml_config): """Test the setting of attribute via MQTT with JSON payload.""" await help_test_setting_attribute_with_template( - hass, mqtt_mock_entry_with_yaml_config, CLIMATE_DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, climate.DOMAIN, DEFAULT_CONFIG_LEGACY ) @@ -1024,7 +1023,11 @@ async def test_update_with_json_attrs_not_dict( ): """Test attributes get extracted from a JSON result.""" await help_test_update_with_json_attrs_not_dict( - hass, mqtt_mock_entry_with_yaml_config, caplog, CLIMATE_DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_with_yaml_config, + caplog, + climate.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) @@ -1033,21 +1036,29 @@ async def test_update_with_json_attrs_bad_JSON( ): """Test attributes get extracted from a JSON result.""" await help_test_update_with_json_attrs_bad_JSON( - hass, mqtt_mock_entry_with_yaml_config, caplog, CLIMATE_DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_with_yaml_config, + caplog, + climate.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) async def test_discovery_update_attr(hass, mqtt_mock_entry_no_yaml_config, caplog): """Test update of discovered MQTTAttributes.""" await help_test_discovery_update_attr( - hass, mqtt_mock_entry_no_yaml_config, caplog, CLIMATE_DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_no_yaml_config, + caplog, + climate.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) async def test_unique_id(hass, mqtt_mock_entry_with_yaml_config): """Test unique id option only creates one climate per unique_id.""" config = { - CLIMATE_DOMAIN: [ + climate.DOMAIN: [ { "platform": "mqtt", "name": "Test 1", @@ -1065,7 +1076,7 @@ async def test_unique_id(hass, mqtt_mock_entry_with_yaml_config): ] } await help_test_unique_id( - hass, mqtt_mock_entry_with_yaml_config, CLIMATE_DOMAIN, config + hass, mqtt_mock_entry_with_yaml_config, climate.DOMAIN, config ) @@ -1095,12 +1106,12 @@ async def test_encoding_subscribable_topics( attribute_value, ): """Test handling of incoming encoded payload.""" - config = copy.deepcopy(DEFAULT_CONFIG[CLIMATE_DOMAIN]) + config = copy.deepcopy(DEFAULT_CONFIG_LEGACY[climate.DOMAIN]) await help_test_encoding_subscribable_topics( hass, mqtt_mock_entry_with_yaml_config, caplog, - CLIMATE_DOMAIN, + climate.DOMAIN, config, topic, value, @@ -1111,9 +1122,9 @@ async def test_encoding_subscribable_topics( async def test_discovery_removal_climate(hass, mqtt_mock_entry_no_yaml_config, caplog): """Test removal of discovered climate.""" - data = json.dumps(DEFAULT_CONFIG[CLIMATE_DOMAIN]) + data = json.dumps(DEFAULT_CONFIG_LEGACY[climate.DOMAIN]) await help_test_discovery_removal( - hass, mqtt_mock_entry_no_yaml_config, caplog, CLIMATE_DOMAIN, data + hass, mqtt_mock_entry_no_yaml_config, caplog, climate.DOMAIN, data ) @@ -1122,7 +1133,7 @@ async def test_discovery_update_climate(hass, mqtt_mock_entry_no_yaml_config, ca config1 = {"name": "Beer"} config2 = {"name": "Milk"} await help_test_discovery_update( - hass, mqtt_mock_entry_no_yaml_config, caplog, CLIMATE_DOMAIN, config1, config2 + hass, mqtt_mock_entry_no_yaml_config, caplog, climate.DOMAIN, config1, config2 ) @@ -1138,7 +1149,7 @@ async def test_discovery_update_unchanged_climate( hass, mqtt_mock_entry_no_yaml_config, caplog, - CLIMATE_DOMAIN, + climate.DOMAIN, data1, discovery_update, ) @@ -1150,42 +1161,42 @@ async def test_discovery_broken(hass, mqtt_mock_entry_no_yaml_config, caplog): data1 = '{ "name": "Beer", "power_command_topic": "test_topic#" }' data2 = '{ "name": "Milk", "power_command_topic": "test_topic" }' await help_test_discovery_broken( - hass, mqtt_mock_entry_no_yaml_config, caplog, CLIMATE_DOMAIN, data1, data2 + hass, mqtt_mock_entry_no_yaml_config, caplog, climate.DOMAIN, data1, data2 ) async def test_entity_device_info_with_connection(hass, mqtt_mock_entry_no_yaml_config): """Test MQTT climate device registry integration.""" await help_test_entity_device_info_with_connection( - hass, mqtt_mock_entry_no_yaml_config, CLIMATE_DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, climate.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_entity_device_info_with_identifier(hass, mqtt_mock_entry_no_yaml_config): """Test MQTT climate device registry integration.""" await help_test_entity_device_info_with_identifier( - hass, mqtt_mock_entry_no_yaml_config, CLIMATE_DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, climate.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_entity_device_info_update(hass, mqtt_mock_entry_no_yaml_config): """Test device registry update.""" await help_test_entity_device_info_update( - hass, mqtt_mock_entry_no_yaml_config, CLIMATE_DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, climate.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_entity_device_info_remove(hass, mqtt_mock_entry_no_yaml_config): """Test device registry remove.""" await help_test_entity_device_info_remove( - hass, mqtt_mock_entry_no_yaml_config, CLIMATE_DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, climate.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_entity_id_update_subscriptions(hass, mqtt_mock_entry_with_yaml_config): """Test MQTT subscriptions are managed when entity_id is updated.""" config = { - CLIMATE_DOMAIN: { + climate.DOMAIN: { "platform": "mqtt", "name": "test", "mode_state_topic": "test-topic", @@ -1195,7 +1206,7 @@ async def test_entity_id_update_subscriptions(hass, mqtt_mock_entry_with_yaml_co await help_test_entity_id_update_subscriptions( hass, mqtt_mock_entry_with_yaml_config, - CLIMATE_DOMAIN, + climate.DOMAIN, config, ["test-topic", "avty-topic"], ) @@ -1204,14 +1215,14 @@ async def test_entity_id_update_subscriptions(hass, mqtt_mock_entry_with_yaml_co async def test_entity_id_update_discovery_update(hass, mqtt_mock_entry_no_yaml_config): """Test MQTT discovery update when entity_id is updated.""" await help_test_entity_id_update_discovery_update( - hass, mqtt_mock_entry_no_yaml_config, CLIMATE_DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, climate.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config): """Test MQTT debug info.""" config = { - CLIMATE_DOMAIN: { + climate.DOMAIN: { "platform": "mqtt", "name": "test", "mode_command_topic": "command-topic", @@ -1221,7 +1232,7 @@ async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config): await help_test_entity_debug_info_message( hass, mqtt_mock_entry_no_yaml_config, - CLIMATE_DOMAIN, + climate.DOMAIN, config, climate.SERVICE_TURN_ON, command_topic="command-topic", @@ -1232,7 +1243,7 @@ async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config): async def test_precision_default(hass, mqtt_mock_entry_with_yaml_config): """Test that setting precision to tenths works as intended.""" - assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_CONFIG) + assert await async_setup_component(hass, mqtt.DOMAIN, DEFAULT_CONFIG) await hass.async_block_till_done() mqtt_mock = await mqtt_mock_entry_with_yaml_config() @@ -1246,9 +1257,9 @@ async def test_precision_default(hass, mqtt_mock_entry_with_yaml_config): async def test_precision_halves(hass, mqtt_mock_entry_with_yaml_config): """Test that setting precision to halves works as intended.""" - config = copy.deepcopy(DEFAULT_CONFIG) + config = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) config["climate"]["precision"] = 0.5 - assert await async_setup_component(hass, CLIMATE_DOMAIN, config) + assert await async_setup_component(hass, mqtt.DOMAIN, {mqtt.DOMAIN: config}) await hass.async_block_till_done() mqtt_mock = await mqtt_mock_entry_with_yaml_config() @@ -1262,9 +1273,9 @@ async def test_precision_halves(hass, mqtt_mock_entry_with_yaml_config): async def test_precision_whole(hass, mqtt_mock_entry_with_yaml_config): """Test that setting precision to whole works as intended.""" - config = copy.deepcopy(DEFAULT_CONFIG) + config = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) config["climate"]["precision"] = 1.0 - assert await async_setup_component(hass, CLIMATE_DOMAIN, config) + assert await async_setup_component(hass, mqtt.DOMAIN, {mqtt.DOMAIN: config}) await hass.async_block_till_done() mqtt_mock = await mqtt_mock_entry_with_yaml_config() @@ -1364,7 +1375,7 @@ async def test_publishing_with_custom_encoding( ): """Test publishing MQTT payload with different encoding.""" domain = climate.DOMAIN - config = copy.deepcopy(DEFAULT_CONFIG[domain]) + config = copy.deepcopy(DEFAULT_CONFIG_LEGACY[domain]) if topic != "preset_mode_command_topic": del config["preset_mode_command_topic"] del config["preset_modes"] @@ -1385,8 +1396,8 @@ async def test_publishing_with_custom_encoding( async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path): """Test reloading the MQTT platform.""" - domain = CLIMATE_DOMAIN - config = DEFAULT_CONFIG[domain] + domain = climate.DOMAIN + config = DEFAULT_CONFIG_LEGACY[domain] await help_test_reloadable( hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config ) @@ -1394,15 +1405,15 @@ async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_pa async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path): """Test reloading the MQTT platform with late entry setup.""" - domain = CLIMATE_DOMAIN - config = DEFAULT_CONFIG[domain] + domain = climate.DOMAIN + config = DEFAULT_CONFIG_LEGACY[domain] await help_test_reloadable_late(hass, caplog, tmp_path, domain, config) async def test_setup_manual_entity_from_yaml(hass): """Test setup manual configured MQTT entity.""" - platform = CLIMATE_DOMAIN - config = copy.deepcopy(DEFAULT_CONFIG[platform]) + platform = climate.DOMAIN + config = copy.deepcopy(DEFAULT_CONFIG_LEGACY[platform]) config["name"] = "test" del config["platform"] await help_test_setup_manual_entity_from_yaml(hass, platform, config) @@ -1412,7 +1423,20 @@ async def test_setup_manual_entity_from_yaml(hass): async def test_unload_entry(hass, mqtt_mock_entry_with_yaml_config, tmp_path): """Test unloading the config entry.""" domain = climate.DOMAIN - config = DEFAULT_CONFIG[domain] + config = DEFAULT_CONFIG_LEGACY[domain] await help_test_unload_config_entry_with_platform( hass, mqtt_mock_entry_with_yaml_config, tmp_path, domain, config ) + + +# Test deprecated YAML configuration under the platform key +# Scheduled to be removed in HA core 2022.12 +async def test_setup_with_legacy_schema(hass, mqtt_mock_entry_with_yaml_config): + """Test a setup with deprecated yaml platform schema.""" + domain = climate.DOMAIN + config = copy.deepcopy(DEFAULT_CONFIG_LEGACY[domain]) + config["name"] = "test" + assert await async_setup_component(hass, domain, {domain: config}) + await hass.async_block_till_done() + await mqtt_mock_entry_with_yaml_config() + assert hass.states.get(f"{domain}.test") is not None diff --git a/tests/components/mqtt/test_cover.py b/tests/components/mqtt/test_cover.py index b1c162073ed..a91f0ecc6ca 100644 --- a/tests/components/mqtt/test_cover.py +++ b/tests/components/mqtt/test_cover.py @@ -5,7 +5,7 @@ from unittest.mock import patch import pytest -from homeassistant.components import cover +from homeassistant.components import cover, mqtt from homeassistant.components.cover import ( ATTR_CURRENT_POSITION, ATTR_CURRENT_TILT_POSITION, @@ -81,9 +81,14 @@ from .test_common import ( from tests.common import async_fire_mqtt_message DEFAULT_CONFIG = { - cover.DOMAIN: {"platform": "mqtt", "name": "test", "state_topic": "test-topic"} + mqtt.DOMAIN: {cover.DOMAIN: {"name": "test", "state_topic": "test-topic"}} } +# Test deprecated YAML configuration under the platform key +# Scheduled to be removed in HA core 2022.12 +DEFAULT_CONFIG_LEGACY = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) +DEFAULT_CONFIG_LEGACY[cover.DOMAIN]["platform"] = mqtt.DOMAIN + @pytest.fixture(autouse=True) def cover_platform_only(): @@ -96,17 +101,18 @@ async def test_state_via_state_topic(hass, mqtt_mock_entry_with_yaml_config): """Test the controlling state via topic.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "qos": 0, - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "qos": 0, + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + } } }, ) @@ -134,19 +140,20 @@ async def test_opening_and_closing_state_via_custom_state_payload( """Test the controlling opening and closing state via a custom payload.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "qos": 0, - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", - "state_opening": "34", - "state_closing": "--43", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "qos": 0, + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + "state_opening": "34", + "state_closing": "--43", + } } }, ) @@ -179,18 +186,19 @@ async def test_open_closed_state_from_position_optimistic( """Test the state after setting the position using optimistic mode.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "position_topic": "position-topic", - "set_position_topic": "set-position-topic", - "qos": 0, - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", - "optimistic": True, + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "position_topic": "position-topic", + "set_position_topic": "set-position-topic", + "qos": 0, + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + "optimistic": True, + } } }, ) @@ -227,19 +235,20 @@ async def test_position_via_position_topic(hass, mqtt_mock_entry_with_yaml_confi """Test the controlling state via topic.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "position_topic": "get-position-topic", - "position_open": 100, - "position_closed": 0, - "command_topic": "command-topic", - "qos": 0, - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "position_topic": "get-position-topic", + "position_open": 100, + "position_closed": 0, + "command_topic": "command-topic", + "qos": 0, + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + } } }, ) @@ -265,20 +274,21 @@ async def test_state_via_template(hass, mqtt_mock_entry_with_yaml_config): """Test the controlling state via topic.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "qos": 0, - "value_template": "\ + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "qos": 0, + "value_template": "\ {% if (value | multiply(0.01) | int) == 0 %}\ closed\ {% else %}\ open\ {% endif %}", + } } }, ) @@ -303,20 +313,21 @@ async def test_state_via_template_and_entity_id(hass, mqtt_mock_entry_with_yaml_ """Test the controlling state via topic.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "qos": 0, - "value_template": '\ + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "qos": 0, + "value_template": '\ {% if value == "open" or value == "closed" %}\ {{ value }}\ {% else %}\ {{ states(entity_id) }}\ {% endif %}', + } } }, ) @@ -345,15 +356,16 @@ async def test_state_via_template_with_json_value( """Test the controlling state via topic with JSON value.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "qos": 0, - "value_template": "{{ value_json.Var1 }}", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "qos": 0, + "value_template": "{{ value_json.Var1 }}", + } } }, ) @@ -387,20 +399,21 @@ async def test_position_via_template_and_entity_id( """Test the controlling state via topic.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "position_topic": "get-position-topic", - "command_topic": "command-topic", - "qos": 0, - "position_template": '\ + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "position_topic": "get-position-topic", + "command_topic": "command-topic", + "qos": 0, + "position_template": '\ {% if state_attr(entity_id, "current_position") == None %}\ {{ value }}\ {% else %}\ {{ state_attr(entity_id, "current_position") + value | int }}\ {% endif %}', + } } }, ) @@ -442,8 +455,8 @@ async def test_optimistic_flag( """Test assumed_state is set correctly.""" assert await async_setup_component( hass, - cover.DOMAIN, - {cover.DOMAIN: {**config, "platform": "mqtt", "name": "test", "qos": 0}}, + mqtt.DOMAIN, + {mqtt.DOMAIN: {cover.DOMAIN: {**config, "name": "test", "qos": 0}}}, ) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -460,13 +473,14 @@ async def test_optimistic_state_change(hass, mqtt_mock_entry_with_yaml_config): """Test changing state optimistically.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "command-topic", - "qos": 0, + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "command_topic": "command-topic", + "qos": 0, + } } }, ) @@ -519,15 +533,16 @@ async def test_optimistic_state_change_with_position( """Test changing state optimistically.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "optimistic": True, - "command_topic": "command-topic", - "position_topic": "position-topic", - "qos": 0, + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "optimistic": True, + "command_topic": "command-topic", + "position_topic": "position-topic", + "qos": 0, + } } }, ) @@ -583,14 +598,15 @@ async def test_send_open_cover_command(hass, mqtt_mock_entry_with_yaml_config): """Test the sending of open_cover.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "qos": 2, + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "qos": 2, + } } }, ) @@ -613,14 +629,15 @@ async def test_send_close_cover_command(hass, mqtt_mock_entry_with_yaml_config): """Test the sending of close_cover.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "qos": 2, + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "qos": 2, + } } }, ) @@ -643,14 +660,15 @@ async def test_send_stop__cover_command(hass, mqtt_mock_entry_with_yaml_config): """Test the sending of stop_cover.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "qos": 2, + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "qos": 2, + } } }, ) @@ -673,18 +691,19 @@ async def test_current_cover_position(hass, mqtt_mock_entry_with_yaml_config): """Test the current cover position.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "position_topic": "get-position-topic", - "command_topic": "command-topic", - "position_open": 100, - "position_closed": 0, - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "position_topic": "get-position-topic", + "command_topic": "command-topic", + "position_open": 100, + "position_closed": 0, + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + } } }, ) @@ -725,18 +744,19 @@ async def test_current_cover_position_inverted(hass, mqtt_mock_entry_with_yaml_c """Test the current cover position.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "position_topic": "get-position-topic", - "command_topic": "command-topic", - "position_open": 0, - "position_closed": 100, - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "position_topic": "get-position-topic", + "command_topic": "command-topic", + "position_open": 0, + "position_closed": 100, + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + } } }, ) @@ -784,44 +804,45 @@ async def test_current_cover_position_inverted(hass, mqtt_mock_entry_with_yaml_c assert hass.states.get("cover.test").state == STATE_CLOSED -async def test_optimistic_position(hass, mqtt_mock_entry_no_yaml_config): +async def test_optimistic_position(hass, caplog): """Test optimistic position is not supported.""" - assert await async_setup_component( + assert not await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "command-topic", - "set_position_topic": "set-position-topic", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "command_topic": "command-topic", + "set_position_topic": "set-position-topic", + } } }, ) - await hass.async_block_till_done() - await mqtt_mock_entry_no_yaml_config() - - state = hass.states.get("cover.test") - assert state is None + assert ( + "Invalid config for [mqtt]: 'set_position_topic' must be set together with 'position_topic'" + in caplog.text + ) async def test_position_update(hass, mqtt_mock_entry_with_yaml_config): """Test cover position update from received MQTT message.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "position_topic": "get-position-topic", - "command_topic": "command-topic", - "set_position_topic": "set-position-topic", - "position_open": 100, - "position_closed": 0, - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "position_topic": "get-position-topic", + "command_topic": "command-topic", + "set_position_topic": "set-position-topic", + "position_open": 100, + "position_closed": 0, + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + } } }, ) @@ -853,20 +874,21 @@ async def test_set_position_templated( """Test setting cover position via template.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "position_topic": "get-position-topic", - "command_topic": "command-topic", - "position_open": 100, - "position_closed": 0, - "set_position_topic": "set-position-topic", - "set_position_template": pos_template, - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "position_topic": "get-position-topic", + "command_topic": "command-topic", + "position_open": 100, + "position_closed": 0, + "set_position_topic": "set-position-topic", + "set_position_template": pos_template, + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + } } }, ) @@ -891,17 +913,17 @@ async def test_set_position_templated_and_attributes( """Test setting cover position via template and using entities attributes.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "position_topic": "get-position-topic", - "command_topic": "command-topic", - "position_open": 100, - "position_closed": 0, - "set_position_topic": "set-position-topic", - "set_position_template": '\ + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "position_topic": "get-position-topic", + "command_topic": "command-topic", + "position_open": 100, + "position_closed": 0, + "set_position_topic": "set-position-topic", + "set_position_template": '\ {% if position > 99 %}\ {% if state_attr(entity_id, "current_position") == None %}\ {{ 5 }}\ @@ -911,9 +933,10 @@ async def test_set_position_templated_and_attributes( {% else %}\ {{ 42 }}\ {% endif %}', - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + } } }, ) @@ -934,22 +957,23 @@ async def test_set_tilt_templated(hass, mqtt_mock_entry_with_yaml_config): """Test setting cover tilt position via template.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "position_topic": "get-position-topic", - "command_topic": "command-topic", - "tilt_command_topic": "tilt-command-topic", - "position_open": 100, - "position_closed": 0, - "set_position_topic": "set-position-topic", - "set_position_template": "{{position-1}}", - "tilt_command_template": "{{tilt_position+1}}", - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "position_topic": "get-position-topic", + "command_topic": "command-topic", + "tilt_command_topic": "tilt-command-topic", + "position_open": 100, + "position_closed": 0, + "set_position_topic": "set-position-topic", + "set_position_template": "{{position-1}}", + "tilt_command_template": "{{tilt_position+1}}", + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + } } }, ) @@ -974,26 +998,27 @@ async def test_set_tilt_templated_and_attributes( """Test setting cover tilt position via template and using entities attributes.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "position_topic": "get-position-topic", - "command_topic": "command-topic", - "tilt_command_topic": "tilt-command-topic", - "position_open": 100, - "position_closed": 0, - "set_position_topic": "set-position-topic", - "set_position_template": "{{position-1}}", - "tilt_command_template": "{" - '"entity_id": "{{ entity_id }}",' - '"value": {{ value }},' - '"tilt_position": {{ tilt_position }}' - "}", - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "position_topic": "get-position-topic", + "command_topic": "command-topic", + "tilt_command_topic": "tilt-command-topic", + "position_open": 100, + "position_closed": 0, + "set_position_topic": "set-position-topic", + "set_position_template": "{{position-1}}", + "tilt_command_template": "{" + '"entity_id": "{{ entity_id }}",' + '"value": {{ value }},' + '"tilt_position": {{ tilt_position }}' + "}", + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + } } }, ) @@ -1061,17 +1086,18 @@ async def test_set_position_untemplated(hass, mqtt_mock_entry_with_yaml_config): """Test setting cover position via template.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "position_topic": "state-topic", - "command_topic": "command-topic", - "set_position_topic": "position-topic", - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "position_topic": "state-topic", + "command_topic": "command-topic", + "set_position_topic": "position-topic", + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + } } }, ) @@ -1094,19 +1120,20 @@ async def test_set_position_untemplated_custom_percentage_range( """Test setting cover position via template.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "position_topic": "state-topic", - "command_topic": "command-topic", - "set_position_topic": "position-topic", - "position_open": 0, - "position_closed": 100, - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "position_topic": "state-topic", + "command_topic": "command-topic", + "set_position_topic": "position-topic", + "position_open": 0, + "position_closed": 100, + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + } } }, ) @@ -1127,17 +1154,18 @@ async def test_no_command_topic(hass, mqtt_mock_entry_with_yaml_config): """Test with no command topic.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "qos": 0, - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", - "tilt_command_topic": "tilt-command", - "tilt_status_topic": "tilt-status", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "qos": 0, + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + "tilt_command_topic": "tilt-command", + "tilt_status_topic": "tilt-status", + } } }, ) @@ -1151,16 +1179,17 @@ async def test_no_payload_close(hass, mqtt_mock_entry_with_yaml_config): """Test with no close payload.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "command-topic", - "qos": 0, - "payload_open": "OPEN", - "payload_close": None, - "payload_stop": "STOP", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "command_topic": "command-topic", + "qos": 0, + "payload_open": "OPEN", + "payload_close": None, + "payload_stop": "STOP", + } } }, ) @@ -1174,16 +1203,17 @@ async def test_no_payload_open(hass, mqtt_mock_entry_with_yaml_config): """Test with no open payload.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "command-topic", - "qos": 0, - "payload_open": None, - "payload_close": "CLOSE", - "payload_stop": "STOP", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "command_topic": "command-topic", + "qos": 0, + "payload_open": None, + "payload_close": "CLOSE", + "payload_stop": "STOP", + } } }, ) @@ -1197,16 +1227,17 @@ async def test_no_payload_stop(hass, mqtt_mock_entry_with_yaml_config): """Test with no stop payload.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "command-topic", - "qos": 0, - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": None, + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "command_topic": "command-topic", + "qos": 0, + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": None, + } } }, ) @@ -1220,18 +1251,19 @@ async def test_with_command_topic_and_tilt(hass, mqtt_mock_entry_with_yaml_confi """Test with command topic and tilt config.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "command_topic": "test", - "platform": "mqtt", - "name": "test", - "qos": 0, - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", - "tilt_command_topic": "tilt-command", - "tilt_status_topic": "tilt-status", + mqtt.DOMAIN: { + cover.DOMAIN: { + "command_topic": "test", + "name": "test", + "qos": 0, + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + "tilt_command_topic": "tilt-command", + "tilt_status_topic": "tilt-status", + } } }, ) @@ -1245,19 +1277,20 @@ async def test_tilt_defaults(hass, mqtt_mock_entry_with_yaml_config): """Test the defaults.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "qos": 0, - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", - "tilt_command_topic": "tilt-command", - "tilt_status_topic": "tilt-status", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "qos": 0, + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + "tilt_command_topic": "tilt-command", + "tilt_status_topic": "tilt-status", + } } }, ) @@ -1273,19 +1306,20 @@ async def test_tilt_via_invocation_defaults(hass, mqtt_mock_entry_with_yaml_conf """Test tilt defaults on close/open.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "qos": 0, - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", - "tilt_command_topic": "tilt-command-topic", - "tilt_status_topic": "tilt-status-topic", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "qos": 0, + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + "tilt_command_topic": "tilt-command-topic", + "tilt_status_topic": "tilt-status-topic", + } } }, ) @@ -1356,21 +1390,22 @@ async def test_tilt_given_value(hass, mqtt_mock_entry_with_yaml_config): """Test tilting to a given value.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "qos": 0, - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", - "tilt_command_topic": "tilt-command-topic", - "tilt_status_topic": "tilt-status-topic", - "tilt_opened_value": 80, - "tilt_closed_value": 25, + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "qos": 0, + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + "tilt_command_topic": "tilt-command-topic", + "tilt_status_topic": "tilt-status-topic", + "tilt_opened_value": 80, + "tilt_closed_value": 25, + } } }, ) @@ -1445,22 +1480,23 @@ async def test_tilt_given_value_optimistic(hass, mqtt_mock_entry_with_yaml_confi """Test tilting to a given value.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "qos": 0, - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", - "tilt_command_topic": "tilt-command-topic", - "tilt_status_topic": "tilt-status-topic", - "tilt_opened_value": 80, - "tilt_closed_value": 25, - "tilt_optimistic": True, + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "qos": 0, + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + "tilt_command_topic": "tilt-command-topic", + "tilt_status_topic": "tilt-status-topic", + "tilt_opened_value": 80, + "tilt_closed_value": 25, + "tilt_optimistic": True, + } } }, ) @@ -1522,24 +1558,25 @@ async def test_tilt_given_value_altered_range(hass, mqtt_mock_entry_with_yaml_co """Test tilting to a given value.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "qos": 0, - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", - "tilt_command_topic": "tilt-command-topic", - "tilt_status_topic": "tilt-status-topic", - "tilt_opened_value": 25, - "tilt_closed_value": 0, - "tilt_min": 0, - "tilt_max": 50, - "tilt_optimistic": True, + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "qos": 0, + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + "tilt_command_topic": "tilt-command-topic", + "tilt_status_topic": "tilt-status-topic", + "tilt_opened_value": 25, + "tilt_closed_value": 0, + "tilt_min": 0, + "tilt_max": 50, + "tilt_optimistic": True, + } } }, ) @@ -1599,19 +1636,20 @@ async def test_tilt_via_topic(hass, mqtt_mock_entry_with_yaml_config): """Test tilt by updating status via MQTT.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "qos": 0, - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", - "tilt_command_topic": "tilt-command-topic", - "tilt_status_topic": "tilt-status-topic", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "qos": 0, + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + "tilt_command_topic": "tilt-command-topic", + "tilt_status_topic": "tilt-status-topic", + } } }, ) @@ -1637,22 +1675,23 @@ async def test_tilt_via_topic_template(hass, mqtt_mock_entry_with_yaml_config): """Test tilt by updating status via MQTT and template.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "qos": 0, - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", - "tilt_command_topic": "tilt-command-topic", - "tilt_status_topic": "tilt-status-topic", - "tilt_status_template": "{{ (value | multiply(0.01)) | int }}", - "tilt_opened_value": 400, - "tilt_closed_value": 125, + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "qos": 0, + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + "tilt_command_topic": "tilt-command-topic", + "tilt_status_topic": "tilt-status-topic", + "tilt_status_template": "{{ (value | multiply(0.01)) | int }}", + "tilt_opened_value": 400, + "tilt_closed_value": 125, + } } }, ) @@ -1680,22 +1719,23 @@ async def test_tilt_via_topic_template_json_value( """Test tilt by updating status via MQTT and template with JSON value.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "qos": 0, - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", - "tilt_command_topic": "tilt-command-topic", - "tilt_status_topic": "tilt-status-topic", - "tilt_status_template": "{{ value_json.Var1 }}", - "tilt_opened_value": 400, - "tilt_closed_value": 125, + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "qos": 0, + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + "tilt_command_topic": "tilt-command-topic", + "tilt_status_topic": "tilt-status-topic", + "tilt_status_template": "{{ value_json.Var1 }}", + "tilt_opened_value": 400, + "tilt_closed_value": 125, + } } }, ) @@ -1727,21 +1767,22 @@ async def test_tilt_via_topic_altered_range(hass, mqtt_mock_entry_with_yaml_conf """Test tilt status via MQTT with altered tilt range.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "qos": 0, - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", - "tilt_command_topic": "tilt-command-topic", - "tilt_status_topic": "tilt-status-topic", - "tilt_min": 0, - "tilt_max": 50, + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "qos": 0, + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + "tilt_command_topic": "tilt-command-topic", + "tilt_status_topic": "tilt-status-topic", + "tilt_min": 0, + "tilt_max": 50, + } } }, ) @@ -1776,21 +1817,22 @@ async def test_tilt_status_out_of_range_warning( """Test tilt status via MQTT tilt out of range warning message.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "qos": 0, - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", - "tilt_command_topic": "tilt-command-topic", - "tilt_status_topic": "tilt-status-topic", - "tilt_min": 0, - "tilt_max": 50, + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "qos": 0, + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + "tilt_command_topic": "tilt-command-topic", + "tilt_status_topic": "tilt-status-topic", + "tilt_min": 0, + "tilt_max": 50, + } } }, ) @@ -1810,21 +1852,22 @@ async def test_tilt_status_not_numeric_warning( """Test tilt status via MQTT tilt not numeric warning message.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "qos": 0, - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", - "tilt_command_topic": "tilt-command-topic", - "tilt_status_topic": "tilt-status-topic", - "tilt_min": 0, - "tilt_max": 50, + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "qos": 0, + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + "tilt_command_topic": "tilt-command-topic", + "tilt_status_topic": "tilt-status-topic", + "tilt_min": 0, + "tilt_max": 50, + } } }, ) @@ -1842,21 +1885,22 @@ async def test_tilt_via_topic_altered_range_inverted( """Test tilt status via MQTT with altered tilt range and inverted tilt position.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "qos": 0, - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", - "tilt_command_topic": "tilt-command-topic", - "tilt_status_topic": "tilt-status-topic", - "tilt_min": 50, - "tilt_max": 0, + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "qos": 0, + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + "tilt_command_topic": "tilt-command-topic", + "tilt_status_topic": "tilt-status-topic", + "tilt_min": 50, + "tilt_max": 0, + } } }, ) @@ -1891,24 +1935,25 @@ async def test_tilt_via_topic_template_altered_range( """Test tilt status via MQTT and template with altered tilt range.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "qos": 0, - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", - "tilt_command_topic": "tilt-command-topic", - "tilt_status_topic": "tilt-status-topic", - "tilt_status_template": "{{ (value | multiply(0.01)) | int }}", - "tilt_opened_value": 400, - "tilt_closed_value": 125, - "tilt_min": 0, - "tilt_max": 50, + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "qos": 0, + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + "tilt_command_topic": "tilt-command-topic", + "tilt_status_topic": "tilt-status-topic", + "tilt_status_template": "{{ (value | multiply(0.01)) | int }}", + "tilt_opened_value": 400, + "tilt_closed_value": 125, + "tilt_min": 0, + "tilt_max": 50, + } } }, ) @@ -1941,19 +1986,20 @@ async def test_tilt_position(hass, mqtt_mock_entry_with_yaml_config): """Test tilt via method invocation.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "qos": 0, - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", - "tilt_command_topic": "tilt-command-topic", - "tilt_status_topic": "tilt-status-topic", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "qos": 0, + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + "tilt_command_topic": "tilt-command-topic", + "tilt_status_topic": "tilt-status-topic", + } } }, ) @@ -1976,20 +2022,21 @@ async def test_tilt_position_templated(hass, mqtt_mock_entry_with_yaml_config): """Test tilt position via template.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "qos": 0, - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", - "tilt_command_topic": "tilt-command-topic", - "tilt_status_topic": "tilt-status-topic", - "tilt_command_template": "{{100-32}}", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "qos": 0, + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + "tilt_command_topic": "tilt-command-topic", + "tilt_status_topic": "tilt-status-topic", + "tilt_command_template": "{{100-32}}", + } } }, ) @@ -2012,23 +2059,24 @@ async def test_tilt_position_altered_range(hass, mqtt_mock_entry_with_yaml_confi """Test tilt via method invocation with altered range.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "qos": 0, - "payload_open": "OPEN", - "payload_close": "CLOSE", - "payload_stop": "STOP", - "tilt_command_topic": "tilt-command-topic", - "tilt_status_topic": "tilt-status-topic", - "tilt_opened_value": 400, - "tilt_closed_value": 125, - "tilt_min": 0, - "tilt_max": 50, + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "qos": 0, + "payload_open": "OPEN", + "payload_close": "CLOSE", + "payload_stop": "STOP", + "tilt_command_topic": "tilt-command-topic", + "tilt_status_topic": "tilt-status-topic", + "tilt_opened_value": 400, + "tilt_closed_value": 125, + "tilt_min": 0, + "tilt_max": 50, + } } }, ) @@ -2396,28 +2444,28 @@ async def test_availability_when_connection_lost( ): """Test availability after MQTT disconnection.""" await help_test_availability_when_connection_lost( - hass, mqtt_mock_entry_with_yaml_config, cover.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, cover.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_availability_without_topic(hass, mqtt_mock_entry_with_yaml_config): """Test availability without defined availability topic.""" await help_test_availability_without_topic( - hass, mqtt_mock_entry_with_yaml_config, cover.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, cover.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_default_availability_payload(hass, mqtt_mock_entry_with_yaml_config): """Test availability by default payload with defined topic.""" await help_test_default_availability_payload( - hass, mqtt_mock_entry_with_yaml_config, cover.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, cover.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_custom_availability_payload(hass, mqtt_mock_entry_with_yaml_config): """Test availability by custom payload with defined topic.""" await help_test_custom_availability_payload( - hass, mqtt_mock_entry_with_yaml_config, cover.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, cover.DOMAIN, DEFAULT_CONFIG_LEGACY ) @@ -2425,13 +2473,14 @@ async def test_valid_device_class(hass, mqtt_mock_entry_with_yaml_config): """Test the setting of a valid device class.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "device_class": "garage", - "state_topic": "test-topic", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "device_class": "garage", + "state_topic": "test-topic", + } } }, ) @@ -2442,25 +2491,22 @@ async def test_valid_device_class(hass, mqtt_mock_entry_with_yaml_config): assert state.attributes.get("device_class") == "garage" -async def test_invalid_device_class(hass, mqtt_mock_entry_no_yaml_config): +async def test_invalid_device_class(hass, caplog): """Test the setting of an invalid device class.""" - assert await async_setup_component( + assert not await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "device_class": "abc123", - "state_topic": "test-topic", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "device_class": "abc123", + "state_topic": "test-topic", + } } }, ) - await hass.async_block_till_done() - await mqtt_mock_entry_no_yaml_config() - - state = hass.states.get("cover.test") - assert state is None + assert "Invalid config for [mqtt]: expected CoverDeviceClass" in caplog.text async def test_setting_attribute_via_mqtt_json_message( @@ -2468,7 +2514,7 @@ async def test_setting_attribute_via_mqtt_json_message( ): """Test the setting of attribute via MQTT with JSON payload.""" await help_test_setting_attribute_via_mqtt_json_message( - hass, mqtt_mock_entry_with_yaml_config, cover.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, cover.DOMAIN, DEFAULT_CONFIG_LEGACY ) @@ -2480,7 +2526,7 @@ async def test_setting_blocked_attribute_via_mqtt_json_message( hass, mqtt_mock_entry_no_yaml_config, cover.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, MQTT_COVER_ATTRIBUTES_BLOCKED, ) @@ -2488,7 +2534,7 @@ async def test_setting_blocked_attribute_via_mqtt_json_message( async def test_setting_attribute_with_template(hass, mqtt_mock_entry_with_yaml_config): """Test the setting of attribute via MQTT with JSON payload.""" await help_test_setting_attribute_with_template( - hass, mqtt_mock_entry_with_yaml_config, cover.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, cover.DOMAIN, DEFAULT_CONFIG_LEGACY ) @@ -2497,7 +2543,11 @@ async def test_update_with_json_attrs_not_dict( ): """Test attributes get extracted from a JSON result.""" await help_test_update_with_json_attrs_not_dict( - hass, mqtt_mock_entry_with_yaml_config, caplog, cover.DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_with_yaml_config, + caplog, + cover.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) @@ -2506,14 +2556,22 @@ async def test_update_with_json_attrs_bad_json( ): """Test attributes get extracted from a JSON result.""" await help_test_update_with_json_attrs_bad_JSON( - hass, mqtt_mock_entry_with_yaml_config, caplog, cover.DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_with_yaml_config, + caplog, + cover.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) async def test_discovery_update_attr(hass, mqtt_mock_entry_no_yaml_config, caplog): """Test update of discovered MQTTAttributes.""" await help_test_discovery_update_attr( - hass, mqtt_mock_entry_no_yaml_config, caplog, cover.DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_no_yaml_config, + caplog, + cover.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) @@ -2588,42 +2646,42 @@ async def test_discovery_broken(hass, mqtt_mock_entry_no_yaml_config, caplog): async def test_entity_device_info_with_connection(hass, mqtt_mock_entry_no_yaml_config): """Test MQTT cover device registry integration.""" await help_test_entity_device_info_with_connection( - hass, mqtt_mock_entry_no_yaml_config, cover.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, cover.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_entity_device_info_with_identifier(hass, mqtt_mock_entry_no_yaml_config): """Test MQTT cover device registry integration.""" await help_test_entity_device_info_with_identifier( - hass, mqtt_mock_entry_no_yaml_config, cover.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, cover.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_entity_device_info_update(hass, mqtt_mock_entry_no_yaml_config): """Test device registry update.""" await help_test_entity_device_info_update( - hass, mqtt_mock_entry_no_yaml_config, cover.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, cover.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_entity_device_info_remove(hass, mqtt_mock_entry_no_yaml_config): """Test device registry remove.""" await help_test_entity_device_info_remove( - hass, mqtt_mock_entry_no_yaml_config, cover.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, cover.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_entity_id_update_subscriptions(hass, mqtt_mock_entry_with_yaml_config): """Test MQTT subscriptions are managed when entity_id is updated.""" await help_test_entity_id_update_subscriptions( - hass, mqtt_mock_entry_with_yaml_config, cover.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, cover.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_entity_id_update_discovery_update(hass, mqtt_mock_entry_no_yaml_config): """Test MQTT discovery update when entity_id is updated.""" await help_test_entity_id_update_discovery_update( - hass, mqtt_mock_entry_no_yaml_config, cover.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, cover.DOMAIN, DEFAULT_CONFIG_LEGACY ) @@ -2633,7 +2691,7 @@ async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config): hass, mqtt_mock_entry_no_yaml_config, cover.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, SERVICE_OPEN_COVER, command_payload="OPEN", ) @@ -2645,19 +2703,20 @@ async def test_state_and_position_topics_state_not_set_via_position_topic( """Test state is not set via position topic when both state and position topics are set.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "position_topic": "get-position-topic", - "position_open": 100, - "position_closed": 0, - "state_open": "OPEN", - "state_closed": "CLOSE", - "command_topic": "command-topic", - "qos": 0, + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "position_topic": "get-position-topic", + "position_open": 100, + "position_closed": 0, + "state_open": "OPEN", + "state_closed": "CLOSE", + "command_topic": "command-topic", + "qos": 0, + } } }, ) @@ -2705,20 +2764,21 @@ async def test_set_state_via_position_using_stopped_state( """Test the controlling state via position topic using stopped state.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "position_topic": "get-position-topic", - "position_open": 100, - "position_closed": 0, - "state_open": "OPEN", - "state_closed": "CLOSE", - "state_stopped": "STOPPED", - "command_topic": "command-topic", - "qos": 0, + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "position_topic": "get-position-topic", + "position_open": 100, + "position_closed": 0, + "state_open": "OPEN", + "state_closed": "CLOSE", + "state_stopped": "STOPPED", + "command_topic": "command-topic", + "qos": 0, + } } }, ) @@ -2761,16 +2821,17 @@ async def test_position_via_position_topic_template( """Test position by updating status via position template.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "set_position_topic": "set-position-topic", - "position_topic": "get-position-topic", - "position_template": "{{ (value | multiply(0.01)) | int }}", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "set_position_topic": "set-position-topic", + "position_topic": "get-position-topic", + "position_template": "{{ (value | multiply(0.01)) | int }}", + } } }, ) @@ -2798,16 +2859,17 @@ async def test_position_via_position_topic_template_json_value( """Test position by updating status via position template with a JSON value.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "set_position_topic": "set-position-topic", - "position_topic": "get-position-topic", - "position_template": "{{ value_json.Var1 }}", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "set_position_topic": "set-position-topic", + "position_topic": "get-position-topic", + "position_template": "{{ value_json.Var1 }}", + } } }, ) @@ -2839,21 +2901,22 @@ async def test_position_template_with_entity_id(hass, mqtt_mock_entry_with_yaml_ """Test position by updating status via position template.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "set_position_topic": "set-position-topic", - "position_topic": "get-position-topic", - "position_template": '\ + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "set_position_topic": "set-position-topic", + "position_topic": "get-position-topic", + "position_template": '\ {% if state_attr(entity_id, "current_position") != None %}\ {{ value | int + state_attr(entity_id, "current_position") }} \ {% else %} \ {{ value }} \ {% endif %}', + } } }, ) @@ -2881,16 +2944,17 @@ async def test_position_via_position_topic_template_return_json( """Test position by updating status via position template and returning json.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "set_position_topic": "set-position-topic", - "position_topic": "get-position-topic", - "position_template": '{{ {"position" : value} | tojson }}', + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "set_position_topic": "set-position-topic", + "position_topic": "get-position-topic", + "position_template": '{{ {"position" : value} | tojson }}', + } } }, ) @@ -2911,16 +2975,17 @@ async def test_position_via_position_topic_template_return_json_warning( """Test position by updating status via position template returning json without position attribute.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "set_position_topic": "set-position-topic", - "position_topic": "get-position-topic", - "position_template": '{{ {"pos" : value} | tojson }}', + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "set_position_topic": "set-position-topic", + "position_topic": "get-position-topic", + "position_template": '{{ {"pos" : value} | tojson }}', + } } }, ) @@ -2941,17 +3006,18 @@ async def test_position_and_tilt_via_position_topic_template_return_json( """Test position and tilt by updating the position via position template.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "set_position_topic": "set-position-topic", - "position_topic": "get-position-topic", - "position_template": '\ + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "set_position_topic": "set-position-topic", + "position_topic": "get-position-topic", + "position_template": '\ {{ {"position" : value, "tilt_position" : (value | int / 2)| int } | tojson }}', + } } }, ) @@ -2984,27 +3050,28 @@ async def test_position_via_position_topic_template_all_variables( """Test position by updating status via position template.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "set_position_topic": "set-position-topic", - "position_topic": "get-position-topic", - "tilt_command_topic": "tilt-command-topic", - "position_open": 99, - "position_closed": 1, - "tilt_min": 11, - "tilt_max": 22, - "position_template": "\ + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "set_position_topic": "set-position-topic", + "position_topic": "get-position-topic", + "tilt_command_topic": "tilt-command-topic", + "position_open": 99, + "position_closed": 1, + "tilt_min": 11, + "tilt_max": 22, + "position_template": "\ {% if value | int < tilt_max %}\ {{ tilt_min }}\ {% endif %}\ {% if value | int > position_closed %}\ {{ position_open }}\ {% endif %}", + } } }, ) @@ -3031,20 +3098,21 @@ async def test_set_state_via_stopped_state_no_position_topic( """Test the controlling state via stopped state when no position topic.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "state_open": "OPEN", - "state_closed": "CLOSE", - "state_stopped": "STOPPED", - "state_opening": "OPENING", - "state_closing": "CLOSING", - "command_topic": "command-topic", - "qos": 0, - "optimistic": False, + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "state_open": "OPEN", + "state_closed": "CLOSE", + "state_stopped": "STOPPED", + "state_opening": "OPENING", + "state_closing": "CLOSING", + "command_topic": "command-topic", + "qos": 0, + "optimistic": False, + } } }, ) @@ -3083,16 +3151,17 @@ async def test_position_via_position_topic_template_return_invalid_json( """Test position by updating status via position template and returning invalid json.""" assert await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "set_position_topic": "set-position-topic", - "position_topic": "get-position-topic", - "position_template": '{{ {"position" : invalid_json} }}', + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "set_position_topic": "set-position-topic", + "position_topic": "get-position-topic", + "position_template": '{{ {"position" : invalid_json} }}', + } } }, ) @@ -3104,74 +3173,65 @@ async def test_position_via_position_topic_template_return_invalid_json( assert ("Payload '{'position': Undefined}' is not numeric") in caplog.text -async def test_set_position_topic_without_get_position_topic_error( - hass, caplog, mqtt_mock_entry_no_yaml_config -): +async def test_set_position_topic_without_get_position_topic_error(hass, caplog): """Test error when set_position_topic is used without position_topic.""" - assert await async_setup_component( + assert not await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "command-topic", - "set_position_topic": "set-position-topic", - "value_template": "{{100-62}}", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "command_topic": "command-topic", + "set_position_topic": "set-position-topic", + "value_template": "{{100-62}}", + } } }, ) - await hass.async_block_till_done() - await mqtt_mock_entry_no_yaml_config() - assert ( f"'{CONF_SET_POSITION_TOPIC}' must be set together with '{CONF_GET_POSITION_TOPIC}'." ) in caplog.text async def test_value_template_without_state_topic_error( - hass, caplog, mqtt_mock_entry_no_yaml_config + hass, + caplog, ): """Test error when value_template is used and state_topic is missing.""" - assert await async_setup_component( + assert not await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "command-topic", - "value_template": "{{100-62}}", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "command_topic": "command-topic", + "value_template": "{{100-62}}", + } } }, ) - await hass.async_block_till_done() - await mqtt_mock_entry_no_yaml_config() - assert ( f"'{CONF_VALUE_TEMPLATE}' must be set together with '{CONF_STATE_TOPIC}'." ) in caplog.text -async def test_position_template_without_position_topic_error( - hass, caplog, mqtt_mock_entry_no_yaml_config -): +async def test_position_template_without_position_topic_error(hass, caplog): """Test error when position_template is used and position_topic is missing.""" - assert await async_setup_component( + assert not await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "command-topic", - "position_template": "{{100-52}}", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "command_topic": "command-topic", + "position_template": "{{100-52}}", + } } }, ) - await hass.async_block_till_done() - await mqtt_mock_entry_no_yaml_config() - assert ( f"'{CONF_GET_POSITION_TEMPLATE}' must be set together with '{CONF_GET_POSITION_TOPIC}'." in caplog.text @@ -3179,74 +3239,65 @@ async def test_position_template_without_position_topic_error( async def test_set_position_template_without_set_position_topic( - hass, caplog, mqtt_mock_entry_no_yaml_config + hass, + caplog, ): """Test error when set_position_template is used and set_position_topic is missing.""" - assert await async_setup_component( + assert not await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "command-topic", - "set_position_template": "{{100-42}}", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "command_topic": "command-topic", + "set_position_template": "{{100-42}}", + } } }, ) - await hass.async_block_till_done() - await mqtt_mock_entry_no_yaml_config() - assert ( f"'{CONF_SET_POSITION_TEMPLATE}' must be set together with '{CONF_SET_POSITION_TOPIC}'." in caplog.text ) -async def test_tilt_command_template_without_tilt_command_topic( - hass, caplog, mqtt_mock_entry_no_yaml_config -): +async def test_tilt_command_template_without_tilt_command_topic(hass, caplog): """Test error when tilt_command_template is used and tilt_command_topic is missing.""" - assert await async_setup_component( + assert not await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "command-topic", - "tilt_command_template": "{{100-32}}", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "command_topic": "command-topic", + "tilt_command_template": "{{100-32}}", + } } }, ) - await hass.async_block_till_done() - await mqtt_mock_entry_no_yaml_config() - assert ( f"'{CONF_TILT_COMMAND_TEMPLATE}' must be set together with '{CONF_TILT_COMMAND_TOPIC}'." in caplog.text ) -async def test_tilt_status_template_without_tilt_status_topic_topic( - hass, caplog, mqtt_mock_entry_no_yaml_config -): +async def test_tilt_status_template_without_tilt_status_topic_topic(hass, caplog): """Test error when tilt_status_template is used and tilt_status_topic is missing.""" - assert await async_setup_component( + assert not await async_setup_component( hass, - cover.DOMAIN, + mqtt.DOMAIN, { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "command-topic", - "tilt_status_template": "{{100-22}}", + mqtt.DOMAIN: { + cover.DOMAIN: { + "name": "test", + "command_topic": "command-topic", + "tilt_status_template": "{{100-22}}", + } } }, ) - await hass.async_block_till_done() - await mqtt_mock_entry_no_yaml_config() - assert ( f"'{CONF_TILT_STATUS_TEMPLATE}' must be set together with '{CONF_TILT_STATUS_TOPIC}'." in caplog.text @@ -3291,7 +3342,7 @@ async def test_publishing_with_custom_encoding( ): """Test publishing MQTT payload with different encoding.""" domain = cover.DOMAIN - config = DEFAULT_CONFIG[domain] + config = DEFAULT_CONFIG_LEGACY[domain] config["position_topic"] = "some-position-topic" await help_test_publishing_with_custom_encoding( @@ -3311,7 +3362,7 @@ async def test_publishing_with_custom_encoding( async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path): """Test reloading the MQTT platform.""" domain = cover.DOMAIN - config = DEFAULT_CONFIG[domain] + config = DEFAULT_CONFIG_LEGACY[domain] await help_test_reloadable( hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config ) @@ -3320,7 +3371,7 @@ async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_pa async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path): """Test reloading the MQTT platform with late entry setup.""" domain = cover.DOMAIN - config = DEFAULT_CONFIG[domain] + config = DEFAULT_CONFIG_LEGACY[domain] await help_test_reloadable_late(hass, caplog, tmp_path, domain, config) @@ -3348,7 +3399,7 @@ async def test_encoding_subscribable_topics( mqtt_mock_entry_with_yaml_config, caplog, cover.DOMAIN, - DEFAULT_CONFIG[cover.DOMAIN], + DEFAULT_CONFIG_LEGACY[cover.DOMAIN], topic, value, attribute, @@ -3360,7 +3411,7 @@ async def test_encoding_subscribable_topics( async def test_setup_manual_entity_from_yaml(hass): """Test setup manual configured MQTT entity.""" platform = cover.DOMAIN - config = copy.deepcopy(DEFAULT_CONFIG[platform]) + config = copy.deepcopy(DEFAULT_CONFIG_LEGACY[platform]) config["name"] = "test" del config["platform"] await help_test_setup_manual_entity_from_yaml(hass, platform, config) @@ -3370,7 +3421,20 @@ async def test_setup_manual_entity_from_yaml(hass): async def test_unload_entry(hass, mqtt_mock_entry_with_yaml_config, tmp_path): """Test unloading the config entry.""" domain = cover.DOMAIN - config = DEFAULT_CONFIG[domain] + config = DEFAULT_CONFIG_LEGACY[domain] await help_test_unload_config_entry_with_platform( hass, mqtt_mock_entry_with_yaml_config, tmp_path, domain, config ) + + +# Test deprecated YAML configuration under the platform key +# Scheduled to be removed in HA core 2022.12 +async def test_setup_with_legacy_schema(hass, mqtt_mock_entry_with_yaml_config): + """Test a setup with deprecated yaml platform schema.""" + domain = cover.DOMAIN + config = copy.deepcopy(DEFAULT_CONFIG_LEGACY[domain]) + config["name"] = "test" + assert await async_setup_component(hass, domain, {domain: config}) + await hass.async_block_till_done() + await mqtt_mock_entry_with_yaml_config() + assert hass.states.get(f"{domain}.test") is not None diff --git a/tests/components/mqtt/test_device_tracker.py b/tests/components/mqtt/test_device_tracker.py index 6708703ddbb..db6e0a292d7 100644 --- a/tests/components/mqtt/test_device_tracker.py +++ b/tests/components/mqtt/test_device_tracker.py @@ -1,10 +1,11 @@ -"""The tests for the MQTT device tracker platform using configuration.yaml.""" +"""The tests for the MQTT device tracker platform using configuration.yaml with legacy schema.""" import json from unittest.mock import patch import pytest -from homeassistant.components.device_tracker.const import DOMAIN, SOURCE_TYPE_BLUETOOTH +from homeassistant.components import device_tracker +from homeassistant.components.device_tracker import SourceType from homeassistant.config_entries import ConfigEntryDisabler from homeassistant.const import CONF_PLATFORM, STATE_HOME, STATE_NOT_HOME, Platform from homeassistant.setup import async_setup_component @@ -12,7 +13,6 @@ from homeassistant.setup import async_setup_component from .test_common import ( MockConfigEntry, help_test_entry_reload_with_new_config, - help_test_setup_manual_entity_from_yaml, help_test_unload_config_entry, ) @@ -45,7 +45,14 @@ async def test_legacy_ensure_device_tracker_platform_validation( dev_id = "paulus" topic = "/location/paulus" assert await async_setup_component( - hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "mqtt", "devices": {dev_id: topic}}} + hass, + device_tracker.DOMAIN, + { + device_tracker.DOMAIN: { + CONF_PLATFORM: "mqtt", + "devices": {dev_id: topic}, + } + }, ) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -59,13 +66,15 @@ async def test_legacy_new_message( """Test new message.""" await mqtt_mock_entry_no_yaml_config() dev_id = "paulus" - entity_id = f"{DOMAIN}.{dev_id}" + entity_id = f"{device_tracker.DOMAIN}.{dev_id}" topic = "/location/paulus" location = "work" hass.config.components = {"mqtt", "zone"} assert await async_setup_component( - hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "mqtt", "devices": {dev_id: topic}}} + hass, + device_tracker.DOMAIN, + {device_tracker.DOMAIN: {CONF_PLATFORM: "mqtt", "devices": {dev_id: topic}}}, ) async_fire_mqtt_message(hass, topic, location) await hass.async_block_till_done() @@ -79,7 +88,7 @@ async def test_legacy_single_level_wildcard_topic( """Test single level wildcard topic.""" await mqtt_mock_entry_no_yaml_config() dev_id = "paulus" - entity_id = f"{DOMAIN}.{dev_id}" + entity_id = f"{device_tracker.DOMAIN}.{dev_id}" subscription = "/location/+/paulus" topic = "/location/room/paulus" location = "work" @@ -87,8 +96,13 @@ async def test_legacy_single_level_wildcard_topic( hass.config.components = {"mqtt", "zone"} assert await async_setup_component( hass, - DOMAIN, - {DOMAIN: {CONF_PLATFORM: "mqtt", "devices": {dev_id: subscription}}}, + device_tracker.DOMAIN, + { + device_tracker.DOMAIN: { + CONF_PLATFORM: "mqtt", + "devices": {dev_id: subscription}, + } + }, ) async_fire_mqtt_message(hass, topic, location) await hass.async_block_till_done() @@ -102,7 +116,7 @@ async def test_legacy_multi_level_wildcard_topic( """Test multi level wildcard topic.""" await mqtt_mock_entry_no_yaml_config() dev_id = "paulus" - entity_id = f"{DOMAIN}.{dev_id}" + entity_id = f"{device_tracker.DOMAIN}.{dev_id}" subscription = "/location/#" topic = "/location/room/paulus" location = "work" @@ -110,8 +124,13 @@ async def test_legacy_multi_level_wildcard_topic( hass.config.components = {"mqtt", "zone"} assert await async_setup_component( hass, - DOMAIN, - {DOMAIN: {CONF_PLATFORM: "mqtt", "devices": {dev_id: subscription}}}, + device_tracker.DOMAIN, + { + device_tracker.DOMAIN: { + CONF_PLATFORM: "mqtt", + "devices": {dev_id: subscription}, + } + }, ) async_fire_mqtt_message(hass, topic, location) await hass.async_block_till_done() @@ -125,7 +144,7 @@ async def test_legacy_single_level_wildcard_topic_not_matching( """Test not matching single level wildcard topic.""" await mqtt_mock_entry_no_yaml_config() dev_id = "paulus" - entity_id = f"{DOMAIN}.{dev_id}" + entity_id = f"{device_tracker.DOMAIN}.{dev_id}" subscription = "/location/+/paulus" topic = "/location/paulus" location = "work" @@ -133,8 +152,13 @@ async def test_legacy_single_level_wildcard_topic_not_matching( hass.config.components = {"mqtt", "zone"} assert await async_setup_component( hass, - DOMAIN, - {DOMAIN: {CONF_PLATFORM: "mqtt", "devices": {dev_id: subscription}}}, + device_tracker.DOMAIN, + { + device_tracker.DOMAIN: { + CONF_PLATFORM: "mqtt", + "devices": {dev_id: subscription}, + } + }, ) async_fire_mqtt_message(hass, topic, location) await hass.async_block_till_done() @@ -148,7 +172,7 @@ async def test_legacy_multi_level_wildcard_topic_not_matching( """Test not matching multi level wildcard topic.""" await mqtt_mock_entry_no_yaml_config() dev_id = "paulus" - entity_id = f"{DOMAIN}.{dev_id}" + entity_id = f"{device_tracker.DOMAIN}.{dev_id}" subscription = "/location/#" topic = "/somewhere/room/paulus" location = "work" @@ -156,8 +180,13 @@ async def test_legacy_multi_level_wildcard_topic_not_matching( hass.config.components = {"mqtt", "zone"} assert await async_setup_component( hass, - DOMAIN, - {DOMAIN: {CONF_PLATFORM: "mqtt", "devices": {dev_id: subscription}}}, + device_tracker.DOMAIN, + { + device_tracker.DOMAIN: { + CONF_PLATFORM: "mqtt", + "devices": {dev_id: subscription}, + } + }, ) async_fire_mqtt_message(hass, topic, location) await hass.async_block_till_done() @@ -171,7 +200,7 @@ async def test_legacy_matching_custom_payload_for_home_and_not_home( """Test custom payload_home sets state to home and custom payload_not_home sets state to not_home.""" await mqtt_mock_entry_no_yaml_config() dev_id = "paulus" - entity_id = f"{DOMAIN}.{dev_id}" + entity_id = f"{device_tracker.DOMAIN}.{dev_id}" topic = "/location/paulus" payload_home = "present" payload_not_home = "not present" @@ -179,9 +208,9 @@ async def test_legacy_matching_custom_payload_for_home_and_not_home( hass.config.components = {"mqtt", "zone"} assert await async_setup_component( hass, - DOMAIN, + device_tracker.DOMAIN, { - DOMAIN: { + device_tracker.DOMAIN: { CONF_PLATFORM: "mqtt", "devices": {dev_id: topic}, "payload_home": payload_home, @@ -205,7 +234,7 @@ async def test_legacy_not_matching_custom_payload_for_home_and_not_home( """Test not matching payload does not set state to home or not_home.""" await mqtt_mock_entry_no_yaml_config() dev_id = "paulus" - entity_id = f"{DOMAIN}.{dev_id}" + entity_id = f"{device_tracker.DOMAIN}.{dev_id}" topic = "/location/paulus" payload_home = "present" payload_not_home = "not present" @@ -214,9 +243,9 @@ async def test_legacy_not_matching_custom_payload_for_home_and_not_home( hass.config.components = {"mqtt", "zone"} assert await async_setup_component( hass, - DOMAIN, + device_tracker.DOMAIN, { - DOMAIN: { + device_tracker.DOMAIN: { CONF_PLATFORM: "mqtt", "devices": {dev_id: topic}, "payload_home": payload_home, @@ -237,17 +266,17 @@ async def test_legacy_matching_source_type( """Test setting source type.""" await mqtt_mock_entry_no_yaml_config() dev_id = "paulus" - entity_id = f"{DOMAIN}.{dev_id}" + entity_id = f"{device_tracker.DOMAIN}.{dev_id}" topic = "/location/paulus" - source_type = SOURCE_TYPE_BLUETOOTH + source_type = SourceType.BLUETOOTH location = "work" hass.config.components = {"mqtt", "zone"} assert await async_setup_component( hass, - DOMAIN, + device_tracker.DOMAIN, { - DOMAIN: { + device_tracker.DOMAIN: { CONF_PLATFORM: "mqtt", "devices": {dev_id: topic}, "source_type": source_type, @@ -257,23 +286,10 @@ async def test_legacy_matching_source_type( async_fire_mqtt_message(hass, topic, location) await hass.async_block_till_done() - assert hass.states.get(entity_id).attributes["source_type"] == SOURCE_TYPE_BLUETOOTH - - -async def test_setup_with_modern_schema(hass, mock_device_tracker_conf): - """Test setup using the modern schema.""" - dev_id = "jan" - entity_id = f"{DOMAIN}.{dev_id}" - topic = "/location/jan" - - hass.config.components = {"zone"} - config = {"name": dev_id, "state_topic": topic} - - await help_test_setup_manual_entity_from_yaml(hass, DOMAIN, config) - - assert hass.states.get(entity_id) is not None + assert hass.states.get(entity_id).attributes["source_type"] == SourceType.BLUETOOTH +# Deprecated in HA Core 2022.6 async def test_unload_entry( hass, mock_device_tracker_conf, mqtt_mock_entry_no_yaml_config, tmp_path ): @@ -281,13 +297,15 @@ async def test_unload_entry( # setup through configuration.yaml await mqtt_mock_entry_no_yaml_config() dev_id = "jan" - entity_id = f"{DOMAIN}.{dev_id}" + entity_id = f"{device_tracker.DOMAIN}.{dev_id}" topic = "/location/jan" location = "home" hass.config.components = {"mqtt", "zone"} assert await async_setup_component( - hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "mqtt", "devices": {dev_id: topic}}} + hass, + device_tracker.DOMAIN, + {device_tracker.DOMAIN: {CONF_PLATFORM: "mqtt", "devices": {dev_id: topic}}}, ) async_fire_mqtt_message(hass, topic, location) await hass.async_block_till_done() @@ -296,7 +314,7 @@ async def test_unload_entry( # setup through discovery dev_id = "piet" subscription = "/location/#" - domain = DOMAIN + domain = device_tracker.DOMAIN discovery_config = { "devices": {dev_id: subscription}, "state_topic": "some-state", @@ -330,21 +348,22 @@ async def test_unload_entry( assert discovery_setup_entity is None +# Deprecated in HA Core 2022.6 async def test_reload_entry_legacy( hass, mock_device_tracker_conf, mqtt_mock_entry_no_yaml_config, tmp_path ): """Test reloading the config entry with manual MQTT items.""" # setup through configuration.yaml await mqtt_mock_entry_no_yaml_config() - entity_id = f"{DOMAIN}.jan" + entity_id = f"{device_tracker.DOMAIN}.jan" topic = "location/jan" location = "home" config = { - DOMAIN: {CONF_PLATFORM: "mqtt", "devices": {"jan": topic}}, + device_tracker.DOMAIN: {CONF_PLATFORM: "mqtt", "devices": {"jan": topic}}, } hass.config.components = {"mqtt", "zone"} - assert await async_setup_component(hass, DOMAIN, config) + assert await async_setup_component(hass, device_tracker.DOMAIN, config) await hass.async_block_till_done() async_fire_mqtt_message(hass, topic, location) @@ -360,6 +379,7 @@ async def test_reload_entry_legacy( assert hass.states.get(entity_id).state == location +# Deprecated in HA Core 2022.6 async def test_setup_with_disabled_entry( hass, mock_device_tracker_conf, caplog ) -> None: @@ -372,11 +392,11 @@ async def test_setup_with_disabled_entry( topic = "location/jan" config = { - DOMAIN: {CONF_PLATFORM: "mqtt", "devices": {"jan": topic}}, + device_tracker.DOMAIN: {CONF_PLATFORM: "mqtt", "devices": {"jan": topic}}, } hass.config.components = {"mqtt", "zone"} - await async_setup_component(hass, DOMAIN, config) + await async_setup_component(hass, device_tracker.DOMAIN, config) await hass.async_block_till_done() assert ( diff --git a/tests/components/mqtt/test_device_tracker_discovery.py b/tests/components/mqtt/test_device_tracker_discovery.py index ac4058c9372..923ae7c9f75 100644 --- a/tests/components/mqtt/test_device_tracker_discovery.py +++ b/tests/components/mqtt/test_device_tracker_discovery.py @@ -1,27 +1,37 @@ -"""The tests for the MQTT device_tracker discovery platform.""" +"""The tests for the MQTT device_tracker platform.""" +import copy from unittest.mock import patch import pytest -from homeassistant.components import device_tracker +from homeassistant.components import device_tracker, mqtt from homeassistant.components.mqtt.const import DOMAIN as MQTT_DOMAIN from homeassistant.components.mqtt.discovery import ALREADY_DISCOVERED from homeassistant.const import STATE_HOME, STATE_NOT_HOME, STATE_UNKNOWN, Platform from homeassistant.setup import async_setup_component -from .test_common import help_test_setting_blocked_attribute_via_mqtt_json_message +from .test_common import ( + help_test_setting_blocked_attribute_via_mqtt_json_message, + help_test_setup_manual_entity_from_yaml, +) from tests.common import async_fire_mqtt_message, mock_device_registry, mock_registry DEFAULT_CONFIG = { - device_tracker.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "test-topic", + mqtt.DOMAIN: { + device_tracker.DOMAIN: { + "name": "test", + "state_topic": "test-topic", + } } } +# Test deprecated YAML configuration under the platform key +# Scheduled to be removed in HA core 2022.12 +DEFAULT_CONFIG_LEGACY = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) +DEFAULT_CONFIG_LEGACY[device_tracker.DOMAIN]["platform"] = mqtt.DOMAIN + @pytest.fixture(autouse=True) def device_tracker_platform_only(): @@ -430,6 +440,19 @@ async def test_setting_blocked_attribute_via_mqtt_json_message( hass, mqtt_mock_entry_no_yaml_config, device_tracker.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, None, ) + + +async def test_setup_with_modern_schema(hass, mock_device_tracker_conf): + """Test setup using the modern schema.""" + dev_id = "jan" + entity_id = f"{device_tracker.DOMAIN}.{dev_id}" + topic = "/location/jan" + + config = {"name": dev_id, "state_topic": topic} + + await help_test_setup_manual_entity_from_yaml(hass, device_tracker.DOMAIN, config) + + assert hass.states.get(entity_id) is not None diff --git a/tests/components/mqtt/test_fan.py b/tests/components/mqtt/test_fan.py index 37dcefc9d3f..efe38234aee 100644 --- a/tests/components/mqtt/test_fan.py +++ b/tests/components/mqtt/test_fan.py @@ -5,7 +5,7 @@ from unittest.mock import patch import pytest from voluptuous.error import MultipleInvalid -from homeassistant.components import fan +from homeassistant.components import fan, mqtt from homeassistant.components.fan import ( ATTR_OSCILLATING, ATTR_PERCENTAGE, @@ -67,14 +67,20 @@ from tests.common import async_fire_mqtt_message from tests.components.fan import common DEFAULT_CONFIG = { - fan.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", + mqtt.DOMAIN: { + fan.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + } } } +# Test deprecated YAML configuration under the platform key +# Scheduled to be removed in HA core 2022.12 +DEFAULT_CONFIG_LEGACY = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) +DEFAULT_CONFIG_LEGACY[fan.DOMAIN]["platform"] = mqtt.DOMAIN + @pytest.fixture(autouse=True) def fan_platform_only(): @@ -83,18 +89,15 @@ def fan_platform_only(): yield -async def test_fail_setup_if_no_command_topic( - hass, caplog, mqtt_mock_entry_no_yaml_config -): +async def test_fail_setup_if_no_command_topic(hass, caplog): """Test if command fails with command topic.""" - assert await async_setup_component( - hass, fan.DOMAIN, {fan.DOMAIN: {"platform": "mqtt", "name": "test"}} + assert not await async_setup_component( + hass, + mqtt.DOMAIN, + {mqtt.DOMAIN: {fan.DOMAIN: {"name": "test"}}}, ) - await hass.async_block_till_done() - await mqtt_mock_entry_no_yaml_config() - assert hass.states.get("fan.test") is None assert ( - "Invalid config for [fan.mqtt]: required key not provided @ data['command_topic']" + "Invalid config for [mqtt]: required key not provided @ data['mqtt']['fan'][0]['command_topic']" in caplog.text ) @@ -105,35 +108,36 @@ async def test_controlling_state_via_topic( """Test the controlling state via topic.""" assert await async_setup_component( hass, - fan.DOMAIN, + mqtt.DOMAIN, { - fan.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "payload_off": "StAtE_OfF", - "payload_on": "StAtE_On", - "oscillation_state_topic": "oscillation-state-topic", - "oscillation_command_topic": "oscillation-command-topic", - "payload_oscillation_off": "OsC_OfF", - "payload_oscillation_on": "OsC_On", - "percentage_state_topic": "percentage-state-topic", - "percentage_command_topic": "percentage-command-topic", - "preset_mode_state_topic": "preset-mode-state-topic", - "preset_mode_command_topic": "preset-mode-command-topic", - "preset_modes": [ - "auto", - "smart", - "whoosh", - "eco", - "breeze", - "silent", - ], - "speed_range_min": 1, - "speed_range_max": 200, - "payload_reset_percentage": "rEset_percentage", - "payload_reset_preset_mode": "rEset_preset_mode", + mqtt.DOMAIN: { + fan.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "payload_off": "StAtE_OfF", + "payload_on": "StAtE_On", + "oscillation_state_topic": "oscillation-state-topic", + "oscillation_command_topic": "oscillation-command-topic", + "payload_oscillation_off": "OsC_OfF", + "payload_oscillation_on": "OsC_On", + "percentage_state_topic": "percentage-state-topic", + "percentage_command_topic": "percentage-command-topic", + "preset_mode_state_topic": "preset-mode-state-topic", + "preset_mode_command_topic": "preset-mode-command-topic", + "preset_modes": [ + "auto", + "smart", + "whoosh", + "eco", + "breeze", + "silent", + ], + "speed_range_min": 1, + "speed_range_max": 200, + "payload_reset_percentage": "rEset_percentage", + "payload_reset_preset_mode": "rEset_preset_mode", + } } }, ) @@ -226,37 +230,36 @@ async def test_controlling_state_via_topic_with_different_speed_range( """Test the controlling state via topic using an alternate speed range.""" assert await async_setup_component( hass, - fan.DOMAIN, + mqtt.DOMAIN, { - fan.DOMAIN: [ - { - "platform": "mqtt", - "name": "test1", - "command_topic": "command-topic", - "percentage_state_topic": "percentage-state-topic1", - "percentage_command_topic": "percentage-command-topic1", - "speed_range_min": 1, - "speed_range_max": 100, - }, - { - "platform": "mqtt", - "name": "test2", - "command_topic": "command-topic", - "percentage_state_topic": "percentage-state-topic2", - "percentage_command_topic": "percentage-command-topic2", - "speed_range_min": 1, - "speed_range_max": 200, - }, - { - "platform": "mqtt", - "name": "test3", - "command_topic": "command-topic", - "percentage_state_topic": "percentage-state-topic3", - "percentage_command_topic": "percentage-command-topic3", - "speed_range_min": 81, - "speed_range_max": 1023, - }, - ] + mqtt.DOMAIN: { + fan.DOMAIN: [ + { + "name": "test1", + "command_topic": "command-topic", + "percentage_state_topic": "percentage-state-topic1", + "percentage_command_topic": "percentage-command-topic1", + "speed_range_min": 1, + "speed_range_max": 100, + }, + { + "name": "test2", + "command_topic": "command-topic", + "percentage_state_topic": "percentage-state-topic2", + "percentage_command_topic": "percentage-command-topic2", + "speed_range_min": 1, + "speed_range_max": 200, + }, + { + "name": "test3", + "command_topic": "command-topic", + "percentage_state_topic": "percentage-state-topic3", + "percentage_command_topic": "percentage-command-topic3", + "speed_range_min": 81, + "speed_range_max": 1023, + }, + ] + } }, ) await hass.async_block_till_done() @@ -289,22 +292,23 @@ async def test_controlling_state_via_topic_no_percentage_topics( """Test the controlling state via topic without percentage topics.""" assert await async_setup_component( hass, - fan.DOMAIN, + mqtt.DOMAIN, { - fan.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "preset_mode_state_topic": "preset-mode-state-topic", - "preset_mode_command_topic": "preset-mode-command-topic", - "preset_modes": [ - "auto", - "smart", - "whoosh", - "eco", - "breeze", - ], + mqtt.DOMAIN: { + fan.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "preset_mode_state_topic": "preset-mode-state-topic", + "preset_mode_command_topic": "preset-mode-command-topic", + "preset_modes": [ + "auto", + "smart", + "whoosh", + "eco", + "breeze", + ], + } } }, ) @@ -345,33 +349,34 @@ async def test_controlling_state_via_topic_and_json_message( """Test the controlling state via topic and JSON message (percentage mode).""" assert await async_setup_component( hass, - fan.DOMAIN, + mqtt.DOMAIN, { - fan.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "oscillation_state_topic": "oscillation-state-topic", - "oscillation_command_topic": "oscillation-command-topic", - "percentage_state_topic": "percentage-state-topic", - "percentage_command_topic": "percentage-command-topic", - "preset_mode_state_topic": "preset-mode-state-topic", - "preset_mode_command_topic": "preset-mode-command-topic", - "preset_modes": [ - "auto", - "smart", - "whoosh", - "eco", - "breeze", - "silent", - ], - "state_value_template": "{{ value_json.val }}", - "oscillation_value_template": "{{ value_json.val }}", - "percentage_value_template": "{{ value_json.val }}", - "preset_mode_value_template": "{{ value_json.val }}", - "speed_range_min": 1, - "speed_range_max": 100, + mqtt.DOMAIN: { + fan.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "oscillation_state_topic": "oscillation-state-topic", + "oscillation_command_topic": "oscillation-command-topic", + "percentage_state_topic": "percentage-state-topic", + "percentage_command_topic": "percentage-command-topic", + "preset_mode_state_topic": "preset-mode-state-topic", + "preset_mode_command_topic": "preset-mode-command-topic", + "preset_modes": [ + "auto", + "smart", + "whoosh", + "eco", + "breeze", + "silent", + ], + "state_value_template": "{{ value_json.val }}", + "oscillation_value_template": "{{ value_json.val }}", + "percentage_value_template": "{{ value_json.val }}", + "preset_mode_value_template": "{{ value_json.val }}", + "speed_range_min": 1, + "speed_range_max": 100, + } } }, ) @@ -450,33 +455,34 @@ async def test_controlling_state_via_topic_and_json_message_shared_topic( """Test the controlling state via topic and JSON message using a shared topic.""" assert await async_setup_component( hass, - fan.DOMAIN, + mqtt.DOMAIN, { - fan.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "shared-state-topic", - "command_topic": "command-topic", - "oscillation_state_topic": "shared-state-topic", - "oscillation_command_topic": "oscillation-command-topic", - "percentage_state_topic": "shared-state-topic", - "percentage_command_topic": "percentage-command-topic", - "preset_mode_state_topic": "shared-state-topic", - "preset_mode_command_topic": "preset-mode-command-topic", - "preset_modes": [ - "auto", - "smart", - "whoosh", - "eco", - "breeze", - "silent", - ], - "state_value_template": "{{ value_json.state }}", - "oscillation_value_template": "{{ value_json.oscillation }}", - "percentage_value_template": "{{ value_json.percentage }}", - "preset_mode_value_template": "{{ value_json.preset_mode }}", - "speed_range_min": 1, - "speed_range_max": 100, + mqtt.DOMAIN: { + fan.DOMAIN: { + "name": "test", + "state_topic": "shared-state-topic", + "command_topic": "command-topic", + "oscillation_state_topic": "shared-state-topic", + "oscillation_command_topic": "oscillation-command-topic", + "percentage_state_topic": "shared-state-topic", + "percentage_command_topic": "percentage-command-topic", + "preset_mode_state_topic": "shared-state-topic", + "preset_mode_command_topic": "preset-mode-command-topic", + "preset_modes": [ + "auto", + "smart", + "whoosh", + "eco", + "breeze", + "silent", + ], + "state_value_template": "{{ value_json.state }}", + "oscillation_value_template": "{{ value_json.oscillation }}", + "percentage_value_template": "{{ value_json.percentage }}", + "preset_mode_value_template": "{{ value_json.preset_mode }}", + "speed_range_min": 1, + "speed_range_max": 100, + } } }, ) @@ -540,24 +546,25 @@ async def test_sending_mqtt_commands_and_optimistic( """Test optimistic mode without state topic.""" assert await async_setup_component( hass, - fan.DOMAIN, + mqtt.DOMAIN, { - fan.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "command-topic", - "payload_off": "StAtE_OfF", - "payload_on": "StAtE_On", - "oscillation_command_topic": "oscillation-command-topic", - "payload_oscillation_off": "OsC_OfF", - "payload_oscillation_on": "OsC_On", - "percentage_command_topic": "percentage-command-topic", - "preset_mode_command_topic": "preset-mode-command-topic", - "preset_modes": [ - "whoosh", - "breeze", - "silent", - ], + mqtt.DOMAIN: { + fan.DOMAIN: { + "name": "test", + "command_topic": "command-topic", + "payload_off": "StAtE_OfF", + "payload_on": "StAtE_On", + "oscillation_command_topic": "oscillation-command-topic", + "payload_oscillation_off": "OsC_OfF", + "payload_oscillation_on": "OsC_On", + "percentage_command_topic": "percentage-command-topic", + "preset_mode_command_topic": "preset-mode-command-topic", + "preset_modes": [ + "whoosh", + "breeze", + "silent", + ], + } } }, ) @@ -664,37 +671,36 @@ async def test_sending_mqtt_commands_with_alternate_speed_range( """Test the controlling state via topic using an alternate speed range.""" assert await async_setup_component( hass, - fan.DOMAIN, + mqtt.DOMAIN, { - fan.DOMAIN: [ - { - "platform": "mqtt", - "name": "test1", - "command_topic": "command-topic", - "percentage_state_topic": "percentage-state-topic1", - "percentage_command_topic": "percentage-command-topic1", - "speed_range_min": 1, - "speed_range_max": 3, - }, - { - "platform": "mqtt", - "name": "test2", - "command_topic": "command-topic", - "percentage_state_topic": "percentage-state-topic2", - "percentage_command_topic": "percentage-command-topic2", - "speed_range_min": 1, - "speed_range_max": 200, - }, - { - "platform": "mqtt", - "name": "test3", - "command_topic": "command-topic", - "percentage_state_topic": "percentage-state-topic3", - "percentage_command_topic": "percentage-command-topic3", - "speed_range_min": 81, - "speed_range_max": 1023, - }, - ] + mqtt.DOMAIN: { + fan.DOMAIN: [ + { + "name": "test1", + "command_topic": "command-topic", + "percentage_state_topic": "percentage-state-topic1", + "percentage_command_topic": "percentage-command-topic1", + "speed_range_min": 1, + "speed_range_max": 3, + }, + { + "name": "test2", + "command_topic": "command-topic", + "percentage_state_topic": "percentage-state-topic2", + "percentage_command_topic": "percentage-command-topic2", + "speed_range_min": 1, + "speed_range_max": 200, + }, + { + "name": "test3", + "command_topic": "command-topic", + "percentage_state_topic": "percentage-state-topic3", + "percentage_command_topic": "percentage-command-topic3", + "speed_range_min": 81, + "speed_range_max": 1023, + }, + ] + } }, ) await hass.async_block_till_done() @@ -771,19 +777,20 @@ async def test_sending_mqtt_commands_and_optimistic_no_legacy( """Test optimistic mode without state topic without legacy speed command topic.""" assert await async_setup_component( hass, - fan.DOMAIN, + mqtt.DOMAIN, { - fan.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "command-topic", - "percentage_command_topic": "percentage-command-topic", - "preset_mode_command_topic": "preset-mode-command-topic", - "preset_modes": [ - "whoosh", - "breeze", - "silent", - ], + mqtt.DOMAIN: { + fan.DOMAIN: { + "name": "test", + "command_topic": "command-topic", + "percentage_command_topic": "percentage-command-topic", + "preset_mode_command_topic": "preset-mode-command-topic", + "preset_modes": [ + "whoosh", + "breeze", + "silent", + ], + } } }, ) @@ -902,24 +909,25 @@ async def test_sending_mqtt_command_templates_( """Test optimistic mode without state topic without legacy speed command topic.""" assert await async_setup_component( hass, - fan.DOMAIN, + mqtt.DOMAIN, { - fan.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "command-topic", - "command_template": "state: {{ value }}", - "oscillation_command_topic": "oscillation-command-topic", - "oscillation_command_template": "oscillation: {{ value }}", - "percentage_command_topic": "percentage-command-topic", - "percentage_command_template": "percentage: {{ value }}", - "preset_mode_command_topic": "preset-mode-command-topic", - "preset_mode_command_template": "preset_mode: {{ value }}", - "preset_modes": [ - "whoosh", - "breeze", - "silent", - ], + mqtt.DOMAIN: { + fan.DOMAIN: { + "name": "test", + "command_topic": "command-topic", + "command_template": "state: {{ value }}", + "oscillation_command_topic": "oscillation-command-topic", + "oscillation_command_template": "oscillation: {{ value }}", + "percentage_command_topic": "percentage-command-topic", + "percentage_command_template": "percentage: {{ value }}", + "preset_mode_command_topic": "preset-mode-command-topic", + "preset_mode_command_template": "preset_mode: {{ value }}", + "preset_modes": [ + "whoosh", + "breeze", + "silent", + ], + } } }, ) @@ -1044,20 +1052,21 @@ async def test_sending_mqtt_commands_and_optimistic_no_percentage_topic( """Test optimistic mode without state topic without percentage command topic.""" assert await async_setup_component( hass, - fan.DOMAIN, + mqtt.DOMAIN, { - fan.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "command-topic", - "preset_mode_command_topic": "preset-mode-command-topic", - "preset_mode_state_topic": "preset-mode-state-topic", - "preset_modes": [ - "whoosh", - "breeze", - "silent", - "high", - ], + mqtt.DOMAIN: { + fan.DOMAIN: { + "name": "test", + "command_topic": "command-topic", + "preset_mode_command_topic": "preset-mode-command-topic", + "preset_mode_state_topic": "preset-mode-state-topic", + "preset_modes": [ + "whoosh", + "breeze", + "silent", + "high", + ], + } } }, ) @@ -1105,25 +1114,26 @@ async def test_sending_mqtt_commands_and_explicit_optimistic( """Test optimistic mode with state topic and turn on attributes.""" assert await async_setup_component( hass, - fan.DOMAIN, + mqtt.DOMAIN, { - fan.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "oscillation_state_topic": "oscillation-state-topic", - "oscillation_command_topic": "oscillation-command-topic", - "percentage_state_topic": "percentage-state-topic", - "percentage_command_topic": "percentage-command-topic", - "preset_mode_command_topic": "preset-mode-command-topic", - "preset_mode_state_topic": "preset-mode-state-topic", - "preset_modes": [ - "whoosh", - "breeze", - "silent", - ], - "optimistic": True, + mqtt.DOMAIN: { + fan.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "oscillation_state_topic": "oscillation-state-topic", + "oscillation_command_topic": "oscillation-command-topic", + "percentage_state_topic": "percentage-state-topic", + "percentage_command_topic": "percentage-command-topic", + "preset_mode_command_topic": "preset-mode-command-topic", + "preset_mode_state_topic": "preset-mode-state-topic", + "preset_modes": [ + "whoosh", + "breeze", + "silent", + ], + "optimistic": True, + } } }, ) @@ -1355,7 +1365,7 @@ async def test_encoding_subscribable_topics( attribute_value, ): """Test handling of incoming encoded payload.""" - config = copy.deepcopy(DEFAULT_CONFIG[fan.DOMAIN]) + config = copy.deepcopy(DEFAULT_CONFIG_LEGACY[fan.DOMAIN]) config[ATTR_PRESET_MODES] = ["eco", "auto"] config[CONF_PRESET_MODE_COMMAND_TOPIC] = "fan/some_preset_mode_command_topic" config[CONF_PERCENTAGE_COMMAND_TOPIC] = "fan/some_percentage_command_topic" @@ -1377,19 +1387,20 @@ async def test_attributes(hass, mqtt_mock_entry_with_yaml_config, caplog): """Test attributes.""" assert await async_setup_component( hass, - fan.DOMAIN, + mqtt.DOMAIN, { - fan.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "command-topic", - "oscillation_command_topic": "oscillation-command-topic", - "preset_mode_command_topic": "preset-mode-command-topic", - "percentage_command_topic": "percentage-command-topic", - "preset_modes": [ - "breeze", - "silent", - ], + mqtt.DOMAIN: { + fan.DOMAIN: { + "name": "test", + "command_topic": "command-topic", + "oscillation_command_topic": "oscillation-command-topic", + "preset_mode_command_topic": "preset-mode-command-topic", + "percentage_command_topic": "percentage-command-topic", + "preset_modes": [ + "breeze", + "silent", + ], + } } }, ) @@ -1424,177 +1435,203 @@ async def test_attributes(hass, mqtt_mock_entry_with_yaml_config, caplog): assert state.attributes.get(fan.ATTR_OSCILLATING) is False -async def test_supported_features(hass, mqtt_mock_entry_with_yaml_config): +@pytest.mark.parametrize( + "name,config,success,features", + [ + ( + "test1", + { + "name": "test1", + "command_topic": "command-topic", + }, + True, + 0, + ), + ( + "test2", + { + "name": "test2", + "command_topic": "command-topic", + "oscillation_command_topic": "oscillation-command-topic", + }, + True, + fan.SUPPORT_OSCILLATE, + ), + ( + "test3", + { + "name": "test3", + "command_topic": "command-topic", + "percentage_command_topic": "percentage-command-topic", + }, + True, + fan.SUPPORT_SET_SPEED, + ), + ( + "test4", + { + "name": "test4", + "command_topic": "command-topic", + "preset_mode_command_topic": "preset-mode-command-topic", + }, + False, + None, + ), + ( + "test5", + { + "name": "test5", + "command_topic": "command-topic", + "preset_mode_command_topic": "preset-mode-command-topic", + "preset_modes": ["eco", "auto"], + }, + True, + fan.SUPPORT_PRESET_MODE, + ), + ( + "test6", + { + "name": "test6", + "command_topic": "command-topic", + "preset_mode_command_topic": "preset-mode-command-topic", + "preset_modes": ["eco", "smart", "auto"], + }, + True, + fan.SUPPORT_PRESET_MODE, + ), + ( + "test7", + { + "name": "test7", + "command_topic": "command-topic", + "percentage_command_topic": "percentage-command-topic", + }, + True, + fan.SUPPORT_SET_SPEED, + ), + ( + "test8", + { + "name": "test8", + "command_topic": "command-topic", + "oscillation_command_topic": "oscillation-command-topic", + "percentage_command_topic": "percentage-command-topic", + }, + True, + fan.SUPPORT_OSCILLATE | fan.SUPPORT_SET_SPEED, + ), + ( + "test9", + { + "name": "test9", + "command_topic": "command-topic", + "preset_mode_command_topic": "preset-mode-command-topic", + "preset_modes": ["Mode1", "Mode2", "Mode3"], + }, + True, + fan.SUPPORT_PRESET_MODE, + ), + ( + "test10", + { + "name": "test10", + "command_topic": "command-topic", + "preset_mode_command_topic": "preset-mode-command-topic", + "preset_modes": ["whoosh", "silent", "auto"], + }, + True, + fan.SUPPORT_PRESET_MODE, + ), + ( + "test11", + { + "name": "test11", + "command_topic": "command-topic", + "oscillation_command_topic": "oscillation-command-topic", + "preset_mode_command_topic": "preset-mode-command-topic", + "preset_modes": ["Mode1", "Mode2", "Mode3"], + }, + True, + fan.SUPPORT_PRESET_MODE | fan.SUPPORT_OSCILLATE, + ), + ( + "test12", + { + "name": "test12", + "command_topic": "command-topic", + "percentage_command_topic": "percentage-command-topic", + "speed_range_min": 1, + "speed_range_max": 40, + }, + True, + fan.SUPPORT_SET_SPEED, + ), + ( + "test13", + { + "name": "test13", + "command_topic": "command-topic", + "percentage_command_topic": "percentage-command-topic", + "speed_range_min": 50, + "speed_range_max": 40, + }, + False, + None, + ), + ( + "test14", + { + "name": "test14", + "command_topic": "command-topic", + "percentage_command_topic": "percentage-command-topic", + "speed_range_min": 0, + "speed_range_max": 40, + }, + False, + None, + ), + ( + "test15", + { + "name": "test7reset_payload_in_preset_modes_a", + "command_topic": "command-topic", + "preset_mode_command_topic": "preset-mode-command-topic", + "preset_modes": ["auto", "smart", "normal", "None"], + }, + False, + None, + ), + ( + "test16", + { + "name": "test16", + "command_topic": "command-topic", + "preset_mode_command_topic": "preset-mode-command-topic", + "preset_modes": ["whoosh", "silent", "auto", "None"], + "payload_reset_preset_mode": "normal", + }, + True, + fan.SUPPORT_PRESET_MODE, + ), + ], +) +async def test_supported_features( + hass, mqtt_mock_entry_with_yaml_config, name, config, success, features +): """Test optimistic mode without state topic.""" - assert await async_setup_component( - hass, - fan.DOMAIN, - { - fan.DOMAIN: [ - { - "platform": "mqtt", - "name": "test1", - "command_topic": "command-topic", - }, - { - "platform": "mqtt", - "name": "test2", - "command_topic": "command-topic", - "oscillation_command_topic": "oscillation-command-topic", - }, - { - "platform": "mqtt", - "name": "test3b", - "command_topic": "command-topic", - "percentage_command_topic": "percentage-command-topic", - }, - { - "platform": "mqtt", - "name": "test3c1", - "command_topic": "command-topic", - "preset_mode_command_topic": "preset-mode-command-topic", - }, - { - "platform": "mqtt", - "name": "test3c2", - "command_topic": "command-topic", - "preset_mode_command_topic": "preset-mode-command-topic", - "preset_modes": ["eco", "auto"], - }, - { - "platform": "mqtt", - "name": "test3c3", - "command_topic": "command-topic", - "preset_mode_command_topic": "preset-mode-command-topic", - "preset_modes": ["eco", "smart", "auto"], - }, - { - "platform": "mqtt", - "name": "test4pcta", - "command_topic": "command-topic", - "percentage_command_topic": "percentage-command-topic", - }, - { - "platform": "mqtt", - "name": "test4pctb", - "command_topic": "command-topic", - "oscillation_command_topic": "oscillation-command-topic", - "percentage_command_topic": "percentage-command-topic", - }, - { - "platform": "mqtt", - "name": "test5pr_ma", - "command_topic": "command-topic", - "preset_mode_command_topic": "preset-mode-command-topic", - "preset_modes": ["Mode1", "Mode2", "Mode3"], - }, - { - "platform": "mqtt", - "name": "test5pr_mb", - "command_topic": "command-topic", - "preset_mode_command_topic": "preset-mode-command-topic", - "preset_modes": ["whoosh", "silent", "auto"], - }, - { - "platform": "mqtt", - "name": "test5pr_mc", - "command_topic": "command-topic", - "oscillation_command_topic": "oscillation-command-topic", - "preset_mode_command_topic": "preset-mode-command-topic", - "preset_modes": ["Mode1", "Mode2", "Mode3"], - }, - { - "platform": "mqtt", - "name": "test6spd_range_a", - "command_topic": "command-topic", - "percentage_command_topic": "percentage-command-topic", - "speed_range_min": 1, - "speed_range_max": 40, - }, - { - "platform": "mqtt", - "name": "test6spd_range_b", - "command_topic": "command-topic", - "percentage_command_topic": "percentage-command-topic", - "speed_range_min": 50, - "speed_range_max": 40, - }, - { - "platform": "mqtt", - "name": "test6spd_range_c", - "command_topic": "command-topic", - "percentage_command_topic": "percentage-command-topic", - "speed_range_min": 0, - "speed_range_max": 40, - }, - { - "platform": "mqtt", - "name": "test7reset_payload_in_preset_modes_a", - "command_topic": "command-topic", - "preset_mode_command_topic": "preset-mode-command-topic", - "preset_modes": ["auto", "smart", "normal", "None"], - }, - { - "platform": "mqtt", - "name": "test7reset_payload_in_preset_modes_b", - "command_topic": "command-topic", - "preset_mode_command_topic": "preset-mode-command-topic", - "preset_modes": ["whoosh", "silent", "auto", "None"], - "payload_reset_preset_mode": "normal", - }, - ] - }, - ) - await hass.async_block_till_done() - await mqtt_mock_entry_with_yaml_config() - state = hass.states.get("fan.test1") - assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 0 - state = hass.states.get("fan.test2") - assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == fan.SUPPORT_OSCILLATE - - state = hass.states.get("fan.test3b") - assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == fan.SUPPORT_SET_SPEED - - state = hass.states.get("fan.test3c1") - assert state is None - - state = hass.states.get("fan.test3c2") - assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == fan.SUPPORT_PRESET_MODE - state = hass.states.get("fan.test3c3") - assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == fan.SUPPORT_PRESET_MODE - - state = hass.states.get("fan.test4pcta") - assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == fan.SUPPORT_SET_SPEED - state = hass.states.get("fan.test4pctb") assert ( - state.attributes.get(ATTR_SUPPORTED_FEATURES) - == fan.SUPPORT_OSCILLATE | fan.SUPPORT_SET_SPEED + await async_setup_component( + hass, mqtt.DOMAIN, {mqtt.DOMAIN: {fan.DOMAIN: config}} + ) + is success ) + if success: + await hass.async_block_till_done() + await mqtt_mock_entry_with_yaml_config() - state = hass.states.get("fan.test5pr_ma") - assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == fan.SUPPORT_PRESET_MODE - state = hass.states.get("fan.test5pr_mb") - assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == fan.SUPPORT_PRESET_MODE - - state = hass.states.get("fan.test5pr_mc") - assert ( - state.attributes.get(ATTR_SUPPORTED_FEATURES) - == fan.SUPPORT_OSCILLATE | fan.SUPPORT_PRESET_MODE - ) - - state = hass.states.get("fan.test6spd_range_a") - assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == fan.SUPPORT_SET_SPEED - assert state.attributes.get("percentage_step") == 2.5 - state = hass.states.get("fan.test6spd_range_b") - assert state is None - state = hass.states.get("fan.test6spd_range_c") - assert state is None - - state = hass.states.get("fan.test7reset_payload_in_preset_modes_a") - assert state is None - state = hass.states.get("fan.test7reset_payload_in_preset_modes_b") - assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == fan.SUPPORT_PRESET_MODE + state = hass.states.get(f"fan.{name}") + assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == features async def test_availability_when_connection_lost( @@ -1602,14 +1639,14 @@ async def test_availability_when_connection_lost( ): """Test availability after MQTT disconnection.""" await help_test_availability_when_connection_lost( - hass, mqtt_mock_entry_with_yaml_config, fan.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, fan.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_availability_without_topic(hass, mqtt_mock_entry_with_yaml_config): """Test availability without defined availability topic.""" await help_test_availability_without_topic( - hass, mqtt_mock_entry_with_yaml_config, fan.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, fan.DOMAIN, DEFAULT_CONFIG_LEGACY ) @@ -1619,7 +1656,7 @@ async def test_default_availability_payload(hass, mqtt_mock_entry_with_yaml_conf hass, mqtt_mock_entry_with_yaml_config, fan.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, True, "state-topic", "1", @@ -1632,7 +1669,7 @@ async def test_custom_availability_payload(hass, mqtt_mock_entry_with_yaml_confi hass, mqtt_mock_entry_with_yaml_config, fan.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, True, "state-topic", "1", @@ -1644,7 +1681,7 @@ async def test_setting_attribute_via_mqtt_json_message( ): """Test the setting of attribute via MQTT with JSON payload.""" await help_test_setting_attribute_via_mqtt_json_message( - hass, mqtt_mock_entry_with_yaml_config, fan.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, fan.DOMAIN, DEFAULT_CONFIG_LEGACY ) @@ -1656,7 +1693,7 @@ async def test_setting_blocked_attribute_via_mqtt_json_message( hass, mqtt_mock_entry_no_yaml_config, fan.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, MQTT_FAN_ATTRIBUTES_BLOCKED, ) @@ -1664,7 +1701,7 @@ async def test_setting_blocked_attribute_via_mqtt_json_message( async def test_setting_attribute_with_template(hass, mqtt_mock_entry_with_yaml_config): """Test the setting of attribute via MQTT with JSON payload.""" await help_test_setting_attribute_with_template( - hass, mqtt_mock_entry_with_yaml_config, fan.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, fan.DOMAIN, DEFAULT_CONFIG_LEGACY ) @@ -1673,7 +1710,11 @@ async def test_update_with_json_attrs_not_dict( ): """Test attributes get extracted from a JSON result.""" await help_test_update_with_json_attrs_not_dict( - hass, mqtt_mock_entry_with_yaml_config, caplog, fan.DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_with_yaml_config, + caplog, + fan.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) @@ -1682,14 +1723,18 @@ async def test_update_with_json_attrs_bad_json( ): """Test attributes get extracted from a JSON result.""" await help_test_update_with_json_attrs_bad_JSON( - hass, mqtt_mock_entry_with_yaml_config, caplog, fan.DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_with_yaml_config, + caplog, + fan.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) async def test_discovery_update_attr(hass, mqtt_mock_entry_no_yaml_config, caplog): """Test update of discovered MQTTAttributes.""" await help_test_discovery_update_attr( - hass, mqtt_mock_entry_no_yaml_config, caplog, fan.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, caplog, fan.DOMAIN, DEFAULT_CONFIG_LEGACY ) @@ -1767,42 +1812,42 @@ async def test_discovery_broken(hass, mqtt_mock_entry_no_yaml_config, caplog): async def test_entity_device_info_with_connection(hass, mqtt_mock_entry_no_yaml_config): """Test MQTT fan device registry integration.""" await help_test_entity_device_info_with_connection( - hass, mqtt_mock_entry_no_yaml_config, fan.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, fan.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_entity_device_info_with_identifier(hass, mqtt_mock_entry_no_yaml_config): """Test MQTT fan device registry integration.""" await help_test_entity_device_info_with_identifier( - hass, mqtt_mock_entry_no_yaml_config, fan.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, fan.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_entity_device_info_update(hass, mqtt_mock_entry_no_yaml_config): """Test device registry update.""" await help_test_entity_device_info_update( - hass, mqtt_mock_entry_no_yaml_config, fan.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, fan.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_entity_device_info_remove(hass, mqtt_mock_entry_no_yaml_config): """Test device registry remove.""" await help_test_entity_device_info_remove( - hass, mqtt_mock_entry_no_yaml_config, fan.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, fan.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_entity_id_update_subscriptions(hass, mqtt_mock_entry_with_yaml_config): """Test MQTT subscriptions are managed when entity_id is updated.""" await help_test_entity_id_update_subscriptions( - hass, mqtt_mock_entry_with_yaml_config, fan.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, fan.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_entity_id_update_discovery_update(hass, mqtt_mock_entry_no_yaml_config): """Test MQTT discovery update when entity_id is updated.""" await help_test_entity_id_update_discovery_update( - hass, mqtt_mock_entry_no_yaml_config, fan.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, fan.DOMAIN, DEFAULT_CONFIG_LEGACY ) @@ -1812,7 +1857,7 @@ async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config): hass, mqtt_mock_entry_no_yaml_config, fan.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, fan.SERVICE_TURN_ON, ) @@ -1869,7 +1914,7 @@ async def test_publishing_with_custom_encoding( ): """Test publishing MQTT payload with different encoding.""" domain = fan.DOMAIN - config = copy.deepcopy(DEFAULT_CONFIG[domain]) + config = copy.deepcopy(DEFAULT_CONFIG_LEGACY[domain]) if topic == "preset_mode_command_topic": config["preset_modes"] = ["auto", "eco"] @@ -1890,7 +1935,7 @@ async def test_publishing_with_custom_encoding( async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path): """Test reloading the MQTT platform.""" domain = fan.DOMAIN - config = DEFAULT_CONFIG[domain] + config = DEFAULT_CONFIG_LEGACY[domain] await help_test_reloadable( hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config ) @@ -1899,14 +1944,14 @@ async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_pa async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path): """Test reloading the MQTT platform with late entry setup.""" domain = fan.DOMAIN - config = DEFAULT_CONFIG[domain] + config = DEFAULT_CONFIG_LEGACY[domain] await help_test_reloadable_late(hass, caplog, tmp_path, domain, config) async def test_setup_manual_entity_from_yaml(hass): """Test setup manual configured MQTT entity.""" platform = fan.DOMAIN - config = copy.deepcopy(DEFAULT_CONFIG[platform]) + config = copy.deepcopy(DEFAULT_CONFIG_LEGACY[platform]) config["name"] = "test" del config["platform"] await help_test_setup_manual_entity_from_yaml(hass, platform, config) @@ -1916,7 +1961,20 @@ async def test_setup_manual_entity_from_yaml(hass): async def test_unload_entry(hass, mqtt_mock_entry_with_yaml_config, tmp_path): """Test unloading the config entry.""" domain = fan.DOMAIN - config = DEFAULT_CONFIG[domain] + config = DEFAULT_CONFIG_LEGACY[domain] await help_test_unload_config_entry_with_platform( hass, mqtt_mock_entry_with_yaml_config, tmp_path, domain, config ) + + +# Test deprecated YAML configuration under the platform key +# Scheduled to be removed in HA core 2022.12 +async def test_setup_with_legacy_schema(hass, mqtt_mock_entry_with_yaml_config): + """Test a setup with deprecated yaml platform schema.""" + domain = fan.DOMAIN + config = copy.deepcopy(DEFAULT_CONFIG_LEGACY[domain]) + config["name"] = "test" + assert await async_setup_component(hass, domain, {domain: config}) + await hass.async_block_till_done() + await mqtt_mock_entry_with_yaml_config() + assert hass.states.get(f"{domain}.test") is not None diff --git a/tests/components/mqtt/test_humidifier.py b/tests/components/mqtt/test_humidifier.py index 38dc634578f..0cc2be638bf 100644 --- a/tests/components/mqtt/test_humidifier.py +++ b/tests/components/mqtt/test_humidifier.py @@ -5,7 +5,7 @@ from unittest.mock import patch import pytest from voluptuous.error import MultipleInvalid -from homeassistant.components import humidifier +from homeassistant.components import humidifier, mqtt from homeassistant.components.humidifier import ( ATTR_HUMIDITY, ATTR_MODE, @@ -68,15 +68,21 @@ from .test_common import ( from tests.common import async_fire_mqtt_message DEFAULT_CONFIG = { - humidifier.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "target_humidity_command_topic": "humidity-command-topic", + mqtt.DOMAIN: { + humidifier.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "target_humidity_command_topic": "humidity-command-topic", + } } } +# Test deprecated YAML configuration under the platform key +# Scheduled to be removed in HA core 2022.12 +DEFAULT_CONFIG_LEGACY = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) +DEFAULT_CONFIG_LEGACY[humidifier.DOMAIN]["platform"] = mqtt.DOMAIN + @pytest.fixture(autouse=True) def humidifer_platform_only(): @@ -126,16 +132,17 @@ async def async_set_humidity( await hass.services.async_call(DOMAIN, SERVICE_SET_HUMIDITY, data, blocking=True) -async def test_fail_setup_if_no_command_topic(hass, mqtt_mock_entry_no_yaml_config): +async def test_fail_setup_if_no_command_topic(hass, caplog): """Test if command fails with command topic.""" - assert await async_setup_component( + assert not await async_setup_component( hass, - humidifier.DOMAIN, - {humidifier.DOMAIN: {"platform": "mqtt", "name": "test"}}, + mqtt.DOMAIN, + {mqtt.DOMAIN: {humidifier.DOMAIN: {"name": "test"}}}, + ) + assert ( + "Invalid config for [mqtt]: required key not provided @ data['mqtt']['humidifier'][0]['command_topic']. Got None" + in caplog.text ) - await hass.async_block_till_done() - await mqtt_mock_entry_no_yaml_config() - assert hass.states.get("humidifier.test") is None async def test_controlling_state_via_topic( @@ -144,29 +151,30 @@ async def test_controlling_state_via_topic( """Test the controlling state via topic.""" assert await async_setup_component( hass, - humidifier.DOMAIN, + mqtt.DOMAIN, { - humidifier.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "payload_off": "StAtE_OfF", - "payload_on": "StAtE_On", - "target_humidity_state_topic": "humidity-state-topic", - "target_humidity_command_topic": "humidity-command-topic", - "mode_state_topic": "mode-state-topic", - "mode_command_topic": "mode-command-topic", - "modes": [ - "auto", - "comfort", - "home", - "eco", - "sleep", - "baby", - ], - "payload_reset_humidity": "rEset_humidity", - "payload_reset_mode": "rEset_mode", + mqtt.DOMAIN: { + humidifier.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "payload_off": "StAtE_OfF", + "payload_on": "StAtE_On", + "target_humidity_state_topic": "humidity-state-topic", + "target_humidity_command_topic": "humidity-command-topic", + "mode_state_topic": "mode-state-topic", + "mode_command_topic": "mode-command-topic", + "modes": [ + "auto", + "comfort", + "home", + "eco", + "sleep", + "baby", + ], + "payload_reset_humidity": "rEset_humidity", + "payload_reset_mode": "rEset_mode", + } } }, ) @@ -248,25 +256,26 @@ async def test_controlling_state_via_topic_and_json_message( """Test the controlling state via topic and JSON message.""" assert await async_setup_component( hass, - humidifier.DOMAIN, + mqtt.DOMAIN, { - humidifier.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "target_humidity_state_topic": "humidity-state-topic", - "target_humidity_command_topic": "humidity-command-topic", - "mode_state_topic": "mode-state-topic", - "mode_command_topic": "mode-command-topic", - "modes": [ - "auto", - "eco", - "baby", - ], - "state_value_template": "{{ value_json.val }}", - "target_humidity_state_template": "{{ value_json.val }}", - "mode_state_template": "{{ value_json.val }}", + mqtt.DOMAIN: { + humidifier.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "target_humidity_state_topic": "humidity-state-topic", + "target_humidity_command_topic": "humidity-command-topic", + "mode_state_topic": "mode-state-topic", + "mode_command_topic": "mode-command-topic", + "modes": [ + "auto", + "eco", + "baby", + ], + "state_value_template": "{{ value_json.val }}", + "target_humidity_state_template": "{{ value_json.val }}", + "mode_state_template": "{{ value_json.val }}", + } } }, ) @@ -336,25 +345,26 @@ async def test_controlling_state_via_topic_and_json_message_shared_topic( """Test the controlling state via topic and JSON message using a shared topic.""" assert await async_setup_component( hass, - humidifier.DOMAIN, + mqtt.DOMAIN, { - humidifier.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "shared-state-topic", - "command_topic": "command-topic", - "target_humidity_state_topic": "shared-state-topic", - "target_humidity_command_topic": "percentage-command-topic", - "mode_state_topic": "shared-state-topic", - "mode_command_topic": "mode-command-topic", - "modes": [ - "auto", - "eco", - "baby", - ], - "state_value_template": "{{ value_json.state }}", - "target_humidity_state_template": "{{ value_json.humidity }}", - "mode_state_template": "{{ value_json.mode }}", + mqtt.DOMAIN: { + humidifier.DOMAIN: { + "name": "test", + "state_topic": "shared-state-topic", + "command_topic": "command-topic", + "target_humidity_state_topic": "shared-state-topic", + "target_humidity_command_topic": "percentage-command-topic", + "mode_state_topic": "shared-state-topic", + "mode_command_topic": "mode-command-topic", + "modes": [ + "auto", + "eco", + "baby", + ], + "state_value_template": "{{ value_json.state }}", + "target_humidity_state_template": "{{ value_json.humidity }}", + "mode_state_template": "{{ value_json.mode }}", + } } }, ) @@ -414,21 +424,22 @@ async def test_sending_mqtt_commands_and_optimistic( """Test optimistic mode without state topic.""" assert await async_setup_component( hass, - humidifier.DOMAIN, + mqtt.DOMAIN, { - humidifier.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "command-topic", - "payload_off": "StAtE_OfF", - "payload_on": "StAtE_On", - "target_humidity_command_topic": "humidity-command-topic", - "mode_command_topic": "mode-command-topic", - "modes": [ - "eco", - "auto", - "baby", - ], + mqtt.DOMAIN: { + humidifier.DOMAIN: { + "name": "test", + "command_topic": "command-topic", + "payload_off": "StAtE_OfF", + "payload_on": "StAtE_On", + "target_humidity_command_topic": "humidity-command-topic", + "mode_command_topic": "mode-command-topic", + "modes": [ + "eco", + "auto", + "baby", + ], + } } }, ) @@ -510,22 +521,23 @@ async def test_sending_mqtt_command_templates_( """Testing command templates with optimistic mode without state topic.""" assert await async_setup_component( hass, - humidifier.DOMAIN, + mqtt.DOMAIN, { - humidifier.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "command-topic", - "command_template": "state: {{ value }}", - "target_humidity_command_topic": "humidity-command-topic", - "target_humidity_command_template": "humidity: {{ value }}", - "mode_command_topic": "mode-command-topic", - "mode_command_template": "mode: {{ value }}", - "modes": [ - "auto", - "eco", - "sleep", - ], + mqtt.DOMAIN: { + humidifier.DOMAIN: { + "name": "test", + "command_topic": "command-topic", + "command_template": "state: {{ value }}", + "target_humidity_command_topic": "humidity-command-topic", + "target_humidity_command_template": "humidity: {{ value }}", + "mode_command_topic": "mode-command-topic", + "mode_command_template": "mode: {{ value }}", + "modes": [ + "auto", + "eco", + "sleep", + ], + } } }, ) @@ -607,23 +619,24 @@ async def test_sending_mqtt_commands_and_explicit_optimistic( """Test optimistic mode with state topic and turn on attributes.""" assert await async_setup_component( hass, - humidifier.DOMAIN, + mqtt.DOMAIN, { - humidifier.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "state-topic", - "command_topic": "command-topic", - "target_humidity_state_topic": "humidity-state-topic", - "target_humidity_command_topic": "humidity-command-topic", - "mode_command_topic": "mode-command-topic", - "mode_state_topic": "mode-state-topic", - "modes": [ - "auto", - "eco", - "baby", - ], - "optimistic": True, + mqtt.DOMAIN: { + humidifier.DOMAIN: { + "name": "test", + "state_topic": "state-topic", + "command_topic": "command-topic", + "target_humidity_state_topic": "humidity-state-topic", + "target_humidity_command_topic": "humidity-command-topic", + "mode_command_topic": "mode-command-topic", + "mode_state_topic": "mode-state-topic", + "modes": [ + "auto", + "eco", + "baby", + ], + "optimistic": True, + } } }, ) @@ -737,7 +750,7 @@ async def test_encoding_subscribable_topics( attribute_value, ): """Test handling of incoming encoded payload.""" - config = copy.deepcopy(DEFAULT_CONFIG[humidifier.DOMAIN]) + config = copy.deepcopy(DEFAULT_CONFIG_LEGACY[humidifier.DOMAIN]) config["modes"] = ["eco", "auto"] config[CONF_MODE_COMMAND_TOPIC] = "humidifier/some_mode_command_topic" await help_test_encoding_subscribable_topics( @@ -757,18 +770,19 @@ async def test_attributes(hass, mqtt_mock_entry_with_yaml_config, caplog): """Test attributes.""" assert await async_setup_component( hass, - humidifier.DOMAIN, + mqtt.DOMAIN, { - humidifier.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "command-topic", - "mode_command_topic": "mode-command-topic", - "target_humidity_command_topic": "humidity-command-topic", - "modes": [ - "eco", - "baby", - ], + mqtt.DOMAIN: { + humidifier.DOMAIN: { + "name": "test", + "command_topic": "command-topic", + "mode_command_topic": "mode-command-topic", + "target_humidity_command_topic": "humidity-command-topic", + "modes": [ + "eco", + "baby", + ], + } } }, ) @@ -799,157 +813,182 @@ async def test_attributes(hass, mqtt_mock_entry_with_yaml_config, caplog): assert state.attributes.get(humidifier.ATTR_MODE) is None -async def test_invalid_configurations(hass, mqtt_mock_entry_with_yaml_config, caplog): - """Test invalid configurations.""" - assert await async_setup_component( - hass, - humidifier.DOMAIN, - { - humidifier.DOMAIN: [ - { - "platform": "mqtt", - "name": "test_valid_1", - "command_topic": "command-topic", - "target_humidity_command_topic": "humidity-command-topic", - }, - { - "platform": "mqtt", - "name": "test_valid_2", - "command_topic": "command-topic", - "target_humidity_command_topic": "humidity-command-topic", - "device_class": "humidifier", - }, - { - "platform": "mqtt", - "name": "test_valid_3", - "command_topic": "command-topic", - "target_humidity_command_topic": "humidity-command-topic", - "device_class": "dehumidifier", - }, - { - "platform": "mqtt", - "name": "test_invalid_device_class", - "command_topic": "command-topic", - "target_humidity_command_topic": "humidity-command-topic", - "device_class": "notsupporedSpeci@l", - }, - { - "platform": "mqtt", - "name": "test_mode_command_without_modes", - "command_topic": "command-topic", - "target_humidity_command_topic": "humidity-command-topic", - "mode_command_topic": "mode-command-topic", - }, - { - "platform": "mqtt", - "name": "test_invalid_humidity_min_max_1", - "command_topic": "command-topic", - "target_humidity_command_topic": "humidity-command-topic", - "min_humidity": 0, - "max_humidity": 101, - }, - { - "platform": "mqtt", - "name": "test_invalid_humidity_min_max_2", - "command_topic": "command-topic", - "target_humidity_command_topic": "humidity-command-topic", - "max_humidity": 20, - "min_humidity": 40, - }, - { - "platform": "mqtt", - "name": "test_invalid_mode_is_reset", - "command_topic": "command-topic", - "target_humidity_command_topic": "humidity-command-topic", - "mode_command_topic": "mode-command-topic", - "modes": ["eco", "None"], - }, - ] - }, +@pytest.mark.parametrize( + "config,valid", + [ + ( + { + "name": "test_valid_1", + "command_topic": "command-topic", + "target_humidity_command_topic": "humidity-command-topic", + }, + True, + ), + ( + { + "name": "test_valid_2", + "command_topic": "command-topic", + "target_humidity_command_topic": "humidity-command-topic", + "device_class": "humidifier", + }, + True, + ), + ( + { + "name": "test_valid_3", + "command_topic": "command-topic", + "target_humidity_command_topic": "humidity-command-topic", + "device_class": "dehumidifier", + }, + True, + ), + ( + { + "name": "test_invalid_device_class", + "command_topic": "command-topic", + "target_humidity_command_topic": "humidity-command-topic", + "device_class": "notsupporedSpeci@l", + }, + False, + ), + ( + { + "name": "test_mode_command_without_modes", + "command_topic": "command-topic", + "target_humidity_command_topic": "humidity-command-topic", + "mode_command_topic": "mode-command-topic", + }, + False, + ), + ( + { + "name": "test_invalid_humidity_min_max_1", + "command_topic": "command-topic", + "target_humidity_command_topic": "humidity-command-topic", + "min_humidity": 0, + "max_humidity": 101, + }, + False, + ), + ( + { + "name": "test_invalid_humidity_min_max_2", + "command_topic": "command-topic", + "target_humidity_command_topic": "humidity-command-topic", + "max_humidity": 20, + "min_humidity": 40, + }, + False, + ), + ( + { + "name": "test_invalid_mode_is_reset", + "command_topic": "command-topic", + "target_humidity_command_topic": "humidity-command-topic", + "mode_command_topic": "mode-command-topic", + "modes": ["eco", "None"], + }, + False, + ), + ], +) +async def test_validity_configurations(hass, config, valid): + """Test validity of configurations.""" + assert ( + await async_setup_component( + hass, + mqtt.DOMAIN, + {mqtt.DOMAIN: {humidifier.DOMAIN: config}}, + ) + is valid ) - await hass.async_block_till_done() - await mqtt_mock_entry_with_yaml_config() - assert hass.states.get("humidifier.test_valid_1") is not None - assert hass.states.get("humidifier.test_valid_2") is not None - assert hass.states.get("humidifier.test_valid_3") is not None - assert hass.states.get("humidifier.test_invalid_device_class") is None - assert hass.states.get("humidifier.test_mode_command_without_modes") is None - assert "not all values in the same group of inclusion" in caplog.text - caplog.clear() - - assert hass.states.get("humidifier.test_invalid_humidity_min_max_1") is None - assert hass.states.get("humidifier.test_invalid_humidity_min_max_2") is None - assert hass.states.get("humidifier.test_invalid_mode_is_reset") is None -async def test_supported_features(hass, mqtt_mock_entry_with_yaml_config): +@pytest.mark.parametrize( + "name,config,success,features", + [ + ( + "test1", + { + "name": "test1", + "command_topic": "command-topic", + "target_humidity_command_topic": "humidity-command-topic", + }, + True, + 0, + ), + ( + "test2", + { + "name": "test2", + "command_topic": "command-topic", + "target_humidity_command_topic": "humidity-command-topic", + "mode_command_topic": "mode-command-topic", + "modes": ["eco", "auto"], + }, + True, + humidifier.SUPPORT_MODES, + ), + ( + "test3", + { + "name": "test3", + "command_topic": "command-topic", + "target_humidity_command_topic": "humidity-command-topic", + }, + True, + 0, + ), + ( + "test4", + { + "name": "test4", + "command_topic": "command-topic", + "target_humidity_command_topic": "humidity-command-topic", + "mode_command_topic": "mode-command-topic", + "modes": ["eco", "auto"], + }, + True, + humidifier.SUPPORT_MODES, + ), + ( + "test5", + { + "name": "test5", + "command_topic": "command-topic", + }, + False, + None, + ), + ( + "test6", + { + "name": "test6", + "target_humidity_command_topic": "humidity-command-topic", + }, + False, + None, + ), + ], +) +async def test_supported_features( + hass, mqtt_mock_entry_with_yaml_config, name, config, success, features +): """Test supported features.""" - assert await async_setup_component( - hass, - humidifier.DOMAIN, - { - humidifier.DOMAIN: [ - { - "platform": "mqtt", - "name": "test1", - "command_topic": "command-topic", - "target_humidity_command_topic": "humidity-command-topic", - }, - { - "platform": "mqtt", - "name": "test2", - "command_topic": "command-topic", - "target_humidity_command_topic": "humidity-command-topic", - "mode_command_topic": "mode-command-topic", - "modes": ["eco", "auto"], - }, - { - "platform": "mqtt", - "name": "test3", - "command_topic": "command-topic", - "target_humidity_command_topic": "humidity-command-topic", - }, - { - "platform": "mqtt", - "name": "test4", - "command_topic": "command-topic", - "target_humidity_command_topic": "humidity-command-topic", - "mode_command_topic": "mode-command-topic", - "modes": ["eco", "auto"], - }, - { - "platform": "mqtt", - "name": "test5", - "command_topic": "command-topic", - }, - { - "platform": "mqtt", - "name": "test6", - "target_humidity_command_topic": "humidity-command-topic", - }, - ] - }, + assert ( + await async_setup_component( + hass, + mqtt.DOMAIN, + {mqtt.DOMAIN: {humidifier.DOMAIN: config}}, + ) + is success ) - await hass.async_block_till_done() - await mqtt_mock_entry_with_yaml_config() + if success: + await hass.async_block_till_done() + await mqtt_mock_entry_with_yaml_config() - state = hass.states.get("humidifier.test1") - assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 0 - - state = hass.states.get("humidifier.test2") - assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == humidifier.SUPPORT_MODES - - state = hass.states.get("humidifier.test3") - assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 0 - - state = hass.states.get("humidifier.test4") - assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == humidifier.SUPPORT_MODES - - state = hass.states.get("humidifier.test5") - assert state is None - - state = hass.states.get("humidifier.test6") - assert state is None + state = hass.states.get(f"humidifier.{name}") + assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == features async def test_availability_when_connection_lost( @@ -957,14 +996,14 @@ async def test_availability_when_connection_lost( ): """Test availability after MQTT disconnection.""" await help_test_availability_when_connection_lost( - hass, mqtt_mock_entry_with_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_availability_without_topic(hass, mqtt_mock_entry_with_yaml_config): """Test availability without defined availability topic.""" await help_test_availability_without_topic( - hass, mqtt_mock_entry_with_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG_LEGACY ) @@ -974,7 +1013,7 @@ async def test_default_availability_payload(hass, mqtt_mock_entry_with_yaml_conf hass, mqtt_mock_entry_with_yaml_config, humidifier.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, True, "state-topic", "1", @@ -987,7 +1026,7 @@ async def test_custom_availability_payload(hass, mqtt_mock_entry_with_yaml_confi hass, mqtt_mock_entry_with_yaml_config, humidifier.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, True, "state-topic", "1", @@ -999,7 +1038,7 @@ async def test_setting_attribute_via_mqtt_json_message( ): """Test the setting of attribute via MQTT with JSON payload.""" await help_test_setting_attribute_via_mqtt_json_message( - hass, mqtt_mock_entry_with_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG_LEGACY ) @@ -1011,7 +1050,7 @@ async def test_setting_blocked_attribute_via_mqtt_json_message( hass, mqtt_mock_entry_no_yaml_config, humidifier.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, MQTT_HUMIDIFIER_ATTRIBUTES_BLOCKED, ) @@ -1019,7 +1058,7 @@ async def test_setting_blocked_attribute_via_mqtt_json_message( async def test_setting_attribute_with_template(hass, mqtt_mock_entry_with_yaml_config): """Test the setting of attribute via MQTT with JSON payload.""" await help_test_setting_attribute_with_template( - hass, mqtt_mock_entry_with_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG_LEGACY ) @@ -1032,7 +1071,7 @@ async def test_update_with_json_attrs_not_dict( mqtt_mock_entry_with_yaml_config, caplog, humidifier.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, ) @@ -1045,14 +1084,18 @@ async def test_update_with_json_attrs_bad_json( mqtt_mock_entry_with_yaml_config, caplog, humidifier.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, ) async def test_discovery_update_attr(hass, mqtt_mock_entry_no_yaml_config, caplog): """Test update of discovered MQTTAttributes.""" await help_test_discovery_update_attr( - hass, mqtt_mock_entry_no_yaml_config, caplog, humidifier.DOMAIN, DEFAULT_CONFIG + hass, + mqtt_mock_entry_no_yaml_config, + caplog, + humidifier.DOMAIN, + DEFAULT_CONFIG_LEGACY, ) @@ -1148,42 +1191,42 @@ async def test_discovery_broken(hass, mqtt_mock_entry_no_yaml_config, caplog): async def test_entity_device_info_with_connection(hass, mqtt_mock_entry_no_yaml_config): """Test MQTT fan device registry integration.""" await help_test_entity_device_info_with_connection( - hass, mqtt_mock_entry_no_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_entity_device_info_with_identifier(hass, mqtt_mock_entry_no_yaml_config): """Test MQTT fan device registry integration.""" await help_test_entity_device_info_with_identifier( - hass, mqtt_mock_entry_no_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_entity_device_info_update(hass, mqtt_mock_entry_no_yaml_config): """Test device registry update.""" await help_test_entity_device_info_update( - hass, mqtt_mock_entry_no_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_entity_device_info_remove(hass, mqtt_mock_entry_no_yaml_config): """Test device registry remove.""" await help_test_entity_device_info_remove( - hass, mqtt_mock_entry_no_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_entity_id_update_subscriptions(hass, mqtt_mock_entry_with_yaml_config): """Test MQTT subscriptions are managed when entity_id is updated.""" await help_test_entity_id_update_subscriptions( - hass, mqtt_mock_entry_with_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_with_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG_LEGACY ) async def test_entity_id_update_discovery_update(hass, mqtt_mock_entry_no_yaml_config): """Test MQTT discovery update when entity_id is updated.""" await help_test_entity_id_update_discovery_update( - hass, mqtt_mock_entry_no_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG + hass, mqtt_mock_entry_no_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG_LEGACY ) @@ -1193,7 +1236,7 @@ async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config): hass, mqtt_mock_entry_no_yaml_config, humidifier.DOMAIN, - DEFAULT_CONFIG, + DEFAULT_CONFIG_LEGACY, humidifier.SERVICE_TURN_ON, ) @@ -1243,7 +1286,7 @@ async def test_publishing_with_custom_encoding( ): """Test publishing MQTT payload with different encoding.""" domain = humidifier.DOMAIN - config = copy.deepcopy(DEFAULT_CONFIG[domain]) + config = copy.deepcopy(DEFAULT_CONFIG_LEGACY[domain]) if topic == "mode_command_topic": config["modes"] = ["auto", "eco"] @@ -1264,7 +1307,7 @@ async def test_publishing_with_custom_encoding( async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path): """Test reloading the MQTT platform.""" domain = humidifier.DOMAIN - config = DEFAULT_CONFIG[domain] + config = DEFAULT_CONFIG_LEGACY[domain] await help_test_reloadable( hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config ) @@ -1273,14 +1316,14 @@ async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_pa async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path): """Test reloading the MQTT platform with late entry setup.""" domain = humidifier.DOMAIN - config = DEFAULT_CONFIG[domain] + config = DEFAULT_CONFIG_LEGACY[domain] await help_test_reloadable_late(hass, caplog, tmp_path, domain, config) async def test_setup_manual_entity_from_yaml(hass): """Test setup manual configured MQTT entity.""" platform = humidifier.DOMAIN - config = copy.deepcopy(DEFAULT_CONFIG[platform]) + config = copy.deepcopy(DEFAULT_CONFIG_LEGACY[platform]) config["name"] = "test" del config["platform"] await help_test_setup_manual_entity_from_yaml(hass, platform, config) @@ -1288,21 +1331,33 @@ async def test_setup_manual_entity_from_yaml(hass): async def test_config_schema_validation(hass): - """Test invalid platform options in the config schema do pass the config validation.""" + """Test invalid platform options in the config schema do not pass the config validation.""" platform = humidifier.DOMAIN - config = copy.deepcopy(DEFAULT_CONFIG[platform]) + config = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][platform]) config["name"] = "test" - del config["platform"] - CONFIG_SCHEMA({DOMAIN: {platform: config}}) - CONFIG_SCHEMA({DOMAIN: {platform: [config]}}) + CONFIG_SCHEMA({mqtt.DOMAIN: {platform: config}}) + CONFIG_SCHEMA({mqtt.DOMAIN: {platform: [config]}}) with pytest.raises(MultipleInvalid): - CONFIG_SCHEMA({"mqtt": {"humidifier": [{"bla": "bla"}]}}) + CONFIG_SCHEMA({mqtt.DOMAIN: {platform: [{"bla": "bla"}]}}) async def test_unload_config_entry(hass, mqtt_mock_entry_with_yaml_config, tmp_path): """Test unloading the config entry.""" domain = humidifier.DOMAIN - config = DEFAULT_CONFIG[domain] + config = DEFAULT_CONFIG_LEGACY[domain] await help_test_unload_config_entry_with_platform( hass, mqtt_mock_entry_with_yaml_config, tmp_path, domain, config ) + + +# Test deprecated YAML configuration under the platform key +# Scheduled to be removed in HA core 2022.12 +async def test_setup_with_legacy_schema(hass, mqtt_mock_entry_with_yaml_config): + """Test a setup with deprecated yaml platform schema.""" + domain = humidifier.DOMAIN + config = copy.deepcopy(DEFAULT_CONFIG_LEGACY[domain]) + config["name"] = "test" + assert await async_setup_component(hass, domain, {domain: config}) + await hass.async_block_till_done() + await mqtt_mock_entry_with_yaml_config() + assert hass.states.get(f"{domain}.test") is not None diff --git a/tests/components/mqtt/test_init.py b/tests/components/mqtt/test_init.py index 020fae1732b..b794d9260ba 100644 --- a/tests/components/mqtt/test_init.py +++ b/tests/components/mqtt/test_init.py @@ -281,6 +281,7 @@ async def test_command_template_value(hass): assert cmd_tpl.async_render(None, variables=variables) == "beer" +@patch("homeassistant.components.mqtt.PLATFORMS", [Platform.SELECT]) async def test_command_template_variables(hass, mqtt_mock_entry_with_yaml_config): """Test the rendering of entity variables.""" topic = "test/select" @@ -290,14 +291,15 @@ async def test_command_template_variables(hass, mqtt_mock_entry_with_yaml_config assert await async_setup_component( hass, - "select", + mqtt.DOMAIN, { - "select": { - "platform": "mqtt", - "command_topic": topic, - "name": "Test Select", - "options": ["milk", "beer"], - "command_template": '{"option": "{{ value }}", "entity_id": "{{ entity_id }}", "name": "{{ name }}", "this_object_state": "{{ this.state }}"}', + mqtt.DOMAIN: { + "select": { + "command_topic": topic, + "name": "Test Select", + "options": ["milk", "beer"], + "command_template": '{"option": "{{ value }}", "entity_id": "{{ entity_id }}", "name": "{{ name }}", "this_object_state": "{{ this.state }}"}', + } } }, ) @@ -2087,20 +2089,19 @@ async def test_mqtt_ws_get_device_debug_info( await mqtt_mock_entry_no_yaml_config() config_sensor = { "device": {"identifiers": ["0AFFD2"]}, - "platform": "mqtt", "state_topic": "foobar/sensor", "unique_id": "unique", } config_trigger = { "automation_type": "trigger", "device": {"identifiers": ["0AFFD2"]}, - "platform": "mqtt", "topic": "test-topic1", "type": "foo", "subtype": "bar", } data_sensor = json.dumps(config_sensor) data_trigger = json.dumps(config_trigger) + config_sensor["platform"] = config_trigger["platform"] = mqtt.DOMAIN async_fire_mqtt_message(hass, "homeassistant/sensor/bla/config", data_sensor) async_fire_mqtt_message( @@ -2151,11 +2152,11 @@ async def test_mqtt_ws_get_device_debug_info_binary( await mqtt_mock_entry_no_yaml_config() config = { "device": {"identifiers": ["0AFFD2"]}, - "platform": "mqtt", "topic": "foobar/image", "unique_id": "unique", } data = json.dumps(config) + config["platform"] = mqtt.DOMAIN async_fire_mqtt_message(hass, "homeassistant/camera/bla/config", data) await hass.async_block_till_done() @@ -2397,7 +2398,9 @@ async def test_debug_info_non_mqtt( device_id=device_entry.id, ) - assert await async_setup_component(hass, DOMAIN, {DOMAIN: {"platform": "test"}}) + assert await async_setup_component( + hass, mqtt.DOMAIN, {mqtt.DOMAIN: {DOMAIN: {"platform": "test"}}} + ) debug_info_data = debug_info.info_for_device(hass, device_entry.id) assert len(debug_info_data["entities"]) == 0 @@ -2409,7 +2412,6 @@ async def test_debug_info_wildcard(hass, mqtt_mock_entry_no_yaml_config): await mqtt_mock_entry_no_yaml_config() config = { "device": {"identifiers": ["helloworld"]}, - "platform": "mqtt", "name": "test", "state_topic": "sensor/#", "unique_id": "veryunique", @@ -2456,7 +2458,6 @@ async def test_debug_info_filter_same(hass, mqtt_mock_entry_no_yaml_config): await mqtt_mock_entry_no_yaml_config() config = { "device": {"identifiers": ["helloworld"]}, - "platform": "mqtt", "name": "test", "state_topic": "sensor/#", "unique_id": "veryunique", @@ -2515,7 +2516,6 @@ async def test_debug_info_same_topic(hass, mqtt_mock_entry_no_yaml_config): await mqtt_mock_entry_no_yaml_config() config = { "device": {"identifiers": ["helloworld"]}, - "platform": "mqtt", "name": "test", "state_topic": "sensor/status", "availability_topic": "sensor/status", @@ -2568,7 +2568,6 @@ async def test_debug_info_qos_retain(hass, mqtt_mock_entry_no_yaml_config): await mqtt_mock_entry_no_yaml_config() config = { "device": {"identifiers": ["helloworld"]}, - "platform": "mqtt", "name": "test", "state_topic": "sensor/#", "unique_id": "veryunique", @@ -2708,6 +2707,8 @@ async def test_subscribe_connection_status( assert mqtt_connected_calls[1] is False +# Test deprecated YAML configuration under the platform key +# Scheduled to be removed in HA core 2022.12 async def test_one_deprecation_warning_per_platform( hass, mqtt_mock_entry_with_yaml_config, caplog ): @@ -2801,6 +2802,8 @@ async def test_reload_entry_with_new_config(hass, tmp_path): "mqtt": { "light": [{"name": "test_new_modern", "command_topic": "test-topic_new"}] }, + # Test deprecated YAML configuration under the platform key + # Scheduled to be removed in HA core 2022.12 "light": [ { "platform": "mqtt", @@ -2826,6 +2829,8 @@ async def test_disabling_and_enabling_entry(hass, tmp_path, caplog): "mqtt": { "light": [{"name": "test_new_modern", "command_topic": "test-topic_new"}] }, + # Test deprecated YAML configuration under the platform key + # Scheduled to be removed in HA core 2022.12 "light": [ { "platform": "mqtt", diff --git a/tests/components/mqtt/test_legacy_vacuum.py b/tests/components/mqtt/test_legacy_vacuum.py index 224e81781cf..ffe9183fe4c 100644 --- a/tests/components/mqtt/test_legacy_vacuum.py +++ b/tests/components/mqtt/test_legacy_vacuum.py @@ -5,7 +5,7 @@ from unittest.mock import patch import pytest -from homeassistant.components import vacuum +from homeassistant.components import mqtt, vacuum from homeassistant.components.mqtt.const import CONF_COMMAND_TOPIC from homeassistant.components.mqtt.vacuum import schema_legacy as mqttvacuum from homeassistant.components.mqtt.vacuum.schema import services_to_strings @@ -66,27 +66,37 @@ from tests.common import async_fire_mqtt_message from tests.components.vacuum import common DEFAULT_CONFIG = { - CONF_PLATFORM: "mqtt", - CONF_NAME: "mqtttest", - CONF_COMMAND_TOPIC: "vacuum/command", - mqttvacuum.CONF_SEND_COMMAND_TOPIC: "vacuum/send_command", - mqttvacuum.CONF_BATTERY_LEVEL_TOPIC: "vacuum/state", - mqttvacuum.CONF_BATTERY_LEVEL_TEMPLATE: "{{ value_json.battery_level }}", - mqttvacuum.CONF_CHARGING_TOPIC: "vacuum/state", - mqttvacuum.CONF_CHARGING_TEMPLATE: "{{ value_json.charging }}", - mqttvacuum.CONF_CLEANING_TOPIC: "vacuum/state", - mqttvacuum.CONF_CLEANING_TEMPLATE: "{{ value_json.cleaning }}", - mqttvacuum.CONF_DOCKED_TOPIC: "vacuum/state", - mqttvacuum.CONF_DOCKED_TEMPLATE: "{{ value_json.docked }}", - mqttvacuum.CONF_ERROR_TOPIC: "vacuum/state", - mqttvacuum.CONF_ERROR_TEMPLATE: "{{ value_json.error }}", - mqttvacuum.CONF_FAN_SPEED_TOPIC: "vacuum/state", - mqttvacuum.CONF_FAN_SPEED_TEMPLATE: "{{ value_json.fan_speed }}", - mqttvacuum.CONF_SET_FAN_SPEED_TOPIC: "vacuum/set_fan_speed", - mqttvacuum.CONF_FAN_SPEED_LIST: ["min", "medium", "high", "max"], + mqtt.DOMAIN: { + vacuum.DOMAIN: { + CONF_NAME: "mqtttest", + CONF_COMMAND_TOPIC: "vacuum/command", + mqttvacuum.CONF_SEND_COMMAND_TOPIC: "vacuum/send_command", + mqttvacuum.CONF_BATTERY_LEVEL_TOPIC: "vacuum/state", + mqttvacuum.CONF_BATTERY_LEVEL_TEMPLATE: "{{ value_json.battery_level }}", + mqttvacuum.CONF_CHARGING_TOPIC: "vacuum/state", + mqttvacuum.CONF_CHARGING_TEMPLATE: "{{ value_json.charging }}", + mqttvacuum.CONF_CLEANING_TOPIC: "vacuum/state", + mqttvacuum.CONF_CLEANING_TEMPLATE: "{{ value_json.cleaning }}", + mqttvacuum.CONF_DOCKED_TOPIC: "vacuum/state", + mqttvacuum.CONF_DOCKED_TEMPLATE: "{{ value_json.docked }}", + mqttvacuum.CONF_ERROR_TOPIC: "vacuum/state", + mqttvacuum.CONF_ERROR_TEMPLATE: "{{ value_json.error }}", + mqttvacuum.CONF_FAN_SPEED_TOPIC: "vacuum/state", + mqttvacuum.CONF_FAN_SPEED_TEMPLATE: "{{ value_json.fan_speed }}", + mqttvacuum.CONF_SET_FAN_SPEED_TOPIC: "vacuum/set_fan_speed", + mqttvacuum.CONF_FAN_SPEED_LIST: ["min", "medium", "high", "max"], + } + } } -DEFAULT_CONFIG_2 = {vacuum.DOMAIN: {"platform": "mqtt", "name": "test"}} +DEFAULT_CONFIG_2 = {mqtt.DOMAIN: {vacuum.DOMAIN: {"name": "test"}}} + +# Test deprecated YAML configuration under the platform key +# Scheduled to be removed in HA core 2022.12 +DEFAULT_CONFIG_LEGACY = deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN]) +DEFAULT_CONFIG_LEGACY[vacuum.DOMAIN][CONF_PLATFORM] = mqtt.DOMAIN +DEFAULT_CONFIG_2_LEGACY = deepcopy(DEFAULT_CONFIG_2[mqtt.DOMAIN]) +DEFAULT_CONFIG_2_LEGACY[vacuum.DOMAIN][CONF_PLATFORM] = mqtt.DOMAIN @pytest.fixture(autouse=True) @@ -98,9 +108,7 @@ def vacuum_platform_only(): async def test_default_supported_features(hass, mqtt_mock_entry_with_yaml_config): """Test that the correct supported features.""" - assert await async_setup_component( - hass, vacuum.DOMAIN, {vacuum.DOMAIN: DEFAULT_CONFIG} - ) + assert await async_setup_component(hass, vacuum.DOMAIN, DEFAULT_CONFIG_LEGACY) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() entity = hass.states.get("vacuum.mqtttest") @@ -120,12 +128,14 @@ async def test_default_supported_features(hass, mqtt_mock_entry_with_yaml_config async def test_all_commands(hass, mqtt_mock_entry_with_yaml_config): """Test simple commands to the vacuum.""" - config = deepcopy(DEFAULT_CONFIG) + config = deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][vacuum.DOMAIN]) config[mqttvacuum.CONF_SUPPORTED_FEATURES] = services_to_strings( ALL_SERVICES, SERVICE_TO_STRING ) - assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config}) + assert await async_setup_component( + hass, mqtt.DOMAIN, {mqtt.DOMAIN: {vacuum.DOMAIN: config}} + ) await hass.async_block_till_done() mqtt_mock = await mqtt_mock_entry_with_yaml_config() @@ -202,13 +212,15 @@ async def test_commands_without_supported_features( hass, mqtt_mock_entry_with_yaml_config ): """Test commands which are not supported by the vacuum.""" - config = deepcopy(DEFAULT_CONFIG) + config = deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][vacuum.DOMAIN]) services = mqttvacuum.STRING_TO_SERVICE["status"] config[mqttvacuum.CONF_SUPPORTED_FEATURES] = services_to_strings( services, SERVICE_TO_STRING ) - assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config}) + assert await async_setup_component( + hass, mqtt.DOMAIN, {mqtt.DOMAIN: {vacuum.DOMAIN: config}} + ) await hass.async_block_till_done() mqtt_mock = await mqtt_mock_entry_with_yaml_config() @@ -253,13 +265,15 @@ async def test_attributes_without_supported_features( hass, mqtt_mock_entry_with_yaml_config ): """Test attributes which are not supported by the vacuum.""" - config = deepcopy(DEFAULT_CONFIG) + config = deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][vacuum.DOMAIN]) services = mqttvacuum.STRING_TO_SERVICE["turn_on"] config[mqttvacuum.CONF_SUPPORTED_FEATURES] = services_to_strings( services, SERVICE_TO_STRING ) - assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config}) + assert await async_setup_component( + hass, mqtt.DOMAIN, {mqtt.DOMAIN: {vacuum.DOMAIN: config}} + ) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -281,12 +295,14 @@ async def test_attributes_without_supported_features( async def test_status(hass, mqtt_mock_entry_with_yaml_config): """Test status updates from the vacuum.""" - config = deepcopy(DEFAULT_CONFIG) + config = deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][vacuum.DOMAIN]) config[mqttvacuum.CONF_SUPPORTED_FEATURES] = services_to_strings( ALL_SERVICES, SERVICE_TO_STRING ) - assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config}) + assert await async_setup_component( + hass, mqtt.DOMAIN, {mqtt.DOMAIN: {vacuum.DOMAIN: config}} + ) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -322,12 +338,14 @@ async def test_status(hass, mqtt_mock_entry_with_yaml_config): async def test_status_battery(hass, mqtt_mock_entry_with_yaml_config): """Test status updates from the vacuum.""" - config = deepcopy(DEFAULT_CONFIG) + config = deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][vacuum.DOMAIN]) config[mqttvacuum.CONF_SUPPORTED_FEATURES] = services_to_strings( ALL_SERVICES, SERVICE_TO_STRING ) - assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config}) + assert await async_setup_component( + hass, mqtt.DOMAIN, {mqtt.DOMAIN: {vacuum.DOMAIN: config}} + ) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -341,12 +359,14 @@ async def test_status_battery(hass, mqtt_mock_entry_with_yaml_config): async def test_status_cleaning(hass, mqtt_mock_entry_with_yaml_config): """Test status updates from the vacuum.""" - config = deepcopy(DEFAULT_CONFIG) + config = deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][vacuum.DOMAIN]) config[mqttvacuum.CONF_SUPPORTED_FEATURES] = services_to_strings( ALL_SERVICES, SERVICE_TO_STRING ) - assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config}) + assert await async_setup_component( + hass, mqtt.DOMAIN, {mqtt.DOMAIN: {vacuum.DOMAIN: config}} + ) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -360,12 +380,14 @@ async def test_status_cleaning(hass, mqtt_mock_entry_with_yaml_config): async def test_status_docked(hass, mqtt_mock_entry_with_yaml_config): """Test status updates from the vacuum.""" - config = deepcopy(DEFAULT_CONFIG) + config = deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][vacuum.DOMAIN]) config[mqttvacuum.CONF_SUPPORTED_FEATURES] = services_to_strings( ALL_SERVICES, SERVICE_TO_STRING ) - assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config}) + assert await async_setup_component( + hass, mqtt.DOMAIN, {mqtt.DOMAIN: {vacuum.DOMAIN: config}} + ) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -379,12 +401,14 @@ async def test_status_docked(hass, mqtt_mock_entry_with_yaml_config): async def test_status_charging(hass, mqtt_mock_entry_with_yaml_config): """Test status updates from the vacuum.""" - config = deepcopy(DEFAULT_CONFIG) + config = deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][vacuum.DOMAIN]) config[mqttvacuum.CONF_SUPPORTED_FEATURES] = services_to_strings( ALL_SERVICES, SERVICE_TO_STRING ) - assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config}) + assert await async_setup_component( + hass, mqtt.DOMAIN, {mqtt.DOMAIN: {vacuum.DOMAIN: config}} + ) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -398,12 +422,14 @@ async def test_status_charging(hass, mqtt_mock_entry_with_yaml_config): async def test_status_fan_speed(hass, mqtt_mock_entry_with_yaml_config): """Test status updates from the vacuum.""" - config = deepcopy(DEFAULT_CONFIG) + config = deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][vacuum.DOMAIN]) config[mqttvacuum.CONF_SUPPORTED_FEATURES] = services_to_strings( ALL_SERVICES, SERVICE_TO_STRING ) - assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config}) + assert await async_setup_component( + hass, mqtt.DOMAIN, {mqtt.DOMAIN: {vacuum.DOMAIN: config}} + ) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -417,12 +443,14 @@ async def test_status_fan_speed(hass, mqtt_mock_entry_with_yaml_config): async def test_status_fan_speed_list(hass, mqtt_mock_entry_with_yaml_config): """Test status updates from the vacuum.""" - config = deepcopy(DEFAULT_CONFIG) + config = deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][vacuum.DOMAIN]) config[mqttvacuum.CONF_SUPPORTED_FEATURES] = services_to_strings( ALL_SERVICES, SERVICE_TO_STRING ) - assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config}) + assert await async_setup_component( + hass, mqtt.DOMAIN, {mqtt.DOMAIN: {vacuum.DOMAIN: config}} + ) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -435,13 +463,15 @@ async def test_status_no_fan_speed_list(hass, mqtt_mock_entry_with_yaml_config): If the vacuum doesn't support fan speed, fan speed list should be None. """ - config = deepcopy(DEFAULT_CONFIG) + config = deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][vacuum.DOMAIN]) services = ALL_SERVICES - VacuumEntityFeature.FAN_SPEED config[mqttvacuum.CONF_SUPPORTED_FEATURES] = services_to_strings( services, SERVICE_TO_STRING ) - assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config}) + assert await async_setup_component( + hass, mqtt.DOMAIN, {mqtt.DOMAIN: {vacuum.DOMAIN: config}} + ) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -451,12 +481,14 @@ async def test_status_no_fan_speed_list(hass, mqtt_mock_entry_with_yaml_config): async def test_status_error(hass, mqtt_mock_entry_with_yaml_config): """Test status updates from the vacuum.""" - config = deepcopy(DEFAULT_CONFIG) + config = deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][vacuum.DOMAIN]) config[mqttvacuum.CONF_SUPPORTED_FEATURES] = services_to_strings( ALL_SERVICES, SERVICE_TO_STRING ) - assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config}) + assert await async_setup_component( + hass, mqtt.DOMAIN, {mqtt.DOMAIN: {vacuum.DOMAIN: config}} + ) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -477,7 +509,7 @@ async def test_status_error(hass, mqtt_mock_entry_with_yaml_config): async def test_battery_template(hass, mqtt_mock_entry_with_yaml_config): """Test that you can use non-default templates for battery_level.""" - config = deepcopy(DEFAULT_CONFIG) + config = deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][vacuum.DOMAIN]) config.update( { mqttvacuum.CONF_SUPPORTED_FEATURES: services_to_strings( @@ -488,7 +520,9 @@ async def test_battery_template(hass, mqtt_mock_entry_with_yaml_config): } ) - assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config}) + assert await async_setup_component( + hass, mqtt.DOMAIN, {mqtt.DOMAIN: {vacuum.DOMAIN: config}} + ) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -500,12 +534,14 @@ async def test_battery_template(hass, mqtt_mock_entry_with_yaml_config): async def test_status_invalid_json(hass, mqtt_mock_entry_with_yaml_config): """Test to make sure nothing breaks if the vacuum sends bad JSON.""" - config = deepcopy(DEFAULT_CONFIG) + config = deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][vacuum.DOMAIN]) config[mqttvacuum.CONF_SUPPORTED_FEATURES] = services_to_strings( ALL_SERVICES, SERVICE_TO_STRING ) - assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config}) + assert await async_setup_component( + hass, mqtt.DOMAIN, {mqtt.DOMAIN: {vacuum.DOMAIN: config}} + ) await hass.async_block_till_done() await mqtt_mock_entry_with_yaml_config() @@ -515,82 +551,64 @@ async def test_status_invalid_json(hass, mqtt_mock_entry_with_yaml_config): assert state.attributes.get(ATTR_STATUS) == "Stopped" -async def test_missing_battery_template(hass, mqtt_mock_entry_no_yaml_config): +async def test_missing_battery_template(hass): """Test to make sure missing template is not allowed.""" - config = deepcopy(DEFAULT_CONFIG) + config = deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][vacuum.DOMAIN]) config.pop(mqttvacuum.CONF_BATTERY_LEVEL_TEMPLATE) - assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config}) - await hass.async_block_till_done() - await mqtt_mock_entry_no_yaml_config() - - state = hass.states.get("vacuum.mqtttest") - assert state is None + assert not await async_setup_component( + hass, mqtt.DOMAIN, {mqtt.DOMAIN: {vacuum.DOMAIN: config}} + ) -async def test_missing_charging_template(hass, mqtt_mock_entry_no_yaml_config): +async def test_missing_charging_template(hass): """Test to make sure missing template is not allowed.""" - config = deepcopy(DEFAULT_CONFIG) + config = deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][vacuum.DOMAIN]) config.pop(mqttvacuum.CONF_CHARGING_TEMPLATE) - assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config}) - await hass.async_block_till_done() - await mqtt_mock_entry_no_yaml_config() - - state = hass.states.get("vacuum.mqtttest") - assert state is None + assert not await async_setup_component( + hass, mqtt.DOMAIN, {mqtt.DOMAIN: {vacuum.DOMAIN: config}} + ) -async def test_missing_cleaning_template(hass, mqtt_mock_entry_no_yaml_config): +async def test_missing_cleaning_template(hass): """Test to make sure missing template is not allowed.""" - config = deepcopy(DEFAULT_CONFIG) + config = deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][vacuum.DOMAIN]) config.pop(mqttvacuum.CONF_CLEANING_TEMPLATE) - assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config}) - await hass.async_block_till_done() - await mqtt_mock_entry_no_yaml_config() - - state = hass.states.get("vacuum.mqtttest") - assert state is None + assert not await async_setup_component( + hass, mqtt.DOMAIN, {mqtt.DOMAIN: {vacuum.DOMAIN: config}} + ) -async def test_missing_docked_template(hass, mqtt_mock_entry_no_yaml_config): +async def test_missing_docked_template(hass): """Test to make sure missing template is not allowed.""" - config = deepcopy(DEFAULT_CONFIG) + config = deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][vacuum.DOMAIN]) config.pop(mqttvacuum.CONF_DOCKED_TEMPLATE) - assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config}) - await hass.async_block_till_done() - await mqtt_mock_entry_no_yaml_config() - - state = hass.states.get("vacuum.mqtttest") - assert state is None + assert not await async_setup_component( + hass, mqtt.DOMAIN, {mqtt.DOMAIN: {vacuum.DOMAIN: config}} + ) -async def test_missing_error_template(hass, mqtt_mock_entry_no_yaml_config): +async def test_missing_error_template(hass): """Test to make sure missing template is not allowed.""" - config = deepcopy(DEFAULT_CONFIG) + config = deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][vacuum.DOMAIN]) config.pop(mqttvacuum.CONF_ERROR_TEMPLATE) - assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config}) - await hass.async_block_till_done() - await mqtt_mock_entry_no_yaml_config() - - state = hass.states.get("vacuum.mqtttest") - assert state is None + assert not await async_setup_component( + hass, mqtt.DOMAIN, {mqtt.DOMAIN: {vacuum.DOMAIN: config}} + ) -async def test_missing_fan_speed_template(hass, mqtt_mock_entry_no_yaml_config): +async def test_missing_fan_speed_template(hass): """Test to make sure missing template is not allowed.""" - config = deepcopy(DEFAULT_CONFIG) + config = deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][vacuum.DOMAIN]) config.pop(mqttvacuum.CONF_FAN_SPEED_TEMPLATE) - assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config}) - await hass.async_block_till_done() - await mqtt_mock_entry_no_yaml_config() - - state = hass.states.get("vacuum.mqtttest") - assert state is None + assert not await async_setup_component( + hass, mqtt.DOMAIN, {mqtt.DOMAIN: {vacuum.DOMAIN: config}} + ) async def test_availability_when_connection_lost( @@ -598,28 +616,28 @@ async def test_availability_when_connection_lost( ): """Test availability after MQTT disconnection.""" await help_test_availability_when_connection_lost( - hass, mqtt_mock_entry_with_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2 + hass, mqtt_mock_entry_with_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2_LEGACY ) async def test_availability_without_topic(hass, mqtt_mock_entry_with_yaml_config): """Test availability without defined availability topic.""" await help_test_availability_without_topic( - hass, mqtt_mock_entry_with_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2 + hass, mqtt_mock_entry_with_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2_LEGACY ) async def test_default_availability_payload(hass, mqtt_mock_entry_with_yaml_config): """Test availability by default payload with defined topic.""" await help_test_default_availability_payload( - hass, mqtt_mock_entry_with_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2 + hass, mqtt_mock_entry_with_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2_LEGACY ) async def test_custom_availability_payload(hass, mqtt_mock_entry_with_yaml_config): """Test availability by custom payload with defined topic.""" await help_test_custom_availability_payload( - hass, mqtt_mock_entry_with_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2 + hass, mqtt_mock_entry_with_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2_LEGACY ) @@ -628,7 +646,7 @@ async def test_setting_attribute_via_mqtt_json_message( ): """Test the setting of attribute via MQTT with JSON payload.""" await help_test_setting_attribute_via_mqtt_json_message( - hass, mqtt_mock_entry_with_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2 + hass, mqtt_mock_entry_with_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2_LEGACY ) @@ -640,7 +658,7 @@ async def test_setting_blocked_attribute_via_mqtt_json_message( hass, mqtt_mock_entry_no_yaml_config, vacuum.DOMAIN, - DEFAULT_CONFIG_2, + DEFAULT_CONFIG_2_LEGACY, MQTT_LEGACY_VACUUM_ATTRIBUTES_BLOCKED, ) @@ -648,7 +666,7 @@ async def test_setting_blocked_attribute_via_mqtt_json_message( async def test_setting_attribute_with_template(hass, mqtt_mock_entry_with_yaml_config): """Test the setting of attribute via MQTT with JSON payload.""" await help_test_setting_attribute_with_template( - hass, mqtt_mock_entry_with_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2 + hass, mqtt_mock_entry_with_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2_LEGACY ) @@ -657,7 +675,11 @@ async def test_update_with_json_attrs_not_dict( ): """Test attributes get extracted from a JSON result.""" await help_test_update_with_json_attrs_not_dict( - hass, mqtt_mock_entry_with_yaml_config, caplog, vacuum.DOMAIN, DEFAULT_CONFIG_2 + hass, + mqtt_mock_entry_with_yaml_config, + caplog, + vacuum.DOMAIN, + DEFAULT_CONFIG_2_LEGACY, ) @@ -666,14 +688,22 @@ async def test_update_with_json_attrs_bad_JSON( ): """Test attributes get extracted from a JSON result.""" await help_test_update_with_json_attrs_bad_JSON( - hass, mqtt_mock_entry_with_yaml_config, caplog, vacuum.DOMAIN, DEFAULT_CONFIG_2 + hass, + mqtt_mock_entry_with_yaml_config, + caplog, + vacuum.DOMAIN, + DEFAULT_CONFIG_2_LEGACY, ) async def test_discovery_update_attr(hass, mqtt_mock_entry_no_yaml_config, caplog): """Test update of discovered MQTTAttributes.""" await help_test_discovery_update_attr( - hass, mqtt_mock_entry_no_yaml_config, caplog, vacuum.DOMAIN, DEFAULT_CONFIG_2 + hass, + mqtt_mock_entry_no_yaml_config, + caplog, + vacuum.DOMAIN, + DEFAULT_CONFIG_2_LEGACY, ) @@ -702,7 +732,7 @@ async def test_unique_id(hass, mqtt_mock_entry_with_yaml_config): async def test_discovery_removal_vacuum(hass, mqtt_mock_entry_no_yaml_config, caplog): """Test removal of discovered vacuum.""" - data = json.dumps(DEFAULT_CONFIG_2[vacuum.DOMAIN]) + data = json.dumps(DEFAULT_CONFIG_2_LEGACY[vacuum.DOMAIN]) await help_test_discovery_removal( hass, mqtt_mock_entry_no_yaml_config, caplog, vacuum.DOMAIN, data ) @@ -748,28 +778,28 @@ async def test_discovery_broken(hass, mqtt_mock_entry_no_yaml_config, caplog): async def test_entity_device_info_with_connection(hass, mqtt_mock_entry_no_yaml_config): """Test MQTT vacuum device registry integration.""" await help_test_entity_device_info_with_connection( - hass, mqtt_mock_entry_no_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2 + hass, mqtt_mock_entry_no_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2_LEGACY ) async def test_entity_device_info_with_identifier(hass, mqtt_mock_entry_no_yaml_config): """Test MQTT vacuum device registry integration.""" await help_test_entity_device_info_with_identifier( - hass, mqtt_mock_entry_no_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2 + hass, mqtt_mock_entry_no_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2_LEGACY ) async def test_entity_device_info_update(hass, mqtt_mock_entry_no_yaml_config): """Test device registry update.""" await help_test_entity_device_info_update( - hass, mqtt_mock_entry_no_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2 + hass, mqtt_mock_entry_no_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2_LEGACY ) async def test_entity_device_info_remove(hass, mqtt_mock_entry_no_yaml_config): """Test device registry remove.""" await help_test_entity_device_info_remove( - hass, mqtt_mock_entry_no_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2 + hass, mqtt_mock_entry_no_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2_LEGACY ) @@ -797,7 +827,7 @@ async def test_entity_id_update_subscriptions(hass, mqtt_mock_entry_with_yaml_co async def test_entity_id_update_discovery_update(hass, mqtt_mock_entry_no_yaml_config): """Test MQTT discovery update when entity_id is updated.""" await help_test_entity_id_update_discovery_update( - hass, mqtt_mock_entry_no_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2 + hass, mqtt_mock_entry_no_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2_LEGACY ) @@ -874,7 +904,7 @@ async def test_publishing_with_custom_encoding( ): """Test publishing MQTT payload with different encoding.""" domain = vacuum.DOMAIN - config = deepcopy(DEFAULT_CONFIG) + config = deepcopy(DEFAULT_CONFIG_LEGACY[domain]) config["supported_features"] = [ "turn_on", "turn_off", @@ -900,7 +930,7 @@ async def test_publishing_with_custom_encoding( async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path): """Test reloading the MQTT platform.""" domain = vacuum.DOMAIN - config = DEFAULT_CONFIG + config = DEFAULT_CONFIG_LEGACY[domain] await help_test_reloadable( hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config ) @@ -909,7 +939,7 @@ async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_pa async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path): """Test reloading the MQTT platform with late entry setup.""" domain = vacuum.DOMAIN - config = DEFAULT_CONFIG + config = DEFAULT_CONFIG_LEGACY[domain] await help_test_reloadable_late(hass, caplog, tmp_path, domain, config) @@ -944,7 +974,8 @@ async def test_encoding_subscribable_topics( attribute_value, ): """Test handling of incoming encoded payload.""" - config = deepcopy(DEFAULT_CONFIG) + domain = vacuum.DOMAIN + config = deepcopy(DEFAULT_CONFIG_LEGACY[domain]) config[CONF_SUPPORTED_FEATURES] = [ "turn_on", "turn_off", @@ -976,8 +1007,21 @@ async def test_encoding_subscribable_topics( async def test_setup_manual_entity_from_yaml(hass): """Test setup manual configured MQTT entity.""" platform = vacuum.DOMAIN - config = deepcopy(DEFAULT_CONFIG) + config = deepcopy(DEFAULT_CONFIG_LEGACY[platform]) config["name"] = "test" del config["platform"] await help_test_setup_manual_entity_from_yaml(hass, platform, config) assert hass.states.get(f"{platform}.test") is not None + + +# Test deprecated YAML configuration under the platform key +# Scheduled to be removed in HA core 2022.12 +async def test_setup_with_legacy_schema(hass, mqtt_mock_entry_with_yaml_config): + """Test a setup with deprecated yaml platform schema.""" + domain = vacuum.DOMAIN + config = deepcopy(DEFAULT_CONFIG_LEGACY[domain]) + config["name"] = "test" + assert await async_setup_component(hass, domain, {domain: config}) + await hass.async_block_till_done() + await mqtt_mock_entry_with_yaml_config() + assert hass.states.get(f"{domain}.test") is not None