Learning   Examples | Foundations | Hacking | Links

Examples > GSM library

GSM Xively Client

This example shows you how to answer a HTTP request using a GSM shield attached to an Arduino. Specifically, it connects to xively.com, a free datalogging site. The example requires that you set up a xively.com account, as well as a xively feed (for more information on setting up an input feed, please click here). Your GSM shield will then connect to that feed and upload sensor data.

To use a data connection with the GSM shield, you'll need your provider's Access Point Name (APN), login, and password. To obtain this information, contact the network provider for the most up to date information. This page has some information about various carrier settings, but it may not be current.

Hardware Required

  • Arduino board
  • Arduino + Telefonica GSM/GPRS Shield
  • SIM card with a data connection
  • Analog sensor attached to A0

Software Required

Circuit

image of the Arduino GSM Shield on top of an Arduino Uno

First, import the GSM library

#include <GSM.h>

Declare the various settings for your Xively account; your API key, feed ID, and project name (the user agent).

#define APIKEY         "YOUR API KEY GOES HERE"  
#define FEEDID         00000    
#define USERAGENT      "My Project"

SIM cards may have a PIN number that enables their functionality. Define the PIN for your SIM. If your SIM has no PIN, you can leave it blank :

#define PINNUMBER ""

Define a number of constants that contain information about the GPRS network you're going to connect to. You'll need the Access Point Name (APN), login, and password. To obtain this information, contact your network provider for the most up to date information. This page has some information about various carrier settings, but it may not be current.

#define GPRS_APN       "GPRS_APN"
#define GPRS_LOGIN     "login"
#define GPRS_PASSWORD  "password"

Initialize instances of the classes you're going to use. You're going to need the GSM, GPRS, GSMServer, and GSMClient classes.

GSMClient client;
GPRS gprs;
GSM gsmAccess;

Create some variables to store information you're going to need in the sketch; a char array to hold the URL, and some variables for setting timing intervals.

char server[] = "api.xively.com";

unsigned long lastConnectionTime = 0;
boolean lastConnected = false;
const unsigned long postingInterval = 10*1000;

In setup, open a serial connection to the computer.

void setup(){
  Serial.begin(9600);

Create a local variable to track the connection status. You'll use this to keep the sketch from starting until the SIM is connected to the network :

boolean notConnected = true;

Connect to the network by calling gsmAccess.begin(). It takes the SIM card's PIN as an argument. You'll also connect to the GPRS network using gprs.attachGPRS(). This requires the APN, login, and password you declared earlier. By placing this inside a while() loop, you can continually check the status of the connection and wait for them to both become true before proceeding.

When the modem does connect and has attached itself to the GPRS network, gsmAccess() will return GSM_READY. Use this as a flag to set the notConnected variable to true or false. Once connected, you can close setup.

while(notConnected)
  {
    if(gsmAccess.begin(PINNUMBER)==GSM_READY)
        (gprs.attachGPRS(GPRS_APN, GPRS_LOGIN, GPRS_PASSWORD)==GPRS_READY))
      notConnected = false;
    else
    {
      Serial.println("Not connected");
      delay(1000);
    }
  }
}

You're going to use some custom functions in this sketch. The first will make a HTTP connection to the server and send any data. Declare a function named sendData() that accepts an argument of type int

void sendData(int thisData)
{

Check to see if there is a successful connection to the server

if (client.connect(server, 80))
  {
    Serial.println("connecting...");

When connected, send a HTTP PUT request with the information about your feed

client.print("PUT /v2/feeds/");
    client.print(FEEDID);
    client.println(".csv HTTP/1.1");
    client.print("Host: api.xively.com\n");
    client.print("X-ApiKey: ");
    client.println(APIKEY);
    client.print("User-Agent: ");
    client.println(USERAGENT);
    client.print("Content-Length: ");

You'll need to calculate the length of the data you're sending. The length will be 8 bytes for the term "sensor1," plus the number of digits of the data. You'll create a new function named getLength() in a moment to handle this information. Once calculated, send the length to the server, and the last pieces of the PUT.

Last, send the data to the server.

int thisLength = 8 + getLength(thisData);
    client.println(thisLength);

    client.print("Content-Type: text/csv\n");
    client.println("Connection: close");
    client.println();

    client.print("sensor1,");
    client.println(thisData);
 }

If the connection attempt was not successful, send a status message to the serial monitor, and disconnect from the server.

else
  {
    Serial.println("connection failed");
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
  }

Update the time that the last connection, or attempt, happened before closing the function.

lastConnectionTime = millis();
}

Create another function, named getLength(), for determining the length of the data being sent in bytes.

int getLength(int someValue)
{

Create a variable named digits to hold the number of bytes. You know that there will always be at least one digit being sent.

To find the total number of digits to send, continually divide the value by ten, adding one to the digit count each time you divide, until you reach 0.

int digits = 1;

  int dividend = someValue /10;
  while (dividend > 0)
  {
    dividend = dividend /10;
    digits++;
  }

Return the number of digits and close the function.

return digits;
}

Inside loop, read the value from the analog sensor and store it in a local variable

void loop(){
  int sensorReading = analogRead(A0);

If there are bytes available, read them and send them to the serial port.

if (client.available())
  {
     char c = client.read();
     Serial.print(c);
  }

Check for an active network connection. If there isn't one, but there was one last time through loop(), then stop the client:

if (!client.connected() && lastConnected)
  {
    client.stop();
  }

If there is no connection, and ten seconds have passed since the last connection, or connection attempt, then connect again and send data

if(!client.connected() && ((millis() - lastConnectionTime) > postingInterval))
  {
  sendData(sensorReading);
  }

Store the state of the connection for next time through loop() and close it up.

lastConnected = client.connected();
}

Once your code is uploaded, open the serial monitor for debugging, and check your xively.com feed to see updates.

/*
 GSM Xively client
 
 This sketch connects an analog sensor to Xively (http://www.xively.com)
 using a Telefonica GSM/GPRS shield.

 This example has been updated to use version 2.0 of the Xively.com API.
 To make it work, create a feed with a datastream, and give it the ID
 sensor1. Or change the code below to match your feed.
 
 Circuit:
 * Analog sensor attached to analog in 0
 * GSM shield attached to an Arduino
 * SIM card with a data plan
 
 created 4 March 2012
 by Tom Igoe
 and adapted for GSM shield by David Del Peral
 
 This code is in the public domain.
 
 http://arduino.cc/en/Tutorial/GSMExamplesXivelyClient
 
 */


// libraries
#include <GSM.h>

// Xively Client data
#define APIKEY         "YOUR API KEY GOES HERE"  // replace your xively api key here
#define FEEDID         00000                     // replace your feed ID
#define USERAGENT      "My Project"              // user agent is the project name

// PIN Number
#define PINNUMBER ""

// APN data
#define GPRS_APN       "GPRS_APN"  // replace your GPRS APN
#define GPRS_LOGIN     "login"     // replace with your GPRS login
#define GPRS_PASSWORD  "password"  // replace with your GPRS password

// initialize the library instance:
GSMClient client;
GPRS gprs;
GSM gsmAccess;

// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:
// IPAddress server(216,52,233,121);    // numeric IP for api.xively.com
char server[] = "api.xively.com";      // name address for xively API

unsigned long lastConnectionTime = 0;         // last time you connected to the server, in milliseconds
boolean lastConnected = false;                  // state of the connection last time through the main loop
const unsigned long postingInterval = 10*1000;  //delay between updates to Xively.com

void setup()
{
  // initialize serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
 
  // connection state
  boolean notConnected = true;
 
  // After starting the modem with GSM.begin()
  // attach the shield to the GPRS network with the APN, login and password
  while(notConnected)
  {
    if((gsmAccess.begin(PINNUMBER)==GSM_READY) &
        (gprs.attachGPRS(GPRS_APN, GPRS_LOGIN, GPRS_PASSWORD)==GPRS_READY))
      notConnected = false;
    else
    {
      Serial.println("Not connected");
      delay(1000);
    }
  }
}

void loop()
{  
  // read the analog sensor:
  int sensorReading = analogRead(A0);  

  // if there's incoming data from the net connection.
  // send it out the serial port.  This is for debugging
  // purposes only:
  if (client.available())
  {
     char c = client.read();
     Serial.print(c);
  }

  // if there's no net connection, but there was one last time
  // through the loop, then stop the client:
  if (!client.connected() && lastConnected)
  {
    client.stop();
  }
 
  // if you're not connected, and ten seconds have passed since
  // your last connection, then connect again and send data:
  if(!client.connected() && ((millis() - lastConnectionTime) > postingInterval))
  {
  sendData(sensorReading);
  }
 
  // store the state of the connection for next time through
  // the loop:
  lastConnected = client.connected();
}

/*
  This method makes a HTTP connection to the server.
*/

void sendData(int thisData)
{
  // if there's a successful connection:
  if (client.connect(server, 80))
  {
    Serial.println("connecting...");
   
    // send the HTTP PUT request:
    client.print("PUT /v2/feeds/");
    client.print(FEEDID);
    client.println(".csv HTTP/1.1");
    client.println("Host: api.xively.com");
    client.print("X-ApiKey: ");
    client.println(APIKEY);
    client.print("User-Agent: ");
    client.println(USERAGENT);
    client.print("Content-Length: ");

    // calculate the length of the sensor reading in bytes:
    // 8 bytes for "sensor1," + number of digits of the data:
    int thisLength = 8 + getLength(thisData);
    client.println(thisLength);

    // last pieces of the HTTP PUT request:
    client.println("Content-Type: text/csv");
    client.println("Connection: close");
    client.println();
   
    // here's the actual content of the PUT request:
    client.print("sensor1,");
    client.println(thisData);
  }
  else
  {
    // if you couldn't make a connection:
    Serial.println("connection failed");
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
  }
  // note the time that the connection was made or attempted
  lastConnectionTime = millis();
}

/*
  This method calculates the number of digits in the
  sensor reading.  Since each digit of the ASCII decimal
  representation is a byte, the number of digits equals
  the number of bytes.
*/

int getLength(int someValue)
{
  // there's at least one byte:
  int digits = 1;
 
  // continually divide the value by ten,
  // adding one to the digit count for each
  // time you divide, until you're at 0:
  int dividend = someValue /10;
  while (dividend > 0)
  {
    dividend = dividend /10;
    digits++;
  }
 
  // return the number of digits:
  return digits;
}

See Also:

Share