Rest: Move common platform setup code into entity.py (#179868)

Co-authored-by: G Johansson <goran.johansson@shiftit.se>
This commit is contained in:
iluvdata
2026-08-31 13:51:08 +02:00
committed by GitHub
co-authored by G Johansson
parent a3a841a8a2
commit 68b5fcb902
3 changed files with 105 additions and 109 deletions
+11 -50
View File
@@ -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(
[
+83 -3
View File
@@ -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,
+11 -56
View File
@@ -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(