mirror of
https://github.com/home-assistant/core.git
synced 2025-07-12 15:57:06 +00:00
Do not return cached values for entity states in emulated_hue (#87642)
* Do not return cached values for state and brightness * Move building the uncached state dict behind a lru_cache (_build_entity_state_dict) --------- Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
2e541e7ef6
commit
354d77d26b
@ -634,17 +634,38 @@ def get_entity_state_dict(config: Config, entity: State) -> dict[str, Any]:
|
|||||||
# Remove the now stale cached entry.
|
# Remove the now stale cached entry.
|
||||||
config.cached_states.pop(entity.entity_id)
|
config.cached_states.pop(entity.entity_id)
|
||||||
|
|
||||||
|
if cached_state is None:
|
||||||
|
return _build_entity_state_dict(entity)
|
||||||
|
|
||||||
|
data: dict[str, Any] = cached_state
|
||||||
|
# Make sure brightness is valid
|
||||||
|
if data[STATE_BRIGHTNESS] is None:
|
||||||
|
data[STATE_BRIGHTNESS] = HUE_API_STATE_BRI_MAX if data[STATE_ON] else 0
|
||||||
|
|
||||||
|
# Make sure hue/saturation are valid
|
||||||
|
if (data[STATE_HUE] is None) or (data[STATE_SATURATION] is None):
|
||||||
|
data[STATE_HUE] = 0
|
||||||
|
data[STATE_SATURATION] = 0
|
||||||
|
|
||||||
|
# If the light is off, set the color to off
|
||||||
|
if data[STATE_BRIGHTNESS] == 0:
|
||||||
|
data[STATE_HUE] = 0
|
||||||
|
data[STATE_SATURATION] = 0
|
||||||
|
|
||||||
|
_clamp_values(data)
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache(maxsize=512)
|
||||||
|
def _build_entity_state_dict(entity: State) -> dict[str, Any]:
|
||||||
|
"""Build a state dict for an entity."""
|
||||||
data: dict[str, Any] = {
|
data: dict[str, Any] = {
|
||||||
STATE_ON: False,
|
STATE_ON: entity.state != STATE_OFF,
|
||||||
STATE_BRIGHTNESS: None,
|
STATE_BRIGHTNESS: None,
|
||||||
STATE_HUE: None,
|
STATE_HUE: None,
|
||||||
STATE_SATURATION: None,
|
STATE_SATURATION: None,
|
||||||
STATE_COLOR_TEMP: None,
|
STATE_COLOR_TEMP: None,
|
||||||
}
|
}
|
||||||
|
|
||||||
if cached_state is None:
|
|
||||||
data[STATE_ON] = entity.state != STATE_OFF
|
|
||||||
|
|
||||||
if data[STATE_ON]:
|
if data[STATE_ON]:
|
||||||
data[STATE_BRIGHTNESS] = hass_to_hue_brightness(
|
data[STATE_BRIGHTNESS] = hass_to_hue_brightness(
|
||||||
entity.attributes.get(ATTR_BRIGHTNESS, 0)
|
entity.attributes.get(ATTR_BRIGHTNESS, 0)
|
||||||
@ -688,23 +709,12 @@ def get_entity_state_dict(config: Config, entity: State) -> dict[str, Any]:
|
|||||||
elif entity.domain == cover.DOMAIN:
|
elif entity.domain == cover.DOMAIN:
|
||||||
level = entity.attributes.get(ATTR_CURRENT_POSITION, 0)
|
level = entity.attributes.get(ATTR_CURRENT_POSITION, 0)
|
||||||
data[STATE_BRIGHTNESS] = round(level / 100 * HUE_API_STATE_BRI_MAX)
|
data[STATE_BRIGHTNESS] = round(level / 100 * HUE_API_STATE_BRI_MAX)
|
||||||
else:
|
_clamp_values(data)
|
||||||
data = cached_state
|
return data
|
||||||
# Make sure brightness is valid
|
|
||||||
if data[STATE_BRIGHTNESS] is None:
|
|
||||||
data[STATE_BRIGHTNESS] = HUE_API_STATE_BRI_MAX if data[STATE_ON] else 0
|
|
||||||
|
|
||||||
# Make sure hue/saturation are valid
|
|
||||||
if (data[STATE_HUE] is None) or (data[STATE_SATURATION] is None):
|
|
||||||
data[STATE_HUE] = 0
|
|
||||||
data[STATE_SATURATION] = 0
|
|
||||||
|
|
||||||
# If the light is off, set the color to off
|
def _clamp_values(data: dict[str, Any]) -> None:
|
||||||
if data[STATE_BRIGHTNESS] == 0:
|
"""Clamp brightness, hue, saturation, and color temp to valid values."""
|
||||||
data[STATE_HUE] = 0
|
|
||||||
data[STATE_SATURATION] = 0
|
|
||||||
|
|
||||||
# Clamp brightness, hue, saturation, and color temp to valid values
|
|
||||||
for key, v_min, v_max in (
|
for key, v_min, v_max in (
|
||||||
(STATE_BRIGHTNESS, HUE_API_STATE_BRI_MIN, HUE_API_STATE_BRI_MAX),
|
(STATE_BRIGHTNESS, HUE_API_STATE_BRI_MIN, HUE_API_STATE_BRI_MAX),
|
||||||
(STATE_HUE, HUE_API_STATE_HUE_MIN, HUE_API_STATE_HUE_MAX),
|
(STATE_HUE, HUE_API_STATE_HUE_MIN, HUE_API_STATE_HUE_MAX),
|
||||||
@ -714,8 +724,6 @@ def get_entity_state_dict(config: Config, entity: State) -> dict[str, Any]:
|
|||||||
if data[key] is not None:
|
if data[key] is not None:
|
||||||
data[key] = max(v_min, min(data[key], v_max))
|
data[key] = max(v_min, min(data[key], v_max))
|
||||||
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
@lru_cache(maxsize=1024)
|
@lru_cache(maxsize=1024)
|
||||||
def _entity_unique_id(entity_id: str) -> str:
|
def _entity_unique_id(entity_id: str) -> str:
|
||||||
@ -843,10 +851,18 @@ def create_config_model(config: Config, request: web.Request) -> dict[str, Any]:
|
|||||||
|
|
||||||
def create_list_of_entities(config: Config, request: web.Request) -> dict[str, Any]:
|
def create_list_of_entities(config: Config, request: web.Request) -> dict[str, Any]:
|
||||||
"""Create a list of all entities."""
|
"""Create a list of all entities."""
|
||||||
json_response: dict[str, Any] = {
|
hass: core.HomeAssistant = request.app["hass"]
|
||||||
config.entity_id_to_number(state.entity_id): state_to_json(config, state)
|
|
||||||
for state in config.get_exposed_states()
|
json_response: dict[str, Any] = {}
|
||||||
}
|
for cached_state in config.get_exposed_states():
|
||||||
|
entity_id = cached_state.entity_id
|
||||||
|
state = hass.states.get(entity_id)
|
||||||
|
assert state is not None
|
||||||
|
|
||||||
|
json_response[config.entity_id_to_number(entity_id)] = state_to_json(
|
||||||
|
config, state
|
||||||
|
)
|
||||||
|
|
||||||
return json_response
|
return json_response
|
||||||
|
|
||||||
|
|
||||||
|
@ -301,6 +301,7 @@ async def test_discover_lights(hass, hue_client):
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
result_json = await async_get_lights(hue_client)
|
result_json = await async_get_lights(hue_client)
|
||||||
|
assert "1" not in result_json.keys()
|
||||||
devices = {val["uniqueid"] for val in result_json.values()}
|
devices = {val["uniqueid"] for val in result_json.values()}
|
||||||
assert "00:2f:d2:31:ce:c5:55:cc-ee" not in devices # light.ceiling_lights
|
assert "00:2f:d2:31:ce:c5:55:cc-ee" not in devices # light.ceiling_lights
|
||||||
|
|
||||||
@ -308,8 +309,16 @@ async def test_discover_lights(hass, hue_client):
|
|||||||
hass.states.async_set("light.ceiling_lights", STATE_ON)
|
hass.states.async_set("light.ceiling_lights", STATE_ON)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
result_json = await async_get_lights(hue_client)
|
result_json = await async_get_lights(hue_client)
|
||||||
devices = {val["uniqueid"] for val in result_json.values()}
|
device = result_json["1"] # Test that light ID did not change
|
||||||
assert "00:2f:d2:31:ce:c5:55:cc-ee" in devices # light.ceiling_lights
|
assert device["uniqueid"] == "00:2f:d2:31:ce:c5:55:cc-ee" # light.ceiling_lights
|
||||||
|
assert device["state"][HUE_API_STATE_ON] is True
|
||||||
|
|
||||||
|
# Test that returned value is fresh and not cached
|
||||||
|
hass.states.async_set("light.ceiling_lights", STATE_OFF)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
result_json = await async_get_lights(hue_client)
|
||||||
|
device = result_json["1"]
|
||||||
|
assert device["state"][HUE_API_STATE_ON] is False
|
||||||
|
|
||||||
|
|
||||||
async def test_light_without_brightness_supported(hass_hue, hue_client):
|
async def test_light_without_brightness_supported(hass_hue, hue_client):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user