Intelligente Kellerbelüftung: Arduino-gesteuerte Feuchteregelung
Komponenten
| Arduino Nano R3 | 1 |
| IO Expander (fertiges Modul mit Relais, OLED, I²C-1-Wire) | 1 |
| IO Expander Bundle (komplettes Set) | 1 |
Software
- Arduino IDE
Funktionen
- Innen-/Außen-Temperatur & Luftfeuchte (SHT10 über 1-Wire→I²C)
- Intelligente Lüftersteuerung durch Feuchtevergleich (absoluter & relativer Wert)
- Reduziert Kellerfeuchte & Schimmelrisiko
- Energiesparend: Lüftet nur bei sinnvollem Klimadelta

Benötigte Teile (Detail)
- IO Expander (Kernmodul)
- 1-Wire zu I²C Adapter
- Arduino Nano
- 1-Kanal 5 V Relais
- 2× SHT10 Feuchtesensor
- I²C SSD1306 OLED 128×64
- 2× 110 V Lüfter (172×150×38 mm, 0,34 A, 2400 U/min)
- Wasserdichtes Gehäuse (158×90×65 mm, IP68)
- IP68 Kabelverschraubungen PG7 + PG9
- 2× RJ11 Keystone Schraubklemmen + Gehäuse
- 2× 50 ft 4C4P RJ11 Kabel (Sensoren)
- 6″ RJ11 Kabel (intern)
- 100 ft 110 V Kabel (Lüfter)
- Netzstecker, 2,54 mm Header-Kabel
- 12 V DC 1 A Netzteil
Verdrahtung

OLED-Anzeige

Zeigt: Innen-/Außentemperatur, relative & absolute Feuchte, Lüfterstatus, Firmware-Version.
Warum IO Expander?
- Einfacheres Design, Fertigmodule
- Keine 1-Wire/Relais/OLED/Font-Treiber selbst schreiben
- Spart Flash (nur 6106 Bytes = 19 %)
- Code in < 1 Tag geschrieben
- Standard RJ11-Kabel (Telefonkabel) für Sensoren – keine Längenprobleme
- Günstiger als Fertigsysteme
- Einfach anpassbar
- Einzelne Stromversorgung
Aufbau
- Arduino Nano an IO Expander anschließen, Code flashen (6-Pin-Header = Debug-Port, später nicht nötig).
ONEWIRE_TO_I2C_ROMAdresse an eigenes Modul anpassen.- 110 VAC an beide Lüfter anschließen.
- Gehäuse: 7/16″ (PG7) & 9/16″ (PG9) bohren, Kabelverschraubungen einbauen. PG7 = 12 V DC Eingang, PG9 = Sensoren/Lüfter.
- Freien Lüftungsschacht als Abluft wählen, gegenüberliegende Schächte als Zuluft öffnen, benachbarte schließen → querlüftung.
- Lüfter innen am Schacht mit Kabelbindern montieren, Ausblasrichtung prüfen.
- Außen-Sensor durch bestehenden Zugang nach draußen führen, fern von Haus/Wänden, gegen Wetterberichte prüfen.
- Beide Sensoren an Keystone-Buchsen anschließen, im Gehäuse montieren.
- 50 ft RJ11-Kabel an Sensoren, zusammen mit Lüfterkabel zum Steuerungsgehäuse führen. Vorvercrimpte Stecker abschneiden, durch Verschraubung führen, neu crimpen.
- Alles im Steuerungsgehäuse verdrahten, mit Doppelklebeband & Schaum fixieren.
- Test: Arduino vom IO Expander trennen, direkt per USB steuern → Relais & Lüfter prüfen. Dann final montieren.
Updates
20.03.2019
Nach Monaten im Kriechkeller: Spitzen-Luftfeuchte >95 % (Wasserrohrbruch) auf <50 % gesenkt. System läuft stabil.

Display getauscht: SSD1306 0,96″ → SH1106 1,3″ (größer, besser lesbar). Einzeilige Code-Änderung: ST10 → ST13.

12.09.2019
Version 1.1: Kaltstart-Problem behoben (OLED blieb dunkel). Lüftet weiterhin zuverlässig.
Code (Basement/Crawlspace Ventilation System v1.1)
/* IO Expander - Basement Ventilation v1.1 */
#include <math.h>
#include <SoftwareSerial.h>
#include <avr/wdt.h>
#include "IOExpander.h"
#define FAHRENHEIT
#define ONEWIRE_TO_I2C_ROM "i4s71"
#define INIT_OLED "st13;si;sc;sd"
#define HUMIDITY_SENSOR_INSIDE "s6t1"
#define HUMIDITY_SENSOR_OUTSIDE "s8t1"
#define FAN_ON "r1o"
#define FAN_OFF "r1f"
#define ABSOLUTE_DELTA_FAN_ON 1.0 // g/m³ Differenz Inside > Outside
#define ABSOLUTE_DELTA_FAN_OFF 0.5 // g/m³ Differenz Inside <= Outside
#define OUTSIDE_RELATIVE_FAN_ON 88 // % rH Outside max
#define OUTSIDE_RELATIVE_FAN_OFF 90 // % rH Outside min
#define MINIMUM_TEMPERATURE 15 // °C, darunter Zyklusbetrieb
#define FAN_ON_TIME (20UL*60*1000) // 20 min
#define FAN_OFF_TIME (20UL*60*1000) // 20 min
//#define SERIAL_DEBUG
#define SERIAL_TIMEOUT 5000
#ifdef SERIAL_DEBUG
SoftwareSerial swSerial(8,7);
#endif
struct HS { float temp, relative, absolute; bool error; };
int led = 13;
bool init_oled = true;
long ontime, offtime;
#ifdef FAHRENHEIT
#define C2F(t) CelsiusToFahrenheit(t)
float CelsiusToFahrenheit(float c) { return (c*9/5)+32; }
#else
#define C2F(t) (t)
#endif
void SerialPrint(const char* s, float v, char err) {
Serial.print(s);
if (err) Serial.print(F("NA")); else Serial.print(v,1);
}
float AbsoluteHumidity(float temp, float rel) {
// Buck (1981) Formel
return (6.1121 * pow(2.718281828, (17.67*temp)/(temp+243.5)) * rel * 18.01534) / ((273.15+temp) * 8.21447215);
}
void ReadHumiditySensor(HS* hs) {
SerialCmd("sr");
if (SerialReadFloat(&hs->temp) && SerialReadFloat(&hs->relative)) {
hs->absolute = AbsoluteHumidity(hs->temp, hs->relative);
hs->error = false;
} else hs->error = true;
SerialReadUntilDone();
}
void setup() {
Serial.begin(115200);
#ifdef SERIAL_DEBUG
swSerial.begin(115200);
#endif
pinMode(led, OUTPUT);
wdt_enable(WDTO_8S);
offtime = millis() - FAN_OFF_TIME;
}
void loop() {
HS inside, outside;
static bool fan = false, cycle = false;
static long last_time = -60000L;
Serial.println();
if (SerialReadUntilDone()) {
if (millis() - last_time > 60000L) { // Sensoren max 1/Min (Selbsterwärmung)
if (SerialCmdDone(HUMIDITY_SENSOR_INSIDE)) ReadHumiditySensor(&inside);
if (SerialCmdDone(HUMIDITY_SENSOR_OUTSIDE)) ReadHumiditySensor(&outside);
if (inside.error || outside.error) fan = false;
else {
if (fan) { // Lüfter AN → Ausschaltbedingungen prüfen
if (outside.relative >= OUTSIDE_RELATIVE_FAN_OFF ||
inside.absolute - outside.absolute <= ABSOLUTE_DELTA_FAN_OFF)
cycle = fan = false;
else if (cycle && outside.temp <= MINIMUM_TEMPERATURE &&
millis() - ontime > FAN_ON_TIME)
fan = false;
if (!fan) offtime = millis();
} else { // Lüfter AUS → Einschaltbedingungen prüfen
if (outside.relative <= OUTSIDE_RELATIVE_FAN_ON &&
inside.absolute - outside.absolute >= ABSOLUTE_DELTA_FAN_ON)
cycle = fan = true;
if (cycle && outside.temp <= MINIMUM_TEMPERATURE)
fan = (millis() - offtime > FAN_OFF_TIME);
if (fan) ontime = millis();
}
}
if (fan) SerialCmdDone(FAN_ON); else SerialCmdDone(FAN_OFF);
if (SerialCmdNoError(ONEWIRE_TO_I2C_ROM)) {
if (init_oled) { SerialCmdDone(INIT_OLED); init_oled = false; }
// OLED Layout befüllen
SerialCmdDone("st13;sc;sf0;sa1;sd70,0,\"INSIDE\";sd127,0,\"OUTSIDE\";sf1;sa0;sd0,12,248,\""
#ifdef FAHRENHEIT
"F"
#else
"C"
#endif
"\";sd0,30,\"%\";sf0;sd0,50,\"g/m\";sd20,46,\"3\";");
SerialPrint("sf1;sa1;sd70,12,\"", C2F(inside.temp), inside.error);
SerialPrint("\";sd70,30,\"", inside.relative, inside.error);
SerialPrint("\";sd70,48,\"", inside.absolute, inside.error);
SerialPrint("\";sd127,12,\"", C2F(outside.temp), outside.error);
SerialPrint("\";sd127,30,\"", outside.relative, outside.error);
SerialPrint("\";sd127,48,\"", outside.absolute, outside.error);
Serial.print("\";");
Serial.print("sf0;sa0;sd0,0,\"");
Serial.print(fan ? "FAN" : "v1.1");
Serial.println("\";sd");
SerialReadUntilDone();
} else init_oled = true;
last_time = millis();
}
delay(1000);
} else { // Kommunikationsfehler → LED blinken
digitalWrite(led, HIGH); delay(500);
digitalWrite(led, LOW); delay(500);
init_oled = true;
}
wdt_reset(); // Watchdog zurücksetzen
}
Schaltplan

Herstellungsprozess
- RFID-Anwesenheitssystem mit Arduino & Python – Daten direkt in phpMyAdmin (XAMPP) speichern
- Arduino-Uno-Roboter zur Personenerkennung – Sensorintegration Schritt für Schritt
- Bluetooth-gesteuerter Arduino-Spybot bauen – Überwachungsroboter mit IP-Kamera
- FlickMote: Gestensteuerung per Ultraschall & IR für Smart Home (Arduino 101)
- DIY Arduino TV-B-Gone: Universelle TV-Aus-Fernbedienung
- Einen eigenen LED-Master-Clock mit Alarm bauen – aus 12 Metern Entfernung ablesbar
- SERENA: Eigenes Arduino Mega 2560 Alarmsystem mit TFT-LCD-Touchscreen
- Automatische Pflanzenbewässerung mit Arduino – Sorgenfrei in den Urlaub
- Echtzeit-Waldbrand-Überwachungssystem mit SMS-Alarm
- Lüftungsanlagen: Frische Luft für gesunde Innenräume