Move entity category to entity platform config flow step

This commit is contained in:
jbouwh
2025-06-18 16:29:22 +00:00
parent 0d1234ac8f
commit df7592abe6
2 changed files with 69 additions and 113 deletions

View File

@@ -2107,8 +2107,6 @@ def data_schema_from_fields(
if field_details.section == schema_section if field_details.section == schema_section
and field_details.exclude_from_reconfig and field_details.exclude_from_reconfig
} }
if not data_element_options:
continue
if schema_section is None: if schema_section is None:
data_schema.update(data_schema_element) data_schema.update(data_schema_element)
continue continue
@@ -2884,8 +2882,6 @@ class MQTTSubentryFlowHandler(ConfigSubentryFlow):
component_data=component_data, component_data=component_data,
user_input=user_input, user_input=user_input,
) )
if not data_schema.schema:
return await self.async_step_mqtt_platform_config()
if user_input is not None: if user_input is not None:
# Test entity fields against the validator # Test entity fields against the validator
merged_user_input, errors = validate_user_input( merged_user_input, errors = validate_user_input(

View File

@@ -2654,7 +2654,6 @@ async def test_migrate_of_incompatible_config_entry(
"config_subentries_data", "config_subentries_data",
"mock_device_user_input", "mock_device_user_input",
"mock_entity_user_input", "mock_entity_user_input",
"mock_entity_failed_user_input",
"mock_entity_details_user_input", "mock_entity_details_user_input",
"mock_entity_details_failed_user_input", "mock_entity_details_failed_user_input",
"mock_mqtt_user_input", "mock_mqtt_user_input",
@@ -2666,16 +2665,6 @@ async def test_migrate_of_incompatible_config_entry(
MOCK_BINARY_SENSOR_SUBENTRY_DATA_SINGLE, MOCK_BINARY_SENSOR_SUBENTRY_DATA_SINGLE,
{"name": "Milk notifier", "mqtt_settings": {"qos": 2}}, {"name": "Milk notifier", "mqtt_settings": {"qos": 2}},
{"name": "Hatch"}, {"name": "Hatch"},
(
(
(
{"entity_category": "config"},
{
"entity_category": "sensor_entity_category_must_not_be_config"
},
),
)
),
{"device_class": "door"}, {"device_class": "door"},
(), (),
{ {
@@ -2695,7 +2684,6 @@ async def test_migrate_of_incompatible_config_entry(
MOCK_BUTTON_SUBENTRY_DATA_SINGLE, MOCK_BUTTON_SUBENTRY_DATA_SINGLE,
{"name": "Milk notifier", "mqtt_settings": {"qos": 2}}, {"name": "Milk notifier", "mqtt_settings": {"qos": 2}},
{"name": "Restart"}, {"name": "Restart"},
(),
{"device_class": "restart"}, {"device_class": "restart"},
(), (),
{ {
@@ -2716,7 +2704,6 @@ async def test_migrate_of_incompatible_config_entry(
MOCK_COVER_SUBENTRY_DATA_SINGLE, MOCK_COVER_SUBENTRY_DATA_SINGLE,
{"name": "Milk notifier", "mqtt_settings": {"qos": 0}}, {"name": "Milk notifier", "mqtt_settings": {"qos": 0}},
{"name": "Blind"}, {"name": "Blind"},
(),
{"device_class": "blind"}, {"device_class": "blind"},
(), (),
{ {
@@ -2803,7 +2790,6 @@ async def test_migrate_of_incompatible_config_entry(
MOCK_FAN_SUBENTRY_DATA_SINGLE, MOCK_FAN_SUBENTRY_DATA_SINGLE,
{"name": "Milk notifier", "mqtt_settings": {"qos": 0}}, {"name": "Milk notifier", "mqtt_settings": {"qos": 0}},
{"name": "Breezer"}, {"name": "Breezer"},
(),
{ {
"fan_feature_speed": True, "fan_feature_speed": True,
"fan_feature_preset_modes": True, "fan_feature_preset_modes": True,
@@ -2955,9 +2941,8 @@ async def test_migrate_of_incompatible_config_entry(
MOCK_NOTIFY_SUBENTRY_DATA_SINGLE, MOCK_NOTIFY_SUBENTRY_DATA_SINGLE,
{"name": "Milk notifier", "mqtt_settings": {"qos": 1}}, {"name": "Milk notifier", "mqtt_settings": {"qos": 1}},
{"name": "Milkman alert"}, {"name": "Milkman alert"},
{},
(), (),
None,
None,
{ {
"command_topic": "test-topic", "command_topic": "test-topic",
"command_template": "{{ value }}", "command_template": "{{ value }}",
@@ -2975,9 +2960,8 @@ async def test_migrate_of_incompatible_config_entry(
MOCK_NOTIFY_SUBENTRY_DATA_NO_NAME, MOCK_NOTIFY_SUBENTRY_DATA_NO_NAME,
{"name": "Milk notifier", "mqtt_settings": {"qos": 0}}, {"name": "Milk notifier", "mqtt_settings": {"qos": 0}},
{}, {},
{},
(), (),
None,
None,
{ {
"command_topic": "test-topic", "command_topic": "test-topic",
"command_template": "{{ value }}", "command_template": "{{ value }}",
@@ -2995,16 +2979,6 @@ async def test_migrate_of_incompatible_config_entry(
MOCK_SENSOR_SUBENTRY_DATA_SINGLE, MOCK_SENSOR_SUBENTRY_DATA_SINGLE,
{"name": "Milk notifier", "mqtt_settings": {"qos": 0}}, {"name": "Milk notifier", "mqtt_settings": {"qos": 0}},
{"name": "Energy"}, {"name": "Energy"},
(
(
(
{"entity_category": "config"},
{
"entity_category": "sensor_entity_category_must_not_be_config"
},
),
)
),
{"device_class": "enum", "options": ["low", "medium", "high"]}, {"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, MOCK_SENSOR_SUBENTRY_DATA_SINGLE_STATE_CLASS,
{"name": "Milk notifier", "mqtt_settings": {"qos": 0}}, {"name": "Milk notifier", "mqtt_settings": {"qos": 0}},
{"name": "Energy"}, {"name": "Energy"},
(),
{ {
"state_class": "measurement", "state_class": "measurement",
}, },
@@ -3084,7 +3057,6 @@ async def test_migrate_of_incompatible_config_entry(
MOCK_SWITCH_SUBENTRY_DATA_SINGLE_STATE_CLASS, MOCK_SWITCH_SUBENTRY_DATA_SINGLE_STATE_CLASS,
{"name": "Milk notifier", "mqtt_settings": {"qos": 0}}, {"name": "Milk notifier", "mqtt_settings": {"qos": 0}},
{"name": "Outlet"}, {"name": "Outlet"},
(),
{"device_class": "outlet"}, {"device_class": "outlet"},
(), (),
{ {
@@ -3113,7 +3085,6 @@ async def test_migrate_of_incompatible_config_entry(
MOCK_LIGHT_BASIC_KELVIN_SUBENTRY_DATA_SINGLE, MOCK_LIGHT_BASIC_KELVIN_SUBENTRY_DATA_SINGLE,
{"name": "Milk notifier", "mqtt_settings": {"qos": 1}}, {"name": "Milk notifier", "mqtt_settings": {"qos": 1}},
{"name": "Basic light"}, {"name": "Basic light"},
(),
{}, {},
{}, {},
{ {
@@ -3175,7 +3146,6 @@ async def test_subentry_configflow(
config_subentries_data: dict[str, Any], config_subentries_data: dict[str, Any],
mock_device_user_input: dict[str, Any], mock_device_user_input: dict[str, Any],
mock_entity_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_user_input: dict[str, Any],
mock_entity_details_failed_user_input: tuple[ mock_entity_details_failed_user_input: tuple[
tuple[dict[str, Any], dict[str, str]], tuple[dict[str, Any], dict[str, str]],
@@ -3232,16 +3202,6 @@ async def test_subentry_configflow(
assert result["type"] is FlowResultType.FORM assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "entity" 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 # Try again with valid data
result = await hass.config_entries.subentries.async_configure( result = await hass.config_entries.subentries.async_configure(
result["flow_id"], result["flow_id"],
@@ -3260,9 +3220,7 @@ async def test_subentry_configflow(
"url": learn_more_url(component["platform"]), "url": learn_more_url(component["platform"]),
} }
# Process extra step if the platform supports it # Process entity details setep
if mock_entity_details_user_input is not None:
# Extra entity details flow step
assert result["step_id"] == "entity_platform_config" assert result["step_id"] == "entity_platform_config"
# First test validators if set of test # First test validators if set of test
@@ -3288,9 +3246,6 @@ async def test_subentry_configflow(
"entity": entity_name, "entity": entity_name,
"url": learn_more_url(component["platform"]), "url": learn_more_url(component["platform"]),
} }
else:
# No details form step
assert result["step_id"] == "mqtt_platform_config"
# Process mqtt platform config flow # Process mqtt platform config flow
# Test an invalid mqtt user input case # 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["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" assert result["step_id"] == "mqtt_platform_config"
# submit the new platform specific entity data # 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_topic": "test-topic1-updated",
"command_template": "{{ value }}", "command_template": "{{ value }}",
@@ -3652,8 +3617,8 @@ async def test_subentry_reconfigure_edit_entity_multi_entitites(
title="Mock subentry", title="Mock subentry",
), ),
), ),
None, (),
None, {},
{ {
"command_topic": "test-topic1-updated", "command_topic": "test-topic1-updated",
"state_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], ... tuple[dict[str, Any], dict[str, str] | None], ...
] ]
| None, | None,
user_input_platform_config: dict[str, Any] | None, user_input_platform_config: dict[str, Any],
user_input_mqtt: dict[str, Any], user_input_mqtt: dict[str, Any],
component_data: dict[str, Any], component_data: dict[str, Any],
removed_options: tuple[str, ...], removed_options: tuple[str, ...],
@@ -3740,12 +3705,9 @@ async def test_subentry_reconfigure_edit_entity_single_entity(
user_input={}, user_input={},
) )
assert result["type"] is FlowResultType.FORM assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "entity_platform_config"
if user_input_platform_config is None: # entity platform config flow step
# Skip entity flow step
assert result["step_id"] == "mqtt_platform_config"
else:
# Additional entity flow step
assert result["step_id"] == "entity_platform_config" assert result["step_id"] == "entity_platform_config"
for entity_validation_config, errors in user_input_platform_config_validation: for entity_validation_config, errors in user_input_platform_config_validation:
result = await hass.config_entries.subentries.async_configure( result = await hass.config_entries.subentries.async_configure(
@@ -3928,7 +3890,12 @@ async def test_subentry_reconfigure_edit_entity_reset_fields(
@pytest.mark.parametrize( @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", "name": "The second notifier",
"entity_picture": "https://example.com", "entity_picture": "https://example.com",
}, },
{"entity_category": "diagnostic"},
{ {
"command_topic": "test-topic2", "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( async def test_subentry_reconfigure_add_entity(
hass: HomeAssistant, hass: HomeAssistant,
@@ -3973,6 +3924,7 @@ async def test_subentry_reconfigure_add_entity(
device_registry: dr.DeviceRegistry, device_registry: dr.DeviceRegistry,
entity_registry: er.EntityRegistry, entity_registry: er.EntityRegistry,
user_input_entity: dict[str, Any], user_input_entity: dict[str, Any],
user_input_entity_platform_config: dict[str, Any],
user_input_mqtt: dict[str, Any], user_input_mqtt: dict[str, Any],
) -> None: ) -> None:
"""Test the subentry ConfigFlow reconfigure and add an entity.""" """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, user_input=user_input_entity,
) )
assert result["type"] is FlowResultType.FORM 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" assert result["step_id"] == "mqtt_platform_config"
# submit the new platform specific entity data # submit the new platform specific entity data