mirror of
https://github.com/home-assistant/core
synced 2024-09-15 17:29:45 +02:00
0e98bc5ea2
* 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
156 lines
5.0 KiB
Python
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
|