ATtiny programmable switching regulator (buck converter) shower extractor fan control.

ATtiny45/85 or ATmega internally clocked at 8MHz to do temperature sensing fan control.
This demonstration uses an ATtiny85 programmed using the Arduino board and IDE
to provide a PWM signal.

Configure your Arduino IDE and Arduino board as an in circuit programmer using this guide:

You'll need to change your preferred AT microcontroller to run internally at 8MHz.
You can do this in the Arduino IDE by selecting your board type in the Tools - Board menu.
For example, choosing ATtiny85 (internal 8MHz clock) and then from
the tools menu again choose Burn Bootloader.

Code and pictures:

   Bathroom/Shower/WC extractor fan control.
   Developed with the Arduino IDE.
   Uses an AVR like the ATtiny45/85 or ATMEGA.
   Senses hot water in the feed pipe and operates fans at 100% for
   a time proportional to however long you produce steam for.
   Fans run at a quiet slow speed during normal operation
   to ensure any damp evaporating moisture does not vent into
   the rest of the house.
   Manual override too. For any bathroom stinky moments.
   One Button provides all mode control:
   First press : Switches fans to full.
   Second press: Switches fans to low.
   Third press : Switches fans off.
   Pressing again repeats the process.
   Press and hold for 4 seconds for low speed set mode.
   While the fans are ramping up and down press the button to
   set the desired speed to be used when on low.
   Not pressing any button after a while keeps the speed at
   the previous value.
   The speed setting is stored in EEPROM.
   31 January 2012
   by Nick Norton
   V1.0          ------
              --|o     |-- +5v
   Thermistor --|45/85 |-- Active low pushbutton
           0v --|      |-- FET drive
The ATtiny is programmed to use its internal 8MHz clock.
To generate 31kHz PWM. Timer/Counter register TCCR0B is altered.
ANY timming such as delay() will also run very fast.

#include <EEPROM.h>                // The EEPROM is used to store the speed of the fan

int temp = 0;                      // temp contains the value we read from the 10 bit ADC.
int fanset = 0;                    // 0 = Off 1 = Low Speed 2 = High Speed.
int hottimer = 0;                  // Counter for how long its been hot for.
int pushbutton = 0;                // Pushbutton. Active low input! It is normally high.
int hold_delay = 0;                // Used to store how long the Pushbutton is low for.
int pulsewidth = 0;                // Initial speed of the fans when on low.
const int thermistor = 2;          // number of the ADC the Thermistor is connected to.
const int buttonPin = 1;           // number of pin a pushbutton switch is connected to.
const int fanPin =  0;             // number of the PWM output pin. Set to 0 on ATtiny.

void setup() {
   TCCR0B = TCCR0B & 0b11111000 | 0b001 ; // Set pin 5 PWM frequency to 31250 Hz
   pinMode(fanPin, OUTPUT);        // initialize the PWM pin as an output.
   pulsewidth =;    // read the stored low fan speed from EEPROM
   analogWrite(fanPin, pulsewidth);// write the stored fan speed to the PWM.
   pinMode(buttonPin, INPUT);      // initialize the buttonPin pin as an INPUT.
   digitalWrite(buttonPin, HIGH);  // connect internal 20k pullup resistor, buttonPin becomes HIGH!
   delay(65535);                   // Now we are powered up, wait briefly before reading inputs.

void loop() {
     // Read the thermistor and if it's hot start counting up.
     temp = analogRead(thermistor);// Read the thermistor
     if(temp < 500) {              // ADC value < 500 is present when the thermistor is hot.
          hottimer = hottimer + 2; //start counting up while the thermistor is hot.
     // If it's been hot for say 50 samples and the fan is off or low, set fan high.
     if(hottimer > 50 && fanset <= 1) {

pushbutton  = digitalRead(buttonPin);
   while (pushbutton == LOW) {
         pushbutton = digitalRead(buttonPin);
         if(hold_delay == 500) { // long press
           hold_delay = 0;
  // If the fan is on high and the button is quickly pressed set the fan to low.
  if(hold_delay > 0 && hold_delay < 50 && fanset == 2) {
             hold_delay = 0;
             delay (20000);   // cheap debounce.

  // If the fan is on low and the button is quickly pressed set the fan to off. 
  if(hold_delay > 0 && hold_delay < 50 && fanset == 1) {
             hold_delay = 0;
             delay (20000);   // cheap debounce.

  // If the fan is off and button is quickly pressed set fan to high. Something to extract Sir/Madam?
  if(hold_delay > 0 && hold_delay < 50 && fanset == 0) {
             hold_delay = 0;
             hottimer = 390*15;// Runtime when manually switched high. 390 is about 1 minute so *15 gives 15 minutes.
             setfanhi();       // ^-Toilet pong may vary, adjust to your own values O_o
             delay (20000);    // cheap debounce.

  // I'm not too worried about checking if the thermistor is cool before counting down.
  // We count up faster than we count back down anyway. Meh, counting is cheap.
  if(hottimer > 0) {
     hottimer = hottimer - 1;
  // If the hottimer has managed to count down due to a cool thermistor then setfanlow           
  if(hottimer == LOW && fanset == 2) {
  delay (10000); // We don't need to loop and count thousands of times a second!
                 // Just don't shower for longer than integer 32,767

} // end of main loop

void setfanhi() {
     analogWrite(fanPin,255); //PWM 100% full 5V
     fanset = 2;

void setfanlow() {
     analogWrite(fanPin,pulsewidth);  //Set PWM for low fan speed.
     fanset = 1;
     hottimer = 0;

void setfanoff() {
     analogWrite(fanPin,0);   //PWM 0% off 0V
     fanset = 0;
     hottimer = 0;
// set_pwm() ramps the fans up and down 5 times while looking for a buttonpress.
// When the fans are running at a nice low speed, press the button and that
// value is stored in EEPROM.
void set_pwm() {
  analogWrite(fanPin,0); //Turn the fans off first.
  delay(131071);         //Delay for spindown, it's about 1.5 seconds at our clock speed.
  for (int loops=0; loops <= 5; loops++) { //ramp up and down 5 times
      // The idea for using an ATtiny to draw PWM circles is awesome.
      // and I took the idea from
      for(int i = 0; i<360; i++){
      //convert 0-360 angle to radian (needed for sin function)
      float rad = DEG_TO_RAD * i;
      //calculate sin of angle as number between 0 and 255
      int sinOut = constrain((sin(rad) * 128) + 128, 0, 255);
      analogWrite(fanPin, sinOut);
      // end of brilliant idea.
      pushbutton  = digitalRead(buttonPin);
      if(pushbutton == LOW) {
        pulsewidth = sinOut;         // our new value for pulsewidth
        EEPROM.write(0, pulsewidth); // store it in the first EEPROM location
        delay(20000);                // debounce
        loops = 6;                   // no point in doing any more loops.
        break;                       // gotta get out of here.
  }//end of loops
  analogWrite(fanPin, pulsewidth); // Sets the PWM back to what it was if you don't choose a new value.
}//end of set_pwm()

LM7805 5 volt regulator
ATtiny85 Atmel 8-bit AVR
2SC1815 NPN Transistor - any general purpose driver NPN should do
IRF4905 P-Channel power MOSFET
BYV27-100 fast diode 2 amps 100V
LED - optional, used for diagnostic purposes
50µH ferrite core inductor
1000µF 25V Electrolytic capacitor
22µF 10V Electrolytic capacitor
470µF 25V Electrolytic capacitor
1K Ohm x 2 resistor
180 Ohm resistor
470 Ohm resistor
10 Ohm resistor
1 K Ohm negative temperature coefficient (NTC) thermistor - any thermistor should do even a PTC one.
Just adjust this line in the code to match results for your thermistor:

if(temp < 500) {              // ADC value < 500 is present when the thermistor is hot.

Use a fuse in case things go wrong. I used a 4 amp fast blow.