Due to my ADHD, I have stints of hyperfocus, where I end up not moving and working for long periods– this is quite unhealthy and I wanted to break this system up a little bit. My desk doesn't have very good lighting so I wanted to get a lamp for it, so the idea of this project was to create a lamp that breaks me out of my flow states. It does this by letting me set a timer (with the timer displayed on an eInk display) for how long I want to work and then the light turns on for that period– quite simple. The idea is that when the light turns off it will break me out of the state.
Fresh out of laser cutting the parts
Setting up the power so the 12V can power the Arduino and the High powered LED
Taping up the body so the glue can set
Setting up the eInk display
Redoing the wiring
Testing to see if it assembles correctly
Connecting the Arduino and wiring to the box before assembly
Assembling the box pt.1
Assembling the box pt.2
Everything went well for the most part, there were a few hiccups that led to unsatisfactory parts like the lamp shade being ruined by not knowing how to use epoxy well. The wiring together with the Arduino Metro barely fit in the lamp, I had to end up cutting a breadboard in half so everything could fit (this worked surprisingly well).
It seemed that most people liked the idea of the lamp and its form/proportions,–very happy about that. Got a couple of odd comments of feedback like adding a way to control the timer intervals with a button/potentiometer– this was quite confusing feedback to get since that is exactly what my project does, I don't know why there was more than one critique related to this since this suggestions is already a large feature in my device (one person at least said they couldn't see the front of the device). The other common critique I got was since I mentioned that it could hold my headphones, it could be designed to be a bit more fitted for them. That is a pretty good idea and not something I considered while working on the project, probably since making it be able to hold my headphones was just an idea in passing to add to the project– not something I gave much thought to.
The eInk display setup was easy to set up for the most part but using it in the first place was a bad idea in the first place, it just doesn't update/ refresh fast enough to be a timer. I ended up having to make it so it refreshes the timer every 20 seconds which works but was quite an unsatisfying result for the work I put in for it. I guess you can't always pick the hardware off "aesthetics".
Another thing I really wish I had given more testing/time to was assembling the lampshade, it just looks terrible. I should have assumed that since it was my first time using epoxy it wouldn't go perfectly on the first try, because in fact it did not go perfectly on the first try. If I had to do this part again, I first would have practiced, wore gloves (put them on halfway through but I had already gotten epoxy on my fingers at that point and researched what types of glue/epoxy are best for clear acrylic. I still might make a new lampshade if I have time.
One last part I want to look back on was the fitting of the hardware in my casing (mainly the Arduino and wiring). While everything ended up fitting albeit very tightly, I should have given more thought to how everything was laid out in the lamp–it's slight luck that everything ended up fitting in the end.
I learned that I CAN assemble things nicely, as long as I don't rush the process(looking at you lampshade). I really haven't built a device from scratch before and it's a great feeling, I am pretty proud of myself even with the plentiful mistakes I made. I think if I had to do this again I would want to integrate some more unique, don't know what they would be but I think I could add some interesting features that would be very useful.
For the next steps: Remake the lampshade, maybe I will 3D print it this time since I like how the light was diffused by Daniel's lamp. Build the base from scratch and not laser cut it, mainly since I don't like the puzzle piece joints to look that much – I could definitely make this lamp more elegant looking. Another step would be to implement the feedback I got about its ability to hold my headphones.
/*
Lamp timer with eInk display
The rotary encoder sets the time when the Rotary encoder is pressed a high-powered warm LED turns on for this time period. The timer is displayed on a eInk display that refreshes every 19-20 seconds.
pin mapping:
Arduino pin | role | description
___________________________________________________________________
10 ePaper Display (Adafruit ThinkInk_213_Tricolor_RW): DC
9 ePaper Display (Adafruit ThinkInk_213_Tricolor_RW): CS
7 ePaper Display (Adafruit ThinkInk_213_Tricolor_RW): BUSY
6 ePaper Display (Adafruit ThinkInk_213_Tricolor_RW): SRAM_CS
8 ePaper Display (Adafruit ThinkInk_213_Tricolor_RW): RESET
11 ePaper Display (Adafruit ThinkInk_213_Tricolor_RW): SPI MOSI
13 ePaper Display (Adafruit ThinkInk_213_Tricolor_RW): SPI SCK
GND ePaper Display (Adafruit ThinkInk_213_Tricolor_RW): GND
3.3V ePaper Display (Adafruit ThinkInk_213_Tricolor_RW): 3.3V
2 Rotary Encoder: CLK
3 Rotary Encoder: DT
4 Rotary Encoder: SW (Button)
5V Rotary Encoder: + (VCC)
GND Rotary Encoder: GND
12 LED: 12 Anode (+)
GND LED: Cathode (-)
*/
#include "Adafruit_ThinkInk.h"
// Display setup
#define EPD_DC 10
#define EPD_CS 9
#define EPD_BUSY 7
#define SRAM_CS 6
#define EPD_RESET 8
#define EPD_SPI &SPI
ThinkInk_213_Tricolor_RW display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, EPD_BUSY, EPD_SPI);
// Rotary Encoder Pins
#define CLK 2
#define DT 3
#define SW 4
// LED Pin
#define LED_PIN 12
int timerDuration = 0;
bool countdownActive = false;
bool ledState = false;
unsigned long startTime = 0;
unsigned long lastUpdateTime = 0;
int lastCLKState;
int lastButtonState = HIGH;
unsigned long lastRotaryTime = 0;
unsigned long lastDebounceTime = 0;
const int debounceDelay = 50;
bool encoderMoved = false;
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
pinMode(SW, INPUT_PULLUP); // Ensure SW is configured properly
pinMode(CLK, INPUT);
pinMode(DT, INPUT);
lastCLKState = digitalRead(CLK);
display.begin(THINKINK_TRICOLOR);
updateDisplay(timerDuration);
Serial.println("Setup Complete");
}
void loop() {
handleRotaryEncoder();
handleButtonPress();
unsigned long currentMillis = millis();
if (countdownActive && currentMillis - lastUpdateTime >= 1000) {
updateCountdown();
lastUpdateTime = currentMillis;
}
if (encoderMoved && millis() - lastRotaryTime > 500) {
updateDisplay(timerDuration);
encoderMoved = false;
}
}
void handleRotaryEncoder() {
int currentCLKState = digitalRead(CLK);
if (currentCLKState != lastCLKState) {
if (digitalRead(DT) != currentCLKState) {
timerDuration += 60;
Serial.println("Encoder Turned Right (+1 min)");
} else {
timerDuration -= 60;
Serial.println("Encoder Turned Left (-1 min)");
}
timerDuration = constrain(timerDuration, 0, 18000);
lastCLKState = currentCLKState;
lastRotaryTime = millis();
encoderMoved = true;
}
}
void handleButtonPress() {
int buttonState = digitalRead(SW);
if (buttonState == LOW && lastButtonState == HIGH && (millis() - lastDebounceTime) > debounceDelay) {
lastDebounceTime = millis();
if (!countdownActive) {
countdownActive = true;
ledState = true;
analogWrite(LED_PIN, 102); // Now at 40% brightness
startTime = millis();
Serial.println("Button Pressed: Timer Started");
} else {
countdownActive = false;
analogWrite(LED_PIN, 0); // Turn LED off
Serial.println("Button Pressed: Timer Stopped");
}
}
lastButtonState = buttonState;
}
void updateCountdown() {
if (countdownActive) {
int elapsedTime = (millis() - startTime) / 1000;
int remainingTime = timerDuration - elapsedTime;
if (remainingTime <= 0) {
analogWrite(LED_PIN, 0);
ledState = false;
countdownActive = false;
remainingTime = 0;
Serial.println("Timer Finished");
}
updateDisplay(remainingTime);
}
}
void updateDisplay(int timeInSeconds) {
int hours = timeInSeconds / 3600;
int minutes = (timeInSeconds % 3600) / 60;
int seconds = timeInSeconds % 60;
Serial.print("Display Update: ");
Serial.printf("%02d:%02d:%02d\n", hours, minutes, seconds);
display.clearBuffer();
display.setTextSize(2);
display.setCursor(10, 30);
display.setTextColor(EPD_BLACK);
display.print((hours < 10) ? "0" : ""); display.print(hours); display.print(":");
display.print((minutes < 10) ? "0" : ""); display.print(minutes); display.print(":");
display.print((seconds < 10) ? "0" : ""); display.print(seconds);
display.display();
}