feat: update-Entitaet fuer die Firmware und das Testgeruest

Aufgebaut wie ha-ninlight: die Abbilder liegen unter ninstrip_firmware im
Konfigurationsverzeichnis, Home Assistant liefert sie selbst unter einer
einmaligen Adresse aus, und zwar genau die Bytes, die vorher geprueft
wurden. Dazu firmware.py (Anhaenger, Versionsreihenfolge, WLAN-Pruefung,
Katalog), http.py, urls.py und shared.py.

Drei Unterschiede zu ninlight, alle aus der Firmware heraus:

* Verglichen wird device_type - die Platine -, nicht product. Letzteres ist
  bei allen Platinen 'ninstrip'; die Abbilder unterscheiden sich aber hart,
  die K1Y invertiert das Datensignal und die KL-RGBC3 nicht. Firmware ohne
  dieses Feld bekommt gar kein Angebot.
* Die WLAN-Pruefung sucht die SSID unverpackt: ein ESP32-Abbild ist nicht
  gzip-verpackt wie das des W600. An einem mit sdkconfig.local gebauten
  Abbild gegengeprueft - die SSID steht genau einmal NUL-gerahmt drin.
* Der Fehlerschluessel heisst device_url_too_long statt lamp_url_too_long.

Dazu das Testgeruest, das es hier bisher gar nicht gab: 204 Tests in
tests_unit/ (ohne HA-Instanz) und tests/ (mit), Abdeckung 97 %, dazu
scripts/check.sh als Ersatz fuer die fehlende CI. Die Nutzdaten in
tests_unit/samples.py sind an der Stehlampe abgefragt.

Beim Gegenpruefen per Mutation fiel auf, dass die Platinenpruefung
unmittelbar vor dem Senden ungeprueft war - der Test dazu ist jetzt da und
faellt, wenn man die Pruefung entfernt.
This commit is contained in:
Michael Sauer
2026-09-22 23:10:07 +02:00
parent d0a9487805
commit 2c77b2d325
44 changed files with 3600 additions and 43 deletions
+97
View File
@@ -0,0 +1,97 @@
"""Echte Nutzdaten zweier Geraete. Bewusst keine Grenzwerte - die stehen in den Tests selbst."""
from __future__ import annotations
from typing import Any
TOKEN = "a201883d13a570dd3cf1f3b64b5e1df7"
HOST_K1Y = "192.168.2.238"
MAC_K1Y = "b0:81:84:49:ad:4c"
# Abgefragt an der Stehlampe (KL-LSC5C3WV2-K1Y, SK6812-RGBW, 60 Pixel).
STATE_K1Y: dict[str, Any] = {
"on": True,
"brightness": 100,
"power_on_behaviour": "last",
"fade_in": 500,
"fade_out": 500,
"transition_default": 300,
"wake_on_change": False,
"preset": 2,
"preset_modified": False,
"segment_count": 1,
"pixel_count": 60,
}
INFO_K1Y: dict[str, Any] = {
"product": "ninstrip",
"device_type": "ninstrip-k1y",
"fw_version": "0.1.0-12-g71a57",
"build_date": "2026-09-22",
"mac": MAC_K1Y,
"name": "",
"wifi": {"mode": "sta", "ssid": "ninIOT", "rssi": -68, "ip": HOST_K1Y, "error": None},
"sacn": {"enabled": True, "active": False, "universe": 1, "universes": 1, "multicast": True},
"uptime": 1459,
"free_heap": 156848,
"strip": {
"chipset": "sk6812_rgbw",
"color_order": "grb",
"data_pin": 19,
"pixel_count": 60,
"leds_per_pixel": 1,
"has_white": True,
"inverted": True,
"power_scale": 100,
"max_milliamps": 1800,
},
"render": {"fps": 50, "render_us": 900, "show_us": 1800, "dropped_frames": 0},
"last_ota_error": None,
}
# wifi.source "compiled": das Geraet kennt sein WLAN nur aus der Firmware.
SETTINGS_COMPILED: dict[str, Any] = {
"name": "",
"wifi": {"ssid": "ninIOT", "source": "compiled"},
"auth_all": False,
"sacn": {
"enabled": True,
"universe": 1,
"start_slot": 1,
"on_timeout": "release",
"channels_per_pixel": 3,
},
"strip": {
"chipset": "sk6812_rgbw",
"color_order": "grb",
"data_pin": 19,
"pixel_count": 60,
"leds_per_pixel": 1,
"max_milliamps": 1800,
"supply_volts": 12,
"inverted": True,
},
}
PRESETS_K1Y: dict[str, Any] = {
"presets": [
{"id": 0, "name": "Warmweiss", "used": True, "segment_count": 1},
{"id": 1, "name": "Kaltweiss", "used": True, "segment_count": 1},
{"id": 2, "name": "Regenbogen", "used": True, "segment_count": 1},
{"id": 3, "name": "Feuer", "used": True, "segment_count": 1},
{"id": 4, "name": "", "used": False, "segment_count": 0},
{"id": 5, "name": "", "used": False, "segment_count": 0},
{"id": 6, "name": "", "used": False, "segment_count": 0},
{"id": 7, "name": "", "used": False, "segment_count": 0},
],
"active": 2,
"modified": False,
}
# wifi.source "stored": ueber das Onboarding ins WLAN gebracht, also vom
# Abbild unabhaengig.
SETTINGS_STORED: dict[str, Any] = {
**SETTINGS_COMPILED,
"wifi": {"ssid": "ninIOT", "source": "stored"},
}