Sleep Remaining Indicator: A Laser Alarm Clock

Sleep remaining indicator

The chunk of title after the colon intends to serve as an explanation of what a sleep remaining indicator is. However, this project is neither an alarm nor a clock. It is a visual indicator of approximately how much time I have remaining to sleep in the night.

This may not be a problem you need solved. If, however, like me you wear glasses or contacts, the world when you are in bed turns into a blurry mess. Normally I reach over and unlock my phone or lean over and squint at my Chumby One, but those actions make it harder to get back to sleep. What I wanted was a way to instantly know how much longer I could sleep before my alarm would go off.

My solution involves a line laser, a servo, and an Arduino. I set a potentiometer with a number dial to approximately the right length of time in hours and hit the reset button. The servo with the line laser attached will shine the laser line onto the ceiling. The servo will then slowly rotate, moving the laser line underneath a cover made of Lego pieces, making the length of line showing on the ceiling shrink over the hours. It’s a little like an hourglass, but with lasers.

Laser line

Here’s the Arduino sketch. Use it under whatever license you want.

/* Sleep Remaining Indicator v1.0
 * by Nirav Patel <http://eclecti.cc>
 */
 
#include <Servo.h>
#include <math.h>
 
//#define photoPin 1
//#define laserPin 9
#define potPin 0
#define servoPin 10
#define M_PI_4 (M_PI/4.0)
#define MINSERVO 1190 // The laser line is no longer visible
#define MAXSERVO 1810 // The laser line is at its longest
 
unsigned long startTime;
unsigned long totalTime;
unsigned int lastVal;
Servo laserServo;
 
void setup()
{
  Serial.begin(9600);
//  pinMode(photoPin, INPUT);
  pinMode(potPin, INPUT);
 
  // this magic converts the pot value to 0 to 9 hours in milliseconds.
  totalTime = (unsigned long)31641*(unsigned long)(1024-analogRead(potPin));
  Serial.print('Time in hours: ');
  Serial.println((double)totalTime/(double)3600000.0);
 
  laserServo.attach(servoPin);
  startTime = millis();
  lastVal = 0;
}
 
void loop()
{
  // The laser brightness should depend on the ambient light in the room.
  // Unfortunately, my laser dislikes PWM, so I just have it hooked to 3.3v
//  unsigned int light = analogRead(photoPin);
//  analogWrite(laserPin,light>>2);
 
  // calculate the time we've been running (well, sleeping)
  unsigned long time = millis()-startTime;
  // Note that one could use this as an alarm clock by setting off a buzzer or
  // even having the servo rotate loudly
  if (time > totalTime) {
    laserServo.writeMicroseconds(MINSERVO);
    while(1) {}
  }
 
  // This trig makes the line length shrink uniformly over time.
  time = totalTime-time;
  double angle = atan2((double)time,(double)totalTime);
  unsigned int servoVal =  (unsigned int)((angle/M_PI_4)*(double)(MAXSERVO-MINSERVO))+MINSERVO;
 
  servoVal = (servoVal > MAXSERVO? MAXSERVO : (servoVal < MINSERVO ? MINSERVO : servoVal));
  // The servo is imperfect, so don't move unless the value actually changed
  if (servoVal != lastVal) {
    Serial.println(servoVal);
    laserServo.writeMicroseconds(servoVal);
    lastVal = servoVal;
  }
 
  // tick like a clock
  delay(1000);
}
10 Comments on Sleep Remaining Indicator: A Laser Alarm Clock