Back in late 2020 I built my daughter a night light. I could have bought one, but where’s the fun in that? I had an Arduino, a pile of jumper wires and a plan scribbled in a notebook.

The result is an owl that sits on a plywood box with three big chunky buttons and two knobs. She can pick the colour of the light by turning the knob, set it to a slow rainbow, or press the moon button and the owl fades itself to sleep over 20 minutes. Here’s what it does and how it works, circuit diagram and code included.

White owl night light sitting on a plywood box with blue, yellow and red buttons and green and white knobs
The finished owl. Every control has a sticker so you don’t need to be able to read to use it.

What does it do?

Each control has a picture sticker above it, so it’s pretty easy to work out even if you’re small and it’s dark.

  • Yellow button (light bulb): on and off. When the owl is off, the yellow button glows so she can find it in the dark.
  • Green knob (colour wheel): picks the colour. Turn it and the owl goes from red to green to blue and back to red again.
  • White knob (sun): brightness, from barely there to full glow.
  • Blue button (rainbow): rainbow mode. The owl slowly cycles through every colour on its own. In this mode the green knob changes the speed, from roughly 5 seconds per lap to nearly 2 minutes.
  • Red button (sleepy moon): sleep mode. The owl jumps to full brightness in whatever colour is selected, then fades out over 20 minutes and switches itself off. The yellow button lights up again, ready for next time.

Here it is in action. I press the yellow button, then twiddle the colour knob and the brightness knob.

Six frames of the owl night light glowing white, blue, pink, aqua, orange and peach
A few frames from the video. Same owl, different moods.

What’s inside the box?

The brains is a DFRobot Bluno Nano. It’s an Arduino Nano compatible board with Bluetooth built in. I didn’t use the Bluetooth at all. Maybe one day the owl gets an app. Maybe not.

The rest of the parts list is pretty short:

  • DFRobot Bluno Nano (any Arduino Nano or Uno would do the job)
  • 3 push buttons: yellow, blue and red, with an LED inside the yellow one
  • 2 potentiometers, with recycled yoghurt lids as the knobs (upcycling at its best)
  • An RGB LED inside the owl
  • A 4 channel MOSFET switch module from AliExpress (IRF540N MOSFETs with optocoupler isolation) to drive the red, green and blue channels, with one channel spare
  • 10k resistors for the buttons and between the Arduino and the MOSFET module, plus a 220Ω resistor for the yellow button’s LED
  • A 5V supply into a terminal block
  • A plywood box, a handful of stickers and heaps of jumper wires
Night light box mid build with the RGB LED mounted on the lid, wires inside and the yellow, blue and red buttons fitted to the front panel
Mid build on the garage floor. The RGB LED is mounted on the lid where the owl sits, and the knobs are still waiting to go in.
DFRobot Bluno Nano board on a prototype board next to the open plywood night light box
The Bluno Nano hanging out the back of the box during testing.
Colourful jumper wires inside the plywood night light box connecting the buttons to the Arduino
Inside the box. Neat it is not, but it works.

The circuit diagram

Here’s how everything is wired up. The pin numbers match the code.

Circuit diagram of the Arduino owl night light showing buttons on D2 to D4, knobs on A1 and A2 and the RGB LED on D9 to D11 through MOSFETs
Circuit diagram of the owl night light.

Here’s how the pieces hook up:

  • Buttons go to digital pins D2 (yellow), D3 (blue) and D4 (red). One side of each button goes to 5V. The pin also has a 10k resistor down to ground, which keeps it reading LOW until the button is pressed. Pressing the button connects it to 5V and it reads HIGH.
  • Knobs are potentiometers wired across 5V and ground, with the middle leg going to an analog pin. The brightness knob is on A1 and the colour knob is on A2. The Arduino reads each one as a number from 0 to 1023.
  • The yellow button’s LED is on D5 through a 220Ω resistor.
  • The owl’s RGB LED is controlled from D9 (red), D10 (blue) and D11 (green). Each pin goes through a 10k resistor to one input on the 4 channel MOSFET module. The LED’s common positive goes to 5V and each colour goes to one of the module’s outputs. When the Arduino turns a pin on, that MOSFET connects the colour to ground and it lights up. The Arduino pins only have to flick switches; the MOSFETs do the heavy lifting.
  • Dimming comes from PWM. D9, D10 and D11 are PWM pins, which means the Arduino can turn them on and off really fast. The longer each pin spends on, the brighter that colour looks.

How does the code work?

The code is one Arduino sketch. It’s saved as nightlight7, so it’s fair to say the first few versions didn’t quite get there.

The owl is always in one of four modes: off, normal, rainbow or sleep. Every time through the main loop it reads the two knobs and three buttons, works out whether a button press should change the mode, then does whatever that mode does.

Turning a knob into a colour

The colour knob gives a number from 0 to 1023. The code splits that into thirds:

  • Bottom third: red fades out while green fades in
  • Middle third: green fades out while blue fades in
  • Top third: blue fades out while red fades in

So turning the knob all the way walks you around the colour wheel and back to where you started. Brightness is then easy; each colour value gets multiplied by the brightness knob’s position.

Rainbow mode

Rainbow mode uses the same colour wheel code, but instead of reading the colour from the knob it steps a counter from 0 to 1023 and starts again. The colour knob sets how long it waits between steps, anywhere from about 5 to 105 milliseconds. Over 1,023 steps that works out to roughly 5 seconds per lap at the fast end and close to 2 minutes at the slow end.

Sleep mode

Sleep mode starts at full brightness and drops one step every 4.7 seconds. There are 255 steps, and 255 × 4.7 seconds is about 20 minutes. When it gets to the bottom it switches the owl off and turns the yellow button light back on.

My notebook says 30 minutes. The code still has the 30 minute value in it, commented out. Somewhere along the way 20 minutes won.

Making it kid proof

After any button press the code ignores the buttons for half a second. That stops one enthusiastic press being read as five. Pressing yellow while the owl is in rainbow or sleep mode takes it back to normal mode rather than off, so a stray press doesn’t plunge the room into darkness.

If you like this sort of dad project, I also built a playing time calculator for kids’ sport.

The full code

Here’s the whole sketch if you want to build your own. My project file is set up for an Arduino Uno, and it doesn’t use any libraries, so it should run on a Nano or an Uno as is.

Show the Arduino code (nightlight7.ino)
int red = 9; //red LED
int blue = 10;  //blue LED
int green = 11;  // the PWM pin the green LED is attached to
float maxbrightness = 255;
float brightness =0;
int buttoninterval = 500;
float millisinterval = 15;
unsigned long previousbuttonMillis = 0;
unsigned long previousMillis = 0;

const int yellowbutton = 2;     // the number of the pushbutton pin
const int bluebutton = 3;
const int redbutton = 4;
const int yellowbuttonled = 5;

int redVal = 0;   // Variables to store the values to send to the pins
int grnVal = 0;
int bluVal = 0;
int potVal = 0; // Variable to store the input from the potentiometer

int yellowbuttonstate = 0;
int redbuttonstate = 0;
int bluebuttonstate = 0;

int mode = 0;
int disablebutton=0;

void setup() {

  pinMode(red, OUTPUT);
  pinMode(blue, OUTPUT);
  pinMode(green, OUTPUT);
  pinMode(yellowbuttonled, OUTPUT);
  randomSeed(analogRead(0));

  //Serial.begin(9600);
  analogWrite(yellowbuttonled, 255); // turn on yellow button LED

}

void get_colour(int potVal) //give it a number 1-1023 and it will return 3 colours - RGB
{
  if (potVal < 341)  // Lowest third of the potentiometer's range (0-340)
  {
    potVal = (potVal * 3) / 4; // Normalize to 0-255

    redVal = 256 - potVal;  // Red from full to off
    grnVal = potVal;        // Green from off to full
    bluVal = 1;             // Blue off
  }
  else if (potVal < 682) // Middle third of potentiometer's range (341-681)
  {
    potVal = ( (potVal-341) * 3) / 4; // Normalize to 0-255

    redVal = 1;            // Red off
    grnVal = 256 - potVal; // Green from full to off
    bluVal = potVal;       // Blue from off to full
  }
  else  // Upper third of potentiometer"s range (682-1023)
  {
    potVal = ( (potVal-683) * 3) / 4; // Normalize to 0-255

    redVal = potVal;       // Red from off to full
    grnVal = 1;            // Green off
    bluVal = 256 - potVal; // Blue from full to off
  }
}

void loop() {

  unsigned long currentMillis = millis();
  unsigned long currentbuttonMillis = millis();

  //read knobs
  float dimmingknob = analogRead(A1); // red knob
  float colourknob = analogRead(A2); // yellow knob

  //read buttons
  redbuttonstate = digitalRead(redbutton);
  yellowbuttonstate = digitalRead(yellowbutton); // on off button
  bluebuttonstate = digitalRead(bluebutton);

  //Serial.println("Red");
  //Serial.println(redbuttonstate);
  //Serial.println("Yellow");
  //Serial.println(yellowbuttonstate);
  //Serial.println("Blue");
  //Serial.println(bluebuttonstate);

  if (currentbuttonMillis - previousbuttonMillis >= buttoninterval)
    {disablebutton=0;}

  if ((yellowbuttonstate == HIGH)&&(disablebutton==0)&&((mode==0)||(mode==2)||(mode==3)))
    {
      mode=1;
      analogWrite(yellowbuttonled, 0); // turn off yellow button LED
      disablebutton=1; //put timer on to stop reading button
      previousbuttonMillis =millis();
    }

  if ((yellowbuttonstate == HIGH)&&(disablebutton==0)&&(mode==1))
    {
      mode=0;
      analogWrite(yellowbuttonled, 255); // turn on yellow button LED
      analogWrite(red, 0);   // Turn off leds
      analogWrite(green, 0);
      analogWrite(blue, 0);
      disablebutton=1; //put timer on to stop reading button
      previousbuttonMillis =millis();
    }

  if ((bluebuttonstate == HIGH)&&(disablebutton==0))
    {
      analogWrite(yellowbuttonled, 0); // turn off yellow button LED
      disablebutton=1; //put timer on to stop reading button
      previousbuttonMillis =millis();
      mode=2;
      potVal=0;
    }

  if ((redbuttonstate == HIGH)&&(disablebutton==0))
    {
      analogWrite(yellowbuttonled, 0); // turn off yellow button LED
      disablebutton=1; //put timer on to stop reading button
      previousbuttonMillis =millis();
      mode=3;
      brightness=255;

    }

  if (mode==0) // Off
  {

    delay(5);

  }
  else if (mode==1) // normal mode - colour changing and dimming with knobs
  {
    brightness = ((dimmingknob/1024)*(maxbrightness/255));
    //Serial.println("brightness");
    //Serial.println(brightness);
    //analogWrite(red, random(10, 255));
    // analogWrite(blue, random(10, 255));
    //analogWrite(green, random(10, 255));

    //Serial.println("Dimming");
    //Serial.println(dimmingknob);
    //Serial.println("Colour");
    //Serial.println(colourknob);

    potVal=colourknob;

    get_colour(potVal);

    analogWrite(red, (redVal*brightness));   // Write values to LED pins
    analogWrite(green, (grnVal*brightness));
    analogWrite(blue, (bluVal*brightness));

  }

  else if (mode==2) // blue button - first press - rainbow cycle
  {

    brightness = ((dimmingknob/1024)*(maxbrightness/255));
    millisinterval = ((colourknob/1024)*100)+5;
    //Serial.println("Millis");
   // Serial.println(millisinterval);

    get_colour(potVal);
    analogWrite(red, (redVal*brightness));   // Write values to LED pins
    analogWrite(green, (grnVal*brightness));
    analogWrite(blue, (bluVal*brightness));

    if (currentMillis - previousMillis >= millisinterval)
    {
      potVal=potVal+1;

      previousMillis =millis();
    }
    if (potVal>1022){potVal=0;}
    //Serial.println(potVal);
  }

  else if (mode==3) // Sleep mode - Dim to off over the next 20 mins - red button pressed
  {

    potVal=colourknob;
    get_colour(potVal);

    analogWrite(red, (redVal*brightness/255));   // Write values to LED pins
    analogWrite(green, (grnVal*brightness/255));
    analogWrite(blue, (bluVal*brightness/255));

    //millisinterval=200; //test
    //millisinterval=7058; // 30 min dim time
    millisinterval=4705; // 20 min dim time = 20min x 60 x 1000 /255

    if (currentMillis - previousMillis >= millisinterval)
    {
      brightness=brightness-1;
      previousMillis =millis();
    }

    if(brightness<2)
    {
      brightness=0;
      mode=0;
      analogWrite(yellowbuttonled, 255); // turn on yellow button LED
      analogWrite(red, 0);   // Turn off leds
      analogWrite(green, 0);
      analogWrite(blue, 0);
    }

  }

  //delay(500); //not sure if this is needed

} // end of loop

If you build one, I’d love to see it.