1 """The rest component."""
3 from __future__
import annotations
6 from collections.abc
import Coroutine
8 from datetime
import timedelta
10 from typing
import Any
13 import voluptuous
as vol
25 CONF_RESOURCE_TEMPLATE,
30 HTTP_DIGEST_AUTHENTICATION,
39 async_integration_yaml_config,
40 async_reload_integration_platforms,
48 CONF_PAYLOAD_TEMPLATE,
51 DEFAULT_SSL_CIPHER_LIST,
58 from .data
import RestData
59 from .schema
import CONFIG_SCHEMA, RESOURCE_SCHEMA
61 _LOGGER = logging.getLogger(__name__)
64 Platform.BINARY_SENSOR,
70 COORDINATOR_AWARE_PLATFORMS = [SENSOR_DOMAIN, BINARY_SENSOR_DOMAIN]
73 async
def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
74 """Set up the rest platforms."""
77 async
def reload_service_handler(service: ServiceCall) ->
None:
78 """Remove all user-defined groups and load new ones from config."""
80 with contextlib.suppress(HomeAssistantError):
88 hass.services.async_register(
89 DOMAIN, SERVICE_RELOAD, reload_service_handler, schema=vol.Schema({})
97 """Create shared data for platform config and rest coordinators."""
98 hass.data[DOMAIN] = {key: []
for key
in (REST_DATA, *COORDINATOR_AWARE_PLATFORMS)}
102 """Process rest configuration."""
103 if DOMAIN
not in config:
106 refresh_coroutines: list[Coroutine[Any, Any,
None]] = []
107 load_coroutines: list[Coroutine[Any, Any,
None]] = []
108 rest_config: list[ConfigType] = config[DOMAIN]
109 for rest_idx, conf
in enumerate(rest_config):
110 scan_interval: timedelta = conf.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL)
111 resource_template: template.Template |
None = conf.get(CONF_RESOURCE_TEMPLATE)
112 payload_template: template.Template |
None = conf.get(CONF_PAYLOAD_TEMPLATE)
115 hass, rest, resource_template, payload_template, scan_interval
117 refresh_coroutines.append(coordinator.async_refresh())
118 hass.data[DOMAIN][REST_DATA].append({REST: rest, COORDINATOR: coordinator})
120 for platform_domain
in COORDINATOR_AWARE_PLATFORMS:
121 if platform_domain
not in conf:
124 for platform_conf
in conf[platform_domain]:
125 hass.data[DOMAIN][platform_domain].append(platform_conf)
126 platform_idx = len(hass.data[DOMAIN][platform_domain]) - 1
128 load_coroutine = discovery.async_load_platform(
132 {REST_IDX: rest_idx, PLATFORM_IDX: platform_idx},
135 load_coroutines.append(load_coroutine)
137 if refresh_coroutines:
138 await asyncio.gather(*(create_eager_task(coro)
for coro
in refresh_coroutines))
141 await asyncio.gather(*(create_eager_task(coro)
for coro
in load_coroutines))
147 hass: HomeAssistant, platform_domain: str, discovery_info: DiscoveryInfoType
148 ) -> tuple[ConfigType, DataUpdateCoordinator[
None], RestData]:
149 """Get the config and coordinator for the platform from discovery."""
150 shared_data = hass.data[DOMAIN][REST_DATA][discovery_info[REST_IDX]]
151 conf: ConfigType = hass.data[DOMAIN][platform_domain][discovery_info[PLATFORM_IDX]]
152 coordinator: DataUpdateCoordinator[
None] = shared_data[COORDINATOR]
153 rest: RestData = shared_data[REST]
154 if rest.data
is None:
155 await coordinator.async_request_refresh()
156 return conf, coordinator, rest
162 resource_template: template.Template |
None,
163 payload_template: template.Template |
None,
164 update_interval: timedelta,
165 ) -> DataUpdateCoordinator[
None]:
166 """Wrap a DataUpdateCoordinator around the rest object."""
167 if resource_template
or payload_template:
169 async
def _async_refresh_with_templates() -> None:
170 if resource_template:
171 rest.set_url(resource_template.async_render(parse_result=
False))
173 rest.set_payload(payload_template.async_render(parse_result=
False))
174 await rest.async_update()
176 update_method = _async_refresh_with_templates
178 update_method = rest.async_update
185 update_method=update_method,
186 update_interval=update_interval,
191 """Create RestData from config."""
192 resource: str |
None = config.get(CONF_RESOURCE)
193 resource_template: template.Template |
None = config.get(CONF_RESOURCE_TEMPLATE)
194 method: str = config[CONF_METHOD]
195 payload: str |
None = config.get(CONF_PAYLOAD)
196 payload_template: template.Template |
None = config.get(CONF_PAYLOAD_TEMPLATE)
197 verify_ssl: bool = config[CONF_VERIFY_SSL]
198 ssl_cipher_list: str = config.get(CONF_SSL_CIPHER_LIST, DEFAULT_SSL_CIPHER_LIST)
199 username: str |
None = config.get(CONF_USERNAME)
200 password: str |
None = config.get(CONF_PASSWORD)
201 headers: dict[str, str] |
None = config.get(CONF_HEADERS)
202 params: dict[str, str] |
None = config.get(CONF_PARAMS)
203 timeout: int = config[CONF_TIMEOUT]
204 encoding: str = config[CONF_ENCODING]
205 if resource_template
is not None:
206 resource = resource_template.async_render(parse_result=
False)
208 if payload_template
is not None:
209 payload = payload_template.async_render(parse_result=
False)
214 auth: httpx.DigestAuth | tuple[str, str] |
None =
None
215 if username
and password:
216 if config.get(CONF_AUTHENTICATION) == HTTP_DIGEST_AUTHENTICATION:
217 auth = httpx.DigestAuth(username, password)
219 auth = (username, password)
bool _async_process_config(HomeAssistant hass, ConfigType config)
RestData create_rest_data_from_config(HomeAssistant hass, ConfigType config)
None _async_setup_shared_data(HomeAssistant hass)
bool async_setup(HomeAssistant hass, ConfigType config)
tuple[ConfigType, DataUpdateCoordinator[None], RestData] async_get_config_and_coordinator(HomeAssistant hass, str platform_domain, DiscoveryInfoType discovery_info)
DataUpdateCoordinator[None] _rest_coordinator(HomeAssistant hass, RestData rest, template.Template|None resource_template, template.Template|None payload_template, timedelta update_interval)
None async_reload_integration_platforms(HomeAssistant hass, str integration_domain, Iterable[str] platform_domains)
ConfigType|None async_integration_yaml_config(HomeAssistant hass, str integration_name)