forked from home-assistant/core
Move entity category to entity platform config flow step
This commit is contained in:
@@ -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(
|
||||||
|
@@ -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,37 +3220,32 @@ 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:
|
assert result["step_id"] == "entity_platform_config"
|
||||||
# Extra entity details flow step
|
|
||||||
assert result["step_id"] == "entity_platform_config"
|
|
||||||
|
|
||||||
# First test validators if set of test
|
# First test validators if set of test
|
||||||
for failed_user_input, failed_errors in mock_entity_details_failed_user_input:
|
for failed_user_input, failed_errors in mock_entity_details_failed_user_input:
|
||||||
# Test an invalid entity details user input case
|
# 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
|
|
||||||
result = await hass.config_entries.subentries.async_configure(
|
result = await hass.config_entries.subentries.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
user_input=mock_entity_details_user_input,
|
user_input=failed_user_input,
|
||||||
)
|
)
|
||||||
assert result["type"] is FlowResultType.FORM
|
assert result["type"] is FlowResultType.FORM
|
||||||
assert result["errors"] == {}
|
assert result["errors"] == failed_errors
|
||||||
assert result["description_placeholders"] == {
|
|
||||||
"mqtt_device": device_name,
|
# Now try again with valid data
|
||||||
"platform": component["platform"],
|
result = await hass.config_entries.subentries.async_configure(
|
||||||
"entity": entity_name,
|
result["flow_id"],
|
||||||
"url": learn_more_url(component["platform"]),
|
user_input=mock_entity_details_user_input,
|
||||||
}
|
)
|
||||||
else:
|
assert result["type"] is FlowResultType.FORM
|
||||||
# No details form step
|
assert result["errors"] == {}
|
||||||
assert result["step_id"] == "mqtt_platform_config"
|
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
|
# 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,28 +3705,25 @@ 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"] == "entity_platform_config"
|
||||||
assert result["step_id"] == "mqtt_platform_config"
|
for entity_validation_config, errors in user_input_platform_config_validation:
|
||||||
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
|
|
||||||
|
|
||||||
result = await hass.config_entries.subentries.async_configure(
|
result = await hass.config_entries.subentries.async_configure(
|
||||||
result["flow_id"],
|
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["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,
|
# submit the new platform specific entity data,
|
||||||
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
|
||||||
|
Reference in New Issue
Block a user