# Optimierungsplan – Lüftersteuerung mit OBD1-Diagnose

Dieser Plan ist in **Software**, **Hardware** und **UX** gegliedert. Jeder Punkt beschreibt: *Problem im IST-Zustand → Lösung → erwarteter Nutzen → Aufwand*.

Die optimierte Firmware (`firmware/ProMini_Optimized/ProMini_Optimized.ino`) implementiert bereits einen Großteil der Software-Punkte und ist **pin-kompatibel** zur bestehenden Platine — kein Neuaufbau nötig.

---

## 1. Software-Optimierungen

### 1.0 PID-Regelung statt Bang-Bang
- **IST:** Schwellwert-Regelung mit Hysterese (5 s Nachlauf). Ergibt grobe Temperatur-Welligkeit (typisch ±5–10 °C über/unter Sollwert), und der Lüfter springt mit voller Last an statt sanft hochzulaufen.
- **SOLL:** PID-Regler `error = T − Sollwert` mit Conditional-Integration (Anti-Wind-up), Derivative on Measurement (kein Setpoint-Kick beim Drehen am Sollwert), und Slow-PWM-Aktor (Default 30 s Periode) auf das Relais. Default-Tuning: Kp = 5 %/°C, Ki = 0.5 %/(°C·s), Kd = 2 %·s/°C.
- **Nutzen:** Temperatur bleibt eng am Sollwert; weniger Drehzahl-Sprünge im Lüfter; bessere Voraussicht durch D-Anteil.
- **⚠ Hardware-Caveat:** Das mechanische SRD-05VDC-Relais ist mit Slow-PWM nur begrenzt haltbar (Schätzung ~830 h bei 30 s Periode und Worst-Case-Duty 50 %). **Empfehlung:** Relais gegen Logik-Pegel-N-MOSFET (z. B. IRLZ44N) oder Halbleiter-Relais (SSR) tauschen. Pinbelegung bleibt identisch. Mit MOSFET kann die PWM-Periode auf 1–10 s reduziert werden, was die Regelung noch glatter macht.
- **Notfall-Fallback:** `#define CFG_USE_PID 0` re-aktiviert das alte Bang-Bang-Verhalten Bit-für-Bit.
- **Aufwand:** mittel (~150 Zeilen Firmware-Code).
- **Status:** ✅ erledigt in `ProMini_Optimized.ino` (Funktion `updateFanPID()` + `applyPwm()`).

### 1.1 NTC-Linearisierung (Steinhart-Hart / Beta-Modell)
- **IST:** `map(adc, 1023, 200, 25, 130)` linear interpoliert auf einem stark nichtlinearen NTC. Fehler kann an den Rändern leicht ±15 °C betragen.
- **SOLL:** Beta-Modell `1/T = 1/T0 + (1/B)·ln(R/R0)` mit konfigurierbarem R25, Beta und Vorwiderstand. Optional als 256-Byte-LUT in PROGMEM für noch weniger Floating-Point-Last.
- **Nutzen:** Korrekte Schwellen­anzeige, vor allem im sicherheitskritischen Bereich um 90–100 °C.
- **Aufwand:** ~20 Zeilen Code; `#include <math.h>` ist Standard.
- **Status:** ✅ erledigt in `ProMini_Optimized.ino` (Funktion `readTemperatureC()`).

### 1.2 Nicht-blockierender ECU-Clear
- **IST:** `clearEcuByPullingLow()` ruft `delay(1000)` auf → 1 Sekunde lang ist der Loop tot. Encoder-Flanken können verloren gehen, Anzeige flackert.
- **SOLL:** Zustands­automat (`ClearState::PULLING_LOW → FLASHING_CLR → IDLE`), getrieben von `millis()`-Vergleichen.
- **Nutzen:** Anzeige bleibt ruhig, Bedienung reagiert sofort.
- **Aufwand:** klein.
- **Status:** ✅ erledigt (Funktionen `startEcuClear` / `updateClearState`).

### 1.3 Adaptive Pausen-Schwelle für die Blinkcode-Erkennung
- **IST:** Hardcodierte 2000 ms als Trennung „kurze vs. lange Pause". Wenn die Motronic eines Tages anders taktet (Hitze, Spannungs­schwankung), bricht die Erkennung.
- **SOLL:** Während der Kalibrierung mit Code 12 wird **beides** gemessen (Pausen­summen für „kurz" und „lang"); die Schwelle wird daraus dynamisch bestimmt: `threshold = (avgShort + avgLong) / 2`.
- **Nutzen:** Robust gegen Toleranzen verschiedener Steuergeräte.
- **Aufwand:** klein.
- **Status:** ✅ erledigt.

### 1.4 Encoder mit Quadratur-Tabelle und Detent-Konsum
- **IST:** Flanken-basierte Erkennung mit `lastEncoderState`. Anfällig für Prellen, gibt mehrfach Schritte ab → Schwellwert „springt" um 2–3 Werte.
- **SOLL:** State-Machine über 4-Bit-Indextabelle (PROGMEM); ein „Detent" = 4 Quadratur-Schritte. Software-Glitch-Filter ~3 ms.
- **Nutzen:** Ein Klick = ein Schritt, immer.
- **Aufwand:** mittel (~25 Zeilen).
- **Status:** ✅ erledigt (`encoderPoll`, `consumeEncoderDetent`).

### 1.5 Tasten-Entprellung in Software
- **IST:** Roher `digitalRead()` ohne Entprellung. Hardware-Schutz hängt von Encoder-PEC16 und Leiterplatten­layout ab.
- **SOLL:** 5 ms-Entprellung mit `pressedEdge`/`releasedEdge`-Events. Damit lassen sich Single, Double, Long-Press sauber unterscheiden.
- **Nutzen:** Keine Phantom-Klicks, keine versehentlichen Override-Toggles.
- **Aufwand:** klein.
- **Status:** ✅ erledigt (`Button` / `buttonUpdate`).

### 1.6 EEPROM-Wear-Leveling
- **IST:** `EEPROM.write()` wird verwendet, schreibt auch bei unverändertem Wert. Schwellwert wird bei jedem Setting-Exit geschrieben — bei häufiger Bedienung kann der EEPROM-Slot in Jahren ermüden (100k Zyklen).
- **SOLL:**
  1. `EEPROM.update()` überall (schreibt nur bei tatsächlicher Änderung).
  2. Wear-Leveling: 8 Slots × 2 Bytes (`[seq][value]`) je für Schwelle und Helligkeit. Lebensdauer × 8.
- **Nutzen:** EEPROM hält Größenordnungen länger.
- **Aufwand:** klein.
- **Status:** ✅ erledigt (`wearLoad` / `wearSave`).

### 1.7 Multiplex auf `micros()`-Basis
- **IST:** `delay(brightnessDelay)` blockiert pro Digit 1–5 ms. In der Loop läuft danach jede andere Funktion mit Verzögerung.
- **SOLL:** `multiplexTick()` schaltet pro Loop-Iteration **maximal eine Stelle** weiter, sobald `micros()` die On-Zeit überschritten hat. Loop läuft im µs-Takt durch.
- **Nutzen:** Encoder-Polling, Diagnose-Signal-Sampling und Anzeige stehen sich nicht mehr im Weg.
- **Aufwand:** mittel.
- **Status:** ✅ erledigt.

### 1.8 Watchdog-Timer
- **IST:** Bei einem Hänger (z. B. EMV-Spike) bleibt das Gerät stumm.
- **SOLL:** `wdt_enable(WDTO_2S)` + regelmäßiger `wdt_reset()` im Loop. Bei jedem Hänger > 2 s springt der MCU automatisch in einen Reset.
- **Nutzen:** Selbstheilung im KFZ-Umfeld.
- **Aufwand:** trivial.
- **Status:** ✅ erledigt (per `CFG_WDT_ENABLE`-Flag).

### 1.9 Brown-Out-Detection (Fuses)
- **IST:** Nicht dokumentiert.
- **SOLL:** BOD-Fuses auf 2.7 V (oder 4.3 V) brennen. Verhindert undefiniertes Verhalten / EEPROM-Korruption bei Spannungs­einbrüchen (Anlasserstart, Lichtmaschinen-Spitzen).
- **Befehl (avrdude):**
  ```
  avrdude -c usbasp -p m328p -U efuse:w:0xFD:m   # BOD 2.7 V
  ```
- **Nutzen:** Robustheit, EEPROM-Sicherheit.
- **Aufwand:** trivial (einmalig pro Board).

### 1.10 Konsequente Kapselung in Modi (Enum)
- **IST:** `bool settingMode`, `mirrorMode`, `historyViewMode`, `brightnessMode` parallel — Reihenfolge­abhängigkeiten in `if`-Ketten.
- **SOLL:** `enum class Mode { NORMAL, SETTING_THRESH, … }` plus zentraler `switch` in `loop()`. Nur ein Modus zur Zeit, klare Übergänge.
- **Nutzen:** Wartbarkeit, weniger Bugs bei Modus­übergängen.
- **Status:** ✅ erledigt.

### 1.11 PROGMEM-Tabellen für Zeichensatz
- **IST:** `digitCodes[]` im RAM; einzelne Buchstaben (C, L, R, P) als Magic-Numbers in if-Zweigen.
- **SOLL:** `DIGIT_FONT[10] PROGMEM` + `SEG_C/SEG_L/SEG_R/SEG_P/SEG_DASH`-Konstanten.
- **Nutzen:** RAM frei, Code lesbarer.
- **Status:** ✅ erledigt.

### 1.12 Compile-Time-Konfiguration
- **IST:** Konstanten verstreut.
- **SOLL:** `CFG_*`-Block am Anfang der Datei (NTC-Parameter, Default-Werte, Watchdog-Flag, Debug-Flag).
- **Nutzen:** Eine Stelle für alle „Knöpfe".
- **Status:** ✅ erledigt.

### 1.13 Optionale Erweiterungen (nicht implementiert, aber empfohlen)
- **CRC8 über die EEPROM-Sitzungs­liste** (1 Byte je Sitzung) — erkennt Korruption.
- **Pin-Change-Interrupt für den Encoder** auf D2/D3 — entlastet den Loop.
- **Power-Save-Mode**, wenn Zündung > 5 min aus und Display blank — spart Strom (KFZ-Standby).
- **OTA-/Serial-Konfiguration**: Schwellwert / Helligkeit per UART ändern (nur wenn Digit3 abgekoppelt).

---

## 2. Hardware-Optimierungen

### 2.1 Pin-Konflikt D0 (RX) entschärfen
- **IST:** Digit3 hängt an D0/RX. Beim Upload muss man die Anzeige abklemmen (oder es flackert kurz mit Upload-Daten).
- **SOLL (Option A, sanft):** Jumper / Schiebeschalter, der D0 zwischen Digit3 und FTDI-Header umlegt.
- **SOLL (Option B, sauber):** Auf zukünftiger Revision der Platine Digit3 nach D10 verlegen (D10 ist bisher frei).
- **Nutzen:** Upload ohne Aufschrauben, Serial-Debug möglich.

### 2.1b Lüfter-Relais ↔ Logik-MOSFET (PID-Voraussetzung)
- **IST:** Mechanisches SRD-05VDC-SL-C (5 V Spule, 10 A Kontakt). Mit der neuen PID-Slow-PWM schaltet es im Worst Case alle 30 s → Lebensdauer ~830 h.
- **SOLL:** Logik-Pegel-N-MOSFET wie **IRLZ44N** (Vgs(th) ~ 1.5 V, RDS(on) ~ 0.022 Ω, 47 A bei TO-220 mit Kühlung) anstelle des Relais. **Anschluss:** Drain → Lüfter-Massepfad, Source → GND, Gate → ATmega-Pin A0 mit 100 Ω in Serie + 10 kΩ Gate-Pulldown nach GND. Freilaufdiode 1N5408 (oder besser TVS) parallel zur Lüfterwicklung.
- **Bonus:** PWM-Periode kann auf 1–10 s gesenkt werden → glattere Regelung, kein hörbares Klicken.
- **Nutzen:** Verschleißfrei, lautlos, schneller, präziser regelbar.
- **Aufwand:** Bauteilwechsel + 2 Widerstände, optional KiCad-Revision.

### 2.2 Hardware-PWM für Helligkeit (statt Multiplex-Duty)
- **IST:** Helligkeit kommt aus der Multiplex-On-Zeit pro Digit. Verändert auch die Refresh-Rate.
- **SOLL:** Common-Cathode-Treiber über N-MOSFET, gemeinsamer Enable über einen PWM-Pin (z. B. D11/Timer2). Multiplex bleibt fix bei ~150 Hz, Helligkeit kommt aus PWM-Duty.
- **Nutzen:** Lineare Helligkeits­regelung (5–100 %), kein Flimmern bei niedriger Helligkeit.
- **Aufwand:** Platinen-Revision; oder als Adapter-Platine zwischen Digit-Treibern und Anzeige.

### 2.3 Pegelwandler / Schutz für die Diagnose-Leitung A3
- **IST:** Direkter Anschluss an die Motronic-Diagnose­leitung (Pin A3 vom Steuergerät, „Check Engine"-Lampe). Im KFZ kommen kurzzeitig 14 V + Spikes vor.
- **SOLL:** TVS-Diode (z. B. SMBJ15CA) gegen Masse, in Serie 1 kΩ + Z-Diode 5,1 V als Clamp, anschließend Optokoppler 4N25 (gleicher Typ wie Zündung, schon im Stock vorhanden) — galvanische Trennung wäre der Königsweg.
- **Nutzen:** Schützt den ATmega vor Überspannung; bei einem Defekt brennt nur der Optokoppler.
- **Aufwand:** klein, minimaler Zusatz an Bauteilen.

### 2.4 Reverse-Polarity-Schutz / Eingangsfilter für 12 V
- **IST:** DC/DC-Wandler 5 V; Eingangs­schutz nicht vollständig dokumentiert.
- **SOLL:** P-MOSFET in High-Side für Verpolungs­schutz (geringer Spannungs­abfall) **oder** Schottky-Diode in Serie + selbst­rückstellende PTC-Sicherung 1 A.
- **Bonus:** LC-Filter (10 µH + 100 µF) gegen Lichtmaschinen-Rippel, dann erst der DC/DC-Wandler.
- **Nutzen:** Überlebt Bordnetz-Anomalien.

### 2.5 Freilaufdiode an den Relais prüfen
- **IST:** Im Code als „Freilaufdiode" erwähnt; im Schaltplan vorhanden — bitte prüfen, ob die 1N4007 in **Sperrrichtung parallel zur Spule** sitzt (nicht in Serie!) und ihre Reverse-Recovery-Zeit für 12 V-Schaltvorgänge ausreichend ist (1N4007: 30 µs; reicht für Relais).
- **SOLL:** Falls möglich, zusätzlich eine **TVS-Diode** parallel — schneller, fängt Spikes besser ab.
- **Aufwand:** trivial.

### 2.6 Entkopplung der Stromversorgung
- **IST:** Standard-Schaltung mit DC/DC.
- **SOLL:** 100 nF Keramik direkt am VCC-Pin des ATmega, **plus** 10 µF Tantal/Elko 1 cm entfernt. Gleicher Trick an den Treiber­ICs / Optokopplern.
- **Nutzen:** Reduziert Glitches bei Schaltvorgängen.

### 2.7 ESD-Schutz an externen Anschlüssen
- **SOLL:** Pro KFZ-Stecker-Pin eine TVS-Diode oder zumindest 100 nF gegen Masse.
- **Nutzen:** Schutz beim An-/Abstecken im Auto.

### 2.8 Optionale Hardware-Erweiterungen (Revision 2)
- **Diagnose-LED separat** (statt nur über die Anzeige) — sieht man die Diagnose-Aktivität auch ohne Sonnenschutz.
- **Buzzer** für akustische Warnung bei Übertemperatur (z. B. > 110 °C).
- **Zweiter NTC** für Ansauglufttemperatur — als Plausibilitäts­check / zukünftige Erweiterung.
- **CAN-Transceiver** (MCP2515 oder ähnlich) — für moderne Motronic-Generationen, falls man den Code später für Motronic ME 1.5.5 / Simtec / OBD2 erweitern möchte.

---

## 3. UX-Optimierungen

### 3.1 Visuelle Bestätigung beim Mode-Wechsel
- **IST:** Modus­übergänge (Long-Press 1 s, 5 s, 10 s) sind „blind" — nichts zeigt an, ob man weit genug gehalten hat.
- **SOLL:**
  - Bei 1 s: kurzes Blinken der aktuellen Anzeige (z. B. 200 ms aus/ein).
  - Bei 5 s: Lauflicht 1× durchlaufen.
  - Bei 10 s: Lauflicht in anderer Richtung.
- **Nutzen:** Bedienung wird vorhersagbar.
- **Aufwand:** klein.

### 3.2 Override-Anzeige (Dauer EIN)
- **IST:** Override aktiviert nur das Relais, die Anzeige bleibt bei Temperatur.
- **SOLL:** Dezimalpunkt (DP) am Einer-Digit als Indikator → muss die Anzeige um den DP-Pin erweitert werden, oder periodisches kurzes Aufblitzen von „On".
- **Nutzen:** Fahrer sieht sofort, dass der Lüfter manuell läuft.
- **Aufwand:** Hardware-DP-Verkabelung **oder** Software-Aufblitzen.

### 3.3 Helligkeit dynamisch (LDR oder fest umschaltbar)
- **IST:** Eine Helligkeit für Tag und Nacht.
- **SOLL:** LDR an A2 (wenn frei) oder Kopplung an die Klemme 58 (Standlicht): tagsüber 100 %, nachts auf gespeicherten Nacht­wert.
- **Nutzen:** Blendet nicht.
- **Aufwand:** mittel (1 Bauteil + Software).

### 3.4 Schwellwert-Schritte mit „Beschleunigung"
- **IST:** 1 °C pro Encoder-Klick. Von 25 → 130 °C sind das 105 Klicks.
- **SOLL:** Erste 5 Klicks: 1 °C. Bei mehr als 3 Klicks/Sekunde: 5 °C/Klick.
- **Nutzen:** Schneller einstellbar.
- **Aufwand:** klein.

### 3.5 Werkseinstellung
- **IST:** Reset nur durch Re-Flash.
- **SOLL:** Geheime Tasten­kombination (z. B. Drehknopf 15 s halten ohne Zündung) → komplettes EEPROM löschen.
- **Aufwand:** trivial.

### 3.6 Service-Modus / Selbsttest
- **SOLL:** Beim Power-On 2 s alle Segmente testen („888"), dann 0,5 s Software-Version anzeigen (z. B. „201"), dann normalbetrieb.
- **Nutzen:** Fehler im Display sind sofort sichtbar.
- **Aufwand:** klein.

### 3.7 Diagnose-Ergebnis besser kommunizieren
- **IST:** Nach Diagnose werden die Codes rotierend angezeigt. Bei vielen Codes verliert man den Überblick.
- **SOLL:**
  - Erst „nXX" anzeigen (Anzahl), dann die Codes.
  - Bei 0 Codes „--- Pas" → null Probleme („Pass").
- **Nutzen:** Information auf einen Blick.
- **Aufwand:** klein.

### 3.8 Alarm bei kritischer Temperatur
- **SOLL:** Ab >110 °C Anzeige rot blinken (falls Anzeige zweifarbig ist) oder mit dem geplanten Buzzer piepen.
- **Nutzen:** Sicherheit (Motorschaden vermeiden).
- **Aufwand:** klein in Software, Hardware nur wenn Buzzer eingebaut wird.

---

## 4. Roadmap (Vorschlag)

| Phase | Inhalt | Aufwand | Risiko |
|-------|--------|---------|--------|
| **0 – sofort** | `ProMini_Optimized.ino` flashen, NTC-Parameter (`CFG_NTC_*`) auf realen NTC anpassen, BOD-Fuses brennen | 1 h | sehr klein, pin-kompatibel |
| **1 – nahe Zukunft** | UX-Punkte 3.1, 3.4, 3.6, 3.7, 3.8 in Software ergänzen | 1 Tag | klein |
| **2 – Hardware-Schutz** | TVS + Optokoppler an A3 (HW 2.3); Verpolungs­schutz (HW 2.4); LC-Filter | 2–3 h Lötarbeit | klein |
| **3 – Platinen-Revision** | D0-Konflikt lösen (HW 2.1), PWM-Helligkeit (HW 2.2), Diagnose-LED, optionaler Buzzer | 1 Wochenende KiCad + 1 Bestellung | mittel |
| **4 – Komfort** | Helligkeit per LDR / Klemme 58 (UX 3.3), Werkseinstellung, Service-Modus | 1 Tag | klein |
| **5 – Erweiterung** | CAN-Transceiver für Motronic ME (HW 2.8), OTA-Konfig per UART, CRC8 im EEPROM | offen | mittel-hoch |

---

## 5. NTC-Kennlinien — kalibrieren

Die `CFG_NTC_*`-Werte in der optimierten Firmware sind Default-Werte für einen typischen 10-kΩ-NTC mit Beta = 3950. Für deinen verbauten NTC bitte:

1. Im Eis­wasser (≈ 0 °C) und in heißem Wasser (≈ 80 °C, **Thermometer parallel**) messen.
2. Im Web-Tool (`Doku/index.html` → Tab „NTC-Tool") R25 und Beta solange anpassen, bis die zwei Messpunkte stimmen.
3. Werte nach `CFG_NTC_R25` / `CFG_NTC_BETA` übertragen.

Alternative: Als LUT in PROGMEM (256 ADC-Werte → 256 °C-Werte). Das NTC-Tool im Web-Doku exportiert auch direkt eine fertige LUT als C-Code.
