Refactor Rest Binary sensor with ManualTriggerEntity (#97400)

* Refactor Rest Binary sensor w/ ManualTriggerEntity

* test availability

* review comments

* Use super

* Fix config
This commit is contained in:
G Johansson 2023-08-10 12:59:23 +02:00 committed by GitHub
parent 9b74321487
commit 4531dbbe62
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 65 additions and 13 deletions

View file

@ -14,6 +14,8 @@ from homeassistant.components.binary_sensor import (
from homeassistant.const import (
CONF_DEVICE_CLASS,
CONF_FORCE_UPDATE,
CONF_ICON,
CONF_NAME,
CONF_RESOURCE,
CONF_RESOURCE_TEMPLATE,
CONF_UNIQUE_ID,
@ -24,7 +26,11 @@ from homeassistant.exceptions import PlatformNotReady
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.template import Template
from homeassistant.helpers.template_entity import TemplateEntity
from homeassistant.helpers.template_entity import (
CONF_AVAILABILITY,
CONF_PICTURE,
ManualTriggerEntity,
)
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
@ -42,6 +48,14 @@ PLATFORM_SCHEMA = vol.All(
cv.has_at_least_one_key(CONF_RESOURCE, CONF_RESOURCE_TEMPLATE), PLATFORM_SCHEMA
)
TRIGGER_ENTITY_OPTIONS = (
CONF_AVAILABILITY,
CONF_DEVICE_CLASS,
CONF_ICON,
CONF_PICTURE,
CONF_UNIQUE_ID,
)
async def async_setup_platform(
hass: HomeAssistant,
@ -74,7 +88,14 @@ async def async_setup_platform(
raise PlatformNotReady from rest.last_exception
raise PlatformNotReady
unique_id = conf.get(CONF_UNIQUE_ID)
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]
async_add_entities(
[
@ -83,13 +104,13 @@ async def async_setup_platform(
coordinator,
rest,
conf,
unique_id,
trigger_entity_config,
)
],
)
class RestBinarySensor(RestEntity, TemplateEntity, BinarySensorEntity):
class RestBinarySensor(ManualTriggerEntity, RestEntity, BinarySensorEntity):
"""Representation of a REST binary sensor."""
def __init__(
@ -98,9 +119,10 @@ class RestBinarySensor(RestEntity, TemplateEntity, BinarySensorEntity):
coordinator: DataUpdateCoordinator[None] | None,
rest: RestData,
config: ConfigType,
unique_id: str | None,
trigger_entity_config: ConfigType,
) -> None:
"""Initialize a REST binary sensor."""
ManualTriggerEntity.__init__(self, hass, trigger_entity_config)
RestEntity.__init__(
self,
coordinator,
@ -108,19 +130,17 @@ class RestBinarySensor(RestEntity, TemplateEntity, BinarySensorEntity):
config.get(CONF_RESOURCE_TEMPLATE),
config[CONF_FORCE_UPDATE],
)
TemplateEntity.__init__(
self,
hass,
config=config,
fallback_name=DEFAULT_BINARY_SENSOR_NAME,
unique_id=unique_id,
)
self._previous_data = None
self._value_template: Template | None = config.get(CONF_VALUE_TEMPLATE)
if (value_template := self._value_template) is not None:
value_template.hass = hass
self._attr_device_class = config.get(CONF_DEVICE_CLASS)
@property
def available(self) -> bool:
"""Return if entity is available."""
available1 = RestEntity.available.fget(self) # type: ignore[attr-defined]
available2 = ManualTriggerEntity.available.fget(self) # type: ignore[attr-defined]
return bool(available1 and available2)
def _update_from_rest_data(self) -> None:
"""Update state from the rest data."""
@ -130,6 +150,8 @@ class RestBinarySensor(RestEntity, TemplateEntity, BinarySensorEntity):
response = self.rest.data
raw_value = response
if self._value_template is not None:
response = self._value_template.async_render_with_possible_json_value(
self.rest.data, False
@ -144,3 +166,6 @@ class RestBinarySensor(RestEntity, TemplateEntity, BinarySensorEntity):
"open": True,
"yes": True,
}.get(response.lower(), False)
self._process_manual_data(raw_value)
self.async_write_ha_state()

View file

@ -28,6 +28,7 @@ from homeassistant.const import (
)
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.template_entity import (
CONF_AVAILABILITY,
TEMPLATE_ENTITY_BASE_SCHEMA,
TEMPLATE_SENSOR_BASE_SCHEMA,
)
@ -82,6 +83,7 @@ BINARY_SENSOR_SCHEMA = {
vol.Optional(CONF_DEVICE_CLASS): BINARY_SENSOR_DEVICE_CLASSES_SCHEMA,
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_FORCE_UPDATE, default=DEFAULT_FORCE_UPDATE): cv.boolean,
vol.Optional(CONF_AVAILABILITY): cv.template,
}

View file

@ -564,6 +564,7 @@ class TriggerBaseEntity(Entity):
async def async_added_to_hass(self) -> None:
"""Handle being added to Home Assistant."""
await super().async_added_to_hass()
template_attach(self.hass, self._config)
def _set_unique_id(self, unique_id: str | None) -> None:

View file

@ -500,3 +500,27 @@ async def test_entity_config(hass: HomeAssistant) -> None:
"friendly_name": "REST Binary Sensor",
"icon": "mdi:one_two_three",
}
@respx.mock
async def test_availability_in_config(hass: HomeAssistant) -> None:
"""Test entity configuration."""
config = {
BINARY_SENSOR_DOMAIN: {
# REST configuration
"platform": DOMAIN,
"method": "GET",
"resource": "http://localhost",
# Entity configuration
"availability": "{{value==1}}",
"name": "{{'REST' + ' ' + 'Binary Sensor'}}",
},
}
respx.get("http://localhost") % HTTPStatus.OK
assert await async_setup_component(hass, BINARY_SENSOR_DOMAIN, config)
await hass.async_block_till_done()
state = hass.states.get("binary_sensor.rest_binary_sensor")
assert state.state == STATE_UNAVAILABLE