Sending Humidity and Temperature data with ZigBee

17715845-21052602-thumbnail.jpg

This is the solution that I posed to my senior design in Biomedical Engineering class (BME 440).  Over the last few weeks we covered basic Arduino programming (e.g. debounced toggle, DHT sensor), we did some basic ZigBee communication (AT mode).  The final project was to build a wireless Humidity, Temperature sensor that can transmit the data to a central computer. Above you can see the wiring to connect the humidity sensor DHT22 (see Adafruit's tutorial) to the Arduino/Xbee Shield.  For this solution we configured the XBee S2's to "ZigBee End Device API" with AP = 2 (escape enabled).  The central computer is connected to the Network coordinator XBee ("ZigBee Coordinator API AP=1).  The Arduino code uses the XBee-Arduino library and the Adafruit DHT library.  The python code is using the python-Xbee library.

untitled
/**
 * Copyright 2012, Helmut Strey
 *
 * This is an Arduino sketch that reads the humidity and temperature
 * from a DHT 22 sensor and transmits it using a ZigBee RF module.
 * It combines two example sketches that came from the XBee-Arduino library: Series2_Tx
 * and DHTtester from the adafruit DHT arduino library.
 * *
 * HumindityTempZigBee is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see http://www.gnu.org/licenses
 */
 
#include "XBee.h"
#include "DHT.h"
 
#define DHTPIN 2     // data pin of the DHT sensor
 
// Uncomment whatever type you're using!
//#define DHTTYPE DHT11   // DHT 11 
#define DHTTYPE DHT22   // DHT 22  (AM2302)
//#define DHTTYPE DHT21   // DHT 21 (AM2301)
 
// Connect pin 1 (on the left) of the sensor to +5V
// Connect pin 2 of the sensor to whatever your DHTPIN is
// Connect pin 4 (on the right) of the sensor to GROUND
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor
 
DHT dht(DHTPIN, DHTTYPE);
 
/*
This example is for Series 2 XBee
 Sends a ZB TX request with the value of analogRead(pin5) and checks the status response for success
*/
 
// create the XBee object
XBee xbee = XBee();
 
// we are going to send two floats of 4 bytes each
uint8_t payload[8] = { 0, 0, 0, 0, 0, 0, 0, 0};
 
// union to convery float to byte string
union u_tag {
    uint8_t b[4];
    float fval;
} u;
 
 
// SH + SL Address of receiving XBee
XBeeAddress64 addr64 = XBeeAddress64(0x0013a200, 0x406F4973);
ZBTxRequest zbTx = ZBTxRequest(addr64, payload, sizeof(payload));
ZBTxStatusResponse txStatus = ZBTxStatusResponse();
 
int statusLed = 13;
int errorLed = 13;
 
void flashLed(int pin, int times, int wait) {
 
  for (int i = 0; i < times; i++) {
    digitalWrite(pin, HIGH);
    delay(wait);
    digitalWrite(pin, LOW);
 
    if (i + 1 < times) {
      delay(wait);
    }
  }
}
 
void setup() {
  pinMode(statusLed, OUTPUT);
  pinMode(errorLed, OUTPUT);
  dht.begin();
  xbee.begin(9600);
}
 
void loop() {
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity();
  float t = dht.readTemperature();
 
  // check if returns are valid, if they are NaN (not a number) then something went wrong!
  if (!isnan(t) && !isnan(h)) {
     
    // convert humidity into a byte array and copy it into the payload array
    u.fval = h;
    for (int i=0;i<4;i++){
      payload[i]=u.b[i];
    }
     
    // same for the temperature
    u.fval = t;
    for (int i=0;i<4;i++){
      payload[i+4]=u.b[i];
    }
     
    xbee.send(zbTx);
 
    // flash TX indicator
    flashLed(statusLed, 1, 100);
 
    // after sending a tx request, we expect a status response
    // wait up to half second for the status response
    if (xbee.readPacket(500)) {
      // got a response!
 
      // should be a znet tx status             
      if (xbee.getResponse().getApiId() == ZB_TX_STATUS_RESPONSE) {
        xbee.getResponse().getZBTxStatusResponse(txStatus);
 
        // get the delivery status, the fifth byte
        if (txStatus.getDeliveryStatus() == SUCCESS) {
          // success.  time to celebrate
          flashLed(statusLed, 5, 50);
        } else {
          // the remote XBee did not receive our packet. is it powered on?
          flashLed(errorLed, 3, 500);
        }
      }
    } else if (xbee.getResponse().isError()) {
      //nss.print("Error reading packet.  Error code: ");  
      //nss.println(xbee.getResponse().getErrorCode());
    } else {
      // local XBee did not provide a timely TX Status Response -- should not happen
      flashLed(errorLed, 2, 50);
    }
  }
  delay(1000);
}

Below is my python script that I used to receive the data.

untitled
#! /usr/bin/python
 
"""
HumidityTempZigBee.py
 
Copyright 2012, Helmut Strey
 
This is a python script that receives and outputs the humidity and temperature
that was wirelessly transmitted from a DHT 22 / ZigBee RF module.
 
HumindityTempZigBee is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program.  If not, see http://www.gnu.org/licenses/.
 
"""
 
from xbee import ZigBee
import serial
import struct
 
PORT = '/dev/tty.usbserial-AE01CQ5N'
BAUD_RATE = 9600
 
def hex(bindata):
    return ''.join('%02x' % ord(byte) for byte in bindata)
 
# Open serial port
ser = serial.Serial(PORT, BAUD_RATE)
 
# Create API object
xbee = ZigBee(ser,escaped=True)
 
# Continuously read and print packets
while True:
    try:
        response = xbee.wait_read_frame()
        sa = hex(response['source_addr_long'][4:])
        rf = hex(response['rf_data'])
        datalength=len(rf)
        # if datalength is compatible with two floats
        # then unpack the 4 byte chunks into floats
        if datalength==16:
            h=struct.unpack('f',response['rf_data'][0:4])[0]
            t=struct.unpack('f',response['rf_data'][4:])[0]
            print sa,' ',rf,' t=',t,'h=',h
        # if it is not two floats show me what I received
        else:
            print sa,' ',rf
    except KeyboardInterrupt:
        break
         
ser.close()