Using AT&T's M2X With the CC3000

This Tutorial is Retired!

This tutorial covers concepts or technologies that are no longer current. It's still here for you to read and enjoy, but may not be as useful as our newest tutorials.

Pages
Contributors: Shawn Hymel
Favorited Favorite 5

Controlling a Device From M2X

Sending information to M2X is great for logging sensor data, but we can also control hardware devices from M2X. This technique requires a bit of trickery, as there is no way to push data to the Arduino (without turning the Arduino into a web server). So, we have the Arduino poll an M2X stream every few seconds looking for data. If it sees a "0" it will turn off the LED. If it sees any other value, it will turn the LED on. Any time the Arduino reads data from the stream, it immediately deletes all data on the stream.

Circuit for controlling an LED from M2X

Required Materials

The Circuit

Connect the CC3000 shield to the Arduino, and connect the resistor and LED as shown.

Fritzing of the CC3000 with LED

Make M2X Stream

Rather than use our "temperature" stream, we are going to make another stream in the same Blueprint. We will poll this stream from the Arduino, read values, and delete entries as we read them.

Log in to your AT&T M2X account.

Click on your Blueprint (e.g. "CC3000 Test").

Scroll down, and click on "Add Steam." Name the stream something memorable (we'll call ours "control"). Pick any Unit and Symbol (it really does not matter. "Barn" seemed like a silly unit, so we used that).

Add a control stream to your Blueprint

Click "Add Stream." Don't add any values! We will add some data later.

Blank control data stream

Adjust Serial Buffer

Sadly, the poor Arduino UNO (i.e. ATmega328P) simply does not have enough RAM to control the CC3000 and process the incoming M2X data. To free up some space in the RAM, we are going to reduce the size of the Serial buffer. Don't forget to change it back for your other projects!

Navigate to \\hardware\arduino\cores\arduino and open up HardwareSerial.cpp with your favorite text editor.

Note: If you are using a different Arduino with more RAM (e.g. the Arduino Mega), then you don't need to perform this step.

HardwareSerial.cpp location

Scroll down and change SERIAL_BUFFER_SIZE from 64 to 32.

HardwareSerial change serial buffer size

Example Code

Open up the Arduino IDE and paste in the following code:

language:c
/****************************************************************
M2X_CC3000_LED.ino
Control an LED with AT&T's M2X
Shawn Hymel @ SparkFun Electronics
August 19, 2014

Manually connects to a WiFi network and performs a GET to the
provided M2X stream. It reads the last data point available
and deletes all data points. This acts as a "producer-consumer"
model.

IMPORTANT: This WILL cause an Uno to run out of RAM. You need to
change SERIAL_BUFFER_SIZE from 64 to 32 in HardwareSerial.cpp,
which can be found in:
C:\Program Files (x86)\Arduino\hardware\arduino\cores\arduino

Change AP_SSID, AP_PASSWORD, AP_SECURITY, FEED_ID, STREAM_NAME,
and M2X_KEY to match your WiFi and M2X parameters.

The security mode is defined by one of the following:
WLAN_SEC_UNSEC, WLAN_SEC_WEP, WLAN_SEC_WPA, WLAN_SEC_WPA2

Resources:
Include SPI.h, SFE_CC3000.h, SFE_CC3000_Client.h, jsonlite.h,
M2XStreamClient.h

Development environment specifics:
Written in Arduino 1.0.5
Tested with Arduino UNO R3

This code is beerware; if you see me (or any other SparkFun 
employee) at the local, and you've found our code helpful, please
buy us a round!

Distributed as-is; no warranty is given.
****************************************************************/

#include <jsonlite.h>
#include <SPI.h>
#include <SFE_CC3000.h>
#include <SFE_CC3000_Client.h>
#include <M2XStreamClient.h>

// Parameters
#define POLL_DELAY_MS   1000 // Poll M2X stream every 1 second

// Pins
#define CC3000_INT      2    // Needs to be an interrupt pin (D2/D3)
#define CC3000_EN       7    // Can be any digital pin
#define CC3000_CS       10   // Preferred is pin 10 on Uno
#define LED_PIN         9    // LED (we can't use pin 13!)

// Connection info data lengths
#define IP_ADDR_LEN     4    // Length of IP address in bytes
#define TIME_LEN        25   // Length of timestamp string

// WiFi Constants
#define AP_SSID         "<SSID>"      // SSID of network
#define AP_PASSWORD     "<PASSWORD>"  // Password of network
#define AP_SECURITY     WLAN_SEC_WPA2 // Security of network
#define TIMEOUT         30000         // Milliseconds

// M2X Constants
#define FEED_ID         "<FFED ID>"
#define STREAM_NAME     "<STREAM NAME>"
#define M2X_KEY         "<M2X MASTER KEY>"
#define FROM_TIME       "1970-01-01T00:00:00.000Z"

// Global Variables
SFE_CC3000 wifi = SFE_CC3000(CC3000_INT, CC3000_EN, CC3000_CS);
SFE_CC3000_Client client = SFE_CC3000_Client(wifi);
M2XStreamClient m2x_client(&client, M2X_KEY);
uint8_t g_new;
int g_response;
int g_index;
char g_time[TIME_LEN];
uint8_t led_state;

// M2X fetch callback. This is called for each entry found.
void on_data_point_found( const char* at, \
                          const char* value, \
                          int index, \
                          void* context) {

  // Index 0 is the most recent. Save the timestamp so we can
  // delete all the entries up to that point. If the value is
  // exactly 0, turn off the LED. Otherwise, turn it on.
  if ( index == 0 ) {
    g_new = 1;
    strncpy(g_time, at, TIME_LEN);
    if ( strcmp(value, "0") == 0 ) {
      led_state = 0;
    } else {
      led_state = 1;
    }
  }
}

// Setup. Configure WiFi and M2X connections.
void setup() {

  g_response = 0;
  g_new = 0;

  // Initialize LED
  led_state = 0;
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);

  // Initialize UART for debugging
  Serial.begin(9600);
  Serial.println();
  Serial.println(F("SparkFun CC3000 - M2X LED"));

  // Initialize CC3000 (configure SPI communications)
  if ( wifi.init() ) {
    Serial.println(F("CC3000 initialization complete"));
  } else {
    Serial.println(F("Something went wrong during CC3000 init!"));
  }

  // Connect using DHCP
  Serial.print(F("Connecting to SSID: "));
  Serial.println(AP_SSID);
  if(wifi.connect(AP_SSID, AP_SECURITY, AP_PASSWORD, TIMEOUT)) {
    Serial.println(F("Connected!"));
  } else {
    Serial.println(F("Error: Could not connect to AP"));
  }
}

// Main loop. Poll M2X stream, update LED, and delete entries.
void loop() {

  // Fetch values from M2X stream
  g_response = m2x_client.fetchValues(FEED_ID, \
                                      STREAM_NAME, \
                                      on_data_point_found, \
                                      NULL);

  // If we fail to receive a reponse, stop running
  Serial.print(F("Fetch response: "));
  Serial.println(g_response);
  if ( g_response == -1 ) {
    while(1);
  }

  // Update LED and delete entries if there was a new value
  if ( g_new ) {

    // Update LED state
    digitalWrite(LED_PIN, led_state);
    Serial.print(F("LED: "));
    Serial.println(led_state);

    // Fetch drops last 4 chars. Add some so we can delete entries.
    strncpy(g_time + 20, "999Z", 5);

    // Delete all entries
    g_response = m2x_client.deleteValues( FEED_ID, \
                                          STREAM_NAME, \
                                          FROM_TIME, \
                                          g_time);

    // If we fail to receive a reponse, stop running
    Serial.print(F("Delete response: "));
    Serial.println(g_response);
    if ( g_response == -1 ) {
      while(1);
    }

    // Reset new flag
    g_new = 0;
  }

  // Wait to poll stream again
  delay(POLL_DELAY_MS);
}

Don't forget to update the WiFi and M2X stream parameters:

  • \<SSID> should be changed to your WiFi network name (SSID)
  • \<PASSWORD> is your WiFi password
  • Make sure AP_SECURITY matches your WiFi security type (e.g. WPA, WEP)
  • Change \ and \ to match your M2X information (see the Post Temperature Data example)
  • Change \ to your new stream name (e.g. "control")

Run Your Program

Upload your program to the Arduino. Open up a Serial Monitor, and you should see the Arduino connect to WiFi and start to poll your M2X stream.

Arduino and CC3000 connected to M2X control stream

While your Arduino is polling the M2X stream, go back to your M2X Blueprint in your browser and expand our new data stream.

Expanded data stream

Click the "Edit" button and enter a value (anything other than "0") into the "Log a Value" field.

M2X log a value

Click "Save Stream." In a few seconds, your Arduino should see that a value was logged to the stream and turn on the LED as a result.

LED on

To turn off the LED, click on "Edit" again for your data stream. This time, set "Log a Value" to 0 and click "Save Stream." Your LED should turn off within a few seconds.

LED off

So What?

OK, so blinking an LED might seem a little simplistic. However, being able to control a microcontroller from the Internet is a pretty big thing (and will garner the admiration of all your geek friends).

You could write a phone app to control the lights in your house by posting and reading values in M2X. You could remotely start your car, computer, stereo, etc. as long as there is Internet connectivity. The list goes on.