Add range to min_max (#78282)
This commit is contained in:
parent
bd01f90d42
commit
f26fadbdfc
3 changed files with 73 additions and 1 deletions
|
@ -22,6 +22,7 @@ _STATISTIC_MEASURES = [
|
|||
selector.SelectOptionDict(value="mean", label="Arithmetic mean"),
|
||||
selector.SelectOptionDict(value="median", label="Median"),
|
||||
selector.SelectOptionDict(value="last", label="Most recently updated"),
|
||||
selector.SelectOptionDict(value="range", label="Statistical range"),
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ ATTR_MEAN = "mean"
|
|||
ATTR_MEDIAN = "median"
|
||||
ATTR_LAST = "last"
|
||||
ATTR_LAST_ENTITY_ID = "last_entity_id"
|
||||
ATTR_RANGE = "range"
|
||||
|
||||
ICON = "mdi:calculator"
|
||||
|
||||
|
@ -48,6 +49,7 @@ SENSOR_TYPES = {
|
|||
ATTR_MEAN: "mean",
|
||||
ATTR_MEDIAN: "median",
|
||||
ATTR_LAST: "last",
|
||||
ATTR_RANGE: "range",
|
||||
}
|
||||
SENSOR_TYPE_TO_ATTR = {v: k for k, v in SENSOR_TYPES.items()}
|
||||
|
||||
|
@ -158,6 +160,19 @@ def calc_median(sensor_values, round_digits):
|
|||
return round(statistics.median(result), round_digits)
|
||||
|
||||
|
||||
def calc_range(sensor_values, round_digits):
|
||||
"""Calculate range value, honoring unknown states."""
|
||||
result = [
|
||||
sensor_value
|
||||
for _, sensor_value in sensor_values
|
||||
if sensor_value not in [STATE_UNKNOWN, STATE_UNAVAILABLE]
|
||||
]
|
||||
|
||||
if not result:
|
||||
return None
|
||||
return round(max(result) - min(result), round_digits)
|
||||
|
||||
|
||||
class MinMaxSensor(SensorEntity):
|
||||
"""Representation of a min/max sensor."""
|
||||
|
||||
|
@ -180,6 +195,7 @@ class MinMaxSensor(SensorEntity):
|
|||
self._unit_of_measurement = None
|
||||
self._unit_of_measurement_mismatch = False
|
||||
self.min_value = self.max_value = self.mean = self.last = self.median = None
|
||||
self.range = None
|
||||
self.min_entity_id = self.max_entity_id = self.last_entity_id = None
|
||||
self.count_sensors = len(self._entity_ids)
|
||||
self.states = {}
|
||||
|
@ -288,3 +304,4 @@ class MinMaxSensor(SensorEntity):
|
|||
self.max_entity_id, self.max_value = calc_max(sensor_values)
|
||||
self.mean = calc_mean(sensor_values, self._round_digits)
|
||||
self.median = calc_median(sensor_values, self._round_digits)
|
||||
self.range = calc_range(sensor_values, self._round_digits)
|
||||
|
|
|
@ -26,6 +26,8 @@ MEAN = round(sum(VALUES) / COUNT, 2)
|
|||
MEAN_1_DIGIT = round(sum(VALUES) / COUNT, 1)
|
||||
MEAN_4_DIGITS = round(sum(VALUES) / COUNT, 4)
|
||||
MEDIAN = round(statistics.median(VALUES), 2)
|
||||
RANGE_1_DIGIT = round(max(VALUES) - min(VALUES), 1)
|
||||
RANGE_4_DIGITS = round(max(VALUES) - min(VALUES), 4)
|
||||
|
||||
|
||||
async def test_default_name_sensor(hass):
|
||||
|
@ -160,7 +162,7 @@ async def test_mean_1_digit_sensor(hass):
|
|||
|
||||
|
||||
async def test_mean_4_digit_sensor(hass):
|
||||
"""Test the mean with 1-digit precision sensor."""
|
||||
"""Test the mean with 4-digit precision sensor."""
|
||||
config = {
|
||||
"sensor": {
|
||||
"platform": "min_max",
|
||||
|
@ -211,6 +213,58 @@ async def test_median_sensor(hass):
|
|||
assert state.attributes.get(ATTR_STATE_CLASS) == SensorStateClass.MEASUREMENT
|
||||
|
||||
|
||||
async def test_range_4_digit_sensor(hass):
|
||||
"""Test the range with 4-digit precision sensor."""
|
||||
config = {
|
||||
"sensor": {
|
||||
"platform": "min_max",
|
||||
"name": "test_range",
|
||||
"type": "range",
|
||||
"round_digits": 4,
|
||||
"entity_ids": ["sensor.test_1", "sensor.test_2", "sensor.test_3"],
|
||||
}
|
||||
}
|
||||
|
||||
assert await async_setup_component(hass, "sensor", config)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entity_ids = config["sensor"]["entity_ids"]
|
||||
|
||||
for entity_id, value in dict(zip(entity_ids, VALUES)).items():
|
||||
hass.states.async_set(entity_id, value)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("sensor.test_range")
|
||||
|
||||
assert str(float(RANGE_4_DIGITS)) == state.state
|
||||
|
||||
|
||||
async def test_range_1_digit_sensor(hass):
|
||||
"""Test the range with 1-digit precision sensor."""
|
||||
config = {
|
||||
"sensor": {
|
||||
"platform": "min_max",
|
||||
"name": "test_range",
|
||||
"type": "range",
|
||||
"round_digits": 1,
|
||||
"entity_ids": ["sensor.test_1", "sensor.test_2", "sensor.test_3"],
|
||||
}
|
||||
}
|
||||
|
||||
assert await async_setup_component(hass, "sensor", config)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entity_ids = config["sensor"]["entity_ids"]
|
||||
|
||||
for entity_id, value in dict(zip(entity_ids, VALUES)).items():
|
||||
hass.states.async_set(entity_id, value)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("sensor.test_range")
|
||||
|
||||
assert str(float(RANGE_1_DIGIT)) == state.state
|
||||
|
||||
|
||||
async def test_not_enough_sensor_value(hass):
|
||||
"""Test that there is nothing done if not enough values available."""
|
||||
config = {
|
||||
|
|
Loading…
Add table
Reference in a new issue