Issues with XBee Setup and Phant Library

Everything pertaining to the data.sparkfun.com service, the phant project which powers it, and user projects which talk to the service.

Moderators: phalanx, toddtreece, Brennen@SparkFun

Post Reply
tex792
Posts: 13
Joined: Sat Dec 12, 2015 8:53 pm

Issues with XBee Setup and Phant Library

Post by tex792 » Sun Jan 29, 2017 1:36 pm

I am attempting to create a setup that takes temperature data and logs it to data.sparkfun.com. I started out by creating a sketch that just sets up the XBee for my local WiFi network and reads the temperature sensor. That sketch works fine, but as soon as I start including lines which reference the Phant library, it stops working. Specifically, my AT commands to the XBee and the associated responses do not transmit cleanly. The more code I include which references the Phant library, the more it seems to affect things.

I posted the code below with the Phant lines commented out (only two of them). Also I provided a screenshot from the serial monitor showing the code running properly, and another screenshot showing what happens when I include the Phant lines. With the included lines, the variable which stores my WiFi password becomes corrupted and seems to have a random string of characters and numbers that are nowhere near my actual password.

Does anyone know how the Phant library may be affecting this?

Thanks,
Travis

*As a side note, I realize this code needs to be more robust. Right now it only checks the XBee status and sends to the serial monitor. In the future, it will need to keep checking network connectivity until we are actually connected to the WiFi network. Right now, if I get a non-zero response from the ‘ATAI’ command, I just hit reset until I’m connected.

Code: Select all

/*
This sketch will enter the command mode, apply network settings to the XBee module and verify those settings, including a connectivity check with the local network.
Next we will collect temperature data and send to the serial monitor. Eventually code will be added to transmit this data to sparkfun.data.com, but that is not included here.

Sensitive info was removed from this sketch: WiFi network name, WiFi password, data stream public/private keys

Hardware Connections:
XBee Shield which has an XBee WiFi Module (PCB Antenna) attached to it and the shield itself is mounted to a Sparkfun Redboard.
Make sure the SWITCH IS IN THE "DLINE" POSITION on the shield. View the serial monitor through a USB connection to the Arduino board.
XBee WiFi: https://www.sparkfun.com/products/12568
XBee Shield: https://www.sparkfun.com/products/12847
Sparkfun Redboard (Arduino): https://www.sparkfun.com/products/12757

IDE: Arduino 1.8.1

Elements of this code taken from:
Jim Lindblom @ SparkFun Electronics, Original Creation Date: May 20, 2014, https://learn.sparkfun.com/tutorials/internet-datalogging-with-arduino-and-xbee-wifi
Code posted on forum at https://forum.sparkfun.com/viewtopic.php?f=13&t=41081
XBee Shield Hookup Guide, https://learn.sparkfun.com/tutorials/xbee-shield-hookup-guide

Author:
Travis Vazansky
January 29, 2017
*/


#include <SoftwareSerial.h> //We will use software serial, not UART, to communicate between the Arduino and XBee. Make sure the shield's switch is in the "DLINE" position.
SoftwareSerial XBee(2, 3); //Define the XBee object.  We will receive from the object on Pin 2 and transmit to the object using Pin 3.

const int temperaturePin = 0; //Define the analog pin which the temperature sensor is connected to

//#include <Phant.h> //Include the Phant libary. Adding this line itself does not affect the code. It will run fine.
//Phant phant("data.sparkfun.com", "XXXPulic KeyXXX", "XXXPrivate KeyXXX"); //When I add this line, the code does not run properly anymore


void setup()
{
  delay(5000); //5s delay to allow the system to initialize
  XBee.begin(9600); //Open the XBee SoftwareSerial port for communication
  Serial.begin(9600); //Open the Serial port for communication
  String address = "54.86.132.254"; //IP address for data.sparkfun.com
  String ssid = "XXXXXX"; //Local network name 
  String security = "2"; //Local network security type (2 = WPA2 AES)
  String pswd = "XXXXXXXX"; //Local network password
  CommandMode(); //Enter command mode
  Serial.println(""); Serial.print("Apply settings to XBee"); Serial.println("");
  ConnectSet(address, ssid, security, pswd); //Apply settings to XBee, including the four variables defined above
  Serial.println(""); Serial.print("Verify XBee settings"); Serial.println("");
  ConnectCheck(); //Check that the settings were stored correctly and that we have proper network association
  Serial.println(""); Serial.print("Exiting command mode"); Serial.println("");
  command("ATCN"); //Exit command mode
  Serial.print("Exited command mode"); Serial.println(""); Serial.println("");
}


void loop()
{
  float voltage, degreesC, degreesF; //Define variables to store temperature data
  voltage = (analogRead(temperaturePin) * 0.004882814); //The analog pin provides a reading between 0-1023. Convert that reading to voltage between 0-5V.
  degreesC = (voltage - 0.5) * 100.0; //Convert voltage to degrees Celsius. This formula comes from the temperature sensor datasheet.
  degreesF = degreesC * (9.0/5.0) + 32.0; //Convert Celsius to Fahrenheit
  Serial.print("voltage: ");
  Serial.print(voltage);
  Serial.print("  deg C: ");
  Serial.print(degreesC);
  Serial.print("  deg F: ");
  Serial.println(degreesF);
  delay(3000);
}


void CommandMode() //This function will enter command mode and verify the XBee's positive response of 'OK'
{
   delay(1500); //Added this guard time per XBee Wi-Fi RF Module S6B User Guide, 'AT command mode' section...include a delay before entering command mode characters
   Serial.println("Entering command mode");
   XBee.print("+++"); //+++ is the sequence of characters that will initiate the command mode. Note that a carriage return is NOT required.
   delay(1500); //Added this guard time per XBee Wi-Fi RF Module S6B User Guide, 'AT command mode' section...include a delay after entering command mode characters
   int rsplen = XBee.available(); //Create a variable to store the LENGTH of the response from the XBee
   char rsp[rsplen]; //Create an array to store RESPONSE from the XBee
   for(int i=0; i<rsplen; i++) //Read the response in the buffer one byte at a time
      rsp[i] = XBee.read();
   String rsps = rsp; //Store the response in a string so we can trim off any leading and trailing whitespace characters
   rsps.trim(); //Trim off leading and trailing whitespace characters
   Serial.print("Response: "); Serial.println(rsps); //Print out the response to the serial monitor
   if (rsps == "OK") //Check if we recieved the expected "OK" response from the XBee
     Serial.println("Entered command mode :)");
   else
     Serial.println("Failed to enter command mode :(");
}


void command(String atcmd) //This function will send AT commands to the XBee module and display the response
{
   Serial.print("Entering command: "); Serial.println(atcmd);
   XBee.print(atcmd); //Send the command
   XBee.print("\r"); //Enter a carriage return
   delay(1500); //Include a delay to give the module time to respond. Responses were patchy before I included this delay.
   int rsplen = XBee.available(); //Create a variable to store the LENGTH of the response from the XBee
   char rsp[rsplen]; //Create an array to store RESPONSE from the XBee
   for(int i=0; i<rsplen; i++) //Read the response in the buffer one byte at a time
      rsp[i] = XBee.read();
   String rsps = rsp; //Store the response in a string so we can trim off any leading and trailing whitespace characters
   rsps.trim(); //Trim off leading and trailing whitespace characters
   Serial.print("Response: "); Serial.println(rsps); //Print out the response to the serial monitor
}


void ConnectSet(String address, String ssid, String security, String pswd) //This function will apply the desired network settings to the XBee module
{
  command("ATIP1"); //Set IP (1 = TCP)
  command("ATDL" + address); //Set DL (destination IP address)
  command("ATDE50"); //Set DE (0x50 = Port 80)
  command("ATAH2"); //Set AH (2 = Infrastructure)
  command("ATCE2"); //Set CE (2 = STA)
  command("ATID" + ssid); //Set ID (local network name)
  command("ATEE" + security); //Set EE (local network encryption type)
  command("ATPK" + pswd); //Set PK (local network password)
  command("ATMA0"); //Set MA (0 = DHCP)
}


void ConnectCheck() //This function will display the XBee network settings so you can confirm they were stored correctly
{
  command("ATIP");
  command("ATDL");
  command("ATDE");
  command("ATAH");
  command("ATCE");
  command("ATID");
  command("ATEE");
  command("ATPK");
  command("ATMA");
  command("ATAI"); //Check network association status...0 means success
}
This is a screenshot of the serial monitor running the code properly without the Phant lines
Forum Post 01 Pic 01.jpg
This is a screenshot of the serial monitor running the code improperly with the Phant lines added
Forum Post 01 Pic 02.jpg

tex792
Posts: 13
Joined: Sat Dec 12, 2015 8:53 pm

Re: Issues with XBee Setup and Phant Library

Post by tex792 » Thu Feb 02, 2017 6:48 pm

I actually got my code to work and wanted to post a follow up. I had to declare my phant object within the function that posts to the phant server (see line below). Whenever I declared this object globally, I would get issues.

(Phant phant("data.sparkfun.com", "PUBLIC KEY", "PRIVATE KEY");"

Code: Select all

/*
This sketch will enter the command mode, apply network settings to the XBee module, verify those settings, and then check connectivity with the local network. It will
continue to send the ATAI command until we get a 0 response. Next we will collect temperature data and send to data.sparkfun.com by using the phant library for Arduino.
Data will also be sent to the serial monitor.

Hardware Connections:
XBee Shield which has an XBee WiFi Module (PCB Antenna) attached to it and the shield itself is mounted to a Sparkfun Redboard.
Make sure the SWITCH IS IN THE "DLINE" POSITION on the shield. View the serial monitor through a USB connection to the Arduino board.
XBee WiFi: https://www.sparkfun.com/products/12568
XBee Shield: https://www.sparkfun.com/products/12847
Sparkfun Redboard (Arduino): https://www.sparkfun.com/products/12757
Temperature Sensor, TMP36: https://www.sparkfun.com/products/10988

IDE: Arduino 1.8.1

Elements of this code taken from:
Jim Lindblom @ SparkFun Electronics, Original Creation Date: May 20, 2014, https://learn.sparkfun.com/tutorials/internet-datalogging-with-arduino-and-xbee-wifi
Code posted on forum at https://forum.sparkfun.com/viewtopic.php?f=13&t=41081
XBee Shield Hookup Guide, https://learn.sparkfun.com/tutorials/xbee-shield-hookup-guide

Author:
Travis Vazansky
February 1, 2017
*/


#include <SoftwareSerial.h> //We will use software serial, not UART, to communicate between the Arduino and XBee. Make sure the shield's switch is in the "DLINE" position.
SoftwareSerial XBee(2, 3); //Define the XBee object.  We will receive from the object on Pin 2 and transmit to the object using Pin 3.

const int temperaturePin = 0; //Define the analog pin which the temperature sensor is connected to

#include <Phant.h> //Include the Phant library
const String tempField ="temp"; //The variable for this value will be the same name that you gave as the Field (or Fields) in the data stream for data.sparkfun.com
float voltageVal; //Temp sensor variable
float celsiusVal; //Temp sensor variable
float fahrenVal; //Temp sensor variable
const unsigned long UPDATE_RATE = 300000; //This variable defines the rate which we will send data to the phant server (300000 = 5 min)
unsigned long lastUpdate = 0; //Initiate this at 0
bool sendError = false; //Do we need this line?

void setup()
{
  delay(5000); //5s delay to allow the system to initialize
  XBee.begin(9600); //Open the XBee SoftwareSerial port for communication
  Serial.begin(9600); //Open the Serial port for communication
  XBee.flush(); //Do we need this line?
  Serial.flush(); //Do we need this line?
  String address = "54.86.132.254"; //IP address for data.sparkfun.com
  String ssid = "XXXXXXXX"; //Local network name 
  String security = "2"; //Local network security type (2 = WPA2 AES)
  String pswd = "XXXXXXXX"; //Local network password
  CommandMode(); //Enter command mode
  Serial.println(""); Serial.print("Apply settings to XBee"); Serial.println("");
  ConnectSet(address, ssid, security, pswd); //Apply settings to XBee, including the four variables defined above
  Serial.println(""); Serial.print("Verify XBee settings"); Serial.println("");
  SettingsCheck(); //Check that the settings were stored correctly
  Serial.println(""); Serial.print("Check network association"); Serial.println("");
  while(ConnectCheck("ATAI") != "0"); //Check that we have proper network association, and continue until we are properly connected. XBee responds with '0' from ATAI command when properly connected.
  Serial.println("Network access point connection success!");
  Serial.println(""); Serial.print("Exiting command mode"); Serial.println("");
  command("ATCN"); //Exit command mode
  Serial.print("Exited command mode"); Serial.println(""); Serial.println("");
}


void loop()
{
  if (millis() > (lastUpdate + UPDATE_RATE)) //If the update time has elapsed since the last update, then enter this loop and send data to the phant server
  {
    Serial.print("\nSending update...");
    if (sendData()) //This function sends data to the phant server 
    {
      sendError = false; //Do we need this line?
      Serial.println("SUCCESS!"); //Honestly this check isn't working so well yet. See sendData() for further comment.
    }
    else
    {
      sendError = true; //Do we need this line?
      Serial.println("Failed :("); //Honestly this check isn't working so well yet. See sendData() for further comment.
    }
    lastUpdate = millis(); //Update the time of the last update
  }
  readSensors(); //This function updates the temperature data
  Serial.print("voltage: ");
  Serial.print(voltageVal);
  Serial.print("  deg C: ");
  Serial.print(celsiusVal);
  Serial.print("  deg F: ");
  Serial.println(fahrenVal);
  delay(3000);
}


void CommandMode() //This function will enter command mode and verify the XBee's positive response of 'OK'
{
   delay(1500); //Added this guard time per XBee Wi-Fi RF Module S6B User Guide, 'AT command mode' section...include a delay before entering command mode characters
   Serial.println("Entering command mode");
   XBee.print("+++"); //+++ is the sequence of characters that will initiate the command mode. Note that a carriage return is NOT required.
   delay(1500); //Added this guard time per XBee Wi-Fi RF Module S6B User Guide, 'AT command mode' section...include a delay after entering command mode characters
   int rsplen = XBee.available(); //Create a variable to store the LENGTH of the response from the XBee
   char rsp[rsplen]; //Create an array to store RESPONSE from the XBee
   for(int i=0; i<rsplen; i++) //Read the response in the buffer one byte at a time
      rsp[i] = XBee.read();
   String rsps = rsp; //Store the response in a string so we can trim off any leading and trailing whitespace characters
   rsps.trim(); //Trim off leading and trailing whitespace characters
   Serial.print("Response: "); Serial.println(rsps); //Print out the response to the serial monitor
   if (rsps == "OK") //Check if we recieved the expected "OK" response from the XBee
     Serial.println("Entered command mode :)");
   else
     Serial.println("Failed to enter command mode :(");
}


void command(String atcmd) //This function will send AT commands to the XBee module and display the response
{
   Serial.print("Entering command: "); Serial.println(atcmd);
   XBee.print(atcmd); //Send the command
   XBee.print("\r"); //Enter a carriage return
   delay(1500); //Include a delay to give the module time to respond. Responses were patchy before I included this delay.
   int rsplen = XBee.available(); //Create a variable to store the LENGTH of the response from the XBee
   char rsp[rsplen]; //Create an array to store RESPONSE from the XBee
   for(int i=0; i<rsplen; i++) //Read the response in the buffer one byte at a time
      rsp[i] = XBee.read();
   String rsps = rsp; //Store the response in a string so we can trim off any leading and trailing whitespace characters
   rsps.trim(); //Trim off leading and trailing whitespace characters
   Serial.print("Response: "); Serial.println(rsps); //Print out the response to the serial monitor
}


void ConnectSet(String address, String ssid, String security, String pswd)  //This function will apply the desired network settings to the XBee module
{
  command("ATIP1"); //Set IP (1 = TCP)
  command("ATDL" + address); //Set DL (destination IP address)
  command("ATDE50"); //Set DE (0x50 = Port 80)
  command("ATAH2"); //Set AH (2 = Infrastructure)
  command("ATCE2"); //Set CE (2 = STA)
  command("ATID" + ssid); //Set ID (local network name)
  command("ATEE" + security); //Set EE (local network encryption type)
  command("ATPK" + pswd); //Set PK (local network password)
  command("ATMA0"); //Set MA (0 = DHCP)
}


void SettingsCheck() //This function will verify network settings for the XBee module
{
  command("ATIP");
  command("ATDL");
  command("ATDE");
  command("ATAH");
  command("ATCE");
  command("ATID");
  command("ATEE");
  command("ATPK");
  command("ATMA");
}


String ConnectCheck(String atcmd) //This function will check if we have network connection (ATAI command should be passed to this function) and it will then return a response from the XBee.
{
  Serial.print("Entering command: "); Serial.println(atcmd);
  XBee.print(atcmd); //Send the command
  XBee.print("\r"); //Enter a carriage return
  delay(1500); //Include a delay to give the module time to respond. Responses were patchy before I included this delay.
  int rsplen = XBee.available(); //Create a variable to store the LENGTH of the response from the XBee
  char rsp[rsplen]; //Create an array to store RESPONSE from the XBee
  for(int i=0; i<rsplen; i++) //Read the response in the buffer one byte at a time
     rsp[i] = XBee.read();
  String rsps = rsp; //Store the response in a string so we can trim off any leading and trailing whitespace characters
  rsps.trim(); //Trim off leading and trailing whitespace characters
  Serial.print("Response: "); Serial.println(rsps); //Print out the response to the serial monitor
  return rsps; //Return the response as a string
}


void readSensors() //Read the temperature sensor
{
  voltageVal = (analogRead(temperaturePin) * 0.004882814); //The analog pin provides a reading between 0-1023. Convert that reading to voltage between 0-5V.
  celsiusVal = (voltageVal - 0.5) * 100.0; //Convert voltage to degrees Celsius. This formula comes from the temperature sensor datasheet.
  fahrenVal = celsiusVal * (9.0/5.0) + 32.0; //Convert Celsius to Fahrenheit
}


int sendData() //This function will post data to the phant server and return a value indicating whether the post was successful or not
{
  Phant phant("data.sparkfun.com", "PUBLIC KEY", "PRIVATE KEY");" //Initialize the Phant object (server, publicKey, privateKey)
  Serial.println("Sending data to Phant...");
  XBee.flush(); //Flush the XBee buffer
  readSensors(); //Read the temperature data
  phant.add(tempField, fahrenVal); //Add the Fahrenheit value (fahrenVal) as the data which will be sent to the phant server
  XBee.print(phant.post()); //Post the value to the phant server
  delay(1500); //Include a delay to give the module time to respond. Responses were patchy before I included this delay.
  int rsplen = XBee.available(); //Create a variable to store the LENGTH of the response from the XBee
  char rsp[rsplen]; //Create an array to store RESPONSE from the XBee
  for(int i=0; i<rsplen; i++) //Read the response in the buffer one byte at a time
     rsp[i] = XBee.read();
  String rsps = rsp; //Store the response in a string so we can trim off any leading and trailing whitespace characters
  rsps.trim(); //Trim off leading and trailing whitespace characters
  Serial.print("Response: "); Serial.println(rsps); //Print out the response to the serial monitor
  if (rsps == "HTTP/1.1 200") //This statement is not working correctly yet. Whenever I get the 'HTTP/1.1 200' response, it is usually amended with other characters.
                              //This means the function always sees the response as an error and returns a '0', even if we made a successful post.
    return 1;
  else
    return 0;
}

Post Reply