WIFI Week: Twitter Temperature 2

Twitter and tweeting with LEGO MINDSTORMS NXT.In or final instalment of WIFI Week, we’ll show you how to send a Tweet to a twitter account. In this example, we will take a temperature with the DI Thermometer, and embed it in a tweet.

To post to twitter, our program uses a twitter service at Tweet Library for Arduino and the built in HTTP functions in the Wifi Sensor.  The code posted below will serve as an example for HTTP POST and HTTP GET functions.

By the end of this tutorial, you will have the code to setup a tweeting robot.

Overview

A basic outline of where we’ll be going in this example:

  1. IP Address: First, we’re going to get the IP Address of Tweet Library for Arduino.  We use this twitter service because it is a simple and clean way to send a tweet.
  2. HTTP Client: Next, we will start an HTTP Client, which is sort of like a web browser in that it reads and interacts with web pages.  The client will connect with the Tweet Library for Arduino web page, and open a CID (Connection Identifier).
  3. HTTP Header: Next we will start to craft a message.  This is more complicated that it sounds.  Because we’re working with an HTTP Client, we will send some complex header information (feel free to copy ours).
  4. HTTP Send: Finally, after the header information, we’ll send our account token and the message we want to tweet.

Get the IP Address

For those that read our previous post on some of the utilities that the Wifi sensor has, this is old news.  We will simply send the command:

AT+DNSLOOKUP=arduino-tweet.appspot.com

The LEGO Wifi sensor returns the IP address of the web site we’re looking for.

Start the HTTP Client

Another easy step.  We simply send the command to open an HTTP client up, with the IP address afterwards.

AT+HTTPOPEN=198.164.0.8

We should receive back a CID (Connection ID) that identifies what connection the client is opened on.

Send the HTTP Configuration Information

To start sending messages, similar to what we did with the TCP server, we will send an Escape sequence.  The escape sequence for HTTP looks like this:

<ESC>H<CID>

Where <ESC> is the escape symbol and <CID> is the Connection ID we got when we opened the HTTP client up.  After each message we send, we will send an <ESC>E to signal the end of the message.

First, we send a series of information strings that carry the following:

  • User Agent information
  • Header Content information
  • Header Length.

This information is the same you would find at the top of a web page.

Send the HTTP Post

Here we designate what page or sub-directory of the domain we are headed to.  In our case, we are trying to go to http://arduino-tweet.appspot.com/update so we will designate Post as “/update”.

HTTP Send – Sending the Tweet

Finally, we are going to send our tweet!

To post to the Twitter website, all we need to do now is send our token, which is a long alpha-numeric code you get by registering your account at Tweet Library.  You will also want to craft a funny, but short message.

Our message is short.  In the example we show below, the NXT reads the temperature in Celsius, and posts it embedded in the twitter message.  It’s short, it’s sweet.  We’re sure you can do better!

These two items, the token and the message, get wrapped up into a command that looks something like this:

token=<YOUR TOKEN>&status=<YOUR STATUS UPDATE>

And that’s it!  We post this to the website, and listen for a response.

Doing It Yourself

Below is the code for RobotC.  Before starting to run it, you will need to visit http://arduino-tweet.appspot.com/ and obtain a token for your twitter account.  Personal details, like the code to get into Dexter Industries Twitter Feed, is blocked out of the below code.   You will want to replace it with your own, and modify the message.

You should note that Twitter will block repeated posts that are exactly the same.

Happy Twittering!

DIWIFI-TCP_Server.c

#pragma config(Sensor, S1,     DTMP,               sensorAnalogInactive)

// Twitter your face off!
//
// DIWFI Tweet uses the Dexter Industries Wifi Sensor to send messages via twitter.
//
// Run this program with the RobotC Debugging Stream On to view any errors.
//
// For more information visit http://www.dexterindustries.com/
//
// This program uses the HTTP client in the Dexter Industries DIWIFI sensor to send a tweet to your account.
// You must first go to http://Arduino-Tweet.appspot.com to get a token for your account.  This program does not
// directly tweet, rather it will tweet through this web application.
//
// Next, craft your message.  You can see that we put a quick message up in the variable "Message1" - "Message5".
// You will also need to count the length of your message.  The message lenght is the number of characters in your message
// plus the number of characters in your token, plus the 14 in overhead.
//
// See more about the Dexter Industries Wifi Sensor for the Lego Mindstorms NXT here:  http://www.dexterindustries.com/wifi.html
//
// This program is based off work done originally by Xander Soldat.
// See his brilliant work at http://www.botbench.com
//////////////////////////////////////////////////////////////////////////////////////////////////////

#include "drivers/common.h"
#include "DIWIFI-Tweet.h"

// Note that the token and the message are defined in DIWIFI-Tweet.h  We did that to make the program cleaner.
// For convenience you can move these variables to the main program here.

task main()
{
  int CID = 0;                      // Zero is a great Connection ID to start with.
  string strIP = " ";               // We will read the IP number of Arduino-Tweet into this string
  closeAllConns();                  // Housekeeping: Close any open connections.
  clear_read_buffer();              // Housekeeping: Clear out the buffer.
  get_IP_address();                 // This gets the IP address of arduino-tweet.appspot.com
  StringFromChars(strIP, IP_num);   // Turns the IP number into a string.
  writeDebugStream(strIP);          // Prints the IP number on the debug stream of RobotC
  CID = start_HTTP_client();        // We start the HTTP client here.  Now we're acting as a client, not a server.
  send_tweet(CID);                  // This kicks off the meat of the project.  We're starting to send a tweet through the connection ID.
}

DIWIFI-TCP_Server.h

#include "drivers/DTMP-driver.h"

const ubyte token[] = {'*','*','*','*','*','*','*','*','*','*','0','J','H','X','f','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','c'};
const ubyte token2[] = {'*','*','*','*','*'}; // Obtain this token by going to Arduino-Tweet.appspot.com.  Ours is removed for our protection.

// Divide your message up into peices.  We did this for convenience of counting.
const ubyte message1[] = {'I','t',' ','i','s',' '};                               // 6 Characters // ,'l','d','!',' ','I','t','s',' ','','t','h','e',' ','f','i','r','s','t',' ','L','E','G','O'};
const ubyte message2[] = {' ','D','e','g',' ','C',' ','D','e','x','t','e','r'};   // 13 Characters // ,'o',' ','t','w','e','e','t','!'}; // Message finale!

      ubyte cmdStart[] = {27, 'H', '0'};      // Starts transmission of HTTP information.  Note it's not a constant
                                              // Because the "0" is the CID and may be replaced depending on how your program operates.
const ubyte cmdEnd[] = {27, 'E'};             // Ends transmission of HTTP information.

const ubyte cmd_Domain[] = {'h','t','t','p',':','/','/','a','r','d','u','i','n','o','-','t','w','e','e','t','.','a','p','p','s','p','o','t','.','c','o','m'};
const ubyte cmd_token[] = {'t','o','k','e','n','='};            // First part of the message, before you send your token.
const ubyte cmd_status[] = {'&','s','t','a','t','u','s','='};   // Second part of the message before you send your message.

const ubyte httpconf[] = {'A','T','+','H','T','T','P','C','O','N','F','='};
const ubyte httpSend[] = {'A','T','+','H','T','T','P','S','E','N','D','='};

ubyte IP_num[64];
ubyte BytesRead[8];
ubyte newline[] = {0x0D};
ubyte contLength[] = {'1','1','5'};

typedef ubyte buff_t[512];
buff_t buffer;

// writeArray function writes an array to the RawHS function
// and prints it out in the debug stream.
void writeArray(int indx)
{
  string buff_out;
  char buff_iter;
  int index = indx;
  nxtWriteRawHS(buffer, index);             // Write to high speed port

  writeDebugStream("%c", newline);          // Give us a new line to make it look clean.
  for(int t = 0; t < index; t++)            // Write to DebugStream
  {
    buff_iter = buffer[t];                  // Load up the specific iteration.
    StringFromChars(buff_out, buff_iter);   // Make it a string.
    writeDebugStream(buff_out);             // Now print to DebugStream
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////
// Receive Bytes
// Reads whatever is in the buffer and prints to debug
////////////////////////////////////////////////////////////////////////////////////////////////////////

void Receive(bool wait=false)
{
  if (wait)
    while (nxtGetAvailHSBytes() == 0) wait1Msec(5);

  while (nxtGetAvailHSBytes() > 0) {
    nxtReadRawHS(BytesRead[0], 1);
    writeDebugStream("%c", BytesRead[0]);
    wait1Msec(1);
  }
}


////////////////////////////////////////////////////////////////////////////////////////////////////////
//      Clear Read Buffer
//      Run this to clear out the reading buffer.
//      Simply sends a carriage return, then clears the buffer out.
////////////////////////////////////////////////////////////////////////////////////////////////////////

void clear_read_buffer()
{
    ubyte nData[] = {13};
    nxtWriteRawHS(nData[0], 1);   // Send the carriage return
    wait10Msec(100);
    while(BytesRead[0] < 0){
      nxtReadRawHS(BytesRead[0], 1);    // Read the response.  Probably an error.
    }
    wait10Msec(100);
}

void closeAllConns() {
  writeDebugStreamLine("closeAllCons");
  ubyte close_cmd[] = {'A','T','+','N','C','L','O','S','E','A','L','L',0x0D};
  nxtWriteRawHS(close_cmd[0], sizeof(close_cmd));       // Send the command, byte by byte.
  Receive(true);
}

int appendToBuff(buff_t &buf, const long index, const ubyte &pData, const long nLength)
{
  if (index == 0) memset(buf, 0, sizeof(buf));

  memcpy(buf[index], pData, nLength);
  return index + nLength;
}

// This function reads an IP address and puts it into a
// ubyte array.
void Read_IP()
{
  int t = 0;

  while (nxtGetAvailHSBytes() == 0) wait1Msec(5);
  while (nxtGetAvailHSBytes() > 0) {
    nxtReadRawHS(BytesRead[0], 1);
    if(t>4 && BytesRead != 13 && BytesRead[0] != 'O' && BytesRead[0] != 'K'){
      IP_num[t-5] = BytesRead[0];
    }
    wait1Msec(2);
    t++;
  }
}

//
// This will get the IP address of a specific domain name.
//
void get_IP_address() {
  int index = 0;
  ubyte listen_cmd[] = {'A','T','+','D','N','S','L','O','O','K','U','P','='};
  ubyte DNS_Name[] = {'a','r','d','u','i','n','o','-','t','w','e','e','t','.','a','p','p','s','p','o','t','.','c','o','m'};
  index = appendToBuff(buffer, index, listen_cmd, sizeof(listen_cmd));
  index = appendToBuff(buffer, index, DNS_Name, sizeof(DNS_Name));
  index = appendToBuff(buffer, index, newline, sizeof(newline));
  writeArray(index);
  Read_IP();
}

//
// Start HTTP client
//
int start_HTTP_client() {
  int index = 0;
  int cid = 0;

  ubyte UDP_cmd[] = {'A','T','+','H','T','T','P','O','P','E','N','='};
  index = appendToBuff(buffer, index, UDP_cmd, sizeof(UDP_cmd));
  index = appendToBuff(buffer, index, IP_num, 14); // sizeof(IP_num));
  index = appendToBuff(buffer, index, newline, sizeof(newline));
  writeArray(index);

  while (nxtGetAvailHSBytes() == 0) wait1Msec(5);
  while (nxtGetAvailHSBytes() > 0) {
    nxtReadRawHS(BytesRead[0], 1);
    writeDebugStream("%c", BytesRead[0]);
    if(BytesRead[0] < 58 && BytesRead[0] > 47){  // So if it's a number . . .
      cid = BytesRead[0]-48;  // Works for connections 0 through 9.
    }
    wait1Msec(2);
  }
  return cid;
}

// Send the UserAgent information (20)
void HTTP_UserAgent() {
  int index = 0;

  ubyte number[] = {'2','0',','};
  ubyte userAgent1[] = {'M','o','z','i','l','l','a','/','4','.','0'};
  index = appendToBuff(buffer, index, httpconf, sizeof(httpconf));    // Add at+httconf

  index = appendToBuff(buffer, index, number, sizeof(number));        // sizeof(IP_num));
  index = appendToBuff(buffer, index, userAgent1, sizeof(userAgent1));        // sizeof(IP_num));
  index = appendToBuff(buffer, index, newline, sizeof(newline));
  writeArray(index);

  while (nxtGetAvailHSBytes() == 0) wait1Msec(5);
  while (nxtGetAvailHSBytes() > 0) {
    nxtReadRawHS(BytesRead[0], 1);
    writeDebugStream("%c", BytesRead[0]);
    wait1Msec(2);
  }
}

// Send the UserAgent information (20)
void HTTP_HeaderContent() {
  int index = 0;

  ubyte number[] = {'7',','};
  ubyte Header_Cont1[] = {'a','p','p','l','i','c','a','t','i','o','n','/'};
  ubyte Header_Cont2[] = {'x','-','w','w','w','-','f','o','r','m','-','u','r','l','e','n','c','o','d','e','d'};
  index = appendToBuff(buffer, index, httpconf, sizeof(httpconf));    // Add at+httconf
  index = appendToBuff(buffer, index, number, sizeof(number));        // sizeof(IP_num));
  index = appendToBuff(buffer, index, Header_Cont1, sizeof(Header_Cont1));        // sizeof(IP_num));
  index = appendToBuff(buffer, index, Header_Cont2, sizeof(Header_Cont2));        // sizeof(IP_num));
  index = appendToBuff(buffer, index, newline, sizeof(newline));
  writeArray(index);

  while (nxtGetAvailHSBytes() == 0) wait1Msec(5);
  while (nxtGetAvailHSBytes() > 0) {
    nxtReadRawHS(BytesRead[0], 1);
    writeDebugStream("%c", BytesRead[0]);
    wait1Msec(2);
  }
}

// Header Content Length
void HTTP_HDR_LENGTH() {
  int index = 0;
  ubyte number[] = {'5',','};

  index = appendToBuff(buffer, index, httpconf, sizeof(httpconf));    // Add at+httconf
  index = appendToBuff(buffer, index, number, sizeof(number));        // sizeof(IP_num));
  index = appendToBuff(buffer, index, contLength, sizeof(contLength));        // sizeof(IP_num));
  index = appendToBuff(buffer, index, newline, sizeof(newline));
  writeArray(index);

  while (nxtGetAvailHSBytes() == 0) wait1Msec(5);
  while (nxtGetAvailHSBytes() > 0) {
    nxtReadRawHS(BytesRead[0], 1);
    writeDebugStream("%c", BytesRead[0]);
    wait1Msec(2);
  }
}

// HTTP SEND
void HTTP_SEND(int cid_in) {
  int index = 0;
  int cid = cid_in;
  char CID_Char = cid+48;
  ubyte number2[] = {'3',','};
  ubyte number3[] = {'2','0',','};
  ubyte comma[] = {','};

  ubyte Post_Page[] = {'/','u','p','d','a','t','e'}; // ,' ','H','T','T','P','/','1','.','0'};

  index = appendToBuff(buffer, index, httpSend, sizeof(httpSend));    // Add at+httconf
  index = appendToBuff(buffer, index, CID_Char, sizeof(CID_Char));        // sizeof(IP_num));
  index = appendToBuff(buffer, index, comma, sizeof(comma));        // Comma;
  index = appendToBuff(buffer, index, number2, sizeof(number2));        // sizeof(IP_num));
  index = appendToBuff(buffer, index, number3, sizeof(number3));        // sizeof(IP_num));
  index = appendToBuff(buffer, index, cmd_Domain, sizeof(cmd_Domain));        // sizeof(IP_num));
  index = appendToBuff(buffer, index, Post_Page, sizeof(Post_Page));        // sizeof(IP_num));
  index = appendToBuff(buffer, index, comma, sizeof(comma));        // Comma;
  index = appendToBuff(buffer, index, contLength, sizeof(contLength));
  index = appendToBuff(buffer, index, newline, sizeof(newline));
  writeArray(index);

  while (nxtGetAvailHSBytes() == 0) wait1Msec(5);
  while (nxtGetAvailHSBytes() > 0) {
    nxtReadRawHS(BytesRead[0], 1);
    writeDebugStream("%c", BytesRead[0]);
    wait1Msec(2);
  }
}

// POST MESSAGE
// Here we're actually going to post the message to twitter.
void POST_MESSAGE(int cid_in) {
  float numTemp;
  string strTemp;
  string tmpString;
  ubyte linebuff[20];

  int index = 0;
  int cid = cid_in;
  cmdStart[2] = cid+48;

  index = 0;
  index = appendToBuff(buffer, index, cmdStart, sizeof(cmdStart));      // Start Command
  index = appendToBuff(buffer, index, cmd_token, sizeof(cmd_token));    // Token Command
  index = appendToBuff(buffer, index, token, sizeof(token));            // Token Command
  index = appendToBuff(buffer, index, token2, sizeof(token2));          // Token Command
  index = appendToBuff(buffer, index, cmd_status, sizeof(cmd_status));  // Token Command
  index = appendToBuff(buffer, index, message1, sizeof(message1));      // Token Command

  DTMPreadTemp(DTMP, numTemp); // Read the temperature.
  StringFormat(strTemp, "%4.2f", numTemp); // Put it into a string.
  tmpString = strTemp;  // Put that string into the buffer.
  memcpy(linebuff, tmpString, strlen(tmpString));
  index = appendToBuff(buffer, index, linebuff, strlen(tmpString));

  index = appendToBuff(buffer, index, message2, sizeof(message2));      // Token Command
  index = appendToBuff(buffer, index, cmdEnd, sizeof(cmdEnd));          // End Command
  index = appendToBuff(buffer, index, newline, sizeof(newline));        // And tack on a new line.
  writeArray(index);

  while (nxtGetAvailHSBytes() == 0) wait1Msec(5);
  while (nxtGetAvailHSBytes() > 0) {
    nxtReadRawHS(BytesRead[0], 1);
    writeDebugStream("%c", BytesRead[0]);
    wait1Msec(2);
  }
}

//
// Send the Tweet
//
void send_tweet(int CID){
  HTTP_UserAgent();
  HTTP_HeaderContent();
  HTTP_HDR_LENGTH();
  HTTP_SEND(CID);
  POST_MESSAGE(CID);
  PlaySound(soundBeepBeep);
  while(true){
    Receive(false);
    wait10Msec(5);
  }
}

Did you like this? Share it:

Related Posts:

2 thoughts on “WIFI Week: Twitter Temperature

  1. Pingback: Teach Your Lego Robot How To Tweet With A Dexter Industries WiFi Sensor | TechCrunch

  2. Pingback: Now Your Lego Creations Can Tweet For You | Gizmodo Australia

Leave a Reply

  

  

  


8 + = thirteen