The Internet of Things: Pachube With DIWIFI and LEGO MINDSTORMS NXT

WIFI Week 2 Header WIFI FOR LEGO MINDSTORMS NXT

Pachube with LEGO MINDSTORMS NXT

Pachube with LEGO™ MINDSTORMS™ NXT

Pachube (pronounced as “Patch bay”) is an on-line database service allowing people to connect sensor-derived data (such as energy and environmental data from objects, devices & buildings) to the Web and to build their own applications based on that data.  In this post we show you how you can use the WIFI Module for LEGO™ MINDSTORMS™  NXT to become part of the internet of things.

Pachube connects people to devices, applications, LEGO™ MINDSTORMS™ NXT and the Internet of Things. As a web-based service built to manage the world’s real-time data, Pachube gives people the power to share, collaborate, and make use of information generated from the world around them.  The site receives millions of datapoints every day from all sorts of projects and products.

Wait, the Internet of Things?  Yes!  As more and more devices become web-enabled, they will share more information and in the process, become smarter and more connected.

Now your robot can become a part of the Internet of Things, using the Wifi sensor!

We have made a quick and easy example in RobotC that allows you to send information from your LEGO™ NXT in real-time:  as soon as something happens, it is posted to the internet.  This can be used for some really interesting projects:

After you have put the data up on the web, you can do some more interesting things, including make real-time charts, embed graphs of the data in your website, and send real-time alerts to other devices like a cell phone or Google Talk.

We’ve posted some RobotC code to get started below.  The code is heavily commented so it should be easy to covert to other languages for your NXT.  We have left our account information in the code to help you get started (it’s an experimental account); feel free to post some data to it as you like.

The feed can be seen on the pachube website here:  http://pachube.com/feeds/51480

DIWIFI-Pachube.C

[sourcecode language=”cpp”] // Connect to Pachube!
//
// DIWIFI-Pachube posts information on the "Internet of Things" to Pachube information online.
//
// "Pachube ("patch-bay") connects people to devices, applications, and the Internet of Things.
// As a web-based service built to manage the world’s real-time data, Pachube gives people
// the power to share, collaborate, and make use of information generated from the world
// around them." – http://pachube.com
//
// This program uses the HTTP client in the Dexter Industries DIWIFI sensor to send information to Pachube.
// We have left our account information on this example to provide a complete example. Post whatever you
// want to this channel, it’s just meant to allow you to try the service out.
//
// To setup your own Pachube feed, just change the variables at the tope of the Pachube.h file, and change the
// API Key.
//
// See more about the Dexter Industries Wifi Sensor for the Lego Mindstorms NXT here: http://www.dexterindustries.com/wifi.html
//
// Run this program with the RobotC Debugging Stream On to view any errors.
// For more information visit http://www.dexterindustries.com/
// Dexter Industries, 2012. Feel free to use as you see the need to but give credit where credit is due.
//////////////////////////////////////////////////////////////////////////////////////////////////////

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

task main()
{
clear_read_buffer();
int CID = 0;

closeAllConns(); // Housekeeping: Close any open connections.
clear_read_buffer(); // Housekeeping: Clear out the buffer.

CID = start_TCP_client(); // We start the HTTP client here. Connect to Pachube.com, get a CID.
writeLineBreak();
Send_to_Pachube(CID); // This kicks off the meat of the project. This will send info to our
// Pachube account.
}
[/sourcecode]

DIWIFI-Pachube.h

[sourcecode language=”cpp”] #include "drivers/DTMP-driver.h"

string FEEDID = "51480"; // This is the feed ID from Pachube.
string STREAMID = "sensor1"; // This is the streamID; also setup on Pachube.
string postinfo = "125";

ubyte byteStart[] = {27, ‘S’, ‘0’}; // Opens a TCP session
ubyte byteEnd[] = {27, ‘E’}; // Closes a TCP session

ubyte BytesRead[8]; // Used in the process of getting bytes from the wifi sensor, turning into usable data.

////////////////////////////////////////////////////////////////////////////////////////////////////////
// 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);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////
// WriteStr
// This function writes a string to the DebugStream and Port4. We wrote this out because it is easier to recognize and see
// strings; easier than working with arrays of characters.
////////////////////////////////////////////////////////////////////////////////////////////////////////
void writeStr(string sData)
{
ubyte byteData = 0;
for(int i = 0; i < strlen(sData); i++)
{
byteData = strIndex(sData, i);
nxtWriteRawHS(byteData, 1);
writeDebugStream("%c", byteData); // Critical for debugging. Make sure you’re getting some time in there
// to read what you wrote.
while(nxtHS_Status == HS_SENDING) wait1Msec(1);
wait1Msec(1); // With
}
}

////////////////////////////////////////////////////////////////////////////////////////////////////////
// WriteLineBreak
// This function just writes a line break to DebugStream and Port4. It is necessary to have this in
// RobotC because strings are limited to 17 characters and sometimes you will need to send commands
// longer than 17 characters.
////////////////////////////////////////////////////////////////////////////////////////////////////////
void writeLineBreak()
{
writeDebugStream("%c", 13);
ubyte newline = 0x0D;
nxtWriteRawHS(newline, 1);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////
// Write CRLN
// This function writes a carriage return and line break to DebugStream and Port4. This is used
// in HTTP communications and ends any line in a HTTP GET or PUT or POST.
////////////////////////////////////////////////////////////////////////////////////////////////////////
void crln()
{
writeDebugStream("%c", 13);
writeDebugStream("%c", 10); // Display this on the debug for our information.
ubyte newline[] = {0x0D, 0x0A}; // Carriage return and then line feed.
nxtWriteRawHS(newline, 2);
wait1Msec(5); // ABSOLUTELY CRITICAL. We added this because
// we found that in line-feeds, the first bytes of the next transmission get
// dropped. VERY IMPORTANT TO HAVE THIS DELAY IN HERE.
}

////////////////////////////////////////////////////////////////////////////////////////////////////////
// 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);
}
}

////////////////////////////////////////////////////////////////////////////////////////////////////////
// CloseAllCons
// Closes any connections that are open (CID’s).
////////////////////////////////////////////////////////////////////////////////////////////////////////
void closeAllConns() {
writeDebugStreamLine("closeAllCons");
clear_read_buffer();
writeStr("at+ncloseall");
writeLineBreak();
wait10Msec(10);
Receive(true);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////
// Start TCP client
// Connects to an IP number.
////////////////////////////////////////////////////////////////////////////////////////////////////////
int start_TCP_client() {
int cid = 0; // CID placeholder
string IP_num = "216.52.233.122"; // This is the IP address of Pachube
string port = ",80"; // We connect on Port 80.

writeStr("AT+NCTCP="); // Function to connect to TCP client
writeStr(IP_num); // Write the IP number.
writeStr(port); // now the port.
writeLineBreak(); // Send the line break. And wait.

// Don’t replace the following code with a Receive function.
// This code picks out the CID number.
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;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////
// TCP Send Data
// Sends data to the server.
////////////////////////////////////////////////////////////////////////////////////////////////////////
void TCP_Send_Data(int CID) {
wait1Msec(250);

byteStart[2] = (CID+48);
nxtWriteRawHS(byteStart, 3); // ESC S sequence. Starts the TCP information flow.
writeDebugStream("%c", byteStart, 2); //
writeDebugStreamLine("%c", (CID+48));

Receive(true); // If the connection is succesful, we will get back and <esc> O. Unsuccesful, <esc> F

writeStr("PUT /v2/feeds/"); // The put sequence
writeStr(FEEDID); // Your feed ID
writeStr("/datastreams/"); // More address info
writeStr(STREAMID); // StreamID
writeStr(".csv "); // This is for text or number messages.
wait1Msec(1);
writeStr("HTTP"); // HTTP Type. Had to seperate this out. for SOme reason, combining led to failure.
writeStr("/1.1");
wait1Msec(1);
crln(); // In HTTP, you need to send a carriage return and then New Line.

writeStr("Host: "); // Send Host information
writeStr("api.pachube.com");
crln();

writeStr("X-PachubeApiKey: ");// Now we’re going to send the API Key. An API key we put together is:
writeStr("cbZR8NpCaD"); //cbZR8NpCaDpsdaqcv-J41Bl6LbCSAKxGOGNoVkVrYWxOdz0g
writeStr("psdaq"); // Feel free to post here, we don’t care.
writeStr("cv-J41Bl6L"); // The API is broken into smaller parts because we experience failure sending it all in one big string.
writeStr("bC");
writeStr("SAKx");
writeStr("GOGNoVkVrY");
writeStr("WxOdz0g");
crln();

writeStr("Content-Length: "); // Content lenghth is goig to be automatically calculated.
string length = "";
StringFormat(length, "%i", strlen(postinfo));
writeStr(length); // For Pachube, we just put the length of the post down.
crln();

writeStr("Connection: "); // One more peice of information the server is looking for.
writeStr("close");
crln(); // This is important: after the header information, send two CR/LNs.
crln();

writeStr(postinfo); // This is where your info will get posted.

wait1Msec(10);
nxtWriteRawHS(byteEnd, 2); // End the TCP connection.

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

////////////////////////////////////////////////////////////////////////////////////////////////////////
// Send_to_Pachube
// Send the Information to Pachube.
// Beep when you’re done.
////////////////////////////////////////////////////////////////////////////////////////////////////////
void Send_to_Pachube(int CID){
TCP_Send_Data(CID); // Connect to a specific CID.
PlaySound(soundBeepBeep); // Go ahead and beep. If it fails or if it doesn’t, whatevs.
while(true){
Receive(false); // Sit and listen. If you wanted to wait a few minutes and repost, you could work that in here.
}
}

[/sourcecode]

3 Comments

  1. First of all, awesome to seek a wifi week 2, and the stuff you guys have got in these week are just what I need for my own project.

    Second, I am having a little bit of a problem with the code here when I copy and paste it to try it out.. It says “Undefined procedure ‘Receive’.” And it’s right–I don’t see a defined ‘Receive’ function anywhere in the code or in the driver.

    Do you know if I am doing anything wrong? All I’ve done is copied and pasted the code and tried to compile

    • Administrator May 7, 2012

      Hey Joraaver, we just updated the code that’s pasted here. Sorry about that, not sure how it got left out. I think it should be working now.

      Let us know how it goes!

  2. Awesome. Compiles perfectly.

    If you looked at my blog, you can see what I’m up to and why all this is helpful. Hopefully, if I can finish this, I’ll share my project with you.

    Thanks again.

Leave a reply