diff --git a/homeassistant/components/mqtt/config_flow.py b/homeassistant/components/mqtt/config_flow.py index 15f3f647c84..65395dd3d2c 100644 --- a/homeassistant/components/mqtt/config_flow.py +++ b/homeassistant/components/mqtt/config_flow.py @@ -2107,8 +2107,6 @@ def data_schema_from_fields( if field_details.section == schema_section and field_details.exclude_from_reconfig } - if not data_element_options: - continue if schema_section is None: data_schema.update(data_schema_element) continue @@ -2884,8 +2882,6 @@ class MQTTSubentryFlowHandler(ConfigSubentryFlow): component_data=component_data, user_input=user_input, ) - if not data_schema.schema: - return await self.async_step_mqtt_platform_config() if user_input is not None: # Test entity fields against the validator merged_user_input, errors = validate_user_input( diff --git a/tests/components/mqtt/test_config_flow.py b/tests/components/mqtt/test_config_flow.py index 8233fde9353..092d6af4f14 100644 --- a/tests/components/mqtt/test_config_flow.py +++ b/tests/components/mqtt/test_config_flow.py @@ -2654,7 +2654,6 @@ async def test_migrate_of_incompatible_config_entry( "config_subentries_data", "mock_device_user_input", "mock_entity_user_input", - "mock_entity_failed_user_input", "mock_entity_details_user_input", "mock_entity_details_failed_user_input", "mock_mqtt_user_input", @@ -2666,16 +2665,6 @@ async def test_migrate_of_incompatible_config_entry( MOCK_BINARY_SENSOR_SUBENTRY_DATA_SINGLE, {"name": "Milk notifier", "mqtt_settings": {"qos": 2}}, {"name": "Hatch"}, - ( - ( - ( - {"entity_category": "config"}, - { - "entity_category": "sensor_entity_category_must_not_be_config" - }, - ), - ) - ), {"device_class": "door"}, (), { @@ -2695,7 +2684,6 @@ async def test_migrate_of_incompatible_config_entry( MOCK_BUTTON_SUBENTRY_DATA_SINGLE, {"name": "Milk notifier", "mqtt_settings": {"qos": 2}}, {"name": "Restart"}, - (), {"device_class": "restart"}, (), { @@ -2716,7 +2704,6 @@ async def test_migrate_of_incompatible_config_entry( MOCK_COVER_SUBENTRY_DATA_SINGLE, {"name": "Milk notifier", "mqtt_settings": {"qos": 0}}, {"name": "Blind"}, - (), {"device_class": "blind"}, (), { @@ -2803,7 +2790,6 @@ async def test_migrate_of_incompatible_config_entry( MOCK_FAN_SUBENTRY_DATA_SINGLE, {"name": "Milk notifier", "mqtt_settings": {"qos": 0}}, {"name": "Breezer"}, - (), { "fan_feature_speed": True, "fan_feature_preset_modes": True, @@ -2955,9 +2941,8 @@ async def test_migrate_of_incompatible_config_entry( MOCK_NOTIFY_SUBENTRY_DATA_SINGLE, {"name": "Milk notifier", "mqtt_settings": {"qos": 1}}, {"name": "Milkman alert"}, + {}, (), - None, - None, { "command_topic": "test-topic", "command_template": "{{ value }}", @@ -2975,9 +2960,8 @@ async def test_migrate_of_incompatible_config_entry( MOCK_NOTIFY_SUBENTRY_DATA_NO_NAME, {"name": "Milk notifier", "mqtt_settings": {"qos": 0}}, {}, + {}, (), - None, - None, { "command_topic": "test-topic", "command_template": "{{ value }}", @@ -2995,16 +2979,6 @@ async def test_migrate_of_incompatible_config_entry( MOCK_SENSOR_SUBENTRY_DATA_SINGLE, {"name": "Milk notifier", "mqtt_settings": {"qos": 0}}, {"name": "Energy"}, - ( - ( - ( - {"entity_category": "config"}, - { - "entity_category": "sensor_entity_category_must_not_be_config" - }, - ), - ) - ), {"device_class": "enum", "options": ["low", "medium", "high"]}, ( ( @@ -3061,7 +3035,6 @@ async def test_migrate_of_incompatible_config_entry( MOCK_SENSOR_SUBENTRY_DATA_SINGLE_STATE_CLASS, {"name": "Milk notifier", "mqtt_settings": {"qos": 0}}, {"name": "Energy"}, - (), { "state_class": "measurement", }, @@ -3084,7 +3057,6 @@ async def test_migrate_of_incompatible_config_entry( MOCK_SWITCH_SUBENTRY_DATA_SINGLE_STATE_CLASS, {"name": "Milk notifier", "mqtt_settings": {"qos": 0}}, {"name": "Outlet"}, - (), {"device_class": "outlet"}, (), { @@ -3113,7 +3085,6 @@ async def test_migrate_of_incompatible_config_entry( MOCK_LIGHT_BASIC_KELVIN_SUBENTRY_DATA_SINGLE, {"name": "Milk notifier", "mqtt_settings": {"qos": 1}}, {"name": "Basic light"}, - (), {}, {}, { @@ -3175,7 +3146,6 @@ async def test_subentry_configflow( config_subentries_data: dict[str, Any], mock_device_user_input: dict[str, Any], mock_entity_user_input: dict[str, Any], - mock_entity_failed_user_input: tuple[tuple[dict[str, Any], dict[str, str]],], mock_entity_details_user_input: dict[str, Any], mock_entity_details_failed_user_input: tuple[ tuple[dict[str, Any], dict[str, str]], @@ -3232,16 +3202,6 @@ async def test_subentry_configflow( assert result["type"] is FlowResultType.FORM assert result["step_id"] == "entity" - # First test platform validators if set of test - for failed_user_input, failed_errors in mock_entity_failed_user_input: - # Test an invalid entity details user input case - result = await hass.config_entries.subentries.async_configure( - result["flow_id"], - user_input={"platform": component["platform"]} | failed_user_input, - ) - assert result["type"] is FlowResultType.FORM - assert result["errors"] == failed_errors - # Try again with valid data result = await hass.config_entries.subentries.async_configure( result["flow_id"], @@ -3260,37 +3220,32 @@ async def test_subentry_configflow( "url": learn_more_url(component["platform"]), } - # Process extra step if the platform supports it - if mock_entity_details_user_input is not None: - # Extra entity details flow step - assert result["step_id"] == "entity_platform_config" + # Process entity details setep + assert result["step_id"] == "entity_platform_config" - # First test validators if set of test - for failed_user_input, failed_errors in mock_entity_details_failed_user_input: - # Test an invalid entity details user input case - result = await hass.config_entries.subentries.async_configure( - result["flow_id"], - user_input=failed_user_input, - ) - assert result["type"] is FlowResultType.FORM - assert result["errors"] == failed_errors - - # Now try again with valid data + # First test validators if set of test + for failed_user_input, failed_errors in mock_entity_details_failed_user_input: + # Test an invalid entity details user input case result = await hass.config_entries.subentries.async_configure( result["flow_id"], - user_input=mock_entity_details_user_input, + user_input=failed_user_input, ) assert result["type"] is FlowResultType.FORM - assert result["errors"] == {} - assert result["description_placeholders"] == { - "mqtt_device": device_name, - "platform": component["platform"], - "entity": entity_name, - "url": learn_more_url(component["platform"]), - } - else: - # No details form step - assert result["step_id"] == "mqtt_platform_config" + assert result["errors"] == failed_errors + + # Now try again with valid data + result = await hass.config_entries.subentries.async_configure( + result["flow_id"], + user_input=mock_entity_details_user_input, + ) + assert result["type"] is FlowResultType.FORM + assert result["errors"] == {} + assert result["description_placeholders"] == { + "mqtt_device": device_name, + "platform": component["platform"], + "entity": entity_name, + "url": learn_more_url(component["platform"]), + } # Process mqtt platform config flow # Test an invalid mqtt user input case @@ -3545,6 +3500,16 @@ async def test_subentry_reconfigure_edit_entity_multi_entitites( }, ) assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "entity_platform_config" + + # submit the platform specific entity data with changed entity_category + result = await hass.config_entries.subentries.async_configure( + result["flow_id"], + user_input={ + "entity_category": "config", + }, + ) + assert result["type"] is FlowResultType.FORM assert result["step_id"] == "mqtt_platform_config" # submit the new platform specific entity data @@ -3591,7 +3556,7 @@ async def test_subentry_reconfigure_edit_entity_multi_entitites( ), ), (), - None, + {}, { "command_topic": "test-topic1-updated", "command_template": "{{ value }}", @@ -3652,8 +3617,8 @@ async def test_subentry_reconfigure_edit_entity_multi_entitites( title="Mock subentry", ), ), - None, - None, + (), + {}, { "command_topic": "test-topic1-updated", "state_topic": "test-topic1-updated", @@ -3680,7 +3645,7 @@ async def test_subentry_reconfigure_edit_entity_single_entity( tuple[dict[str, Any], dict[str, str] | None], ... ] | None, - user_input_platform_config: dict[str, Any] | None, + user_input_platform_config: dict[str, Any], user_input_mqtt: dict[str, Any], component_data: dict[str, Any], removed_options: tuple[str, ...], @@ -3740,28 +3705,25 @@ async def test_subentry_reconfigure_edit_entity_single_entity( user_input={}, ) assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "entity_platform_config" - if user_input_platform_config is None: - # Skip entity flow step - assert result["step_id"] == "mqtt_platform_config" - else: - # Additional entity flow step - assert result["step_id"] == "entity_platform_config" - for entity_validation_config, errors in user_input_platform_config_validation: - result = await hass.config_entries.subentries.async_configure( - result["flow_id"], - user_input=entity_validation_config, - ) - assert result["step_id"] == "entity_platform_config" - assert result.get("errors") == errors - assert result["type"] is FlowResultType.FORM - + # entity platform config flow step + assert result["step_id"] == "entity_platform_config" + for entity_validation_config, errors in user_input_platform_config_validation: result = await hass.config_entries.subentries.async_configure( result["flow_id"], - user_input=user_input_platform_config, + user_input=entity_validation_config, ) + assert result["step_id"] == "entity_platform_config" + assert result.get("errors") == errors assert result["type"] is FlowResultType.FORM - assert result["step_id"] == "mqtt_platform_config" + + result = await hass.config_entries.subentries.async_configure( + result["flow_id"], + user_input=user_input_platform_config, + ) + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "mqtt_platform_config" # submit the new platform specific entity data, result = await hass.config_entries.subentries.async_configure( @@ -3928,7 +3890,12 @@ async def test_subentry_reconfigure_edit_entity_reset_fields( @pytest.mark.parametrize( - ("mqtt_config_subentries_data", "user_input_entity", "user_input_mqtt"), + ( + "mqtt_config_subentries_data", + "user_input_entity", + "user_input_entity_platform_config", + "user_input_mqtt", + ), [ ( ( @@ -3943,29 +3910,13 @@ async def test_subentry_reconfigure_edit_entity_reset_fields( "name": "The second notifier", "entity_picture": "https://example.com", }, + {"entity_category": "diagnostic"}, { "command_topic": "test-topic2", }, - ), - ( - ( - ConfigSubentryData( - data=MOCK_NOTIFY_SUBENTRY_DATA_SINGLE, - subentry_type="device", - title="Mock subentry", - ), - ), - { - "platform": "notify", - "name": "The second notifier", - "entity_category": "config", - }, - { - "command_topic": "test-topic2", - }, - ), + ) ], - ids=["notify_notify_no_entity_category", "notify_notify_entity_category"], + ids=["notify_notify"], ) async def test_subentry_reconfigure_add_entity( hass: HomeAssistant, @@ -3973,6 +3924,7 @@ async def test_subentry_reconfigure_add_entity( device_registry: dr.DeviceRegistry, entity_registry: er.EntityRegistry, user_input_entity: dict[str, Any], + user_input_entity_platform_config: dict[str, Any], user_input_mqtt: dict[str, Any], ) -> None: """Test the subentry ConfigFlow reconfigure and add an entity.""" @@ -4027,6 +3979,14 @@ async def test_subentry_reconfigure_add_entity( user_input=user_input_entity, ) assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "entity_platform_config" + + # submit the new entity platform config + result = await hass.config_entries.subentries.async_configure( + result["flow_id"], + user_input=user_input_entity_platform_config, + ) + assert result["type"] is FlowResultType.FORM assert result["step_id"] == "mqtt_platform_config" # submit the new platform specific entity data