Add brightness_pct beside brightness in the LLM live context (#182571)

This commit is contained in:
jdavidbush
2026-09-19 10:57:05 +02:00
committed by GitHub
parent 2809e5fdf2
commit a72ca7b2d7
2 changed files with 51 additions and 0 deletions
@@ -7,6 +7,7 @@ from typing import Any, override
import probatio
from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN
from homeassistant.components.llm import LLMTools
from homeassistant.components.sensor import (
DOMAIN as SENSOR_DOMAIN,
@@ -172,6 +173,14 @@ def async_get_exposed_entities(
if attr_name in interesting_attributes
}
):
# Tools take brightness as a 0-100 percentage; the attribute is 0-255.
if state.domain == LIGHT_DOMAIN and isinstance(
brightness := state.attributes.get("brightness"), int
):
pct = round(brightness / 255 * 100)
attributes["brightness_pct"] = str(
max(pct, 1) if brightness > 0 else pct
)
info["attributes"] = attributes
entities[state.entity_id] = info
@@ -412,3 +412,45 @@ async def test_get_live_context_schema(
schema = to_openapi(tool.parameters, custom_serializer=api.custom_serializer)
assert schema == snapshot
async def test_get_exposed_entities_brightness_percentage(hass: HomeAssistant) -> None:
"""Test that a light's brightness is also rendered as a percentage."""
hass.states.async_set(
ENTITY_ID, "on", {"friendly_name": "Kitchen Light", "brightness": 128}
)
async_expose_entity(hass, "conversation", ENTITY_ID, True)
exposed = async_get_exposed_entities(hass, "conversation", include_state=True)
attributes = exposed[ENTITY_ID]["attributes"]
# The raw attribute is unchanged, so anything reading it keeps working.
assert attributes["brightness"] == "128"
# The percentage is the inverse of the percentage-to-brightness conversion.
assert attributes["brightness_pct"] == "50"
hass.states.async_set(
ENTITY_ID, "on", {"friendly_name": "Kitchen Light", "brightness": 255}
)
exposed = async_get_exposed_entities(hass, "conversation", include_state=True)
assert exposed[ENTITY_ID]["attributes"]["brightness_pct"] == "100"
# A lit light never rounds down to nothing.
hass.states.async_set(
ENTITY_ID, "on", {"friendly_name": "Kitchen Light", "brightness": 1}
)
exposed = async_get_exposed_entities(hass, "conversation", include_state=True)
assert exposed[ENTITY_ID]["attributes"]["brightness_pct"] == "1"
hass.states.async_set(ENTITY_ID, "off", {"friendly_name": "Kitchen Light"})
exposed = async_get_exposed_entities(hass, "conversation", include_state=True)
assert "brightness_pct" not in exposed[ENTITY_ID].get("attributes", {})
# Only lights get the percentage, whatever attribute another domain carries.
hass.states.async_set(
"fan.kitchen", "on", {"friendly_name": "Kitchen Fan", "brightness": 128}
)
async_expose_entity(hass, "conversation", "fan.kitchen", True)
exposed = async_get_exposed_entities(hass, "conversation", include_state=True)
assert exposed["fan.kitchen"]["attributes"]["brightness"] == "128"
assert "brightness_pct" not in exposed["fan.kitchen"]["attributes"]