Der Regler war eine Pseudobedienung. Der SMC lehnt Schreibzugriffe auf CHLT ab — der Helfer hat es mit korrekter Größe versucht und „geschrieben (false), zurückgelesen 85" gemeldet. Das Sicherheitsnetz hat also die Wahrheit gesagt; die Oberfläche hat sie nur nicht gezeigt. Weiter zu raten hieße, im Lade-Subsystem Keys durchzuprobieren, und das ist die eine Operation in diesem Projekt, die Hardware dauerhaft beschädigen kann. Also: das Limit wird gelesen und angezeigt, mit einem Weg in die Systemeinstellungen, wo es tatsächlich geht. Der Schreibpfad ist aus dem privilegierten Helfer entfernt — ein Root-Dienst trägt nur, was benutzt wird. Die Akku-Kachel zeigte „40 %" und einen Verlauf über die letzten Sekunden. Der Ladestand ändert sich in Minuten, nicht in Sekunden; der Graph war eine waagerechte Linie. Jetzt: verbleibende Zeit bzw. Zeit bis voll, Leistung in Watt mit Richtung, Ladelimit, Zustand, Zyklen — und der Energiesparmodus. Der erklärt, warum die Maschine langsamer wirkt, und ohne diesen Hinweis sucht man den Grund woanders. In der Menüleiste standen fünf nackte Prozentzahlen nebeneinander. Man sah Zahlen und wusste nicht, welche wozu gehört. Zwei neue Darstellungen: Kürzel und Wert („CPU 34 %") sowie Symbol und Wert. Beim Akku stehen sie zuoberst in der Auswahl. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
5.4 KiB
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
- Phase 6 wird geteilt: Lüftersteuerung kann gebaut werden, das Ladelimit wartet auf die Differenzmessung.
- Alle SMC-Werte werden little-endian gelesen — betrifft
MetricsProviderundOnyxHelper. F0Mn/F0Mxwerden zur Laufzeit aus der Firmware gelesen statt fest verdrahtet.- Lüfterdrehzahlen sind
flt, nichtfpe2.