Du hast einen Keller oder einen anderen Raum, der ständig feucht ist und regelmäßig gelüftet werden müsste – oder erheblich Energie verschwendet, wenn du ihn beheizst? Eine Taupunkt-Lüftung bietet hier eine smarte Lösung: Sie misst die Luftbedingungen automatisch und sorgt für Belüftung, wenn es am effektivsten ist.
Nach den drastisch steigenden Heizkosten im Winter 2022/2023 habe ich in einem wenig genutzten, großvolumigen Raum die Heizung stark reduziert – auf lediglich 8 °C. Um Gefrieren der Leitungen und Schimmelbildung zu verhindern, habe ich auf eine automatische Taupunkt-Lüftung gesetzt. Die Folge: deutlich reduzierte Heizkosten – und kein Schimmel im Raum.
Theorie
Luftfeuchte wird relativ in Prozent gemessen (relative Luftfeuchte). Relative Luftfeuchte beschreibt, wie viel Wasser in der Luft ist im Vergleich zu dem Maximum, das die Luft bei ihrer Temperatur speichern kann. Verändert sich die Temperatur, verändert sich auch die Menge an Wasser, die die Luft speichern kann. Verringert sich die Temperatur, wird die Wassermenge kleiner, wird die Luft wärmer, wird die Wassermenge größer.
Bleibt die Wassermenge in der Luft gleich und die Temperatur erhöht sich, dann wird die relative Luftfeuchte also kleiner. Verringert sich die Temperatur, wird die Luftfeuchte höher bis zu einem Maximum von 100%. Die Lufttemperatur, bei der die Luftfeuchte 100% erreichen würde und von hier an kondensiert, nennt man Taupunkt. Den Taupunkt kannst du also als Maß verwendet werden, um Luftmassen unterschiedlicher Temperatur und Luftfeuchte miteinander zu vergleichen. Luft mit einem geringeren Taupunkt enthält weniger Wasser als Luft mit einem höheren Taupunkt.
Wenn du also optimal Lüften willst, wartest du auf einen Zeitpunkt, an dem die Außenluft einen geringeren Taupunkt hat als die Luft innerhalb eines zu feuchten Raumes. Ist der Taupunkt der Außenluft höher, ist das Lüften sogar kontraproduktiv, weil du mehr Feuchtigkeit in deinen Raum hereinbringst, als bereits vorhanden ist. Vor allem im Sommer enthält die Luft oft mehr Feuchtigkeit, weil die warme Luft eben mehr Feuchtigkeit fassen kann als vielleicht deine kühlere Kellerluft.
Bei meinen Messungen habe ich die Beobachtung gemacht, dass besonders morgens zum Sonnenaufgang der beste Zeitpunkt zum Lüften ist, da die Außenluft hier meist am trockensten ist. Aber wir wollen es genau wissen.
Schimmel kann entstehen bei einer dauerhaften Luftfeuchte von 60% oder mehr. (Quelle: Verbraucherzentrale)
In einem anderen Beitrag schildere ich über eine Benachrichtigungsfunktion für gute Lüftungszeitpunkte, die 61% als Schwellwert verwenden und auch mit Taupunkten arbeitet.
TL;DR
- Relative Luftfeuchtigkeit beschreibt, wie viel Feuchtigkeit die Luft im Vergleich zum Maximum bei ihrer Temperatur enthält.
- Wenn die Temperatur sinkt, kann die Luft weniger Feuchtigkeit halten – steigt die Luftfeuchtigkeit dann auf 100 %, beginnt Kondensation.
- Dieser Punkt wird als Taupunkt bezeichnet – er hilft, Luft verschiedener Temperatur und Feuchtigkeitszustände vergleichbar zu machen.
Deine Vorteile auf einen Blick
- Automatische Steuerung nach Luftfeuchte und Taupunkt
- Schutz vor Schimmelbildung
- Effiziente Nutzung der Außenluft – nur dann lüften, wenn es effektiv ist
- Kosten- und Energieeinsparung, wie im DIY-Beispiel demonstriert
Hardware
Die Hardwareteile sind unten in der Grafik schon zu sehen. Das ein oder andere Teil ist sicher austauschbar. Ich habe folgende Komponenten verwendet
- 1x D1 Mini NodeMcu mit ESP8266
- 1x TCA9548A I2C-Switch
- 2x Sensor BME280
- 1x Widerstand: 1kΩ
- 1x TIP122 Transistor NPN
- 2x 70cm 4pin Dupont Kabel männlich zu weiblich (zur einfachen Anbindung der Sensoren)
- Jumper-Kabel
- 120mm PC-Lüfter (so viele du glaubst zu brauchen)
- 1x Breadboard
- 1x Breadboard Power Supply MB120
- 1x DC Steckernetzteil 12V 5A passend zum Breadboard Power Supply
- ggf. Plexiglas passend für die Öffnung, mit der du die Luftzufuhr steuern willst.
Das ganze kannst du wie unten zu sehen dann verkabeln. Ich verwende D4 als Signal-Pin um die Lüfter zu aktivieren. D1 und D2 um den I2C-Switch anzubinden und dort die Kanäle 2 und 3 für die Sensoren, die du aber auch ändern kannst. Denk nur daran, die auch später in de Konfiguration zu ändern. Der Sensor an Kanal 3 ist für drinnen, der Sensor an Kanal 2 ist für draußen bestimmt.
Die Lüfter werden so angebracht, dass sie die feuchte Luft aus dem Raum heraussaugen. Frische trockenere Luft strömt dann von woanders nach.

Software
1) Vor oder nach dem Zusammenbau will der ESP8266 mit Software betankt werden. Mit ESPHome geht das sehr einfach, wenn du das erstmalig in Betrieb genommen hast. Python gibt es nicht nur für Linux, sondern auch für Windows. Hast du kein Linux auf deinem Rechner, willst es aber verwenden, kannst du das auch innerhalb einer VirtualBox laufen lassen. Ich habe es auch geschafft, mit Portable Python von Windows aus ESPHome zu verwenden.
1.1)Hinweis: Unter Ubuntu 22.04 wird der ESP nicht automatisch korrekt erkannt. Hier sind vorher noch zwei Handgriffe nötig:
- btltty entfernen
sudo apt remove brltty #removes brltty, do not remove if you need this because of blindness!
- Installiere den CH340x-Treiber
oder benutze ein früheres Ubuntu.
Für Windows und normalerweise auch unter anderen Ubuntu-Versionen lässt sich der ESP recht einfach provisionieren ohne 1.1)
2) Schließe deinen ESP8266 an deinen Rechner an und provisioniere ihn mit web.esphome.io.
3) Und verwende folgende ESPHome-Konfiguration:
(nachdem du name, wifi und mqtt auf dein Netz angepasst hast)
esphome:
name: esp-fan-controller
esp8266:
board: d1_mini
#board: nodemcuv2
# Enable logging
logger:
tx_buffer_size: 256
#level: NONE
#level: VERBOSE
web_server:
port: 80
ota:
# password: ""
wifi:
networks:
- ssid: "XXXXX"
password: "XXXXX"
reboot_timeout: 2min
#https://esphome.io/components/i2c.html
i2c:
id: i2c_main
scl: D1
sda: D2
scan: true
frequency: 20kHz
tca9548a:
- address: 0x70
id: multiplex0
i2c_id: i2c_main
channels:
- bus_id: i2c_0
channel: 2
- bus_id: i2c_1
channel: 3
sensor:
- platform: uptime
id: uptime_id
name: "Uptime"
update_interval: 15s
#BME/P280
#https://esphome.io/components/sensor/bme280.html
- platform: bme280
i2c_id: i2c_0
temperature:
name: "BME-T 2 (out)"
id: bme280_0_temperature
oversampling: 8x
filters:
- filter_out: NaN
pressure:
name: "BME-P 2 (out)"
id: bme280_0_pressure
filters:
- filter_out: NaN
humidity:
name: "BME-H 2 (out)"
id: bme280_0_humidity
filters:
- filter_out: NaN
address: 0x76
update_interval: 30s
- platform: template
name: "Dew Point 2 (out)"
id: bme280_0_dewpoint
lambda: |-
return (243.5*(log(id(bme280_0_humidity).state/100)+((17.67*id(bme280_0_temperature).state)/
(243.5+id(bme280_0_temperature).state)))/(17.67-log(id(bme280_0_humidity).state/100)-
((17.67*id(bme280_0_temperature).state)/(243.5+id(bme280_0_temperature).state))));
unit_of_measurement: °C
icon: 'mdi:thermometer-alert'
filters:
- filter_out: NaN
- platform: bme280
i2c_id: i2c_1
temperature:
name: "BME-T 3 (in)"
id: bme280_1_temperature
oversampling: 8x
filters:
- filter_out: NaN
pressure:
name: "BME-P 3 (in)"
id: bme280_1_pressure
filters:
- filter_out: NaN
humidity:
name: "BME-H 3 (in)"
id: bme280_1_humidity
filters:
- filter_out: NaN
address: 0x76
update_interval: 30s
- platform: template
name: "Dew Point 3 (in)"
id: bme280_1_dewpoint
lambda: |-
return (243.5*(log(id(bme280_1_humidity).state/100)+((17.67*id(bme280_1_temperature).state)/
(243.5+id(bme280_1_temperature).state)))/(17.67-log(id(bme280_1_humidity).state/100)-
((17.67*id(bme280_1_temperature).state)/(243.5+id(bme280_1_temperature).state))));
unit_of_measurement: °C
icon: 'mdi:thermometer-alert'
filters:
- filter_out: NaN
button:
#https://esphome.io/components/button/restart.html
- platform: restart
name: "Restart"
switch:
#Digital Pins
- platform: gpio
id: gpio_d4
name: "Fans"
pin: D4
http_request:
id: http_request_data
useragent: esphome/device
timeout: 10s
interval:
- interval: 30s
then:
- if:
condition:
lambda: |-
return id(bme280_0_dewpoint).state + 2.0 < id(bme280_1_dewpoint).state;
then:
- switch.turn_on: gpio_d4
else:
- switch.turn_off: gpio_d4
- interval: 30s
then:
- http_request.post:
url: !lambda |-
const size_t capacity = JSON_OBJECT_SIZE(10);
DynamicJsonDocument root(capacity);
root["name"] = "NeuensteinKeller";
root["uptime"] = id(uptime_id).state;
root["bme280_0_temperature"] = id(bme280_0_temperature).state;
root["bme280_0_pressure"] = id(bme280_0_pressure).state;
root["bme280_0_humidity"] = id(bme280_0_humidity).state;
root["bme280_0_dewpoint"] = id(bme280_0_dewpoint).state;
root["bme280_1_temperature"] = id(bme280_1_temperature).state;
root["bme280_1_pressure"] = id(bme280_1_pressure).state;
root["bme280_1_humidity"] = id(bme280_1_humidity).state;
root["bme280_1_dewpoint"] = id(bme280_1_dewpoint).state;
String jsonPayload;
serializeJson(root, jsonPayload);
return ((String) "https://mystryx.dd-dns.de/files/json_receiver/?name=NeuensteinKeller&json=" + jsonPayload).c_str();
headers:
Content-Type: application/json
verify_ssl: false
json: |-
root["name"] = "NeuensteinKeller";
root["uptime"] = id(uptime_id).state;
root["bme280_0_temperature"]= id(bme280_0_temperature).state;
root["bme280_0_pressure"] = id(bme280_0_pressure).state;
root["bme280_0_humidity"] = id(bme280_0_humidity).state;
root["bme280_0_dewpoint"] = id(bme280_0_dewpoint).state;
root["bme280_1_temperature"]= id(bme280_1_temperature).state;
root["bme280_1_pressure"] = id(bme280_1_pressure).state;
root["bme280_1_humidity"] = id(bme280_1_humidity).state;
root["bme280_1_dewpoint"] = id(bme280_1_dewpoint).state;
Ich verwende meine Konstruktion in einem anderen Netzwerk uns sende mir die Daten selbst. Die HTTP-Requests sind zur Funktion nicht notwendig. Das letzte Interval kannst du für deine Zwecke vielleicht entfernen oder muss von dir angepasst werden.
Der json_receiver ist ein per HTTPS im Netz erreichbarer Server, der empfangene Daten in meinem Netz als MQTT-Nachricht einspeist.
Wenn die Luft aktiv in den Raum geblasen wird, anstatt sie nach aussen zu blasen, kann es nicht zu Unterdruck kommen, und damit kein CO2 z.B. aus dem Kachelofen gezogen werden.