Damit keine Missverständnisse aufkommen: Node-Red ist natürlich kein Entfeuchtungsgerät sondern eine grafische Entwicklungsumgebung für Internet Of Things Anwendungen. Node-Red hat Schnittstellen zu Raspberry Pi bereits integriert, so dass das Ansteuern oder Auslesen der GPIO Pins ein Klacks ist. Die Node-Red Umgebung läuft problemlos auf dem Raspberry Pi, gerne auch zusammen mit einem MQTT Broker wie z.B. Mosquitto.
Da Node-Red auch eine MQTT Schnittstelle hat, können wir unsere Sensoren und andere Komponenten ganz locker integrieren, ohne dass wir zusätzliche Kabel oder Anderes verlöten müssten.
Ebenso gibt es eine Vielzahl von Schnittstellen zu Webservices um beispielsweise den Deutsche Wetterdienst abzufragen und vielleicht mit einer von dort gezogenen Sturmwarnung ein Rollo hochzufahren oder Ähnliches.
So lassen sich auch komplexe Anwendungen relativ leicht entwickeln und produktiv nutzen, ohne dass man sich die Finger wund programmiert um eine schöne Benutzeroberfläche zu bauen. Die Grafische Darstellung von Messwerten etc. ist ebenfalls ganz einfach.
Ich werde hier allerdings nicht das x-te Node-Red Tutorial schreiben. Bei Youtube gibt es eine Reihe gut gemachter Tutorials, außerdem möchte ich wieder auf haus-automatisierung.com verweisen, wo sich ein hervorragendes aber kostenpflichtiges Node-Red Video Tutorial befindet.
Keller entfeuchten
Wie oben erwähnt, dient Node-Red bei mir dazu, eine effektive und kostengünstige Kellerentfeuchtung sicherzustellen. Ansonsten würden mein gesamtes Werkzeug und andere Dinge verrosten bzw. verschimmeln. Mein Keller ist wirklich sehr feucht – trotz Sanierung und Sperrputz.
- Ich möchte den Keller trocken halten, indem ich mit einem Fensterventilator bei Bedarf und wenn sinnvoll, die feuchte Kellerluft mit trockener Außenluft austausche.
- Dafür messe ich mit Hilfe von zwei Temperatur-/Luftfeuchtigkeitssensoren die Werte im Keller selbst und außerhalb des Kellers.
- Die gemessene, relative Luftfeuchtigkeit wird in absolute Luftfeuchtigkeit umgerechnet und die Werte von Innen und Außen miteinander verglichen. (Siehe Kapitel “Physik” weiter unten).
- Ist die absolute Luftfeuchtgkeit außen signifikant (~15%) niedriger als innen, wird der Ventilator eingeschaltet sofern das erforderlich ist; d.h. wenn die relative Luftfeuchtigkeit im Keller über 65% liegt.
- Die Luft wird ausgetauscht, die relative Feuchte sinkt unter 60%, der Ventilator stoppt. Die Feuchte steigt über ein paar Stunden hinweg wieder an und sobald 65% überschritten sind, startet der Ventilator neu – vorausgesetzt die Luft draußen ist trockener als drinnen.
- Ist der Unterschied zu gering oder ist es draußen absolut feuchter als drinnen, soll ein im Keller stehender Luftentfeuchter eingeschaltet werden um die Luftfeuchtigkeit zu regulieren (optional).
Warum zwei verschiedene Geräte zum Trocknen? Ein Ventilator hat eine Leistungsaufnahme von 30W, ein Trocknungsaggregat meist um die 250W. Je nach den Umständen läuft die Anlage 6-12 Stunden am Tag, der Stromverbrauch läppert sich mit der Zeit. Ein Ventilator ist also deutlich günstiger. Allerdings kann es bei schwül-heißem Wetter durchaus sein, dass der Ventilator nie zum Zuge kommt. Deshalb der Trockner als “Aushilfe”.
Was brauche ich dazu?
Benötigt werden:
- zwei Luftfeuchtigkeits-/Temperatur Sensoren mit MQTT Eigenschaft. Das können welche aus meinem Artikel Wemos ESP8266 (D1 MINI) Sensor mit MQTT sein oder Shelly H & T Sensoren oder andere. WLANfähigkeit und MQTT Protokoll sind ein Muss für die hier beschriebene Lösung
- Ein Raspberry Pi – egal welcher – ein Pi Zero reicht aus. Darauf muss ein MQTT Broker (ich empfehle Mosquitto) und Node-Red installiert sein (Anleitung z.B. bei https://nodered.org/docs/getting-started/raspberrypi)
- zwei WLAN Steckdosen z.B. Shelly Plug S oder die etwas günstigeren Delock WLAN Steckdosen Schalter zum Einschalten des Ventilators und des Trockners.
- einen Fensterventilator, oder Rohrventilator oder was auch immer. In jedem Fall muss der Ventilator die Luft von außen nach innen blasen.
- Optional einen Luftentfeuchter und zwar einen, der nach dem Unterbrechen des Stroms automatisch wieder anläuft. Viele Luftentfeuchter wollen, dass man nach dem Einschalten irgendwelche Tasten drückt – bei vollautmatischem Betrieb eher hinderlich. Ich habe mich deshalb für den Aktobis WDH-610HA Luftentfeuchter entschieden, ausreichend für meinen 12m² großen Keller, 180W Leistungsaufnahme, ohne überflüssiges Chi-Chi und mit ca. 130€ recht günstig.
- Der oben erwähnte Luftentfeuchter ist inzwischen nicht mehr verfügbar. Eine Alternative wäre z.B. das Modell WDH-310EKW das sogar WiFi tauglich ist und über das Tuya Home Automation System gesteuert werden kann. Auch für Node-Red gibt es ensprechende Tuya Nodes. Leider ist die Integration nicht ohne, da man sich dann erst einen Tuya Developer Account zulegen und anschließend durch eine vermurxte Website hangeln muss, nur um die sogenannte Device ID des Geräts herauszufinden. Die Dokumentation dafür ist schrottig-grottig – so wie die meiste Software, die uns aus dem Reich der Mitte erreicht. Schlampig übersetzt, bzw. in BSE (badly spoken English), durchsetzt mit chinesischen Schriftzeichen, komplett verschwurbelte Logik etc. Ich hab’s erst einmal sein lassen und verwende weiter meine Shelly Steckdosenadapter.
Achtung: Physik
Warum verwende ich die absolute Luftfeuchtigkeit und nicht die relative Luftfeuchtigkeit zum Vergleich zwischen außen und innen?
Physikalisch gilt: je wärmer die Luft ist, desto mehr mehr Feuchtigkeit kann sie aufnehmen. Luft mit einer relativen Feuchte (= Sättigungsgrad) von 80% enthält bei 10°C ca. 7,5 Gramm Wasser pro m³ (= absolute Luftfeuchtigkeit).
Bei 25°C enhält sie 18.4 g/m³, also mehr als das Doppelte. Oder anders ausgedrückt kann es durchaus sein, dass warme Luft mit einer niedrigeren relativen Feuchtigkeit de facto “nasser” ist als kalte Luft mit einer hohen relativen Feuchtigkeit.
Ziel ist also, kalte, möglichst trockene Luft gegen warme, feuchte Luft auszutauschen. Es macht deshalb oft keinen Sinn, den Ventilator tagsüber laufen zu lassen, da die absoute Luftfeuchtigkeit draußen höher ist als drinnen – so würde die Feuchtigkeit in den Keller hineintransportiert werden anstatt hinaus.
Zum Berechnen gibt es eine Näherungsformel , die ich bei Wetterochs.de gefunden habe. Optimalerweise würde man auch noch den Luftdruck benötigen, aber die Näherung basierend auf Temperatur und relativer Feuchte reicht uns. Siehe Formel im nächsten Kapitel Flow.
Diese Formel habe ich in einen Function Node von Node-Red übertragen.
Flow
Hier zuerst einmal der zugegebenermaßen recht aufwendige Flow (anklicken für vergößerte Darstellung):
Die JSON Datei zum Herunterladen findet ihr hier. Ich lerne hier jeden Tag etwas Neues hinzu, es ist also sehr wahrscheinlich, dass mein Flow noch einiges Optimierungspotenzial aufweist.
Der Flow ist in kreuzförmig in vier bzw. fünf Teile aufgeteilt.
Links oben die Messung der Außentemperatur und Luftfeuchtigkeit (MQTT) mit Konversion.
Links unten dasselbe nur für innen.
In der Mitte die Entscheidung ob Trocknung nötig, also ob die Luft getrocknet werden muss bzw. ob sie ausreichend trocken ist.
Rechts davon die Berechnung der Methode (draußen absolut trockener als innen) –> Ventilator, sonst Trockner.
Rechts oben dann die Steuerung des Ventilators und
rechts unten dann die Steuerung des elektrischen Luftentfeuchters.
Zusätzlich sind noch diverse Nodes für das Dashboard angeschlossen.
Die Function Nodes rel2abs wandeln die relative Luftfeuchtigkeit in absolute Werte um.
Die Formel läuft sinngemäß wie folgt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
var T = parseFloat(flow.get('aussentemp')); var r = parseFloat(flow.get('aussenhum')); var aussenAF = null; var AF = 99; var a = 7.5; var b = 237.3; var RG = 8314.3; var mw = 18.016; var TK = T + 273.15; if (T <= 0){ a = 7.6; b = 240.7;} SDDt = 6.1078 * Math.pow(10 , ((a*T)/(b+T))); DDrT = r/100 * SDDt; AF = (Math.pow(10,5)*mw/RG * DDrT/TK).toFixed(1) msg.payload = AF; flow.set('aussenAF', msg.payload); return msg; |
Für den Innensensor muss das entsprechend angepasst werden. Die Variablen T und r verwende ich als Flow Variablen, da sie im weiteren Verlauf des öfteren gebraucht werden.
Dashboard
Ich habe zwei Dashboards, eines für die Messwerte:
Und eines für die Effizienz der Methode in einem eigenen Flow:
Grün ist hierbei der Ventilatorbetrieb, gelb der Trocknerbetrieb.
Der JSON Flow dazu sieht wie folgt aus:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 |
[ { "id": "998b9be7.b8b3d", "type": "tab", "label": "RF Keller", "disabled": false, "info": "" }, { "id": "33fb8f61.117f68", "type": "ui_chart", "z": "998b9be7.b8b3d", "name": "", "group": "251d9c80.de5134", "order": 1, "width": 13, "height": 6, "label": "Keller rel. LF 24h", "chartType": "line", "legend": "false", "xformat": "HH:mm:ss", "interpolate": "bezier", "nodata": "Awaiting Data", "dot": false, "ymin": "50", "ymax": "70", "removeOlder": "24", "removeOlderPoints": "", "removeOlderUnit": "3600", "cutout": 0, "useOneColor": false, "colors": [ "#1f77b4", "#aec7e8", "#ff7f0e", "#2ca02c", "#98df8a", "#d62728", "#ff9896", "#9467bd", "#c5b0d5" ], "useOldStyle": false, "outputs": 1, "x": 550, "y": 220, "wires": [ [] ] }, { "id": "351edc62.1c05ac", "type": "mqtt in", "z": "998b9be7.b8b3d", "name": "Keller innen rel. Feuchte %", "topic": "/Keller/innen/humidity", "qos": "2", "datatype": "auto", "broker": "e3a7d99a.19f948", "x": 150, "y": 220, "wires": [ [ "33fb8f61.117f68" ] ] }, { "id": "c36093d6.cff208", "type": "mqtt in", "z": "998b9be7.b8b3d", "name": "MQTT Fan Status", "topic": "/Keller/switch/fan/POWER", "qos": "2", "datatype": "utf8", "broker": "e3a7d99a.19f948", "x": 130, "y": 300, "wires": [ [ "3ee85973.b858e6" ] ] }, { "id": "1d1965be.315302", "type": "mqtt in", "z": "998b9be7.b8b3d", "name": "MQTT Dehum Status", "topic": "Keller/switch/dehum/POWER", "qos": "2", "datatype": "utf8", "broker": "e3a7d99a.19f948", "x": 140, "y": 360, "wires": [ [ "53c4bb2e.c0fdc4" ] ] }, { "id": "3ee85973.b858e6", "type": "change", "z": "998b9be7.b8b3d", "name": "", "rules": [ { "t": "change", "p": "payload", "pt": "msg", "from": "ON", "fromt": "str", "to": "1.0", "tot": "num" }, { "t": "change", "p": "payload", "pt": "msg", "from": "OFF", "fromt": "str", "to": "0.0", "tot": "num" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 540, "y": 300, "wires": [ [ "f239604.beab82" ] ] }, { "id": "53c4bb2e.c0fdc4", "type": "change", "z": "998b9be7.b8b3d", "name": "", "rules": [ { "t": "change", "p": "payload", "pt": "msg", "from": "ON", "fromt": "str", "to": "1.0", "tot": "num" }, { "t": "change", "p": "payload", "pt": "msg", "from": "OFF", "fromt": "str", "to": "0.0", "tot": "num" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 540, "y": 360, "wires": [ [ "f239604.beab82" ] ] }, { "id": "f239604.beab82", "type": "ui_chart", "z": "998b9be7.b8b3d", "name": "", "group": "251d9c80.de5134", "order": 2, "width": 13, "height": 3, "label": "Lüftung/Trocknung", "chartType": "line", "legend": "false", "xformat": "HH:mm:ss", "interpolate": "step", "nodata": "", "dot": false, "ymin": "0", "ymax": "1", "removeOlder": "24", "removeOlderPoints": "", "removeOlderUnit": "3600", "cutout": 0, "useOneColor": false, "colors": [ "#008000", "#ffff00", "#ff7f0e", "#2ca02c", "#98df8a", "#d62728", "#ff9896", "#9467bd", "#c5b0d5" ], "useOldStyle": false, "outputs": 1, "x": 800, "y": 340, "wires": [ [] ] }, { "id": "251d9c80.de5134", "type": "ui_group", "z": "", "name": "Keller Luftfeuchtigkeit", "tab": "7e312a09.8bd094", "disp": true, "width": 13, "collapse": false }, { "id": "e3a7d99a.19f948", "type": "mqtt-broker", "z": "", "name": "Brokername", "broker": "192.168.178.99", "port": "1883", "clientid": "", "usetls": false, "compatmode": false, "keepalive": "60", "cleansession": true, "birthTopic": "", "birthQos": "0", "birthPayload": "", "closeTopic": "", "closeQos": "0", "closePayload": "", "willTopic": "", "willQos": "0", "willPayload": "" }, { "id": "7e312a09.8bd094", "type": "ui_tab", "z": "", "name": "Keller LF", "icon": "dashboard", "disabled": false, "hidden": false } ] |
Zugegebermaßen ist das Alles nicht ganz einfach zu verstehen bzw. seine Hirn um die Thematik zu wickeln. Wenn ihr Fragen oder Kommentare habt, dann freue ich mich über euer Feedback.
Prima Anleitung, hat mir sehr geholfen. Da ich den Keller nicht unnötig abkühlen will, schalte ich den Lüfter nur ein, wenn es da mehr als 15℃ hat.
Irgendwie will das Chart für den Lüfter/Kondensator Status nicht laden, da muss ich noch schauen, was da falsch ist.
Danke auf jeden Fall, habe viel gelernt!
Norbert
Prima, freut mich, wenn ich die helfen konnte! Falls du einen Fehler in meiner Anleitung entdeckst freue ich mich über einen Hinweis.
Viele Grüße
Chris
Klasse! Genau so etwas habe ich gesucht – Danke.