Skip to content

Instantly share code, notes, and snippets.

@MarcelloTheArcane
Last active August 24, 2020 11:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MarcelloTheArcane/7be865507c2018faa79d0f57276a63ac to your computer and use it in GitHub Desktop.
Save MarcelloTheArcane/7be865507c2018faa79d0f57276a63ac to your computer and use it in GitHub Desktop.
Safelight

See the project on hackaday.

For Arduino Uno compatible board.

Wiring

  • Red LED strip via NPN transistor on pin 1
  • Four timer buttons, plus timer start buttons, and enlarger button via voltage divider on pin A0
  • Rotary encoder on pins A1 and A2
  • Relay module on pin A3
  • Safelight switch on pin A4
  • Piezo buzzer on pin A5
  • 4 × 7 segment display on pins 2-13
#include <SevSeg.h>
#include <EEPROM.h>
const byte SAFELIGHT_PIN = 1;
const byte BUTTON_ARRAY_PIN = A0;
const byte ENCODER_A_PIN = A1;
const byte ENCODER_B_PIN = A2;
const byte RELAY_PIN = A3;
const byte SAFELIGHT_BUTTON_PIN = A4;
const byte BUZZER_PIN = A5;
// Changable if EEPROM ever wears out at these addresses
const int EEPROM_ADDRESSES[] = { 0, 1, 2, 3 };
const byte NUM_DIGITS = 4;
const byte DIGIT_PINS[] = { 5, 4, 3, 2 };
const byte SEGMENT_PINS[] = { 11, 13, 9, 7, 6, 12, 10, 8 };
SevSeg screen;
int buttonArrayValue;
unsigned long lastButtonArrayTime;
unsigned long lastTimerUpdate;
unsigned long timerUpdate;
boolean lastEncoderAValue;
boolean encoderAValue;
boolean encoderBValue;
byte activeTimer = 0;
int timers[] = {
EEPROM.read(EEPROM_ADDRESSES[0]),
EEPROM.read(EEPROM_ADDRESSES[1]),
EEPROM.read(EEPROM_ADDRESSES[2]),
EEPROM.read(EEPROM_ADDRESSES[3])
};
boolean timerRunning = false;
boolean safelightOn = false;
void setup() {
pinMode(BUZZER_PIN, OUTPUT);
pinMode(RELAY_PIN, OUTPUT);
pinMode(SAFELIGHT_PIN, OUTPUT);
pinMode(ENCODER_A_PIN, INPUT);
pinMode(ENCODER_B_PIN, INPUT);
pinMode(SAFELIGHT_BUTTON_PIN, INPUT);
// Type, digits, segments, digit pins, segment pins, resistors on pins, update with delay, leading zeroes.
screen.begin(COMMON_CATHODE, NUM_DIGITS, DIGIT_PINS, SEGMENT_PINS, true, false, true);
screen.setBrightness(10);
lastEncoderAValue = digitalRead(ENCODER_A_PIN);
}
void loop() {
// Read rotary encoder
encoderAValue = digitalRead(ENCODER_A_PIN);
encoderBValue = digitalRead(ENCODER_B_PIN);
if (encoderAValue != lastEncoderAValue && encoderAValue == true && timerRunning == false) {
if (encoderBValue != encoderAValue) {
timers[activeTimer]++;
} else {
timers[activeTimer]--;
}
// Minimum timer is 0, maximum timer is 99 minutes, 99 seconds = 6039 seconds
timers[activeTimer] = min(max(0, timers[activeTimer]), 6039);
}
lastEncoderAValue = encoderAValue;
// Button array
buttonArrayValue = analogRead(BUTTON_ARRAY_PIN);
if (millis() - lastButtonArrayTime > 100 && timerRunning == false) {
if (buttonPressed(buttonArrayValue, 516)) {
startTimer();
} else if (buttonPressed(buttonArrayValue, 344)) {
startTimer();
digitalWrite(RELAY_PIN, HIGH);
} else if (buttonPressed(buttonArrayValue, 257)) {
activeTimer = 0;
} else if (buttonPressed(buttonArrayValue, 205)) {
activeTimer = 1;
} else if (buttonPressed(buttonArrayValue, 171)) {
activeTimer = 2;
} else if (buttonPressed(buttonArrayValue, 146)) {
activeTimer = 3;
}
lastButtonArrayTime = millis();
}
timerUpdate = millis() - lastTimerUpdate;
// Clear timer
if (timerUpdate > 1000 && timerRunning == true && timers[activeTimer] <= 0) {
timers[activeTimer] = EEPROM.read(EEPROM_ADDRESSES[activeTimer]);
tone(BUZZER_PIN, 880, 1000);
timerRunning = false;
digitalWrite(RELAY_PIN, LOW);
}
// Update timer every second
if (timerUpdate > 1000 && timerRunning == true) {
timers[activeTimer]--;
// Beep every second, with a higher beep every 30 seconds.
if (timers[activeTimer] % 30 == 0) {
tone(BUZZER_PIN, 880, 250);
} else {
tone(BUZZER_PIN, 440, 50);
}
lastTimerUpdate += timerUpdate; // Use the timerUpdate so average time is correct
}
// Update displays (safelight and screen).
safelightOn = digitalRead(SAFELIGHT_BUTTON_PIN);
if (safelightOn == true) {
digitalWrite(SAFELIGHT_PIN, HIGH);
screen.setNumber(secondsToMinutes(timers[activeTimer]), 3 - activeTimer);
} else {
digitalWrite(SAFELIGHT_PIN, LOW);
screen.blank();
}
screen.refreshDisplay();
}
// Calculates if a number is within a margin of +/- 15. If so, it returns true.
// This is used for the analogue buttons to see if they were pressed.
boolean buttonPressed (int buttonArrayValue, int target) {
if (abs(buttonArrayValue - target) < 15) {
return true;
} else {
return false;
}
}
// Returns a seconds value in MMSS format.
int secondsToMinutes (int seconds) {
if (seconds < 60) {
return seconds;
} else {
return (floor(seconds / 60) * 100) + (seconds % 60);
}
}
// Stores the current time if it is new, and starts the timer.
void startTimer () {
EEPROM.update(EEPROM_ADDRESSES[activeTimer], timers[activeTimer]);
timerRunning = true;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment