Add additional characteristics to the statistics integration (#62631)
* Improve config checking, add device_class timestamp * Improve warning message
This commit is contained in:
parent
1df99badcf
commit
f2d6a06a6a
2 changed files with 90 additions and 2 deletions
|
@ -64,8 +64,12 @@ STAT_CHANGE = "change"
|
|||
STAT_CHANGE_SAMPLE = "change_sample"
|
||||
STAT_CHANGE_SECOND = "change_second"
|
||||
STAT_COUNT = "count"
|
||||
STAT_COUNT_BINARY_ON = "count_on"
|
||||
STAT_COUNT_BINARY_OFF = "count_off"
|
||||
STAT_DATETIME_NEWEST = "datetime_newest"
|
||||
STAT_DATETIME_OLDEST = "datetime_oldest"
|
||||
STAT_DATETIME_VALUE_MAX = "datetime_value_max"
|
||||
STAT_DATETIME_VALUE_MIN = "datetime_value_min"
|
||||
STAT_DISTANCE_95P = "distance_95_percent_of_values"
|
||||
STAT_DISTANCE_99P = "distance_99_percent_of_values"
|
||||
STAT_DISTANCE_ABSOLUTE = "distance_absolute"
|
||||
|
@ -99,6 +103,8 @@ STATS_NUMERIC_SUPPORT = {
|
|||
STAT_COUNT,
|
||||
STAT_DATETIME_NEWEST,
|
||||
STAT_DATETIME_OLDEST,
|
||||
STAT_DATETIME_VALUE_MAX,
|
||||
STAT_DATETIME_VALUE_MIN,
|
||||
STAT_DISTANCE_95P,
|
||||
STAT_DISTANCE_99P,
|
||||
STAT_DISTANCE_ABSOLUTE,
|
||||
|
@ -118,18 +124,26 @@ STATS_BINARY_SUPPORT = {
|
|||
STAT_AVERAGE_STEP,
|
||||
STAT_AVERAGE_TIMELESS,
|
||||
STAT_COUNT,
|
||||
STAT_COUNT_BINARY_ON,
|
||||
STAT_COUNT_BINARY_OFF,
|
||||
STAT_DATETIME_NEWEST,
|
||||
STAT_DATETIME_OLDEST,
|
||||
STAT_MEAN,
|
||||
}
|
||||
|
||||
STATS_NOT_A_NUMBER = {
|
||||
STAT_DATETIME_NEWEST,
|
||||
STAT_DATETIME_OLDEST,
|
||||
STAT_DATETIME_VALUE_MAX,
|
||||
STAT_DATETIME_VALUE_MIN,
|
||||
STAT_QUANTILES,
|
||||
}
|
||||
|
||||
STATS_DATETIME = {
|
||||
STAT_DATETIME_NEWEST,
|
||||
STAT_DATETIME_OLDEST,
|
||||
STAT_DATETIME_VALUE_MAX,
|
||||
STAT_DATETIME_VALUE_MIN,
|
||||
}
|
||||
|
||||
# Statistics which retain the unit of the source entity
|
||||
|
@ -351,7 +365,7 @@ class StatisticsSensor(SensorEntity):
|
|||
except ValueError:
|
||||
self.attributes[STAT_SOURCE_VALUE_VALID] = False
|
||||
_LOGGER.error(
|
||||
"%s: parsing error, expected number and received %s",
|
||||
"%s: parsing error. Expected number or binary state, but received '%s'",
|
||||
self.entity_id,
|
||||
new_state.state,
|
||||
)
|
||||
|
@ -370,7 +384,11 @@ class StatisticsSensor(SensorEntity):
|
|||
unit = base_unit
|
||||
elif self._state_characteristic in STATS_NOT_A_NUMBER:
|
||||
unit = None
|
||||
elif self._state_characteristic == STAT_COUNT:
|
||||
elif self._state_characteristic in (
|
||||
STAT_COUNT,
|
||||
STAT_COUNT_BINARY_ON,
|
||||
STAT_COUNT_BINARY_OFF,
|
||||
):
|
||||
unit = None
|
||||
elif self._state_characteristic == STAT_VARIANCE:
|
||||
unit = base_unit + "²"
|
||||
|
@ -614,6 +632,16 @@ class StatisticsSensor(SensorEntity):
|
|||
return self.ages[0]
|
||||
return None
|
||||
|
||||
def _stat_datetime_value_max(self) -> datetime | None:
|
||||
if len(self.states) > 0:
|
||||
return self.ages[self.states.index(max(self.states))]
|
||||
return None
|
||||
|
||||
def _stat_datetime_value_min(self) -> datetime | None:
|
||||
if len(self.states) > 0:
|
||||
return self.ages[self.states.index(min(self.states))]
|
||||
return None
|
||||
|
||||
def _stat_distance_95_percent_of_values(self) -> StateType:
|
||||
if len(self.states) >= 2:
|
||||
return 2 * 1.96 * cast(float, self._stat_standard_deviation())
|
||||
|
@ -704,6 +732,18 @@ class StatisticsSensor(SensorEntity):
|
|||
def _stat_binary_count(self) -> StateType:
|
||||
return len(self.states)
|
||||
|
||||
def _stat_binary_count_on(self) -> StateType:
|
||||
return self.states.count(True)
|
||||
|
||||
def _stat_binary_count_off(self) -> StateType:
|
||||
return self.states.count(False)
|
||||
|
||||
def _stat_binary_datetime_newest(self) -> datetime | None:
|
||||
return self._stat_datetime_newest()
|
||||
|
||||
def _stat_binary_datetime_oldest(self) -> datetime | None:
|
||||
return self._stat_datetime_oldest()
|
||||
|
||||
def _stat_binary_mean(self) -> StateType:
|
||||
if len(self.states) > 0:
|
||||
return 100.0 / len(self.states) * self.states.count(True)
|
||||
|
|
|
@ -687,6 +687,22 @@ async def test_state_characteristics(hass: HomeAssistant):
|
|||
"value_9": (start_datetime + timedelta(minutes=1)).isoformat(),
|
||||
"unit": None,
|
||||
},
|
||||
{
|
||||
"source_sensor_domain": "sensor",
|
||||
"name": "datetime_value_max",
|
||||
"value_0": STATE_UNKNOWN,
|
||||
"value_1": (start_datetime + timedelta(minutes=9)).isoformat(),
|
||||
"value_9": (start_datetime + timedelta(minutes=2)).isoformat(),
|
||||
"unit": None,
|
||||
},
|
||||
{
|
||||
"source_sensor_domain": "sensor",
|
||||
"name": "datetime_value_min",
|
||||
"value_0": STATE_UNKNOWN,
|
||||
"value_1": (start_datetime + timedelta(minutes=9)).isoformat(),
|
||||
"value_9": (start_datetime + timedelta(minutes=5)).isoformat(),
|
||||
"unit": None,
|
||||
},
|
||||
{
|
||||
"source_sensor_domain": "sensor",
|
||||
"name": "distance_95_percent_of_values",
|
||||
|
@ -811,6 +827,38 @@ async def test_state_characteristics(hass: HomeAssistant):
|
|||
"value_9": len(VALUES_BINARY),
|
||||
"unit": None,
|
||||
},
|
||||
{
|
||||
"source_sensor_domain": "binary_sensor",
|
||||
"name": "count_on",
|
||||
"value_0": 0,
|
||||
"value_1": 1,
|
||||
"value_9": VALUES_BINARY.count("on"),
|
||||
"unit": None,
|
||||
},
|
||||
{
|
||||
"source_sensor_domain": "binary_sensor",
|
||||
"name": "count_off",
|
||||
"value_0": 0,
|
||||
"value_1": 0,
|
||||
"value_9": VALUES_BINARY.count("off"),
|
||||
"unit": None,
|
||||
},
|
||||
{
|
||||
"source_sensor_domain": "binary_sensor",
|
||||
"name": "datetime_newest",
|
||||
"value_0": STATE_UNKNOWN,
|
||||
"value_1": (start_datetime + timedelta(minutes=9)).isoformat(),
|
||||
"value_9": (start_datetime + timedelta(minutes=9)).isoformat(),
|
||||
"unit": None,
|
||||
},
|
||||
{
|
||||
"source_sensor_domain": "binary_sensor",
|
||||
"name": "datetime_oldest",
|
||||
"value_0": STATE_UNKNOWN,
|
||||
"value_1": (start_datetime + timedelta(minutes=9)).isoformat(),
|
||||
"value_9": (start_datetime + timedelta(minutes=1)).isoformat(),
|
||||
"unit": None,
|
||||
},
|
||||
{
|
||||
"source_sensor_domain": "binary_sensor",
|
||||
"name": "mean",
|
||||
|
|
Loading…
Add table
Reference in a new issue