# -*- coding: utf-8 -*- """ LED Layout-Definitionen. Definiert verschiedene physische LED-Anordnungen (Single, Jewel, Ring) und stellt eine automatische Layout-Erkennung bereit. """ from __future__ import annotations from dataclasses import dataclass, field from trixy_core.utils.debug import pdebug, pwarn @dataclass class LEDLayout: """Layout-Definition fuer eine LED-Anordnung. Beschreibt die physische Anordnung der LEDs, insbesondere welche LEDs zum Ring gehoeren und ob eine Center-LED existiert. Attributes: name: Bezeichnung des Layouts (z.B. "single", "jewel_7", "ring_12"). led_count: Gesamtanzahl der LEDs. center_index: Index der Center-LED (None wenn keine vorhanden). ring_indices: Indizes der Ring-LEDs in Reihenfolge. """ name: str led_count: int center_index: int | None = None ring_indices: list[int] = field(default_factory=list) @property def has_center(self) -> bool: """Prueft ob das Layout eine Center-LED hat.""" return self.center_index is not None @property def ring_count(self) -> int: """Anzahl der Ring-LEDs.""" return len(self.ring_indices) # ── Vordefinierte Layouts ────────────────────────────────────────────── LAYOUT_SINGLE = LEDLayout( name="single", led_count=1, center_index=None, ring_indices=[0], ) LAYOUT_JEWEL_7 = LEDLayout( name="jewel_7", led_count=7, center_index=0, ring_indices=[1, 2, 3, 4, 5, 6], ) LAYOUT_RING_12 = LEDLayout( name="ring_12", led_count=12, center_index=None, ring_indices=list(range(12)), ) LAYOUT_RING_16 = LEDLayout( name="ring_16", led_count=16, center_index=None, ring_indices=list(range(16)), ) LAYOUT_RING_24 = LEDLayout( name="ring_24", led_count=24, center_index=None, ring_indices=list(range(24)), ) # Lookup-Tabelle: Name → Layout LAYOUTS: dict[str, LEDLayout] = { "single": LAYOUT_SINGLE, "jewel_7": LAYOUT_JEWEL_7, "ring_12": LAYOUT_RING_12, "ring_16": LAYOUT_RING_16, "ring_24": LAYOUT_RING_24, } # Auto-Detect: LED-Anzahl → Layout-Name (fuer gaengige Konfigurationen) _COUNT_TO_LAYOUT: dict[int, str] = { 1: "single", 7: "jewel_7", 12: "ring_12", 16: "ring_16", 24: "ring_24", } def get_layout(type_name: str, led_count: int) -> LEDLayout: """Gibt passendes Layout zurueck oder erkennt es automatisch. Sucht zuerst nach dem angegebenen Layout-Namen. Falls kein Name angegeben oder nicht gefunden, wird anhand der LED-Anzahl ein passendes Layout gewaehlt. Als Fallback wird ein generisches Ring-Layout erzeugt. Args: type_name: Gewuenschter Layout-Name (z.B. "jewel_7"). Leerer String fuer Auto-Erkennung. led_count: Anzahl der LEDs. Returns: Passendes LEDLayout fuer die Konfiguration. """ # Expliziter Layout-Name angegeben if type_name and type_name in LAYOUTS: layout = LAYOUTS[type_name] if layout.led_count != led_count: pwarn( f"LED-Layout '{type_name}' erwartet {layout.led_count} LEDs, " f"aber {led_count} konfiguriert — verwende Layout trotzdem" ) pdebug(f"LED-Layout '{type_name}' geladen ({layout.led_count} LEDs)") return layout # Warnung wenn unbekannter Name angegeben if type_name: pwarn( f"Unbekanntes LED-Layout '{type_name}' — versuche Auto-Erkennung" ) # Auto-Erkennung anhand LED-Anzahl if led_count in _COUNT_TO_LAYOUT: auto_name = _COUNT_TO_LAYOUT[led_count] layout = LAYOUTS[auto_name] pdebug( f"LED-Layout automatisch erkannt: '{auto_name}' ({led_count} LEDs)" ) return layout # Fallback: Generisches Ring-Layout pdebug( f"Kein vordefiniertes Layout fuer {led_count} LEDs — " f"erzeuge generisches Ring-Layout" ) return LEDLayout( name=f"ring_{led_count}", led_count=led_count, center_index=None, ring_indices=list(range(led_count)), )