mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 20:27:08 +00:00
Allow delayed commands to not have a device id (#118390)
This commit is contained in:
parent
181ae1227a
commit
3ffbbcfa5c
@ -45,8 +45,11 @@ class TimerInfo:
|
|||||||
seconds: int
|
seconds: int
|
||||||
"""Total number of seconds the timer should run for."""
|
"""Total number of seconds the timer should run for."""
|
||||||
|
|
||||||
device_id: str
|
device_id: str | None
|
||||||
"""Id of the device where the timer was set."""
|
"""Id of the device where the timer was set.
|
||||||
|
|
||||||
|
May be None only if conversation_command is set.
|
||||||
|
"""
|
||||||
|
|
||||||
start_hours: int | None
|
start_hours: int | None
|
||||||
"""Number of hours the timer should run as given by the user."""
|
"""Number of hours the timer should run as given by the user."""
|
||||||
@ -213,7 +216,7 @@ class TimerManager:
|
|||||||
|
|
||||||
def start_timer(
|
def start_timer(
|
||||||
self,
|
self,
|
||||||
device_id: str,
|
device_id: str | None,
|
||||||
hours: int | None,
|
hours: int | None,
|
||||||
minutes: int | None,
|
minutes: int | None,
|
||||||
seconds: int | None,
|
seconds: int | None,
|
||||||
@ -223,7 +226,10 @@ class TimerManager:
|
|||||||
conversation_agent_id: str | None = None,
|
conversation_agent_id: str | None = None,
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Start a timer."""
|
"""Start a timer."""
|
||||||
if not self.is_timer_device(device_id):
|
if (not conversation_command) and (device_id is None):
|
||||||
|
raise ValueError("Conversation command must be set if no device id")
|
||||||
|
|
||||||
|
if (device_id is not None) and (not self.is_timer_device(device_id)):
|
||||||
raise TimersNotSupportedError(device_id)
|
raise TimersNotSupportedError(device_id)
|
||||||
|
|
||||||
total_seconds = 0
|
total_seconds = 0
|
||||||
@ -270,6 +276,7 @@ class TimerManager:
|
|||||||
name=f"Timer {timer_id}",
|
name=f"Timer {timer_id}",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if timer.device_id is not None:
|
||||||
self.handlers[timer.device_id](TimerEventType.STARTED, timer)
|
self.handlers[timer.device_id](TimerEventType.STARTED, timer)
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"Timer started: id=%s, name=%s, hours=%s, minutes=%s, seconds=%s, device_id=%s",
|
"Timer started: id=%s, name=%s, hours=%s, minutes=%s, seconds=%s, device_id=%s",
|
||||||
@ -487,7 +494,11 @@ def _find_timer(
|
|||||||
) -> TimerInfo:
|
) -> TimerInfo:
|
||||||
"""Match a single timer with constraints or raise an error."""
|
"""Match a single timer with constraints or raise an error."""
|
||||||
timer_manager: TimerManager = hass.data[TIMER_DATA]
|
timer_manager: TimerManager = hass.data[TIMER_DATA]
|
||||||
matching_timers: list[TimerInfo] = list(timer_manager.timers.values())
|
|
||||||
|
# Ignore delayed command timers
|
||||||
|
matching_timers: list[TimerInfo] = [
|
||||||
|
t for t in timer_manager.timers.values() if not t.conversation_command
|
||||||
|
]
|
||||||
has_filter = False
|
has_filter = False
|
||||||
|
|
||||||
if find_filter:
|
if find_filter:
|
||||||
@ -617,7 +628,11 @@ def _find_timers(
|
|||||||
) -> list[TimerInfo]:
|
) -> list[TimerInfo]:
|
||||||
"""Match multiple timers with constraints or raise an error."""
|
"""Match multiple timers with constraints or raise an error."""
|
||||||
timer_manager: TimerManager = hass.data[TIMER_DATA]
|
timer_manager: TimerManager = hass.data[TIMER_DATA]
|
||||||
matching_timers: list[TimerInfo] = list(timer_manager.timers.values())
|
|
||||||
|
# Ignore delayed command timers
|
||||||
|
matching_timers: list[TimerInfo] = [
|
||||||
|
t for t in timer_manager.timers.values() if not t.conversation_command
|
||||||
|
]
|
||||||
|
|
||||||
# Filter by name first
|
# Filter by name first
|
||||||
name: str | None = None
|
name: str | None = None
|
||||||
@ -784,10 +799,17 @@ class StartTimerIntentHandler(intent.IntentHandler):
|
|||||||
timer_manager: TimerManager = hass.data[TIMER_DATA]
|
timer_manager: TimerManager = hass.data[TIMER_DATA]
|
||||||
slots = self.async_validate_slots(intent_obj.slots)
|
slots = self.async_validate_slots(intent_obj.slots)
|
||||||
|
|
||||||
if not (
|
conversation_command: str | None = None
|
||||||
intent_obj.device_id and timer_manager.is_timer_device(intent_obj.device_id)
|
if "conversation_command" in slots:
|
||||||
|
conversation_command = slots["conversation_command"]["value"].strip()
|
||||||
|
|
||||||
|
if (not conversation_command) and (
|
||||||
|
not (
|
||||||
|
intent_obj.device_id
|
||||||
|
and timer_manager.is_timer_device(intent_obj.device_id)
|
||||||
|
)
|
||||||
):
|
):
|
||||||
# Fail early
|
# Fail early if this is not a delayed command
|
||||||
raise TimersNotSupportedError(intent_obj.device_id)
|
raise TimersNotSupportedError(intent_obj.device_id)
|
||||||
|
|
||||||
name: str | None = None
|
name: str | None = None
|
||||||
@ -806,10 +828,6 @@ class StartTimerIntentHandler(intent.IntentHandler):
|
|||||||
if "seconds" in slots:
|
if "seconds" in slots:
|
||||||
seconds = int(slots["seconds"]["value"])
|
seconds = int(slots["seconds"]["value"])
|
||||||
|
|
||||||
conversation_command: str | None = None
|
|
||||||
if "conversation_command" in slots:
|
|
||||||
conversation_command = slots["conversation_command"]["value"]
|
|
||||||
|
|
||||||
timer_manager.start_timer(
|
timer_manager.start_timer(
|
||||||
intent_obj.device_id,
|
intent_obj.device_id,
|
||||||
hours,
|
hours,
|
||||||
|
@ -13,6 +13,7 @@ from homeassistant.components.intent.timers import (
|
|||||||
TimerNotFoundError,
|
TimerNotFoundError,
|
||||||
TimersNotSupportedError,
|
TimersNotSupportedError,
|
||||||
_round_time,
|
_round_time,
|
||||||
|
async_device_supports_timers,
|
||||||
async_register_timer_handler,
|
async_register_timer_handler,
|
||||||
)
|
)
|
||||||
from homeassistant.const import ATTR_DEVICE_ID, ATTR_NAME
|
from homeassistant.const import ATTR_DEVICE_ID, ATTR_NAME
|
||||||
@ -1440,6 +1441,17 @@ async def test_start_timer_with_conversation_command(
|
|||||||
|
|
||||||
async_register_timer_handler(hass, device_id, handle_timer)
|
async_register_timer_handler(hass, device_id, handle_timer)
|
||||||
|
|
||||||
|
# Device id is required if no conversation command
|
||||||
|
timer_manager = TimerManager(hass)
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
timer_manager.start_timer(
|
||||||
|
device_id=None,
|
||||||
|
hours=None,
|
||||||
|
minutes=5,
|
||||||
|
seconds=None,
|
||||||
|
language=hass.config.language,
|
||||||
|
)
|
||||||
|
|
||||||
with patch("homeassistant.components.conversation.async_converse") as mock_converse:
|
with patch("homeassistant.components.conversation.async_converse") as mock_converse:
|
||||||
result = await intent.async_handle(
|
result = await intent.async_handle(
|
||||||
hass,
|
hass,
|
||||||
@ -1566,3 +1578,24 @@ async def test_pause_unpause_timer_disambiguate(
|
|||||||
await updated_event.wait()
|
await updated_event.wait()
|
||||||
assert len(unpaused_timer_ids) == 2
|
assert len(unpaused_timer_ids) == 2
|
||||||
assert unpaused_timer_ids[1] == started_timer_ids[0]
|
assert unpaused_timer_ids[1] == started_timer_ids[0]
|
||||||
|
|
||||||
|
|
||||||
|
async def test_async_device_supports_timers(hass: HomeAssistant) -> None:
|
||||||
|
"""Test async_device_supports_timers function."""
|
||||||
|
device_id = "test_device"
|
||||||
|
|
||||||
|
# Before intent initialization
|
||||||
|
assert not async_device_supports_timers(hass, device_id)
|
||||||
|
|
||||||
|
# After intent initialization
|
||||||
|
assert await async_setup_component(hass, "intent", {})
|
||||||
|
assert not async_device_supports_timers(hass, device_id)
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def handle_timer(event_type: TimerEventType, timer: TimerInfo) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
async_register_timer_handler(hass, device_id, handle_timer)
|
||||||
|
|
||||||
|
# After handler registration
|
||||||
|
assert async_device_supports_timers(hass, device_id)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user