fix(light): kein Farbtemperaturmodus ohne echten Bereich
Das Montana-Black-Shield (neues Ziel ledshield_rgb in der Firmware) steuert analoge RGB-Streifen und hat keinen eigenen Weisskanal. Sein Board meldet deshalb ct_min == ct_max (nl_board.c: 4000/4000) - die Konvention der Firmware fuer "weiss entsteht als RGB-Mischung". supported_color_modes bot COLOR_TEMP bisher IMMER an. Beim Shield bekaeme Home Assistant damit einen Farbtemperaturregler, dessen Grenzen zusammenfallen. Jetzt entscheidet der gemeldete Bereich: nur wenn oben > unten, gibt es COLOR_TEMP. Dieselbe Regel benutzt ninlight_core schon (device_state.dart, hasColorTemp), dort faellt der Regler beim Shield von selbst weg. Die Menge darf nie leer werden - HA verlangt mindestens einen Modus -, deshalb faellt sie im Grenzfall auf BRIGHTNESS zurueck: ein Geraet ohne Farbe und ohne Bereich kann immer noch dimmen.
This commit is contained in:
@@ -68,11 +68,30 @@ class NinlightLight(NinlightEntity, LightEntity):
|
|||||||
def brightness(self) -> int:
|
def brightness(self) -> int:
|
||||||
return lamp_to_ha_brightness(int(self._state["brightness"]))
|
return lamp_to_ha_brightness(int(self._state["brightness"]))
|
||||||
|
|
||||||
|
def _has_ct_range(self) -> bool:
|
||||||
|
"""Ob das Geraet einen echten Farbtemperaturbereich hat.
|
||||||
|
|
||||||
|
Das Montana-Black-Shield steuert analoge RGB-Streifen ohne eigenen
|
||||||
|
Weisskanal und meldet deshalb ct_min == ct_max (nl_board.c,
|
||||||
|
"ledshield_rgb": 4000/4000) - die Konvention der Firmware fuer "weiss
|
||||||
|
entsteht als RGB-Mischung". Ein Bereich ohne Spielraum ist keiner;
|
||||||
|
wuerde er hier als COLOR_TEMP durchgehen, bekaeme Home Assistant einen
|
||||||
|
Regler mit min == max.
|
||||||
|
"""
|
||||||
|
unten, oben = self._kelvin_range()
|
||||||
|
return oben > unten
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def supported_color_modes(self) -> set[ColorMode]:
|
def supported_color_modes(self) -> set[ColorMode]:
|
||||||
if self._state["capabilities"].get("color"):
|
farbe = bool(self._state["capabilities"].get("color"))
|
||||||
return {ColorMode.RGB, ColorMode.COLOR_TEMP}
|
modi: set[ColorMode] = set()
|
||||||
return {ColorMode.COLOR_TEMP}
|
if farbe:
|
||||||
|
modi.add(ColorMode.RGB)
|
||||||
|
if self._has_ct_range():
|
||||||
|
modi.add(ColorMode.COLOR_TEMP)
|
||||||
|
# Leer darf die Menge nie sein - HA verlangt mindestens einen Modus.
|
||||||
|
# Ein Geraet ohne Farbe und ohne Bereich kann immer noch dimmen.
|
||||||
|
return modi or {ColorMode.BRIGHTNESS}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def color_mode(self) -> ColorMode:
|
def color_mode(self) -> ColorMode:
|
||||||
|
|||||||
+35
-1
@@ -44,7 +44,16 @@ from custom_components.ninlight.light import (
|
|||||||
transition_ms,
|
transition_ms,
|
||||||
)
|
)
|
||||||
from tests.helpers import entity_id_for
|
from tests.helpers import entity_id_for
|
||||||
from tests_unit.samples import HOST_CW, INFO_CW, MAC_CW, STATE_CW, STATE_RGB, TOKEN
|
from tests_unit.samples import (
|
||||||
|
HOST_CW,
|
||||||
|
HOST_RGB,
|
||||||
|
INFO_CW,
|
||||||
|
MAC_CW,
|
||||||
|
MAC_RGB,
|
||||||
|
STATE_CW,
|
||||||
|
STATE_RGB,
|
||||||
|
TOKEN,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_brightness_never_zero_and_round_trips() -> None:
|
def test_brightness_never_zero_and_round_trips() -> None:
|
||||||
@@ -99,6 +108,31 @@ async def test_white_lamp_offers_only_color_temp(
|
|||||||
assert state.attributes[ATTR_MAX_COLOR_TEMP_KELVIN] == 5000
|
assert state.attributes[ATTR_MAX_COLOR_TEMP_KELVIN] == 5000
|
||||||
|
|
||||||
|
|
||||||
|
async def test_shield_without_ct_range_offers_only_rgb(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_client: MagicMock,
|
||||||
|
lamp_state: dict[str, Any],
|
||||||
|
) -> None:
|
||||||
|
"""Das Montana-Black-Shield steuert analoge RGB-Streifen und hat keinen
|
||||||
|
eigenen Weisskanal: sein Board meldet ct_min == ct_max (nl_board.c,
|
||||||
|
"ledshield_rgb", 4000/4000) - die Konvention fuer "weiss entsteht als
|
||||||
|
RGB-Mischung". Ein Bereich ohne Spielraum ist kein Farbtemperaturbereich;
|
||||||
|
HA bekaeme sonst einen Regler mit min == max.
|
||||||
|
"""
|
||||||
|
lamp_state.clear()
|
||||||
|
lamp_state.update(deepcopy(STATE_RGB))
|
||||||
|
lamp_state["capabilities"] = {"color": True, "color_temp": [4000, 4000]}
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN, unique_id=MAC_RGB, data={CONF_HOST: HOST_RGB, CONF_TOKEN: TOKEN}
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get(entity_id_for(hass, "light", "light"))
|
||||||
|
assert state.attributes[ATTR_SUPPORTED_COLOR_MODES] == [ColorMode.RGB]
|
||||||
|
|
||||||
|
|
||||||
async def test_turn_on_sends_everything_in_one_request(
|
async def test_turn_on_sends_everything_in_one_request(
|
||||||
hass: HomeAssistant, init_integration, mock_client: MagicMock
|
hass: HomeAssistant, init_integration, mock_client: MagicMock
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|||||||
Reference in New Issue
Block a user