Dewpoint controlled dehumidification/ventilation

Tags: #<Tag:0x00007f185fd1efd8> #<Tag:0x00007f185fd1eec0> #<Tag:0x00007f185fd1edf8>

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

	Item Aussenbereich_Temperature received update or
	Item Aussenbereich_Humidity received update or
	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

	Item Keller_Temperature received update or
	Item Keller_Humidity received update or
	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
	Item Keller_Dehumidification_Steady changed
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_Ventilation_Steady 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_Ventilation_Steady.state == ON) {
		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 *
 * ***********************************************************
 */
Switch Keller_Ventilation_Steady

// Entfeuchter-Variablen
Switch Keller_Dehumidification_Steady
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_Ventilation_Steady label="Dauerl├╝ftung"
		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
			}
		}
		Text item=Keller_Lueftung_RSSI
	}
	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
			}
		}
		Text item=Keller_Entfeuchter_RSSI
	}
10 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 :slight_smile:

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 ÔÇŽ

IÔÇÖm not sure about this part in the items code:

ÔÇŽ 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
	Item Keller_Dehumidification_Steady changed
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_Ventilation_Steady 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!
	if (Keller_Ventilation_Steady.state == ON) {
		sendCommand(Keller_Lueftung_Steckdose, ON)
		logInfo("Dehumidification","L├╝ftung an, da Dauerl├╝ftung eingeschaltet.")
		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.")
			])
			logInfo("Dehumidification","5 Minuten-Timer f├╝r L├╝ftung 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)
			logInfo("Dehumidification","L├╝ftung pauschal aus.")
		}

	}
	
	if (Keller_Lueftung_Steckdose.state == ON) logInfo("Dehumidification","L├╝ftung l├Ąuft.")
	else logInfo("Dehumidification","L├╝ftung ist aus.")

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.