diff --git a/homeassistant/components/logentries.py b/homeassistant/components/logentries.py new file mode 100644 index 00000000000..5aaaf2df562 --- /dev/null +++ b/homeassistant/components/logentries.py @@ -0,0 +1,61 @@ +""" +Support for sending data to Logentries webhook endpoint. + +For more details about this component, please refer to the documentation at +https://home-assistant.io/components/logentries/ +""" +import json +import logging +import requests +import homeassistant.util as util +from homeassistant.const import EVENT_STATE_CHANGED +from homeassistant.helpers import state as state_helper +from homeassistant.helpers import validate_config + +_LOGGER = logging.getLogger(__name__) + +DOMAIN = "logentries" +DEPENDENCIES = [] + +DEFAULT_HOST = 'https://webhook.logentries.com/noformat/logs/' + +CONF_TOKEN = 'token' + + +def setup(hass, config): + """Setup the Logentries component.""" + if not validate_config(config, {DOMAIN: ['token']}, _LOGGER): + _LOGGER.error("Logentries token not present") + return False + conf = config[DOMAIN] + token = util.convert(conf.get(CONF_TOKEN), str) + le_wh = DEFAULT_HOST + token + + def logentries_event_listener(event): + """Listen for new messages on the bus and sends them to Logentries.""" + state = event.data.get('new_state') + if state is None: + return + try: + _state = state_helper.state_as_number(state) + except ValueError: + _state = state.state + json_body = [ + { + 'domain': state.domain, + 'entity_id': state.object_id, + 'attributes': dict(state.attributes), + 'time': str(event.time_fired), + 'value': _state, + } + ] + try: + payload = {"host": le_wh, + "event": json_body} + requests.post(le_wh, data=json.dumps(payload), timeout=10) + except requests.exceptions.RequestException as error: + _LOGGER.exception('Error sending to Logentries: %s', error) + + hass.bus.listen(EVENT_STATE_CHANGED, logentries_event_listener) + + return True diff --git a/tests/components/test_logentries.py b/tests/components/test_logentries.py new file mode 100644 index 00000000000..c5bad5332f4 --- /dev/null +++ b/tests/components/test_logentries.py @@ -0,0 +1,88 @@ +"""The tests for the Logentries component.""" + +import unittest +from unittest import mock + +import homeassistant.components.logentries as logentries +from homeassistant.const import STATE_ON, STATE_OFF, EVENT_STATE_CHANGED + + +class TestLogentries(unittest.TestCase): + """Test the Logentries component.""" + + def test_setup_config_full(self): + """Test setup with all data.""" + config = { + 'logentries': { + 'host': 'host', + 'token': 'secret', + } + } + hass = mock.MagicMock() + self.assertTrue(logentries.setup(hass, config)) + self.assertTrue(hass.bus.listen.called) + self.assertEqual(EVENT_STATE_CHANGED, + hass.bus.listen.call_args_list[0][0][0]) + + def test_setup_config_defaults(self): + """Test setup with defaults.""" + config = { + 'logentries': { + 'host': 'host', + 'token': 'token', + } + } + hass = mock.MagicMock() + self.assertTrue(logentries.setup(hass, config)) + self.assertTrue(hass.bus.listen.called) + self.assertEqual(EVENT_STATE_CHANGED, + hass.bus.listen.call_args_list[0][0][0]) + + def _setup(self, mock_requests): + """Test the setup.""" + self.mock_post = mock_requests.post + self.mock_request_exception = Exception + mock_requests.exceptions.RequestException = self.mock_request_exception + config = { + 'logentries': { + 'host': 'https://webhook.logentries.com/noformat/logs/token', + 'token': 'token' + } + } + self.hass = mock.MagicMock() + logentries.setup(self.hass, config) + self.handler_method = self.hass.bus.listen.call_args_list[0][0][1] + + @mock.patch.object(logentries, 'requests') + @mock.patch('json.dumps') + def test_event_listener(self, mock_dump, mock_requests): + """Test event listener.""" + mock_dump.side_effect = lambda x: x + self._setup(mock_requests) + + valid = {'1': 1, + '1.0': 1.0, + STATE_ON: 1, + STATE_OFF: 0, + 'foo': 'foo'} + for in_, out in valid.items(): + state = mock.MagicMock(state=in_, + domain='fake', + object_id='entity', + attributes={}) + event = mock.MagicMock(data={'new_state': state}, + time_fired=12345) + body = [{ + 'domain': 'fake', + 'entity_id': 'entity', + 'attributes': {}, + 'time': '12345', + 'value': out, + }] + payload = {'host': 'https://webhook.logentries.com/noformat/' + 'logs/token', + 'event': body} + self.handler_method(event) + self.mock_post.assert_called_once_with( + payload['host'], data=payload, timeout=10) + self.mock_post.reset_mock()