IoT Mbed Smart Alarm Clock
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
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/
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:
- 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.
- 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
- We would have liked to use a WiFly module to accest the internet instead of an Ethernet mag jack.
- 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.
- 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.
Components
Ethernet magic jack breakout
Sd card reader breakout
uLCD screen
Zero Cross Tail
PowerSSR Tail
Breakout Audio Jack
External Speakers
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:
Please log in to post comments.
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.