Humidity-Based Fan Controller

Daniel Koch and Liam Davies

Issue 58, May 2022

A fan controller with a difference.


Most fan control projects we see feature a temperature sensor with a threshold limit, and a fan turns on once this threshold is reached. This project is different. We have two humidity sensors for this set-up, one of which will be positioned inside the space of concern, and the other outside of it. The controller is designed to measure the difference between outside and inside, and only engage the fan when the inside air is above a threshold but the outside air is not worse.

The idea here is a situation like a growing house for plants, or a household roof space with bathroom fans exhausting shower steam into the roof space. Some roofs are far more sealed than others, and in some houses, this is bad enough to lead to mould growth when damp air is constantly pumped into the space. The same can be said of environments for plants:

Excessive humidity, which comes from the plants anyway, leads to fungal diseases. However, in both cases, there is little value in turning on fans to change the air with outside air once humidity reaches a certain point, if that outside air is more humid at the time than the air inside. This can happen on its own on certain days, but is almost guaranteed during rain.

Accordingly, we set about constructing a controller which would measure humidity, and also give a PWM signal to control a MOSFET motor driver. The MOSFET itself is fairly straightforward, because we chose a logic-level device with a low gate capacitance and threshold voltage, enabling it to be driven from the GPIO of an ATtiny85 without an intermediate gate driver. Many microcontroller designs use MOSFETs without drivers, but as we covered in Classroom Issue 43, this can have consequences in terms of current handling or long-term reliability if the right MOSFET is not chosen. It is not just about the current handling!

We chose an ATtiny85 for the sake of cost and space. There is just no need for anything bigger. We decided to go with two separate MOSFET outputs, each driven from its own I/O to be identical. This enables an input and output fan to be used, each on their own MOSFET. Heatsinking space will be limited, and the fans we have in mind draw up to 10A continuous, and more for start-up. We chose to use car radiator fans. These are very high-flow, easy to source, run on 12V already, and most importantly, they are ruggedised and rated for a wet environment in the engine bay of a car. The challenge will be powering these beasts reliably! For that, a PC power supply will be called on. However, the right one has to be chosen, as some are approaching their 12V current limit for two fans, and cheaper ones often cannot provide the start-up surge current required.


There is sometimes confusion about what relative humidity is. We hear the term sometimes in weather reports and the like, but there are plenty of people who have little interaction with it and often don't know what the terms mean. Most people know it has something to do with moisture in the air, but beyond that, it's a mystery. Generally, the term 'humidity' when used in most situations means 'relative humidity'. Water evaporates into air, and there are different factors which influence this. The biggest is temperature. Lesser factors include air pressure, but at regular atmospheric ranges the difference is so small, we don't bother. In a pressure vessel, things would be different. Wind speed has a great effect on the rate of evaporation for water, but not on the humidity of a given volume of air, except when that wind is mixing different volumes of air. Even then, it still isn't affecting the humidity itself but rather the perception of it from the point of measurement.

Therefore, humidity is the amount of moisture that is in the air at a given time. Absolute Humidity is the amount of moisture in the air. It has no other variables and is measured, most commonly, in grams per cubic metre of air (g/m3). However, this term is rarely used in everyday life. We are more used to Relative Humidity, which is the amount of moisture in the air relative to the amount that air at that temperature could hold.

So, a relative humidity reading of 60% means that the air at the point of measurement has 60% of the moisture that it could hold at that temperature. The lower the temperature, the less moisture air can hold. The same volume of water evaporated into one cubic metre of air will have a much higher relative humidity percentage at ten degrees Celsius than it would at forty-five degrees Celsius, because air at forty-five degrees can hold much more moisture.

It is relative humidity that our bodies perceive as 'dampness'. That's why we feel that we can't get dry as easily after getting out of a pool or the like on a day of high humidity when compared to the same on a day of lower humidity: The air is closer to capacity and it takes longer for moisture to evaporate from our skin. It is also an important factor in mould growth and many fungal diseases in plants.


One of the most common humidity sensors in the maker market that is available at retailers is the DHT11. It has almost become the generic sensor, and, in fact, many examples are clones from different manufacturers. However, it has a maximum relative humidity (RH) rating of 80%, and a temperature maximum capability of 0 - 50°C. Our initial plan did not call for temperature to be measured, so we went looking for a better sensor. As it turns out, they're rather hard to find. In the end, we bought a sensor from Element14 that we could not find on the retail market.

This sensor is a capacitive element which is varied by relative humidity. At face value, it might seem more logical for the sensor to be a measurer of Absolute Humidity, because it seems that the amount of water which might affect capacitance would not change even if the amount of water that the air could be holding at that time did change. However, this is not the case. This project isn't the place to present the science lesson on why, and honestly the result wouldn't justify the source-searching, fact-checking, and revision to ensure accuracy. The fact that the manufacturer clearly labels the device as a 'Relative Humidity Sensor' rather than just a 'Humidity Sensor' is enough evidence. Accuracy guarantees are given, too.

On the face of it, this sensor seemed great. It has an operating temperature of between 60°C and 140°C, and a 0 - 100% RH range. The sensor works by being the heart of an oscillator: As the relative humidity changes, the capacitance of the device changes in a very predictable way. Therefore, the oscillator will change its output frequency accordingly. Better still, the datasheet for the device even suggests an oscillator circuit, based on the 555! A CMOS 555, but a 555 nonetheless, meaning most makers are already familiar with the circuit.

However, things are not quite so rosy. We need a way to turn the frequency into a voltage if we want to use a comparator to switch the fan on and off. The LM2917 we featured in Classroom recently was not suitable, as the capacitance of the sensor did not match the requirements of that IC to give the voltages desired. Under normal circumstances, capacitor and resistor values are chosen to give the voltages desired, but here the capacitor is dictated by the sensor. Things got even more complicated when we decided that we also wanted the future capability of temperature sensing.

The need to work with the frequency we had from the oscillator, despite the ability to change it somewhat by varying the resistors in the oscillator, meant that we were no longer building an discrete circuit. A microcontroller was now required. Given this, the possibility was opened to additional features. Temperature sensors could now easily be added, as well as the ability to give a varied PWM signal to control motor speed.

However, the effort to build the capacitive sensor circuits was beginning to feel very redundant, despite the increased range (and accuracy) of the capacitive sensor against the DHT11. Four separate circuits are required: Inside and outside humidity sensors based on an oscillator; and inside and outside temperature sensors based on either a thermistor straight to the MCU using digital to analog conversion, or with a comparator in between to provide digital IO.

After we considered the ease of availability of the DHT11 versus the fact that the capacitive sensor is only available from commercial suppliers like Element14 (always an important factor for us); and the single-wire ability of one sensor to communicate temperature and humidity on one pin, we chose to go with the DHT11. This will limit the functionality of the circuit in the intended roofspace environment, where the temperature will regularly exceed 50°C in summer, but given that the fan would likely be turned on before then in temperature-controlled situations, we think this is acceptable in light of the above factors.

The same goes for the limited humidity range. We'll keep working on this idea for later, for a much more capable and rugged version but for now, an MCU with DHT11 sensors was the plan.


With that decision made, the build became much simpler. We chose an ATtiny85 as the MCU, which has enough I/O pins for the task, is cheap, and more than capable of the somewhat simple task asked of it. In addition to the DHT11s, which needed a pin each, we decided to use two MOSFETs, each driven with their own pin.

The intention was for two fans to have their own driver circuit working in parallel. This avoids any conflicts between the dynamics of the motors, and guarantees current handling even during startup surges. The MOSFETs chosen were logic types. We used IRLZ44Ns but any logic level MOSFET with a high enough current rating will do.

There was still a concern over the amount of time the MOSFET would spend in the saturation zone with only the 20mA current of the ATTiny I/O to charge the gate capacitor, although being a logic-level MOSFET, it is designed with a lower gate voltage threshold and smaller capacitance.

Even so, we decided to heatsink the MOSFETs without even stopping to calculate the requirement. The rationale here was that we could use the heatsink as a mounting surface for both the MOSFETs and the terminals to connect the motors, and a heatsink big enough to have mounting flanges will be big enough for the MOSFETs no matter how much heat they generate.

That's assuming the end use is not bigger than a radiator fan, however, but some of these still draw 15A or more.

Having two fans was aimed at having one push air into the roofspace at one end, and the other to draw it out at the far end. There were two options: To have the MOSFETs together close to the controller, to avoid the resistance of the wires between gate and I/O pins; or have them near the motors and use long wires to drive the gates.

We chose to keep them together, because the power supply would also need to be run out to the motors if the MOSFETS were separated. The final design calls for a PC power supply to run the motors and drive circuit. Long twin-core would be used to connect the motors to the MOSFETs.

Housings were needed for the sensors. The outside sensor would need to be rainproof, but the inside sensor needed a cover as well. We use the terms 'inside' and 'outside' rather than indoors or out, because in situations like a plant propagation hothouse, the location may still be considered 'outdoors', being not in a building and consisting of little more than a metal frame with a plastic skin. This environment often has a lot of condensation and other contamination such as heavy dust that is not present 'indoors' in a normal building. In the roofspace environment, however, and in some growing houses, temperatures far exceed what PLA can cope with. While we could print in another filament, plenty of makers only have PLA experience. It was better to go with commercial options.

Accordingly, the outside sensor was mounted in a small project enclosure, with cutouts in the sides and lid, with metal fly screen glued over the holes. This allows air flow while keeping insects and larger dust and contaminants out.

The enclosure is intended to be suspended upside down, with the sensor in the middle and spaced down from the top so that heat from the plastic in sunlight makes less of an impact on the temperature reading. The inside sensor is similar, but with larger openings because of the intended lack of rain and wind. In horticultural environments with some types of irrigation, the outside sensor design may be necessary inside, too.

In addition to the two DHT11 sensor inputs, we built in a pushbutton for manual operation of the fans. The intention before we started building was for a button inside the house that could start the fans if there was a reason that had not been thought of in the code design, or just to override it. For example, in extended wet conditions, there may not be a humidity difference to activate the fans, but you may wish to circulate the air anyway to refresh it.

Having read our thinking and rationale, you might find you can adapt and alter the design. If your situation is different from our intended use, there are aspects of this build that may not apply, and other factors that may, which we did not have to consider.

The Build:

Parts Required:IDJaycarAltronicsPakronics
1 x Solder Breadboard-HP9570H0701ADA1609
1 x Packet of Wire Links-PB8850P1014ASS110990044
1 x 10nF Ceramic CapacitorC2RC5348R2846DF-FIT0118
1 x 470µF 16V Electrolytic CapacitorC1RE6194R5163DF-FIT0117
2 x 240Ω ResistorsR4, R5RR0557R7543SS110990043
3 x 10kΩ ResistorsR1, R2, R3RR0596R7582SS110990043
1 x ATtiny85IC1ZZ8721Z5105-
2 x IRLZ44N MOSFETsQ1, Q2Element14: 865141802Z6320 %DF-DFR0067
2 x DHT11 Sensor Modules-XC4520H0804A-
12 x PCB Pins-HP1250P0550-
1 x IC Socket-PI6500S1060CSS110990055
1 x Pushbutton SwitchSW1SP0710P2140A-
4 x Screw Terminal Block-HM3196H0568-
Heatsink to suit, user-determined-HH8572W2283-
Hookup Wire-WH3052W2100-
Light-Duty Speaker Wire-WB1702W7100-
Cat5E Cable-WB2020HF0205-
1 x Enclosure for Circuit-HB6016H0203-
1 x Enclosure for Sensor Mounting, user-determined-HB6013

Parts Required:

You'll also need 2 x Fans of Choice, from case fans to radiator fans. Hookup wire to suit, and some Metal Fly Screen.

%Not a direct equivalent, may need different code

We built the circuit on one of our favourite products: Solder breadboard. These boards are almost a hole-for-hole copy of the solderless prototyping boards we're all familiar with. The only differences with the particular brand of board we used are that the rails are one hole closer to the rows, and the whole board is a couple of rows shorter. Besides that, layouts on a solderless breadboard can be copied straight to these solder boards, and the only change needed is that power rail wire links need to be one hole shorter.

We started by adding the resistors and wire links as the low-profile components, followed by the IC socket. Then
the ceramic debounce capacitor for the switch went in, followed by the PCB pins and finally, the capacitor on the supply rails.

Next, the MOSFETs were attached to the heatsink with heatsink tape. The tab and metal back on the IRLZ44N is connected to the drain, and so could not be allowed to contact the heatsink. A better method would be to bolt the MOSFETs down with M3 bolts, threaded into the heatsink, with silicone rubber washers and insulating bushes. However, we cannot find our M3 tap set anywhere. Heatsink tape is adequate given the expectations of the circuit.

The heatsink was mounted to a piece of wood and a terminal block added beside it. These were both fixed down with screws. Plastic P-clamps provide cable tie points One terminal takes the incoming 12V from the power supply on one side, and the two distribution wires to the fans on the other. There is one terminal each for the returning wire from the motor, and the other side of each of those terminals connects to the relevant drain of a MOSFET. The fourth terminal is for the sources of the MOSFETs to connect to the ground of the power supply. All wiring to the MOSFETs was soldered and covered with heatshrink. Also added at this point were single-core wires for the gates of the MOSFETs, long enough to reach back to the circuit board. These wires had PCB pin sockets added to the ends, which were then covered with heatshrink. Note that in the photo, the power supply is not connected yet.

The DHT11 sensors were connected to Cat5e cable, which has a big enough core size when the pairs are used together, to cover most distances we could envisage without problematic levels of voltage drop. Two pairs carry power, ››

one carries the signal, and one remains unused. The cable was cut to length so that one sensor could hang in the middle of the roofspace, while the other could be extended out to the edge of the roof and under the eaves. The lengths are for our installation, so yours will vary. PCB pin sockets were added to the ends so that attachment could take place after the cables were run, without using a soldering iron in the cramped roofspace. The same applied for the manual override switch, but this is attached to light-duty hookup wire. It will run down a wall to an out-of-the-way place in the laundry.

Holes were cut in the sides of a project enclosure, and pieces of fly screen were glued over the holes. Hot melt glue is unsuitable because of the temperatures that will sometimes occur where this item is located. It will not melt, but it will soften enough to lose strength. Instead, cyanoacrylate glue, epoxy, PVA, or any other adhesive that will not fail in the heat, should be used. However, hot melt glue is good for tacking in place while another glue sets. A hole was drilled in the side of the case, then a support glued in to space the sensor away from the back of the enclosure. Ours will be mounted under an eave but we built it as though it may end up outdoors in the sun. This support can be any material you have around.

The cable was passed through the hole and cable-tied as strain relief. The sensor was glued down to the support, then more metal fly screen was glued over the top where the lid would normally go. This completed the outside sensor.

The inside sensor was mounted to the lid of the enclosure that was used for the outside sensor. Over this was glued a box made from metal fly screen, with tabs cut and folded like the nets many of us would remember from making 3D shapes from 2D drawings at school. This sensor only needs to have insects and larger particles kept off it, but the solid lid will stop vertical falling water like drips of condensation or the like if used in a growing house.

The PC power supply was prepared by cutting away all but the green, black, yellow, and one red wire. The green and one black wire were stripped and twisted together, before being covered by heatshrink. This is the 'on' switch for the power supply and ensures the circuit powers up when the mains lead is plugged in. One black wire and the red wire had their ends stripped and PCB pin sockets fitted. With heatshrink over these, they are ready to install on the circuit board. Finally, as many of the remaining black wires as would fit in the terminal block for the ground connection were stripped and twisted together. All others are cut away. The same was done for the yellow wires, into the motor power terminal.Finally, holes were drilled into a small bulkhead-mounted enclosure for the circuit board to fit in: One each for each sensor wire, one for power, and one for the MOSFET gate wires and switch wires. The relevant wires were passed through each hole, and the sockets connected to the correct PCB pins. Then, cable ties were added for strain relief, before the lid was attached. For photographic reasons, we mounted ours straight to the timber. It will be mounted in the enclosure before final installation.

Now all that remained was to mount the heatsink and enclosures inside the roof, the sensors in their locations, and the fans to the vents. However, there were no vents. The installation of them in the particular roof that this project was designed for, had not yet happened at the time of writing. The radiator fans have their custom-made mountings attached to the vent frame, but the vents are still on the floor in the garage awaiting installation by a proper roofing tradesperson. Getting the flashing even slightly wrong on these will let water in, and if this is a tiny amount that is not noticed from inside the house, rotting can occur over many years until the roof structure is damaged. We do not recommend attempting this work yourself.

Instead, we decided to do some static testing. The cable on even the inside sensor is long enough for the circuit and MOSFET heatsink to be mounted to a piece of timber for testing, and still reach either the air conditioner or a container with warm water in the bottom of it to ensure high humidity.

The Code

The code had to measure the inputs from the DHT11 sensors, and decide whether the fans needed to be on, and if so, how much so. We arbitrarily decided on thresholds, with the upper one being the upper limit of what the DHT11 can read. We decided to work on differential rather than absolute values. So, if the inside air is 5% to 10% more humid than outside, the fans are activated with a PWM of 20%. If the difference is between 10% and 20% RH, PWM increases to 50%. Anything greater than a 20% RH difference causes the PWM signal to be 100%.

Manual override is also included, and the button is pullup connected. It gives a 30% PWM for one press, 60% for the second press, and 100% PWM for the third, if pressed within five seconds. After that, the next press turns it off.

The code itself is fairly self-explanatory, and revolves mainly around comparing two humidity sensors.

#define DHTTYPE DHT11
#define PWM_PIN_1 0
#define PWM_PIN_2 1
#define MODE_BUTTON 2
DHT inside(3, DHT11);
DHT outside(4, DHT11);
void setup() {
  // put your setup code here, to run once:
  pinMode(PWM_PIN_1, OUTPUT);
  pinMode(PWM_PIN_2, OUTPUT);

The setup code is all configurable, so it's easy enough to change any parameters if you have a different system. The DHT11 type and configuration may need to be changed, which may be a DHT11, DHT22 or DHT21. All of the pins can also be changed here.

The 'inside' and 'outside' sensors are DHT objects that can be called from the code in order to receive data from them.

//Mode 0 - automatic mode
//Mode 1 - 30% PWM
//Mode 2 - 60% PWM
//Mode 3 - 100% PWM
//Mode 4 - completely off
uint8_t mode = 0;
void writeFanOutput(uint8_t output) {
  analogWrite(PWM_PIN_1, output);
  analogWrite(PWM_PIN_2, output);

The mode variable above will let us track which fan mode we're in, which we can change with a button as we'll see later on in the code.

void loop() {
  // put your main code here, to run repeatedly:
  if(mode == 0) {
    float insHum = inside.readHumidity();
    float outHum = outside.readHumidity();
    //If both humidity readings are valid.
    if(!isnan(insHum) && !isnan(outHum)) {
      float diff = insHum - outHum;
      if(diff >= 20) {
        //100% duty cycle
      } else if (diff >= 10) {
        //50% duty cycle
      } else if (diff >= 0) {
        //20% duty cycle
      } else {
        //0% duty cycle
  } else if (mode == 1) {
    //30% duty cycle
  } else if (mode == 2) {
    //60% duty cycle
  } else if (mode == 3) {
    //100% duty cycle
  } else {
    //Completely off.

Finally, here is how we're changing the fan speed based on the difference between the readings. This only applies in mode 0, where the fan speed is automatic and will turn on when needed.

The other modes will output a constant fan speed. You may notice that the numbers used are somewhat arbitrary, such as 76 and 153, however this is simply because the duty cycle of a PWM output goes between 0 (0%) and 255 (100%), so the values are scaled accordingly. Of course, all of this code can be changed accordingly.

Where to from here?

Later, we would like to add temperature capability to the circuit. That could be achieved as-is with the DHT11, but we feel that thinking about exactly how it should work is beneficial. This will take some time.

For example, how should temperature relate to humidity? Does humidity take priority so that damp air on a hot humid day is not pulled into a dryer roofspace? Is temperature the more important factor above a certain threshold, and where should that threshold be?

Does the temperature function use a more than/ less than function like humidity, or should it be based on absolute inside values and not comparative These and other factors need careful thought, and we find that the longer we think about these things, the better the end result.

We would also like to factor in those 0% - 100% sensors we found earlier. However, we need a better way to utilise them, and add temperature control. Perhaps a different MCU is needed, so that temperature can be done with onboard ADC, the capacitive sensors can function with an oscillator to produce a frequency counted at a digital I/O pin, and there can still be independent pins for the MOSFETs.

Regardless of that, the project does what we asked of it, despite the room for improvement. We're pretty happy with where things are at and won't be fiddling too much with the design. However, that does not mean you cannot!