Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions homeassistant/helpers/config_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,17 @@ def entity_id(value: Any) -> str:
raise vol.Invalid(f"Entity ID {value} is an invalid entity ID")


def strict_entity_id(value: Any) -> str:
"""Validate Entity ID, strictly."""
if not isinstance(value, str):
raise vol.Invalid(f"Entity ID {value} is not a string")

if valid_entity_id(value):
return value

raise vol.Invalid(f"Entity ID {value} is not a valid entity ID")


def entity_id_or_uuid(value: Any) -> str:
"""Validate Entity specified by entity_id or uuid."""
with contextlib.suppress(vol.Invalid):
Expand Down Expand Up @@ -1292,6 +1303,15 @@ def platform_only_config_schema(domain: str) -> Callable[[dict], dict]:

PLATFORM_SCHEMA_BASE = PLATFORM_SCHEMA.extend({}, extra=vol.ALLOW_EXTRA)


Comment thread
arturpragacz marked this conversation as resolved.
TARGET_FIELDS: VolDictType = {
vol.Optional(ATTR_ENTITY_ID): vol.All(ensure_list, [strict_entity_id]),
vol.Optional(ATTR_DEVICE_ID): vol.All(ensure_list, [str]),
vol.Optional(ATTR_AREA_ID): vol.All(ensure_list, [str]),
vol.Optional(ATTR_FLOOR_ID): vol.All(ensure_list, [str]),
vol.Optional(ATTR_LABEL_ID): vol.All(ensure_list, [str]),
}

ENTITY_SERVICE_FIELDS: VolDictType = {
# Either accept static entity IDs, a single dynamic template or a mixed list
# of static and dynamic templates. While this could be solved with a single
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/helpers/llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -827,7 +827,7 @@ def selector_serializer(schema: Any) -> Any: # noqa: C901
return {"type": "string", "enum": options}

if isinstance(schema, selector.TargetSelector):
return convert(cv.TARGET_SERVICE_FIELDS)
return convert(cv.TARGET_FIELDS)

if isinstance(schema, selector.TemplateSelector):
return {"type": "string", "format": "jinja2"}
Expand Down
39 changes: 5 additions & 34 deletions tests/helpers/test_llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -1216,43 +1216,14 @@ async def test_selector_serializer(
selector.StateSelector({"entity_id": "sensor.test"})
) == {"type": "string"}
target_schema = selector_serializer(selector.TargetSelector())
target_schema["properties"]["entity_id"]["anyOf"][0][
"enum"
].sort() # Order is not deterministic
assert target_schema == {
"type": "object",
"properties": {
"area_id": {
"anyOf": [
{"type": "string", "enum": ["none"]},
{"type": "array", "items": {"type": "string", "nullable": True}},
]
},
"device_id": {
"anyOf": [
{"type": "string", "enum": ["none"]},
{"type": "array", "items": {"type": "string", "nullable": True}},
]
},
"entity_id": {
"anyOf": [
{"type": "string", "enum": ["all", "none"], "format": "lower"},
{"type": "string", "nullable": True},
{"type": "array", "items": {"type": "string"}},
]
},
"floor_id": {
"anyOf": [
{"type": "string", "enum": ["none"]},
{"type": "array", "items": {"type": "string", "nullable": True}},
]
},
"label_id": {
"anyOf": [
{"type": "string", "enum": ["none"]},
{"type": "array", "items": {"type": "string", "nullable": True}},
]
},
"area_id": {"items": {"type": "string"}, "type": "array"},
"device_id": {"items": {"type": "string"}, "type": "array"},
"entity_id": {"items": {"type": "string"}, "type": "array"},
"floor_id": {"items": {"type": "string"}, "type": "array"},
"label_id": {"items": {"type": "string"}, "type": "array"},
},
"required": [],
}
Expand Down