Saturday, April 2, 2011

Humidity & Temperature wireless mote


More than a week without posting a single article to this blog... My second son was born yesterday after a week full of stress, worries and finally happiness :-)

Meanwhile, I've only progressed on the software aspects of the panStmap project. The jswap Java library has been improved with some smarties that will let the user application send commands to sleeping motes when they come back to life for their periodic reports. Additionally, a basic XML profile inspector has been added to the engine, providing a number of informations to the master application about each available device from a single product code (8 bytes). Nevertheless I wanted to close this week with a practical application, a true sensor mote that sends temperature and humidity values with the use of a panStamp, a couple of AA batteries and a DHT11 Humidity & Temperature sensor

Figure 1: Humidity & Temperature panStamp sensor 

DHT11 is an interesting sensor providing compensated digital temperature and humidity values through a single wire. There are some example applications about DHT11 for Arduino so integrating this dual sensor with panStamp has resulted to be very easy.

Figure 2: Another view of this home-brew wireless sensor

As you can see, the hardware part of this practical example is quite simple. Just to be noted that the DHT11 sensor is actually being powered from a panStamp digital pin so that the sensor can be unpowered before the panStamp enters the power-down mode. This will ensure that the wireless mote will not exceed 5 uA during sleep and, although I've not checked the power consumption when in active mode, I expect to have an autonomy of about 1.5 years with the showed alkaline batteries.

Firmware wise, what is behind the scenes? The arduino sketch is primarily represented by the following loop code:

/**
  * loop
  *
  * Arduino main loop
  */
void loop()
{
   epTable[EPI_PRODUCTCODE]->getData(); // Transmit product code
   delay(10);
   epTable[EPI_VOLTSUPPLY]->getData(); // Measure and transmit voltage supply
   delay(10);
   epTable[EPI_HUMIDTEMP]->getData(); // Measure and transmit humidity and temp values (2 bytes)
   delay(100); // Listen for remote commands for 100 msec
   panstamp.sleepFor(WDTO_8S); // Power-down for 8 sec
}

The above code may be modified to make the panStamp sleep during longer periods. Besides, anyone may prefer to not to send the product code so frequently or decompose humidity and temperature in two different endpoints. All this is customizable by the developer.

But previous to the above code, the new non-standard endpoints have had to be declared somewhere in the sketch:
/*
  * Add here your custom endpoints
  */
// Voltage supply
static byte dtVoltSupply[2];
ENDPOINT epVoltSupply(dtVoltSupply, sizeof(dtVoltSupply), &updtVoltSupply, NULL);
// Temperature and humidity from the DHT11 sensor
static byte dtTempHum[2];
ENDPOINT epTempHum(dtTempHum, sizeof(dtTempHum), &updtTempHum, NULL);
Here both endpoints are declared and statically allocated. For each endpoint, a pointer to an “updater” function or “getter” is passed as argument to the ENDPOINT constructor. These “getters” will later be called whenever ENDPOINT.getData() is used in the sketch. In fact these custom functions are automatically called by the SWAP library to automate things like sending info messages after receiving SWAP queries for instance so that the end user has not to worry about dealing with the basic mechanisms of the SWAP protocol.

Then the new endpoints are declared as part of the global array of endpoints (epTable):

/**
  * Initialize table of endpoints
  */
ENDPOINT *epTable[] = {
&epProductCode,
&epHwVersion,
&epFwVersion,
&epSysState,
&epCarrierFreq,
&epFreqChannel,
&epSecuOption,
&epSecuNonce,
&epNetworkId,
&epDevAddress,
// Add here your custom endpoints
&epVoltSupply,
&epTempHum
};

And finally, both updater or getter functions are defined:

/**
  * updtVoltSupply
  *
  * Measure voltage supply and update endpoint. Code inspired from
  * http://code.google.com/p/tinkerit/wiki/SecretVoltmeter
  *
  * 'eId' Endpoint ID
  */
const void updtVoltSupply(byte eId)
{
   unsigned short result;
   // Read 1.1V reference against AVcc
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA,ADSC));
   result = ADCL;
   result |= ADCH << 8;
   result = 1126400L / result; // Back-calculate AVcc in mV

  /**
   * endpoint[eId]->member can be replaced by epVoltSupply.member in this case since
   * no other endpoint is going to use "updtVoltSupply" as "updater" function
   */

   // Update endpoint value
   epTable[eId]->value[0] = (result >> 8) & 0xFF;
   epTable[eId]->value[1] = result & 0xFF;
}

/**
  * updtTempHum
  *
  * Measure humidity and temperature and update endpoint
  *
  * 'eId' Endpoint ID
  */
const void updtTempHum(byte eId)
{
   int result;
   if ((result = dht11_ReadTempHum()) < 0)
     return;
   // Update endpoint value
   epTempHum.value[0] = (result >> 8) & 0xFF;
   epTempHum.value[1] = result & 0xFF;
}


No comments:

Post a Comment