mirror of
https://github.com/home-assistant/core.git
synced 2025-07-18 18:57:06 +00:00
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
@ -64,8 +64,12 @@ STAT_CHANGE = "change"
|
|||||||
STAT_CHANGE_SAMPLE = "change_sample"
|
STAT_CHANGE_SAMPLE = "change_sample"
|
||||||
STAT_CHANGE_SECOND = "change_second"
|
STAT_CHANGE_SECOND = "change_second"
|
||||||
STAT_COUNT = "count"
|
STAT_COUNT = "count"
|
||||||
|
STAT_COUNT_BINARY_ON = "count_on"
|
||||||
|
STAT_COUNT_BINARY_OFF = "count_off"
|
||||||
STAT_DATETIME_NEWEST = "datetime_newest"
|
STAT_DATETIME_NEWEST = "datetime_newest"
|
||||||
STAT_DATETIME_OLDEST = "datetime_oldest"
|
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_95P = "distance_95_percent_of_values"
|
||||||
STAT_DISTANCE_99P = "distance_99_percent_of_values"
|
STAT_DISTANCE_99P = "distance_99_percent_of_values"
|
||||||
STAT_DISTANCE_ABSOLUTE = "distance_absolute"
|
STAT_DISTANCE_ABSOLUTE = "distance_absolute"
|
||||||
@ -99,6 +103,8 @@ STATS_NUMERIC_SUPPORT = {
|
|||||||
STAT_COUNT,
|
STAT_COUNT,
|
||||||
STAT_DATETIME_NEWEST,
|
STAT_DATETIME_NEWEST,
|
||||||
STAT_DATETIME_OLDEST,
|
STAT_DATETIME_OLDEST,
|
||||||
|
STAT_DATETIME_VALUE_MAX,
|
||||||
|
STAT_DATETIME_VALUE_MIN,
|
||||||
STAT_DISTANCE_95P,
|
STAT_DISTANCE_95P,
|
||||||
STAT_DISTANCE_99P,
|
STAT_DISTANCE_99P,
|
||||||
STAT_DISTANCE_ABSOLUTE,
|
STAT_DISTANCE_ABSOLUTE,
|
||||||
@ -118,18 +124,26 @@ STATS_BINARY_SUPPORT = {
|
|||||||
STAT_AVERAGE_STEP,
|
STAT_AVERAGE_STEP,
|
||||||
STAT_AVERAGE_TIMELESS,
|
STAT_AVERAGE_TIMELESS,
|
||||||
STAT_COUNT,
|
STAT_COUNT,
|
||||||
|
STAT_COUNT_BINARY_ON,
|
||||||
|
STAT_COUNT_BINARY_OFF,
|
||||||
|
STAT_DATETIME_NEWEST,
|
||||||
|
STAT_DATETIME_OLDEST,
|
||||||
STAT_MEAN,
|
STAT_MEAN,
|
||||||
}
|
}
|
||||||
|
|
||||||
STATS_NOT_A_NUMBER = {
|
STATS_NOT_A_NUMBER = {
|
||||||
STAT_DATETIME_NEWEST,
|
STAT_DATETIME_NEWEST,
|
||||||
STAT_DATETIME_OLDEST,
|
STAT_DATETIME_OLDEST,
|
||||||
|
STAT_DATETIME_VALUE_MAX,
|
||||||
|
STAT_DATETIME_VALUE_MIN,
|
||||||
STAT_QUANTILES,
|
STAT_QUANTILES,
|
||||||
}
|
}
|
||||||
|
|
||||||
STATS_DATETIME = {
|
STATS_DATETIME = {
|
||||||
STAT_DATETIME_NEWEST,
|
STAT_DATETIME_NEWEST,
|
||||||
STAT_DATETIME_OLDEST,
|
STAT_DATETIME_OLDEST,
|
||||||
|
STAT_DATETIME_VALUE_MAX,
|
||||||
|
STAT_DATETIME_VALUE_MIN,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Statistics which retain the unit of the source entity
|
# Statistics which retain the unit of the source entity
|
||||||
@ -351,7 +365,7 @@ class StatisticsSensor(SensorEntity):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
self.attributes[STAT_SOURCE_VALUE_VALID] = False
|
self.attributes[STAT_SOURCE_VALUE_VALID] = False
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"%s: parsing error, expected number and received %s",
|
"%s: parsing error. Expected number or binary state, but received '%s'",
|
||||||
self.entity_id,
|
self.entity_id,
|
||||||
new_state.state,
|
new_state.state,
|
||||||
)
|
)
|
||||||
@ -370,7 +384,11 @@ class StatisticsSensor(SensorEntity):
|
|||||||
unit = base_unit
|
unit = base_unit
|
||||||
elif self._state_characteristic in STATS_NOT_A_NUMBER:
|
elif self._state_characteristic in STATS_NOT_A_NUMBER:
|
||||||
unit = None
|
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
|
unit = None
|
||||||
elif self._state_characteristic == STAT_VARIANCE:
|
elif self._state_characteristic == STAT_VARIANCE:
|
||||||
unit = base_unit + "²"
|
unit = base_unit + "²"
|
||||||
@ -614,6 +632,16 @@ class StatisticsSensor(SensorEntity):
|
|||||||
return self.ages[0]
|
return self.ages[0]
|
||||||
return None
|
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:
|
def _stat_distance_95_percent_of_values(self) -> StateType:
|
||||||
if len(self.states) >= 2:
|
if len(self.states) >= 2:
|
||||||
return 2 * 1.96 * cast(float, self._stat_standard_deviation())
|
return 2 * 1.96 * cast(float, self._stat_standard_deviation())
|
||||||
@ -704,6 +732,18 @@ class StatisticsSensor(SensorEntity):
|
|||||||
def _stat_binary_count(self) -> StateType:
|
def _stat_binary_count(self) -> StateType:
|
||||||
return len(self.states)
|
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:
|
def _stat_binary_mean(self) -> StateType:
|
||||||
if len(self.states) > 0:
|
if len(self.states) > 0:
|
||||||
return 100.0 / len(self.states) * self.states.count(True)
|
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(),
|
"value_9": (start_datetime + timedelta(minutes=1)).isoformat(),
|
||||||
"unit": None,
|
"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",
|
"source_sensor_domain": "sensor",
|
||||||
"name": "distance_95_percent_of_values",
|
"name": "distance_95_percent_of_values",
|
||||||
@ -811,6 +827,38 @@ async def test_state_characteristics(hass: HomeAssistant):
|
|||||||
"value_9": len(VALUES_BINARY),
|
"value_9": len(VALUES_BINARY),
|
||||||
"unit": None,
|
"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",
|
"source_sensor_domain": "binary_sensor",
|
||||||
"name": "mean",
|
"name": "mean",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user