mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
[esphome] Assist timers (#118275)
* [esphome] Assist timers * Add intent to manifest dependencies * Add test --------- Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
This commit is contained in:
parent
06d6f99964
commit
7f530ee0e4
@ -27,6 +27,7 @@ from awesomeversion import AwesomeVersion
|
|||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components import tag, zeroconf
|
from homeassistant.components import tag, zeroconf
|
||||||
|
from homeassistant.components.intent import async_register_timer_handler
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_DEVICE_ID,
|
ATTR_DEVICE_ID,
|
||||||
@ -77,6 +78,7 @@ from .voice_assistant import (
|
|||||||
VoiceAssistantAPIPipeline,
|
VoiceAssistantAPIPipeline,
|
||||||
VoiceAssistantPipeline,
|
VoiceAssistantPipeline,
|
||||||
VoiceAssistantUDPPipeline,
|
VoiceAssistantUDPPipeline,
|
||||||
|
handle_timer_event,
|
||||||
)
|
)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
@ -517,6 +519,12 @@ class ESPHomeManager:
|
|||||||
handle_stop=self._handle_pipeline_stop,
|
handle_stop=self._handle_pipeline_stop,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
if flags & VoiceAssistantFeature.TIMERS:
|
||||||
|
entry_data.disconnect_callbacks.add(
|
||||||
|
async_register_timer_handler(
|
||||||
|
hass, self.device_id, partial(handle_timer_event, cli)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
cli.subscribe_states(entry_data.async_update_state)
|
cli.subscribe_states(entry_data.async_update_state)
|
||||||
cli.subscribe_service_calls(self.async_on_service_call)
|
cli.subscribe_service_calls(self.async_on_service_call)
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"after_dependencies": ["zeroconf", "tag"],
|
"after_dependencies": ["zeroconf", "tag"],
|
||||||
"codeowners": ["@OttoWinter", "@jesserockz", "@kbx81", "@bdraco"],
|
"codeowners": ["@OttoWinter", "@jesserockz", "@kbx81", "@bdraco"],
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"dependencies": ["assist_pipeline", "bluetooth"],
|
"dependencies": ["assist_pipeline", "bluetooth", "intent"],
|
||||||
"dhcp": [
|
"dhcp": [
|
||||||
{
|
{
|
||||||
"registered_devices": true
|
"registered_devices": true
|
||||||
|
@ -16,6 +16,7 @@ from aioesphomeapi import (
|
|||||||
VoiceAssistantCommandFlag,
|
VoiceAssistantCommandFlag,
|
||||||
VoiceAssistantEventType,
|
VoiceAssistantEventType,
|
||||||
VoiceAssistantFeature,
|
VoiceAssistantFeature,
|
||||||
|
VoiceAssistantTimerEventType,
|
||||||
)
|
)
|
||||||
|
|
||||||
from homeassistant.components import stt, tts
|
from homeassistant.components import stt, tts
|
||||||
@ -33,6 +34,7 @@ from homeassistant.components.assist_pipeline.error import (
|
|||||||
WakeWordDetectionAborted,
|
WakeWordDetectionAborted,
|
||||||
WakeWordDetectionError,
|
WakeWordDetectionError,
|
||||||
)
|
)
|
||||||
|
from homeassistant.components.intent.timers import TimerEventType, TimerInfo
|
||||||
from homeassistant.components.media_player import async_process_play_media_url
|
from homeassistant.components.media_player import async_process_play_media_url
|
||||||
from homeassistant.core import Context, HomeAssistant, callback
|
from homeassistant.core import Context, HomeAssistant, callback
|
||||||
|
|
||||||
@ -65,6 +67,17 @@ _VOICE_ASSISTANT_EVENT_TYPES: EsphomeEnumMapper[
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
_TIMER_EVENT_TYPES: EsphomeEnumMapper[VoiceAssistantTimerEventType, TimerEventType] = (
|
||||||
|
EsphomeEnumMapper(
|
||||||
|
{
|
||||||
|
VoiceAssistantTimerEventType.VOICE_ASSISTANT_TIMER_STARTED: TimerEventType.STARTED,
|
||||||
|
VoiceAssistantTimerEventType.VOICE_ASSISTANT_TIMER_UPDATED: TimerEventType.UPDATED,
|
||||||
|
VoiceAssistantTimerEventType.VOICE_ASSISTANT_TIMER_CANCELLED: TimerEventType.CANCELLED,
|
||||||
|
VoiceAssistantTimerEventType.VOICE_ASSISTANT_TIMER_FINISHED: TimerEventType.FINISHED,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class VoiceAssistantPipeline:
|
class VoiceAssistantPipeline:
|
||||||
"""Base abstract pipeline class."""
|
"""Base abstract pipeline class."""
|
||||||
@ -438,3 +451,23 @@ class VoiceAssistantAPIPipeline(VoiceAssistantPipeline):
|
|||||||
|
|
||||||
self.started = False
|
self.started = False
|
||||||
self.stop_requested = True
|
self.stop_requested = True
|
||||||
|
|
||||||
|
|
||||||
|
def handle_timer_event(
|
||||||
|
api_client: APIClient, event_type: TimerEventType, timer_info: TimerInfo
|
||||||
|
) -> None:
|
||||||
|
"""Handle timer events."""
|
||||||
|
try:
|
||||||
|
native_event_type = _TIMER_EVENT_TYPES.from_hass(event_type)
|
||||||
|
except KeyError:
|
||||||
|
_LOGGER.debug("Received unknown timer event type: %s", event_type)
|
||||||
|
return
|
||||||
|
|
||||||
|
api_client.send_voice_assistant_timer_event(
|
||||||
|
native_event_type,
|
||||||
|
timer_info.id,
|
||||||
|
timer_info.name,
|
||||||
|
timer_info.seconds,
|
||||||
|
timer_info.seconds_left,
|
||||||
|
timer_info.is_active,
|
||||||
|
)
|
||||||
|
@ -1,13 +1,21 @@
|
|||||||
"""Test ESPHome voice assistant server."""
|
"""Test ESPHome voice assistant server."""
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from collections.abc import Callable
|
from collections.abc import Awaitable, Callable
|
||||||
import io
|
import io
|
||||||
import socket
|
import socket
|
||||||
from unittest.mock import Mock, patch
|
from unittest.mock import ANY, Mock, patch
|
||||||
import wave
|
import wave
|
||||||
|
|
||||||
from aioesphomeapi import APIClient, VoiceAssistantEventType
|
from aioesphomeapi import (
|
||||||
|
APIClient,
|
||||||
|
EntityInfo,
|
||||||
|
EntityState,
|
||||||
|
UserService,
|
||||||
|
VoiceAssistantEventType,
|
||||||
|
VoiceAssistantFeature,
|
||||||
|
VoiceAssistantTimerEventType,
|
||||||
|
)
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.assist_pipeline import (
|
from homeassistant.components.assist_pipeline import (
|
||||||
@ -25,6 +33,10 @@ from homeassistant.components.esphome.voice_assistant import (
|
|||||||
VoiceAssistantUDPPipeline,
|
VoiceAssistantUDPPipeline,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers import intent as intent_helper
|
||||||
|
import homeassistant.helpers.device_registry as dr
|
||||||
|
|
||||||
|
from .conftest import MockESPHomeDevice
|
||||||
|
|
||||||
_TEST_INPUT_TEXT = "This is an input test"
|
_TEST_INPUT_TEXT = "This is an input test"
|
||||||
_TEST_OUTPUT_TEXT = "This is an output test"
|
_TEST_OUTPUT_TEXT = "This is an output test"
|
||||||
@ -720,3 +732,51 @@ async def test_wake_word_abort_exception(
|
|||||||
)
|
)
|
||||||
|
|
||||||
mock_handle_event.assert_not_called()
|
mock_handle_event.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
async def test_timer_events(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_client: APIClient,
|
||||||
|
mock_esphome_device: Callable[
|
||||||
|
[APIClient, list[EntityInfo], list[UserService], list[EntityState]],
|
||||||
|
Awaitable[MockESPHomeDevice],
|
||||||
|
],
|
||||||
|
) -> None:
|
||||||
|
"""Test that injecting timer events results in the correct api client calls."""
|
||||||
|
|
||||||
|
mock_device: MockESPHomeDevice = await mock_esphome_device(
|
||||||
|
mock_client=mock_client,
|
||||||
|
entity_info=[],
|
||||||
|
user_service=[],
|
||||||
|
states=[],
|
||||||
|
device_info={
|
||||||
|
"voice_assistant_feature_flags": VoiceAssistantFeature.VOICE_ASSISTANT
|
||||||
|
| VoiceAssistantFeature.TIMERS
|
||||||
|
},
|
||||||
|
)
|
||||||
|
dev_reg = dr.async_get(hass)
|
||||||
|
dev = dev_reg.async_get_device(
|
||||||
|
connections={(dr.CONNECTION_NETWORK_MAC, mock_device.entry.unique_id)}
|
||||||
|
)
|
||||||
|
|
||||||
|
await intent_helper.async_handle(
|
||||||
|
hass,
|
||||||
|
"test",
|
||||||
|
intent_helper.INTENT_START_TIMER,
|
||||||
|
{
|
||||||
|
"name": {"value": "test timer"},
|
||||||
|
"hours": {"value": 1},
|
||||||
|
"minutes": {"value": 2},
|
||||||
|
"seconds": {"value": 3},
|
||||||
|
},
|
||||||
|
device_id=dev.id,
|
||||||
|
)
|
||||||
|
|
||||||
|
mock_client.send_voice_assistant_timer_event.assert_called_with(
|
||||||
|
VoiceAssistantTimerEventType.VOICE_ASSISTANT_TIMER_STARTED,
|
||||||
|
ANY,
|
||||||
|
"test timer",
|
||||||
|
3723,
|
||||||
|
3723,
|
||||||
|
True,
|
||||||
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user