auto format changes and change max to MAX

This commit is contained in:
Tower committed 2026-04-15 17:18:42 +02:00
1 parent 2a9830017a
commit 9be7ab7ffb
1 file changed
+283 -208
+283 -208
View File
@@ -6,7 +6,7 @@
#include <DallasTemperature.h>
#include <RTClib.h>
#include <LiquidCrystal.h>
#include <max6675.h>
#include <MAX6675.h>
#include <Wire.h>
// Adafruit_GFX und Adafruit_SSD1306 entfernt – OLED aktuell nicht genutzt,
// das Objekt würde ~1 KB RAM als Frame-Buffer belegen.;
@@ -31,111 +31,120 @@ const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
// MAX6675 Abgastemperatur
const int max6675SO = 8;
const int max6675CS = 9;
const int max6675SO = 8;
const int max6675CS = 9;
const int max6675CLK = 10;
MAX6675 ktc(max6675CLK, max6675CS, max6675SO);
// Sensor-Adressen
DeviceAddress wohnung = {0x28, 0xA3, 0x9A, 0x61, 0x2F, 0x21, 0x01, 0x9E};
DeviceAddress Kunten = {0x28, 0x51, 0x4D, 0x56, 0x2F, 0x21, 0x01, 0x43};
DeviceAddress Koben = {0x28, 0x81, 0x87, 0x64, 0x2F, 0x21, 0x01, 0x57};
DeviceAddress Kunten = {0x28, 0x51, 0x4D, 0x56, 0x2F, 0x21, 0x01, 0x43};
DeviceAddress Koben = {0x28, 0x81, 0x87, 0x64, 0x2F, 0x21, 0x01, 0x57};
DeviceAddress Vorlauf = {0x28, 0x22, 0xF7, 0x60, 0x2F, 0x21, 0x01, 0x31};
DeviceAddress Aussen = {0x28, 0xE8, 0x19, 0x60, 0x2F, 0x21, 0x01, 0x19};
DeviceAddress Aussen = {0x28, 0xE8, 0x19, 0x60, 0x2F, 0x21, 0x01, 0x19};
// ============================================================
// Einstellbare Parameter (änderbar per Serial-Befehl vom Raspi)
// ============================================================
float time_adjust = 140.0; // Sekunden – Mischer-Laufzeit von ganz-zu bis ganz-auf
float neigung = 1.2; // Heizkurven-Neigung
int rtsoll = 20; // Raumtemperatur Soll (°C)
int nachtabs = 3; // Nachtabsenkung (Grad)
int tag_anfang = 4; // Stunde: Tagesbetrieb beginnt
int tag_ende = 20; // Stunde: Tagesbetrieb endet
int misch_begin = 12; // Heizung läuft wenn Aussentemperatur <= diesem Wert
float neigung = 1.2; // Heizkurven-Neigung
int rtsoll = 20; // Raumtemperatur Soll (°C)
int nachtabs = 3; // Nachtabsenkung (Grad)
int tag_anfang = 4; // Stunde: Tagesbetrieb beginnt
int tag_ende = 20; // Stunde: Tagesbetrieb endet
int misch_begin = 12; // Heizung läuft wenn Aussentemperatur <= diesem Wert
// ============================================================
// Interne Zustandsvariablen
// ============================================================
float temp_aussen = 0;
float temp_aussen = 0;
float temp_vorlauf = 0;
float temp_koben = 0;
float temp_kunten = 0;
float temp_koben = 0;
float temp_kunten = 0;
float temp_wohnung = 0;
float temp_abgas = 0;
float temp_abgas = 0;
float vtsoll = 0;
float niveau = 0;
float darw = 0;
float vtsoll = 0;
float niveau = 0;
float darw = 0;
int stellung = 0; // aktuelle Mischerstellung in Sekunden (0 = kalt, time_adjust = warm)
int stellung = 0; // aktuelle Mischerstellung in Sekunden (0 = kalt, time_adjust = warm)
int mischeron = 0;
const int arranz = 7; // Anzahl Anzeige-Einträge
// ============================================================
// System-Zustandsautomat
// ============================================================
enum SystemState { STARTUP, RUNNING };
enum SystemState
{
STARTUP,
RUNNING
};
SystemState systemState = STARTUP;
unsigned long startupStart = 0;
// ============================================================
// Sensor-Timing
// ============================================================
unsigned long sensorTimer = 0;
const unsigned long SENSOR_INTERVAL = 10000UL; // alle 10 Sekunden Temp lesen
bool sensorsRequested = false;
unsigned long sensorTimer = 0;
const unsigned long SENSOR_INTERVAL = 10000UL; // alle 10 Sekunden Temp lesen
bool sensorsRequested = false;
unsigned long sensorRequestTime = 0;
const unsigned long SENSOR_WAIT = 800UL; // DS18B20 Konvertierungszeit
const unsigned long SENSOR_WAIT = 800UL; // DS18B20 Konvertierungszeit
// ============================================================
// Mischer-Puls (non-blocking, abweichungsabhängige Pulszeit)
// ============================================================
enum MischerPulse { PULSE_NONE, PULSE_PLUS, PULSE_MINUS };
MischerPulse currentPulse = PULSE_NONE;
enum MischerPulse
{
PULSE_NONE,
PULSE_PLUS,
PULSE_MINUS
};
MischerPulse currentPulse = PULSE_NONE;
unsigned long mischerPulseStart = 0;
unsigned long activePulseTime = 4000UL; // wird vor jedem Puls gesetzt
unsigned long activePulseTime = 4000UL; // wird vor jedem Puls gesetzt
// Zonalregelung: Schwellwerte der Vorlauf-Abweichung (°C)
// Der Sensor sitzt außen am Rohr → Totzeit ca. 2-5 Min.
// Bei großer Abweichung aggressiv regeln, bei kleiner vorsichtig (kein Überschwingen)
const float ZONE_SPRINT = 8.0; // >8°C Abweichung → maximale Energie
const float ZONE_JOGGING = 4.0; // 4-8°C → zügig
const float ZONE_NORMAL = 1.5; // 1.5-4°C → fein / Totband-Grenze
const float ZONE_SPRINT = 8.0; // >8°C Abweichung → maximale Energie
const float ZONE_JOGGING = 4.0; // 4-8°C → zügig
const float ZONE_NORMAL = 1.5; // 1.5-4°C → fein / Totband-Grenze
// Pulszeiten pro Zone (öffnen / Richtung +)
const unsigned long PULS_SPRINT = 12000UL; // 12 Sekunden
const unsigned long PULS_JOGGING = 6000UL; // 6 Sekunden
const unsigned long PULS_NORMAL = 3000UL; // 3 Sekunden
const unsigned long PULS_SPRINT = 12000UL; // 12 Sekunden
const unsigned long PULS_JOGGING = 6000UL; // 6 Sekunden
const unsigned long PULS_NORMAL = 3000UL; // 3 Sekunden
// Schließen (Richtung −): zonenabhängig, aber etwas kürzer als Plus (Sensor-Trägheit)
const unsigned long PULS_MINUS_SPRINT = 8000UL; // 8 Sekunden
const unsigned long PULS_MINUS_SPRINT = 8000UL; // 8 Sekunden
const unsigned long PULS_MINUS_JOGGING = 4000UL; // 4 Sekunden
const unsigned long PULS_MINUS_NORMAL = 2000UL; // 2 Sekunden
const unsigned long PULS_MINUS_NORMAL = 2000UL; // 2 Sekunden
// Check-Intervalle pro Zone
const unsigned long CHECK_SPRINT = 25000UL; // 25 Sekunden
const unsigned long CHECK_SPRINT = 25000UL; // 25 Sekunden
const unsigned long CHECK_JOGGING = 45000UL; // 45 Sekunden
const unsigned long CHECK_NORMAL = 70000UL; // 70 Sekunden
const unsigned long CHECK_NORMAL = 70000UL; // 70 Sekunden
const unsigned long CHECK_TOTBAND = 90000UL; // 90 Sekunden (nur Überwachung)
// Wartezeit zwischen Mischer-Korrekturen (wird dynamisch aus Zone gesetzt)
unsigned long mischerCheckTimer = 0;
unsigned long mischerCheckTimer = 0;
unsigned long dynamicCheckInterval = CHECK_TOTBAND; // aktuell gültiges Intervall
// Anlaufphase: nach mischeron 0→1 weiß der Regler dass das Rohr kalt ist.
// → erste Prüfung nach 20 s, danach 5 Min. lang aggressiverer Modus.
unsigned long mischeronStart = 0;
bool mischeronWarmup = false; // true = Anlaufphase aktiv
const unsigned long WARMUP_DAUER = 300000UL; // 5 Minuten Anlaufphase
unsigned long mischeronStart = 0;
bool mischeronWarmup = false; // true = Anlaufphase aktiv
const unsigned long WARMUP_DAUER = 300000UL; // 5 Minuten Anlaufphase
// ============================================================
// Display-Zyklus (ersetzt delay(3000) im Display-Loop)
// ============================================================
unsigned long displayTimer = 0;
const unsigned long DISPLAY_INTERVAL = 3000UL; // 3 Sekunden pro Sensor
unsigned long displayTimer = 0;
const unsigned long DISPLAY_INTERVAL = 3000UL; // 3 Sekunden pro Sensor
int displayIndex = 0;
bool showProzent = false;
bool showProzent = false;
unsigned long prozentTimer = 0;
const unsigned long PROZENT_DURATION = 3000UL;
@@ -148,31 +157,33 @@ const unsigned long SERIAL_OUT_INTERVAL = 2000UL; // alle 2 Sekunden JSON senden
// ============================================================
// SETUP
// ============================================================
void setup() {
void setup()
{
Serial.begin(9600);
Serial.setTimeout(100); // readStringUntil() bricht nach 100ms ab statt 1s
//rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
sensors.begin();
rtc.begin();
const int relaisPins[] = {
relais1,
relais2,
relais3,
relais4,
relais5,
relais6,
relais7,
relais8
};
for (int i = 0; i < 8; i++) {
relais1,
relais2,
relais3,
relais4,
relais5,
relais6,
relais7,
relais8};
for (int i = 0; i < 8; i++)
{
pinMode(relaisPins[i], OUTPUT);
digitalWrite(relaisPins[i], HIGH); // HIGH = Relais aus (ActiveLow)
}
// Kesselpumpe sofort an wenn Abgas heiß
if (ktc.readCelsius() >= 40) {
if (ktc.readCelsius() >= 40)
{
digitalWrite(relais5, LOW);
}
@@ -184,32 +195,35 @@ void setup() {
// Mischer auf ganz-kalt fahren (non-blocking: Relais an, Zeit merken)
digitalWrite(relais1, LOW);
startupStart = millis();
systemState = STARTUP;
systemState = STARTUP;
}
// ============================================================
// LOOP
// ============================================================
void loop() {
void loop()
{
unsigned long now = millis();
// --- STARTUP: Mischer vollständig zurückdrehen ---
if (systemState == STARTUP) {
if (now - startupStart >= (unsigned long)(time_adjust * 1000UL)) {
if (systemState == STARTUP)
{
if (now - startupStart >= (unsigned long)(time_adjust * 1000UL))
{
digitalWrite(relais1, HIGH); // Relais aus – Mischer stoppt
stellung = 0;
stellung = 0;
systemState = RUNNING;
// Timer initialisieren
sensorTimer = now;
displayTimer = now;
serialOutTimer = now;
sensorTimer = now;
displayTimer = now;
serialOutTimer = now;
mischerCheckTimer = now;
// Erste Sensorabfrage starten
sensors.requestTemperatures();
sensorsRequested = true;
sensorRequestTime = now;
sensorsRequested = true;
sensorRequestTime = now;
lcd.clear();
lcd.print("Bereit");
@@ -223,15 +237,17 @@ void loop() {
handleSerialInput();
// Sensorabfrage periodisch starten
if (!sensorsRequested && (now - sensorTimer >= SENSOR_INTERVAL)) {
sensorTimer = now;
if (!sensorsRequested && (now - sensorTimer >= SENSOR_INTERVAL))
{
sensorTimer = now;
sensors.requestTemperatures();
sensorsRequested = true;
sensorRequestTime = now;
sensorsRequested = true;
sensorRequestTime = now;
}
// Sensorwerte auslesen nach Konvertierungszeit
if (sensorsRequested && (now - sensorRequestTime >= SENSOR_WAIT)) {
if (sensorsRequested && (now - sensorRequestTime >= SENSOR_WAIT))
{
sensorsRequested = false;
readSensors();
updateLogic(now);
@@ -244,7 +260,8 @@ void loop() {
updateDisplay(now);
// JSON an Raspberry Pi senden
if (now - serialOutTimer >= SERIAL_OUT_INTERVAL) {
if (now - serialOutTimer >= SERIAL_OUT_INTERVAL)
{
serialOutTimer = now;
sendSerialJSON();
}
@@ -255,24 +272,29 @@ void loop() {
// ============================================================
// DS18B20 Fehlerwerte: -127°C = Kabelbruch/nicht angeschlossen, 85°C = Initialisierungswert
// Bei Fehler: letzten gültigen Wert behalten (wird nicht überschrieben)
#define SENSOR_ERR_LOW -100.0
#define SENSOR_ERR_HIGH 84.0
#define SENSOR_ERR_LOW -100.0
#define SENSOR_ERR_HIGH 84.0
static void readSensor(float &dest, float raw) {
if (raw > SENSOR_ERR_LOW && raw < SENSOR_ERR_HIGH) {
static void readSensor(float &dest, float raw)
{
if (raw > SENSOR_ERR_LOW && raw < SENSOR_ERR_HIGH)
{
dest = raw;
} else {
}
else
{
Serial.print(F("# Sensorfehler: "));
Serial.println(raw, 1);
// dest bleibt unverändert (letzter gültiger Wert)
}
}
void readSensors() {
readSensor(temp_aussen, sensors.getTempC(Aussen));
void readSensors()
{
readSensor(temp_aussen, sensors.getTempC(Aussen));
readSensor(temp_vorlauf, sensors.getTempC(Vorlauf));
readSensor(temp_koben, sensors.getTempC(Koben));
readSensor(temp_kunten, sensors.getTempC(Kunten));
readSensor(temp_koben, sensors.getTempC(Koben));
readSensor(temp_kunten, sensors.getTempC(Kunten));
readSensor(temp_wohnung, sensors.getTempC(wohnung));
temp_abgas = ktc.readCelsius(); // MAX6675 hat eigenes Fehlerprotokoll
}
@@ -280,60 +302,71 @@ void readSensors() {
// ============================================================
// Heizungslogik
// ============================================================
void updateLogic(unsigned long now) {
void updateLogic(unsigned long now)
{
DateTime aktuell = rtc.now();
int jetzt = aktuell.hour();
// Kesselpumpe: an wenn Abgas >= 40°C
if (temp_abgas >= 40) {
if (temp_abgas >= 40)
{
digitalWrite(relais5, LOW);
} else {
}
else
{
digitalWrite(relais5, HIGH);
}
// Heizkurve: Vorlaufsoll berechnen
darw = temp_aussen - (float)rtsoll;
float rtsoll_eff = (float)rtsoll;
if (jetzt < tag_anfang || jetzt >= tag_ende) {
if (jetzt < tag_anfang || jetzt >= tag_ende)
{
rtsoll_eff -= (float)nachtabs; // Nachtabsenkung
}
vtsoll = rtsoll_eff + niveau
- neigung * darw * (1.4347 + 0.021 * darw + 247.9e-6 * darw * darw);
vtsoll = rtsoll_eff + niveau - neigung * darw * (1.4347 + 0.021 * darw + 247.9e-6 * darw * darw);
// Sicherheitsbegrenzung: vtsoll physikalisch sinnvoll halten
// Schützt vor Extremwerten bei Sensorfehler (z.B. -127°C Kabelbruch)
if (vtsoll < 10.0) vtsoll = 10.0;
if (vtsoll > 75.0) vtsoll = 75.0;
if (vtsoll < 10.0)
vtsoll = 10.0;
if (vtsoll > 75.0)
vtsoll = 75.0;
// Heizkreispumpe / Mischer-Freigabe
bool pufferOK = (temp_koben >= vtsoll);
bool pufferOK = (temp_koben >= vtsoll);
bool aussenKalt = (temp_aussen <= (float)misch_begin);
bool abgasHot = (temp_abgas >= 40);
bool abgasHot = (temp_abgas >= 40);
int mischeronAlt = mischeron;
if (aussenKalt && (pufferOK || abgasHot)) {
if (aussenKalt && (pufferOK || abgasHot))
{
digitalWrite(relais3, LOW);
mischeron = 1;
} else {
}
else
{
digitalWrite(relais3, HIGH);
mischeron = 0;
}
// Anlaufphase erkennen: wenn Mischer gerade eingeschaltet wurde
if (mischeron == 1 && mischeronAlt == 0) {
if (mischeron == 1 && mischeronAlt == 0)
{
// Übergang 0→1: Rohr ist kalt, sofort erste Prüfung in 20 Sekunden
mischeronWarmup = true;
mischeronStart = now;
mischeronWarmup = true;
mischeronStart = now;
mischerCheckTimer = now - CHECK_SPRINT + 20000UL; // erste Prüfung nach 20s
Serial.println(F("# Anlaufphase gestartet"));
}
if (mischeron == 0) {
if (mischeron == 0)
{
mischeronWarmup = false; // Anlaufphase beenden wenn Heizung aus
}
bool inWarmup = mischeronWarmup && (now - mischeronStart < WARMUP_DAUER);
// ── Zonalregelung ──────────────────────────────────────────────────────────
// Abweichung positiv = Vorlauf zu kalt, negativ = zu warm
float abweichung = vtsoll - temp_vorlauf;
float abweichung = vtsoll - temp_vorlauf;
float abweichungAbs = fabs(abweichung);
// Regelzone bestimmen → gibt Pulszeit und Check-Intervall vor.
@@ -341,46 +374,66 @@ void updateLogic(unsigned long now) {
// Würden wir es mid-flight ändern, würde handleMischerPulse() den Puls
// zum falschen Zeitpunkt beenden und stellung falsch berechnen.
// Während Anlaufphase: eine Zone aggressiver, da das Rohr erst aufgeheizt werden muss.
if (abweichungAbs > ZONE_SPRINT || (inWarmup && abweichungAbs > ZONE_JOGGING)) {
if (abweichungAbs > ZONE_SPRINT || (inWarmup && abweichungAbs > ZONE_JOGGING))
{
dynamicCheckInterval = CHECK_SPRINT;
if (currentPulse == PULSE_NONE) activePulseTime = PULS_SPRINT;
} else if (abweichungAbs > ZONE_JOGGING || (inWarmup && abweichungAbs > ZONE_NORMAL)) {
if (currentPulse == PULSE_NONE)
activePulseTime = PULS_SPRINT;
}
else if (abweichungAbs > ZONE_JOGGING || (inWarmup && abweichungAbs > ZONE_NORMAL))
{
dynamicCheckInterval = CHECK_JOGGING;
if (currentPulse == PULSE_NONE) activePulseTime = PULS_JOGGING;
} else if (abweichungAbs > ZONE_NORMAL) {
if (currentPulse == PULSE_NONE)
activePulseTime = PULS_JOGGING;
}
else if (abweichungAbs > ZONE_NORMAL)
{
dynamicCheckInterval = CHECK_NORMAL;
if (currentPulse == PULSE_NONE) activePulseTime = PULS_NORMAL;
} else {
if (currentPulse == PULSE_NONE)
activePulseTime = PULS_NORMAL;
}
else
{
// Totband: Mischer sitzt richtig, nur überwachen
dynamicCheckInterval = CHECK_TOTBAND;
if (currentPulse == PULSE_NONE) activePulseTime = PULS_NORMAL;
if (currentPulse == PULSE_NONE)
activePulseTime = PULS_NORMAL;
}
// Mischer regeln – nur wenn Heizkreis läuft, kein Puls aktiv
// und das zonenabhängige Check-Intervall abgelaufen ist
if (mischeron == 1 && currentPulse == PULSE_NONE &&
(now - mischerCheckTimer >= dynamicCheckInterval)) {
(now - mischerCheckTimer >= dynamicCheckInterval))
{
if (abweichung > ZONE_NORMAL && stellung < (int)time_adjust) {
if (abweichung > ZONE_NORMAL && stellung < (int)time_adjust)
{
// Mischer weiter öffnen (wärmer)
// activePulseTime wurde oben zonenabhängig gesetzt
currentPulse = PULSE_PLUS;
currentPulse = PULSE_PLUS;
mischerPulseStart = now;
digitalWrite(relais2, LOW);
Serial.print(F("# Mische + Puls="));
Serial.print(activePulseTime / 1000);
Serial.print(F("s Abw="));
Serial.println(abweichung, 1);
} else if (abweichung < -ZONE_NORMAL && stellung > 0) {
}
else if (abweichung < -ZONE_NORMAL && stellung > 0)
{
// Mischer schließen (kälter) – zonenabhängig, etwas kürzer als Plus
if (abweichungAbs > ZONE_SPRINT) {
if (abweichungAbs > ZONE_SPRINT)
{
activePulseTime = PULS_MINUS_SPRINT;
} else if (abweichungAbs > ZONE_JOGGING) {
}
else if (abweichungAbs > ZONE_JOGGING)
{
activePulseTime = PULS_MINUS_JOGGING;
} else {
}
else
{
activePulseTime = PULS_MINUS_NORMAL;
}
currentPulse = PULSE_MINUS;
currentPulse = PULSE_MINUS;
mischerPulseStart = now;
digitalWrite(relais1, LOW);
Serial.print(F("# Mische - Abw="));
@@ -392,73 +445,84 @@ void updateLogic(unsigned long now) {
// ============================================================
// Mischer-Puls beenden wenn Zeit abgelaufen
// ============================================================
void handleMischerPulse(unsigned long now) {
if (currentPulse == PULSE_NONE) return;
void handleMischerPulse(unsigned long now)
{
if (currentPulse == PULSE_NONE)
return;
if (now - mischerPulseStart >= activePulseTime) {
if (now - mischerPulseStart >= activePulseTime)
{
// Stellung um die tatsächliche Pulszeit (in Sekunden) aktualisieren
int pulsSekunden = (int)(activePulseTime / 1000UL);
if (currentPulse == PULSE_PLUS) {
if (currentPulse == PULSE_PLUS)
{
digitalWrite(relais2, HIGH);
stellung += pulsSekunden;
if (stellung > (int)time_adjust) stellung = (int)time_adjust;
} else {
if (stellung > (int)time_adjust)
stellung = (int)time_adjust;
}
else
{
digitalWrite(relais1, HIGH);
stellung -= pulsSekunden;
if (stellung < 0) stellung = 0;
if (stellung < 0)
stellung = 0;
}
currentPulse = PULSE_NONE;
currentPulse = PULSE_NONE;
mischerCheckTimer = now; // Check-Timer neu starten (nächstes Intervall läuft ab jetzt)
// Prozentanzeige für 3 Sekunden einblenden
showProzent = true;
showProzent = true;
prozentTimer = now;
//showProzentDisplay();
// showProzentDisplay();
}
}
// ============================================================
// Display-Zyklus (non-blocking)
// ============================================================
void updateDisplay(unsigned long now) {
void updateDisplay(unsigned long now)
{
// Prozentanzeige: solange aktiv, nichts anderes zeigen
if (showProzent) {
if (now - prozentTimer >= PROZENT_DURATION) {
showProzent = false;
if (showProzent)
{
if (now - prozentTimer >= PROZENT_DURATION)
{
showProzent = false;
displayTimer = now; // Zyklus-Timer zurücksetzen
}
return;
}
if (now - displayTimer >= DISPLAY_INTERVAL) {
if (now - displayTimer >= DISPLAY_INTERVAL)
{
displayTimer = now;
displayIndex = (displayIndex + 1) % arranz;
showSensor();
}
}
//void showProzentDisplay() {
// float proz = (stellung * 100.0) / time_adjust;
// lcd.clear();
// lcd.print("Mischer ");
// lcd.print(proz, 0);
// lcd.print("%");
// lcd.setCursor(0, 1);
// lcd.print("geoeffnet");
//}
// void showProzentDisplay() {
// float proz = (stellung * 100.0) / time_adjust;
// lcd.clear();
// lcd.print("Mischer ");
// lcd.print(proz, 0);
// lcd.print("%");
// lcd.setCursor(0, 1);
// lcd.print("geoeffnet");
// }
void showSensor() {
void showSensor()
{
char Uhr[] = "hh:mm";
DateTime aktuell = rtc.now();
float sensorVal[7] = {
temp_aussen, temp_vorlauf, vtsoll,
temp_koben, temp_kunten, temp_wohnung, temp_abgas
};
const char* ort[7] = {
"Aussentemp", "Vorlauf ist", "Vorlauf soll",
"Puffer Oben", "Puffer unt.", "Heizung", "Abgas"
};
temp_aussen, temp_vorlauf, vtsoll,
temp_koben, temp_kunten, temp_wohnung, temp_abgas};
const char *ort[7] = {
"Aussentemp", "Vorlauf ist", "Vorlauf soll",
"Puffer Oben", "Puffer unt.", "Heizung", "Abgas"};
lcd.clear();
lcd.begin(16, 2);
@@ -471,7 +535,7 @@ void showSensor() {
// showProzentDisplay();
// Sonderanzeige Mischer-Grenzwerte – nur wenn Mischer aktiv läuft
//if (mischeron) {
// if (mischeron) {
// if (stellung >= (int)time_adjust) {
// lcd.clear();
// lcd.print("Mischer max!");
@@ -489,60 +553,60 @@ void showSensor() {
// ============================================================
// JSON-Ausgabe an Raspberry Pi
// ============================================================
void sendSerialJSON() {
void sendSerialJSON()
{
char buffer[512];
float abw = vtsoll - temp_vorlauf;
snprintf(buffer, sizeof(buffer),
"{"
"\"aussentemp\":%.1f,"
"\"vorlauf_ist\":%.1f,"
"\"vorlauf_soll\":%.1f,"
"\"kessel_oben\":%.1f,"
"\"kessel_unten\":%.1f,"
"\"wohnung\":%.1f,"
"\"abgas\":%.1f,"
"\"stellung\":%d,"
"\"mischeron\":%d,"
"\"neigung\":%.2f,"
"\"rtsoll\":%d,"
"\"misch_begin\":%d,"
"\"nachtabs\":%d,"
"\"tag_anfang\":%d,"
"\"tag_ende\":%d,"
"\"time_adjust\":%d,"
"\"abweichung\":%.1f,"
"\"check_intervall\":%ld,"
"\"puls_zeit\":%ld,"
"\"puls_aktiv\":%d,"
"\"warmup\":%d"
"}",
"{"
"\"aussentemp\":%.1f,"
"\"vorlauf_ist\":%.1f,"
"\"vorlauf_soll\":%.1f,"
"\"kessel_oben\":%.1f,"
"\"kessel_unten\":%.1f,"
"\"wohnung\":%.1f,"
"\"abgas\":%.1f,"
"\"stellung\":%d,"
"\"mischeron\":%d,"
"\"neigung\":%.2f,"
"\"rtsoll\":%d,"
"\"misch_begin\":%d,"
"\"nachtabs\":%d,"
"\"tag_anfang\":%d,"
"\"tag_ende\":%d,"
"\"time_adjust\":%d,"
"\"abweichung\":%.1f,"
"\"check_intervall\":%ld,"
"\"puls_zeit\":%ld,"
"\"puls_aktiv\":%d,"
"\"warmup\":%d"
"}",
temp_aussen,
temp_vorlauf,
vtsoll,
temp_koben,
temp_kunten,
temp_wohnung,
temp_abgas,
temp_aussen,
temp_vorlauf,
vtsoll,
temp_koben,
temp_kunten,
temp_wohnung,
temp_abgas,
stellung,
mischeron,
neigung,
rtsoll,
misch_begin,
nachtabs,
tag_anfang,
tag_ende,
time_adjust,
stellung,
mischeron,
neigung,
rtsoll,
misch_begin,
nachtabs,
tag_anfang,
tag_ende,
time_adjust,
abw,
dynamicCheckInterval / 1000,
activePulseTime / 1000,
(currentPulse != PULSE_NONE) ? 1 : 0,
mischeronWarmup ? 1 : 0
);
abw,
dynamicCheckInterval / 1000,
activePulseTime / 1000,
(currentPulse != PULSE_NONE) ? 1 : 0,
mischeronWarmup ? 1 : 0);
Serial.println(buffer);
}
@@ -551,31 +615,42 @@ void sendSerialJSON() {
// Serielle Befehle vom Raspberry Pi verarbeiten
// Format: SET <key> <value>\n
// ============================================================
void handleSerialInput() {
if (!Serial.available()) return;
void handleSerialInput()
{
if (!Serial.available())
return;
String line = Serial.readStringUntil('\n');
line.trim();
if (!line.startsWith(F("SET "))) return;
if (!line.startsWith(F("SET ")))
return;
// "SET key value" parsen
int sp1 = line.indexOf(' '); // nach "SET"
int sp1 = line.indexOf(' '); // nach "SET"
int sp2 = line.indexOf(' ', sp1 + 1);
if (sp1 < 0 || sp2 < 0) return;
if (sp1 < 0 || sp2 < 0)
return;
String key = line.substring(sp1 + 1, sp2);
String val = line.substring(sp2 + 1);
val.trim();
bool ok = true;
if (key == F("neigung")) neigung = val.toFloat();
else if (key == F("rtsoll")) rtsoll = val.toInt();
else if (key == F("nachtabs")) nachtabs = val.toInt();
else if (key == F("misch_begin")) misch_begin = val.toInt();
else if (key == F("tag_anfang")) tag_anfang = val.toInt();
else if (key == F("tag_ende")) tag_ende = val.toInt();
else ok = false;
if (key == F("neigung"))
neigung = val.toFloat();
else if (key == F("rtsoll"))
rtsoll = val.toInt();
else if (key == F("nachtabs"))
nachtabs = val.toInt();
else if (key == F("misch_begin"))
misch_begin = val.toInt();
else if (key == F("tag_anfang"))
tag_anfang = val.toInt();
else if (key == F("tag_ende"))
tag_ende = val.toInt();
else
ok = false;
// Bestätigung zurücksenden
Serial.print(F("{\"ok\":"));