Add a group notify platform (#2842)

* Add a group notify platform which allows sending a single notification to multiple platforms.

* Correctly sort group.py

* Clean up the payload logic

* Make name and entity id required in the schema

* Deep update the dictionary to fix a bug where data wasnt merging.

* Add notify.group tests.

* Improve docstrings.

* Change entities to services and entity_id to service

* Make service a slug without a default value

* Update tests for entities->services, entity_id->service

* vol.Any(cv.slug) -> cv.slug
This commit is contained in:
Robbie Trencheny 2016-08-16 22:14:04 -07:00 committed by Paulus Schoutsen
parent c1ce6855c5
commit 848781fbb7
3 changed files with 148 additions and 0 deletions

View file

@ -173,6 +173,7 @@ omit =
homeassistant/components/notify/aws_sqs.py
homeassistant/components/notify/free_mobile.py
homeassistant/components/notify/gntp.py
homeassistant/components/notify/group.py
homeassistant/components/notify/instapush.py
homeassistant/components/notify/joaoapps_join.py
homeassistant/components/notify/message_bird.py

View file

@ -0,0 +1,65 @@
"""
Group platform for notify component.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/notify.group/
"""
import collections
import logging
import voluptuous as vol
from homeassistant.const import (CONF_PLATFORM, CONF_NAME, ATTR_SERVICE)
from homeassistant.components.notify import (DOMAIN, ATTR_MESSAGE, ATTR_DATA,
BaseNotificationService)
import homeassistant.helpers.config_validation as cv
_LOGGER = logging.getLogger(__name__)
CONF_SERVICES = "services"
PLATFORM_SCHEMA = vol.Schema({
vol.Required(CONF_PLATFORM): "group",
vol.Required(CONF_NAME): vol.Coerce(str),
vol.Required(CONF_SERVICES): vol.All(cv.ensure_list, [{
vol.Required(ATTR_SERVICE): cv.slug,
vol.Optional(ATTR_DATA): dict,
}])
})
def update(input_dict, update_source):
"""Deep update a dictionary."""
for key, val in update_source.items():
if isinstance(val, collections.Mapping):
recurse = update(input_dict.get(key, {}), val)
input_dict[key] = recurse
else:
input_dict[key] = update_source[key]
return input_dict
def get_service(hass, config):
"""Get the Group notification service."""
return GroupNotifyPlatform(hass, config.get(CONF_SERVICES))
# pylint: disable=too-few-public-methods
class GroupNotifyPlatform(BaseNotificationService):
"""Implement the notification service for the group notify playform."""
def __init__(self, hass, entities):
"""Initialize the service."""
self.hass = hass
self.entities = entities
def send_message(self, message="", **kwargs):
"""Send message to all entities in the group."""
payload = {ATTR_MESSAGE: message}
payload.update({key: val for key, val in kwargs.items() if val})
for entity in self.entities:
sending_payload = payload.copy()
if entity.get(ATTR_DATA) is not None:
update(sending_payload, entity.get(ATTR_DATA))
self.hass.services.call(DOMAIN, entity.get(ATTR_SERVICE),
sending_payload)

View file

@ -0,0 +1,82 @@
"""The tests for the notify.group platform."""
import unittest
import homeassistant.components.notify as notify
from homeassistant.components.notify import group
from tests.common import get_test_home_assistant
class TestNotifyGroup(unittest.TestCase):
"""Test the notify.group platform."""
def setUp(self): # pylint: disable=invalid-name
"""Setup things to be run when tests are started."""
self.hass = get_test_home_assistant()
self.events = []
self.assertTrue(notify.setup(self.hass, {
'notify': {
'name': 'demo1',
'platform': 'demo'
}
}))
self.assertTrue(notify.setup(self.hass, {
'notify': {
'name': 'demo2',
'platform': 'demo'
}
}))
self.service = group.get_service(self.hass, {'services': [
{'service': 'demo1'},
{'service': 'demo2',
'data': {'target': 'unnamed device',
'data': {'test': 'message'}}}]})
assert self.service is not None
def record_event(event):
"""Record event to send notification."""
self.events.append(event)
self.hass.bus.listen("notify", record_event)
def tearDown(self): # pylint: disable=invalid-name
""""Stop everything that was started."""
self.hass.stop()
def test_send_message_to_group(self):
"""Test sending a message to a notify group."""
self.service.send_message('Hello', title='Test notification')
self.hass.pool.block_till_done()
self.assertTrue(len(self.events) == 2)
last_event = self.events[-1]
self.assertEqual(last_event.data[notify.ATTR_TITLE],
'Test notification')
self.assertEqual(last_event.data[notify.ATTR_MESSAGE], 'Hello')
def test_send_message_with_data(self):
"""Test sending a message with to a notify group."""
notify_data = {'hello': 'world'}
self.service.send_message('Hello', title='Test notification',
data=notify_data)
self.hass.pool.block_till_done()
last_event = self.events[-1]
self.assertEqual(last_event.data[notify.ATTR_TITLE],
'Test notification')
self.assertEqual(last_event.data[notify.ATTR_MESSAGE], 'Hello')
self.assertEqual(last_event.data[notify.ATTR_DATA], notify_data)
def test_entity_data_passes_through(self):
"""Test sending a message with data to merge to a notify group."""
notify_data = {'hello': 'world'}
self.service.send_message('Hello', title='Test notification',
data=notify_data)
self.hass.pool.block_till_done()
data = self.events[-1].data
assert {
'message': 'Hello',
'target': 'unnamed device',
'title': 'Test notification',
'data': {'hello': 'world', 'test': 'message'}
} == data