//https://github.com/MakeMagazinDE/Taupunktluefter/blob/main/Taupunkt_Lueftung.ino
//https://forum.arduino.cc/t/hilfe-bei-einer-Implen-pumpensteuerung/509398/7
//https://wokwi.com/arduino/projects/324484140498944595
//24.02.2022
// Dieser Code benötigt die folgenden Libraries:
#include "DHT.h"
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
//#include <avr/wdt.h>
//Messinterval Feuchte in ms
const long interval = 7000; //Intervall für aktualisierung Taupunkte und Logik
unsigned long previousMillis = 0;
int ledState = LOW;
//Taupunkte Speicher
float Taupunkt_1 = 0.0;
float Taupunkt_2 = 0.0;
//RELAIS OUTPUTS (FALSE = EIN)
const int DO_00 = 22; //Lüftergruppe Zuluft Keller
const int DO_01 = 24; //Lüftergruppe Abluft Werkstatt
const int DO_02 = 26; //Lüftergruppe Abluft Keller
const int DO_03 = 28; //Freigabe Luftentfeuchter
const int DO_04 = 30; //Reserve
const int DO_05 = 32; //Reserve
const int DO_06 = 34; //Reserve
const int DO_07 = 36; //12V KondenAtpumpe
//direkte OUTPUTS (TRUE = EIN)
const int DO_08 = 46; //Fehler LED
const int DO_09 = 44; //Status LED
//INPUTS
const int DI_00 = 23; //LSH Hochschaltpunkt Pumpstation
const int DI_01 = 25; //LSL Tiefschaltpunkt Pumpstation
const int DI_02 = 27; //Reserve für HAND EIN ENTFEUCHTER
const int DI_03 = 29; //Reserve für HAND EIN LÜFTER
const int DI_04 = 31; //Reserve für Türkontakt Werkstatt
const int DI_05 = 33; //Reserve
const int DI_06 = 35; //Reserve
const int DI_07 = 37; //Reserve
//INPUTS DHT21 Sensoren
#define DHTPIN_1 5 // Datenleitung für den DHT-Sensor 1 (innen)
#define DHTPIN_2 4 // Datenleitung für den DHT-Sensor 2 (außen)
#define RELAIS_EIN LOW //Invertierung der Ausgänge
#define RELAIS_AUS HIGH
bool trocknen; //trocknen durch Aussenluft möglich
bool fehler = true;//Fehler bei Trocknungs Logik
#define DHTTYPE_1 DHT22 // Auf DHT 21 geändert / vorher DHTTYPE_1 DHT22
#define DHTTYPE_2 DHT22 //
// ******* Korrekturwerte der einzelnen Sensorwerte *******
#define Korrektur_t_1 0 // Korrekturwert Innensensor Temperatur / geändert auf 0 vorher -3
#define Korrektur_t_2 0 // Korrekturwert Außensensor Temperatur / geändert auf 0 vorher -4
#define Korrektur_h_1 0 // Korrekturwert Innensensor Luftfeuchtigkeit
#define Korrektur_h_2 0 // Korrekturwert Außensensor Luftfeuchtigkeit
//***********************************************************
#define SCHALTmin 5.0 // minimaler Taupunktunterschied, bei dem das Relais schaltet
#define HYSTERESE 1.0 // Abstand von Ein- und Ausschaltpunkt
#define TEMP1_min 7.0 // Minimale Innentemperatur, bei der die Lüftung aktiviert wird / geändert auf 7.5 vorher 10.0
#define TEMP2_min -10.0 // Minimale Außentemperatur, bei der die Lüftung aktiviert wird
#define h1_soll 55.0 //Soll Luftfeuchte im Keller
DHT dht1(DHTPIN_1, DHTTYPE_1); //Der Innensensor wird ab jetzt mit dht1 angesprochen
DHT dht2(DHTPIN_2, DHTTYPE_2); //Der Außensensor wird ab jetzt mit dht2 angesprochen
LiquidCrystal_I2C lcd(0x27,20,4); // LCD: I2C-Addresse und Displaygröße setzen
void setup() { //Setup
pinMode(DO_00, OUTPUT);
pinMode(DO_01, OUTPUT);
pinMode(DO_02, OUTPUT);
pinMode(DO_03, OUTPUT);
pinMode(DO_04, OUTPUT);
pinMode(DO_05, OUTPUT);
pinMode(DO_06, OUTPUT);
pinMode(DO_07, OUTPUT);
pinMode(DO_08, OUTPUT);
pinMode(DO_09, OUTPUT);
digitalWrite(DO_00, RELAIS_AUS); // Relais ausschalten
digitalWrite(DO_01, RELAIS_AUS);
digitalWrite(DO_02, RELAIS_AUS);
digitalWrite(DO_03, RELAIS_AUS);
digitalWrite(DO_04, RELAIS_AUS);
digitalWrite(DO_05, RELAIS_AUS);
digitalWrite(DO_06, RELAIS_AUS);
digitalWrite(DO_07, RELAIS_AUS);
digitalWrite(DO_08,LOW);
digitalWrite(DO_09,LOW);
pinMode(DI_00, INPUT_PULLUP);
pinMode(DI_01, INPUT_PULLUP);
pinMode(DI_02, INPUT);
pinMode(DI_03, INPUT);
pinMode(DI_04, INPUT);
pinMode(DI_05, INPUT);
pinMode(DI_06, INPUT);
pinMode(DI_07, INPUT_PULLUP);
Serial.begin(9600); // Serielle Ausgabe, falls noch kein LCD angeschlossen ist
Serial.println(F("Setup Sensoren.."));
lcd.init();
lcd.backlight();
lcd.setCursor(2,0);
lcd.print(F("Setup Sensoren.."));
byte Grad[8] = {B00111,B00101,B00111,B0000,B00000,B00000,B00000,B00000}; // Sonderzeichen ° definieren
lcd.createChar(0, Grad);
byte Strich[8] = {B00100,B00100,B00100,B00100,B00100,B00100,B00100,B00100}; // Sonderzeichen senkrechter Strich definieren
lcd.createChar(1, Strich);
dht1.begin(); // Sensoren starten
dht2.begin();
}
//----------------------------------------------------------LOOP START
void loop() {
//Temp und Luftfeuchte lesen und in Speicher schreiben -> Aktualisiere Werte jeden Zyklus
float h1 = dht1.readHumidity()+Korrektur_h_1; // Innenluftfeuchtigkeit auslesen und unter „h1“ speichern
float t1 = dht1.readTemperature()+ Korrektur_t_1; // Innentemperatur auslesen und unter „t1“ speichern
float h2 = dht2.readHumidity()+Korrektur_h_2; // Außenluftfeuchtigkeit auslesen und unter „h2“ speichern
float t2 = dht2.readTemperature()+ Korrektur_t_2; // Außentemperatur auslesen und unter „t2“ speichern
if (fehler == true) // wenn fehler true Prüfen, ob gültige Werte von den Sensoren kommen
{
fehler = false;
if (isnan(h1) || isnan(t1) || h1 > 100 || h1 < 1 || t1 < -30 || t1 > 80 ) {
Serial.println(F("Fehler beim Auslesen vom 1. Sensor!"));
lcd.setCursor(0,1);
lcd.print(F("Fehler Sensor 1"));
fehler = true;
}else {
lcd.setCursor(0,1);
lcd.print(F("Sensor 1 in Ordnung"));
}
delay(2000); // Zeit um das Display zu lesen
if (isnan(h2) || isnan(t2) || h2 > 100 || h2 < 1 || t2 < -30 || t2 > 80) {
Serial.println(F("Fehler beim Auslesen vom 2. Sensor!"));
lcd.setCursor(0,2);
lcd.print(F("Fehler Sensor 2"));
fehler = true;
} else {
lcd.setCursor(0,2);
lcd.print(F("Sensor 2 in Ordnung"));
}
delay(2000); // Zeit um das Display zu lesen
}
if (isnan(h1) || isnan(t1) || isnan(h2) || isnan(t2)) fehler = true;
if (fehler == true) {
digitalWrite(DO_00, RELAIS_AUS); // Relais ausschalten
digitalWrite(DO_08, HIGH); //Fehler LED an
lcd.clear();
lcd.setCursor(0,0);
lcd.print(F("SENSORFEHLER "));
lcd.setCursor(0,1);
lcd.print(F("LUEFTUNG AUS"));
while (1){ // Endlosschleife
pumpen();//Pumpfunktion hier auch aufrufen? -Pumpe soll auch laufen wenn Lüftung ein Problem hat
};
}
//Messintervall Taupunkte
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// letzten Ausführungszeitpunkt speichern
previousMillis = currentMillis;
//**** Taupunkte errechnen********
Taupunkt_1 = taupunkt(t1, h1);
Taupunkt_2 = taupunkt(t2, h2);
// wenn aus dann ein sonst aus
if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
}
// schreibe Status LED
digitalWrite(DO_09, ledState);
}
// Werteausgabe auf Serial Monitor
Serial.print(F("Sensor 1 -Innen: " ));
Serial.print(F("Luftfeuchtigkeit: "));
Serial.print(h1);
Serial.print(F("% Temperatur: "));
Serial.print(t1);
Serial.print(F("°C "));
Serial.print(F(" Taupunkt: "));
Serial.print(Taupunkt_1);
Serial.println(F("°C "));
Serial.print("Sensor 2 -Aussen: " );
Serial.print(F("Luftfeuchtigkeit: "));
Serial.print(h2);
Serial.print(F("% Temperatur: "));
Serial.print(t2);
Serial.print(F("°C "));
Serial.print(F(" Taupunkt: "));
Serial.print(Taupunkt_2);
Serial.println(F("°C "));
Serial.println();
// Werteausgabe auf dem I2C-Display
lcd.clear();
lcd.setCursor(0,0);
lcd.print(F("I:"));// geändert vorher lcd.print(F("S1: "))
lcd.print(t1);
lcd.write((uint8_t)0); // Sonderzeichen °C
lcd.write(('C'));
lcd.setCursor(9,0);
lcd.write((uint8_t)1); // Sonderzeichen |
lcd.print(h1);
lcd.print(F("%"));
lcd.setCursor(0,1);
lcd.print(F("A:"));// geändert vorher lcd.print(F("S1: "))
lcd.print(t2);
lcd.write((uint8_t)0); // Sonderzeichen °C
lcd.write(('C'));
lcd.setCursor(9,1);
lcd.write((uint8_t)1); // Sonderzeichen |
lcd.print(h2);
lcd.print(F("%"));
lcd.setCursor(0,2);
lcd.print(F("TPI:"));
lcd.print(Taupunkt_1);
lcd.setCursor(9,2);
lcd.write((uint8_t)1); // Sonderzeichen |
lcd.setCursor(10,2);
lcd.print(F("TPA:"));
lcd.print(Taupunkt_2);
//Taupunkt Differenz berechnen
float DeltaTP = Taupunkt_1 - Taupunkt_2;
//Nach Taupunkt differenz + Hysterese schalten
if (DeltaTP > (SCHALTmin + HYSTERESE))trocknen = true;
if (DeltaTP < (SCHALTmin))trocknen = false;
if (t1 < TEMP1_min )trocknen = false;
if (t2 < TEMP2_min )trocknen = false;
if (trocknen == true)
{
lcd.setCursor(18,1);
lcd.print("<-");
digitalWrite(DO_00, RELAIS_EIN); // Relais einschalten
digitalWrite(DO_01, RELAIS_EIN); // Relais einschalten
digitalWrite(DO_02, RELAIS_EIN); // Relais einschalten
lcd.setCursor(9,3);
lcd.write((uint8_t)1); // Sonderzeichen
lcd.print(F("TPC L-EIN"));
} else {
lcd.setCursor(18,0);
lcd.print("<-");
digitalWrite(DO_00, RELAIS_AUS);
digitalWrite(DO_01, RELAIS_AUS); // Relais einschalten
digitalWrite(DO_02, RELAIS_AUS); // Relais einschalten
lcd.setCursor(9,3);
lcd.write((uint8_t)1); // Sonderzeichen |// Relais ausschalten
lcd.print(F("TPC L-AUS"));
}
if (trocknen == false && h1 > h1_soll)
{
digitalWrite(DO_03, RELAIS_EIN);
} else {
digitalWrite(DO_03, RELAIS_AUS);
}
pumpen(); //FunktionAufruf KondenAt abpumpen
//CHKIOBAD
if (isnan(h1) || isnan(t1) || h1 > 100 || h1 < 1 || t1 < -30 || t1 > 80 ) { //IOBAD SENSOR 1
Serial.println(F("Fehler beim Auslesen vom 1. Sensor!"));
fehler = true;
}
// Zeit um das Display zu lesen
if (isnan(h2) || isnan(t2) || h2 > 100 || h2 < 1 || t2 < -30 || t2 > 80) { //IOBAD SENSOR 2
Serial.println(F("Fehler beim Auslesen vom 2. Sensor!"));
fehler = true;
}
}
//----------------------------------------------------------LOOP ENDE
float taupunkt(float t, float r) {
float a, b;
if (t >= 0) {
a = 7.5;
b = 237.3;
} else if (t < 0) {
a = 7.6;
b = 240.7;
}
// Sättigungsdampfdruck in hPa
float sdd = 6.1078 * pow(10, (a*t)/(b+t));
// Dampfdruck in hPa
float dd = sdd * (r/100);
// v-Parameter
float v = log10(dd/6.1078);
// Taupunkttemperatur (°C)
float tt = (b*v) / (a-v);
return { tt };
}
void pumpen()
{ //definiere Funktion Pumpen
bool NIVEAU_HOCH = !digitalRead(DI_00); //INPUT Schwimmer Oben
bool NIVEAU_NIEDR = !digitalRead(DI_01); //INPUT Schwimmer Unten
static byte StatePump = 0; //Status der Statemachine Pumpen, Lokale Variable, static - Arduino-Referenz
static long timeout = 10000; //Timeout Pumpen in ms, Lokale Variable
static long StartZeit = 0;
switch (StatePump){
case 0:
lcd.setCursor(0,3);
lcd.print(F("NL P-AUS")); // Init: Voll? Wenn ja Pumpe EIN und springe nach 1
if (NIVEAU_HOCH && NIVEAU_NIEDR){ // wenn oberer Pegel erreicht
digitalWrite(DO_07, RELAIS_EIN); // Pumpe ein
StartZeit = millis(); // Zeit merken
StatePump = 1;lcd.setCursor(0,3);
lcd.print(F("NH P-EIN"));
// nächster State: 1
}
break; //break
case 1:
lcd.setCursor(0,3);
lcd.print(F("NH P-EIN")); // Pumpen: Pumpe ist EIN, warte auf Niveau_Niedrig LOW
if (!NIVEAU_HOCH && !NIVEAU_NIEDR){ // wenn unterer Pegel erreicht
digitalWrite(DO_07, RELAIS_AUS); // Pumpe aus
StatePump = 0;
lcd.setCursor(0,3);
lcd.print(F("NL P-AUS")); // nächster State: Init
}
if(millis()-StartZeit > timeout){ // Wenn Timeout, setze Fehler case
digitalWrite(DO_07, RELAIS_AUS); // Pumpe aus
digitalWrite(DO_08, HIGH); // Fehler LED an
StatePump = 2; // nächster Status: Fehler
}
break; //break
case 2:
lcd.setCursor(0,3);
lcd.print(F("NF P-AUS")); //in Fehler gehen
}
}// end switch