Fix statistics precision handling (#59202)
* Fix statistics precision error when configured 0, fix #42547 * Add tests for statistics precision * Apply precision=0 logic to float numbers only * Implement contextlib way of exception handling
This commit is contained in:
parent
2924f4605b
commit
9eaf8bd21b
2 changed files with 79 additions and 5 deletions
|
@ -1,5 +1,6 @@
|
|||
"""Support for statistics for sensor values."""
|
||||
from collections import deque
|
||||
import contextlib
|
||||
import logging
|
||||
import statistics
|
||||
|
||||
|
@ -203,7 +204,12 @@ class StatisticsSensor(SensorEntity):
|
|||
@property
|
||||
def native_value(self):
|
||||
"""Return the state of the sensor."""
|
||||
return self.mean if not self.is_binary else self.count
|
||||
if self.is_binary:
|
||||
return self.count
|
||||
if self._precision == 0:
|
||||
with contextlib.suppress(TypeError, ValueError):
|
||||
return int(self.mean)
|
||||
return self.mean
|
||||
|
||||
@property
|
||||
def native_unit_of_measurement(self):
|
||||
|
|
|
@ -103,7 +103,9 @@ class TestStatisticsSensor(unittest.TestCase):
|
|||
|
||||
for value in self.values:
|
||||
self.hass.states.set(
|
||||
"sensor.test_monitored", value, {ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS}
|
||||
"sensor.test_monitored",
|
||||
value,
|
||||
{ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -163,7 +165,9 @@ class TestStatisticsSensor(unittest.TestCase):
|
|||
|
||||
for value in self.values:
|
||||
self.hass.states.set(
|
||||
"sensor.test_monitored", value, {ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS}
|
||||
"sensor.test_monitored",
|
||||
value,
|
||||
{ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -193,7 +197,9 @@ class TestStatisticsSensor(unittest.TestCase):
|
|||
|
||||
for value in self.values[-3:]: # just the last 3 will do
|
||||
self.hass.states.set(
|
||||
"sensor.test_monitored", value, {ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS}
|
||||
"sensor.test_monitored",
|
||||
value,
|
||||
{ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -363,6 +369,66 @@ class TestStatisticsSensor(unittest.TestCase):
|
|||
) == state.attributes.get("max_age")
|
||||
assert self.change_rate == state.attributes.get("change_rate")
|
||||
|
||||
def test_precision_0(self):
|
||||
"""Test correct result with precision=0 as integer."""
|
||||
assert setup_component(
|
||||
self.hass,
|
||||
"sensor",
|
||||
{
|
||||
"sensor": {
|
||||
"platform": "statistics",
|
||||
"name": "test",
|
||||
"entity_id": "sensor.test_monitored",
|
||||
"precision": 0,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
self.hass.block_till_done()
|
||||
self.hass.start()
|
||||
self.hass.block_till_done()
|
||||
|
||||
for value in self.values:
|
||||
self.hass.states.set(
|
||||
"sensor.test_monitored",
|
||||
value,
|
||||
{ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get("sensor.test")
|
||||
assert state.state == str(int(state.attributes.get("mean")))
|
||||
|
||||
def test_precision_1(self):
|
||||
"""Test correct result with precision=1 rounded to one decimal."""
|
||||
assert setup_component(
|
||||
self.hass,
|
||||
"sensor",
|
||||
{
|
||||
"sensor": {
|
||||
"platform": "statistics",
|
||||
"name": "test",
|
||||
"entity_id": "sensor.test_monitored",
|
||||
"precision": 1,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
self.hass.block_till_done()
|
||||
self.hass.start()
|
||||
self.hass.block_till_done()
|
||||
|
||||
for value in self.values:
|
||||
self.hass.states.set(
|
||||
"sensor.test_monitored",
|
||||
value,
|
||||
{ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get("sensor.test")
|
||||
assert state.state == str(round(sum(self.values) / len(self.values), 1))
|
||||
|
||||
def test_initialize_from_database(self):
|
||||
"""Test initializing the statistics from the database."""
|
||||
# enable the recorder
|
||||
|
@ -372,7 +438,9 @@ class TestStatisticsSensor(unittest.TestCase):
|
|||
# store some values
|
||||
for value in self.values:
|
||||
self.hass.states.set(
|
||||
"sensor.test_monitored", value, {ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS}
|
||||
"sensor.test_monitored",
|
||||
value,
|
||||
{ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
# wait for the recorder to really store the data
|
||||
|
|
Loading…
Add table
Reference in a new issue