Arduino / Twilio Project

While staying up at all hours of the night with my new baby I began looking at my newly acquired Ethernet Arduino shield which has been sitting in the box for months now, and decided to do a weekend project to try and put it to good use.  Overall goal of the project was to utilize several new Arduino peripherals, get an understanding of the Twilio SMS API, and provide a mechanism that would assist with one of our new daily baby related tasks.

Problem to solve:

We are currently tracking the feeding cycle of our newborn which entails both the start time and length of the feeding cycle.  Pretty easy process, we just write it down on a tracking sheet which is located next to the bed.  That easy part of the process however starts to go out of the window when you are waking up at 3:15am after getting a total of one hours of sleep. Trying to remember those early morning times after the fact for cataloging later in the day can be quite a challenge.

Project Goal:

Utilizing the Arduino Ethernet, create a mechanism to track the length of the feeding period and send those results to my phone utilizing Twilio.  As the baby has an unbelievable internal clock and wakes up on almost a periodic schedule for feeding time,  create a way to send a text message to my phone after a predetermined time so that I can wakes up and catch him before he starts stirring.

Project Outcome:

A schematic of the final hardware can be seen below.  The user flow is as follows:

  • On power-up, we initialize the LCD and LAN connections
  • User is able to define the value for a countdown timer (hours + minutes)
  • Once the process is started the user is actually shown an increasing timer which signifies that a feeding is on-going
  • Pressing of an interrupt button will stop the increasing timer, send an SMS with the total feeding time to my phone via Twilio, then change over to the countdown timer which is already in progress
  • Once the countdown timer has expired a  SMS is sent to my device, letting me know that it is probably a good idea to get up as the next feeding is about to start

With this setup I am now able to go thru my phone messages (with the accurate time and lengths) and log them when in a more coherent state of mind.

 

This is the schematic for the hardware setup
This is the schematic for the hardware setup

 

New Learnings + Lessons Learned:

One great thing about this project was that I was able to incorporate so many new features which I hadn’t used previously, both on the Arduino and some server based code.  Below is the list of the areas (in general I went thru each of  these on their own and created small unit tests for each so that I could make sure they were working properly, then worked on integrating them together into one complete project), I will then expand on each one with both my lessons learned, and some links on where I was able to get the best information online.

  • Ethernet Library
  • Twilio SMS Service
  • 2×16 LCD
  • FSR (Force Sensitive Resistor)
  • Software Interrupt
  • Parsing of GET requests via .php

Arduino Ethernet Library:

Connecting to the internet via the Ethernet library was really quite straight forward.  The examples available on the Arduino site were able to get me up and running without major difficulty.

Lessons Learned:  For some reason on my setup if I had the subnet and gateway defined, my script/Arduino was unable to connect to the internet.  Commenting out those fields seemed to solve the issue for me.

I tried for the longest time figure out what the issue was, and never found the root cause.  When I tried the absolute simplest example I could find from the Arduino site which didn’t seem to have the gateway/subnet defined and it worked properly, I just made the change and moved on to other more interesting problems to solve.

Links:

http://arduino.cc/en/Tutorial/WebClient  — Basic setup;  Good way to get your board online and then go from there.

 

Twilio SMS:

Before I started doing any coding within Arduino, I began by reviewing the Twilio SMS API documentation.  Overall the documentation was great, and after setting up my trial account I was able to send SMS’s via a CURL message to my phone (process time overall was about 5 minutes).  Given how easy it was to accomplish this with a POST message, I felt this would be the best path forward to try to replicate and handle everything from the Arduino device.

It actually took me several different routes and several dead ends to finally settle on a solution (the final solution being the easiest, and would have probably taken me less than 15 minutes total to setup if I had gone that route first)

Process / Lessons Learned

  • Start by deconstructing the CURL command, so that you can piece together the individual attributes into your own POST message.  For this I utilized a Firefox plug-in called ‘POSTER’, and went thru the W3C specification for Header Field definitions.  With some trial & error I was able to get the right message configuration, POST to Twilio with the plug-in and receive the SMS message.    Lessons Learned:  One major lessons learned here was that POSTER is nice enough to allow you to place your username / password within the form.  When creating your own POST message realize that the ‘Authorization’ header is Base64 encoded.
  • Now that I had the PUSH message I wanted to set, I needed to find a way to configure this message from the Arduino.  For this there seems to be a defacto example which everyone references where you can POST data to a Google Spreadsheet.  Going thru this example provided a good feeling on how to configure the messages, so I moved forward to implementing my own POST to the Twilio service.  This process wasn’t going well, and I was unable to obtain a connection to the Twilio service.  LL: If you are using the code from the Google spreadsheet example as a template the printing of log info to the Serial Monitor wasn’t working properly as it was outside of the loop.
  • Lots of logging and research online later I uncovered two major road blocks for this path forward.  LL:  The Arduino isn’t able to do HTTPS connections.  Seems the reasoning for this is that there isn’t enough processing power to handle the certificate exchange.  LL:  The Twilio service is unable to handle HTTP POST requests to it’s service.   Lessons Learned:  Not sure if it is an error or a feature, but when you do a HTTP POST to Twilio via the ‘POSTER’ app, the service will respond back with a log of your previous text messages.  (I didn’t check in Wireshark, but maybe after a re-direct to HTTPS some of the msg parameters are being modified?) Feature Request:  Twilio really should provide a mechanism for standard HTTP POST’s to their service.  Maybe put a very aggressive rate limiter on the feature, provide a separate unique token, anything that would allow this to happen as it would make things much more self contained from an Arduino / connected device standpoint.  Feature Request:  On the website it says HTTP POST all over the place, these maybe better served to be called HTTPS POST (doesn’t roll off the tongue as well)
  • Since the POST command wasn’t going to be an option any longer, I looked at the examples on the Twilio developer site and used the .php example to create a basic script to send the message to the device.  In the final case I just created two separate scripts, one which just sends a standard message (time to get up), and one which sends a message with a time parameter.  This is accomplished by appending the details of the timer within the GET message and then sending this to the script on my server.  Overall a very easy process, both with the .php scripts as well as the GET message within Arduino (I had already done tons of research on the message composition for the POST message)  LL:  Only slight issue I encountered was wether I should have the brackets within the Token definition or not.  That is most likely not an issue with their documentation but due to my lack of experience with .php
  • Overall, even though it took much longer than I expected to accomplish this part of the project, I learned a huge amount about HTTP messaging, the Twilio API, and basic .php scripting.

Links:

http://curl.haxx.se/docs/manpage.html - Used when deconstructing the CURL messaging

http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html – Specification for HTTP headers which are used within the POST messages

http://www.base64encode.org/ – Used for getting my Base64 encoding

https://addons.mozilla.org/en-us/firefox/addon/poster/ – Add-on for Firefox which allows for HTTP POST requests.

http://www.twilio.com/docs/api/rest/sending-sms – Twilio docs on sending a SMS message utilizing their service

http://www.open-electronics.org/how-send-data-from-arduino-to-google-docs-spreadsheet/ – Walk thru on sending data via Arduino to a Google Spreadsheet / Good overview of sending POST data

 

2×16 LCD

I had been looking for an excuse to use my LCD screen, so was excited to put it to good use.  The overview’s within the Arduino site give pretty good guidance on how to use the lcd library.

Lessons Learned:

  • On my LCD setup, I had to use different pins then what were outlined within the examples.  Just make sure you are accounting for that within your setup() section of code
  • Make sure you look out for edge cases.  Minutes going from 59 -> 0, Hours going from 9-10, etc.  Make sure there is room for any additional digits, and that you are clearing any unused digits from the display so you don’t have artifacts
  • Making some functions to handle some common display use cases can make your code much more manageable

Links:

http://arduino.cc/en/Tutorial/LiquidCrystal – Good overview on how to use the display.  After this, it is just a matter of playing with different combinations and getting comfortable.  Don’t forget to make separate functions for the common layouts, that was a big time saver for me.

 

FSR – Force Sensitive Resistor:

I didn’t really have to use this for the project, I could have just as easily used a push button for the same mechanism, but it was a good way to understand how the part works, implement it, and then have that available for future project where it might make more sense.  No major issues or lessons learned to share.  Just follow the setup as shown in the example, and that should get you on your way with your own project.

Links:

http://learn.adafruit.com/force-sensitive-resistor-fsr/overview – General overview with code samples for FSR

 

Software Interrupt:

When you up the delay for the timer code to one minute in it is difficult to actually register any button presses to stop the timer as the delay() function prohibits the digitalread() from being triggered during the delay.  One way around that was to implement a Interrupt, so that the button press can be registered and actions can then be taken.  (My code below is using a short delay for demo purposes.  When the delay is set for one minute, 60,000 milliseconds, the action although registered will take the remainder of that delay function to be shown.  Overall the reference within the Arduino site was enough to get going and implement this properly.

Links:

http://arduino.cc/en/Reference/AttachInterrupt – Overview on implementation of attachInterupt()

 

Parsing of GET requests via .php

After completing the exercises with POST messages and the general Twilio .php scripts, getting variables to be sent along with the GET request to the .php script was pretty straight forward.  Major item from the Arduino side is to segment the GET request into several segments, just paying special attention to if you are using clint.print() or client.println().  From the server side, adding a few lines to the existing Twilio .php script allowed it to capture the variables and add it to the message field.

Links:

http://www.lornajane.net/posts/2008/accessing-incoming-put-data-from-php – Site which explains clearly how to parse content from a GET request via PHP

 

Conclusion:

Overall, a great way to spend some sleepless nights.  By using a large number of different components and services, I was able to obtain additional modules that will make my future projects that much easier and spectacular.

Pretty impressed with how easy the Twilio API service was to use, at least after I figured out the limitations regarding the POST messages.

What would I do to improve upon this project / next steps?

  • Clean up the code a little bit, and possible add Cases() instead of the multiple if() statements
  • Add an additional button / interrupt so that you can reset the countdown timer  (I had some code in there that worked with the short delay, but I didn’t want to rewire the board to implement a second interrupt button that would work with the minute long delay)
  • Redo the messaging on the LCD screen.  It can be more relavent, maybe highlight which buttons to press, etc.
  • If I am sending the info to a PHP script anyway, would be interesting to find a way to send this info to my Evernote account via their email alias (take even one more step out of the process)

 

// include the library code:
#include 
#include 
#include 

//Setup the Ethernet part of the code

byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x72, 0x2D };  //MAC Address of my Ethernet Arduino
byte ip[] = {192, 168, 1, 130};  //The Arduino device IP address
// byte subnet[] = {255,255,255,0};  //Subnet of my home router  --- For some reason I couldn't get a connection with this part enabled.  Took quite a bit of head scratching, it works so don't want to think about it now
// byte gateway[] = {192,168,1,1}; // IP address of the router   --- Same, enabled = connection
byte server[] = {173,201,239,128}; // Spikybear IP
EthernetClient client; 

// initialize the library for the LCD with the numbers of the interface pins
LiquidCrystal lcd(7, 8, A5, 3, 5, 6);  //Moved Pin2 to A5 so that I can use Pin 2 for a hardware interrupt at a later time.

// Defining my variables

long delay_value = 1000;            //This is the delay value for the timer.  I was using a low value to make it go fast and test;  Should be set for minutes so 1000*60

int fsrPin = A0;     // the FSR and 10K pulldown are connected to a0
int button_min = A1;  // This is the button to add minutes
int button_hour = A2; // This is the button to add hours + later functionality
int button_min_state = 0;
int button_hour_state = 0;

int fsrReading;     // the analog reading from the FSR resistor divider

int new_loop=1;   // This is used for debugging to see when I start a brand new loop (ready for input)
int state = 2;    // Using the state value to get out of the loop and handle reset requests   -- State 2 == Normal   State 3 == Interrupt
int led = 9;      // On my Ethernet Arduino this is set for using the on-board LED
int hour = 3;     // Currently this is set to 3 hours as default timing, need to add two buttons so I can change Mins and Hours 
int min_tot_up = 0;  // This is the variable that will count up during the first phase...
int min_tot = 180; // Currently this is set to 3 hours as default timing, need to add two buttons so I can change Mins and Hours   
int min1=59;  // This is the remainder from the division and thus displays the minutes in the countdown timer
int hour_up = 0;  //This is the hour value after doing the math for the count up section
int min_up = 0;   //This is the minute value after doing the math for the count up section
int j = 1;        //Going to use this within the if loop for the Count-up function

volatile int kick_button = LOW;     // Setting up parameter for the Interrupt button

void setup() {
  lcd.begin(16, 2);                                       // set up the LCD's number of columns and rows: 
  lcd.print("Hello,Wrld12+LAN");                          // Print a message to the LCD to start us off.
  lcd.setCursor(0,1);
  lcd.print("Timed Twilio SMS");

  //Setting the Pins and the serial monitor config

  pinMode(led, OUTPUT);                                 
  pinMode(button_min, INPUT);
  pinMode(button_hour, INPUT);
  Serial.begin(57600);

  //Setting up the Interrupt  --  With a long delay will need this to get the variable to change
  attachInterrupt(0, kickout, CHANGE);
  //Setting up the Ethernet
  Ethernet.begin(mac, ip);

}

void loop() {
  delay(500);                                                  // Currently need this here, as was getting some errors on button presses

 if(new_loop == 1){
   Serial.println("This is a new Loop !!!!!!");               // This is used for debugging to see when I start a brand new loop (ready for input)
   new_loop=0;
 }

 fsrReading = analogRead(fsrPin);                            // Reading the pressure sensitive button
 button_min_state = digitalRead(button_min);                 // Reading the button for minutes
 button_hour_state = digitalRead(button_hour);               // Reading the button for hours

 if(button_min_state == HIGH){
   Serial.print("Total minutes from minute button loop: ");   
   Serial.println(min_tot);
  min_tot++;
  lcd_hour_min();                                                // Pressing button to increase the timer by one minute
 }
                                                                // Presing the button to increase the timer by one hour;  
 if(button_hour_state == HIGH){                                 // Also have mechanism to bring it back to 0 hours after 11; Max timer value will thus be 11:59
   if(min_tot >= 660){
     min_tot = min_tot - 720;
   }
   Serial.print("Total minutes from hour button loop: ");   
   Serial.println(min_tot);   
   min_tot = min_tot + 60;
   lcd_hour_min();
 }                                                              

 if(fsrReading > 200){                                                //This is going to start the Count-up / Count Down
  Serial.println("Total Number of Minutes at beginning of Loop ");    // Just verifing all the parameters are correct within the serial monitor
  Serial.println(min_tot);
  Serial.println();
  Serial.print("State Value at beginning of Loop ");
  Serial.println(state);
  Serial.println();

  while (min_tot>0 && state == 2) {    //While there are still minutes to print, and State = 2 (Normal)

      if (j==1){
        lcd_hour_min_count_up();
        delay(delay_value);
        button_hour_state = digitalRead(button_hour);                 //Reading this button, as will use this to stop the up timer
        min_tot--;
        min_tot_up++;
        Serial.print("Value of kick_button  ");
        Serial.println(kick_button);
        // if(button_hour_state == HIGH)                              //Trying the interrupt; This will move us to the countdown section, sending SMS via Twilio

        if(kick_button == HIGH)
        {
          j = 0; 
          kick_button = LOW;
          if (client.connect(server, 80)) 
          {
          Serial.println("connected"); 
          client.print("GET /yourpath.php?timertime=");
          client.print(min_tot_up);
          client.println(" HTTP/1.0");
          client.println("HOST: www.spikybear.com");
          client.println();

          }
          while (client.available()) 
          {
          char c = client.read();
          Serial.print("Response: "); //for debugging
          Serial.println(c); //for debugging
          } 

          client.stop();
          Serial.println("Should have been a successful send...."); 
          }

      }
      else{
      lcd_hour_min();
      delay(delay_value);                                             
      min_tot--;

/*  Need to implement another interrupt here to handle the reset case.  Reset case is when the user wants to stop the countdown timer without sending an SMS.

        if (kick_button2 == HIGH);  {
        min_tot=0;        //Changing min_tot to zero will stop the While loop 
        j = 0;
        state=3;                                                      // Change the state so that we get a different result on screen
        Serial.print("Total time in minutes ");
        Serial.println(min_tot);
        Serial.print("State Value ");
        Serial.println(state);
        Serial.println();
        }

*/        
      }

                                                            //This will allow us to move down by a minute at a time
                                                                  //Closing bracket for the first else statement (right after the count_up code)
}                                                                      //Closing bracket for the While Loop
 // This while loop is going to end with either a State 2 or State 3;  min_tot will alsways be '0'

 /*  For this part (Timer expires normally) I am showing the LED, changing the LCD, resetting the min_tot for the next round, resetting new_loop.  
Sending GET msg to send Twilio SMS */

 if (state == 2){
 Serial.print("This is the total time in minutes within lower if statemet ");      
 Serial.println(min_tot);
 digitalWrite(led,HIGH);
 lcd.setCursor(0,0);
 lcd.print("Twilio SMS Sent");
 lcd.setCursor(0,1);
 lcd.print("Timer Expired!!!");  

 //This is where the code would go to send the message to Twilio

   if (client.connect(server, 80)) {
    Serial.println("connected");
    delay(1000); 
    client.println("GET /yourpath.php HTTP/1.0");
    client.println("HOST: www.spikybear.com");
    client.println();

  }
          while (client.available()) {
          char c = client.read();
          Serial.print("Response: "); //for debugging
          Serial.println(c); //for debugging
        } 

  client.stop();
  Serial.println("Should have been a successful send...."); 

 delay(10000);
 digitalWrite(led,LOW);
 min_tot=180;
 new_loop=1;
 j = 1;
 min_tot_up = 0;
 }  

 else {
      min_tot=180;
      hour=min_tot/60;
      min1=min_tot%60;
      lcd_hour_min();
      lcd.setCursor(0,0);
      lcd.print("Rst/press start");
      state = 2;
      j = 1;
      new_loop=1;
      min_tot_up = 0;

 }

 }

 }
 void lcd_hour_min() {                                                 // Trying to create a function for the printing of hours/mins to the LCD Display
      hour=min_tot/60;                                               //So simple when you think about it.  Total mins / 60 = # hours
      min1=min_tot%60;                                               //Remainder value is your number of minutes
      Serial.print("Total time in minutes ");                        //Serial Monitor stuff
      Serial.println(min_tot);
      Serial.print("Number of Hours ");
      Serial.println(hour);
      Serial.print("Number of Minutes ");
      Serial.println(min1);
      Serial.print("State Value ");
      Serial.println(state);
      Serial.println();
      lcd.setCursor(0, 0);                                            //Print all the fun stuff to the display
      lcd.print("Time to Twilio!!");
      lcd.setCursor(0, 1);
      lcd.print("Hours");
      lcd.setCursor(6,1);
      lcd.print(hour);
      if(hour<10){                                                    //Making sure that we don't have artifacts after looping back to single digits
        lcd.setCursor(7,1);
        lcd.print(" ");
      }
      lcd.setCursor(8,1);
      lcd.print(" ");
      lcd.setCursor(9,1);
      lcd.print("Mins ");
      lcd.setCursor(14, 1);
      lcd.print(min1);
      lcd.print(" ");

 }

void lcd_hour_min_count_up() {                                                 // Trying to create a function for the printing of hours/mins for the Count up feature to the LCD Display
      hour_up=min_tot_up/60;                                               //So simple when you think about it.  Total mins / 60 = # hours
      min_up=min_tot_up%60;                                               //Remainder value is your number of minutes
      Serial.print("Total time in minutes for Count Up ");                        //Serial Monitor stuff
      Serial.println(min_tot_up);
      Serial.print("Number of Hours for Count Up ");
      Serial.println(hour_up);
      Serial.print("Number of Minutes for Count Up ");
      Serial.println(min_up);
      Serial.print("State Value ");
      Serial.println(state);
      Serial.println();
      lcd.setCursor(0, 0);                                            //Print all the fun stuff to the display
      lcd.print("Count Up! Done??");
      lcd.setCursor(0, 1);
      lcd.print("Hours");
      lcd.setCursor(6,1);
      lcd.print(hour_up);
      if(hour_up<10){
        lcd.setCursor(7,1);
        lcd.print(" ");
      }
      lcd.setCursor(8,1);
      lcd.print(" ");
      lcd.setCursor(9,1);
      lcd.print("Mins ");
      lcd.setCursor(14, 1);
      lcd.print(min_up);
      lcd.print(" ");

 }

 void kickout()
 {
   kick_button = HIGH;
 }
<?php
// Download/Install the PHP helper library from twilio.com/docs/libraries.
// This line loads the library
require('Twilio/Services/Twilio.php');

// Your Account Sid and Auth Token from twilio.com/user/account
$sid = "Your Account";
$token = "Your Token";
$client = new Services_Twilio($sid, $token);

$message = $client->account->sms_messages->create("+From#", "+To#", " Time to get up and get the baby ready ", array());
echo $message->sid;
<?php
// Download/Install the PHP helper library from twilio.com/docs/libraries.
// This line loads the library
require('Twilio/Services/Twilio.php');

// Your Account Sid and Auth Token from twilio.com/user/account
$sid = "Your sid";
$token = "Your Token";
$client = new Services_Twilio($sid, $token);

if($_SERVER['REQUEST_METHOD'] == 'GET') {

$message = $client->account->sms_messages->create("+From#", "+To#", $_GET['timertime']." Minutes Total for the Feeding", array());
echo $message->sid;
echo "<br>this is a Get request<br>";
echo $_GET['timertime']." amount of time for timer";

}

One thought on “Arduino / Twilio Project”

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>