parent
bfb5daa31c
commit
586471b5a9
2 changed files with 71 additions and 55 deletions
|
@ -114,6 +114,15 @@ async def async_setup_platform(
|
|||
)
|
||||
|
||||
|
||||
def _threshold_type(lower: float | None, upper: float | None) -> str:
|
||||
"""Return the type of threshold this sensor represents."""
|
||||
if lower is not None and upper is not None:
|
||||
return TYPE_RANGE
|
||||
if lower is not None:
|
||||
return TYPE_LOWER
|
||||
return TYPE_UPPER
|
||||
|
||||
|
||||
class ThresholdSensor(BinarySensorEntity):
|
||||
"""Representation of a Threshold sensor."""
|
||||
|
||||
|
@ -134,8 +143,11 @@ class ThresholdSensor(BinarySensorEntity):
|
|||
self._attr_unique_id = unique_id
|
||||
self._entity_id = entity_id
|
||||
self._name = name
|
||||
self._threshold_lower = lower
|
||||
self._threshold_upper = upper
|
||||
if lower is not None:
|
||||
self._threshold_lower = lower
|
||||
if upper is not None:
|
||||
self._threshold_upper = upper
|
||||
self.threshold_type = _threshold_type(lower, upper)
|
||||
self._hysteresis: float = hysteresis
|
||||
self._device_class = device_class
|
||||
self._state_position = POSITION_UNKNOWN
|
||||
|
@ -187,26 +199,17 @@ class ThresholdSensor(BinarySensorEntity):
|
|||
"""Return the sensor class of the sensor."""
|
||||
return self._device_class
|
||||
|
||||
@property
|
||||
def threshold_type(self) -> str:
|
||||
"""Return the type of threshold this sensor represents."""
|
||||
if self._threshold_lower is not None and self._threshold_upper is not None:
|
||||
return TYPE_RANGE
|
||||
if self._threshold_lower is not None:
|
||||
return TYPE_LOWER
|
||||
return TYPE_UPPER
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self) -> dict[str, Any]:
|
||||
"""Return the state attributes of the sensor."""
|
||||
return {
|
||||
ATTR_ENTITY_ID: self._entity_id,
|
||||
ATTR_HYSTERESIS: self._hysteresis,
|
||||
ATTR_LOWER: self._threshold_lower,
|
||||
ATTR_LOWER: getattr(self, "_threshold_lower", None),
|
||||
ATTR_POSITION: self._state_position,
|
||||
ATTR_SENSOR_VALUE: self.sensor_value,
|
||||
ATTR_TYPE: self.threshold_type,
|
||||
ATTR_UPPER: self._threshold_upper,
|
||||
ATTR_UPPER: getattr(self, "_threshold_upper", None),
|
||||
}
|
||||
|
||||
@callback
|
||||
|
@ -223,30 +226,42 @@ class ThresholdSensor(BinarySensorEntity):
|
|||
|
||||
if self.sensor_value is None:
|
||||
self._state_position = POSITION_UNKNOWN
|
||||
self._state = False
|
||||
self._state = None
|
||||
return
|
||||
|
||||
if self.threshold_type == TYPE_LOWER and self._threshold_lower is not None:
|
||||
if self.threshold_type == TYPE_LOWER:
|
||||
if self._state is None:
|
||||
self._state = False
|
||||
self._state_position = POSITION_ABOVE
|
||||
|
||||
if below(self.sensor_value, self._threshold_lower):
|
||||
self._state_position = POSITION_BELOW
|
||||
self._state = True
|
||||
elif above(self.sensor_value, self._threshold_lower):
|
||||
self._state_position = POSITION_ABOVE
|
||||
self._state = False
|
||||
return
|
||||
|
||||
if self.threshold_type == TYPE_UPPER:
|
||||
assert self._threshold_upper is not None
|
||||
|
||||
if self._state is None:
|
||||
self._state = False
|
||||
self._state_position = POSITION_BELOW
|
||||
|
||||
if self.threshold_type == TYPE_UPPER and self._threshold_upper is not None:
|
||||
if above(self.sensor_value, self._threshold_upper):
|
||||
self._state_position = POSITION_ABOVE
|
||||
self._state = True
|
||||
elif below(self.sensor_value, self._threshold_upper):
|
||||
self._state_position = POSITION_BELOW
|
||||
self._state = False
|
||||
return
|
||||
|
||||
if self.threshold_type == TYPE_RANGE:
|
||||
if self._state is None:
|
||||
self._state = True
|
||||
self._state_position = POSITION_IN_RANGE
|
||||
|
||||
if (
|
||||
self.threshold_type == TYPE_RANGE
|
||||
and self._threshold_lower is not None
|
||||
and self._threshold_upper is not None
|
||||
):
|
||||
if below(self.sensor_value, self._threshold_lower):
|
||||
self._state_position = POSITION_BELOW
|
||||
self._state = False
|
||||
|
@ -258,3 +273,4 @@ class ThresholdSensor(BinarySensorEntity):
|
|||
):
|
||||
self._state_position = POSITION_IN_RANGE
|
||||
self._state = True
|
||||
return
|
||||
|
|
|
@ -29,8 +29,8 @@ async def test_sensor_upper(hass: HomeAssistant) -> None:
|
|||
hass.states.async_set("sensor.test_monitored", 15)
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("binary_sensor.threshold")
|
||||
assert state.attributes["position"] == "unknown"
|
||||
assert state.state == "unknown"
|
||||
assert state.attributes["position"] == "below"
|
||||
assert state.state == "off"
|
||||
|
||||
hass.states.async_set(
|
||||
"sensor.test_monitored",
|
||||
|
@ -63,12 +63,12 @@ async def test_sensor_upper(hass: HomeAssistant) -> None:
|
|||
await hass.async_block_till_done()
|
||||
state = hass.states.get("binary_sensor.threshold")
|
||||
assert state.attributes["position"] == "unknown"
|
||||
assert state.state == "off"
|
||||
assert state.state == "unknown"
|
||||
|
||||
hass.states.async_set("sensor.test_monitored", 15)
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("binary_sensor.threshold")
|
||||
assert state.attributes["position"] == "unknown"
|
||||
assert state.attributes["position"] == "below"
|
||||
assert state.state == "off"
|
||||
|
||||
|
||||
|
@ -89,8 +89,8 @@ async def test_sensor_lower(hass: HomeAssistant) -> None:
|
|||
hass.states.async_set("sensor.test_monitored", 15)
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("binary_sensor.threshold")
|
||||
assert state.attributes["position"] == "unknown"
|
||||
assert state.state == "unknown"
|
||||
assert state.attributes["position"] == "above"
|
||||
assert state.state == "off"
|
||||
|
||||
hass.states.async_set("sensor.test_monitored", 16)
|
||||
await hass.async_block_till_done()
|
||||
|
@ -117,12 +117,12 @@ async def test_sensor_lower(hass: HomeAssistant) -> None:
|
|||
await hass.async_block_till_done()
|
||||
state = hass.states.get("binary_sensor.threshold")
|
||||
assert state.attributes["position"] == "unknown"
|
||||
assert state.state == "off"
|
||||
assert state.state == "unknown"
|
||||
|
||||
hass.states.async_set("sensor.test_monitored", 15)
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("binary_sensor.threshold")
|
||||
assert state.attributes["position"] == "unknown"
|
||||
assert state.attributes["position"] == "above"
|
||||
assert state.state == "off"
|
||||
|
||||
|
||||
|
@ -144,15 +144,15 @@ async def test_sensor_upper_hysteresis(hass: HomeAssistant) -> None:
|
|||
hass.states.async_set("sensor.test_monitored", 17.5)
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("binary_sensor.threshold")
|
||||
assert state.attributes["position"] == "unknown"
|
||||
assert state.state == "unknown"
|
||||
assert state.attributes["position"] == "below"
|
||||
assert state.state == "off"
|
||||
|
||||
# Set the monitored sensor's state to the threshold - hysteresis
|
||||
hass.states.async_set("sensor.test_monitored", 12.5)
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("binary_sensor.threshold")
|
||||
assert state.attributes["position"] == "unknown"
|
||||
assert state.state == "unknown"
|
||||
assert state.attributes["position"] == "below"
|
||||
assert state.state == "off"
|
||||
|
||||
hass.states.async_set("sensor.test_monitored", 20)
|
||||
await hass.async_block_till_done()
|
||||
|
@ -192,7 +192,7 @@ async def test_sensor_upper_hysteresis(hass: HomeAssistant) -> None:
|
|||
await hass.async_block_till_done()
|
||||
state = hass.states.get("binary_sensor.threshold")
|
||||
assert state.attributes["position"] == "unknown"
|
||||
assert state.state == "off"
|
||||
assert state.state == "unknown"
|
||||
|
||||
hass.states.async_set("sensor.test_monitored", 18)
|
||||
await hass.async_block_till_done()
|
||||
|
@ -219,15 +219,15 @@ async def test_sensor_lower_hysteresis(hass: HomeAssistant) -> None:
|
|||
hass.states.async_set("sensor.test_monitored", 17.5)
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("binary_sensor.threshold")
|
||||
assert state.attributes["position"] == "unknown"
|
||||
assert state.state == "unknown"
|
||||
assert state.attributes["position"] == "above"
|
||||
assert state.state == "off"
|
||||
|
||||
# Set the monitored sensor's state to the threshold - hysteresis
|
||||
hass.states.async_set("sensor.test_monitored", 12.5)
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("binary_sensor.threshold")
|
||||
assert state.attributes["position"] == "unknown"
|
||||
assert state.state == "unknown"
|
||||
assert state.attributes["position"] == "above"
|
||||
assert state.state == "off"
|
||||
|
||||
hass.states.async_set("sensor.test_monitored", 20)
|
||||
await hass.async_block_till_done()
|
||||
|
@ -267,7 +267,7 @@ async def test_sensor_lower_hysteresis(hass: HomeAssistant) -> None:
|
|||
await hass.async_block_till_done()
|
||||
state = hass.states.get("binary_sensor.threshold")
|
||||
assert state.attributes["position"] == "unknown"
|
||||
assert state.state == "off"
|
||||
assert state.state == "unknown"
|
||||
|
||||
hass.states.async_set("sensor.test_monitored", 18)
|
||||
await hass.async_block_till_done()
|
||||
|
@ -294,15 +294,15 @@ async def test_sensor_in_range_no_hysteresis(hass: HomeAssistant) -> None:
|
|||
hass.states.async_set("sensor.test_monitored", 10)
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("binary_sensor.threshold")
|
||||
assert state.attributes["position"] == "unknown"
|
||||
assert state.state == "unknown"
|
||||
assert state.attributes["position"] == "in_range"
|
||||
assert state.state == "on"
|
||||
|
||||
# Set the monitored sensor's state to the upper threshold
|
||||
hass.states.async_set("sensor.test_monitored", 20)
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("binary_sensor.threshold")
|
||||
assert state.attributes["position"] == "unknown"
|
||||
assert state.state == "unknown"
|
||||
assert state.attributes["position"] == "in_range"
|
||||
assert state.state == "on"
|
||||
|
||||
hass.states.async_set(
|
||||
"sensor.test_monitored",
|
||||
|
@ -336,7 +336,7 @@ async def test_sensor_in_range_no_hysteresis(hass: HomeAssistant) -> None:
|
|||
await hass.async_block_till_done()
|
||||
state = hass.states.get("binary_sensor.threshold")
|
||||
assert state.attributes["position"] == "unknown"
|
||||
assert state.state == "off"
|
||||
assert state.state == "unknown"
|
||||
|
||||
hass.states.async_set("sensor.test_monitored", 21)
|
||||
await hass.async_block_till_done()
|
||||
|
@ -364,29 +364,29 @@ async def test_sensor_in_range_with_hysteresis(hass: HomeAssistant) -> None:
|
|||
hass.states.async_set("sensor.test_monitored", 8)
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("binary_sensor.threshold")
|
||||
assert state.attributes["position"] == "unknown"
|
||||
assert state.state == "unknown"
|
||||
assert state.attributes["position"] == "in_range"
|
||||
assert state.state == "on"
|
||||
|
||||
# Set the monitored sensor's state to the lower threshold + hysteresis
|
||||
hass.states.async_set("sensor.test_monitored", 12)
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("binary_sensor.threshold")
|
||||
assert state.attributes["position"] == "unknown"
|
||||
assert state.state == "unknown"
|
||||
assert state.attributes["position"] == "in_range"
|
||||
assert state.state == "on"
|
||||
|
||||
# Set the monitored sensor's state to the upper threshold + hysteresis
|
||||
hass.states.async_set("sensor.test_monitored", 22)
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("binary_sensor.threshold")
|
||||
assert state.attributes["position"] == "unknown"
|
||||
assert state.state == "unknown"
|
||||
assert state.attributes["position"] == "in_range"
|
||||
assert state.state == "on"
|
||||
|
||||
# Set the monitored sensor's state to the upper threshold - hysteresis
|
||||
hass.states.async_set("sensor.test_monitored", 18)
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("binary_sensor.threshold")
|
||||
assert state.attributes["position"] == "unknown"
|
||||
assert state.state == "unknown"
|
||||
assert state.attributes["position"] == "in_range"
|
||||
assert state.state == "on"
|
||||
|
||||
hass.states.async_set(
|
||||
"sensor.test_monitored",
|
||||
|
@ -460,7 +460,7 @@ async def test_sensor_in_range_with_hysteresis(hass: HomeAssistant) -> None:
|
|||
await hass.async_block_till_done()
|
||||
state = hass.states.get("binary_sensor.threshold")
|
||||
assert state.attributes["position"] == "unknown"
|
||||
assert state.state == "off"
|
||||
assert state.state == "unknown"
|
||||
|
||||
hass.states.async_set("sensor.test_monitored", 17)
|
||||
await hass.async_block_till_done()
|
||||
|
@ -507,13 +507,13 @@ async def test_sensor_in_range_unknown_state(
|
|||
await hass.async_block_till_done()
|
||||
state = hass.states.get("binary_sensor.threshold")
|
||||
assert state.attributes["position"] == "unknown"
|
||||
assert state.state == "off"
|
||||
assert state.state == "unknown"
|
||||
|
||||
hass.states.async_set("sensor.test_monitored", STATE_UNAVAILABLE)
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("binary_sensor.threshold")
|
||||
assert state.attributes["position"] == "unknown"
|
||||
assert state.state == "off"
|
||||
assert state.state == "unknown"
|
||||
|
||||
assert "State is not numerical" not in caplog.text
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue