Sam HofmannGeorge Powell
Published © GPL3+

The Ultimate Alarm Clock

A sleep cycle alarm clock that senses motion, turns on the lights and alarm, and makes coffee!

IntermediateFull instructions provided6 hours1,582
The Ultimate Alarm Clock

Things used in this project

Hardware components

Photon
Particle Photon
The "brains" of the system
×2
High-Power Relay Shield for Particle Photon I²C 1-Channel SPDT 10-Amp
ControlEverything.com High-Power Relay Shield for Particle Photon I²C 1-Channel SPDT 10-Amp
To control the lights and coffee maker
×2
PIR Motion Sensor (generic)
PIR Motion Sensor (generic)
The input/trigger of the system
×1
Buzzer
Buzzer
The alarm
×1
General Purpose Transistor NPN
General Purpose Transistor NPN
Relay subcircuit (optional)
×1
1N4007 – High Voltage, High Current Rated Diode
1N4007 – High Voltage, High Current Rated Diode
Relay Subcircuit (optional)
×1
Resistor 330 ohm
Resistor 330 ohm
Relay subcircuit (optional)
×1
Slide Switch
Slide Switch
To turn off the alarm
×1

Software apps and online services

Mobicle
ControlEverything.com Mobicle
In case you just want a WiFi coffee maker!

Story

Read more

Schematics

Project Schematic

This is the schematic of both of the circuits involved in this project. The dotted line between the two Photons represents HTML requests via WiFi using Particle.publish() and Particle.subscribe() commands. Both circuits are shown with the relay subcircuit (the stuff that connects to D7 on Photon 1). A relay shield is a much easier option, but we already had a relay that we wanted to put to use.
***Correction: "PID" should read "PIR," representing the PIR motion sensor for D0 on Photon1***

Code

Code for Both Photons (user must separate them)

C/C++
This is the code for the both Photons. It was created and uploaded to the Photons through the online IDE (build.particle.io) This is meant for use in conjunction with some sort of wall outlet timer for the alarm Photon. If you do not have a wall outlet timer, just add a delay(runTime(hrs,mins)) call in the setup code. The code has been thoroughly commented for easy understanding.
/*******************************************************************************
 NOTE: THIS IS TWO PROGRAMS IN ONE AND MUST BE SEPARATED INTO TWO FILES!!!
*******************************************************************************/

/*  This code takes input from a PIR sensor and 
    triggers a buzzer and a light to turn on, 
    and then publishes an event to the cloud for another 
    Photon to receive and start brewing coffee
*/

int sensor = D0;
int relay = D7;
int buzzer = D3;
//  creates variables for the digital pins to be used
//  the pins are associated with a PIR sensor, a piezo buzzer, and an SPDT relay to control the lights

void setup() {
    pinMode(sensor,INPUT);
    pinMode(relay,OUTPUT);
    pinMode(buzzer,OUTPUT);
    //  sets the PIR sensor as an input for the Photon, and the other two as outputs
    digitalWrite(sensor,LOW);
    digitalWrite(relay,LOW);
    digitalWrite(buzzer,LOW);
    //  sets each pin to low before the loop runs
    delay(30000);
    //  allows the PIR sensor to calibrate to its thermal environment
}
//  this code will run only once upon startup

void loop() {
    if (digitalRead(sensor) == HIGH)   {
    //  this block of code is only executed if the PIR sensor detects motion
        delay(2000);
        //  allows the Particle.publish() function to work properly
        Particle.publish("brew-coffee","Coffee is brewing!");
        //  publishes an event to the cloud for any connected device to subscribe to
        digitalWrite(relay,HIGH);
        //  turns on the lights
        delay(runTime(0,2));
        //  wakes you up gently before the alarm sounds
        alarmTone(750,750,15);
        //  sounds alarm (see funnction below) for specified time
        digitalWrite(relay,LOW);
        digitalWrite(buzzer,LOW);
        //  turns the lights and the buzzer off
        delay(runTime(18,0));
        //  keeps the loop from resuming
    }
    else if (millis() > runTime(0,40))  {
    //  this block of code is only executed if the code has run until the latest wake time specified
        delay(2000);
        //  allows the Particle.publish() function to work properly
        Particle.publish("brew-coffee","Coffee is brewing!");
        //  publishes an event to the cloud for any connected device to subscribe to
        digitalWrite(relay,HIGH);
        alarmTone(500,500,15);
        //  sounds alarm (see function below) and turns on lights for specified time
        digitalWrite(relay,LOW);
        digitalWrite(buzzer,LOW);
        //  turns the lights and the buzzer off
        delay(runTime(18,0));
        //  keeps the loop from resuming
    }
    else    {
    //  this block of code is what the loop executes most of the time, if the other two conditions are false
        digitalWrite(relay,LOW);
        digitalWrite(buzzer,LOW);
        //  sets each pin low
    }
}
//  this code will run repeatedly

void alarmTone(int play,int pause,int duration) {
    int n = round((duration*60000)/(play+pause));
    //  converts duration to amount of loops needed
    int i = 0;
    //  creates a counter
    while (i < n)    {
    //  this block of code executes for the specified duration
        digitalWrite(buzzer,HIGH);
        delay(play);
        digitalWrite(buzzer,LOW);
        delay(pause);
        //  turns the buzzer on and off for a customized tone
        i = i+1;
        //  updates the counter
    }
}
//  this is a function that plays a customized alarm tone for a specified time
//  it also serves as a delay to keep the lights on for the specified duration
//  the inputs are in (ms,ms,mins)

int runTime(int hours,int mins)   {
    int secs = (hours*60 + mins)*60;
    return secs*1000;
    //  converts inputs to milliseconds and returns that value
}
//  this is a function that returns an integer representing milliseconds
//  this is useful in conjunction with the delay function
//  the inputs are in (hrs,mins)

/*******************************************************************************
 THE FOLLOWING CODE IS TO BE PLACED IN ANOTHER FILE FOR A SEPARATE PHOTON!!!
*******************************************************************************/

/*  This code listens for an event or a command
    from the cloud and executes the corresponding function.
*/

int relay = D7;
//  creates a variable for the relay to control the coffee maker
//  the on-board LED turns on when the coffee maker is on

void setup() {
    pinMode(relay,OUTPUT);
    //  sets the relay pin as an output for the Photon
    digitalWrite(relay,LOW);
    //  sets the pin to low to start
    Particle.function("Coffee",Brew_Coffee);
    //  this allows the function Brew_Coffee to be published to the cloud
    Particle.subscribe("brew-coffee",brewCoffee,"3f0031000947343432313031");
    //  this allows the Photon to subscribe to the event published by the first Photon
}
//  this block of code will run once during startup

void brewCoffee(const char *event, const char *data)    {
    digitalWrite(relay,HIGH);
    delay(runTime(0,20));
    digitalWrite(relay,LOW);
    //  turns the coffee maker on for 20 minutes, then turns it off
}
//  this block of code will run if the Particle has subscribed to the event brew-coffee

int Brew_Coffee(String command)    {
    if (command == "brew" || "on" || "Brew" || "On")  {
        digitalWrite(relay,HIGH);
        delay(runTime(0,20));
        //  turns the coffe maker on for 20 minutes
        digitalWrite(relay,LOW);
        return 1;
        //  turns the coffee maker off and returns 1 for true
    }
    //  this block of code runs if the command matches one of the above options
    else    {
        digitalWrite(relay,LOW);
        return 0;
        //  sets the relay pin low and returns 0 for false
    }
    //  this block of code runs if the command does not match
}
//  this block of code runs if it is prompted with a command
//  the command can be input via Mobicle.io

int runTime(int hours,int mins)   {
    int secs = (hours*60 + mins)*60;
    return secs*1000;
    //  converts inputs to milliseconds and returns that value
}
//  this is a function that returns an integer representing milliseconds
//  this is useful in conjunction with the delay function
//  the inputs are in (hrs,mins)

Credits

Sam Hofmann

Sam Hofmann

1 project • 2 followers
I am a double major in Mechanical Engineering and Physics at UNC Charlotte.
George Powell

George Powell

1 project • 2 followers

Comments