Add preview to Threshold config & option flow (#117181)

Co-authored-by: Erik Montnemery <erik@montnemery.com>
Co-authored-by: Franck Nijhof <git@frenck.dev>
This commit is contained in:
Jan-Philipp Benecke 2024-06-22 13:19:57 +02:00 committed by GitHub
parent 2b2c4e8262
commit 1c2aa9a49b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 351 additions and 9 deletions

View file

@ -2,6 +2,7 @@
from __future__ import annotations
from collections.abc import Callable, Mapping
import logging
from typing import Any
@ -22,7 +23,13 @@ from homeassistant.const import (
STATE_UNAVAILABLE,
STATE_UNKNOWN,
)
from homeassistant.core import Event, EventStateChangedData, HomeAssistant, callback
from homeassistant.core import (
CALLBACK_TYPE,
Event,
EventStateChangedData,
HomeAssistant,
callback,
)
from homeassistant.helpers import (
config_validation as cv,
device_registry as dr,
@ -111,7 +118,6 @@ async def async_setup_entry(
async_add_entities(
[
ThresholdSensor(
hass,
entity_id,
name,
lower,
@ -145,7 +151,7 @@ async def async_setup_platform(
async_add_entities(
[
ThresholdSensor(
hass, entity_id, name, lower, upper, hysteresis, device_class, None
entity_id, name, lower, upper, hysteresis, device_class, None
)
],
)
@ -167,7 +173,6 @@ class ThresholdSensor(BinarySensorEntity):
def __init__(
self,
hass: HomeAssistant,
entity_id: str,
name: str,
lower: float | None,
@ -178,6 +183,7 @@ class ThresholdSensor(BinarySensorEntity):
device_info: DeviceInfo | None = None,
) -> None:
"""Initialize the Threshold sensor."""
self._preview_callback: Callable[[str, Mapping[str, Any]], None] | None = None
self._attr_unique_id = unique_id
self._attr_device_info = device_info
self._entity_id = entity_id
@ -193,9 +199,17 @@ class ThresholdSensor(BinarySensorEntity):
self._state: bool | None = None
self.sensor_value: float | None = None
async def async_added_to_hass(self) -> None:
"""Run when entity about to be added to hass."""
self._async_setup_sensor()
@callback
def _async_setup_sensor(self) -> None:
"""Set up the sensor and start tracking state changes."""
def _update_sensor_state() -> None:
"""Handle sensor state changes."""
if (new_state := hass.states.get(self._entity_id)) is None:
if (new_state := self.hass.states.get(self._entity_id)) is None:
return
try:
@ -210,17 +224,26 @@ class ThresholdSensor(BinarySensorEntity):
self._update_state()
if self._preview_callback:
calculated_state = self._async_calculate_state()
self._preview_callback(
calculated_state.state, calculated_state.attributes
)
@callback
def async_threshold_sensor_state_listener(
event: Event[EventStateChangedData],
) -> None:
"""Handle sensor state changes."""
_update_sensor_state()
self.async_write_ha_state()
# only write state to the state machine if we are not in preview mode
if not self._preview_callback:
self.async_write_ha_state()
self.async_on_remove(
async_track_state_change_event(
hass, [entity_id], async_threshold_sensor_state_listener
self.hass, [self._entity_id], async_threshold_sensor_state_listener
)
)
_update_sensor_state()
@ -305,3 +328,26 @@ class ThresholdSensor(BinarySensorEntity):
self._state_position = POSITION_IN_RANGE
self._state = True
return
@callback
def async_start_preview(
self,
preview_callback: Callable[[str, Mapping[str, Any]], None],
) -> CALLBACK_TYPE:
"""Render a preview."""
# abort early if there is no entity_id
# as without we can't track changes
# or if neither lower nor upper thresholds are set
if not self._entity_id or (
not hasattr(self, "_threshold_lower")
and not hasattr(self, "_threshold_upper")
):
self._attr_available = False
calculated_state = self._async_calculate_state()
preview_callback(calculated_state.state, calculated_state.attributes)
return self._call_on_remove_callbacks
self._preview_callback = preview_callback
self._async_setup_sensor()
return self._call_on_remove_callbacks