For example Discord webhooks returns a 204 success code as response, which gets logged as an error in the log, even though it is successful. Update the allowed statuses to accept all 2xx responses as successful.
119 lines
4.7 KiB
Python
119 lines
4.7 KiB
Python
"""
|
|
RESTful platform for notify component.
|
|
|
|
For more details about this platform, please refer to the documentation at
|
|
https://home-assistant.io/components/notify.rest/
|
|
"""
|
|
import logging
|
|
|
|
import requests
|
|
import voluptuous as vol
|
|
|
|
from homeassistant.components.notify import (
|
|
ATTR_TARGET, ATTR_TITLE, ATTR_TITLE_DEFAULT, BaseNotificationService,
|
|
PLATFORM_SCHEMA)
|
|
from homeassistant.const import (CONF_RESOURCE, CONF_METHOD, CONF_NAME,
|
|
CONF_HEADERS)
|
|
import homeassistant.helpers.config_validation as cv
|
|
|
|
CONF_DATA = 'data'
|
|
CONF_DATA_TEMPLATE = 'data_template'
|
|
CONF_MESSAGE_PARAMETER_NAME = 'message_param_name'
|
|
CONF_TARGET_PARAMETER_NAME = 'target_param_name'
|
|
CONF_TITLE_PARAMETER_NAME = 'title_param_name'
|
|
DEFAULT_MESSAGE_PARAM_NAME = 'message'
|
|
DEFAULT_METHOD = 'GET'
|
|
|
|
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
|
vol.Required(CONF_RESOURCE): cv.url,
|
|
vol.Optional(CONF_MESSAGE_PARAMETER_NAME,
|
|
default=DEFAULT_MESSAGE_PARAM_NAME): cv.string,
|
|
vol.Optional(CONF_METHOD, default=DEFAULT_METHOD):
|
|
vol.In(['POST', 'GET', 'POST_JSON']),
|
|
vol.Optional(CONF_HEADERS): vol.Schema({cv.string: cv.string}),
|
|
vol.Optional(CONF_NAME): cv.string,
|
|
vol.Optional(CONF_TARGET_PARAMETER_NAME): cv.string,
|
|
vol.Optional(CONF_TITLE_PARAMETER_NAME): cv.string,
|
|
vol.Optional(CONF_DATA): dict,
|
|
vol.Optional(CONF_DATA_TEMPLATE): {cv.match_all: cv.template_complex}
|
|
})
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
def get_service(hass, config, discovery_info=None):
|
|
"""Get the RESTful notification service."""
|
|
resource = config.get(CONF_RESOURCE)
|
|
method = config.get(CONF_METHOD)
|
|
headers = config.get(CONF_HEADERS)
|
|
message_param_name = config.get(CONF_MESSAGE_PARAMETER_NAME)
|
|
title_param_name = config.get(CONF_TITLE_PARAMETER_NAME)
|
|
target_param_name = config.get(CONF_TARGET_PARAMETER_NAME)
|
|
data = config.get(CONF_DATA)
|
|
data_template = config.get(CONF_DATA_TEMPLATE)
|
|
|
|
return RestNotificationService(
|
|
hass, resource, method, headers, message_param_name,
|
|
title_param_name, target_param_name, data, data_template)
|
|
|
|
|
|
class RestNotificationService(BaseNotificationService):
|
|
"""Implementation of a notification service for REST."""
|
|
|
|
def __init__(self, hass, resource, method, headers, message_param_name,
|
|
title_param_name, target_param_name, data, data_template):
|
|
"""Initialize the service."""
|
|
self._resource = resource
|
|
self._hass = hass
|
|
self._method = method.upper()
|
|
self._headers = headers
|
|
self._message_param_name = message_param_name
|
|
self._title_param_name = title_param_name
|
|
self._target_param_name = target_param_name
|
|
self._data = data
|
|
self._data_template = data_template
|
|
|
|
def send_message(self, message="", **kwargs):
|
|
"""Send a message to a user."""
|
|
data = {
|
|
self._message_param_name: message
|
|
}
|
|
|
|
if self._title_param_name is not None:
|
|
data[self._title_param_name] = kwargs.get(
|
|
ATTR_TITLE, ATTR_TITLE_DEFAULT)
|
|
|
|
if self._target_param_name is not None and ATTR_TARGET in kwargs:
|
|
# Target is a list as of 0.29 and we don't want to break existing
|
|
# integrations, so just return the first target in the list.
|
|
data[self._target_param_name] = kwargs[ATTR_TARGET][0]
|
|
|
|
if self._data:
|
|
data.update(self._data)
|
|
elif self._data_template:
|
|
def _data_template_creator(value):
|
|
"""Recursive template creator helper function."""
|
|
if isinstance(value, list):
|
|
return [_data_template_creator(item) for item in value]
|
|
if isinstance(value, dict):
|
|
return {key: _data_template_creator(item)
|
|
for key, item in value.items()}
|
|
value.hass = self._hass
|
|
return value.async_render(kwargs)
|
|
data.update(_data_template_creator(self._data_template))
|
|
|
|
if self._method == 'POST':
|
|
response = requests.post(self._resource, headers=self._headers,
|
|
data=data, timeout=10)
|
|
elif self._method == 'POST_JSON':
|
|
response = requests.post(self._resource, headers=self._headers,
|
|
json=data, timeout=10)
|
|
else: # default GET
|
|
response = requests.get(self._resource, headers=self._headers,
|
|
params=data, timeout=10)
|
|
|
|
success_codes = (200, 201, 202, 203, 204, 205, 206, 207, 208, 226)
|
|
if response.status_code not in success_codes:
|
|
_LOGGER.exception(
|
|
"Error sending message. Response %d: %s:",
|
|
response.status_code, response.reason)
|