mirror of
https://github.com/home-assistant/core.git
synced 2025-11-15 14:00:24 +00:00
Compare commits
10 Commits
copilot/ad
...
services-t
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5baad9a87 | ||
|
|
e50dbbf873 | ||
|
|
8d284244bb | ||
|
|
229587d5b6 | ||
|
|
d78dffd4a5 | ||
|
|
10b387e9a5 | ||
|
|
f2e7e65849 | ||
|
|
c54905a5ba | ||
|
|
854780fa8a | ||
|
|
0b1817ad73 |
@@ -30,7 +30,7 @@ from homeassistant.const import (
|
|||||||
UnitOfTemperature,
|
UnitOfTemperature,
|
||||||
UnitOfVolume,
|
UnitOfVolume,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant, ServiceCall, callback
|
from homeassistant.core import HomeAssistant, ServiceCall, ServiceResponse, callback
|
||||||
from homeassistant.helpers import config_validation as cv
|
from homeassistant.helpers import config_validation as cv
|
||||||
from homeassistant.helpers.device_registry import DeviceEntry
|
from homeassistant.helpers.device_registry import DeviceEntry
|
||||||
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
|
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
|
||||||
@@ -76,11 +76,22 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||||||
)
|
)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def service_handler(call: ServiceCall | None = None) -> None:
|
def service_handler(call: ServiceCall | None = None) -> ServiceResponse:
|
||||||
"""Do nothing."""
|
"""Do nothing."""
|
||||||
|
return None
|
||||||
|
|
||||||
hass.services.async_register(
|
hass.services.async_register(
|
||||||
DOMAIN, "test_service_1", service_handler, SCHEMA_SERVICE_TEST_SERVICE_1
|
DOMAIN,
|
||||||
|
"test_service_1",
|
||||||
|
service_handler,
|
||||||
|
SCHEMA_SERVICE_TEST_SERVICE_1,
|
||||||
|
description_placeholders={
|
||||||
|
"meep_1": "foo",
|
||||||
|
"meep_2": "bar",
|
||||||
|
"meep_3": "beer",
|
||||||
|
"meep_4": "milk",
|
||||||
|
"meep_5": "https://example.com",
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -105,14 +105,16 @@
|
|||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
"test_service_1": {
|
"test_service_1": {
|
||||||
"description": "Fake action for testing",
|
"description": "Fake action for testing {meep_2}",
|
||||||
"fields": {
|
"fields": {
|
||||||
"field_1": {
|
"field_1": {
|
||||||
"description": "Number of seconds",
|
"description": "Number of seconds {meep_4}",
|
||||||
"name": "Field 1"
|
"example": "Example: {meep_5}",
|
||||||
|
"name": "Field 1 {meep_3}"
|
||||||
},
|
},
|
||||||
"field_2": {
|
"field_2": {
|
||||||
"description": "Mode",
|
"description": "Mode",
|
||||||
|
"example": "Field 2 example",
|
||||||
"name": "Field 2"
|
"name": "Field 2"
|
||||||
},
|
},
|
||||||
"field_3": {
|
"field_3": {
|
||||||
@@ -124,7 +126,7 @@
|
|||||||
"name": "Field 4"
|
"name": "Field 4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"name": "Test action 1",
|
"name": "Test action {meep_1}",
|
||||||
"sections": {
|
"sections": {
|
||||||
"advanced_fields": {
|
"advanced_fields": {
|
||||||
"description": "Some very advanced things",
|
"description": "Some very advanced things",
|
||||||
|
|||||||
@@ -2426,7 +2426,14 @@ class SupportsResponse(enum.StrEnum):
|
|||||||
class Service:
|
class Service:
|
||||||
"""Representation of a callable service."""
|
"""Representation of a callable service."""
|
||||||
|
|
||||||
__slots__ = ["domain", "job", "schema", "service", "supports_response"]
|
__slots__ = [
|
||||||
|
"description_placeholders",
|
||||||
|
"domain",
|
||||||
|
"job",
|
||||||
|
"schema",
|
||||||
|
"service",
|
||||||
|
"supports_response",
|
||||||
|
]
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@@ -2443,11 +2450,13 @@ class Service:
|
|||||||
context: Context | None = None,
|
context: Context | None = None,
|
||||||
supports_response: SupportsResponse = SupportsResponse.NONE,
|
supports_response: SupportsResponse = SupportsResponse.NONE,
|
||||||
job_type: HassJobType | None = None,
|
job_type: HassJobType | None = None,
|
||||||
|
description_placeholders: Mapping[str, str] | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize a service."""
|
"""Initialize a service."""
|
||||||
self.job = HassJob(func, f"service {domain}.{service}", job_type=job_type)
|
self.job = HassJob(func, f"service {domain}.{service}", job_type=job_type)
|
||||||
self.schema = schema
|
self.schema = schema
|
||||||
self.supports_response = supports_response
|
self.supports_response = supports_response
|
||||||
|
self.description_placeholders = description_placeholders
|
||||||
|
|
||||||
|
|
||||||
class ServiceCall:
|
class ServiceCall:
|
||||||
@@ -2590,6 +2599,8 @@ class ServiceRegistry:
|
|||||||
schema: VolSchemaType | None = None,
|
schema: VolSchemaType | None = None,
|
||||||
supports_response: SupportsResponse = SupportsResponse.NONE,
|
supports_response: SupportsResponse = SupportsResponse.NONE,
|
||||||
job_type: HassJobType | None = None,
|
job_type: HassJobType | None = None,
|
||||||
|
*,
|
||||||
|
description_placeholders: Mapping[str, str] | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Register a service.
|
"""Register a service.
|
||||||
|
|
||||||
@@ -2599,7 +2610,13 @@ class ServiceRegistry:
|
|||||||
"""
|
"""
|
||||||
self._hass.verify_event_loop_thread("hass.services.async_register")
|
self._hass.verify_event_loop_thread("hass.services.async_register")
|
||||||
self._async_register(
|
self._async_register(
|
||||||
domain, service, service_func, schema, supports_response, job_type
|
domain,
|
||||||
|
service,
|
||||||
|
service_func,
|
||||||
|
schema,
|
||||||
|
supports_response,
|
||||||
|
job_type,
|
||||||
|
description_placeholders,
|
||||||
)
|
)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
@@ -2617,6 +2634,7 @@ class ServiceRegistry:
|
|||||||
schema: VolSchemaType | None = None,
|
schema: VolSchemaType | None = None,
|
||||||
supports_response: SupportsResponse = SupportsResponse.NONE,
|
supports_response: SupportsResponse = SupportsResponse.NONE,
|
||||||
job_type: HassJobType | None = None,
|
job_type: HassJobType | None = None,
|
||||||
|
description_placeholders: Mapping[str, str] | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Register a service.
|
"""Register a service.
|
||||||
|
|
||||||
@@ -2633,6 +2651,7 @@ class ServiceRegistry:
|
|||||||
service,
|
service,
|
||||||
supports_response=supports_response,
|
supports_response=supports_response,
|
||||||
job_type=job_type,
|
job_type=job_type,
|
||||||
|
description_placeholders=description_placeholders,
|
||||||
)
|
)
|
||||||
|
|
||||||
if domain in self._services:
|
if domain in self._services:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from collections.abc import Callable, Iterable
|
from collections.abc import Callable, Iterable, Mapping
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
import logging
|
import logging
|
||||||
from types import ModuleType
|
from types import ModuleType
|
||||||
@@ -251,6 +251,8 @@ class EntityComponent[_EntityT: entity.Entity = entity.Entity]:
|
|||||||
func: str | Callable[..., Any],
|
func: str | Callable[..., Any],
|
||||||
required_features: list[int] | None = None,
|
required_features: list[int] | None = None,
|
||||||
supports_response: SupportsResponse = SupportsResponse.NONE,
|
supports_response: SupportsResponse = SupportsResponse.NONE,
|
||||||
|
*,
|
||||||
|
description_placeholders: Mapping[str, str] | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Register an entity service."""
|
"""Register an entity service."""
|
||||||
service.async_register_entity_service(
|
service.async_register_entity_service(
|
||||||
@@ -263,6 +265,7 @@ class EntityComponent[_EntityT: entity.Entity = entity.Entity]:
|
|||||||
required_features=required_features,
|
required_features=required_features,
|
||||||
schema=schema,
|
schema=schema,
|
||||||
supports_response=supports_response,
|
supports_response=supports_response,
|
||||||
|
description_placeholders=description_placeholders,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_setup_platform(
|
async def async_setup_platform(
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from collections.abc import Awaitable, Callable, Coroutine, Iterable
|
from collections.abc import Awaitable, Callable, Coroutine, Iterable, Mapping
|
||||||
from contextvars import ContextVar
|
from contextvars import ContextVar
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from logging import Logger, getLogger
|
from logging import Logger, getLogger
|
||||||
@@ -1081,6 +1081,7 @@ class EntityPlatform:
|
|||||||
supports_response: SupportsResponse = SupportsResponse.NONE,
|
supports_response: SupportsResponse = SupportsResponse.NONE,
|
||||||
*,
|
*,
|
||||||
entity_device_classes: Iterable[str | None] | None = None,
|
entity_device_classes: Iterable[str | None] | None = None,
|
||||||
|
description_placeholders: Mapping[str, str] | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Register an entity service.
|
"""Register an entity service.
|
||||||
|
|
||||||
@@ -1100,6 +1101,7 @@ class EntityPlatform:
|
|||||||
required_features=required_features,
|
required_features=required_features,
|
||||||
schema=schema,
|
schema=schema,
|
||||||
supports_response=supports_response,
|
supports_response=supports_response,
|
||||||
|
description_placeholders=description_placeholders,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def _async_update_entity_states(self) -> None:
|
async def _async_update_entity_states(self) -> None:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from collections.abc import Callable, Coroutine, Iterable
|
from collections.abc import Callable, Coroutine, Iterable, Mapping
|
||||||
import dataclasses
|
import dataclasses
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from functools import cache, partial
|
from functools import cache, partial
|
||||||
@@ -612,6 +612,8 @@ async def async_get_all_descriptions(
|
|||||||
# Don't warn for missing services, because it triggers false
|
# Don't warn for missing services, because it triggers false
|
||||||
# positives for things like scripts, that register as a service
|
# positives for things like scripts, that register as a service
|
||||||
description = {"fields": yaml_description.get("fields", {})}
|
description = {"fields": yaml_description.get("fields", {})}
|
||||||
|
if description_placeholders := service.description_placeholders:
|
||||||
|
description["description_placeholders"] = description_placeholders
|
||||||
|
|
||||||
for item in ("description", "name", "target"):
|
for item in ("description", "name", "target"):
|
||||||
if item in yaml_description:
|
if item in yaml_description:
|
||||||
@@ -955,6 +957,8 @@ def async_register_admin_service(
|
|||||||
],
|
],
|
||||||
schema: VolSchemaType = vol.Schema({}, extra=vol.PREVENT_EXTRA),
|
schema: VolSchemaType = vol.Schema({}, extra=vol.PREVENT_EXTRA),
|
||||||
supports_response: SupportsResponse = SupportsResponse.NONE,
|
supports_response: SupportsResponse = SupportsResponse.NONE,
|
||||||
|
*,
|
||||||
|
description_placeholders: Mapping[str, str] | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Register a service that requires admin access."""
|
"""Register a service that requires admin access."""
|
||||||
hass.services.async_register(
|
hass.services.async_register(
|
||||||
@@ -967,6 +971,7 @@ def async_register_admin_service(
|
|||||||
),
|
),
|
||||||
schema,
|
schema,
|
||||||
supports_response,
|
supports_response,
|
||||||
|
description_placeholders=description_placeholders,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -1112,6 +1117,7 @@ def async_register_entity_service(
|
|||||||
domain: str,
|
domain: str,
|
||||||
name: str,
|
name: str,
|
||||||
*,
|
*,
|
||||||
|
description_placeholders: Mapping[str, str] | None = None,
|
||||||
entity_device_classes: Iterable[str | None] | None = None,
|
entity_device_classes: Iterable[str | None] | None = None,
|
||||||
entities: dict[str, Entity],
|
entities: dict[str, Entity],
|
||||||
func: str | Callable[..., Any],
|
func: str | Callable[..., Any],
|
||||||
@@ -1145,6 +1151,7 @@ def async_register_entity_service(
|
|||||||
schema,
|
schema,
|
||||||
supports_response,
|
supports_response,
|
||||||
job_type=job_type,
|
job_type=job_type,
|
||||||
|
description_placeholders=description_placeholders,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -1154,6 +1161,7 @@ def async_register_platform_entity_service(
|
|||||||
service_domain: str,
|
service_domain: str,
|
||||||
service_name: str,
|
service_name: str,
|
||||||
*,
|
*,
|
||||||
|
description_placeholders: Mapping[str, str] | None = None,
|
||||||
entity_device_classes: Iterable[str | None] | None = None,
|
entity_device_classes: Iterable[str | None] | None = None,
|
||||||
entity_domain: str,
|
entity_domain: str,
|
||||||
func: str | Callable[..., Any],
|
func: str | Callable[..., Any],
|
||||||
@@ -1191,4 +1199,5 @@ def async_register_platform_entity_service(
|
|||||||
schema,
|
schema,
|
||||||
supports_response,
|
supports_response,
|
||||||
job_type=HassJobType.Coroutinefunction,
|
job_type=HassJobType.Coroutinefunction,
|
||||||
|
description_placeholders=description_placeholders,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ from homeassistant.exceptions import HomeAssistantError, PlatformNotReady
|
|||||||
from homeassistant.helpers import config_validation as cv, discovery
|
from homeassistant.helpers import config_validation as cv, discovery
|
||||||
from homeassistant.helpers.entity_component import EntityComponent, async_update_entity
|
from homeassistant.helpers.entity_component import EntityComponent, async_update_entity
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
from homeassistant.helpers.service import async_get_all_descriptions
|
||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
from homeassistant.util import dt as dt_util
|
from homeassistant.util import dt as dt_util
|
||||||
@@ -511,7 +512,7 @@ async def test_register_entity_service(
|
|||||||
schema: dict | None,
|
schema: dict | None,
|
||||||
service_data: dict,
|
service_data: dict,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test registering an enttiy service and calling it."""
|
"""Test registering an entity service and calling it."""
|
||||||
entity = MockEntity(entity_id=f"{DOMAIN}.entity")
|
entity = MockEntity(entity_id=f"{DOMAIN}.entity")
|
||||||
calls = []
|
calls = []
|
||||||
|
|
||||||
@@ -525,7 +526,16 @@ async def test_register_entity_service(
|
|||||||
await component.async_setup({})
|
await component.async_setup({})
|
||||||
await component.async_add_entities([entity])
|
await component.async_add_entities([entity])
|
||||||
|
|
||||||
component.async_register_entity_service("hello", schema, "async_called_by_service")
|
component.async_register_entity_service(
|
||||||
|
"hello",
|
||||||
|
schema,
|
||||||
|
"async_called_by_service",
|
||||||
|
description_placeholders={"test_placeholder": "beer"},
|
||||||
|
)
|
||||||
|
descriptions = await async_get_all_descriptions(hass)
|
||||||
|
assert descriptions["test_domain"]["hello"]["description_placeholders"] == {
|
||||||
|
"test_placeholder": "beer"
|
||||||
|
}
|
||||||
|
|
||||||
with pytest.raises(vol.Invalid):
|
with pytest.raises(vol.Invalid):
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ from homeassistant.helpers.entity_platform import (
|
|||||||
AddConfigEntryEntitiesCallback,
|
AddConfigEntryEntitiesCallback,
|
||||||
AddEntitiesCallback,
|
AddEntitiesCallback,
|
||||||
)
|
)
|
||||||
|
from homeassistant.helpers.service import async_get_all_descriptions
|
||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
from homeassistant.util import dt as dt_util
|
from homeassistant.util import dt as dt_util
|
||||||
|
|
||||||
@@ -1639,10 +1640,20 @@ async def test_platforms_sharing_services(hass: HomeAssistant) -> None:
|
|||||||
def handle_service(entity, data):
|
def handle_service(entity, data):
|
||||||
entities.append(entity)
|
entities.append(entity)
|
||||||
|
|
||||||
entity_platform1.async_register_entity_service("hello", {}, handle_service)
|
entity_platform1.async_register_entity_service(
|
||||||
entity_platform2.async_register_entity_service(
|
"hello", {}, handle_service, description_placeholders={"drink": "beer"}
|
||||||
"hello", {}, Mock(side_effect=AssertionError("Should not be called"))
|
|
||||||
)
|
)
|
||||||
|
entity_platform2.async_register_entity_service(
|
||||||
|
"hello",
|
||||||
|
{},
|
||||||
|
Mock(side_effect=AssertionError("Should not be called")),
|
||||||
|
description_placeholders={"drink": "milk"},
|
||||||
|
)
|
||||||
|
|
||||||
|
descriptions = await async_get_all_descriptions(hass)
|
||||||
|
assert descriptions["mock_platform"]["hello"]["description_placeholders"] == {
|
||||||
|
"drink": "beer"
|
||||||
|
}
|
||||||
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
"mock_platform", "hello", {"entity_id": "all"}, blocking=True
|
"mock_platform", "hello", {"entity_id": "all"}, blocking=True
|
||||||
|
|||||||
@@ -1393,6 +1393,94 @@ async def test_async_get_all_descriptions_new_service_added_while_loading(
|
|||||||
assert descriptions[logger_domain]["new_service"]["description"] == "new service"
|
assert descriptions[logger_domain]["new_service"]["description"] == "new service"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_async_get_descriptions_with_placeholders(hass: HomeAssistant) -> None:
|
||||||
|
"""Test descriptions async_get_all_descriptions with placeholders.
|
||||||
|
|
||||||
|
Placeholders supplied with a service registration should be included.
|
||||||
|
"""
|
||||||
|
service_descriptions = """
|
||||||
|
happy_time:
|
||||||
|
fields:
|
||||||
|
topic:
|
||||||
|
selector:
|
||||||
|
text:
|
||||||
|
duration:
|
||||||
|
default: 5
|
||||||
|
selector:
|
||||||
|
number:
|
||||||
|
min: 1
|
||||||
|
max: 300
|
||||||
|
unit_of_measurement: "seconds"
|
||||||
|
"""
|
||||||
|
|
||||||
|
service_schema = vol.Schema(
|
||||||
|
{
|
||||||
|
"topic": cv.string,
|
||||||
|
"duration": cv.positive_int,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
domain = "test_domain"
|
||||||
|
|
||||||
|
hass.services.async_register(
|
||||||
|
domain,
|
||||||
|
"happy_time",
|
||||||
|
lambda call: None,
|
||||||
|
schema=service_schema,
|
||||||
|
description_placeholders={"placeholder": "beer"},
|
||||||
|
)
|
||||||
|
mock_integration(hass, MockModule(domain), top_level_files={"services.yaml"})
|
||||||
|
assert await async_setup_component(hass, domain, {})
|
||||||
|
|
||||||
|
def load_yaml(fname, secrets=None):
|
||||||
|
with io.StringIO(service_descriptions) as file:
|
||||||
|
return parse_yaml(file)
|
||||||
|
|
||||||
|
with (
|
||||||
|
patch(
|
||||||
|
"homeassistant.helpers.service._load_services_files",
|
||||||
|
side_effect=service._load_services_files,
|
||||||
|
) as proxy_load_services_files,
|
||||||
|
patch(
|
||||||
|
"annotatedyaml.loader.load_yaml",
|
||||||
|
side_effect=load_yaml,
|
||||||
|
) as mock_load_yaml,
|
||||||
|
):
|
||||||
|
descriptions = await service.async_get_all_descriptions(hass)
|
||||||
|
|
||||||
|
mock_load_yaml.assert_called_once_with("services.yaml", None)
|
||||||
|
assert proxy_load_services_files.mock_calls[0][1][0] == unordered(
|
||||||
|
[
|
||||||
|
await async_get_integration(hass, domain),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
assert descriptions == {
|
||||||
|
"test_domain": {
|
||||||
|
"happy_time": {
|
||||||
|
"fields": {
|
||||||
|
"topic": {
|
||||||
|
"selector": {"text": {"multiple": False, "multiline": False}}
|
||||||
|
},
|
||||||
|
"duration": {
|
||||||
|
"default": 5,
|
||||||
|
"selector": {
|
||||||
|
"number": {
|
||||||
|
"min": 1.0,
|
||||||
|
"max": 300.0,
|
||||||
|
"unit_of_measurement": "seconds",
|
||||||
|
"step": 1.0,
|
||||||
|
"mode": "slider",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"description_placeholders": {"placeholder": "beer"},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async def test_register_with_mixed_case(hass: HomeAssistant) -> None:
|
async def test_register_with_mixed_case(hass: HomeAssistant) -> None:
|
||||||
"""Test registering a service with mixed case.
|
"""Test registering a service with mixed case.
|
||||||
|
|
||||||
@@ -1838,6 +1926,37 @@ async def test_register_admin_service(
|
|||||||
assert calls[0].context.user_id == hass_admin_user.id
|
assert calls[0].context.user_id == hass_admin_user.id
|
||||||
|
|
||||||
|
|
||||||
|
async def test_register_admin_service_with_placeholders(
|
||||||
|
hass: HomeAssistant, hass_admin_user: MockUser
|
||||||
|
) -> None:
|
||||||
|
"""Test the register admin service with description placeholders."""
|
||||||
|
calls = []
|
||||||
|
|
||||||
|
async def mock_service(call):
|
||||||
|
calls.append(call)
|
||||||
|
|
||||||
|
service.async_register_admin_service(
|
||||||
|
hass,
|
||||||
|
"test",
|
||||||
|
"test",
|
||||||
|
mock_service,
|
||||||
|
description_placeholders={"test_placeholder": "beer"},
|
||||||
|
)
|
||||||
|
await hass.services.async_call(
|
||||||
|
"test",
|
||||||
|
"test",
|
||||||
|
{},
|
||||||
|
blocking=True,
|
||||||
|
context=Context(user_id=hass_admin_user.id),
|
||||||
|
)
|
||||||
|
assert len(calls) == 1
|
||||||
|
|
||||||
|
descriptions = await service.async_get_all_descriptions(hass)
|
||||||
|
assert descriptions["test"]["test"]["description_placeholders"] == {
|
||||||
|
"test_placeholder": "beer"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"supports_response",
|
"supports_response",
|
||||||
[SupportsResponse.ONLY, SupportsResponse.OPTIONAL],
|
[SupportsResponse.ONLY, SupportsResponse.OPTIONAL],
|
||||||
@@ -2647,6 +2766,13 @@ async def test_register_platform_entity_service(
|
|||||||
entity_domain="mock_integration",
|
entity_domain="mock_integration",
|
||||||
schema={},
|
schema={},
|
||||||
func=handle_service,
|
func=handle_service,
|
||||||
|
description_placeholders={"test_placeholder": "beer"},
|
||||||
|
)
|
||||||
|
descriptions = await service.async_get_all_descriptions(hass)
|
||||||
|
assert (
|
||||||
|
descriptions["mock_platform"]["hello"]["description_placeholders"]
|
||||||
|
== {"test_placeholder": "beer"}
|
||||||
|
== {"test_placeholder": "beer"}
|
||||||
)
|
)
|
||||||
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
|
|||||||
Reference in New Issue
Block a user