Add timer support to mobile app (#121469)
* Add timer support to mobile app * Fix tests * Make it time-sensitive
This commit is contained in:
parent
4ae6e38800
commit
454ca0ce95
4 changed files with 139 additions and 3 deletions
|
@ -1,9 +1,10 @@
|
||||||
"""Integrates Native Apps to Home Assistant."""
|
"""Integrates Native Apps to Home Assistant."""
|
||||||
|
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
|
from functools import partial
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from homeassistant.components import cloud, notify as hass_notify
|
from homeassistant.components import cloud, intent, notify as hass_notify
|
||||||
from homeassistant.components.webhook import (
|
from homeassistant.components.webhook import (
|
||||||
async_register as webhook_register,
|
async_register as webhook_register,
|
||||||
async_unregister as webhook_unregister,
|
async_unregister as webhook_unregister,
|
||||||
|
@ -46,7 +47,8 @@ from .const import (
|
||||||
)
|
)
|
||||||
from .helpers import savable_state
|
from .helpers import savable_state
|
||||||
from .http_api import RegistrationsView
|
from .http_api import RegistrationsView
|
||||||
from .util import async_create_cloud_hook
|
from .timers import async_handle_timer_event
|
||||||
|
from .util import async_create_cloud_hook, supports_push
|
||||||
from .webhook import handle_webhook
|
from .webhook import handle_webhook
|
||||||
|
|
||||||
PLATFORMS = [Platform.BINARY_SENSOR, Platform.DEVICE_TRACKER, Platform.SENSOR]
|
PLATFORMS = [Platform.BINARY_SENSOR, Platform.DEVICE_TRACKER, Platform.SENSOR]
|
||||||
|
@ -133,6 +135,13 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
|
|
||||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||||
|
|
||||||
|
if supports_push(hass, webhook_id):
|
||||||
|
entry.async_on_unload(
|
||||||
|
intent.async_register_timer_handler(
|
||||||
|
hass, device.id, partial(async_handle_timer_event, hass, entry)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
await hass_notify.async_reload(hass, DOMAIN)
|
await hass_notify.async_reload(hass, DOMAIN)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -4,7 +4,14 @@
|
||||||
"after_dependencies": ["cloud", "camera", "conversation", "notify"],
|
"after_dependencies": ["cloud", "camera", "conversation", "notify"],
|
||||||
"codeowners": ["@home-assistant/core"],
|
"codeowners": ["@home-assistant/core"],
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"dependencies": ["http", "webhook", "person", "tag", "websocket_api"],
|
"dependencies": [
|
||||||
|
"http",
|
||||||
|
"intent",
|
||||||
|
"person",
|
||||||
|
"tag",
|
||||||
|
"webhook",
|
||||||
|
"websocket_api"
|
||||||
|
],
|
||||||
"documentation": "https://www.home-assistant.io/integrations/mobile_app",
|
"documentation": "https://www.home-assistant.io/integrations/mobile_app",
|
||||||
"iot_class": "local_push",
|
"iot_class": "local_push",
|
||||||
"loggers": ["nacl"],
|
"loggers": ["nacl"],
|
||||||
|
|
52
homeassistant/components/mobile_app/timers.py
Normal file
52
homeassistant/components/mobile_app/timers.py
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
"""Timers for the mobile app."""
|
||||||
|
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
|
from homeassistant.components import notify
|
||||||
|
from homeassistant.components.intent.timers import TimerEventType, TimerInfo
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.const import CONF_DEVICE_ID
|
||||||
|
from homeassistant.core import HomeAssistant, callback
|
||||||
|
|
||||||
|
from . import device_action
|
||||||
|
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def async_handle_timer_event(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entry: ConfigEntry,
|
||||||
|
event_type: TimerEventType,
|
||||||
|
timer_info: TimerInfo,
|
||||||
|
) -> None:
|
||||||
|
"""Handle timer events."""
|
||||||
|
if event_type != TimerEventType.FINISHED:
|
||||||
|
return
|
||||||
|
|
||||||
|
if timer_info.name:
|
||||||
|
message = f"{timer_info.name} finished"
|
||||||
|
else:
|
||||||
|
message = f"{timedelta(seconds=timer_info.created_seconds)} timer finished"
|
||||||
|
|
||||||
|
entry.async_create_task(
|
||||||
|
hass,
|
||||||
|
device_action.async_call_action_from_config(
|
||||||
|
hass,
|
||||||
|
{
|
||||||
|
CONF_DEVICE_ID: timer_info.device_id,
|
||||||
|
notify.ATTR_MESSAGE: message,
|
||||||
|
notify.ATTR_DATA: {
|
||||||
|
"group": "timers",
|
||||||
|
# Android
|
||||||
|
"channel": "Timers",
|
||||||
|
"importance": "high",
|
||||||
|
# iOS
|
||||||
|
"push": {
|
||||||
|
"interruption-level": "time-sensitive",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
"mobile_app_timer_notification",
|
||||||
|
)
|
68
tests/components/mobile_app/test_timers.py
Normal file
68
tests/components/mobile_app/test_timers.py
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
"""Test mobile app timers."""
|
||||||
|
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.components.mobile_app import DATA_DEVICES, DOMAIN
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers import intent as intent_helper
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("intent_args", "message"),
|
||||||
|
[
|
||||||
|
(
|
||||||
|
{},
|
||||||
|
"0:02:00 timer finished",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
{"name": {"value": "pizza"}},
|
||||||
|
"pizza finished",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_timer_events(
|
||||||
|
hass: HomeAssistant, push_registration, intent_args: dict, message: str
|
||||||
|
) -> None:
|
||||||
|
"""Test for timer events."""
|
||||||
|
webhook_id = push_registration["webhook_id"]
|
||||||
|
device_id = hass.data[DOMAIN][DATA_DEVICES][webhook_id].id
|
||||||
|
|
||||||
|
await intent_helper.async_handle(
|
||||||
|
hass,
|
||||||
|
"test",
|
||||||
|
intent_helper.INTENT_START_TIMER,
|
||||||
|
{
|
||||||
|
"minutes": {"value": 2},
|
||||||
|
}
|
||||||
|
| intent_args,
|
||||||
|
device_id=device_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.mobile_app.notify.MobileAppNotificationService.async_send_message"
|
||||||
|
) as mock_send_message:
|
||||||
|
await intent_helper.async_handle(
|
||||||
|
hass,
|
||||||
|
"test",
|
||||||
|
intent_helper.INTENT_DECREASE_TIMER,
|
||||||
|
{
|
||||||
|
"minutes": {"value": 2},
|
||||||
|
},
|
||||||
|
device_id=device_id,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert mock_send_message.mock_calls[0][2] == {
|
||||||
|
"target": [webhook_id],
|
||||||
|
"message": message,
|
||||||
|
"data": {
|
||||||
|
"channel": "Timers",
|
||||||
|
"group": "timers",
|
||||||
|
"importance": "high",
|
||||||
|
"push": {
|
||||||
|
"interruption-level": "time-sensitive",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue