mirror of
https://github.com/home-assistant/core.git
synced 2025-07-25 14:17:45 +00:00
Adding done_message to alert (#8116)
* Adding done_message to alert Adding an optional entry to the config that will send a notification when an alarm goes from on to off. * Update test_alert.py * Update test_alert.py
This commit is contained in:
parent
ed20f7e359
commit
5e56bc7464
@ -25,6 +25,7 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
DOMAIN = 'alert'
|
DOMAIN = 'alert'
|
||||||
ENTITY_ID_FORMAT = DOMAIN + '.{}'
|
ENTITY_ID_FORMAT = DOMAIN + '.{}'
|
||||||
|
|
||||||
|
CONF_DONE_MESSAGE = 'done_message'
|
||||||
CONF_CAN_ACK = 'can_acknowledge'
|
CONF_CAN_ACK = 'can_acknowledge'
|
||||||
CONF_NOTIFIERS = 'notifiers'
|
CONF_NOTIFIERS = 'notifiers'
|
||||||
CONF_REPEAT = 'repeat'
|
CONF_REPEAT = 'repeat'
|
||||||
@ -35,6 +36,7 @@ DEFAULT_SKIP_FIRST = False
|
|||||||
|
|
||||||
ALERT_SCHEMA = vol.Schema({
|
ALERT_SCHEMA = vol.Schema({
|
||||||
vol.Required(CONF_NAME): cv.string,
|
vol.Required(CONF_NAME): cv.string,
|
||||||
|
vol.Optional(CONF_DONE_MESSAGE, default=None): cv.string,
|
||||||
vol.Required(CONF_ENTITY_ID): cv.entity_id,
|
vol.Required(CONF_ENTITY_ID): cv.entity_id,
|
||||||
vol.Required(CONF_STATE, default=STATE_ON): cv.string,
|
vol.Required(CONF_STATE, default=STATE_ON): cv.string,
|
||||||
vol.Required(CONF_REPEAT): vol.All(cv.ensure_list, [vol.Coerce(float)]),
|
vol.Required(CONF_REPEAT): vol.All(cv.ensure_list, [vol.Coerce(float)]),
|
||||||
@ -121,10 +123,10 @@ def async_setup(hass, config):
|
|||||||
# Setup alerts
|
# Setup alerts
|
||||||
for entity_id, alert in alerts.items():
|
for entity_id, alert in alerts.items():
|
||||||
entity = Alert(hass, entity_id,
|
entity = Alert(hass, entity_id,
|
||||||
alert[CONF_NAME], alert[CONF_ENTITY_ID],
|
alert[CONF_NAME], alert[CONF_DONE_MESSAGE],
|
||||||
alert[CONF_STATE], alert[CONF_REPEAT],
|
alert[CONF_ENTITY_ID], alert[CONF_STATE],
|
||||||
alert[CONF_SKIP_FIRST], alert[CONF_NOTIFIERS],
|
alert[CONF_REPEAT], alert[CONF_SKIP_FIRST],
|
||||||
alert[CONF_CAN_ACK])
|
alert[CONF_NOTIFIERS], alert[CONF_CAN_ACK])
|
||||||
all_alerts[entity.entity_id] = entity
|
all_alerts[entity.entity_id] = entity
|
||||||
|
|
||||||
# Read descriptions
|
# Read descriptions
|
||||||
@ -154,8 +156,8 @@ def async_setup(hass, config):
|
|||||||
class Alert(ToggleEntity):
|
class Alert(ToggleEntity):
|
||||||
"""Representation of an alert."""
|
"""Representation of an alert."""
|
||||||
|
|
||||||
def __init__(self, hass, entity_id, name, watched_entity_id, state,
|
def __init__(self, hass, entity_id, name, done_message, watched_entity_id,
|
||||||
repeat, skip_first, notifiers, can_ack):
|
state, repeat, skip_first, notifiers, can_ack):
|
||||||
"""Initialize the alert."""
|
"""Initialize the alert."""
|
||||||
self.hass = hass
|
self.hass = hass
|
||||||
self._name = name
|
self._name = name
|
||||||
@ -163,6 +165,7 @@ class Alert(ToggleEntity):
|
|||||||
self._skip_first = skip_first
|
self._skip_first = skip_first
|
||||||
self._notifiers = notifiers
|
self._notifiers = notifiers
|
||||||
self._can_ack = can_ack
|
self._can_ack = can_ack
|
||||||
|
self._done_message = done_message
|
||||||
|
|
||||||
self._delay = [timedelta(minutes=val) for val in repeat]
|
self._delay = [timedelta(minutes=val) for val in repeat]
|
||||||
self._next_delay = 0
|
self._next_delay = 0
|
||||||
@ -170,6 +173,7 @@ class Alert(ToggleEntity):
|
|||||||
self._firing = False
|
self._firing = False
|
||||||
self._ack = False
|
self._ack = False
|
||||||
self._cancel = None
|
self._cancel = None
|
||||||
|
self._send_done_message = False
|
||||||
self.entity_id = ENTITY_ID_FORMAT.format(entity_id)
|
self.entity_id = ENTITY_ID_FORMAT.format(entity_id)
|
||||||
|
|
||||||
event.async_track_state_change(
|
event.async_track_state_change(
|
||||||
@ -230,6 +234,8 @@ class Alert(ToggleEntity):
|
|||||||
self._cancel()
|
self._cancel()
|
||||||
self._ack = False
|
self._ack = False
|
||||||
self._firing = False
|
self._firing = False
|
||||||
|
if self._done_message and self._send_done_message:
|
||||||
|
yield from self._notify_done_message()
|
||||||
self.hass.async_add_job(self.async_update_ha_state)
|
self.hass.async_add_job(self.async_update_ha_state)
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
@ -249,11 +255,21 @@ class Alert(ToggleEntity):
|
|||||||
|
|
||||||
if not self._ack:
|
if not self._ack:
|
||||||
_LOGGER.info("Alerting: %s", self._name)
|
_LOGGER.info("Alerting: %s", self._name)
|
||||||
|
self._send_done_message = True
|
||||||
for target in self._notifiers:
|
for target in self._notifiers:
|
||||||
yield from self.hass.services.async_call(
|
yield from self.hass.services.async_call(
|
||||||
'notify', target, {'message': self._name})
|
'notify', target, {'message': self._name})
|
||||||
yield from self._schedule_notify()
|
yield from self._schedule_notify()
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def _notify_done_message(self, *args):
|
||||||
|
"""Send notification of complete alert."""
|
||||||
|
_LOGGER.info("Alerting: %s", self._done_message)
|
||||||
|
self._send_done_message = False
|
||||||
|
for target in self._notifiers:
|
||||||
|
yield from self.hass.services.async_call(
|
||||||
|
'notify', target, {'message': self._done_message})
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def async_turn_on(self):
|
def async_turn_on(self):
|
||||||
"""Async Unacknowledge alert."""
|
"""Async Unacknowledge alert."""
|
||||||
|
@ -13,19 +13,21 @@ from homeassistant.const import (CONF_ENTITY_ID, STATE_IDLE, CONF_NAME,
|
|||||||
from tests.common import get_test_home_assistant
|
from tests.common import get_test_home_assistant
|
||||||
|
|
||||||
NAME = "alert_test"
|
NAME = "alert_test"
|
||||||
|
DONE_MESSAGE = "alert_gone"
|
||||||
NOTIFIER = 'test'
|
NOTIFIER = 'test'
|
||||||
TEST_CONFIG = \
|
TEST_CONFIG = \
|
||||||
{alert.DOMAIN: {
|
{alert.DOMAIN: {
|
||||||
NAME: {
|
NAME: {
|
||||||
CONF_NAME: NAME,
|
CONF_NAME: NAME,
|
||||||
|
alert.CONF_DONE_MESSAGE: DONE_MESSAGE,
|
||||||
CONF_ENTITY_ID: "sensor.test",
|
CONF_ENTITY_ID: "sensor.test",
|
||||||
CONF_STATE: STATE_ON,
|
CONF_STATE: STATE_ON,
|
||||||
alert.CONF_REPEAT: 30,
|
alert.CONF_REPEAT: 30,
|
||||||
alert.CONF_SKIP_FIRST: False,
|
alert.CONF_SKIP_FIRST: False,
|
||||||
alert.CONF_NOTIFIERS: [NOTIFIER]}
|
alert.CONF_NOTIFIERS: [NOTIFIER]}
|
||||||
}}
|
}}
|
||||||
TEST_NOACK = [NAME, NAME, "sensor.test", STATE_ON,
|
TEST_NOACK = [NAME, NAME, DONE_MESSAGE, "sensor.test",
|
||||||
[30], False, NOTIFIER, False]
|
STATE_ON, [30], False, NOTIFIER, False]
|
||||||
ENTITY_ID = alert.ENTITY_ID_FORMAT.format(NAME)
|
ENTITY_ID = alert.ENTITY_ID_FORMAT.format(NAME)
|
||||||
|
|
||||||
|
|
||||||
@ -119,6 +121,31 @@ class TestAlert(unittest.TestCase):
|
|||||||
hidden = self.hass.states.get(ENTITY_ID).attributes.get('hidden')
|
hidden = self.hass.states.get(ENTITY_ID).attributes.get('hidden')
|
||||||
self.assertFalse(hidden)
|
self.assertFalse(hidden)
|
||||||
|
|
||||||
|
def test_notification_no_done_message(self):
|
||||||
|
"""Test notifications."""
|
||||||
|
events = []
|
||||||
|
config = deepcopy(TEST_CONFIG)
|
||||||
|
del(config[alert.DOMAIN][NAME][alert.CONF_DONE_MESSAGE])
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def record_event(event):
|
||||||
|
"""Add recorded event to set."""
|
||||||
|
events.append(event)
|
||||||
|
|
||||||
|
self.hass.services.register(
|
||||||
|
notify.DOMAIN, NOTIFIER, record_event)
|
||||||
|
|
||||||
|
assert setup_component(self.hass, alert.DOMAIN, config)
|
||||||
|
self.assertEqual(0, len(events))
|
||||||
|
|
||||||
|
self.hass.states.set("sensor.test", STATE_ON)
|
||||||
|
self.hass.block_till_done()
|
||||||
|
self.assertEqual(1, len(events))
|
||||||
|
|
||||||
|
self.hass.states.set("sensor.test", STATE_OFF)
|
||||||
|
self.hass.block_till_done()
|
||||||
|
self.assertEqual(1, len(events))
|
||||||
|
|
||||||
def test_notification(self):
|
def test_notification(self):
|
||||||
"""Test notifications."""
|
"""Test notifications."""
|
||||||
events = []
|
events = []
|
||||||
@ -140,7 +167,7 @@ class TestAlert(unittest.TestCase):
|
|||||||
|
|
||||||
self.hass.states.set("sensor.test", STATE_OFF)
|
self.hass.states.set("sensor.test", STATE_OFF)
|
||||||
self.hass.block_till_done()
|
self.hass.block_till_done()
|
||||||
self.assertEqual(1, len(events))
|
self.assertEqual(2, len(events))
|
||||||
|
|
||||||
def test_skipfirst(self):
|
def test_skipfirst(self):
|
||||||
"""Test skipping first notification."""
|
"""Test skipping first notification."""
|
||||||
@ -170,3 +197,13 @@ class TestAlert(unittest.TestCase):
|
|||||||
self.hass.block_till_done()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
self.assertEqual(True, entity.hidden)
|
self.assertEqual(True, entity.hidden)
|
||||||
|
|
||||||
|
def test_done_message_state_tracker_reset_on_cancel(self):
|
||||||
|
"""Test that the done message is reset when cancelled."""
|
||||||
|
entity = alert.Alert(self.hass, *TEST_NOACK)
|
||||||
|
entity._cancel = lambda *args: None
|
||||||
|
assert entity._send_done_message is False
|
||||||
|
entity._send_done_message = True
|
||||||
|
self.hass.add_job(entity.end_alerting)
|
||||||
|
self.hass.block_till_done()
|
||||||
|
assert entity._send_done_message is False
|
||||||
|
Loading…
x
Reference in New Issue
Block a user