mirror of
https://github.com/home-assistant/core.git
synced 2025-07-24 21:57:51 +00:00
Add intent to cancel all timers (#130873)
* Add intent to cancel all timers * Add intent to llm test
This commit is contained in:
parent
a2ebfe6e83
commit
1a71fbe427
@ -45,6 +45,7 @@ from homeassistant.util import dt as dt_util
|
|||||||
|
|
||||||
from .const import DOMAIN, TIMER_DATA
|
from .const import DOMAIN, TIMER_DATA
|
||||||
from .timers import (
|
from .timers import (
|
||||||
|
CancelAllTimersIntentHandler,
|
||||||
CancelTimerIntentHandler,
|
CancelTimerIntentHandler,
|
||||||
DecreaseTimerIntentHandler,
|
DecreaseTimerIntentHandler,
|
||||||
IncreaseTimerIntentHandler,
|
IncreaseTimerIntentHandler,
|
||||||
@ -130,6 +131,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||||||
intent.async_register(hass, SetPositionIntentHandler())
|
intent.async_register(hass, SetPositionIntentHandler())
|
||||||
intent.async_register(hass, StartTimerIntentHandler())
|
intent.async_register(hass, StartTimerIntentHandler())
|
||||||
intent.async_register(hass, CancelTimerIntentHandler())
|
intent.async_register(hass, CancelTimerIntentHandler())
|
||||||
|
intent.async_register(hass, CancelAllTimersIntentHandler())
|
||||||
intent.async_register(hass, IncreaseTimerIntentHandler())
|
intent.async_register(hass, IncreaseTimerIntentHandler())
|
||||||
intent.async_register(hass, DecreaseTimerIntentHandler())
|
intent.async_register(hass, DecreaseTimerIntentHandler())
|
||||||
intent.async_register(hass, PauseTimerIntentHandler())
|
intent.async_register(hass, PauseTimerIntentHandler())
|
||||||
|
@ -887,6 +887,32 @@ class CancelTimerIntentHandler(intent.IntentHandler):
|
|||||||
return intent_obj.create_response()
|
return intent_obj.create_response()
|
||||||
|
|
||||||
|
|
||||||
|
class CancelAllTimersIntentHandler(intent.IntentHandler):
|
||||||
|
"""Intent handler for cancelling all timers."""
|
||||||
|
|
||||||
|
intent_type = intent.INTENT_CANCEL_ALL_TIMERS
|
||||||
|
description = "Cancels all timers"
|
||||||
|
slot_schema = {
|
||||||
|
vol.Optional("area"): cv.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
async def async_handle(self, intent_obj: intent.Intent) -> intent.IntentResponse:
|
||||||
|
"""Handle the intent."""
|
||||||
|
hass = intent_obj.hass
|
||||||
|
timer_manager: TimerManager = hass.data[TIMER_DATA]
|
||||||
|
slots = self.async_validate_slots(intent_obj.slots)
|
||||||
|
canceled = 0
|
||||||
|
|
||||||
|
for timer in _find_timers(hass, intent_obj.device_id, slots):
|
||||||
|
timer_manager.cancel_timer(timer.id)
|
||||||
|
canceled += 1
|
||||||
|
|
||||||
|
response = intent_obj.create_response()
|
||||||
|
response.async_set_speech_slots({"canceled": canceled})
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
class IncreaseTimerIntentHandler(intent.IntentHandler):
|
class IncreaseTimerIntentHandler(intent.IntentHandler):
|
||||||
"""Intent handler for increasing the time of a timer."""
|
"""Intent handler for increasing the time of a timer."""
|
||||||
|
|
||||||
|
@ -49,6 +49,7 @@ INTENT_NEVERMIND = "HassNevermind"
|
|||||||
INTENT_SET_POSITION = "HassSetPosition"
|
INTENT_SET_POSITION = "HassSetPosition"
|
||||||
INTENT_START_TIMER = "HassStartTimer"
|
INTENT_START_TIMER = "HassStartTimer"
|
||||||
INTENT_CANCEL_TIMER = "HassCancelTimer"
|
INTENT_CANCEL_TIMER = "HassCancelTimer"
|
||||||
|
INTENT_CANCEL_ALL_TIMERS = "HassCancelAllTimers"
|
||||||
INTENT_INCREASE_TIMER = "HassIncreaseTimer"
|
INTENT_INCREASE_TIMER = "HassIncreaseTimer"
|
||||||
INTENT_DECREASE_TIMER = "HassDecreaseTimer"
|
INTENT_DECREASE_TIMER = "HassDecreaseTimer"
|
||||||
INTENT_PAUSE_TIMER = "HassPauseTimer"
|
INTENT_PAUSE_TIMER = "HassPauseTimer"
|
||||||
|
@ -1587,3 +1587,181 @@ async def test_async_device_supports_timers(hass: HomeAssistant) -> None:
|
|||||||
|
|
||||||
# After handler registration
|
# After handler registration
|
||||||
assert async_device_supports_timers(hass, device_id)
|
assert async_device_supports_timers(hass, device_id)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_cancel_all_timers(hass: HomeAssistant, init_components) -> None:
|
||||||
|
"""Test cancelling all timers."""
|
||||||
|
device_id = "test_device"
|
||||||
|
|
||||||
|
started_event = asyncio.Event()
|
||||||
|
num_started = 0
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def handle_timer(event_type: TimerEventType, timer: TimerInfo) -> None:
|
||||||
|
nonlocal num_started
|
||||||
|
|
||||||
|
if event_type == TimerEventType.STARTED:
|
||||||
|
num_started += 1
|
||||||
|
if num_started == 3:
|
||||||
|
started_event.set()
|
||||||
|
|
||||||
|
async_register_timer_handler(hass, device_id, handle_timer)
|
||||||
|
|
||||||
|
# Start timers
|
||||||
|
result = await intent.async_handle(
|
||||||
|
hass,
|
||||||
|
"test",
|
||||||
|
intent.INTENT_START_TIMER,
|
||||||
|
{"name": {"value": "pizza"}, "minutes": {"value": 10}},
|
||||||
|
device_id=device_id,
|
||||||
|
)
|
||||||
|
assert result.response_type == intent.IntentResponseType.ACTION_DONE
|
||||||
|
|
||||||
|
result = await intent.async_handle(
|
||||||
|
hass,
|
||||||
|
"test",
|
||||||
|
intent.INTENT_START_TIMER,
|
||||||
|
{"name": {"value": "tv"}, "minutes": {"value": 10}},
|
||||||
|
device_id=device_id,
|
||||||
|
)
|
||||||
|
assert result.response_type == intent.IntentResponseType.ACTION_DONE
|
||||||
|
|
||||||
|
result2 = await intent.async_handle(
|
||||||
|
hass,
|
||||||
|
"test",
|
||||||
|
intent.INTENT_START_TIMER,
|
||||||
|
{"name": {"value": "media"}, "minutes": {"value": 15}},
|
||||||
|
device_id=device_id,
|
||||||
|
)
|
||||||
|
assert result2.response_type == intent.IntentResponseType.ACTION_DONE
|
||||||
|
|
||||||
|
# Wait for all timers to start
|
||||||
|
async with asyncio.timeout(1):
|
||||||
|
await started_event.wait()
|
||||||
|
|
||||||
|
# Cancel all timers
|
||||||
|
result = await intent.async_handle(
|
||||||
|
hass, "test", intent.INTENT_CANCEL_ALL_TIMERS, {}, device_id=device_id
|
||||||
|
)
|
||||||
|
assert result.response_type == intent.IntentResponseType.ACTION_DONE
|
||||||
|
assert result.speech_slots.get("canceled", 0) == 3
|
||||||
|
|
||||||
|
# No timers should be running for test_device
|
||||||
|
result = await intent.async_handle(
|
||||||
|
hass, "test", intent.INTENT_TIMER_STATUS, {}, device_id=device_id
|
||||||
|
)
|
||||||
|
assert result.response_type == intent.IntentResponseType.ACTION_DONE
|
||||||
|
timers = result.speech_slots.get("timers", [])
|
||||||
|
assert len(timers) == 0
|
||||||
|
|
||||||
|
|
||||||
|
async def test_cancel_all_timers_area(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
init_components,
|
||||||
|
area_registry: ar.AreaRegistry,
|
||||||
|
device_registry: dr.DeviceRegistry,
|
||||||
|
) -> None:
|
||||||
|
"""Test cancelling all timers in an area."""
|
||||||
|
entry = MockConfigEntry()
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
area_kitchen = area_registry.async_create("kitchen")
|
||||||
|
device_kitchen = device_registry.async_get_or_create(
|
||||||
|
config_entry_id=entry.entry_id,
|
||||||
|
connections=set(),
|
||||||
|
identifiers={("test", "kitchen-device")},
|
||||||
|
)
|
||||||
|
device_registry.async_update_device(device_kitchen.id, area_id=area_kitchen.id)
|
||||||
|
|
||||||
|
area_living_room = area_registry.async_create("living room")
|
||||||
|
device_living_room = device_registry.async_get_or_create(
|
||||||
|
config_entry_id=entry.entry_id,
|
||||||
|
connections=set(),
|
||||||
|
identifiers={("test", "living_room-device")},
|
||||||
|
)
|
||||||
|
device_registry.async_update_device(
|
||||||
|
device_living_room.id, area_id=area_living_room.id
|
||||||
|
)
|
||||||
|
|
||||||
|
started_event = asyncio.Event()
|
||||||
|
num_timers = 3
|
||||||
|
num_started = 0
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def handle_timer(event_type: TimerEventType, timer: TimerInfo) -> None:
|
||||||
|
nonlocal num_started
|
||||||
|
|
||||||
|
if event_type == TimerEventType.STARTED:
|
||||||
|
num_started += 1
|
||||||
|
if num_started == num_timers:
|
||||||
|
started_event.set()
|
||||||
|
|
||||||
|
async_register_timer_handler(hass, device_kitchen.id, handle_timer)
|
||||||
|
async_register_timer_handler(hass, device_living_room.id, handle_timer)
|
||||||
|
|
||||||
|
# Start timers in different areas
|
||||||
|
result = await intent.async_handle(
|
||||||
|
hass,
|
||||||
|
"test",
|
||||||
|
intent.INTENT_START_TIMER,
|
||||||
|
{"name": {"value": "pizza"}, "minutes": {"value": 10}},
|
||||||
|
device_id=device_kitchen.id,
|
||||||
|
)
|
||||||
|
assert result.response_type == intent.IntentResponseType.ACTION_DONE
|
||||||
|
|
||||||
|
result = await intent.async_handle(
|
||||||
|
hass,
|
||||||
|
"test",
|
||||||
|
intent.INTENT_START_TIMER,
|
||||||
|
{"name": {"value": "tv"}, "minutes": {"value": 10}},
|
||||||
|
device_id=device_living_room.id,
|
||||||
|
)
|
||||||
|
assert result.response_type == intent.IntentResponseType.ACTION_DONE
|
||||||
|
|
||||||
|
result = await intent.async_handle(
|
||||||
|
hass,
|
||||||
|
"test",
|
||||||
|
intent.INTENT_START_TIMER,
|
||||||
|
{"name": {"value": "media"}, "minutes": {"value": 15}},
|
||||||
|
device_id=device_living_room.id,
|
||||||
|
)
|
||||||
|
assert result.response_type == intent.IntentResponseType.ACTION_DONE
|
||||||
|
|
||||||
|
# Wait for all timers to start
|
||||||
|
async with asyncio.timeout(1):
|
||||||
|
await started_event.wait()
|
||||||
|
|
||||||
|
# Cancel all timers in kitchen
|
||||||
|
result = await intent.async_handle(
|
||||||
|
hass,
|
||||||
|
"test",
|
||||||
|
intent.INTENT_CANCEL_ALL_TIMERS,
|
||||||
|
{"area": {"value": "kitchen"}},
|
||||||
|
device_id=device_kitchen.id,
|
||||||
|
)
|
||||||
|
assert result.response_type == intent.IntentResponseType.ACTION_DONE
|
||||||
|
assert result.speech_slots.get("canceled", 0) == 1
|
||||||
|
|
||||||
|
# No timers should be running in kitchen
|
||||||
|
result = await intent.async_handle(
|
||||||
|
hass,
|
||||||
|
"test",
|
||||||
|
intent.INTENT_TIMER_STATUS,
|
||||||
|
{"area": {"value": "kitchen"}},
|
||||||
|
device_id=device_kitchen.id,
|
||||||
|
)
|
||||||
|
assert result.response_type == intent.IntentResponseType.ACTION_DONE
|
||||||
|
timers = result.speech_slots.get("timers", [])
|
||||||
|
assert len(timers) == 0
|
||||||
|
|
||||||
|
# timers should be running in living room
|
||||||
|
result = await intent.async_handle(
|
||||||
|
hass,
|
||||||
|
"test",
|
||||||
|
intent.INTENT_TIMER_STATUS,
|
||||||
|
{"area": {"value": "living room"}},
|
||||||
|
device_id=device_living_room.id,
|
||||||
|
)
|
||||||
|
assert result.response_type == intent.IntentResponseType.ACTION_DONE
|
||||||
|
timers = result.speech_slots.get("timers", [])
|
||||||
|
assert len(timers) == 2
|
||||||
|
@ -306,6 +306,7 @@ async def test_assist_api_tools(
|
|||||||
"HassSetPosition",
|
"HassSetPosition",
|
||||||
"HassStartTimer",
|
"HassStartTimer",
|
||||||
"HassCancelTimer",
|
"HassCancelTimer",
|
||||||
|
"HassCancelAllTimers",
|
||||||
"HassIncreaseTimer",
|
"HassIncreaseTimer",
|
||||||
"HassDecreaseTimer",
|
"HassDecreaseTimer",
|
||||||
"HassPauseTimer",
|
"HassPauseTimer",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user