mirror of
https://github.com/home-assistant/core.git
synced 2025-12-24 12:59:34 +00:00
Add new intents for cover, valve, vacuum, and media player (#110757)
* Add valve to HassTurnOn/Off * Add set position for valves * Add set position to covers * Add HassTurnOn/Off for vacuums * Add media player intents * Split out vacuum intents * Address comments * Extra test
This commit is contained in:
@@ -7,6 +7,7 @@ from collections.abc import Collection, Coroutine, Iterable
|
||||
import dataclasses
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
from functools import cached_property
|
||||
import logging
|
||||
from typing import Any, TypeVar
|
||||
|
||||
@@ -33,6 +34,7 @@ INTENT_TURN_ON = "HassTurnOn"
|
||||
INTENT_TOGGLE = "HassToggle"
|
||||
INTENT_GET_STATE = "HassGetState"
|
||||
INTENT_NEVERMIND = "HassNevermind"
|
||||
INTENT_SET_POSITION = "HassSetPosition"
|
||||
|
||||
SLOT_SCHEMA = vol.Schema({}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
@@ -347,7 +349,6 @@ class IntentHandler:
|
||||
|
||||
intent_type: str | None = None
|
||||
slot_schema: vol.Schema | None = None
|
||||
_slot_schema: vol.Schema | None = None
|
||||
platforms: Iterable[str] | None = []
|
||||
|
||||
@callback
|
||||
@@ -361,17 +362,20 @@ class IntentHandler:
|
||||
if self.slot_schema is None:
|
||||
return slots
|
||||
|
||||
if self._slot_schema is None:
|
||||
self._slot_schema = vol.Schema(
|
||||
{
|
||||
key: SLOT_SCHEMA.extend({"value": validator})
|
||||
for key, validator in self.slot_schema.items()
|
||||
},
|
||||
extra=vol.ALLOW_EXTRA,
|
||||
)
|
||||
|
||||
return self._slot_schema(slots) # type: ignore[no-any-return]
|
||||
|
||||
@cached_property
|
||||
def _slot_schema(self) -> vol.Schema:
|
||||
"""Create validation schema for slots."""
|
||||
assert self.slot_schema is not None
|
||||
return vol.Schema(
|
||||
{
|
||||
key: SLOT_SCHEMA.extend({"value": validator})
|
||||
for key, validator in self.slot_schema.items()
|
||||
},
|
||||
extra=vol.ALLOW_EXTRA,
|
||||
)
|
||||
|
||||
async def async_handle(self, intent_obj: Intent) -> IntentResponse:
|
||||
"""Handle the intent."""
|
||||
raise NotImplementedError()
|
||||
@@ -398,13 +402,44 @@ class ServiceIntentHandler(IntentHandler):
|
||||
service_timeout: float = 0.2
|
||||
|
||||
def __init__(
|
||||
self, intent_type: str, domain: str, service: str, speech: str | None = None
|
||||
self,
|
||||
intent_type: str,
|
||||
domain: str,
|
||||
service: str,
|
||||
speech: str | None = None,
|
||||
extra_slots: dict[str, vol.Schema] | None = None,
|
||||
) -> None:
|
||||
"""Create Service Intent Handler."""
|
||||
self.intent_type = intent_type
|
||||
self.domain = domain
|
||||
self.service = service
|
||||
self.speech = speech
|
||||
self.extra_slots = extra_slots
|
||||
|
||||
@cached_property
|
||||
def _slot_schema(self) -> vol.Schema:
|
||||
"""Create validation schema for slots (with extra required slots)."""
|
||||
if self.slot_schema is None:
|
||||
raise ValueError("Slot schema is not defined")
|
||||
|
||||
if self.extra_slots:
|
||||
slot_schema = {
|
||||
**self.slot_schema,
|
||||
**{
|
||||
vol.Required(key): schema
|
||||
for key, schema in self.extra_slots.items()
|
||||
},
|
||||
}
|
||||
else:
|
||||
slot_schema = self.slot_schema
|
||||
|
||||
return vol.Schema(
|
||||
{
|
||||
key: SLOT_SCHEMA.extend({"value": validator})
|
||||
for key, validator in slot_schema.items()
|
||||
},
|
||||
extra=vol.ALLOW_EXTRA,
|
||||
)
|
||||
|
||||
async def async_handle(self, intent_obj: Intent) -> IntentResponse:
|
||||
"""Handle the hass intent."""
|
||||
@@ -467,6 +502,9 @@ class ServiceIntentHandler(IntentHandler):
|
||||
area=area_name or area_id,
|
||||
)
|
||||
|
||||
# Update intent slots to include any transformations done by the schemas
|
||||
intent_obj.slots = slots
|
||||
|
||||
response = await self.async_handle_states(intent_obj, states, area)
|
||||
|
||||
# Make the matched states available in the response
|
||||
@@ -539,12 +577,19 @@ class ServiceIntentHandler(IntentHandler):
|
||||
async def async_call_service(self, intent_obj: Intent, state: State) -> None:
|
||||
"""Call service on entity."""
|
||||
hass = intent_obj.hass
|
||||
|
||||
service_data: dict[str, Any] = {ATTR_ENTITY_ID: state.entity_id}
|
||||
if self.extra_slots:
|
||||
service_data.update(
|
||||
{key: intent_obj.slots[key]["value"] for key in self.extra_slots}
|
||||
)
|
||||
|
||||
await self._run_then_background(
|
||||
hass.async_create_task(
|
||||
hass.services.async_call(
|
||||
self.domain,
|
||||
self.service,
|
||||
{ATTR_ENTITY_ID: state.entity_id},
|
||||
service_data,
|
||||
context=intent_obj.context,
|
||||
blocking=True,
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user