Light significant changes + sensor tweaks (#45583)

This commit is contained in:
Paulus Schoutsen 2021-01-26 22:11:06 +01:00 committed by GitHub
parent 74efe78d0a
commit 352d0870e3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 179 additions and 15 deletions

View file

@ -0,0 +1,71 @@
"""Helper to test significant Light state changes."""
from typing import Any, Optional
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.significant_change import (
check_numeric_changed,
either_one_none,
)
from . import (
ATTR_BRIGHTNESS,
ATTR_COLOR_TEMP,
ATTR_EFFECT,
ATTR_HS_COLOR,
ATTR_WHITE_VALUE,
)
@callback
def async_check_significant_change(
hass: HomeAssistant,
old_state: str,
old_attrs: dict,
new_state: str,
new_attrs: dict,
**kwargs: Any,
) -> Optional[bool]:
"""Test if state significantly changed."""
if old_state != new_state:
return True
if old_attrs.get(ATTR_EFFECT) != new_attrs.get(ATTR_EFFECT):
return True
old_color = old_attrs.get(ATTR_HS_COLOR)
new_color = new_attrs.get(ATTR_HS_COLOR)
if either_one_none(old_color, new_color):
return True
if old_color and new_color:
# Range 0..360
if check_numeric_changed(old_color[0], new_color[0], 5):
return True
# Range 0..100
if check_numeric_changed(old_color[1], new_color[1], 3):
return True
if check_numeric_changed(
old_attrs.get(ATTR_BRIGHTNESS), new_attrs.get(ATTR_BRIGHTNESS), 3
):
return True
if check_numeric_changed(
# Default range 153..500
old_attrs.get(ATTR_COLOR_TEMP),
new_attrs.get(ATTR_COLOR_TEMP),
5,
):
return True
if check_numeric_changed(
# Range 0..255
old_attrs.get(ATTR_WHITE_VALUE),
new_attrs.get(ATTR_WHITE_VALUE),
5,
):
return True
return False

View file

@ -1,5 +1,5 @@
"""Helper to test significant sensor state changes.""" """Helper to test significant sensor state changes."""
from typing import Any, Optional from typing import Any, Optional, Union
from homeassistant.const import ( from homeassistant.const import (
ATTR_DEVICE_CLASS, ATTR_DEVICE_CLASS,
@ -28,18 +28,18 @@ def async_check_significant_change(
if device_class == DEVICE_CLASS_TEMPERATURE: if device_class == DEVICE_CLASS_TEMPERATURE:
if new_attrs.get(ATTR_UNIT_OF_MEASUREMENT) == TEMP_FAHRENHEIT: if new_attrs.get(ATTR_UNIT_OF_MEASUREMENT) == TEMP_FAHRENHEIT:
change = 0.03 change: Union[float, int] = 1
else: else:
change = 0.05 change = 0.5
old_value = float(old_state) old_value = float(old_state)
new_value = float(new_state) new_value = float(new_state)
return abs(1 - old_value / new_value) > change return abs(old_value - new_value) >= change
if device_class in (DEVICE_CLASS_BATTERY, DEVICE_CLASS_HUMIDITY): if device_class in (DEVICE_CLASS_BATTERY, DEVICE_CLASS_HUMIDITY):
old_value = float(old_state) old_value = float(old_state)
new_value = float(new_state) new_value = float(new_state)
return abs(old_value - new_value) > 2 return abs(old_value - new_value) >= 1
return None return None

View file

@ -73,6 +73,32 @@ async def _initialize(hass: HomeAssistant) -> None:
await async_process_integration_platforms(hass, PLATFORM, process_platform) await async_process_integration_platforms(hass, PLATFORM, process_platform)
def either_one_none(val1: Optional[Any], val2: Optional[Any]) -> bool:
"""Test if exactly one value is None."""
return (val1 is None and val2 is not None) or (val1 is not None and val2 is None)
def check_numeric_changed(
val1: Optional[Union[int, float]],
val2: Optional[Union[int, float]],
change: Union[int, float],
) -> bool:
"""Check if two numeric values have changed."""
if val1 is None and val2 is None:
return False
if either_one_none(val1, val2):
return True
assert val1 is not None
assert val2 is not None
if abs(val1 - val2) >= change:
return True
return False
class SignificantlyChangedChecker: class SignificantlyChangedChecker:
"""Class to keep track of entities to see if they have significantly changed. """Class to keep track of entities to see if they have significantly changed.

View file

@ -1,14 +1,11 @@
"""Test the sensor significant change platform.""" """Test the NEW_NAME significant change platform."""
from homeassistant.components.NEW_DOMAIN.significant_change import ( from homeassistant.components.NEW_DOMAIN.significant_change import (
async_check_significant_change, async_check_significant_change,
) )
from homeassistant.const import ATTR_DEVICE_CLASS
async def test_significant_change(): async def test_significant_change():
"""Detect NEW_NAME significant change.""" """Detect NEW_NAME significant changes."""
attrs = {ATTR_DEVICE_CLASS: "some_device_class"} attrs = {}
assert not async_check_significant_change(None, "on", attrs, "on", attrs) assert not async_check_significant_change(None, "on", attrs, "on", attrs)
assert async_check_significant_change(None, "on", attrs, "off", attrs) assert async_check_significant_change(None, "on", attrs, "off", attrs)

View file

@ -0,0 +1,70 @@
"""Test the Light significant change platform."""
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
ATTR_COLOR_TEMP,
ATTR_EFFECT,
ATTR_HS_COLOR,
ATTR_WHITE_VALUE,
)
from homeassistant.components.light.significant_change import (
async_check_significant_change,
)
async def test_significant_change():
"""Detect Light significant changes."""
assert not async_check_significant_change(None, "on", {}, "on", {})
assert async_check_significant_change(None, "on", {}, "off", {})
# Brightness
assert not async_check_significant_change(
None, "on", {ATTR_BRIGHTNESS: 60}, "on", {ATTR_BRIGHTNESS: 61}
)
assert async_check_significant_change(
None, "on", {ATTR_BRIGHTNESS: 60}, "on", {ATTR_BRIGHTNESS: 63}
)
# Color temp
assert not async_check_significant_change(
None, "on", {ATTR_COLOR_TEMP: 60}, "on", {ATTR_COLOR_TEMP: 64}
)
assert async_check_significant_change(
None, "on", {ATTR_COLOR_TEMP: 60}, "on", {ATTR_COLOR_TEMP: 65}
)
# White value
assert not async_check_significant_change(
None, "on", {ATTR_WHITE_VALUE: 60}, "on", {ATTR_WHITE_VALUE: 64}
)
assert async_check_significant_change(
None, "on", {ATTR_WHITE_VALUE: 60}, "on", {ATTR_WHITE_VALUE: 65}
)
# Effect
for eff1, eff2, expected in (
(None, None, False),
(None, "colorloop", True),
("colorloop", None, True),
("colorloop", "jump", True),
("colorloop", "colorloop", False),
):
result = async_check_significant_change(
None, "on", {ATTR_EFFECT: eff1}, "on", {ATTR_EFFECT: eff2}
)
assert result is expected
# Hue
assert not async_check_significant_change(
None, "on", {ATTR_HS_COLOR: [120, 20]}, "on", {ATTR_HS_COLOR: [124, 20]}
)
assert async_check_significant_change(
None, "on", {ATTR_HS_COLOR: [120, 20]}, "on", {ATTR_HS_COLOR: [125, 20]}
)
# Satursation
assert not async_check_significant_change(
None, "on", {ATTR_HS_COLOR: [120, 20]}, "on", {ATTR_HS_COLOR: [120, 22]}
)
assert async_check_significant_change(
None, "on", {ATTR_HS_COLOR: [120, 20]}, "on", {ATTR_HS_COLOR: [120, 23]}
)

View file

@ -34,10 +34,10 @@ async def test_significant_change_temperature():
ATTR_UNIT_OF_MEASUREMENT: TEMP_FAHRENHEIT, ATTR_UNIT_OF_MEASUREMENT: TEMP_FAHRENHEIT,
} }
assert async_check_significant_change( assert async_check_significant_change(
None, "70", freedom_attrs, "74", freedom_attrs None, "70", freedom_attrs, "71", freedom_attrs
) )
assert not async_check_significant_change( assert not async_check_significant_change(
None, "70", freedom_attrs, "71", freedom_attrs None, "70", freedom_attrs, "70.5", freedom_attrs
) )
@ -47,7 +47,7 @@ async def test_significant_change_battery():
ATTR_DEVICE_CLASS: DEVICE_CLASS_BATTERY, ATTR_DEVICE_CLASS: DEVICE_CLASS_BATTERY,
} }
assert not async_check_significant_change(None, "100", attrs, "100", attrs) assert not async_check_significant_change(None, "100", attrs, "100", attrs)
assert async_check_significant_change(None, "100", attrs, "97", attrs) assert async_check_significant_change(None, "100", attrs, "99", attrs)
async def test_significant_change_humidity(): async def test_significant_change_humidity():
@ -56,4 +56,4 @@ async def test_significant_change_humidity():
ATTR_DEVICE_CLASS: DEVICE_CLASS_HUMIDITY, ATTR_DEVICE_CLASS: DEVICE_CLASS_HUMIDITY,
} }
assert not async_check_significant_change(None, "100", attrs, "100", attrs) assert not async_check_significant_change(None, "100", attrs, "100", attrs)
assert async_check_significant_change(None, "100", attrs, "97", attrs) assert async_check_significant_change(None, "100", attrs, "99", attrs)