Hallo ihr tollen Menschen und Tüftler.
Ich bin dabei mir eine Lüftersteuerung für meinen Netzwerkschrank zu bauen.
Die temperaturabhängige Steuerung habe ich bereits hinbekommen, somit funktioniert das Einschalten, das Ausschalten und die temperaturabhängige lineare Lüfterkurve.
Nun möchte ich zusätzlich noch eine Blockade-Erkennung, zum Schutz der Lüfter einbauen. Dabei war die Grundidee, wenn eine Blockade erkannt wird, dann soll der betroffenen Lüfter ausgeschaltet werden.
Nach 60s soll ein erster Kickstart-Versuch mit 100% PWM erfolgen, nach weiteren 5s wird eine Prüfung mit einer Dauer von 10s gestartet und ausgewertet werden, ob der Lüfter nun läuft oder weiterhin blockiert ist.
Wenn Prüfung erfolgreich war und der Lüfter wieder läuft, dann darf die Automatik wieder die Regelung übernehmen.
Sollte die Prüfung fehlgeschlagen sein, weil Lüfter noch blockiert oder defekt, dann soll der Lüfter wieder ausgeschaltet werden und nach 60s soll ein zweiter Kickstart-Versuch unternommen werden, mit den selben Bedingungen wie aus dem ersten Versuch.
Ist die Prüfung diesmal erfolgreich und der Lüfter läuft wieder, darf die Automatik wieder übernehmen.
Schlägt die Prüfung abermals fehl, soll der Lüfter deaktiviert werden und nicht mehr steuerbar bleiben, bis ich mittels Quittierung (Button) bestätige, dass die Blockierung oder der Defekt beseitigt wurde.
Hier einmal mein betroffener Code-Schnipsel:
// *******************************************************
// 2) Wenn Kickstart aktiv -> Automatik überspringen
// *******************************************************
if (id(fan1_kick_active) || id(fan2_kick_active)) {
ESP_LOGI("auto", "Kickstart aktiv -> Automatik pausiert.");
}
// *******************************************************
// 3) Blockade-Erkennung (Lüfter 1)
// *******************************************************
if (!id(fan1_kick_active)) {
if (id(fan1_pwm_value).state > PWM_MIN_DETECT && id(fan1_rpm).state < 100) {
if (id(fan1_block_start) == 0) {
id(fan1_block_start) = millis(); // Ersten Erkennungszeitpunkt merken
} else if ((millis() - id(fan1_block_start)) > BLOCK_DETECT_MS) {
// nur beim erstmaligen Erkennen fault setzen
if (!id(fan1_fault)) {
ESP_LOGE("FAN1", "BLOCKADE erkannt!");
id(fan1_fault) = true;
id(fan1_kick_counter) = 0;
id(fan1_kick_phase) = 0;
// Lüfter SOFORT deaktivieren
id(fan1_pwm_value).publish_state(0);
id(fan1_pwm).set_level(0.0f);
// Kickstart-Delay starten (60s)
id(fan1_kick_delay_start) = millis();
// block_start bleibt gesetzt als Basiszeit
}
}
} else {
id(fan1_block_start) = 0;
}
}
// *******************************************************
// 4) Auto-Kickstart Lüfter 1 (max. 2 Versuche)
// *******************************************************
if (id(fan1_fault) && id(fan1_kick_counter) < 2) {
unsigned long now = millis();
// Start Kick, wenn Wartezeit abgelaufen und noch nicht aktiv
if (!id(fan1_kick_active) && (now - id(fan1_kick_delay_start)) > KICK_DELAY_MS) {
id(fan1_kick_counter) ++;
id(fan1_kick_active) = true;
id(fan1_kick_start_time) = now;
ESP_LOGW("FAN1", "KICKSTART - Versuch %d gestartet", id(fan1_kick_counter));
// setze 100% PWM
id(fan1_pwm_value).publish_state(100);
id(fan1_pwm).set_level(1.0f);
}
// Wenn Kick aktiv -> prüfe Ergebnis im Window [KICK_CHECK_START .. KICK_CHECK_START+KICK_CHECK_LEN]
if (id(fan1_kick_active)) {
unsigned long elapsed = now - id(fan1_kick_start_time);
// Prüfbeginn nach KICK_CHECK_START
if (elapsed >= KICK_CHECK_START && elapsed <= (KICK_CHECK_START + KICK_CHECK_LEN)) {
// während des Prüfwindows: check ob RPM konsistent über treshold (wir verwenden aktuelles + prev)
if (id(fan1_rpm).state > RPM_GOOD_TRESH && id(fan1_prev_rpm) > RPM_GOOD_TRESH) {
// Erfolg
ESP_LOGI("FAN1", "Kickstart erfolgreich (Versuch %d)!", id(fan1_kick_counter));
id(fan1_fault) = false;
id(fan1_kick_counter) = 0;
id(fan1_kick_phase) = 0;
id(fan1_kick_active) = false;
id(fan1_kick_start_time) = 0;
id(fan1_block_start) = 0;
// zurück zu Automatik-Sollwert
id(fan1_pwm_value).publish_state((int)round(speed));
id(fan1_pwm).set_level(speed_norm);
id(fan_master_value).publish_state((int)round(speed));
}
}
// Wenn Prüfwindow abgelaufen und noch kein Erfolg -> FEHLER
else if (elapsed > (KICK_CHECK_START + KICK_CHECK_LEN)) {
ESP_LOGE("FAN1", "Kickstart fehlgeschlagen (Versuch %d).", id(fan1_kick_counter));
// sofort ausschalten
id(fan1_pwm_value).publish_state(0);
id(fan1_pwm).set_level(0.0f);
id(fan1_kick_active) = false;
id(fan1_kick_start_time) = 0;
if (id(fan1_kick_counter) == 1) {
// erster Fehlversuch
id(fan1_kick_phase) = 1;
id(fan1_kick_delay_start) = now;
ESP_LOGW("FAN1", "Warte auf zweiten Kickstart...");
} else {
// zweiter Fehlversuch -> Sperre
id(fan1_kick_phase) = 2;
ESP_LOGE("FAN1", "2 Kickstarts fehlgeschlagen -> Lüfter 1 gesperrt bis Quittierung!");
}
}
}
}
Ich unterteile meine Tests nun in A, B und C.
Test A: (funktioniert perfekt)
Ich blockiere den Lüfter, schaue im LOG wann der Eintrag „BLOCKADE erkannt!“ auftaucht.
Anschließend entferne ich die Blockierung, warte bis der erste Kickstart-Versuch startet und wenn der Lüfter läuft, ob ihn die Automatik übernimmt.
Test B: (schlägt nach Kickstart bei Prüfung fehl)
Ich blockiere den Lüfter, schaue im LOG bis wieder „BLOCKADE erkannt“ erscheint, lasse aber diesmal die Blockade bestehen und warte, bis der erste Kickstart-Versuch begonnen hat und die Meldung „Kickstart fehlgeschlagen“ erscheint.
Nun entferne ich die Blockierung und warte erneut, bis der zweite Kickstart-Versuch eingeleitet wird.
Der Lüfter dreht nun hoch, aber es erscheint keine Meldung mehr im LOG, dass der Lüfter läuft, er dreht immer weiter auf voller Leistung und die Automatik übernimmt auch nicht mehr.
Test C: (schlägt vermutlich fehl, da Test B schon nicht funktioniert)
Ich blockiere den Lüfter, nun soll aber die Blockade verbleiben, bis der zweite Kickstart-Versuch fehlgeschlagen ist. Doch anstatt einen neuen Kickstart-Versuch zu unternehmen, soll nun der Lüfter eben gesperrt bleiben. Im LOG sollte der Eintrag “2 Kickstarts fehlgeschlagen → Lüfter 1 gesperrt bis Quittierung!” erscheinen und der betroffene Lüfter soll erst wieder bedienbar sein, wenn ich mittels Quittierung bestätige.
Ich drehe mit hier leider seit Wochen im Kreis und komme einfach nicht weiter.
Ich verstehe nicht, warum die Prüfung nach dem ersten Kickstart funktioniert und anläuft,
aber beim zweiten Versuch nicht.
Was setze ich hier falsch oder was fehlt mir?
Auch durch ChatGPT und ESPHome.io werde ich nicht schlauer.
Kann mir da vielleicht wer helfend unter die Arme greifen?