A smart light or dark activated relay powered by Arduino. Modes of operation and switching threshold configurable by rotary encoder.
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.
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 |
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).
Hi Cornelius,
ReplyDeletewhat drawing program was used for creating schematic Light and Dark switch with Arduino ?
Thanks,
Ondrej
I used TinyCAD with custom libraries. I wrote about TinyCAD here and you can download my custom libraries from Google Drive.
DeleteThanks for it, Cornelius. It is very helpful.
DeleteI 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
You probably don't need encoder except for training
ReplyDelete