DIY Arduino Koelspiegel-hygrometer: Precieze temperatuur- en vochtigheidsmeting
Onderdelen en benodigdheden
- Arduino UNO (1×)
- 12 V 10 A voeding (1×)
- 12 V 40 mm high-power ventilator (1×)
- 12 V 40 mm TEC (Peltier-element) (1×)
- 40 mm warmteuitwisselaar (heatsink) (1×)
- Klein spiegeltje (1×)
- Thermisch geleidende lijm (1×)
- Warmtepasta (1×)
- BTS7960 motordriver (voor Peltier-stroom) (1×)
- 3 mm gele LED (lichtbron, 1×)
- OPT101 lichtsensor (geïntegreerde fotodiode + versterker) (1×)
- IRF520 MOSFET-module (voor ventilatorsturing) (1×)
- DS18B20 1-Wire digitale temperatuursensor (omgevingsemperatuur, 1×)
- Si7021 temperatuur/vochtigheidssensor (voor spiegeltemperatuur, 1×)
Benodigde tools en machines
- Lijmpistool
Apps en online services
- Arduino IDE
Over dit project
Over
Vochtigheidsmeting kan op veel manieren. Capacitieve sensoren zijn populair, maar verliezen snel nauwkeurigheid bij continue hoge vochtigheid. Een Koelspiegel-hygrometer (Chilled Mirror Hygrometer) heeft dit probleem niet en is veel nauwkeuriger, vooral in het hoge vochtigheidsbereik. Commerciële modellen kosten duizenden dollars, maar het principe is simpel genoeg voor DIY. Deze proof-of-concept haalt niet de 0,1 °C nauwkeurigheid van commerciële apparaten, maar is voor meeste doeleinden voldoende en superieur aan capacitieve sensoren.
Hoe het werkt
Een Peltier-element (TEC) koelt een reflecterend oppervlak (spiegel) tot er condensatie ontstaat. Een lichtbron (LED of laser) en een optische sensor (OPT101) detecteren de condensatie. De spiegeltemperatuur op het moment van condensatie = dauwpunt. Relatieve vochtigheid (RH) wordt berekend uit dauwpunt en omgevingstemperatuur (August-Roche-Magnus benadering).
Vereenvoudigingen t.o.v. commercieel
- Spiegel: Commercieel: platina/rhodium-geplate koper. DIY: gewone spiegel (of gepolijst RVS). Vierkante spiegel beter dan ronde; niet te vinden.
- Temperatuursensor: Commercieel: Platinum Resistance Thermometer (PRT) onder spiegel ingebouwd. DIY: SMD-sensor (Si7021) op spiegel geplakt. Minder nauwkeurig door warmtestoring, maar makkelijker.
- Afmetingen: Commercieel: ~5 mm spiegel. DIY: ~4 cm (makkelijker beschikbaar, minder stroom, standaard driver).
- Lichtafscherming: Geen behuizing in deze versie. 3D-print aanbevolen (wel geventileerd, lucht naar binnen trekken, niet wegblazen). Toegang voor spiegelreiniging.
- Rijppunt: Niet meetbaar (vereist tweede optische sensor voor verstrooiing).
Hoe te bouwen
- Peltier + heatsink: Schoon beide vlakken, smeer thermisch geleidende lijm (of warmtepasta + superglue op randen) op warme kant Peltier. Druk heatsink erop, laat drogen.
- Spiegel op koude kant: Schoon, smeer warmtepasta gelijkmatig (geen luchtbellen!), druk spiegel erop, laat drogen.
- Ventilator: Bevestig op heatsink (lijmpistool). Zorg voor voldoende capaciteit – heatsink wordt heet.
- Test condensatieprofiel: Ventilator aan, Peltier kort aan. Kijk waar condensatie tegelijkertijd verschijnt. Foto of markeer die plek – daar komen sensoren. Langdurig aan = uniforme condensatie (niet gewenst voor meting).
- Temperatuursensor (Si7021) monteren: Grote drup niet-geleidende warmtepasta op sensor, PCB ook bedekken (condensatiepreventie). 4 klonters hete lijm op PCB-hoeken, snel drukken op gemarkeerde plek, horizontaal. Hete lijm hardent direct. Herpositioneren: afschrapen, nieuwe lijm.
- Lichtbron & sensor: LED of laser (beide werken). Laser: betere respons, lastiger uitlijnen. LED: breder straal, makkelijker. PWM niet gebruiken (storing), serieweerstand voor stroombegrenzing. Montage met koperdraad + hete lijm (proof-of-concept); 3D-geprinte houder in behuizing is beter.
- Peltier-driver: BTS7960 motordriver (PWM-sturing, minder efficiënt dan stroomsturing, maar beschikbaar).
- In bedrijf stellen: Code uploaden, OPT101 gevoeligheid instellen met potentiometer (zie datasheet Fig. 3). Debug: op spiegel blazen voor condensatie, of object voor sensor. Airco aan/uit → vochtigheidsverandering zichtbaar.



Onevenmatige warmtepasta → onregelmatig condensatieprofiel (zie foto).




Veiligheid
Hardware kan de spiegel ook verwarmen (polariteit Peltier omdraaien) voor sneller verdampen condensatie en snellere respons. Risico: als code vastloopt in verwarmen-modus → smelt lijm, draden, brandgevaar. De meegeleverde code ondersteunt dit niet.
Nauwkeurigheid
- Dauwpunt is absolute waarde → kalibratie minder kritisch dan capacitieve sensoren.
- Temperatuurverschil sensor- vs lichtmeetplek introduceert fout. Kalibreer met commerciële koelspiegel-hygrometer indien nodig.
- Vervuiling spiegel: meetprincipe is relatief (referentie = begin koelcyclus), dus lichte vervuiling geen probleem. Maar sommige vervuiling verschuift condensatietemperatuur → regelmatig schoonmaken.
- Resolutie temperatuursensoren belangrijker dan absolute calibratie. Jitter <0,1 °C gewenst. TSYS01 sensoren (PRT-nauwkeurigheid) aanbevolen voor beide metingen.
- Goed thermisch contact sensor-spiegel cruciaal (niet-geleidende warmtepasta).
- Koelsnelheid < responstijd sensor, anders onnauwkeurig dauwpunt.
- Sensor op plek plaatsen waar condensatie tegelijkertijd met lichtmeetplek ontstaat.
- Infrarood-thermometer niet geschikt (spiegel reflekteert thermische straling).
- Luchtdruk invloed minimaal in omgevingsomstandigheden; sluitende deuren/wind geven meer ruis.
- Hete lucht heatsink niet over spiegel trekken.
- Langzame koeling = nauwkeuriger, maar langzamere respons. Respons verbeteren door temperatuur te laten oscilleren rond dauwpunt.

Code
Arduino-sketch Chilled Mirror Hygrometer (C/C++). Vereist custom libraries: Si7021.h, Timer.h, timerManager.h, plus standaard OneWire, DallasTemperature, avr/wdt.h.
#include <math.h>
#include <avr/wdt.h>
#include "Si7021.h"
#include <OneWire.h>
#include <DallasTemperature.h>
#include "timer.h"
#include "timerManager.h"
#define coolingPWM 6
#define heatingPWM 5
#define coolingEnable 13
#define heatingEnable 12
#define tecFan 7
#define opticalSensor 0
#define oneWireBus A3
#define COOLING 0
#define HEATING 1
#define OFF 2
Timer timerMainLoop;
Timer timerTecCooling;
Timer timerSampleNoise;
Si7021 si7021;
OneWire oneWire(oneWireBus);
DallasTemperature sensors(&oneWire);
float humidity = 0;
float ambientTemp = 0;
float opticalDewpoint = 0;
float mirrorTemp = 30;
float optical = 30;
float dewPoint = 15;
float relativeHumidity = 30;
int tecState = OFF;
bool cooling = false;
int intervalTecCooling = 200;
float opticalThreshold = 0.5f;
int pwmIncrement = 1;
int startPwm = 100;
int maxPwm = 255;
int intervalMainLoop = 200;
int tecPwm = 0;
int noiseSampleIndex = 0;
int noiseSampleAmount = 10;
float noiseSampleHighest = 0;
float noiseSampleLowest = 10000;
bool noiseSampling = false;
float calculateHumidity(float TD, float T) {
if (TD > T) TD = T;
float rh = 100 * (exp((17.625*TD)/(243.04+TD)) / exp((17.625*T)/(243.04+T)));
return rh;
}
void SetTEC(int state, int amount) {
tecState = state;
switch(state) {
case COOLING:
digitalWrite(heatingEnable, HIGH); analogWrite(heatingPWM, 0);
digitalWrite(coolingEnable, HIGH); analogWrite(coolingPWM, amount);
break;
case HEATING:
digitalWrite(coolingEnable, HIGH); analogWrite(coolingPWM, 0);
digitalWrite(heatingEnable, HIGH); analogWrite(heatingPWM, amount);
break;
case OFF:
default:
digitalWrite(coolingEnable, LOW); analogWrite(coolingPWM, 0);
digitalWrite(heatingEnable, LOW); analogWrite(heatingPWM, 0);
}
}
void setup() {
wdt_enable(WDTO_2S);
Serial.begin(9600);
pinMode(coolingPWM, OUTPUT);
pinMode(heatingPWM, OUTPUT);
pinMode(coolingEnable, OUTPUT);
pinMode(heatingEnable, OUTPUT);
pinMode(tecFan, OUTPUT);
pinMode(opticalSensor, INPUT);
timerMainLoop.setInterval(intervalMainLoop);
timerMainLoop.setCallback(mainLoop);
timerMainLoop.start();
timerTecCooling.setInterval(intervalTecCooling);
timerTecCooling.setCallback(tecCoolingCallback);
timerSampleNoise.setInterval(intervalTecCooling);
timerSampleNoise.setCallback(sampleNoiseCallback);
si7021.begin();
sensors.begin();
startNoiseSampling();
}
float getOptical() {
int opt = analogRead(opticalSensor);
return (float)opt / 30.0f;
}
void tecCoolingCallback() {
digitalWrite(tecFan, HIGH);
tecPwm += pwmIncrement;
if (tecPwm > maxPwm) tecPwm = maxPwm;
SetTEC(COOLING, tecPwm);
if (optical <= (noiseSampleLowest - opticalThreshold)) {
dewPoint = mirrorTemp;
opticalDewpoint = optical;
stopTec();
}
}
void startNoiseSampling() {
noiseSampling = true;
noiseSampleHighest = 0;
noiseSampleLowest = 10000;
timerSampleNoise.start();
}
void sampleNoiseReset() {
timerSampleNoise.stop();
noiseSampleIndex = 0;
noiseSampling = false;
}
void sampleNoiseCallback() {
if (noiseSampleIndex > noiseSampleAmount) {
sampleNoiseReset();
startTecCooling();
} else {
if (optical > noiseSampleHighest) noiseSampleHighest = optical;
if (optical < noiseSampleLowest) noiseSampleLowest = optical;
}
noiseSampleIndex++;
}
void startTecCooling() {
cooling = true;
digitalWrite(tecFan, HIGH);
tecPwm = startPwm;
timerTecCooling.start();
}
void stopTec() {
cooling = false;
digitalWrite(tecFan, LOW);
timerTecCooling.stop();
SetTEC(OFF, 0);
}
void mainLoop() {
sensors.setResolution(10);
sensors.requestTemperatures();
ambientTemp = sensors.getTempCByIndex(0);
mirrorTemp = si7021.measureTemperature();
optical = getOptical();
relativeHumidity = calculateHumidity(dewPoint, ambientTemp);
// Serial Plotter output
Serial.print(mirrorTemp, 2); Serial.print(" ");
Serial.print(optical, 2); Serial.print(" ");
Serial.println(dewPoint, 2);
if (!cooling && !noiseSampling && (optical >= noiseSampleLowest)) {
startNoiseSampling();
}
}
void loop() {
wdt_reset();
TimerManager::instance().update();
}
Schema's

Productieproces
- De Wetenschap en Vakmanschap van Moderne Spiegels
- Bluetooth-gecontroleerde Arduino Spybot bouwen
- FlickMote: Gebarengecontroleerde IR-afstandsbediening voor Slimme Huizen
- DIY Arduino TV-B-Gone: Universele TV-uit-schakelaar
- DIY Kaleidoscoop Oneindige Spiegel – Bouw een Indrukwekkende LED-lichtdisplay
- Bouw een Aangepaste LED Hoofdklok met Alarm – Zichtbaar vanaf 12 Meter
- Find Me: Slimme Item Locator met Arduino en Bluetooth
- Geoptimaliseerde Voedingsoplossingen voor Arduino Projecten
- Arduino Boter-Kaas-Eieren met MAX7219 LED Matrix en Kartonnen Behuizing
- Bouw een Slimme Arduino Vierpotige Robot: Stap-voor-Stap Handleiding
- Bouw een Aangepaste Arduino Joystick Stuurwiel voor Gaming