Files
ha-ninstrip/tests/test_effekte.py
T
Michael SauerandClaude Opus 5 ffcbbdfe4a feat(light): Effekte zur Auswahl
Die neun Effekte der Firmware waren in Home Assistant nicht erreichbar -
das Auswahlfeld, das es schon gab, sind die Szenen. Jetzt bietet die
Lichtentitaet sie an:

* Gewaehlt wird ueber den NAMEN aus der Firmware ("Regenbogen"),
  geschickt wird die Kennung ("rainbow"). Eine Liste englischer
  Kennungen waere in einer deutschen Oberflaeche unnoetig sperrig.
* Ein Effekt laeuft wie eine Farbe in ALLEN Segmenten; angezeigt wird er
  nur, wenn alle denselben fahren.
* Eine Kennung, die nicht in der Liste steht (neuere Firmware, aeltere
  Liste), wird roh angezeigt statt verschluckt.
* Ein unbekannter Name wird abgelehnt, statt stillschweigend nichts zu
  tun.

Die Liste steht fest in der Firmware und wird deshalb einmal geholt,
nicht je Abfragezyklus - erneut erst, wenn sich die Version aendert. Eine
sechste Anfrage je Zyklus fuer etwas, das sich nie aendert, waere
Verschwendung.

Effekt-Parameter (Geschwindigkeit, Intensitaet, Palette) fehlen noch;
dafuer braucht es Entitaeten je Segment.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 11:15:36 +02:00

137 lines
4.7 KiB
Python

"""Effekte: Liste, Anzeige, Setzen - und was passiert, wenn sie fehlen."""
from __future__ import annotations
from typing import Any
from unittest.mock import MagicMock
from freezegun.api import FrozenDateTimeFactory
from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ServiceValidationError
import pytest
from pytest_homeassistant_custom_component.common import MockConfigEntry
from tests.helpers import abfragen, entity_id_for
def light_id(hass: HomeAssistant) -> str:
return entity_id_for(hass, "light", "light")
async def test_die_liste_zeigt_namen_nicht_kennungen(
hass: HomeAssistant, init_integration: MockConfigEntry
) -> None:
state = hass.states.get(light_id(hass))
assert state.attributes["effect_list"] == ["Regenbogen", "Feuer", "Lauflicht"]
async def test_die_liste_wird_nur_einmal_geholt(
hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_client: MagicMock,
freezer: FrozenDateTimeFactory,
) -> None:
"""Sie steht fest in der Firmware - eine sechste Anfrage je Zyklus waere
Verschwendung."""
vorher = mock_client.get_effects.await_count
await abfragen(hass, freezer)
await abfragen(hass, freezer)
assert mock_client.get_effects.await_count == vorher
async def test_nach_einem_firmware_update_wird_sie_neu_geholt(
hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_client: MagicMock,
strip_info: dict[str, Any],
freezer: FrozenDateTimeFactory,
) -> None:
"""Eine neue Firmware kann neue Effekte mitbringen."""
vorher = mock_client.get_effects.await_count
strip_info["fw_version"] = "0.2.0"
await abfragen(hass, freezer)
assert mock_client.get_effects.await_count == vorher + 1
async def test_laufender_effekt_wird_mit_namen_angezeigt(
hass: HomeAssistant,
init_integration: MockConfigEntry,
strip_segments: dict[str, Any],
freezer: FrozenDateTimeFactory,
) -> None:
strip_segments["segments"][0].update({"mode": "effect", "effect": "fire"})
await abfragen(hass, freezer)
assert hass.states.get(light_id(hass)).attributes["effect"] == "Feuer"
async def test_unbekannte_kennung_wird_roh_gezeigt(
hass: HomeAssistant,
init_integration: MockConfigEntry,
strip_segments: dict[str, Any],
freezer: FrozenDateTimeFactory,
) -> None:
"""Neuere Firmware, aeltere Liste - dann lieber die Kennung als nichts."""
strip_segments["segments"][0].update({"mode": "effect", "effect": "meteor"})
await abfragen(hass, freezer)
assert hass.states.get(light_id(hass)).attributes["effect"] == "meteor"
async def test_ohne_effektmodus_kein_effekt(
hass: HomeAssistant, init_integration: MockConfigEntry
) -> None:
assert hass.states.get(light_id(hass)).attributes["effect"] is None
async def test_uneinige_segmente_zeigen_keinen_effekt(
hass: HomeAssistant,
init_integration: MockConfigEntry,
strip_segments: dict[str, Any],
freezer: FrozenDateTimeFactory,
) -> None:
strip_segments["segments"] = [
{"id": 0, "start": 0, "end": 29, "mode": "effect", "effect": "fire", "brightness": 80},
{"id": 1, "start": 30, "end": 59, "mode": "effect", "effect": "chase", "brightness": 80},
]
await abfragen(hass, freezer)
assert hass.states.get(light_id(hass)).attributes["effect"] is None
async def test_effekt_setzen_schreibt_die_kennung(
hass: HomeAssistant, init_integration: MockConfigEntry, mock_client: MagicMock
) -> None:
await hass.services.async_call(
"light",
"turn_on",
{ATTR_ENTITY_ID: light_id(hass), "effect": "Lauflicht"},
blocking=True,
)
(geschrieben,) = mock_client.put_segments.await_args.args
assert [(s["mode"], s["effect"]) for s in geschrieben] == [("effect", "chase")]
assert hass.states.get(light_id(hass)).attributes["effect"] == "Lauflicht"
async def test_unbekannter_effekt_wird_abgelehnt(
hass: HomeAssistant, init_integration: MockConfigEntry, mock_client: MagicMock
) -> None:
with pytest.raises(ServiceValidationError):
await hass.services.async_call(
"light",
"turn_on",
{ATTR_ENTITY_ID: light_id(hass), "effect": "Diskokugel"},
blocking=True,
)
mock_client.put_segments.assert_not_awaited()
async def test_firmware_ohne_effektliste_bietet_keine_an(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_client: MagicMock,
) -> None:
mock_client.get_effects.side_effect = lambda: {"palettes": []}
mock_config_entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
assert hass.states.get(light_id(hass)).attributes["effect_list"] == []