Light or dark activated switch using Arduino

 Author:   Posted on:   Updated on:  2017-11-18T21:32:32Z
Light or dark activated relays are useful devices when you need to automatically turn on lights or activate some other electric device when lighting decreases or increases above a threshold. Usually, to build such a device, you would use a LDR (photoresistor), some resistors to make voltage dividers, an opamp as comparator, a transistor and a relay that will be driven by the transistor.

Using a microcontroller we can design a smarter device. One that does not activate the relay at every instant change of light (flash). The same device can turn from a dark activated relay into a light activated relay at a push of a button.

The following project uses an ATmega328 board with some modules which are part of a popular Arduino sensor kit. Don't worry if you don't have that modules. They are simple circuits for which I provided schematic.
Light or dark activated switch using Arduino

The working principle is rather simple. The output voltage from a divider formed by a photoresistor and a fixed resistor is read by an analog input pin of the microcontroller (MCU). Depending on this value and the user configurable threshold and mode of operation, the relay is activated or not by a digital output of the MCU. The rotary encoder allows changing the switching threshold (rotation) and cycling through the four modes of operation: always off, always on, light activated relay and dark activated relay. The threshold and mode of operation are stored inside MCU EEPROM and these variables are restored when powering up the device.

Arduino light/dark switch with rotary encoder
Arduino light/dark switch with rotary encoder
I designed this using a Nano board, but if you want a standalone device, there is no need for USB port, so you should use the smaller Pro Mini board. The rotary encoder and its switch are connected to D2 respectively D3 pins and use interrupts to change program variables. The analog value from photoresistor is sampled on pin A3 twice in 0.5 seconds. If the value is rather constant, the relay is activated or not on pin D4.

If you will build this to turn on the light in a room, make sure the light you turn on does not get to the photoresistor. Otherwise the switch will run an endless loop of turning on and off the light. The photoresistor should look to outdoor lighting, while the relay will turn on indoor lights.

This is the initial sketch. I recommend using the sketch from GitHub because this is more often updated.
/*  
 *  Arduino powered light/dark activated switch
 *  Copyright (C) 2017 One Transistor <https://www.onetransistor.eu>
 *  Licensed under GNU General Public License v3
 */  

#include <EEPROM.h>

// Pins for photoresistor, relay and encoder
const int sensorPin = A3; // A3
const int relayPin = 4; // D4
const int encoderA = 2; // D2
const int encoderB = 5; // D5
const int modeSwitchPin = 3; // D3

// Change that will be considered significant in read value
const int valueThreshold = 20;
const int rotaryEncoderStep = 10;

int sensorValue = 0;
volatile unsigned int sensorThreshold = 512;
volatile byte modeSwitch = 0; // 0 = always off, 1 = always on, 2 and 3 = dark or light activated switch

void setup() {
  pinMode(sensorPin, INPUT_PULLUP);
  pinMode(relayPin, OUTPUT);
  digitalWrite(relayPin, LOW);
  pinMode(encoderA, INPUT);
  pinMode(encoderB, INPUT);
  pinMode(modeSwitchPin, INPUT_PULLUP);

  attachInterrupt(0, readEncoder, CHANGE);
  attachInterrupt(1, readMode, LOW);

  modeSwitch = EEPROM.read(1);
  if (modeSwitch > 3) modeSwitch = 2;

  sensorThreshold = (EEPROM.read(2) << 8) + EEPROM.read(3);
  if (sensorThreshold > 1023) sensorThreshold = 512;

  // uncomment these lines for debugging
  //Serial.begin(9600);
  //Serial.println("Light/dark activated switch");
}

void loop() {
  while (modeSwitch < 2) ;

  // sensor is read twice in 0.5 seconds
  // if there is no significant change in sensor value
  // it is decided whether to activate the relay or not
  int sensorValueInstant1;
  do {
    sensorValueInstant1 = analogRead(sensorPin); // read sensor
    delay(500); // wait 0.5 seconds
    int sensorValueInstant2 = analogRead(sensorPin); // read sensor again

    // if there is no significant change in read values
    // it means there is a constant change of light intensity
    if (max(sensorValueInstant1, sensorValueInstant2) - min(sensorValueInstant1, sensorValueInstant2) < valueThreshold)
      sensorValue = sensorValueInstant1; // store sensor value

    delay(500);
  } while (sensorValue != sensorValueInstant1);

  // uncomment these lines for debugging
  //Serial.print("Photoresistor: ");
  //Serial.print(sensorValue / 10.24, 1);
  //Serial.println(" %");

  // if value is over or below threshold
  // depending on mode setting, turn on or off the relay
  if ((sensorValue < sensorThreshold) && (modeSwitch > 1))
    digitalWrite(relayPin, (modeSwitch == 2) ? HIGH : LOW);
  else
    digitalWrite(relayPin, (modeSwitch == 3) ? HIGH : LOW);
}

// https://playground.arduino.cc/Main/RotaryEncoders
void readEncoder() {
  if (digitalRead(encoderA) == digitalRead(encoderB))
  {
    if (sensorThreshold < 1024) sensorThreshold += rotaryEncoderStep;
  }
  else {
    if (sensorThreshold > 0) sensorThreshold -= rotaryEncoderStep;
  }

  EEPROM.update(2, sensorThreshold >> 8);
  EEPROM.update(3, sensorThreshold & 0xFF);

  // uncomment these lines for debugging
  //Serial.print("New threshold: ");
  //Serial.print(sensorThreshold / 10.24, 1);
  //Serial.println(" %");
}

// "debouncing" procedure from
// http://forum.arduino.cc/index.php?topic=45000.0
void readMode() {
  static unsigned long lastPush = 0;
  unsigned long currentPush = millis();

  if (currentPush - lastPush > 200) {
    modeSwitch++;
    if (modeSwitch > 3)
      modeSwitch = 0;
  }
  lastPush = currentPush;

  if (modeSwitch < 2)
    digitalWrite(relayPin, (modeSwitch == 1) ? HIGH : LOW);

  EEPROM.update(1, modeSwitch);

  // uncomment these lines for debugging
  //Serial.print("Sensor mode: ");
  //Serial.println(modeSwitch, DEC);
}

This project should be built in a case. You must pay attention to mains voltages that can be controlled by the relay. The entire circuit is powered at 5V (use a 5V Arduino board).

3 comments :

  1. Hi Cornelius,
    what drawing program was used for creating schematic Light and Dark switch with Arduino ?

    Thanks,
    Ondrej

    ReplyDelete
    Replies
    1. I used TinyCAD with custom libraries. I wrote about TinyCAD here and you can download my custom libraries from Google Drive.

      Delete
    2. Thanks for it, Cornelius. It is very helpful.
      I expected TinyCAD with your own symbols :)
      I have created my symbol for Arduino Uno yesterday, because I needed to finish some schematic - it was my first schematic in TinyCAD. It looks very good program.

      Ondrej

      Delete

Please read the comments policy before publishing your comment.