# Dewpoint controlled dehumidification/ventilation

Since my initial project to start with smart home devices at all was to dehumidify our 400 year old basement, I decided to post my current results on that project here.

The problem was, to start ventilators only when the air outside has the correct humidity/temperature condition in order to dry the air inside the basement. For us, this is to keep the humidity in the basement as low as possible. We also have a dehumidificator, but it uses about 450 W (the ventilators only around 40 W).

The devices I use:

• two Sonoff POW switches to control ventilators/dehumidificator and to have an overview of energy consumption.
• outsite I use several sensors to identify the outdoor dewpoint (homematic weather station, homematic outdoor sensor, netatmo modul).
• inside I use netatmo modul and a AM2301 Sensor connected to Sonoff TH16 running custom firmware

But you can use whatever type of sensors and switch. I post my code below to make it public. I may translate everything into englisch when I have the time. But my approach may help the one or other already. I wasn’t able to find a complete working system before, so have fun drying you basement in a low cost way:

My script to calculate the dewpoint:

val org.eclipse.xtext.xbase.lib.Functions\$Function2<Double, Double, Double> getDewPoint = [

Double Temperature,
Double Humidity

|

var Double a
var Double b
var Double SDD
var Double DD
var Double v
var Double t = Temperature
var Double h = Humidity

if (t >= 0.0){ // T >= 0 °C
a = 7.5
b = 237.3
} else { // T < 0 °C über Wasser
a = 7.6
b = 240.7
}
SDD=(6.1078 * Math::pow(10.0, ((a*t)/(b+t))))
DD = (h/100.0*SDD)
v = Math::log10((DD/6.107))
return ((b*v)/(a-v))

]

rule "Taupunktberechnung Außenbereich" // calculation of outdoor dewpoint
when

System started

then

if ((Aussenbereich_Temperature.state != NULL) && (Aussenbereich_Humidity.state != NULL))
{

var t = (Aussenbereich_Temperature.state as DecimalType).doubleValue
var h = (Aussenbereich_Humidity.state as DecimalType).doubleValue

// OutsideThermometerCombined.sendCommand(String::format("%.1f°C / %.0f%%", t, h))

Aussenbereich_Taupunkt.postUpdate(getDewPoint.apply(t, h))

}

end

rule "Taupunktberechnung Keller" // calculation of basement dewpoint
when

System started

then

if ((Keller_Temperature.state != NULL) && (Keller_Humidity.state != NULL))
{

var t = (Keller_Temperature.state as DecimalType).doubleValue
var h = (Keller_Humidity.state as DecimalType).doubleValue

// OutsideThermometerCombined.sendCommand(String::format("%.1f°C / %.0f%%", t, h))

Keller_Taupunkt.postUpdate(getDewPoint.apply(t, h))

}

end

rule "Taupunktdifferenz berechnen" // for statistics: dewpoint difference
when
Item Keller_Taupunkt changed or
Item Aussenbereich_Taupunkt changed
then
var dewpoint_keller = (Keller_Taupunkt.state as DecimalType).doubleValue
var dewpoint_aussen = (Aussenbereich_Taupunkt.state as DecimalType).doubleValue
Taupunkt_Differenz.postUpdate(dewpoint_keller - dewpoint_aussen)
end

My script to control ventilation:

var Timer ventilation_timer = null
var Timer interval_timer = null

rule "Dehumidification" // this is to switch the dehumidificator when the inner humidity runs above a certain value
when
Item Keller_Humidity changed or
then
var Number basement_humidity = Keller_Humidity.state as DecimalType
var Number dehumitification_bottom = Dehumitification_Bottom.state as DecimalType
var Number dehumitification_top = Dehumitification_Top.state as DecimalType

if(basement_humidity >= dehumitification_top) {
sendCommand(Keller_Entfeuchter_Steckdose, ON)
}
if(basement_humidity <= dehumitification_bottom) {
sendCommand(Keller_Entfeuchter_Steckdose, OFF)
}
end

// this is the core ventilation rule. I checks the surrounding parameters an starts the ventilators for 5 minutes and waits a certain time period to let the "fresh" air collecting the humidity from the inside.
rule "Ventilation"
when
Item Aussenbereich_Taupunkt changed or
Item Aussenbereich_Temperature changed or
Item Keller_Taupunkt changed or
Item Keller_Ventilation_Interval changed or
Item Keller_Temperatur_Min changed or
Item Keller_Temperature changed or
Item Keller_Lueftung_Steckdose changed
then
var Number outdoor_dewpoint = Aussenbereich_Taupunkt.state as DecimalType
var Number basement_dewpoint = Keller_Taupunkt.state as DecimalType
var Number dewpoint_min_gap = Keller_Dewpoint_Gap_Min.state as DecimalType
var Number outdoor_temperature = Aussenbereich_Temperature.state as DecimalType

// Wenn Lüftung ständig an, dann Steckdose an!
if (Keller_Lueftung_Steckdose.state == OFF) sendCommand(Keller_Lueftung_Steckdose, ON)
} else if (outdoor_temperature <= 0) {
if (Keller_Lueftung_Steckdose.state == ON) sendCommand(Keller_Lueftung_Steckdose, OFF)
}
// Wenn Taupunkt außen höher ist, als Taupunkt Keller, in jedem Fall ausschalten!
else if (outdoor_dewpoint > basement_dewpoint) {
sendCommand(Keller_Lueftung_Steckdose, OFF)
ventilation_timer = null
interval_timer = null
}
else if (basement_dewpoint - outdoor_dewpoint >= dewpoint_min_gap) {

var Number ventilation_interval = (Keller_Ventilation_Interval.state as DecimalType).intValue

if (ventilation_timer == null && interval_timer == null) {
if (Keller_Lueftung_Steckdose.state == OFF) sendCommand(Keller_Lueftung_Steckdose, ON)
// 5 Minuten Lüften
ventilation_timer = createTimer(now.plusMinutes(5)) [|
sendCommand(Keller_Lueftung_Steckdose, OFF)
ventilation_timer = null
// Pause gem. Keller_Ventilation_Interval
interval_timer = createTimer(now.plusMinutes(ventilation_interval)) [|
sendCommand(Keller_Lueftung_Steckdose, ON)
interval_timer = null
]
]
}
}

end

My items

/* **********************************************************************
* * Einstellung der Taupunktdifferenz (Kellertaupunkt - Außentaupunkt) *
* *            2°C bis 9°C, 1°-Schritte, Standardwert 5°C              *
* **********************************************************************
* Eine Entfeuchtung erfolgt nach der eingestellten Taupunktdifferenz (effektive Feuchtigkeit).
* Der Standardwert liegt bei ca. 5°C Taupunktdifferenz. Dies ist ein Erfahrungswert um eine Entfeuchtung
* effektiv zu gewährleisten. Die Werten können zwischen 2°C und 9°C eingestellt werden. Wird die Differenz
* verkleinert, also gegen 2 gehen gelassen, wird öfter gelüftet, jedoch wesentlich weniger entfeuchtet.
*
*/
Number Keller_Dewpoint_Gap_Min

/* ************************************************************************************************
* *         Einstellung des Lüftungsintervalls (Zeit zwischen 5-Minuten-Lüftungsphasen)          *
* * 0 bis 90 Min., Entfeuchtung bei 0 Min., Erhaltungslüftung 10 bis 90 Min. in 10-Min.-Schitten *
* ************************************************************************************************
* Zur Entfeuchtung von Kellern wird hier ein automatisches Stoßlüften durchgeführt (Einstellung 0 Min.).
* Die Kellerluft wird dann durch die Querlüftung durch trockene Außenluft ausgetauscht, ohne dass sich
* die Wände abkühlen. Danach stoppt die Steuerung bei Taupunkt < 1°C) und wartet erneut auf die
* eingestellten Lüftungsbedingungen.
*/
Number Keller_Ventilation_Interval

/* **************************************************
* *      Einstellung der Innenraumtemperatur       *
* * 5°C bis 25°C in 1°-Schritten, Standardwert 8°C *
* **************************************************
*
* Mit diesem Wert wird die Absenkung der Innenraumtemperatur begrenzt.
*
*/
Number Keller_Temperatur_Min

/* ***********************************************************
* *                      Dauerlüftung                       *
* * Einschalten der Lüftung unabhängig von allen Parametern *
* ***********************************************************
*/

// Entfeuchter-Variablen
Number Dehumitification_Bottom
Number Dehumitification_Top

// Berechnete Temperaturwerte (Durchschnittswerte)
Number Aussenbereich_Humidity       "Luftfeuchtigkeit außen [%.2f %%]" 		<humidity>		(Weather, Humidity)
Number Aussenbereich_Temperature    "Temperatur außen [%.2f°C]" 	<temperature>	(Weather, Temperature)
Number Keller_Humidity              "Luftfeuchtigkeit Keller [%.2f %%]" 		<humidity>		(Weather, Humidity)
Number Keller_Temperature           "Temperatur Keller [%.2f°C]" 	<temperature>	(Weather, Temperature)

// Berechnete Taupunktwerte (siehe dewpoint.rules)
Number Keller_Taupunkt "Taupunkt Keller [%.2f°C]"       (Weather, Temperature)
Number Aussenbereich_Taupunkt "Taupunkt außen [%.2f°C]" (Weather, Temperature)
Number Taupunkt_Differenz "Taupunktdifferenz [%.2f°C]"  (Weather, Temperature)

My sitemap

Frame label="Lüftungsprogramm" {
Setpoint item=Keller_Ventilation_Interval icon="clock" label="Lüftungsintervall [%.0f Min.]" step=10 minValue=0 maxValue=90
Setpoint item=Keller_Dewpoint_Gap_Min icon="water" label="Taupunktdifferenz (5°C) [%.1f°C]" step=1 minValue=2 maxValue=9
// Setpoint item=Keller_Temperatur_Min icon="temperature" label="Min. Temperatur (8°C) [%.1f°C]" step=1 minValue=5 maxValue=25
Switch item=Keller_Lueftung_Steckdose
Text item=Keller_Lueftung_Power {
Frame {
Text item=Keller_Lueftung_Power
Text item=Keller_Lueftung_Pow_Total
Text item=Keller_Lueftung_Pow_Yesterday
Text item=Keller_Lueftung_Pow_Today
}
}
}
Frame label="Entfeuchtung" {
Setpoint item=Dehumitification_Bottom icon="rain" label="Entfeuchter aus [%.0f %%]" step=1 minValue=0 maxValue=90
Setpoint item=Dehumitification_Top icon="rain" label="Entfeuchter an [%.0f %%]" step=1 minValue=0 maxValue=90

Switch item=Keller_Entfeuchter_Steckdose
Text item=Keller_Entfeuchter_Power {
Frame {
Text item=Keller_Entfeuchter_Power
Text item=Keller_Entfeuchter_Pow_Total
Text item=Keller_Entfeuchter_Pow_Yesterday
Text item=Keller_Entfeuchter_Pow_Today
}
}
}
12 Likes

Thank you for sharing this with us ! It is always great to see what problems and solutions other have found.

Do you happen to have any before/after data ? (Power consumption, humidity, … ?)

Sorry for reviving this old thread but I would like to thank @kisseler very much for this excellent tutorial! I am currently using it as a very helpful starting point for my own basement ventilation. In my new home, I found out that the basement is quite wet, too. An approach like this looks very promising!

Just as @Spottyq I would be glad to hear something about your experiences with this topic. Maybe you have refined your ideas and may share them with the community? Thanks a lot!

1 Like

Many thanks for sharing this project

I have quite the same situation at my house.
It would be great if you could tell me which ventilators do you have and how they are installed. I’m thinking about to install two ventilators - one for blowing air into the cellar and one for blowing air out of the cellar …

… the comment “Berechnete Temperaturwerte (Durchschnittswerte)” confuses me.
Where one gets the data from for these items?

That’s exacly how I do it at the moment. I installed one ventilator in the one end of the basement and another on the other end. I used the ventilators that I bought with my former control from keller-doktor.de: https://www.kellerlueftung24.de/epages/17633109.sf/de_DE/?ObjectPath=/Shops/17633109/Products/CF12452
And I have a dehmidificator, that you can turn on by connecting mains and turn off by deconnecting.
Both systems are powered/controlled by a Sonoff Pow in order to have an eye on the power consumption. For me that is especially interesting because the ventilators use about 50 W in total and the dehumidificator about 300 W. The dehumidificator is made use of only when the outdoor/indoor climate gap does not allow ventilation.

The Headline Berechnete Temperaturwerte (Durchschnittswerte) is only a headline. The temperature/humidity values can be gained by any sensor in your smart home setup. I have two different sensors in the outside (outdoor sensor on the north and weather station on the roof). And I have two DHT22 sensors in the basement on different places. So I calculate the average values that are used by my rules.

I did not have too many time to do evaluation. But I can say, that especially in the summer it is amazingly often that the weather conditions don’t allow ventilation - even during the night!

And with a new setup I would have chosen stronger/bigger ventilators (I have currently the 150 mm type installed).

My current rules look like that:

var Timer ventilation_timer = null
var Timer interval_timer = null

rule "Dehumidification"
when
Item Keller_Humidity changed or
then
var Number basement_humidity = Keller_Humidity.state as DecimalType
var Number dehumitification_bottom = Dehumitification_Bottom.state as DecimalType
var Number dehumitification_top = Dehumitification_Top.state as DecimalType
var Number dewpoint_gap = Taupunkt_Differenz.state as DecimalType
var Number dewpoint_min_gap = Keller_Dewpoint_Gap_Min.state as DecimalType

if(basement_humidity >= dehumitification_top && dewpoint_gap <= dewpoint_min_gap) {
sendCommand(Keller_Entfeuchter_Steckdose, ON)
}
if(basement_humidity <= dehumitification_bottom) {
sendCommand(Keller_Entfeuchter_Steckdose, OFF)
}
end

rule "Ventilation"
when
Item Taupunkt_Differenz changed or
Item Keller_Ventilation_Interval changed or
Item Keller_Temperatur_Min changed or
Item Keller_Lueftung_Steckdose changed
then
var Number dewpoint_gap = Taupunkt_Differenz.state as DecimalType
var Number dewpoint_min_gap = Keller_Dewpoint_Gap_Min.state as DecimalType
var Number outdoor_temperature = Aussenbereich_Temperature.state as DecimalType
var Number ventilation_interval = (Keller_Ventilation_Interval.state as DecimalType).intValue

logInfo("Dehumidification","Außentaupunkt muss niedriger sein als Kellertaupunkt. Taupunktdifferenz (Keller minus Außen) ist " + dewpoint_gap + ". Mindestdifferenz ist " + dewpoint_min_gap + "." )

// Wenn Lüftung ständig an sein soll, dann Steckdose an!
sendCommand(Keller_Lueftung_Steckdose, ON)
ventilation_timer = null
interval_timer = null
}
// Auskühlung des Kellers verhindern
else if (outdoor_temperature <= 2) {
sendCommand(Keller_Lueftung_Steckdose, OFF)
logInfo("Dehumidification","Lüftung aus, da Außentemperatur niedriger als 2°C.")
ventilation_timer = null
interval_timer = null
}
// Wenn Taupunkt außen höher ist, als Taupunkt Keller, in jedem Fall ausschalten!
else if (dewpoint_gap <= 0) {
sendCommand(Keller_Lueftung_Steckdose, OFF)
logInfo("Dehumidification","Lüftung aus, da Außentaupunkt höher als Kellertaupunkt.")
ventilation_timer = null
interval_timer = null
}
// Lüftungsprogramm abfragen
else if (dewpoint_gap >= dewpoint_min_gap) {

if (ventilation_interval > 0 && ventilation_timer === null && interval_timer === null) {

if (Keller_Lueftung_Steckdose.state == OFF) sendCommand(Keller_Lueftung_Steckdose, ON)

// nach 5 Minuten Lüften ausschalten
ventilation_timer = createTimer(now.plusMinutes(5), [|
sendCommand(Keller_Lueftung_Steckdose, OFF)
ventilation_timer = null
logInfo("Dehumidification","Lüftung aus, da 5 Minuten gelüftet.")
// Pause gem. Keller_Ventilation_Interval
interval_timer = createTimer(now.plusMinutes(ventilation_interval), [|
sendCommand(Keller_Lueftung_Steckdose, ON)
interval_timer = null
logInfo("Dehumidification","Lüftung an, weil " + ventilation_interval + " Minuten Pausen-Intervall vorbei.")
])
logInfo("Dehumidification", ventilation_interval + "-Minuten-Timer für Pausen-Intervall gesetzt.")
])
} else if (ventilation_interval == 0) {
if (Keller_Lueftung_Steckdose.state == OFF) sendCommand(Keller_Lueftung_Steckdose, ON)
}

} else if (ventilation_timer === null && interval_timer === null) {

if (Keller_Lueftung_Steckdose.state == ON) {
if (Keller_Lueftung_Steckdose.state == ON) sendCommand(Keller_Lueftung_Steckdose, OFF)
}

}

if (Keller_Lueftung_Steckdose.state == ON) logInfo("Dehumidification","Lüftung läuft.")

end
1 Like

I have installed just one ventilator like this that blows the air out of the cellar:
https://www.amazon.de/dp/B00RLR6Y14/
But please note - in contrast to its specifications it does not consume 8 W but up to 12 W according to my own measurements. I monitor this by using a FRITZ!DECT 200 which is also controlled by openHAB. My assumption is that incoming air will be automatically sucked into the house as it is not that sealed. I have replaced a cellar window with a moisture-proof panel and I sawed a corresponding hole for the ventlator in it. I do not use any dehumidificator so far. I will monitor the operation of my system next summer and add one if my current setup is not sufficient.

I have the same observation.

Thank you for your response and the updated rules file.

I think I’ll order two 237 mm ventilators of this kind:

… and mount it into the cellar windows.

Why did you switch from the “Kellerdoktor”-Control-Device to your custom solution?

I also already have dehumidification - so it’s quite the same setup.
My cellar consists of 3 rooms which are connected by open doors - in total approx. 65 m².

I used to have such a small ventilator too - but the performance for my cellar is far too poor. Thus I’m happy that I’ve found this thread.

Hey, I’m just curious, how can I adapt this to my house dehumidifier?
Could someone explain shortly how to do the work with the code?
Thanks!

The Tutorials & Examples section is not for questions unless they’re directly related to the examples or tutorial. Open a new thread.

@kisseler

1. Could you please let me know what the purpose of the item Keller_Dehumidification_Steady is?
In my setup, I have a Sonoff POW before the dehumidifier to track energy consumption. The dehumidifier itself has a humidity sensor.

In order to follow your setup, I guess I need to replace Keller_Dehumidification_Steady with KE_x_pow1_switch and set the threshold to 100%. So the dehumidifier will run as long as KE_x_pow1_switch is ON, right?

Some more questions:
2) Not sure how to use Keller_Temperatur_Min
3) Do makes these settings sense?

That would be it.

Keller_Temperatur_Min is meant as threashold, so not too cold air is blown into the house. First it might affect the temperature in the rest of the house, second too cold air is quite ineffective in drying.

Your settings (65% turn dehumidifier of, 66% turn it off) might cause a bit of a “nervous” behaviour, so I chose a range between 3 an 10 % as hysteresis.

1 Like

@kisseler

Another question:

It seems that my setup is dealing with different units which switch the dehumidifier always off

Entfeuchter AUS (basement_humidity [76.63 %]  <= dehumitification_bottom [55]
var Timer ventilation_timer = null
var Timer interval_timer = null

rule "Dehumidification"
when
Item KE_s_XiaomiTemperatursensorC_Humidity changed or
Item KE_x_pow1_switch changed
then
var Number basement_humidity = KE_s_XiaomiTemperatursensorC_Humidity.state as QuantityType<Number>
var Number dehumitification_bottom = Dehumitification_Bottom.state as DecimalType
var Number dehumitification_top = Dehumitification_Top.state as DecimalType
var Number dewpoint_gap = Taupunkt_Differenz.state as DecimalType
var Number dewpoint_min_gap = Keller_Dewpoint_Gap_Min.state as DecimalType

if(basement_humidity >= dehumitification_top && dewpoint_gap <= dewpoint_min_gap) {
sendCommand(KE_x_pow1_switch , ON)
logInfo("Dehumidification","Entfeuchter AN (basement_humidity [" + basement_humidity + "]  >= dehumitification_bottom [" + dehumitification_top + "]" )
}
if(basement_humidity <= dehumitification_bottom) {
sendCommand(KE_x_pow1_switch , OFF)
logInfo("Dehumidification","Entfeuchter AUS (basement_humidity [" + basement_humidity + "]  <= dehumitification_bottom [" + dehumitification_bottom + "]" )
}
end

How can one fix this?

When multiplying with 100 it works now

var Number basement_humidity = KE_s_XiaomiTemperatursensorC_Humidity.state as QuantityType<Number> * 100

Just in case someone runs into the same issue concerning lambda expression and type mismatch

Hallo Zusammen, ich bin absoluter Neuling und versuche verzweifelt überhaupt mal das Script mit dem Taupunkt hinzubekommen. Ich erhalte aber im Log ausschließlich mehr Fehler…

Ich nutze OH 3 und habe einen Sonoff Temperatur und Feuchte Sensor.

Kann der darf ich Neulingsfragen hier stellen? Sind sicher auch Fragen dabei die sich für Euch komisch anhören…

For sure you should ask questions. That is the way to learn ting. But please do it in englisch,

Question 1: Do you get humidity and teperature values, if not this is the first thing to solve.

quetsion2: Please post the errors. A simple it does not work is not enough to help.