Add service response data for listing calendar events (#94759)
* Add service response data for listing calendar events Add the capability of response data for for the entity component. * Rename input arguments and add service description * Improve list events to be more user friendly Allow the end date to be determined based on a relative time duration. Make the start time optional and set to "now". Add additional test coverage. Update demo calendar to actually perform date range checks. * Wrap docstrings properly. * Increase test coverage * Update to use new API calls * Readability improvements * Wrap docstrings * Require at least one of end or duration * Check for multiple entity matches earlier in the request * Update documentation strings
This commit is contained in:
parent
65454c945d
commit
b9b5fe6be8
9 changed files with 331 additions and 31 deletions
|
@ -2,7 +2,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from collections.abc import Awaitable, Callable, Iterable
|
||||
from collections.abc import Awaitable, Callable, Coroutine, Iterable
|
||||
import dataclasses
|
||||
from enum import Enum
|
||||
from functools import cache, partial, wraps
|
||||
|
@ -26,7 +26,13 @@ from homeassistant.const import (
|
|||
ENTITY_MATCH_ALL,
|
||||
ENTITY_MATCH_NONE,
|
||||
)
|
||||
from homeassistant.core import Context, HomeAssistant, ServiceCall, callback
|
||||
from homeassistant.core import (
|
||||
Context,
|
||||
HomeAssistant,
|
||||
ServiceCall,
|
||||
ServiceResponse,
|
||||
callback,
|
||||
)
|
||||
from homeassistant.exceptions import (
|
||||
HomeAssistantError,
|
||||
TemplateError,
|
||||
|
@ -672,10 +678,10 @@ def async_set_service_schema(
|
|||
async def entity_service_call( # noqa: C901
|
||||
hass: HomeAssistant,
|
||||
platforms: Iterable[EntityPlatform],
|
||||
func: str | Callable[..., Any],
|
||||
func: str | Callable[..., Coroutine[Any, Any, ServiceResponse]],
|
||||
call: ServiceCall,
|
||||
required_features: Iterable[int] | None = None,
|
||||
) -> None:
|
||||
) -> ServiceResponse | None:
|
||||
"""Handle an entity service call.
|
||||
|
||||
Calls all platforms simultaneously.
|
||||
|
@ -791,7 +797,16 @@ async def entity_service_call( # noqa: C901
|
|||
entities.append(entity)
|
||||
|
||||
if not entities:
|
||||
return
|
||||
if call.return_response:
|
||||
raise HomeAssistantError(
|
||||
"Service call requested response data but did not match any entities"
|
||||
)
|
||||
return None
|
||||
|
||||
if call.return_response and len(entities) != 1:
|
||||
raise HomeAssistantError(
|
||||
"Service call requested response data but matched more than one entity"
|
||||
)
|
||||
|
||||
done, pending = await asyncio.wait(
|
||||
[
|
||||
|
@ -804,8 +819,10 @@ async def entity_service_call( # noqa: C901
|
|||
]
|
||||
)
|
||||
assert not pending
|
||||
for future in done:
|
||||
future.result() # pop exception if have
|
||||
|
||||
response_data: ServiceResponse | None
|
||||
for task in done:
|
||||
response_data = task.result() # pop exception if have
|
||||
|
||||
tasks: list[asyncio.Task[None]] = []
|
||||
|
||||
|
@ -824,28 +841,32 @@ async def entity_service_call( # noqa: C901
|
|||
for future in done:
|
||||
future.result() # pop exception if have
|
||||
|
||||
return response_data if call.return_response else None
|
||||
|
||||
|
||||
async def _handle_entity_call(
|
||||
hass: HomeAssistant,
|
||||
entity: Entity,
|
||||
func: str | Callable[..., Any],
|
||||
func: str | Callable[..., Coroutine[Any, Any, ServiceResponse]],
|
||||
data: dict | ServiceCall,
|
||||
context: Context,
|
||||
) -> None:
|
||||
) -> ServiceResponse:
|
||||
"""Handle calling service method."""
|
||||
entity.async_set_context(context)
|
||||
|
||||
task: asyncio.Future[ServiceResponse] | None
|
||||
if isinstance(func, str):
|
||||
result = hass.async_run_job(
|
||||
task = hass.async_run_job(
|
||||
partial(getattr(entity, func), **data) # type: ignore[arg-type]
|
||||
)
|
||||
else:
|
||||
result = hass.async_run_job(func, entity, data)
|
||||
task = hass.async_run_job(func, entity, data)
|
||||
|
||||
# Guard because callback functions do not return a task when passed to
|
||||
# async_run_job.
|
||||
if result is not None:
|
||||
await result
|
||||
result: ServiceResponse | None = None
|
||||
if task is not None:
|
||||
result = await task
|
||||
|
||||
if asyncio.iscoroutine(result):
|
||||
_LOGGER.error(
|
||||
|
@ -856,7 +877,9 @@ async def _handle_entity_call(
|
|||
func,
|
||||
entity.entity_id,
|
||||
)
|
||||
await result
|
||||
result = await result
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@bind_hass
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue