# Spike A — SMC-Keys auf Mac17,9 (M5 Pro) Gemessen am 10.08.2026, macOS 26.6.1 (25G76), **ohne root**, ausschließlich lesend. Werkzeug: `Spikes/smc-dump.swift`. 3486 Keys insgesamt. ## Ergebnis in einem Satz **Lüftersteuerung: bestätigt und umsetzbar.** **Ladelimit: Key noch nicht identifiziert** — das Standardverfahren aus AlDente/batt greift auf dieser Maschine nicht, weil die dort benutzten Keys schlicht nicht existieren. ## Wichtige Querbefunde **SMC-Integer sind little-endian.** Meine erste BE-Dekodierung ergab Unsinn (Akkuspannung 31023 mV). LE ergibt konsistente Werte, zweifach gegengeprüft: | Key | Roh | LE-Wert | Gegenprobe | |---|---|---|---| | `B0AV` | `AA 2F` | 12202 mV | plausible Zellspannung | | `CH0V` | `AA 2F 00 00` | 12202 mV | identisch zu `B0AV` | | `B0AC` | `85 FD` | −635 mA | entlädt; passt zu `PMVR` = 0 W (kein Netzteil) | | `PPBR` | — | 12,13 W | ≈ 12,2 V × 0,64 A ✓ | `flt`-Keys sind ebenfalls little-endian IEEE-754. Für die Implementierung heißt das: **alle Mehrbyte-SMC-Werte little-endian lesen**, entgegen dem verbreiteten Beispielcode, der big-endian annimmt (der stammt aus der Intel-Ära). ## Lüfter — vollständig nutzbar Zwei Lüfter vorhanden (`FNum` = 2). | Key | Typ | Wert | Bedeutung | |---|---|---|---| | `F0md` / `F1md` | ui8 | 0 | **Modus: 0 = auto, 1 = manuell** | | `F0Tg` / `F1Tg` | flt | 2317 / 2502 | Ziel-Drehzahl | | `F0Ac` / `F1Ac` | flt | 2321 / 2499 | Ist-Drehzahl | | `F0Mn` / `F1Mn` | flt | 2317 | Minimum | | `F0Mx` / `F1Mx` | flt | 7826 | Maximum | | `F0St` / `F1St` | ui8 | 5 | Status | | `FEna` | hex | 07 | Freigabe-Bitmaske | **Korrektur zur Planannahme:** der Modus-Key heißt `F0md` **klein geschrieben**, nicht `F0Md`. Mit der Großschreibung aus der Intel-Dokumentation findet man ihn nicht — genau deshalb lief dieser Spike vor dem Implementierungscode. `FS! ` (die alte Force-Bitmaske) existiert **nicht**. Der Weg ist also: `F0md = 1` → `F0Tg = Wunschdrehzahl`, zurück auf Automatik mit `F0md = 0`. Der Sicherheitsrahmen aus dem Plan lässt sich damit sauber umsetzen: `F0Mn`/`F0Mx` liefern die harten Grenzen direkt aus der Firmware, und `F0md = 0` ist ein einzelner, immer verfügbarer Rückfallbefehl. ## Ladelimit — noch offen **Nicht vorhanden:** `CHWA`, `CH0B`, `CH0C`, `CH0I`, `CH0J`, `CH0K`, `BCLM`, `bfE0`, `bfF0`. Damit scheiden sowohl das AlDente-Legacy-Verfahren (`CH0B`/`CH0C`) als auch das 80-%-Flag (`CHWA`) als auch das vollständige Firmware-Backend (`bfD0`/`bfE0`/`bfF0`) aus — von letzterem existiert nur `bfD0` (hex, 2 Byte, `00 00`). Vorhanden ist stattdessen ein umfangreicher `CH*`-Satz. Plausible Kandidaten: | Key | Typ | Wert (LE) | Vermutung | |---|---|---|---| | `CHTE` | ui32 | 0 | Ladeziel — 0 könnte „kein Limit" heißen | | `CHTL` | ui32 | 3600 | untere Schwelle? | | `CHTU` | ui32 | 4100 | obere Schwelle? (mV je Zelle) | | `CHBV` | ui32 | 4125 | Ladeschlussspannung mV | | `CHIL` / `CHIO` | flag | false | Inhibit-Flags | | `CHSE` / `CHST` / `CHRT` | ui8 | 0 | Status/Steuerung | **Das bleibt Vermutung, und Vermutungen werden hier nicht geschrieben.** Ein falscher Wert im Lade-Subsystem ist die eine Operation in diesem Projekt, die Hardware dauerhaft beschädigen kann. ### Nachtrag 11.08.2026: Key gefunden, aber nicht beschreibbar Die Differenzmessung hat ihn geliefert. Der Key heißt **`CHLT`**, Typ `hex_`, drei Bytes: | macOS-Einstellung | `CHLT` | |---|---| | 80 % | `50 01 00` | | 85 % | `55 01 00` | | 95 % | `5F 01 00` | Erstes Byte ist die Prozentzahl, zweites offenbar „Limit aktiv", drittes unbenutzt. Drei Messpunkte, weil einer Zufall sein kann: `BACC` passte beim ersten Vergleich ebenfalls — ein Zähler, in dem gerade `50` stand. `ChargerConfiguration` aus `ioreg` sah mit niedrigem Byte `0x50` ebenfalls wie eine Quelle aus, blieb aber unverändert, als `CHLT` längst auf 95 stand. **Schreiben scheitert.** Der Helfer hat es mit korrekter Größe (3 Byte) versucht; der SMC-Userclient gibt einen Fehler zurück, der Wert bleibt stehen: ``` Ladelimit: 95 % gewünscht, 95 % geschrieben (false), zurückgelesen 85 % ``` macOS setzt das Limit also auf einem anderen Weg. Welchem, ist offen — und weiter zu raten hieße, im Lade-Subsystem Keys durchzuprobieren. Das ist die eine Operation in diesem Projekt, die Hardware dauerhaft beschädigen kann, also unterbleibt es. **Folge für Onyx:** das Ladelimit ist eine **Anzeige**. Der Wert wird gelesen und im Akku-Widget sowie im Akku-Popover gezeigt, mit einem Weg in die Systemeinstellungen. Der Schreibpfad ist aus dem privilegierten Helfer wieder entfernt — ein Root-Dienst trägt nur, was benutzt wird. ### Damals geplanter Schritt: Differenzmessung statt Raten macOS hat selbst eine Ladebegrenzung (Systemeinstellungen → Batterie → Batteriezustand → „Optimiertes Laden" bzw. das 80-%-Limit). Wird sie umgeschaltet, muss sich der zuständige SMC-Key ändern. `Spikes/smc-diff.sh` nimmt zwei vollständige Dumps auf und zeigt die Differenz — damit ist der Key **ohne einen einzigen Schreibzugriff** identifizierbar. Bis dieser Test gelaufen ist, bleibt die Akkukarte reine Anzeige. ## Auswirkungen auf den Plan 1. Phase 6 wird geteilt: **Lüftersteuerung kann gebaut werden**, das Ladelimit wartet auf die Differenzmessung. 2. Alle SMC-Werte werden little-endian gelesen — betrifft `MetricsProvider` und `OnyxHelper`. 3. `F0Mn`/`F0Mx` werden zur Laufzeit aus der Firmware gelesen statt fest verdrahtet. 4. Lüfterdrehzahlen sind `flt`, nicht `fpe2`.