diff --git a/homeassistant/components/rest/binary_sensor.py b/homeassistant/components/rest/binary_sensor.py index 45ecabe60125..c6318ceb2814 100644 --- a/homeassistant/components/rest/binary_sensor.py +++ b/homeassistant/components/rest/binary_sensor.py @@ -1,7 +1,6 @@ """Support for RESTful binary sensors.""" import logging -import ssl from typing import override from xml.parsers.expat import ExpatError @@ -13,33 +12,28 @@ from homeassistant.components.binary_sensor import ( BinarySensorEntity, ) from homeassistant.const import ( - CONF_DEVICE_CLASS, CONF_FORCE_UPDATE, - CONF_ICON, - CONF_NAME, CONF_RESOURCE, CONF_RESOURCE_TEMPLATE, - CONF_UNIQUE_ID, CONF_VALUE_TEMPLATE, ) from homeassistant.core import HomeAssistant -from homeassistant.exceptions import PlatformNotReady from homeassistant.helpers import config_validation as cv from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.template import Template from homeassistant.helpers.trigger_template_entity import ( - CONF_AVAILABILITY, - CONF_PICTURE, ManualTriggerEntity, ValueTemplate, ) from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.update_coordinator import DataUpdateCoordinator -from . import async_get_config_and_coordinator, create_rest_data_from_config from .const import DEFAULT_BINARY_SENSOR_NAME from .data import RestData -from .entity import RestEntity +from .entity import ( + RestEntity, + async_get_config_rest_data_and_coordinator, + async_get_trigger_entity_config, +) from .schema import BINARY_SENSOR_SCHEMA, RESOURCE_SCHEMA _LOGGER = logging.getLogger(__name__) @@ -49,14 +43,6 @@ PLATFORM_SCHEMA = vol.All( cv.has_at_least_one_key(CONF_RESOURCE, CONF_RESOURCE_TEMPLATE), ) -TRIGGER_ENTITY_OPTIONS = ( - CONF_AVAILABILITY, - CONF_DEVICE_CLASS, - CONF_ICON, - CONF_PICTURE, - CONF_UNIQUE_ID, -) - async def async_setup_platform( hass: HomeAssistant, @@ -65,38 +51,13 @@ async def async_setup_platform( discovery_info: DiscoveryInfoType | None = None, ) -> None: """Set up the REST binary sensor.""" - # Must update the sensor now (including fetching the rest resource) to - # ensure it's updating its state. - if discovery_info is not None: - conf, coordinator, rest = await async_get_config_and_coordinator( - hass, BINARY_SENSOR_DOMAIN, discovery_info - ) - else: - conf = config - coordinator = None - rest = create_rest_data_from_config(hass, conf) - await rest.async_update(log_errors=False) - if rest.data is None: - if rest.last_exception: - if isinstance(rest.last_exception, ssl.SSLError): - _LOGGER.error( - "Error connecting %s failed with %s", - rest.url, - rest.last_exception, - ) - return - raise PlatformNotReady from rest.last_exception - raise PlatformNotReady - - name = conf.get(CONF_NAME) or Template(DEFAULT_BINARY_SENSOR_NAME, hass) - - trigger_entity_config = {CONF_NAME: name} - - for key in TRIGGER_ENTITY_OPTIONS: - if key not in conf: - continue - trigger_entity_config[key] = conf[key] + conf, rest, coordinator = await async_get_config_rest_data_and_coordinator( + hass, config, BINARY_SENSOR_DOMAIN, discovery_info + ) + trigger_entity_config = async_get_trigger_entity_config( + hass, conf, DEFAULT_BINARY_SENSOR_NAME + ) async_add_entities( [ diff --git a/homeassistant/components/rest/entity.py b/homeassistant/components/rest/entity.py index b7389a67273b..8a7f5112cc37 100644 --- a/homeassistant/components/rest/entity.py +++ b/homeassistant/components/rest/entity.py @@ -1,22 +1,102 @@ """The base entity for the rest component.""" from abc import abstractmethod -from typing import Any, override +import logging +import ssl +from typing import override -from homeassistant.core import callback +from homeassistant.components.sensor import CONF_STATE_CLASS +from homeassistant.const import ( + CONF_DEVICE_CLASS, + CONF_ICON, + CONF_NAME, + CONF_UNIQUE_ID, + CONF_UNIT_OF_MEASUREMENT, +) +from homeassistant.core import HomeAssistant, callback +from homeassistant.exceptions import HomeAssistantError, PlatformNotReady from homeassistant.helpers.entity import Entity from homeassistant.helpers.template import Template +from homeassistant.helpers.trigger_template_entity import ( + CONF_AVAILABILITY, + CONF_PICTURE, +) +from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.update_coordinator import DataUpdateCoordinator +from . import async_get_config_and_coordinator, create_rest_data_from_config from .data import RestData +TRIGGER_ENTITY_OPTIONS = ( + CONF_AVAILABILITY, + CONF_DEVICE_CLASS, + CONF_ICON, + CONF_PICTURE, + CONF_UNIQUE_ID, + CONF_STATE_CLASS, + CONF_UNIT_OF_MEASUREMENT, +) + +_LOGGER = logging.getLogger(__name__) + + +async def async_get_config_rest_data_and_coordinator( + hass: HomeAssistant, + config: ConfigType, + entity_domain: str, + discovery_info: DiscoveryInfoType | None = None, +) -> tuple[ConfigType, RestData, DataUpdateCoordinator[None] | None]: + """Get the config, rest data +/- coordinator for sub entity.""" + # Must update the sensor now (including fetching the rest resource) to + # ensure it's updating its state. + if discovery_info is not None: + conf, coordinator, rest = await async_get_config_and_coordinator( + hass, entity_domain, discovery_info + ) + else: + conf = config + coordinator = None + rest = create_rest_data_from_config(hass, conf) + await rest.async_update(log_errors=False) + + if rest.data is None: + if rest.last_exception: + if isinstance(rest.last_exception, ssl.SSLError): + _LOGGER.error( + "Error connecting %s failed with %s", + rest.url, + rest.last_exception, + ) + raise HomeAssistantError from rest.last_exception + raise PlatformNotReady from rest.last_exception + raise PlatformNotReady + + return conf, rest, coordinator + + +def async_get_trigger_entity_config( + hass: HomeAssistant, + config: ConfigType, + default_name: str, +) -> ConfigType: + """Get trigger entity config.""" + + trigger_entity_config = { + CONF_NAME: config.get(CONF_NAME, Template(default_name, hass)) + } + for key in TRIGGER_ENTITY_OPTIONS: + if key not in config: + continue + trigger_entity_config[key] = config[key] + return trigger_entity_config + class RestEntity(Entity): """A class for entities using DataUpdateCoordinator or rest data directly.""" def __init__( self, - coordinator: DataUpdateCoordinator[Any] | None, + coordinator: DataUpdateCoordinator[None] | None, rest: RestData, resource_template: Template | None, force_update: bool, diff --git a/homeassistant/components/rest/sensor.py b/homeassistant/components/rest/sensor.py index e4ee56b28668..08df21466e8b 100644 --- a/homeassistant/components/rest/sensor.py +++ b/homeassistant/components/rest/sensor.py @@ -1,46 +1,38 @@ """Support for RESTful API sensors.""" import logging -import ssl from typing import Any, override from xml.parsers.expat import ExpatError import voluptuous as vol from homeassistant.components.sensor import ( - CONF_STATE_CLASS, DOMAIN as SENSOR_DOMAIN, PLATFORM_SCHEMA as SENSOR_PLATFORM_SCHEMA, ) from homeassistant.const import ( - CONF_DEVICE_CLASS, CONF_FORCE_UPDATE, - CONF_ICON, - CONF_NAME, CONF_RESOURCE, CONF_RESOURCE_TEMPLATE, - CONF_UNIQUE_ID, - CONF_UNIT_OF_MEASUREMENT, CONF_VALUE_TEMPLATE, ) from homeassistant.core import HomeAssistant -from homeassistant.exceptions import PlatformNotReady from homeassistant.helpers import config_validation as cv from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.template import Template from homeassistant.helpers.trigger_template_entity import ( - CONF_AVAILABILITY, - CONF_PICTURE, ManualTriggerSensorEntity, ValueTemplate, ) from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.update_coordinator import DataUpdateCoordinator -from . import async_get_config_and_coordinator, create_rest_data_from_config from .const import CONF_JSON_ATTRS, CONF_JSON_ATTRS_PATH, DEFAULT_SENSOR_NAME from .data import RestData -from .entity import RestEntity +from .entity import ( + RestEntity, + async_get_config_rest_data_and_coordinator, + async_get_trigger_entity_config, +) from .schema import RESOURCE_SCHEMA, SENSOR_SCHEMA from .util import parse_json_attributes @@ -51,16 +43,6 @@ PLATFORM_SCHEMA = vol.All( cv.has_at_least_one_key(CONF_RESOURCE, CONF_RESOURCE_TEMPLATE), ) -TRIGGER_ENTITY_OPTIONS = ( - CONF_AVAILABILITY, - CONF_DEVICE_CLASS, - CONF_ICON, - CONF_PICTURE, - CONF_UNIQUE_ID, - CONF_STATE_CLASS, - CONF_UNIT_OF_MEASUREMENT, -) - async def async_setup_platform( hass: HomeAssistant, @@ -69,39 +51,12 @@ async def async_setup_platform( discovery_info: DiscoveryInfoType | None = None, ) -> None: """Set up the RESTful sensor.""" - # Must update the sensor now (including fetching the rest resource) to - # ensure it's updating its state. - if discovery_info is not None: - conf, coordinator, rest = await async_get_config_and_coordinator( - hass, SENSOR_DOMAIN, discovery_info - ) - else: - conf = config - coordinator = None - rest = create_rest_data_from_config(hass, conf) - await rest.async_update(log_errors=False) - - if rest.data is None: - if rest.last_exception: - if isinstance(rest.last_exception, ssl.SSLError): - _LOGGER.error( - "Error connecting %s failed with %s", - rest.url, - rest.last_exception, - ) - return - raise PlatformNotReady from rest.last_exception - raise PlatformNotReady - - name = conf.get(CONF_NAME) or Template(DEFAULT_SENSOR_NAME, hass) - - trigger_entity_config = {CONF_NAME: name} - - for key in TRIGGER_ENTITY_OPTIONS: - if key not in conf: - continue - trigger_entity_config[key] = conf[key] - + conf, rest, coordinator = await async_get_config_rest_data_and_coordinator( + hass, config, SENSOR_DOMAIN, discovery_info + ) + trigger_entity_config = async_get_trigger_entity_config( + hass, conf, DEFAULT_SENSOR_NAME + ) async_add_entities( [ RestSensor(