XBee Library graphing application

Here’s a simple program that uses Rob Faludi and Dan Shiffman’s XBee library for processing to read three analog sensors from a remote XBee radio and graph it. For this application, you need two XBee series 1 radios. One is attached to the serial port of the computer, and the other is remote, broadcasting three analog values.

The settings for the radios are as follows:

Base station radio:

  • Personal Area Network (PAN) ID: AAAA
  • Source address: ATMY 0
  • Baud rate 115200 bits per second: ATBD 7

Remote radio:

  • Personal Area Network (PAN) ID: AAAA
  • Source address: ATMY 1
  • Destination address: ATDL 0
  • Analog inputs activated:
    • ATD0 2
    • ATD1 2
    • ATD2 2
  • Sample rate 80 milliseconds: ATIR 50
  • 1 sample per transmission: ATIT 1
  • Baud rate 115200 bits per second: ATBD 7

And here’s the code:

/*
  XBee sensor data graphing sketch
 
 This sketch takes data in from an XBee radio and graphs the analog 
 input values.  It's for XBee series 1 radios
 
 Based on code from  Rob Faludi and Daniel Shiffman
 http://www.faludi.com
 http://www.shiffman.net 
 
 created 2 Feb 2008
 by Tom Igoe  
 */

//import the xbee and serial libraries:
import xbee.*;
import processing.serial.*;


// Your Serial Port
Serial port;
// Your XBee Reader object
XBeeReader xbee;

// set up a font for displaying text:
PFont myFont;
int fontSize = 12;

// set up Xbee parameters:
int rssi = 0;                       // received signal strength
int address = 0;                    // sender's address
int[] analog = new int[6];          // values from the analog I/O pins
int[] previousValue = new int[6];   // previous values from the pins

int numSensors = 3;                 // number of sensors you actually plan to graph

int xpos = 0;                       // graph x position
int oldYPos = 0;                    // graph y position
int yPos = 0;                       // previous y position

int hitThreshold = 250;             // peak value to check hits against
int hits = 0;                       // hit count
int lastHitValue = 0;               // value of last hit

boolean newData = false;            //whether or not you got a new reading 

void setup() {
  size(400, 300);                // window size
  frameRate(60);                 // frame rate
  smooth();                      // clean the jagged edges

  // create a font with the third font available to the system:
  myFont = createFont(PFont.list()[2], fontSize);
  textFont(myFont);

  // you might need a list of the serial ports to find yours:
  println("Available serial ports:");
  println(Serial.list());
  // open the first serial port.  Change this to match 
  // your serial port number in the list:
  port = new Serial(this, Serial.list()[0], 115200);
  // initialize the xbee object:
  xbee = new XBeeReader(this,port);
  xbee.startXBee();

  // black screen:
  background(0);
}

public void draw() {
  // only draw when you have a new reading:
  if (newData == true) {
    // iterate over the number of sensors:
    for (int thisSensor = 0; thisSensor < numSensors; thisSensor++) {
      // if you have new data and it's valid (>0), graph it:
      if (analog[thisSensor] > -1) {
        // map the sensor values to the screen size for graphing:
        yPos = int(map(analog[thisSensor], 0, 1023, 0, height));
        oldYPos = int(map(previousValue[thisSensor], 0, 1023, 0, height));

        // if we get a big change, increment the hit counter:
        if (abs(yPos - oldYPos) >= hitThreshold) {
          hits++;
          // note the magnitude of the hit:
          lastHitValue = abs(yPos - oldYPos);
        }
      }
      // draw the graph axis: 
      stroke(255);
      int xAxis = height/2;
      line(0, xAxis, width, xAxis);

      // use a different the graphing color for each axis:
      switch (thisSensor) {
      case 0:
        stroke(255,0,0);
        break;
      case 1:
        stroke(0,255,0);
        break;
      case 2: 
        stroke(0,0,255);
        break;
      }
      // draw the graph line from last value to current:
      line(xpos, oldYPos, xpos+1,yPos);
      newData = false;

      // write the text at the top
      noStroke();
      fill(0);
      rect(0, 0, 300, 100);
      fill(255);
      text("From: " + hex(address), 10, 20);
      text ("RSSI: " + rssi + " dBm", 10, 40);
      text("X: " + analog[0] + "  Y: " + analog[1] + "  Z: " + analog[2], 10, 60);
      text("Last hit value: " + lastHitValue,  10, 80);
    }
    // if you're at the right of the screen, 
    // clear and go back to the left:
    if (xpos >= width) {
      xpos = 0;
      background(0);
    } 
    else {
      xpos++;
    }
  }
}



/*  
  This function works just like a "serialEvent()" and is 
  called for you when data is available to be read from your XBee radio.
*/
  
public void xBeeEvent(XBeeReader xbee) {
  // Grab a frame of data
  XBeeDataFrame data = xbee.getXBeeReading();

  // This version of the library only works with IOPackets
  // For ZNet radios, you would say XBeeDataFrame.ZNET_IOPACKET
  if (data.getApiID() == XBeeDataFrame.SERIES1_IOPACKET) {

    // Get the transmitter address
    address = data.getAddress16();

    // Get the RSSI reading in dBM 
    rssi = data.getRSSI();

    // save previous state of analog values:
    arraycopy(analog, previousValue);
    
    // get the current values
   //  (-1 indicates channel is not configured):
    analog = data.getAnalog(); 
    
      // trip the new data flag so the draw() loop will graph:
      newData = true;    
  } 
  else {
    // it's not I/O data:
    println("Not I/O data: " + data.getApiID());
  }
}