diff --git a/.coveragerc b/.coveragerc index a4f25bd73f8..8e9ed417d7b 100644 --- a/.coveragerc +++ b/.coveragerc @@ -610,6 +610,7 @@ omit = homeassistant/components/notify/gntp.py homeassistant/components/notify/group.py homeassistant/components/notify/hipchat.py + homeassistant/components/notify/homematic.py homeassistant/components/notify/instapush.py homeassistant/components/notify/kodi.py homeassistant/components/notify/lannouncer.py diff --git a/homeassistant/components/notify/homematic.py b/homeassistant/components/notify/homematic.py new file mode 100644 index 00000000000..2587bac8b6c --- /dev/null +++ b/homeassistant/components/notify/homematic.py @@ -0,0 +1,74 @@ +""" +Notification support for Homematic. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/notify.homematic/ +""" +import logging + +import voluptuous as vol + +from homeassistant.components.notify import ( + BaseNotificationService, PLATFORM_SCHEMA, ATTR_DATA) +import homeassistant.helpers.config_validation as cv +from homeassistant.components.homematic import ( + DOMAIN, SERVICE_SET_DEVICE_VALUE, ATTR_ADDRESS, ATTR_CHANNEL, ATTR_PARAM, + ATTR_VALUE, ATTR_INTERFACE) +import homeassistant.helpers.template as template_helper + +_LOGGER = logging.getLogger(__name__) +DEPENDENCIES = ["homematic"] + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(ATTR_ADDRESS): vol.All(cv.string, vol.Upper), + vol.Required(ATTR_CHANNEL): vol.Coerce(int), + vol.Required(ATTR_PARAM): vol.All(cv.string, vol.Upper), + vol.Required(ATTR_VALUE): cv.match_all, + vol.Optional(ATTR_INTERFACE): cv.string, +}) + + +def get_service(hass, config, discovery_info=None): + """Get the Homematic notification service.""" + data = { + ATTR_ADDRESS: config[ATTR_ADDRESS], + ATTR_CHANNEL: config[ATTR_CHANNEL], + ATTR_PARAM: config[ATTR_PARAM], + ATTR_VALUE: config[ATTR_VALUE] + } + if ATTR_INTERFACE in config: + data[ATTR_INTERFACE] = config[ATTR_INTERFACE] + + return HomematicNotificationService(hass, data) + + +class HomematicNotificationService(BaseNotificationService): + """Implement the notification service for Homematic.""" + + def __init__(self, hass, data): + """Initialize the service.""" + self.hass = hass + self.data = data + + def send_message(self, message="", **kwargs): + """Send a notification to the device.""" + attr_data = kwargs.get(ATTR_DATA) + if attr_data is not None: + if 'address' in attr_data: + self.data[ATTR_ADDRESS] = attr_data['address'] + if 'channel' in attr_data: + self.data[ATTR_CHANNEL] = attr_data['channel'] + if 'param' in attr_data: + self.data[ATTR_PARAM] = attr_data['param'] + if 'value' in attr_data: + self.data[ATTR_VALUE] = attr_data['value'] + if 'interface' in attr_data: + self.data[ATTR_INTERFACE] = attr_data['interface'] + + if self.data[ATTR_VALUE] is not None: + templ = template_helper.Template(self.data[ATTR_VALUE], self.hass) + self.data[ATTR_VALUE] = template_helper.render_complex(templ, None) + + _LOGGER.debug("Calling service: domain=%s;service=%s;data=%s", + DOMAIN, SERVICE_SET_DEVICE_VALUE, str(self.data)) + self.hass.services.call(DOMAIN, SERVICE_SET_DEVICE_VALUE, self.data) diff --git a/requirements_test_all.txt b/requirements_test_all.txt index e6d9a6f3fe5..280b77d6ebd 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -153,6 +153,9 @@ pydeconz==47 # homeassistant.components.zwave pydispatcher==2.0.5 +# homeassistant.components.homematic +pyhomematic==0.1.50 + # homeassistant.components.litejet pylitejet==0.1 diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py index eef77b9ec81..fd161898acc 100755 --- a/script/gen_requirements_all.py +++ b/script/gen_requirements_all.py @@ -76,6 +76,7 @@ TEST_REQUIREMENTS = ( 'pyblackbird', 'pydeconz', 'pydispatcher', + 'pyhomematic', 'pylitejet', 'pymonoprice', 'pynx584', diff --git a/tests/components/notify/test_homematic.py b/tests/components/notify/test_homematic.py new file mode 100644 index 00000000000..2ea98fc020b --- /dev/null +++ b/tests/components/notify/test_homematic.py @@ -0,0 +1,78 @@ +"""The tests for the Homematic notification platform.""" + +import unittest + +from homeassistant.setup import setup_component +import homeassistant.components.notify as notify_comp +from tests.common import assert_setup_component, get_test_home_assistant + + +class TestHomematicNotify(unittest.TestCase): + """Test the Homematic notifications.""" + + def setUp(self): # pylint: disable=invalid-name + """Set up things to be run when tests are started.""" + self.hass = get_test_home_assistant() + + def tearDown(self): # pylint: disable=invalid-name + """Stop down everything that was started.""" + self.hass.stop() + + def test_setup_full(self): + """Test valid configuration.""" + setup_component(self.hass, 'homematic', { + 'homematic': { + 'hosts': { + 'ccu2': { + 'host': '127.0.0.1' + } + } + } + }) + with assert_setup_component(1) as handle_config: + assert setup_component(self.hass, 'notify', { + 'notify': { + 'name': 'test', + 'platform': 'homematic', + 'address': 'NEQXXXXXXX', + 'channel': 2, + 'param': 'SUBMIT', + 'value': '1,1,108000,2', + 'interface': 'my-interface'} + }) + assert handle_config[notify_comp.DOMAIN] + + def test_setup_without_optional(self): + """Test valid configuration without optional.""" + setup_component(self.hass, 'homematic', { + 'homematic': { + 'hosts': { + 'ccu2': { + 'host': '127.0.0.1' + } + } + } + }) + with assert_setup_component(1) as handle_config: + assert setup_component(self.hass, 'notify', { + 'notify': { + 'name': 'test', + 'platform': 'homematic', + 'address': 'NEQXXXXXXX', + 'channel': 2, + 'param': 'SUBMIT', + 'value': '1,1,108000,2'} + }) + assert handle_config[notify_comp.DOMAIN] + + def test_bad_config(self): + """Test invalid configuration.""" + config = { + notify_comp.DOMAIN: { + 'name': 'test', + 'platform': 'homematic' + } + } + with assert_setup_component(0) as handle_config: + assert setup_component(self.hass, notify_comp.DOMAIN, config) + assert not handle_config[notify_comp.DOMAIN]