1
mirror of https://github.com/home-assistant/core synced 2024-09-15 17:29:45 +02:00
ha-core/homeassistant/components/rest_command/__init__.py
Franck Nijhof 0e98bc5ea2
Skip template result parsing in several places (#42408)
* Skip template result parsing in several places

* Adjust alert integration

* Adjust Alexa integration

* Adjust apns integration

* Adjust arest integration

* Adjust dialogflow integration

* Adjust generic camera integration

* Adjust imap email content  integration

* Adjust InfluxDB integration

* Adjust intent integration

* Adjust logbook integration

* Adjust HP ILO integration

* Adjust manual alarm control panel integration

* Adjust manual mqtt alarm control panel integration

* Adjust minio integration

* Adjust mqtt integration

* Adjust notify integration

* Adjust persistent notification integration

* Adjust rest integration

* Adjust rss feed template integration

* Adjust slack integration

* Adjust Xiaomi integration

* Adjust TCP integration

* Adjust Telegram Bot integration

* Bump CI cache version

* Revert "Bump CI cache version"

This reverts commit 875efe58cf.

* Adjust demo tests
2020-10-26 19:29:10 +01:00

156 lines
5.0 KiB
Python

"""Support for exposing regular REST commands as services."""
import asyncio
import logging
import aiohttp
from aiohttp import hdrs
import voluptuous as vol
from homeassistant.const import (
CONF_HEADERS,
CONF_METHOD,
CONF_PASSWORD,
CONF_PAYLOAD,
CONF_TIMEOUT,
CONF_URL,
CONF_USERNAME,
CONF_VERIFY_SSL,
HTTP_BAD_REQUEST,
)
from homeassistant.core import callback
from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv
DOMAIN = "rest_command"
_LOGGER = logging.getLogger(__name__)
DEFAULT_TIMEOUT = 10
DEFAULT_METHOD = "get"
DEFAULT_VERIFY_SSL = True
SUPPORT_REST_METHODS = ["get", "patch", "post", "put", "delete"]
CONF_CONTENT_TYPE = "content_type"
COMMAND_SCHEMA = vol.Schema(
{
vol.Required(CONF_URL): cv.template,
vol.Optional(CONF_METHOD, default=DEFAULT_METHOD): vol.All(
vol.Lower, vol.In(SUPPORT_REST_METHODS)
),
vol.Optional(CONF_HEADERS): vol.Schema({cv.string: cv.template}),
vol.Inclusive(CONF_USERNAME, "authentication"): cv.string,
vol.Inclusive(CONF_PASSWORD, "authentication"): cv.string,
vol.Optional(CONF_PAYLOAD): cv.template,
vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): vol.Coerce(int),
vol.Optional(CONF_CONTENT_TYPE): cv.string,
vol.Optional(CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL): cv.boolean,
}
)
CONFIG_SCHEMA = vol.Schema(
{DOMAIN: cv.schema_with_slug_keys(COMMAND_SCHEMA)}, extra=vol.ALLOW_EXTRA
)
async def async_setup(hass, config):
"""Set up the REST command component."""
@callback
def async_register_rest_command(name, command_config):
"""Create service for rest command."""
websession = async_get_clientsession(hass, command_config.get(CONF_VERIFY_SSL))
timeout = command_config[CONF_TIMEOUT]
method = command_config[CONF_METHOD]
template_url = command_config[CONF_URL]
template_url.hass = hass
auth = None
if CONF_USERNAME in command_config:
username = command_config[CONF_USERNAME]
password = command_config.get(CONF_PASSWORD, "")
auth = aiohttp.BasicAuth(username, password=password)
template_payload = None
if CONF_PAYLOAD in command_config:
template_payload = command_config[CONF_PAYLOAD]
template_payload.hass = hass
template_headers = None
if CONF_HEADERS in command_config:
template_headers = command_config[CONF_HEADERS]
for template_header in template_headers.values():
template_header.hass = hass
content_type = None
if CONF_CONTENT_TYPE in command_config:
content_type = command_config[CONF_CONTENT_TYPE]
async def async_service_handler(service):
"""Execute a shell command service."""
payload = None
if template_payload:
payload = bytes(
template_payload.async_render(
variables=service.data, parse_result=False
),
"utf-8",
)
request_url = template_url.async_render(
variables=service.data, parse_result=False
)
headers = None
if template_headers:
headers = {}
for header_name, template_header in template_headers.items():
headers[header_name] = template_header.async_render(
variables=service.data, parse_result=False
)
if content_type:
if headers is None:
headers = {}
headers[hdrs.CONTENT_TYPE] = content_type
try:
async with getattr(websession, method)(
request_url,
data=payload,
auth=auth,
headers=headers,
timeout=timeout,
) as response:
if response.status < HTTP_BAD_REQUEST:
_LOGGER.debug(
"Success. Url: %s. Status code: %d. Payload: %s",
response.url,
response.status,
payload,
)
else:
_LOGGER.warning(
"Error. Url: %s. Status code %d. Payload: %s",
response.url,
response.status,
payload,
)
except asyncio.TimeoutError:
_LOGGER.warning("Timeout call %s", request_url)
except aiohttp.ClientError:
_LOGGER.error("Client error %s", request_url)
# register services
hass.services.async_register(DOMAIN, name, async_service_handler)
for command, command_config in config[DOMAIN].items():
async_register_rest_command(command, command_config)
return True