Introduction: RaspberryPi Alarm Clock

About: Jack passed away May 20, 2018 after a long battle with cancer. His Instructables site will be kept active and questions will be answered by our son-in-law, Terry Pilling. Most of Jack's instructables are tuto…

This is an alarm clock based on a RaspberryPi. Any RaspberryPi will work. I used a model B1 version 2 because it has the mounting holes and speed does not matter. I have a task that needs to be performed every other day. For that reason there is an asterisk displayed in the bottom corner of the display every other day to help me keep track. It would be easy to change the operation of this feature in the code if you have different needs. You might also wish to change the sound of the alarm. Make it warble or sound like a siren, feel free to experiment.

You will need:

* Any model RaspberryPi will work. If you use one of the very first ones with no mounting holes you will need to stick it down with two sided tape. If you use a new model three you will still need the WIFI dongle to get the WIFI out of the metal case. For the Zero, if you can find one, you will need a different USB data cable.

** Purchased locally at Ace hardware

*** Purchased locally, mine has terminals to plug into female jumper wires. I don't know where it came from. This speaker, https://www.sparkfun.com/products/9151, will work. Solder a piece of 22 gauge hookup wire onto the terminals and leave about 1/2 inch of wire sticking out to attach the female jumper wires.

.

This project uses the wiringPi libraries, written by Gordon Henderson, for programming the GPIO in C in a style similar to the Arduino IDE.

wiringPi must be installed.

Instructions for download, install and use are located at http://wiringpi.com

wiringPi uses it's own pin numbering scheme. All pin numbers mentioned in the program or in the text are wiringPi numbers unless otherwise specified.

After installing wiringPi you can obtain a list showing the pin numbering for your specific model of RaspberryPi by opening a command terminal and typing: gpio readall

Step 1: Drill Mounting Holes in Enclosure

Bottom:

The four holes that are already in the chassis are for the rubber feet, avoid them.

Position the Raspberry and the Perma-proto board for the amplifier as shown in the first picture. Mark, then drill 1/8 inch mounting holes.

Install the four rubber feet.

Front:

Position the LCD screen centered on the front panel of the chassis, mark and drill the four 1/8 inch mounting holes.

Drill three 5/16 holes holes for the wires to run through and insert the grommets.

It can be hard to drill large holes in thin sheet metal. For the larger holes I drilled them to 1/4 inch and used a conical reamer to enlarge them. The conical reamer was purchased at the local Ace hardware store.

Back:

Drill an 1/8 inch hole about 7/8 inch in from both sides and 3/4 inch up from the bottom.

Drill an 1/8 inch hole 15mm to the left and right of both of these holes.

Open the center holes up to 1/2 inch diameter. The left side is the USB power connector and the right hole is for the USB WIFI dongle.

Use a small file to enlarge the sides of the hole on the right so the dongle can go in all the way and clear the sides.

Drill the three remaining 1/2 inch holes approximately where shown in the photo, location not critical.

Top:

Drill a hole in the top centered side to side about 2 inches from the back and enlarge the hole to 1/2 inch.

Step 2: Amplifier for the Alarm

The amplifier for the alarm is based on an LM386 audio amplifier IC.

Build the circuit according to the diagram and photo.

The blue and green wires on the right of the drawing are jumper wires about seven inches long with female ends to connect to the speaker.

The red and black wires on the left side of the diagram are about 2 1/2 inches long, they are jumper wires with female ends to connect to five volts and ground on the RaspberryPi.

The yellow wire on the left bottom of the diagram is about 2 1/2 inches long. It is a jumper wire with a female end that connects to wiringPi pin number 1, the PWM output from the RaspberryPi. This is the input to the amplifier.

The white wire bottom right is the contrast for the LCD screen, it is 22 gauge hookup wire.

The black wire bottom right is the ground for the switches, it is 22 gauge hookup wire.

The pot on the left is the volume control and the one on the right is the contrast control for the LCD screen. Both pots are 10 KΩ.

Step 3: Preparing the RaspberryPi

Install Raspbian as you normally would.

Run sudo raspi-config

While in raspi-config make sure you enable ssh, so you can access the RaspberryPi without dis-assembling the clock.

Setup the wireless and make sure it connects automatically when the RaspberryPi boots.

Run ifconfig and make note of the MAC address.

Open your router config utility and reserve an IP address for the WIFI connection.

With this done you can ssh into the RaspberryPi from another computer on your LAN with the command:

ssh [USER_NAME]@[IP_ADDRESS]

If you are running linux start ssh with the command:

ssh -X -4 [USER_NAME]@[IP_ADDRESS]

Then you can run GUI based programs from another computer on your LAN.

I also installed geany because it is the programming environment I prefer to use.

If you want it you can install it with the command: sudo apt-get install geany

Step 4: Test the Amplifier, Set Frequency and Volume

To test the amplifier connect the red wire to physical pin 2 on the RaspberryPi, this is a 5 volt pin.

Connect the black wire to physical pin 6 on the RaspberryPi, this is a ground pin.

Connect the yellow wire to physical pin 12 on the RaspberryPi, this is wiringPi pin 1, the PWM pin.

Copy this program to the RaspberryPi, It is a simple program to test the amplifier and make adjustments to the sound. It should turn on a buzzer for five seconds.

/******************************************************************
 * Filename: sound.c
 *
 * All pin numbers are wiringPi numbers unless otherwise specified.
 ******************************************************************/

#include <wiringPi.h>

int PWMpin = 1; // Alarm sound pin

/**************************************************************
 * main() function
 **************************************************************/
int main()
{
  wiringPiSetup();              // Setup required by wiringPi

  pinMode (PWMpin, PWM_OUTPUT); // Alarm sound pin
  pwmSetMode(PWM_MODE_MS);      // Mark/Space mode
  pwmSetClock(100);             // Default 100 (int)
  pwmSetRange(1024);            // Default 1024 (unsigned int)
  int duty = 200;               // Duty cycle

  pwmWrite(PWMpin, duty);       // sound alarm
  delay(5000);                  // for five seconds.
  pwmWrite(PWMpin, 0);          // turn off alarm
  return 0; 
}

Compile it with the command:

gcc -o sound -Wall -I/usr/local/include -L/usr/local/lib sound.c -lwiringPi

And run it with the command:

sudo ./sound

You need to use sudo because the RaspberryPi requires you to be root for low level access to hardware, like the GPIO.

Make sure you have the volume turned down when you start the program, it can get very loud.

Adjust the frequency by changing the 100 in the line that says pwmSetClock(100);

You can also adjust the volumeby changing the 200 in the line that says int duty = 200;

Remember the changes you made to include them in the clock program.

In the clock program these lines are located just above the while(1) in the main() function.

Attachments

Step 5: The Program

Copy the clock program to your RaspberryPi.

/******************************************************************
 * Filename: clock.c
 *
 * RaspberryPi alarm clock With special reminder feature.
 *
 * Compile: gcc -o clock -Wall -I/usr/local/include -L/usr/local/lib 
 *          clock.c -lwiringPi -lwiringPiDev
 * 
 * Execute: sudo ./clock
 *
 * All pin numbers are wiringPi numbers unless otherwise specified.
 ******************************************************************/
#include <time.h>
#include <stdio.h>
#include <wiringPi.h>
#include <lcd.h>

static int lcdhandle; // LCD screen

char hours[24][3] = {"12","01","02","03","04","05","06","07",
                     "08","09","10","11","12","01","02","03",
                     "04","05","06","07","08","09","10","11"};

char dow[7][4] = {"Sun","Mon","Tue","Wed",
                   "Thu","Fri","Sat"};

char months[12][4] = {"Jan","Feb","Mar","Apr","May","Jun",
                       "Jul","Aug","Sep","Oct","Nov","Dec"};

struct tm tm2;  // Structures for getting time.
int timeh, timem, times;     // Current time elements.
int date, month, year, wday; 

int apin = 5;   // Alarm button
int hpin = 6;   // Set hours button
int mpin = 12;  // Set minutes button
int spin = 13;  // Special button

int PWMpin = 1; // Alarm sound pin

int aflag = 0;  // Alarm flag
int sflag = 0;  // special flag

int alh = 0;    // Alarm hours
int alm = 0;    // Alarm minutes

/*********************************************************
 * gettime() function - Get system time and load it into  
 * global variables. 
 *********************************************************/
void gettime()
{
  time_t now;
  char *str;

  now = time(NULL);                          // Get the time.
  str = ctime(&now);                         // Convert it to a string.
  strptime(str,"%a %b %d %H:%M:%S %Y",&tm2); // Convert from string.

  timeh = tm2.tm_hour;                       // Copy times
  timem = tm2.tm_min;                        // into global variables.
  times = tm2.tm_sec;
  date = tm2.tm_mday;
  month = tm2.tm_mon;
  year = tm2.tm_year;
  wday = tm2.tm_wday;
}

/*********************************************************
 * dsptime() function - Displays the time. 
 *********************************************************/
void dsptime()
{
  lcdPosition (lcdhandle, 6, 0);
  lcdPrintf(lcdhandle,"%s:", *hours+(timeh*3)); // Display hours
  lcdPrintf(lcdhandle,"%02d", timem);           // Display minutes
  if(timeh<12) lcdPrintf(lcdhandle," AM");      // Display AM/PM
  else lcdPrintf(lcdhandle," PM");

  lcdPosition (lcdhandle, 0, 1);
  lcdPrintf(lcdhandle,"   %s %s %d %d  ",
           *dow+(wday*4), *months+(month*4), date ,(1900+year));

  if(sflag>0)
  { 
    lcdPosition(lcdhandle,0, 3);  
    lcdPrintf(lcdhandle,"* ");
  }
  else
  { 
    lcdPosition(lcdhandle,0, 3);
    lcdPrintf(lcdhandle,"  ");
  }

  if(aflag==0) lcdPrintf(lcdhandle,"Alarm: OFF      ");
  else
  {
    lcdPrintf(lcdhandle,"Alarm: %s:%02d ", *hours+(alh*3), alm); 
    if(alh<12) lcdPrintf(lcdhandle,"AM");// Display AM/PM
    else lcdPrintf(lcdhandle,"PM");
  }

}

/*********************************************************
 * dspalarm() function - Display the alarm time.  
 *********************************************************/
void dspalarm()
{
  lcdPosition (lcdhandle, 0, 1);
  lcdPrintf(lcdhandle,"Set Alarm: %s:%02d ", *hours+(alh*3), alm); 
  if(alh<12) lcdPrintf(lcdhandle,"AM");// Display AM/PM
  else lcdPrintf(lcdhandle,"PM");
}

/*********************************************************
 * setalarm() function - Set the time for the alarm
 * and turn it on.  
 *********************************************************/
void setalarm()
{
  lcdClear(lcdhandle);
  dspalarm();    
  while(aflag==2)
  {
    while(digitalRead(hpin)==0)      // Is minute button pressed?
    {
      alh++;                         // Increment alarm hour
      if(alh>23) alh=0;              // Hour can't be > 23
      dspalarm();                    // Redo the display
      delay(500);                    // Time to read it
    }
    delay(25);                       // Debounce 
    
    while(digitalRead(mpin)==0)      // Is minute button pressed?
    {
      alm+=5;                        // Add 5 to alarm minutes.
      if(alm>59) alm=0;              // Minute can't be > 59
      dspalarm();                    // Redo the display
      delay(500);                    // Time to read it  
    }  
    delay(25);                       // Debounce 

    if(digitalRead(apin)==0)
    {
      while(digitalRead(apin)==0);
      delay(25);
      aflag = 3;
    }
  }
}

/**************************************************************
 * main() function
 **************************************************************/
int main()
{
  int ptime = 70;               // previous time after gettime()
  int pday = 32;                // Prevoius day   

  wiringPiSetup();              // Setup required by wiringPi

  lcdhandle = lcdInit (4, 20, 4, 11,10, 0,2,3,4,0,0,0,0) ;

  pinMode(apin, INPUT);         // Set alarm pin to input pullup
  pullUpDnControl(apin, PUD_UP);
  pinMode(hpin, INPUT);         // Set hours pin to input pullup
  pullUpDnControl(hpin, PUD_UP);
  pinMode(mpin, INPUT);         // Set minutes pin to input pullup
  pullUpDnControl(mpin, PUD_UP);
  pinMode(spin, INPUT);         // Set special pin to input pullup
  pullUpDnControl(spin, PUD_UP);

  pinMode (PWMpin, PWM_OUTPUT); // Alarm sound pin
  pwmSetMode(PWM_MODE_MS);      // Mark/Space mode
  pwmSetClock(100);             // Default 100 (int)
  pwmSetRange(1024);            // Default 1024 (unsigned int)
  int duty = 200;               // Duty cycle (0 - range)

  while(1)
  {
// Get and display system time
    gettime();
    if(ptime != times)
    {
      ptime = times; // Save time as previous time
      dsptime();     // Display the time
    }
// Toggle special flag if black button pressed or new day.
    if(digitalRead(spin)==0)      // If button pressed toggle    
    {                             // special flag
      while(digitalRead(spin)==0) // debounce
      {
        delay(25);
      }
      sflag = !sflag;             // toggle
    }    
    if(date != pday)              // Is it a new day?
    {
      lcdClear(lcdhandle);
      sflag = !sflag;             // If so toggle special flag,
      pday = date;                // and save date as previous.
    } 

// Sound alarm.
    if(timeh==alh)                // If alarm hour
    {
      if(timem==alm)              // and alarm minute
      { 
        if(aflag==1)              // and alarm flag == 1
        {
          pwmWrite(PWMpin, duty); // sound alarm
        }
      }
    } 

    if(aflag==0) pwmWrite(PWMpin, 0);   // Alarm off if button pressed
    if(timem!=alm) pwmWrite(PWMpin, 0); // or 1 minute has passsed

// Turn alarm off, set alarm.
    if(digitalRead(apin)==0)  // Is alarm button pressed?
    {
      while(digitalRead(apin)==0) delay(25); // debounce
     
      if(aflag==1) aflag=0;  // If alarm flag set clear it.
      else aflag = 2;        // If alarm flag clear
    } 

    if(aflag==2) setalarm(); // run alarm set function
    if(timem != alm) if(aflag == 3) aflag = 1;
  } 
  return 0; 
}

Compile it with the command:
gcc -o clock -Wall -I/usr/local/include -L/usr/local/lib clock.c -lwiringPi -lwiringPiDev

And run it with the command: sudo ./clock

when you compile it you get the following warning message:

clock.c: In function ‘gettime’:<br>clock.c:60:3: warning: implicit declaration of function ‘strptime’ [-Wimplicit-function-declaration]
    strptime(str,"%a %b %d %H:%M:%S %Y",&tm2); // Convert from string. 
    ^

Don't worry about it.

Attachments

Step 6: Soldering Wires for the Screen

Drill out the 4 mounting holes on the LCD screen with a 7/64 drill so the #4 machine screws will fit.

Cut pieces of the female jumper wires 5 inches long and strip 1/4 inch on the cut end.

Use the same color wires as in the picture and diagram, In step 8 I refer to the colors when connecting the wires.

The red wire connected to pin three is a piece of 22 gauge hookup wire six inches long. All the others are female jumper wires.

Solder the black and white wires and the wires connecting more than one pin last.

Step 7: Mounting the Parts

The Screen:

Cut two pieces of the electrical tape about 1/4 inch wide and long enough to cover the sides of the screen. This will stop a lot of stray light shining out the sides.

Carefully thread three wires through each rubber grommet.

Use 4 each #4-40x1/2 machine screws, #4-40 nuts and #6 nylon spacers 1/4 inch long to mount the screen.

The RaspberryPi:

Mount the RaspberryPi using two (or four) #4-40x3/4 screws,1/2 inch spacers and #4-40 nuts.

Plug the USB power and data cables into the RaspberryPi and mount them with the power cable on the left and the data cable on the right. Use the supplied screws and #4 washers. You might have to cut off the little things that stop the cable from bending too tight it is a close fit, like in the second picture. As devices are getting smaller they keep making the plastic housings around cable connectors bigger, that has always been a pet peeve of mine. On a model B+ or newer the USB ports are recessed a which will give you a little more room.

Plug in the WIFI module.

The Amplifier board:

Mount the amplifier board using two #4-40x3/4 screws,1/2 inch spacers and #4-40 nuts.

The Breadboard:

The breadboard sticks on like in the diagram.

The Top cover:

Put the large red switch in the hole you drilled in the top cover.

Solder a female jumper wire 8 inches long to one terminal and a black 22 gauge hookup wire 8 inches long to the other.

Mount the speaker on the left side using 2 #4-40x12 screws, nuts, and #4 washers with #8 washes to hold the speaker in place.

The three back panel switches:

Solder a black 22 gauge hookup wire 4 inches long to each switch.

Solder a female jumper wire 6 inches long to the other terminal.

Mount the switches as shown in the photo.

Step 8: Connecting the Wires

Connect the Amplifier board to the RaspberryPi like you did in the testing step.

The red wire goes to physical pin 2 on the RaspberryPi.

The black wire goes to physical pin 6 on the RaspberryPi.

The yellow wire to physical pin 12 on the RaspberryPi, this is wiringPi pin 1.

Connect the black and white wires from the amplifier to the breadboard, they must be in two different columns.

The red wire from the LCD screen goes to the same column as the white wire from the amplifier.

The black wires from the three back panel switches go in the same column as the black wire from the Amplifier. In the picture of the breadboard you can see there is one open position in this column. The black wire from the alarm switch will go here.

Connect the wires from the screen to the RaspberryPi.

The white wire goes to physical pin 4 - 5 Volts.

The The black wire goes to physical pin 9 - Ground.

The orange wire connects to physical pin 26 - wiringPi pin 11.

The yellow wire connects to physical pin 24 - wiringPi pin 10.

The blue wire connects to physical pin 11 - wiringPi pin 0.

The green wire connects to physical pin 13 - wiringPi pin 2.

The purple wire connects to physical pin 15 - wiringPi pin 3.

The grey wire connects to physical pin 16 - wiringPi pin 4.

Connect the wires from the three back panel switches to the RaspberryPi.

The wire from the red switch goes to physical pin 22 - wiringPi 6.

The wire from the green switch goes to physical pin 19 - wiringPi 12.

The wire from the black switch goes to physical pin 21 - wiringPi 13.

Set the top close to the chassis on the left side.

Connect the blue and green wires from the amplifier to the speaker.

Connect the jumper wire from the top switch to physical pin 18 - wiringPi pin 5.

Connect the black 22 gauge wire from the top switch to the breadboard, in the same column as the other switches.

Place the cover on top of the chassis and use the four screws that came with the enclosure to secure the cover.

Step 9: Using the Clock

There are two different methods for starting the clock.

Since you no longer have a monitor attached you have to start it blind or use ssh.

To start it blind:

  1. Plug in the WIFI module.
  2. Plug in the power and wait about one minute.
  3. Plug in a keyboard and type your user name.
  4. Wait a sew seconds and type your password.
  5. Enter the command sudo ./clock to start the program.
  6. Wait a sew seconds and type your password.
  7. Disconnect the keyboard.
  8. Do not re-insert the WIFI module.

Start using ssh:

  1. Make sure your router has an IP reserved for the clock. (Step 3)
  2. Plug in the WIFI module.
  3. Plug in the clock and wait about one minute.
  4. Open a terminal on a computer on your LAN.
  5. Type the command: ssh [USER_NAME]@[IP_ADDRESS]
  6. Start the clock with the command: sudo ./clock
  7. Press -C to stop the program.
  8. Start the clock again with the command: sudo ./clock &

Once the clock is started you can remove the WIFI module to air gap the RaspberryPi for greater security, or you can leave it in for greater accuracy. With the WIFI module removed mine gained about one second in two days. Your results may vary. If the WIFI module is removed re-inserting it will stop the program.

.

I have a task that should be performed every other day. That is what the reminder is used for. The asterisk in the lower left corner switches on/off every other day. The black pushbutton on the back panel toggles it. Once it is set it will stay right as long as the clock runs.

.

When you start the clock the alarm will be off.

Press the alarm button (the big one on top) and it will bring up the screen to set the alarm.

The red button on the back advances the alarm one hour and the green button advances it five minutes.

Press the alarm button again and the alarm will be set to sound at the specified time.

When the alarm sounds it will stay on for one minute then turn off by itself and remain set to sound at the same time the next day.

When the alarm sounds press the button once to turn it off, or three times to reset it for the same time.