Projects

Morning Has Broken

It's Okay, We Fixed It!

Oliver Higgins

Issue 12, June 2018

This article includes additional downloadable resources.
Please log in to access.

Log in

A clever daylight alarm clock for a softer start to your day.

Do you ever wake up still feeling tired, hit the snooze button and then go back to sleep? Only to then find you’re running late for work or school?

With winter arriving now (here in Australia), the days are getting shorter, and often they feel very long and tiring; especially because we’re waking up and it’s still dark outside. Eventually, this routine can take its toll on your performance, as your circadian rhythm (the physical, mental and behavioural changes that follow a roughly 24-hour cycle) responds primarily to the light and darkness in your environment. So in winter it can fall out of sync with your day, leaving you feeling tired, sluggish and lacking in energy.

One solution is an alarm clock that wakes you up with a gradual brightening light, naturally resetting your sleep/wake cycle to help you feel refreshed, alert and energised all day. The sunrise effect is a natural cue for your body to reduce the production of sleep hormones (e.g., melatonin), and gradually increase the levels of those that help you get up and go (i.e., cortisol). In Europe, this product is classed as a medical device, and is popular among people suffering insomnia, depression, lack of energy and seasonal affective disorder (SAD).

Waking up with light every day can help to improve your sleep/wake cycle and, therefore, overall health and wellbeing.

THE BROAD OVERVIEW

The problem we face is not overly complex, but it can be if we really want to get stuck into this code. This is one project that is present in a functioning state, but the code has been designed with the maker in mind. There are endless possibilities in what you could achieve with this clock, but for now, we will focus on making it meet our initial brief: to wake a person up, by simulating a slow sunrise light show.

Think about a typical Sunday morning sleep-in. You awake naturally, as the sun fills your room, leaving you in a nice, light, dreamy state, which enables you to then gently regain your conscious. You’ll tend to feel more well rested, even if you’ve slept for the same amount of hours that you usually get. This process of lifting the conscious to a non-REM or wake state, leads to an easier awakening; and this is what we’re aiming to replicate.

We need to set our alarm and have the alarm “trigger” an event during a pre-defined period, before our desired time to wake. In this case, we will have our previous event one-hour before the time that we want to be woken up. The aim here is to trigger a soft red light that mimics the first light of dawn. Then, as time progresses, the light shifts through orange hues before arriving at a white that mimics daybreak.

HOW IT WORKS

“Daylight lamp”, “daylight alarm”, “dawn simulator”, “artificial sunrise”, “sunrise alarm” and “wake up light therapy” are all different terms that refer to what we’re making here. Whatever you prefer to call it, we need to first create a timing system that triggers light changes at defined intervals; in our case, it will be every 15 minutes over the course of an hour.

We will be using a 4 × 7 segment display for the clock; it uses the TM1637 chip. There are several modules using this chip to form a four-digit numerical display module (sometimes called a “digital tube”). These modules are available from Jaycar as part of the linker series.

Light strips and Neopixels

LEDs are awesome and have been around for a long time. It was only until the advent of the blue LED ten years ago that they could pave the way to white. This has led to RGB multicoloured LEDs that we can control. This was the domain of 3 Pulse Width Modulation (PWM) channels until recently, but Adafruit came along with their NeoPixels and this all changed. Under the branding lies the WS2812B LEDs. These tiny units are capable of delivering the full RGB spectrum, and with the use of the NeoPixels library, we can control them with just a single wire, and no need to worry about PWM! These are available through Adafruit in many different configurations but Jaycar stocks a compatible 8 LED “strip”. These strips, as with all of these LEDs, are configurable as a daisy chain, so can lead to some spectacular builds.

THE Build

Parts Required:JaycarAltronics
1 × Wemos D1 R2--
1 × Standard Uno Proto ShieldXC4482
1 × 100Ω Resistor*RR0548R7534
1 × 10k Resistor*RR0596R7582
1 × Linker 4-Digit 7-Segment ModuleXC4569-
2 × 5V RGB LED StripsXC4380-
1 × Momentary ButtonSP0700S1084
1 × Piezo BuzzerAB3458S6104

* Quantity shown, may be in packs. Jumpers/hookup cable required.

We start by printing out the required 3D parts. Be mindful to print your parts using supports as both the main lamp and the NeoPixel holders have some complex overhangs. Mount the Wemos using four small screws, ensuring you have clearance for the USB and the power socket.

Next we’ll attach the Piezo to the board. Place it in the centre, which will allow clearance under the LED strip 3D part. Attach the 100Ω resistor to the negative side, and then to ground and connect the positive to pin D10 on the breakout board.

The clock TM1637 module is next. It’s easier to use some male-female jumper leads here. Connect the wires to the DIO, and the CLK pins, then connect the power and ground but leave the other ends bare for the moment. Place the clock module into the clear faceplate diffuser using a hot glue gun to hold in place. We will come back to this again shortly.

For the button, we start by fitting the physical button in place and connecting the 3.3V wire to one side and the 10k resistor to the other before connecting it to a ground wire. Connect a jumper to pin D5 on the Wemos board.

When it comes to the LED strips, take your time. The LED strips have four connection pads, so clean and solder a header strip onto one end of the first unit. Be mindful with the soldering, as the pads are small so it’s easy to get a poor connection or short circuits.

fig 2

Put a header on each end of the first one, and one on the second. If you decide to do more than two then just follow this pattern. Place both on the provided 3D printed part, and secure with screws. You can either use female-female jumpers or solder into place the connecting outputs and inputs.

We reiterate: take your time here, as soldering may result in the pads becoming unstuck.

Connect the CLK and DIO to pins D7 and D6, and the LED strip to pin D8. We have just used male headers, as there is enough room in the printed chassis.

Wire up the 5V from the button, clock and NeoPixels. Solder and heat shrink together before repeating with the ground wires. We can now power up and test.

You should have power to the major items, so feel free to upload the provided code. This will trigger the party mode, which will test all the parts. Hold down the reset button, and you should get a beep and a blue flash before the LEDs turn off and the clock starts, provided we have set the WiFi credentials. If everything checks out fine, assemble the printed unit.

inside
The electronics placed into our 3D printed case.

THE CODE

With most code setup we bunch the libraries together, and then set our object and variables. In this case, the setup is a little busier, so we have put like components and code together in one spot. This makes configurations and changing a little easier. Additionally, we have made this code quite simple and as such, the code appears quite verbose at times; but it is very easy to follow.

Make sure that you have installed the required libraries. All of these libraries can be found in the Arduino library manager. Following is a list of the dependencies.

Libraries:

We start with the LED strips. They use the NeoPixel libraries and so need to be set up as such. The main thing to note with this section of code is the line #define PIN D8, which tells the library which pin to send information to, regarding the lighting up of the strip. This is one of the fantastic things about this system – it just requires one pin assignment!

The next thing of note is to tell the library how many pixels are daisy chained together. Each of the strips has 8 LEDs, and we will be using two of them; therefore, we define it as 16. You can add more or less, but be mindful of the increase in power requirements for each additional LED. As this project stands, we are on the edge of the power consumption that the Wemos can safely deliver.

Finally, in our last line we instantiate the NeoPixel object and name it “pixels”.

NeoPixel Setup

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
#define PIN        D3
#define NUMPIXELS  16
#define BRIGHTNESS 255
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

For the clock display model, we use the TM1637 library. For this, we define the two pins that we will be using for the assignment, in this case D7 and D6 for CLK and DIO, before creating the TM1637 object.

#include "TM1637.h"
#define CLK D7
#define DIO D6
TM1637 tm1637(CLK, DIO);

WIFI SETUP

const char* ssid = "YourSSID";
const char* pass =  "YourPassword";

We need to set up our internet access via WiFi. Place your router's SSID and password in the above code. For this instance we will not be setting the IP but leaving it to DHCP to issue one to us. When the system boots we will be given the current IP in the serial output.

ALARMS SETUP

#include <TimeLib.h>
#include <TimeAlarms.h>

Next we set up the pins that we will be using for our inputs and outputs. We declare these here as we can just refer to them by name throughout our code. If the pin assignment changes then we only need to change the code in one spot.

int resetButton = D5;
int piezoPin = D10;
int buzzerOn = 0;

The alarm can be set for any hour, minute and second you want, but time can be fickle when performing functions on it.

Now we prepare the functions for use in the main sketch. There was some repetition in this code and so it has been removed for clarity. Please see the full source code for more detail.

This is the chase function, which is used in partyMode. It is a sub-routine that makes the LED’s appear to chase each other along the strip.

static void chase(uint32_t c) {
  for (uint16_t i = 0; i < pixels.numPixels() + 4; i++) {
    pixels.setPixelColor(i , c); // Draw new pixel
    pixels.setPixelColor(i - 4, 0); // Erase pixel a few steps back
    pixels.show();
    delay(25);
  }
}

Party mode is a piece of demonstration code to test all the pixels are working. It will loop until the reset button is held down at which point the clock will revert to its normal function mode. It will beep and flash blue to signify that this has happened.

void partyMode() {
  while (digitalRead(resetButton) == LOW) {
    //set clock
    //we’re gunna party like it’s;
    tm1637.point(POINT_OFF);
    tm1637.display(0, 1);
    tm1637.display(1, 9);
    tm1637.display(2, 9);
    tm1637.display(3, 9);
    chase(pixels.Color(255, 0, 0)); // Red
    chase(pixels.Color(0, 255, 0)); // Green
    chase(pixels.Color(0, 0, 255)); // Blue
  }
    }

This segment of code is used to turn the lights off; we simply put all the RGB values to 0 then update the pixels object.

void lightOff() {
  for (int i = 0; i < NUMPIXELS; i++) {
    pixels.setPixelColor(i, pixels.Color(0, 0, 0));
    pixels.show();
  }
}

We have several functions that are used to control the colour of the lights. We have simply defined them as colours with function names that reflect that. This is repeated for green, blue and pink.

void setRed() {
  Serial.println("Set to RED, 60 minutes");
  for (int i = 0; i < NUMPIXELS; i++) {
    pixels.setPixelColor(i, pixels.Color(255, 0, 0));
    pixels.show();
  }
}

This is the first of the colour changes. We repeat this process four more times, each time changing colour. You could use this to start a function that could cycle through the colours to create a better fade, or alternately add in code to trigger something else entirely.

void set1() {
  Serial.println("Function set1 active");
  for (int i = 0; i < NUMPIXELS; i++) {
    pixels.setPixelColor(i, pixels.Color(255, 5, 0));
    pixels.show();
  }
}

The above code is used to set the first stage of the actions when called by our original alarm functions. In this instance we have 3 “set” functions we will be using, set1, set2 and set3. In this case we have set1 and it is the first called in our sequence to change the LED lights. Next we have a loop that will step through our LED’s in the LED strip. In this case we will go through each one and set the specified RGB colour using the set pixel function. We specify our different colours in the Red, Green, Blue colour sequences by specifying a value of 0-255 for each colour. This loop occurs 16 times before we “send" the data to the LED strips using the pixels.show() command.

The following code is used to set the clock module to display the current time. The time digits are refreshed in a different part of the code. The purpose of this is to simply change the seven segment LEDs. The initial “If” statement checks on the decPoint variable. If it’s 0 then we do not change the “seconds” point, however if the varible is 1 then we tell the module to turn the seconds segment on. This results in a basic flash to indicate that seconds have passed.

The next four lines are dedicated to each segment. The first argument declares which LED we change, 0 being the left most when looking at it. We do some simple maths on the hour and minute, to get the individual numbers, which are then fed to the display.

void setClockDisplay() {
  if (decPoint == 0) {
    tm1637.point(POINT_OFF);
    decPoint = 1;
  } else {
    tm1637.point(POINT_ON);
    decPoint = 0;
  }
  tm1637.display(0, hh / 10);
  tm1637.display(1, hh % 10);
  tm1637.display(2, mm / 10); 
  tm1637.display(3, mm % 10);
  delay(500);
}

We now move on to the setup routine itself. To start we set the maximum brightness level of the NeoPixel LED strips. The Pixel strip is then started using the “begin” command. We set our pin mode to output on the Piezo, before initialising the TM1637 driver.

NTP SERVER

We will be pulling the time from an NTP server; this means we will always have accurate time once the system has started up. One thing to note is that the NTP server delivers the time as the current time at UTC. We are located in NSW Australia, so our time zone is +10 hours (+11 for daylight savings). We have included this variable for time offset in line 13 of the code.

int timezone = 10; 
//make 11 for Daylight saving. +10 for sydney etc

With this completed, we are done configuring the NTP. The system will automatically find the required server.

The code itself for processing the NTP data is not overly long or complicated, but we have to add in some outputs to show you how to get more than just UTC. The following code is in the getTime() function.

We start by getting a random server from the NTP pool before sending an NTP packet to a time server, and then we wait to see if a reply is available.

WiFi.hostByName(ntpServerName, timeServerIP);
  sendNTPpacket(timeServerIP); 
  delay(1000);

We wait to see if data has been received; if not, then we wait because having a clock with no time is somewhat useless!

  int cb = udp.parsePacket();
  if (!cb) {
    Serial.println("no packet yet");
  }

We've received a packet, read the data from it, then placed the packet into the buffer. The timestamp starts at byte 40 of the received packet and is four bytes, or two words in length. First, we'll extract the two words. To do so, we combine the four bytes (two words) into a long integer, which is NTP time (seconds since Jan 1 1900).

  Serial.print("packet received, length=");
  Serial.println(cb);
  udp.read(packetBuffer, NTP_PACKET_SIZE); 
  unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
  unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
  unsigned long secsSince1900 = highWord << 16 | lowWord;
  Serial.print("Seconds since Jan 1 1900 = " );
  Serial.println(secsSince1900);

We now convert NTP time into everyday time. The Unix epoch starts on Jan 1 1970, or 70 years after NTP time. We subtract 70 years (that's 2208988800 seconds) from our number, before outputting the Unix time:

  Serial.print("Unix time = ");
  const unsigned long seventyYears = 2208988800UL;
  unsigned long epoch = secsSince1900 - seventyYears;
  Serial.println(epoch);

The code goes on to show how we can use this timestamp to display the time and date, and use it throughout the rest of the project.

Next, we move to setting our alarms. A limitation of the Alarms library is its maximum of five alarms. You can delete some obsolete alarms if required, but for our purposes we will just keep it simple. One method around this may to be set one alarm, and part of that alarm is to delete the current alarm and create a new one. This could be styled as a recursive alarm process. But a task for another time.

When setting the alarm, we need to set the time but also which function we will call when the alarm is triggered. For our project we have created four different functions for our different colour changes. Unfortunately for us, the Alarm library does not allow the use of parameters in its function calls.

Finally, we call the “lights off” function that turns all the LED lights out, before starting partyMode. Party mode is designed as a test. It starts up the Neopixel strips and runs through each RGB colour before cycling again. When the clock is switched on, this loops until the reset button is held down for one second.

We have omitted some of the serial outputs and comments for clarity, but please review the full sketch for more information.

When compared to the above, our main loop is quite minimal. We’ll start each loop by setting up the clock for use. We pull the current time from NTP and place into the “now” variable. This gets us the values we need for the clock display. We then move to see if the buzzer variable is flagged, which lets us know if we need to sound the alarm buzzer. We then set the display on the clock before checking to see if the reset button is being held down. Note: there is a slight delay here, to allow for switch bounce, but there is a second delay function in the setClockDisplay function, at half-second intervals. This is required to make the colon between the digits flash on the display. If you want the system to run more responsively, remove this delay and the code required for the flashing.

THE SETUP

Once you have assembled, tested and partied like it’s 1999, we need to set up our WiFi access if you have not done it already. On line 7 and 8 of the code you will find the SSID and password variables. Change these to match your wireless network.

We now have a functioning clock system that after boot and partymode if enabled will display the current time. To set the alarm time, we have created a basic web app. You will find it in the web app directory of the source files. In the first instance open it on your computer. This is a HTML5 app which can be saved to your phone. Before we start the web app we need to get the IP address of the clock. With your clock connected to the Arduino IDE, open the serial monitor and wait to boot. Once a connection is made to the WiFi network your devices IP will be outputted. Generally the IP address will not change after each power-cycle however it is dynamic so if you have issue connecting from the web app check the serial output to confirm the IP address.

alarm clock

When the app is first opened you will be greeted by the initial screen which is attempting to connect to our device. As our IP address is not set up, you will not be able to connect.

You will now be prompted to input your devices IP. Please note that we are using JSON data here and as such communicating over http so we must put http:// before your IP.

setup

If the IP is correct then we are greeted by the dashboard. This will return the current time that the system is set for. We have two options available to us, setting the alarm and turning the lamp on and off. The lamp option simply turns our LEDs to full brightness and all white.

alarm on light off

To set the alarm on the clock we touch or click the alarm icon on the dashboard screen. This will bring up the time selection screen. First select the hour, then the minute you want the alarm set for. The app will then communicate with the device and return you to the dashboard showing the set time.

setting alarm

ADD TO SMARTPHONE HOMESCREEN

We have hosted the HTML package at https://diyode.io/012html for your convenience. If you prefer to serve the HTML package yourself, you will need to use a web server or an online service such as an AWS S3 bucket with static website enabled.

It is pure front-end content however, so any web server will handle it without any server side requirements.

To add to your home screen, browse to the website and then:

iPhone:

Safari › Add to home screen

Android:

Chrome › Add to home screen

The app will now launch in full screen mode, hiding the URL bar to provide a native app experience. This is a powerful shortcut to a full-featured app. While it doesn't provide all the functionality and access of a full native app, it provides more than enough for this type of application.

WHERE TO FROM HERE?

Of all the projects we have done, this one probably has the most potential to provide great exercise for coding with flexibility for additional functionality. Therefore, we set you the challenge for the “Open Daylight Clock”.

See how many of these you can implement:

  • A wind-down mode that works inverse to the original plan, where it starts bright and mimics sunset, removing blue-light from the light spectrum to help you get to sleep.
  • Cycle the beep with the modes, so as the lamp gets brighter the beeps get faster.
  • Add in brightness settings so that as the colour changes, it gets brighter.
  • What about Monday to Friday? Check out the documentation for the Alarms library and only have the alarm go off on weekdays.
  • What about a snooze function on a button press, when the alarm is active?

This project has the potential to deliver so much more than what we’ve discussed here, so give it a try and let us know how you go!