Add data/data_template/title to alert component (#17616)

* Add data/data_template/title to alert component

* Fix line length

* Fix tests

* Fix lint

* fix line length

* Fix tests, make title templatable

* Fix test

* Fix test

* Optimize data, make title templated

* Fix line length

* Add title template

* typo

* Fix tests
This commit is contained in:
Frank 2019-01-23 08:47:37 +01:00 committed by Martin Hjelmare
parent 3484e506e8
commit db277ad023
2 changed files with 76 additions and 17 deletions

View File

@ -5,19 +5,19 @@ For more details about this component, please refer to the documentation at
https://home-assistant.io/components/alert/
"""
import asyncio
from datetime import datetime, timedelta
import logging
from datetime import datetime, timedelta
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from homeassistant.components.notify import (
ATTR_MESSAGE, DOMAIN as DOMAIN_NOTIFY)
ATTR_MESSAGE, ATTR_TITLE, ATTR_DATA, DOMAIN as DOMAIN_NOTIFY)
from homeassistant.const import (
CONF_ENTITY_ID, STATE_IDLE, CONF_NAME, CONF_STATE, STATE_ON, STATE_OFF,
SERVICE_TURN_ON, SERVICE_TURN_OFF, SERVICE_TOGGLE, ATTR_ENTITY_ID)
from homeassistant.helpers.entity import ToggleEntity
from homeassistant.helpers import service, event
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import ToggleEntity
_LOGGER = logging.getLogger(__name__)
@ -30,6 +30,8 @@ CONF_REPEAT = 'repeat'
CONF_SKIP_FIRST = 'skip_first'
CONF_ALERT_MESSAGE = 'message'
CONF_DONE_MESSAGE = 'done_message'
CONF_TITLE = 'title'
CONF_DATA = 'data'
DEFAULT_CAN_ACK = True
DEFAULT_SKIP_FIRST = False
@ -43,13 +45,14 @@ ALERT_SCHEMA = vol.Schema({
vol.Required(CONF_SKIP_FIRST, default=DEFAULT_SKIP_FIRST): cv.boolean,
vol.Optional(CONF_ALERT_MESSAGE): cv.template,
vol.Optional(CONF_DONE_MESSAGE): cv.template,
vol.Optional(CONF_TITLE): cv.template,
vol.Optional(CONF_DATA): dict,
vol.Required(CONF_NOTIFIERS): cv.ensure_list})
CONFIG_SCHEMA = vol.Schema({
DOMAIN: cv.schema_with_slug_keys(ALERT_SCHEMA),
}, extra=vol.ALLOW_EXTRA)
ALERT_SERVICE_SCHEMA = vol.Schema({
vol.Required(ATTR_ENTITY_ID): cv.entity_ids,
})
@ -77,12 +80,14 @@ async def async_setup(hass, config):
done_message_template = cfg.get(CONF_DONE_MESSAGE)
notifiers = cfg.get(CONF_NOTIFIERS)
can_ack = cfg.get(CONF_CAN_ACK)
title_template = cfg.get(CONF_TITLE)
data = cfg.get(CONF_DATA)
entities.append(Alert(hass, object_id, name,
watched_entity_id, alert_state, repeat,
skip_first, message_template,
done_message_template, notifiers,
can_ack))
can_ack, title_template, data))
if not entities:
return False
@ -127,12 +132,14 @@ class Alert(ToggleEntity):
def __init__(self, hass, entity_id, name, watched_entity_id,
state, repeat, skip_first, message_template,
done_message_template, notifiers, can_ack):
done_message_template, notifiers, can_ack, title_template,
data):
"""Initialize the alert."""
self.hass = hass
self._name = name
self._alert_state = state
self._skip_first = skip_first
self._data = data
self._message_template = message_template
if self._message_template is not None:
@ -142,6 +149,10 @@ class Alert(ToggleEntity):
if self._done_message_template is not None:
self._done_message_template.hass = hass
self._title_template = title_template
if self._title_template is not None:
self._title_template.hass = hass
self._notifiers = notifiers
self._can_ack = can_ack
@ -251,9 +262,20 @@ class Alert(ToggleEntity):
await self._send_notification_message(message)
async def _send_notification_message(self, message):
msg_payload = {ATTR_MESSAGE: message}
if self._title_template is not None:
title = self._title_template.async_render()
msg_payload.update({ATTR_TITLE: title})
if self._data:
msg_payload.update({ATTR_DATA: self._data})
_LOGGER.debug(msg_payload)
for target in self._notifiers:
await self.hass.services.async_call(
DOMAIN_NOTIFY, target, {ATTR_MESSAGE: message})
DOMAIN_NOTIFY, target, msg_payload)
async def async_turn_on(self, **kwargs):
"""Async Unacknowledge alert."""

View File

@ -1,17 +1,16 @@
"""The tests for the Alert component."""
import unittest
# pylint: disable=protected-access
from copy import deepcopy
import unittest
from homeassistant.setup import setup_component
from homeassistant.core import callback
from homeassistant.components.alert import DOMAIN
import homeassistant.components.alert as alert
import homeassistant.components.notify as notify
from homeassistant.components.alert import DOMAIN
from homeassistant.const import (
ATTR_ENTITY_ID, CONF_ENTITY_ID, STATE_IDLE, CONF_NAME, CONF_STATE,
SERVICE_TOGGLE, SERVICE_TURN_OFF, SERVICE_TURN_ON, STATE_ON, STATE_OFF)
from homeassistant.core import callback
from homeassistant.setup import setup_component
from tests.common import get_test_home_assistant
NAME = "alert_test"
@ -19,6 +18,13 @@ DONE_MESSAGE = "alert_gone"
NOTIFIER = 'test'
TEMPLATE = "{{ states.sensor.test.entity_id }}"
TEST_ENTITY = "sensor.test"
TITLE = "{{ states.sensor.test.entity_id }}"
TEST_TITLE = "sensor.test"
TEST_DATA = {
'data': {
'inline_keyboard': ['Close garage:/close_garage']
}
}
TEST_CONFIG = \
{alert.DOMAIN: {
NAME: {
@ -28,10 +34,13 @@ TEST_CONFIG = \
CONF_STATE: STATE_ON,
alert.CONF_REPEAT: 30,
alert.CONF_SKIP_FIRST: False,
alert.CONF_NOTIFIERS: [NOTIFIER]}
}}
alert.CONF_NOTIFIERS: [NOTIFIER],
alert.CONF_TITLE: TITLE,
alert.CONF_DATA: {}
}
}}
TEST_NOACK = [NAME, NAME, "sensor.test",
STATE_ON, [30], False, None, None, NOTIFIER, False]
STATE_ON, [30], False, None, None, NOTIFIER, False, None, None]
ENTITY_ID = alert.ENTITY_ID_FORMAT.format(NAME)
@ -200,7 +209,7 @@ class TestAlert(unittest.TestCase):
"""Test notifications."""
events = []
config = deepcopy(TEST_CONFIG)
del(config[alert.DOMAIN][NAME][alert.CONF_DONE_MESSAGE])
del (config[alert.DOMAIN][NAME][alert.CONF_DONE_MESSAGE])
@callback
def record_event(event):
@ -286,6 +295,34 @@ class TestAlert(unittest.TestCase):
last_event = events[-1]
self.assertEqual(last_event.data[notify.ATTR_MESSAGE], TEST_ENTITY)
def test_sending_titled_notification(self):
"""Test notifications."""
events = self._setup_notify()
config = deepcopy(TEST_CONFIG)
config[alert.DOMAIN][NAME][alert.CONF_TITLE] = TITLE
assert setup_component(self.hass, alert.DOMAIN, config)
self.hass.states.set(TEST_ENTITY, STATE_ON)
self.hass.block_till_done()
self.assertEqual(1, len(events))
last_event = events[-1]
self.assertEqual(last_event.data[notify.ATTR_TITLE], TEST_TITLE)
def test_sending_data_notification(self):
"""Test notifications."""
events = self._setup_notify()
config = deepcopy(TEST_CONFIG)
config[alert.DOMAIN][NAME][alert.CONF_DATA] = TEST_DATA
assert setup_component(self.hass, alert.DOMAIN, config)
self.hass.states.set(TEST_ENTITY, STATE_ON)
self.hass.block_till_done()
self.assertEqual(1, len(events))
last_event = events[-1]
self.assertEqual(last_event.data[notify.ATTR_DATA], TEST_DATA)
def test_skipfirst(self):
"""Test skipping first notification."""
config = deepcopy(TEST_CONFIG)