mirror of
https://github.com/home-assistant/core.git
synced 2025-07-13 08:17:08 +00:00
parent
cf681cd921
commit
635d8c01fb
@ -23,6 +23,7 @@ _STATISTIC_MEASURES = [
|
|||||||
selector.SelectOptionDict(value="median", label="Median"),
|
selector.SelectOptionDict(value="median", label="Median"),
|
||||||
selector.SelectOptionDict(value="last", label="Most recently updated"),
|
selector.SelectOptionDict(value="last", label="Most recently updated"),
|
||||||
selector.SelectOptionDict(value="range", label="Statistical range"),
|
selector.SelectOptionDict(value="range", label="Statistical range"),
|
||||||
|
selector.SelectOptionDict(value="sum", label="Sum"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -48,6 +48,7 @@ ATTR_MEDIAN = "median"
|
|||||||
ATTR_LAST = "last"
|
ATTR_LAST = "last"
|
||||||
ATTR_LAST_ENTITY_ID = "last_entity_id"
|
ATTR_LAST_ENTITY_ID = "last_entity_id"
|
||||||
ATTR_RANGE = "range"
|
ATTR_RANGE = "range"
|
||||||
|
ATTR_SUM = "sum"
|
||||||
|
|
||||||
ICON = "mdi:calculator"
|
ICON = "mdi:calculator"
|
||||||
|
|
||||||
@ -58,6 +59,7 @@ SENSOR_TYPES = {
|
|||||||
ATTR_MEDIAN: "median",
|
ATTR_MEDIAN: "median",
|
||||||
ATTR_LAST: "last",
|
ATTR_LAST: "last",
|
||||||
ATTR_RANGE: "range",
|
ATTR_RANGE: "range",
|
||||||
|
ATTR_SUM: "sum",
|
||||||
}
|
}
|
||||||
SENSOR_TYPE_TO_ATTR = {v: k for k, v in SENSOR_TYPES.items()}
|
SENSOR_TYPE_TO_ATTR = {v: k for k, v in SENSOR_TYPES.items()}
|
||||||
|
|
||||||
@ -188,6 +190,18 @@ def calc_range(sensor_values: list[tuple[str, Any]], round_digits: int) -> float
|
|||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def calc_sum(sensor_values: list[tuple[str, Any]], round_digits: int) -> float | None:
|
||||||
|
"""Calculate a sum of values, not honoring unknown states."""
|
||||||
|
result = 0
|
||||||
|
for _, sensor_value in sensor_values:
|
||||||
|
if sensor_value in [STATE_UNKNOWN, STATE_UNAVAILABLE]:
|
||||||
|
return None
|
||||||
|
result += sensor_value
|
||||||
|
|
||||||
|
value: float = round(result, round_digits)
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
class MinMaxSensor(SensorEntity):
|
class MinMaxSensor(SensorEntity):
|
||||||
"""Representation of a min/max sensor."""
|
"""Representation of a min/max sensor."""
|
||||||
|
|
||||||
@ -222,6 +236,7 @@ class MinMaxSensor(SensorEntity):
|
|||||||
self.last: float | None = None
|
self.last: float | None = None
|
||||||
self.median: float | None = None
|
self.median: float | None = None
|
||||||
self.range: float | None = None
|
self.range: float | None = None
|
||||||
|
self.sum: float | None = None
|
||||||
self.min_entity_id: str | None = None
|
self.min_entity_id: str | None = None
|
||||||
self.max_entity_id: str | None = None
|
self.max_entity_id: str | None = None
|
||||||
self.last_entity_id: str | None = None
|
self.last_entity_id: str | None = None
|
||||||
@ -336,3 +351,4 @@ class MinMaxSensor(SensorEntity):
|
|||||||
self.mean = calc_mean(sensor_values, self._round_digits)
|
self.mean = calc_mean(sensor_values, self._round_digits)
|
||||||
self.median = calc_median(sensor_values, self._round_digits)
|
self.median = calc_median(sensor_values, self._round_digits)
|
||||||
self.range = calc_range(sensor_values, self._round_digits)
|
self.range = calc_range(sensor_values, self._round_digits)
|
||||||
|
self.sum = calc_sum(sensor_values, self._round_digits)
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"title": "Min / max / mean / median sensor",
|
"title": "Combine the state of several sensors",
|
||||||
"config": {
|
"config": {
|
||||||
"step": {
|
"step": {
|
||||||
"user": {
|
"user": {
|
||||||
"title": "Add min / max / mean / median sensor",
|
"title": "Combine the state of several sensors",
|
||||||
"description": "Create a sensor that calculates a min, max, mean or median value from a list of input sensors.",
|
"description": "Create a sensor that calculates a min, max, mean, median or sum from a list of input sensors.",
|
||||||
"data": {
|
"data": {
|
||||||
"entity_ids": "Input entities",
|
"entity_ids": "Input entities",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
@ -12,7 +12,7 @@
|
|||||||
"type": "Statistic characteristic"
|
"type": "Statistic characteristic"
|
||||||
},
|
},
|
||||||
"data_description": {
|
"data_description": {
|
||||||
"round_digits": "Controls the number of decimal digits in the output when the statistics characteristic is mean or median."
|
"round_digits": "Controls the number of decimal digits in the output when the statistics characteristic is mean, median or sum."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,10 +9,10 @@
|
|||||||
"type": "Statistic characteristic"
|
"type": "Statistic characteristic"
|
||||||
},
|
},
|
||||||
"data_description": {
|
"data_description": {
|
||||||
"round_digits": "Controls the number of decimal digits in the output when the statistics characteristic is mean or median."
|
"round_digits": "Controls the number of decimal digits in the output when the statistics characteristic is mean, median or sum."
|
||||||
},
|
},
|
||||||
"description": "Create a sensor that calculates a min, max, mean or median value from a list of input sensors.",
|
"description": "Create a sensor that calculates a min, max, mean, median or sum from a list of input sensors.",
|
||||||
"title": "Add min / max / mean / median sensor"
|
"title": "Combine the state of several sensors"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -25,10 +25,10 @@
|
|||||||
"type": "Statistic characteristic"
|
"type": "Statistic characteristic"
|
||||||
},
|
},
|
||||||
"data_description": {
|
"data_description": {
|
||||||
"round_digits": "Controls the number of decimal digits in the output when the statistics characteristic is mean or median."
|
"round_digits": "Controls the number of decimal digits in the output when the statistics characteristic is mean, median or sum."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"title": "Min / max / mean / median sensor"
|
"title": "Combine the state of several sensors"
|
||||||
}
|
}
|
@ -33,6 +33,7 @@ MEAN_4_DIGITS = round(sum(VALUES) / COUNT, 4)
|
|||||||
MEDIAN = round(statistics.median(VALUES), 2)
|
MEDIAN = round(statistics.median(VALUES), 2)
|
||||||
RANGE_1_DIGIT = round(max(VALUES) - min(VALUES), 1)
|
RANGE_1_DIGIT = round(max(VALUES) - min(VALUES), 1)
|
||||||
RANGE_4_DIGITS = round(max(VALUES) - min(VALUES), 4)
|
RANGE_4_DIGITS = round(max(VALUES) - min(VALUES), 4)
|
||||||
|
SUM_VALUE = sum(VALUES)
|
||||||
|
|
||||||
|
|
||||||
async def test_default_name_sensor(hass: HomeAssistant) -> None:
|
async def test_default_name_sensor(hass: HomeAssistant) -> None:
|
||||||
@ -466,3 +467,60 @@ async def test_sensor_incorrect_state(
|
|||||||
|
|
||||||
assert state.state == "15.3"
|
assert state.state == "15.3"
|
||||||
assert "Unable to store state. Only numerical states are supported" in caplog.text
|
assert "Unable to store state. Only numerical states are supported" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
|
async def test_sum_sensor(hass: HomeAssistant) -> None:
|
||||||
|
"""Test the sum sensor."""
|
||||||
|
config = {
|
||||||
|
"sensor": {
|
||||||
|
"platform": "min_max",
|
||||||
|
"name": "test_sum",
|
||||||
|
"type": "sum",
|
||||||
|
"entity_ids": ["sensor.test_1", "sensor.test_2", "sensor.test_3"],
|
||||||
|
"unique_id": "very_unique_id_sum_sensor",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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_sum")
|
||||||
|
|
||||||
|
assert str(float(SUM_VALUE)) == state.state
|
||||||
|
assert state.attributes.get(ATTR_STATE_CLASS) == SensorStateClass.MEASUREMENT
|
||||||
|
|
||||||
|
entity_reg = er.async_get(hass)
|
||||||
|
entity = entity_reg.async_get("sensor.test_sum")
|
||||||
|
assert entity.unique_id == "very_unique_id_sum_sensor"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_sum_sensor_no_state(hass: HomeAssistant) -> None:
|
||||||
|
"""Test the sum sensor with no state ."""
|
||||||
|
config = {
|
||||||
|
"sensor": {
|
||||||
|
"platform": "min_max",
|
||||||
|
"name": "test_sum",
|
||||||
|
"type": "sum",
|
||||||
|
"entity_ids": ["sensor.test_1", "sensor.test_2", "sensor.test_3"],
|
||||||
|
"unique_id": "very_unique_id_sum_sensor",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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_ERROR)).items():
|
||||||
|
hass.states.async_set(entity_id, value)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.test_sum")
|
||||||
|
|
||||||
|
assert state.state == STATE_UNKNOWN
|
||||||
|
Loading…
x
Reference in New Issue
Block a user