IoT Mbed Smart Alarm Clock

/media/uploads/jhawkins38/capture.jpg

Description

The Smart Alarm is a fully integrated alarm clock that will wake you up in the morning with your favorite music or a default beeping tone, display the current weather, and turn on your room lights. The smart alarm can be set from the users smartphone by accessing the mbed server over the internet. The block diagram below depicts the basic setup of the smart alarm. This project was completed by Angel Andres Daruna, Paul Rabbat, James Hawkins, and Cordel Williams for the final project in the Georgia Tech ECE4180 Embedded Systems course.

Alarm Display

/media/uploads/jhawkins38/img_9320.jpg

Time Data

The smart alarm uses an NTPClient to set the date/time. Link: http://developer.mbed.org/users/donatien/code/NTPClient/

Weather Data

The smart alarm uses an HTTP Client to access web data, such as the weather. Link: http://developer.mbed.org/users/donatien/code/HTTPClient/

The smart alarm obtains weather data using Yahoo’s free weather API Link: https://developer.yahoo.com/weather/

User Interface

The smart alarm uses an HTTP Server for the user interface. A user on the same network as the mbed can access the mbed’s IP address and set the alarm time. Specifically, it uses RPC command encoding to communicate with the mbed. Link: http://developer.mbed.org/users/feb11/code/HTTP-Server/ /media/uploads/jhawkins38/img_9296.png

Complications

The mbed LPC1768 has only 32KB of RAM. This is barely enough RAM for multiple Ethernet modules. However, we needed to used the NTPClient, the HTTP Client, and the HTTP Server, amongst other large parts of the code. When we first coded the system, it was very unreliable. The mbed froze after several seconds on each reset. The RAM was limiting our code. After spending several days of attempting to fix the issue, we had to limit our usage of RAM:

  1. First, we had to remove the XML parser library that we indented to use for parsing weather data. Instead, we wrote our own XML parser. Ours did not require a copy of the 3000-charater HTTP Get buffer.
  2. We utilized function calling to reduce variable scope wherever possible: In main,

getAndParseWeather();
wait(1);
getTime();
wait(1);

Where getAndParseWeather(),

void getAndParseWeather(){
   char* buf = getWeather();
   wait(1);
   parseResults(buf);
}

Future Work

  1. We would have liked to use a WiFly module to accest the internet instead of an Ethernet mag jack.
  2. We hard-coded the Yahoo location ID for Atlanta, GA. It would be beneficial to obtain this ID using GeoLocation so the weather data is always accurate for the user’s location.
  3. A force sensor underneath the bed could be used to determine if the alarm was successful or if the user tured off the alarm and went back to sleep.

/media/uploads/jhawkins38/img_9321.jpg /media/uploads/jhawkins38/img_9319.jpg

Components

Ethernet magic jack breakout

/media/uploads/jhawkins38/ethernet.jpg

Sd card reader breakout

/media/uploads/jhawkins38/sd.jpg

uLCD screen

/media/uploads/jhawkins38/ulcd.jpg

Zero Cross Tail

/media/uploads/jhawkins38/zero_cross_tail.jpg

PowerSSR Tail

/media/uploads/jhawkins38/power.jpg

Breakout Audio Jack

/media/uploads/jhawkins38/speaker.jpg

External Speakers

/media/uploads/jhawkins38/ext_speaker.jpg A dre beats plug in speaker was used in this project via the breakout audio jack attachment.

Demo Video

Demo of our project working

Code

Import programECE4180_FinalProject_SmartAlarm

Code written by Paul Rabbat, Angel Daruna, Jarel Hawkins, and Cordel Williams

IoT Smart Alarm Clock Code

// Includes
#include "SDFileSystem.h"
#include "PinDetect.h"
#include "mbed.h"
#include "NTPClient.h"
#include "uLCD_4DGL.h"
#include "EthernetInterface.h"
#include <vector>
#include <string>
#include "mbed_rpc.h"
#include "RPCCommand.h"
#include "HTTPServer.h"
#include "Formatter.h"
#include "RequestHandler.h"
#include "RPCType.h"
#include "alarmContainer.h"
#include "wave_player.h"
#include "HTTPClient.h"
 
// Defines
#define SERVER_PORT 80 //HTTPSERVER
 
// Global variables
EthernetInterface eth;
uLCD_4DGL uLCD(p28, p27, p29); // serial tx, serial rx, reset pin;
alarmModel _alarm;
string dayOfWeek, month, dayNum, ampm;
int hour, minute, sec;
PwmOut led1(LED1); // led 1 indicates dim value
DigitalOut led2(LED2); // led 2 indicates delay time for interrupts
DigitalOut led3(LED3); // Indicates the alarm has been set 
DigitalOut led4(LED4);  // Indiciates the alarm is going off
 
int alarmSignaled = 0;
PwmOut alarm(p25);
AnalogOut DACout(p18);
PinDetect snooze(p23);
PinDetect stop(p24);
SDFileSystem sd(p5, p6, p7, p8, p12, "sd"); //SD card
FILE *wave_file;
string filepath = "/sd/mymusic/";
 
string weatherCondition = "";
string lowTemperature = "";
string highTemperature = "";
 
volatile bool t = true;
volatile bool play = true;
volatile float vol = .52;
volatile bool insert;
volatile int index;
wave_player waver(&DACout);
int num = 0;
vector<string> filenames; //filenames are stored in a vector string
 
// pin for ZeroCross tail input
// An external 1K pullup required
InterruptIn zerocross(p22);
 
// pin for PowerSSRtail output
DigitalOut SSR(p21);
 
//use timer interrupts to control dimming
Timeout SSRtriggerOn;
 
// dimmer value 0.0=off and 1.0=full on
volatile float dim;
 
// AC power line frequency
const float powerlinefrequency=60.000;
 
 
// Function prototypes
HTTPServer create_simple_server();
HTTPServer create_interactive_server();
 
void stop_hit_callback(void);
void snooze_hit_callback(void);
void read_file_names(char *dir);
void play_wake_up(void);
void thread_server(void const *args);
void thread_display(void const *args);
void thread_alarm(void const *args);
void triggerOn();
void dimmer();
void turn_on();
void getAndParseWeather();
char* getWeather();
void getTime();
void parseResults(char*);
 
int main() {
    snooze.mode(PullUp);
    stop.mode(PullUp);
    wait(.01);
    snooze.attach_deasserted(&snooze_hit_callback);
    stop.attach_deasserted(&stop_hit_callback);
    stop.setSampleFrequency(); 
    snooze.setSampleFrequency(); //default is 20KHz sampling
    
    insert = sd.SD_inserted();
    if(insert){
        printf("Inserted worked.");
    }
    printf("Attempting to read file names");
    read_file_names("/sd/myMusic");
    printf("File names read");
    
    wave_file = fopen( (filepath+filenames[index]).c_str(), "r");
    printf("Wave file opened");
    
    dim = -1.0;
    printf("Getting IP Address.. ");
    uLCD.baudrate(2000000);
    uLCD.cls();
    uLCD.background_color(BLACK); 
    uLCD.textbackground_color(BLACK);
    uLCD.locate(0,0);
    uLCD.color(BLUE);
    uLCD.text_height(2);
    uLCD.text_width(2);
    uLCD.printf("\n\nUniv Time\n  Clock\n");
    uLCD.text_height(1);
    uLCD.text_width(1);
    uLCD.printf("    Loading...\n");
    uLCD.locate(0,0);
    
    if(eth.init())
    {
        printf("Error while initializing the ethernet interface.\n");
        return -1;
    }
    wait(5);
    if(eth.connect())
    {
        printf("Error while starting the ethernet interface.\n");
        return -1;
    }
    
    printf("IP Address is %s\n", eth.getIPAddress());
    
    getAndParseWeather();
    wait(1);
    getTime();
    wait(1);
    
    //set up interrupt routine to detect AC line zero crossings
    zerocross.mode(PullNone);
    wait(.2);
    zerocross.rise(&dimmer);
    // main program only sets dimmer level (dim)
    // interrupt routines dim the light
 
    Thread t1(thread_server); //start thread_server
    Thread t2(thread_display);
    Thread t3(thread_alarm);
    
    while(1){
        led1=!led1;
        Thread::wait(1000);
    }
}
 
void getAndParseWeather(){
    char* buf = getWeather();
    wait(1);
    parseResults(buf);    
}
 
char* getWeather(){
    /*** WEATHER****/
    char buf[3000];
    printf("Getting weather..\n");
    HTTPClient http; 
    int retHttp = http.get("http://weather.yahooapis.com/forecastrss?w=2357024&u=f", buf, sizeof(buf));
    
    switch(retHttp){
    case HTTP_OK:
        printf("Read completely\n");    
        break;
    case HTTP_TIMEOUT:
        printf("Connection Timeout\n");          
        break;
    case HTTP_CONN:
        printf("Connection Error\n");
        break;
    default:
        printf("Error\n");                        
    }
    
    return buf;        
}
 
void parseResults(char* buf){
    printf("Starting parser\n");  
    int i=0;
    char* chars_array = strtok(buf, "\"");
    while(chars_array)
    {
        if(i==63){
            lowTemperature = chars_array;
            printf("Low temp: %s F\n", lowTemperature);
        }
        else if(i==65){
            highTemperature = chars_array;
            printf("Low temp: %s F\n", highTemperature);
        }
        else if (i==67){
            weatherCondition = chars_array;
            printf("Weather: %s\n", weatherCondition);
        }
        
        i++;
        chars_array = strtok(NULL, "\"");
    }
    
    printf("Parser complete!\n");
}
 
void getTime(){
    NTPClient ntpClient;
    printf("Reading time..\n");
    char* domainName="us.pool.ntp.org"; //SET TO DOMAIN NAME OF SERVER GETTING TIME FROM
    //GETS THE TIME FROM THE SERVER
    //setTime(DOMAIN_NAME,PORT_NUMBER,TIME_OUT)
    //DOMAIN_NAME= domain name
    //PORT NUMBER=port number (123 for NTP)
    //TIME_OUT= timeout value for request
    ntpClient.setTime(domainName,123,0x00005000);
    printf("Time set.\n");    
}
 
void thread_alarm(void const *args)
{
    while(1){
        if(_alarm.alarmSet && !alarmSignaled){
            led3 = 1;
            if(_alarm.hours == hour && _alarm.minutes == minute && _alarm.amPm == ampm){
                alarmSignaled = 1;
                //increase brightness
                for(dim = 0.0; dim <= 1.0; dim += 0.025) {
                    led1 = (dim < 0 ? 0 : dim);
                    wait(0.3);
                }
                dim = 1.0;
                led4 = 1;
                play_wake_up();
            }
        }
        Thread::wait(100);
    }       
}
 
void thread_display(void const *args){
    time_t ctTime; //system time structure
    uLCD.cls();
    uLCD.locate(0,0);
    uLCD.text_height(2);
    uLCD.text_width(1);
    char buffer[80]; //BUFFER TO HOLD FORMATTED TIME DATA
    uLCD.textbackground_color(BLACK);
    
    while (1) {
       
        uLCD.locate(0,0);
        uLCD.color(RED);
        // loop and periodically update the LCD's time display
        ctTime = time(NULL)-(3600*4);  //TIME with offset for eastern time US
        
        //FORMAT TIME FOR DISPLAY AND STORE FORMATTED RESULT IN BUFFER
        strftime(buffer,80,"%a %b %d %T %p %z %Z",localtime(&ctTime));
        
        int i=0;
        char* chars_array = strtok(buffer, " :");
        while(chars_array)
        {
            switch(i){
                case 0:
                    dayOfWeek = chars_array;
                    break;
                case 1:
                    month = chars_array;
                    break;
                case 2:
                    dayNum = chars_array;
                    break;    
                case 3:
                    int hourTemp = atoi(chars_array); 
                    hourTemp--; //Daylight savings
                    if(hourTemp > 12) hourTemp -= 12;
                    hour = hourTemp;
                    break; 
                case 4:
                    minute = atoi(chars_array);
                    break; 
                case 5:
                    sec = atoi(chars_array);
                    break; 
                case 6:
                    ampm = chars_array;
                    break;
            }
            i++;
            chars_array = strtok(NULL, " :");
        }
        
        uLCD.printf("    %s, %s %s\n    %02d:%02d:%02d %s\n", dayOfWeek, month, dayNum, hour, minute, sec, ampm);
        uLCD.color(BLUE);
        uLCD.printf("    Low: %s F\n    High: %s F\n    Weather:\n  %s", lowTemperature, highTemperature, weatherCondition);
        if(_alarm.alarmSet){
            uLCD.locate(0,6);
            uLCD.color(GREEN);
            uLCD.printf("    Alarm:\n    %d:%02d %s", _alarm.hours, _alarm.minutes, _alarm.amPm);
        }
        
        Thread::wait(100);
    }  
}
 
void thread_server(void const *args)
{
    RPCType::instance().register_types();
    HTTPServer srv = create_interactive_server();
 
    if(!srv.init(SERVER_PORT))
    {
        eth.disconnect();
        printf("Thread 1 error.\n");
        return;
    }
 
    srv.run();
}
 
HTTPServer create_simple_server()
{    
    HTTPServer srv;
    srv.add_request_handler("DELETE", new DeleteRequestHandler());
    srv.add_request_handler("GET", new GetRequestHandler());
    srv.add_request_handler("PUT", new PutRequestHandler());
    return srv;
}
 
HTTPServer create_interactive_server()
{
    HTTPServer srv(new InteractiveHTMLFormatter());
    srv.add_request_handler("GET", new ComplexRequestHandler());
    return srv;
}  
 
// this interrupt routine is activated after a time delay set by dim value
void triggerOn()
{
    SSR = 1;
    led2=0;
}
 
// this interrupt routine is activated by every AC line zero crossing
// it is needed to synchronize the SSR turnon time delay to the AC line
void dimmer()
{
    // turn off SSR at zero crossing
    SSR = 0;
    // compute time delay using dim value and set timer interrupt
    // triggers SSR after a small post zero crossing time delay
    SSRtriggerOn.attach(&triggerOn,(1.001-dim)/(2*powerlinefrequency));
    led2=1;
}
 
void turn_on(){
    //increase brightness
    for(dim = 0.0; dim <= 1.0; dim += 0.005) {
        led1 = (dim < 0 ? 0 : dim);
        wait(0.3);
    }
    dim = 1.0;
}
 
void stop_hit_callback(void){
   vol = 0.0;
   t = false;
   if (insert == true){
       play = !play;
    }
}
 
void snooze_hit_callback(void) {
    alarm = 0.0;
    wait(5);
    if (insert == true) {
        play =! play;
        wait(5);
        play =! play;
    }
}
 
void read_file_names(char *dir)
{
    DIR *dp;
    struct dirent *dirp;
    dp = opendir(dir);
    //read all directory and file names in current directory into filename vector
    while((dirp = readdir(dp)) != NULL) {
        filenames.push_back(string(dirp->d_name));
        num++;
    }
    num= num;
}
 
void play_wake_up(void){
    while(t == true) {
        printf("Started playing.");
        if ((insert == true) && (play ==true)) {
                waver.play(wave_file, &play);
               if (feof(wave_file)) // when playback ends file will close and play will equal false
                {
                fclose(wave_file);
                printf("Wav ended.");
                } 
                 
            }
        if ((insert == false)&&(play == true)) {
            // generate a 500Hz tone using PWM hardware output
            for (int j=0; j<26; j=j+2) {
                alarm.period(1.0/500.0); // 500hz period
                alarm =vol; //50% duty cycle - max volume
                wait(.5);
                alarm.period(0.0/500.0);
                wait(.5);
                } // end of for
        
            // two tone police siren effect -  two periods or two frequencies
            // increase volume - by changing the PWM duty cycle
            for (int i=0; i<26; i=i+2) {
                alarm = vol;
                alarm.period(1.0/969.0);
                wait(.5);
                alarm.period(1.0/800.0);
                wait(.5);
            } 
        } 
    }
    alarm = 0.0;
}

formatter.cpp (mbed web server code)

#include "Formatter.h"
#include "mbed.h"
#include "RPCObjectManager.h"
#include "EthernetInterface.h"
#include "alarmContainer.h"
#include <string>
 
/* itoa:  convert n to characters in s */
void itoa( unsigned long long int value, char *str)
{   
   int i,j;
   char temp[30];
   for(i=0; value > 0; i++){    
       str[i] = value%10+'0';
       value=value/10;
    }
    for(j=0;i>=0;j++,i--){
        temp[j]=str[i-1];
    }
    for(i=0;i<j;i++){
        str[i]=temp[i];
    }   
}
 
const char *SIMPLE_HTML_CODE = "\
<!DOCTYPE html>\
<html>\
<head>\
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\
<title>Your AC</title>\
</head>\
 <body>";
 
 
const char* INTERACTIVE_HTML_CODE_1 = "\
<!DOCTYPE html> \
<html>\
<head>\
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\
<title>Your Alarm Clock</title>\
<script type=\"text/javascript\">\
var ip = \"%s\";\
function submitCreateForm()\
{\
var url = \"http://\" + ip + \"/Alarm/\" + \"new?name=Alarm\";\
location.href= url;\
}\
function submitCallFuncForm()\
{\
var command = document.getElementById(\"command\").value;\
if(command === \"\") \
return; \
var tmp = command.split(\' \');\
var url = tmp[0];\
if(tmp.length > 1)\
url += \"?\";\
for(var i = 1; i < tmp.length; ++i)\
{\
url += \"arg\" + i + \"=\" + tmp[i];\
if(i+1 < tmp.length)\
url += \"&\";\
}\
location.href = url;\
}\
function submitAlarmPreferences()\
{\
var h = document.getElementById(\"hour\").value;\
var m = document.getElementById(\"minute\").value;\
var a = document.getElementById(\"ampm\").value;\
var url = \"/Alarm/updateAlarmPreference?arg1=\" + h + \"&arg2=\" + m + \"&arg2=\" + a;\
location.href = url;\
}\
function setAlarm()\
{\
var url = \"/Alarm/setAlarm\";\
location.href = url;\
}\
</script>\
</head> \
<body>";
    
const char* INTERACTIVE_HTML_CODE_2 = "</body> \
</html>";
 
//static char chunk[1024];
static char chunk[4096];
        
Formatter::Formatter(int nb):
currentChunk(0),
nbChunk(nb)
{
}    
 
char* Formatter::get_page(char *reply)
{
    chunk[0] = '\0';
 
    if(currentChunk < nbChunk)
    {
        get_chunk(currentChunk, reply);
        currentChunk++;
    }
    else
        currentChunk = 0;
    
    return chunk;
}    
 
void Formatter::get_chunk(const int c, char *reply)
{
    strcat(chunk, reply);
}
 
SimpleHTMLFormatter::SimpleHTMLFormatter():
Formatter()
{
}
 
void SimpleHTMLFormatter::get_chunk(const int c, char* reply)
{
    strcat(chunk, SIMPLE_HTML_CODE);
    
    if(reply != NULL && strlen(reply) != 0)
    {
        /*
        strcat(chunk, "RPC reply : ");
        strcat(chunk, reply);
        */
    }
        
    if(!RPCObjectManager::instance().is_empty())
    {
        strcat(chunk, "<ul>");
        for(std::list<char*>::iterator itor = RPCObjectManager::instance().begin();
            itor != RPCObjectManager::instance().end();
            ++itor)
        {
            strcat(chunk, "<li>");
            strcat(chunk, *itor);
            strcat(chunk, "</li>");
        }
        strcat(chunk, "</ul>");
    }
    
    strcat(chunk, "</body></html>");
}
 
InteractiveHTMLFormatter::InteractiveHTMLFormatter():
Formatter(3)
{
}
 
void InteractiveHTMLFormatter::get_chunk(const int c, char *reply)
{
    int alarmCreated = 0;
    
    if(c == 0)
        sprintf(chunk, INTERACTIVE_HTML_CODE_1, EthernetInterface::getIPAddress());
 
    else if(c == 1){
        if(!RPCObjectManager::instance().is_empty()){
            alarmCreated = 1;
        }
        strcat(chunk, " ");
        
        if(!alarmCreated){
            strcat(chunk, "<p><input type=\"button\" value=\"Create Alarm\" onclick=\"javascript:submitCreateForm();\"></p>");
        }else{
            strcat(chunk, "<h3>Set Your Alarm:</h3>");
            strcat(chunk, "<form>");
            
            /******* HOUR *******/
            strcat(chunk, "<select id=\"hour\">");
            strcat(chunk, "<option ");
            if(_alarm.hours == 1){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"1\">1</option>");
            strcat(chunk, "<option ");
            if(_alarm.hours == 2){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"2\">2</option>");
            strcat(chunk, "<option ");
            if(_alarm.hours == 3){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"3\">3</option>");
            strcat(chunk, "<option ");
            if(_alarm.hours == 4){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"4\">4</option>");
            strcat(chunk, "<option ");
            if(_alarm.hours == 5){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"5\">5</option>");
            strcat(chunk, "<option ");
            if(_alarm.hours == 6){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"6\">6</option>");
            strcat(chunk, "<option ");
            if(_alarm.hours == 7){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"7\">7</option>");
            strcat(chunk, "<option ");
            if(_alarm.hours == 8){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"8\">8</option>");
            strcat(chunk, "<option ");
            if(_alarm.hours == 9){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"9\">9</option>");
            strcat(chunk, "<option ");
            if(_alarm.hours == 10){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"10\">10</option>");
            strcat(chunk, "<option ");
            if(_alarm.hours == 11){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"11\">11</option>");
            strcat(chunk, "<option ");
            if(_alarm.hours == 12 || _alarm.hours == 0){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"12\">12</option>");
            strcat(chunk, "</select>");
            
            strcat(chunk, ":");
            
            /******* MINUTE *******/  
            strcat(chunk, "<select id=\"minute\">");
            strcat(chunk, "<option ");
            if(_alarm.minutes == 0){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"0\">00</option>");
            strcat(chunk, "<option ");
            if(_alarm.minutes == 1){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"1\">01</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 2){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"2\">02</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 3){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"3\">03</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 4){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"4\">04</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 5){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"5\">05</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 6){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"6\">06</option>");
            strcat(chunk, "<option ");
            if(_alarm.minutes == 7){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"7\">07</option>");
            strcat(chunk, "<option ");
            if(_alarm.minutes == 8){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"8\">08</option>");
            strcat(chunk, "<option ");
            if(_alarm.minutes == 9){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"9\">09</option>");
            
            strcat(chunk, "<option ");
            if(_alarm.minutes == 10){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"10\">10</option>");
            strcat(chunk, "<option ");
            if(_alarm.minutes == 11){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"11\">11</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 12){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"12\">12</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 13){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"13\">13</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 14){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"14\">14</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 15){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"15\">15</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 16){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"16\">16</option>");
            strcat(chunk, "<option ");
            if(_alarm.minutes == 17){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"17\">17</option>");
            strcat(chunk, "<option ");
            if(_alarm.minutes == 18){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"18\">18</option>");
            strcat(chunk, "<option ");
            if(_alarm.minutes == 19){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"19\">19</option>");
            strcat(chunk, "<option ");
            if(_alarm.minutes == 20){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"20\">20</option>");
            strcat(chunk, "<option ");
            if(_alarm.minutes == 21){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"21\">21</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 22){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"22\">22</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 23){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"23\">23</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 24){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"24\">24</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 25){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"25\">25</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 26){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"26\">26</option>");
            strcat(chunk, "<option ");
            if(_alarm.minutes == 27){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"27\">27</option>");
            strcat(chunk, "<option ");
            if(_alarm.minutes == 28){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"28\">28</option>");
            strcat(chunk, "<option ");
            if(_alarm.minutes == 29){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"29\">29</option>");
            
            strcat(chunk, "<option ");
            if(_alarm.minutes == 30){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"30\">30</option>");
            strcat(chunk, "<option ");
            if(_alarm.minutes == 31){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"31\">31</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 32){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"32\">32</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 33){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"33\">33</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 34){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"34\">34</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 35){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"35\">35</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 36){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"36\">36</option>");
            strcat(chunk, "<option ");
            if(_alarm.minutes == 37){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"37\">37</option>");
            strcat(chunk, "<option ");
            if(_alarm.minutes == 38){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"38\">38</option>");
            strcat(chunk, "<option ");
            if(_alarm.minutes == 39){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"39\">39</option>");
            strcat(chunk, "<option ");
            if(_alarm.minutes == 40){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"40\">40</option>");
            strcat(chunk, "<option ");
            if(_alarm.minutes == 41){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"41\">41</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 42){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"42\">42</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 43){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"43\">43</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 44){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"44\">44</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 45){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"45\">45</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 46){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"46\">46</option>");
            strcat(chunk, "<option ");
            if(_alarm.minutes == 47){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"47\">47</option>");
            strcat(chunk, "<option ");
            if(_alarm.minutes == 48){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"48\">48</option>");
            strcat(chunk, "<option ");
            if(_alarm.minutes == 49){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"49\">49</option>");
            strcat(chunk, "<option ");
             if(_alarm.minutes == 50){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"50\">50</option>");
            strcat(chunk, "<option ");
            if(_alarm.minutes == 51){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"51\">51</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 52){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"52\">52</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 53){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"53\">53</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 54){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"54\">54</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 55){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"55\">55</option>");
             strcat(chunk, "<option ");
            if(_alarm.minutes == 56){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"56\">56</option>");
            strcat(chunk, "<option ");
            if(_alarm.minutes == 57){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"57\">57</option>");
            strcat(chunk, "<option ");
            if(_alarm.minutes == 58){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"58\">58</option>");
            strcat(chunk, "<option ");
            if(_alarm.minutes == 59){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"59\">59</option>");
            
            strcat(chunk, "</select>");
            
            /******* AM PM *******/
            strcat(chunk, "<select id=\"ampm\">");
            strcat(chunk, "<option ");
            if(strcmp(_alarm.amPm,"AM") == 0){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"0\">AM</option>");
            
            strcat(chunk, "<option ");
            if(strcmp(_alarm.amPm,"PM") == 0){ strcat(chunk, "selected=\"selected\""); }
            strcat(chunk, "value=\"1\">PM</option>");
        
            strcat(chunk, "</select>");
            strcat(chunk, "<br><p>");
            strcat(chunk, "<input type=\"button\" value=\"Save\" onclick=\"javascript:submitAlarmPreferences();\">");
            strcat(chunk, "<input type=\"button\" value=\"Set\" onclick=\"javascript:setAlarm();\">");
            strcat(chunk, "</p><br></form>");
        }
    }
    else if(c == 2)
        strcat(chunk, INTERACTIVE_HTML_CODE_2);
}


2 comments on IoT Mbed Smart Alarm Clock:

12 Dec 2014

Cool project! You mentioned running out of memory and having things get buggy occasionally, so here's one suggestion for future improvement that jumped out at me:

getWeather() defines the buf[] array within the function, and then returns a pointer to buf, which means it's returning an address on the stack, and thus immediately marked as unused space as soon as getWeather() returns. It looks like you got lucky that important data in buf doesn't get overwritten by parseResults()'s stack frame. Additionally, because you have interrupt routines as well as multiple threads running, it's entirely possible for a thread switch to happen between getWeather() and parseResults() getting called, which could further mess up buf's stack data. Reducing variable scope can be a good thing, but you shouldn't try to use variables after they've already gone out of scope.

A better implementation would be to malloc() buf on the heap (and then free it when you're done) so it's safe to return a pointer to it, or have getWeather() directly call parseResults() and then return the results directly.

21 Jul 2016

how it will turn on lights or fans?

Please log in to post comments.