Startseite » Automatischer Taupunkt-Lüfter – Smarthome DIY

Automatischer Taupunkt-Lüfter – Smarthome DIY

📅
•
⏱️ 26 Min. Lesezeit
•
✍️ Alexander Hacker

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

Taupunktrechner / Simulation

Taupunkt-Lüftungsrechner & Simulation

Vergleiche absolute Feuchte und Taupunkt – erkenne sofort, ob Lüften Kellerfeuchte abführt oder Schimmel erzeugt.

🌱 ERDREICH KELLERBODEN ⚠️ SOMMERKONDENSATION Tauwasser an 13.0°C Wand! AUSSENBEREICH 28.0°C • 65% rF KELLERRAUM 16.0°C • 70% rF LÜFTER AUS • FEUCHTE-WARNUNG
⛔ Lüften vermeiden (Lüfter AUS)
Δ Abs. Feuchte: -8.1 g/m³
Δ Taupunkt: -10.3 °C
Achtung, Lüftungsfalle! Die warme Sommerluft enthält absolut 8.1 g/m³ MEHR Wasser als die Kellerluft. Ein Lüften würde enorme Feuchtigkeitsmengen in den Keller transportieren, wo sie an den kühlen Wänden kondensiert!
ESPHome Regel Bedingung: Taupunkt(Außen) + 2.0°C < Taupunkt(Keller)
Lüfter: OFF 🛑 (Schutz aktiv)
⚠️
Feuchtetransport bei 1x komplettem Luftwechsel (Keller ~55 m³):
Ein vollständiger Luftwechsel würde ca. 445 ml flüssiges Wasser ZUSÄTZLICH in den Raum pumpen – fast ein halber Liter Wasser an den Wänden!
🏠 Kellerluft (Innen) TP: 10.5°C (9.5 g/m³)
Temperatur innen 16.0 °C
Relative Feuchte innen 70 %
🌳 Außenluft TP: 20.8°C (17.6 g/m³)
Temperatur außen 28.0 °C
Relative Feuchte außen 65 %
13.0 °C
Erkennt Kondensationsgefahr an ungedämmten Kellerwänden oder Betonböden.
📐 Keller-Raumgröße 25 m² (~55 m³)
m²
Berechnet die reale Wassermenge in Litern/ml bei vollständigem Luftwechsel.
Messgröße Keller (Innen) Außenluft Differenz (Innen − Außen)
Absolute Feuchte (aF) 9.5 g/m³ 17.6 g/m³ -8.1 g/m³
Taupunkt (Td) 10.5 °C 20.8 °C -10.3 °C
Dampfdruck (e) 12.7 hPa 24.6 hPa -11.9 hPa
Sättigungsdampfdruck (es) 18.2 hPa 37.8 hPa —
Wassergehalt im Raum 525 g (~0.53 L) 970 g (~0.97 L) +445 ml Wasser
Meteorologische Berechnungsgrundlage:
Der Rechner ermittelt den Sättigungsdampfdruck und Taupunkt nach der offiziellen Magnus-Formel (Sonntag 1990 / DWD) mit den Parametern \(a = 17{,}62\), \(b = 243{,}12\) und \(c = 6{,}112\text{ hPa}\).
Die Hystereseregel für automatische Lüfter (wie im ESPHome Projekt beschrieben) verlangt einen Mindestabstand von 2.0 °C Taupunktdifferenz bzw. 0.5 g/m³ Feuchtedifferenz, um Sensortoleranzen (±3% rF) und wechselhaftes Wetter zuverlässig abzufangen.
Entwickelt für smarthome-node.de • Lokale Berechnung im Browser • DSGVO-konform

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!

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/
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/
  - 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/
  - 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.

openHAB Automatisierung: Intelligente Taupunkt-Schwellwert-Logik

Sobald ESPHome die Sensordaten (Temperatur, Feuchtigkeit und errechneten Taupunkt von innen und außen) via MQTT oder REST an openHAB liefert, übernimmt openHAB die eigentliche Regelung des Lüfters. Eine simple Lüftung nach relativer Feuchte ist im Keller fatal: Strömt im Sommer warme Außenluft mit 60 % Feuchte in den kühlen Keller, kühlt sie dort ab und die relative Feuchte steigt schnell auf über 90 % – Kondenswasser und Schimmel entstehen.

Die goldene Regel: Nur lüften, wenn der absolute Feuchtegehalt bzw. der Taupunkt der Außenluft signifikant niedriger ist als der des Raumes!

1. Items Definition

// Taupunkte
Number:Temperature    WetterstationDewPoint     "Taupunkt Außen [%.2f °C]"    <rain>          { channel="mqtt:topic:myMosquitto:Arduino_55:dew_point" }
Number:Temperature    Keller_DewPoint           "Taupunkt Keller [%.2f °C]"   <rain>          { channel="mqtt:topic:myMosquitto:Arduino_57:dew_point" }

// Temperaturen (für Unterkühlungsschutz)
Number:Temperature    WetterstationTemperature  "Außentemperatur [%.1f °C]"   <temperature>   { channel="mqtt:topic:myMosquitto:Arduino_55:temperature" }
Number:Temperature    Keller_Temperature        "Kellertemperatur [%.1f °C]"  <temperature>   { channel="mqtt:topic:myMosquitto:Arduino_57:temperature" }

// Relais-Aktor für Lüfter
Switch                Keller_Luefter_Switch     "Kellerlüfter [%s]"           <fan>           { channel="mqtt:topic:myMosquitto:esphome_fan:relay" }

2. Schwellwert-Logik mit JS Scripting (ECMAScript 2021+)

Die nachfolgende Regel prüft alle 5 Minuten die Taupunktdifferenz und berücksichtigt eine Hysterese (Einschalten bei $\Delta \ge 2{,}0\,^\circ\text{C}$, Ausschalten bei $\Delta \le 0{,}8\,^\circ\text{C}$) sowie einen Frost- und Unterkühlungsschutz für den Keller:

const { rules, triggers, items, Quantity } = require('openhab');

// Schwellwerte und Hysteresen
const DELTA_ON  = 2.0; // Lüfter AN wenn Keller-Taupunkt mindestens 2.0 °C über Außen-Taupunkt liegt
const DELTA_OFF = 0.8; // Lüfter AUS sobald Differenz unter 0.8 °C fällt (Hysterese)
const MIN_CELLAR_TEMP = 12.0; // Verhindert Auskühlen des Kellers im Winter
const MIN_OUTDOOR_TEMP = 2.0; // Frostschutz: Keine eisige Außenluft einblasen

rules.JSRule({
    name: "Automatischer Taupunkt-Lüfter",
    description: "Steuert Kellerlüftung basierend auf Taupunktdifferenz mit Hysterese und Frostschutz",
    triggers: [
        triggers.GenericCronTrigger("0 */5 * * * ?"), // Alle 5 Minuten prüfen
        triggers.ItemStateChangeTrigger("WetterstationDewPoint"),
        triggers.ItemStateChangeTrigger("Keller_DewPoint")
    ],
    execute: () => {
        const itemDewOut   = items.getItem("WetterstationDewPoint");
        const itemDewIn    = items.getItem("Keller_DewPoint");
        const itemTempOut  = items.getItem("WetterstationTemperature");
        const itemTempIn   = items.getItem("Keller_Temperature");
        const itemFan      = items.getItem("Keller_Luefter_Switch");

        // Sicherheitsprüfung: Alle Items initialisiert?
        if (itemDewOut.isUninitialized || itemDewIn.isUninitialized ||
            itemTempOut.isUninitialized || itemTempIn.isUninitialized) {
            return;
        }

        const dewOut   = itemDewOut.numericState;
        const dewIn    = itemDewIn.numericState;
        const tempOut  = itemTempOut.numericState;
        const tempIn   = itemTempIn.numericState;
        const fanState = itemFan.state;

        // 1. Unterkühlungs- & Frostschutz prüfen
        if (tempIn < MIN_CELLAR_TEMP || tempOut < MIN_OUTDOOR_TEMP) {
            if (fanState === 'ON') {
                console.info("[Taupunkt-Lüfter] Unterkühlungsschutz aktiv: Lüfter wird abgeschaltet.");
                itemFan.sendCommand('OFF');
            }
            return;
        }

        // 2. Taupunktdifferenz berechnen (Innentaupunkt minus Außentaupunkt)
        const diff = dewIn - dewOut;

        // 3. Einschaltbedingung mit Hysterese
        if (diff >= DELTA_ON && fanState !== 'ON') {
            console.info([Taupunkt-Lüfter] Optimales Lüftungswetter: Diff=°C (In: °C, Out: °C). Lüfter AN.);
            itemFan.sendCommand('ON');
        } 
        // 4. Abschaltbedingung (Differenz zu gering oder Feuchteeintrag droht)
        else if (diff <= DELTA_OFF && fanState === 'ON') {
            console.info([Taupunkt-Lüfter] Differenz zu gering (Diff=°C). Lüfter AUS.);
            itemFan.sendCommand('OFF');
        }
    }
});

Historisches Archiv: Legacy Rules DSL (openHAB 2/3)

Hinweis: Für openHAB 2 und 3 Installationen wurde die Logik früher als klassische .rules-Datei umgesetzt:

rule "Taupunkt Luefter Steuerung"
when
    Time cron "0 */5 * * * ?"
then
    if (WetterstationDewPoint.state != NULL && Keller_DewPoint.state != NULL) {
        val Number dewOut = (WetterstationDewPoint.state as Number).floatValue
        val Number dewIn  = (Keller_DewPoint.state as Number).floatValue
        val Number diff   = dewIn - dewOut

        if (diff >= 2.0 && Keller_Luefter_Switch.state != ON) {
            Keller_Luefter_Switch.sendCommand(ON)
        } else if (diff <= 0.8 && Keller_Luefter_Switch.state == ON) {
            Keller_Luefter_Switch.sendCommand(OFF)
        }
    }
end
0
0
Alexander Hacker
Autor & Smart-Home-Entwickler

Alexander Hacker

Dokumentiert auf SmartHome Node praxisnahe Do-It-Yourself-Projekte, offene Architekturen und Automatisierungen mit openHAB 5, Zigbee2MQTT, ESPHome und Linux – ohne Abhängigkeit von Hersteller-Clouds.

1 Gedanke zu „Automatischer Taupunkt-Lüfter – Smarthome DIY“

  1. 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.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre, wie deine Kommentardaten verarbeitet werden.

Translate »