FEZ XBee Sensor: Hat Trick

As mentioned at the end of my Watching the Watcher article, the Netduino Plant Light project is going to take a sharp turn at this point, losing both the Netduino and the Plant Light.  I’m going to spin off some of the code into a new project, a FEZ XBee Sensor.

Like its predecessor, the XBee Sensor is a .Net Micro Framework device, which uses an XBee wireless transceiver to post data to the Internet by way of a Python middleman.

I’m structuring the code to be more flexible, supporting a variety of sensors and logging to a variety of databases.  Personally, I’m using it to measure plant soil moisture, light levels, temperature and humidity, as described in the “Hardware Configuration” section below.

If you decide to use a different mix of sensors (as I’m sure you will), you’ll need to make a small change to the C# code, as shown in the Programmer’s Show and Tell section below.  I’m aiming for a more generic device configuration, where all  sensor devices run exactly the same code, and all sensor configuration is done through Python.

Since a new project gives me an excuse to start playing with new hardware, I’ve also switched from using the Netduino to a rival Micro Net Framework product, the FEZ Panda.

I’m not abandoning the Netduino: my own Netduino continues to perform its duties as a Plant Light Controller, and I’ll do my best to continue to support the Netduino in the XBee Sensor source code.  It’s relatively easy to switch the code between a FEZ and Netduino target.  I’ll point the code changes that are required in the Programmer’s Show and Tell section .

Also, the Python code used in this article is compatible with the Netduino Plant Light controller code from Watching the Watcher, so you can have both a Netduino Plant Light Controller and an XBee sensor reporting data to the Python code if you like, or even just the Netduino.

The FEZ Panda

The FEZ Panda is one of a line of products from GHI Electronics: Fez Mini, Panda, Panda II and Domino.  The Fez Mini is similar to the Netduino Mini — both mimic the form factor and pinout of the Basic Stamp — while the Pandas are similar to the Netduino.  The Domino is a more powerful beast, using a chipset that supports USB Host.

FEZ Panda II
FEZ Panda II

Compared to the Netduino, the Pandas (both versions I and II) have a few advantages that will come in handy when acting as a remote sensor.

1. More pins: 54 digital I/Os, as opposed to the Netduino’s (and Arduino’s) 13, and 3 COM ports to the Netduino’s 2.  More analog pins would have been even better, but the Panda only has 6, same as the other platforms.

2. Native code.  This one is huge: the .Net code can invoke “unmanaged” native code, which has full access to the microprocessor’s capabilities, including microsecond-level timing.  This eliminates the Micro Net Framework’s biggest disadvantage to the Arduino.

3. Ability to store data in flash memory.  The FEZ firmware includes a class that allows .Net code read/write access to 4K of flash memory, analogous to the Arduino’s Flash library.

4. More documentation!  This one might not excite you as much as it does me (whee!), but GHI’s TinyCLR site offers a ton of documentation covering pretty much every feature of the FEZ platform and the underlying Net Micro Framework.  I’d particularly like to point out the Beginner’s Guide to .Net Micro Framework, which I feel is still the best publication of any type covering the MNF, and much of which is also applicable to the Netduino.  A Tutorials section was recently added to the TinyCLR site, which has rapidly expanded to cover a lot of very useful features, again many of them applicable to the Netduino.  (Both the Beginners Guide and the Tutorials section can be found on the TinyCLR Support page).

Back in the Netduino: A Little Help From Its Friends article, I used an Arduino as a helper to the Netduino.  It handled a couple of actions that the Netduino (and Micro Net Framework) couldn’t do: read data from the DHT11 temperature/humidity sensor and saving settings to Flash memory.  The FEZ Panda can actually do both these things itself.    Smarter than the average bear!

By the way, the difference between the Panda and Panda II is that the latter contains a micro SD card socket, and adds female headers for most of the additional digital pins, which are repositioned to be accessible even when an Arduino shield is in place.  I’m using Panda Is (currently being sold off by GHI at the ridiculously low price of $15), but everything that I’m doing in this project will also work on a Panda II.   The code will work almost unchanged – all you have to do is remove the Project Reference to FEZPanda_… and replace it with FezPandaII_…, as shown in the screenshot.

Selecting Panda II Assembly
Selecting Panda II Assembly

Hardware Configuration

At this point, the XBee Sensor project is geared towards supporting analog sensors plus one particular digital sensor, the DHT11/DHT22 temperature and humidity sensor. I’m using the analog ports as moisture and light sensors, but any analog sensor that can run on 3.3V should work without code changes.

The XBee Sensors are intended to be used without displays, but when first configuring them it’s handy to connect an LCD to see what they’re doing (or failing to do). So, I added an optional “Debug LCD”, which displays the current sensor readings, as well as any Exceptions or other error messages.

I’ve written the code so that, if the LCD isn’t connected, it shrugs and keeps going.  However, if your device seems to behave erratically when the LCD is disconnected, you can disable use of the LCD by removing the DEBUG_LCD compiler flag (as shown in the Programmer’s Show And Tell section below).

You can also select the type of LCD using a compiler flag.  LCD support is basically the same as in the Netduino Plant Light Controller code, with the addition of the Adafruit i2c / SPI character LCD backpack — more details on that support are also in the Programmer’s Show And Tell section.

If you are using an LCD, you’ll probably want to add a button to D7, to toggle the backlight on or off.

Soil Moisture Sensors

The soil moisture sensors use the same approach as in the Garduino project.  I built mine from

  • A pair of galvanized nails.  I think any nails will do, as long as they’re galvanized and big-assed, I’m using Tree Island Gold 4” 20d Hot Dip Galvanized nails
  • 2 lengths of 20 AWG wire, long enough to go from the plant pot to the Panda
  • a 10K resistor, connecting the analog in to ground

As you can see from the photo, one end of each wire is soldered to a nail, then covered with heat shrink tubing to keep it attached tight.  The other end of the wires connect to the Panda.  One wire connects directly to 3.3V, and the other other wire is split: it connects directly to an analog port, then connects through a 10K resistor to ground.

Moisture Sensor Wiring - Click to Enlarge
Moisture Sensor Wiring - Click to Enlarge

I found that the screw connectors on the Adafruit Wing Protoboard is ideal for this setup, since the screw connectors firmly hold the wires in place , and the protoboard layout makes it easy to add the resistor-to-ground connection.  The Adafruit board also provides 4 spare screw connectors, in the upper-right of the above photo – I used mine to provide the extra 3.3V connections required for this project.

The Garduino actually uses 5V, but 3.3V works just as well for this purpose, with similar calibration.  My oldest moisture sensor has been in service for almost 3 months now, with no apparent degradation of the nails or weird behaviour in the voltage readings.  (No electrocuted plants either – the 10K resistor ensures that the current is too low to hurt either plants or humans).

The light sensor is a garden variety (nyuk nyuk) cadium sensor that uses the exact same circuit as the moisture sensors: one wire connected to 3.3V, and the other split between an analog pin and ground through a 10K resistor.

Here is what the XBee Sensor looks like with all its accoutrements:

FEZ XBee Sensor - Up and Running
FEZ XBee Sensor - Up and Running
Here is an alternative configuration.  This one uses a Serial LCD, the SeeedStudio Grove Base Shield, and connects the moisture sensor wires to a Grove Prototype Twig.  The prototype twig works pretty well for connecting the moisture sensors, since it has plenty of room for the resistor connections to ground, and it supports 2 sensors per twig.  However, it uses 5V by default, so I snipped the power cable and wired it to 3.3V instead.

FEZ XBee Sensor - The Next Generation
FEZ XBee Sensor - The Next Generation

Temperature/Humidity Sensor

I have the DHT11 from the A Little Help From Its Friends article connected to one of my XBee Sensor configurations, and the DHT11′s big brother, the DHT22, connected to another.

The code used to read from the 2 devices is identical – the only difference is how the .Net code parses the data to retrieve the temperature and humidity values.

As mentioned earlier, the Panda’s support for native “RLP” (Runtime Loadable Procedures) code means that it can handle the microsecond-level timing required by the DH22 and DHT11.

The RLP code that I’m using comes from this project on GHI’s TinyCLR site.  The description of the project only mentions the DHT11, but the RLP code works for the DHT22 too.

I’ve modified the code slightly to prevent an infinite loop if anything goes wrong with the communication, and added a few comments to explain why the code is doing what it’s doing. My modified version, along with a compiled .elf file and all of the files needed to build the .elf, can be downloaded from my Google Code project page.

(By the way, if you Google for the DHT11 or DHT22 datasheet, you’ll probably find a “Chinglish” version that’s awfully hard to understand.  A better datasheet can be found here: it refers to the RHT21, but that’s identical to the DHT22 as far as the communication is protocol is concerned).

The native code isn’t something that you copy and paste into Visual Studio alongside your C# code – instead, it is built using a separate piece of open source software with the charming name of Yagarto (Yet Another GNU ARM Toolchain).

An introduction to generating RLPs with Yagarto can be found in TinyCLR’s tutorial.  I’d recommend you use this more extensive tutorial instead, which covers a few small but important steps skipped by the TinyCLR tutorial.

However, if you’d rather not learn Yet Another Anything at this time, the good news is that you can just use the .elf file that is included with the source code for this article.  It should work with any DHT11 or DHT22 connected to any of the FEZ devices that use the USBizi100 chipset: Fez Mini, Panda, or Panda II.

You will have to get your own unlocking code from GHI, to paste into the Visual Studio project. It’s a quick and painless, if somewhat mystifying, process:

1. Create a MyGHI account here: http://www.tinyclr.com/register/

2. Once registered, login and click on the My Account link.

3. Click on the RLP Access Code link

4. Click the checkbox to agree to the “Technology Access Agreement” (which I assume is the whole point of this process), click Submit and your access code will be e-mailed to you.

The access code is pasted into the Visual Studio project, as shown in the Programmer’s Show and Tell section below.  The first time you run the unlock command on a FEZ device, it sets aside 10K for RLP use, then reboots.  The device remains unlocked after that, until the next time you update the firmware.

I’m not sure what exactly the unlock command does to your FEZ device, but based on my experience it’s a safe thing to try.  It doesn’t cause any instability or change the way that you debug your code.  If you decide you’d rather have the 10K back for .Net code, then you can remove RLP support by reloading the FEZ firmware.

I should point out one “gotcha” regarding the DHT11/DHT22 support, which probably applies to any RLP code that is timer-dependent.  You need to invoke the RLP subroutines from the main thread of the .Net application, not from a timer or event handler.  When I tried reading invoking the code from the timer thread that reads the other sensors, I found that the code ran slightly too slowly to keep up with the signals being sent from the DHT22 (which explains why I modified the code to break out of an infinite loop).  When invoked from the main thread, the code is rock solid – I haven’t noticed any failed readings in the weeks that I’ve been running it.

You might be wondering if RLP support is worth all the trouble.  If all you want is to support the DHT11/22, then you actually have an alternative to RLP: this TinyCLR Code project describes an alternative approach using just managed C# code and a clever hardware hack (which would probably also work with a Netduino, by the way).  However,  I really think RLP is worth learning, since it opens up support for all kinds of accessories previously off-limits to Micro Net Framework devices, such as Graphical LCDs and audio input.  For examples, do a search of “RLP” in the TinyCLR Code section.  Pretty much anything that the Arduino supports can (in theory) also be supported for Fez using RLP.

XBee

The XBee configuration at both the FEZ and Python end is the same as in the Netduino Meets World article, with one exception. The Python code will now be using the XBee in API mode, and its XBee (but not the one at the FEZ end) must therefore have its API mode enabled.

The easiest way to do this is to open a console connection to the XBee (as described in Netduino Meets World), and enter

+++
ATAP 1
ATWR

Or, if you prefer, you can use the X-CTU Windows application to turn on API mode.

X-CTU setting for API Mode
X-CTU setting for API Mode

Note that the XBee address at the FEZ still needs to be hard-coded as “1”, even if you are using multiple XBee Sensors, or both XBee Sensors and a Netduino Plant Light Controller.  This isn’t a problem yet, since the FEZ/Netduino code doesn’t care what it receives, and the Python code doesn’t use the address to identify what it is receiving.  That will change in a future stage of the project

Python Middleware

The Python code has the same role as in the Watching the Watcher article: it forwards the sensor readings to a data repository on the Internet.

I’ve expanded the Python code to support 2 different repositories: Nimbits and Pachube.  I’ve also expanded the configuration file to give you a bit more control over which sensors are posted to which sites.

The Python code is compatible with the Netduino Plant Light controller that was created in my previous blog posts.

You can download the Python code and sample configuration file from my Google Code project page.  Note that I’ve renamed them to better reflect their role: SensorRelay.py.

The sample configuration file looks like this:

# Configuration file for SensorRelay.py
# ----------- General App Settings ------------
# XBEEPORT = \.COMxx <-- on some systems, Windows COM port 
#   must be specified in this format
XBEEPORT = COMxx
# USBPORT = COMyy
LOGFILENAME = SensorRelay.log
LOGDATA = False
SENDTIME = True
DEBUG = True
# -------- Sensor Settings -----------
#  - sensor line format is <Netduino Sensor ID> 
# = <Nimbits Data Point ID OR Pachube Datastream ID>
#[,Update Interval in seconds]
[Nimbits 1]
NIMBITS_SERVER = http://app.nimbits.com
NIMBITS_USERID = you@wherever.com
NIMBITS_API_KEY = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
UPDATE_INTERVAL = 300
A1 = ASensor,60
A2 = AnotherSensor
T1 = TemperatureSensor,1500
H1 = HumiditySensor
[Pachube 1]
PACHUBE_FEED_ID = nnnnn
PACHUBE_API_KEY = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
UPDATE_INTERVAL = 300
A1 = ASensor,60
A3 = AThirdSensor
T1 = TemperatureSensor
H1 = HumiditySensor

The settings are:

XBEEPORT = The serial port that the XBee is connected to.  On a Linux box, this would have a different format, like /dev/ttyUSBn.

USBPORT = The (very optional) serial port that an XBee Sensor is directly connected to.  (Technically, this would make it a FEZ USB/XBee Sensor – nice acronym!)

Note that you can use an XBEEPORT or a USBPORT, or both.  Just comment out or delete the one you aren’t using.

In the Python code in the Watching the Watcher article, I mentioned that the XBEEPORT setting could actually be set to the port of a USB-connected Netduino.  Why did I break that out to a separate USBPORT setting now?  The Python code now sends data to the XBEEPORT using the lower-level XBee API, while it still uses a generic Serial interface to a USB-connected device.

LOGFILENAME – The filename (or full path and filename) to which sensor data is logged in CSV format.  Note that, unlike the Python code in the Watching the Watcher article, errors and debug messages aren’t written to this file – they are written to a file named SensorRelayError.log instead, in the directory from which SensorRelay.py is run.

LOGDATA – This is used to enable or disable the logging of data to LOGFILENAME.   If your Python code is running on a ultra low power device like the Beagleboard, with just an SD card as its disk drive, then turning off data logging saves some wear-and-tear on the SD card.

SENDTIME – If true, the date and time will be sent to the XBeeSensor each minute.  You’ll want to leave this turned off if you’re using an XBee Sensor, but you should turn it on if you’re using the Netduino Plant Light Controller from my previous blog posts.

DEBUG – If true, debug messages will be written to both the console and the XBeeSensorError.log file.

The sensor configuration sections of the configuration file must always start with a name in square brackets, like “[Nimbits 1]”.  (The name can be whatever you like, actually, as long as you don’t use it more than once).  There must be at least 1 sensor configuration section, but you can have multiple sections if you want to send your data to multiple data repositories.

Personally, I use three: 1 for the public Nimbits app server (to test my code with the latest version of Nimbits), one for my personal Google App Server installation of Nimbits (to which I log more frequently), and one for Pachube, so that I can play around with its API too.

The Nimbits settings are identical to the ones used in the Watching the Watcher article – please see it for details.

The Pachube settings are almost the same as the Nimbits settings, but the lingo is somewhat different.  For details on getting started with Pachube, see my Tweet-A-Watt: Beyond the Twitter article

PACHUBE_FEED_ID = The numeric feed ID.  (A Pachube Feed is a group of datastreams.  A datastream is the Pachube equivalent of a Nimbits Data Point.)  If you want to send different sensor readings to different feeds, you should create multiple Pachube sections in your configuration file (e.g. [Pachube 1], [Pachube 2]).

PACHUBE_API_KEY = A Pachube API key that you’ve generated, and which has write access to your feeds.

UPDATE_INTERVAL = As with Nimbits, this determines how often the sensor data will be posted to Pachube, in seconds.  Note that Pachube has a rate limiter that depends on the type of plan you have.  Each datastream update counts as a separate API call, so if you have 5 datastreams, that is 5 API calls.

SENSOR_ID = DATASTREAM_ID[, UPDATE_INTERVAL] = Determines which sensor reading received from the XBee Sensor will be sent to which Pachube datastream, optionally overriding the default update interval.  For example

A1 = ASensor,60

…means that sensor A1 received from the XBee Sensor will be sent to Pachube Datastream ASensor, every 60 seconds.

Programmer’s Show and Tell

.Net Code

As before, you can get the .Net code from my Google Code page in either of 2 ways:

  1. If you are familiar with Subversion, you use any SVN client (my favorite is TortoiseSVN) to get a copy of all the project files.  The SVN URL is https://gigamega-micro.googlecode.com/svn/trunk, and the code for this article is in the XBeeSensor article.
  2. Or, download the good old .zip file from the Downloads section of the Google Code project. Here is a direct link to the code for this article.

I’m using the MicroLiquidCrystal library to add support for an i2c-connected LCD. The solution file will look for this project, and grumble if it can’t find it.  If you aren’t using an i2c LCD, you should remove the Reference to the MicroLiquidCrystal library from the project References list.  Otherwise, you’ll need to download the MicroLiquidCrystal source code and store it in the XBeeRemoteSensor solution folder..

While the .Net code is a totally separate project from the Netduino Plant Light controller, a lot of its contents will be familiar if you’ve read the Show and Tell sections of my previous blog posts.

Switching from the Netduino to the FEZ doesn’t require many changes to the code.  The underlying .Net Micro Framework codebase is 100% identical, and very little of the XBee Sensor code makes use of features that are specific to the Netduino or FEZ.  Where it does, I’ve used “#if” conditional compiler flags to include the correct code.

By the way, I’ve switched to putting compiler flags in the Project properties, as shown in the screenshot below, rather than hard-coding them with #define statements.  The default flag is “FEZ” – if you want to use a Netduino instead of a FEZ device, remove “FEZ” from the Conditional Compilation Symbols

Compiler Flags
Compiler Flags

In addition to getting the compiler flag right, the project’s References need to point to the right set of assemblies. For the FEZ Panda, use GHI’s libraries; for the Netduino, use SecretLabs’.  Your references lists should look like the one below – if you’ve got exclamation marks next to the GHIElectronics libraries, then perhaps you haven’t installed the FEZ SDK yet?  Otherwise, any problems are likely due to differences in the versions of the GHI libraries that I’m using and the ones you’re using – just delete the 3 GHI libraries from the References list, then add them back from the list on your PC.

Project References List
Project References List

The compiler flags take care of the rest.  For example, the “using” statements at the top of each class ensure that the proper assemblies are being used:

#if FEZ
using GHIElectronics.NETMF.FEZ;
using GHIElectronics.NETMF.Hardware;
#if DHT22 || DHT11
using GHIElectronics.NETMF.Native;
#endif
#else
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;
#endif</pre>

Near the top of Program.cs, you’ll find the following code:

// !!!!!!!!!!!!!!!! USER MUST SET THE FOLLOWING 3 LINES!!!!!!!!!!!!!!!!!!!!!!!

const int NUM_ANALOG_SENSORS = 5; // number of analog sensors

#if FEZ

static FEZ_Pin.AnalogIn[] sensorPins = new FEZ_Pin.AnalogIn[] { FEZ_Pin.AnalogIn.An0, FEZ_Pin.AnalogIn.An1,

FEZ_Pin.AnalogIn.An2, FEZ_Pin.AnalogIn.An3, FEZ_Pin.AnalogIn.An4};

#else

static Cpu.Pin[] sensorPins = new Cpu.Pin[] { Pins.GPIO_PIN_A0, Pins.GPIO_PIN_A1, Pins.GPIO_PIN_A, Pins.GPIO_PIN_A3, Pins.GPIO_PIN_A4 };

#endif

static string[] sensorIDs = new

string[] { "M1", "M2", "M3", "M4", "L1", "T1", "H1" };

// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

By default, this is configured for 5 analog sensors, A0 – A4, as well as a DHT22 providing temperature and humidity readings.  You’ll need to modify this to match your own configuration.  Note that, if using a DHT11 or DHT22, the 2 sensor IDs for temperature and humidity should be added to the end of the sensorIDs array.  The tags you use for sensorIDs can be anything you like, but they need to match the sensor IDs in the Python configuration file, SensorRelay.cfg.

Note that the above code uses a different syntax to reference analog pins on a FEZ device as compared to the Netduino.  This difference in syntax applies to the digital pins too.  While the pins might be in the same location on the outside, they map to very different CPU pins internally.

As mentioned earlier, I’ve added support for the Adafruit i2c/SPI Character LCD backpack.  This required very little code, since the backpack is supported by the MicroLiquidCrystal .Net library that I used in the Netduino Plant Light Controller code.

The backpack is enabled by adding MLC_I2C to the compiler flags.

There is only 1 I2C port on the FEZ devices (as with the Netduino), and the .Net Micro Framework is able to figure out which pins the i2c interface uses.  So, the i2c LCD initialization code just passes the number of rows and columns:

lcd = new clsLCD_MLC(4, 20);

Beyond that, the LCD interface is identical to the one used by parallel LCDs, as described in earlier articles about the Netduino Plant Light Controller.  One catch, though: I2C is quite slow compared to other LCD interfaces, and if you have multiple threads writing to the LCD, there is a good chance that one will interrupt another in mid-communication, causing the LCD to hang go all garbly.  To prevent this, I use the Monitor method of .Net’s Threading library:

static string lcdLock = "LockMe!";

. . .

try
{
	if (blnDisableLCD)
	{
		return;
	}

	// prevent other thread from writing to lcd at same time (mandatory for I2C LCD)
	Monitor.Enter(lcdLock);

	. . .


	for (int i = 0; i <= intLastRow; i++)
	{
		lcd.SelectLine((byte)(i + 1), true);
		lcd.WriteStringToLCD(strLCDBuffer[i]);

	}
finally
{
	Monitor.Exit(lcdLock);
}

Support for the DHT11 or DHT22 temperature/humidity sensor is enabled by adding the “DHT11″ or “DHT22″ compiler flag.  As mentioned earlier, this makes uses of the FEZ support for native RLP code.  The DHT11/DHT22 code won’t work at all if you’re using a Netduino.

All RLP code is initialized in basically the same way:

-          Call RLP.Enable

-          Call RLP.Unlock, passing it the values that you received in the e-mail.  Just copy and paste the “RLP.Unlock” statement from the e-mail into the code.

-          Load the RLP code (an ELF file) from your projects Resources section

-          Call GetProcedure for each RLP function that you want to call.


RLP.Enable();

//TODO - If your device isn't already unlocked, 
//  you MUST paste YOUR ID and byte array into the code below
//RLP.Unlock();

byte[] elf_file = Resources.GetBytes(Resources.BinaryResources.dht11_rlp);
RLP.LoadELF(elf_file);

RLP.InitializeBSSRegion(elf_file);

ReadDHT = RLP.GetProcedure(elf_file, "ReadDHT");
DHTSetup = RLP.GetProcedure(elf_file, "Setup");

// We don't need this anymore
elf_file = null;
Debug.GC(true);

If the initialization succeeds, you can then call the DHTSetup function in the RLP code, passing it the pin that the DHT11 or DHT22 is connected to:


// Call setup function - use Di4 for DHT22
if (DHTSetup != null)
{
	success = DHTSetup.Invoke((int)(FEZ_Pin.Interrupt.Di4));
}
if (success == 0)
{
	Debug_WriteToLCD("DHT Setup failed!");
	DHTSetup = null; // disable use of DHT22
}
else
{
	// give DHT time to stabilize
	Thread.Sleep(1000);
}

To read the temperature and sensor data, call the ReadDHT function.  It returns a 5-byte array:

int intResult = ReadDHT.Invoke(bytArray);

Up to this point, the code used for the DHT11 and DHT22 is 100% identical.  The only difference is how the 5-byte array is processed to extract the temperature and humidity:


if ((intTotal & 255) == bytArray[4])
{

#if DHT22
	int intValues = 256 * (bytArray[2] & 0x7f) + bytArray[3];
	if ((bytArray[2] & 0x80) != 0)
	{
		intValues *= -1;
	}
	fltTemperature = intValues;
	fltTemperature /= 10;
#endif
#if DHT11
	fltTemperature = bytArray[2];
#endif


	Debug_WriteToLCD("Temp " + fltTemperature.ToString("F1"));

#if DHT22
	intValues = 256 * bytArray[0] + bytArray[1];
	fltHumidity = intValues;
	fltHumidity /= 10;
#endif
#if DHT11
	fltHumidity = bytArray[0];
#endif

	Debug_WriteToLCD("Hum " + fltHumidity.ToString("F1"));
}
else
{
	Debug_WriteToLCD("Checksum failed");
}

Python Code

The Python code is based on that described in the Watching the Watcher article, but with some notable improvements.

I’ve rewritten the logging code to follow proper Python standards.  So, instead of dumping error messages and debug information in the same file that contains the sensor data, I’m using the standard Python logging library:


logging.basicConfig(level=logging.DEBUG,

format='%(asctime)s %(levelname)s %(message)s',

filename='SensorRelayError.log')

log = logging.getLogger()

Note that you can change the level of logging, and the log file name, by changing this line of code.  For example, if you wanted to have debug messages sent just to the console, but not the log file, change logging.DEBUG to logging.ERROR.

Exception logging now follows Python standards as well, with the full stack trace being written to the log.  For example:


try:

    . . .

except:

    log.exception('Error sending to pachube, datapoint ' + dataPoint)

The resulting error message in the log includes all the fixings:

2011-09-19 17:40:06,180 ERROR Error sending to pachube, 
   datapoint PlantLight1
Traceback (most recent call last):
File "SensorRelay.py", line 51, in sendToPachube
pac.put()
File "build/bdist.linux-armv7l/egg/eeml/datastream.py", line 45, in put
conn.request('PUT', self._url, self._eeml.toeeml().toxml(), 
   {'X-PachubeApiKey': self._key})
File "/usr/lib/python2.6/httplib.py", line 914, in request
self._send_request(method, url, body, headers)
File "/usr/lib/python2.6/httplib.py", line 951, in _send_request
self.endheaders()
File "/usr/lib/python2.6/httplib.py", line 908, in endheaders
self._send_output()
File "/usr/lib/python2.6/httplib.py", line 780, in _send_output
self.send(msg)
File "/usr/lib/python2.6/httplib.py", line 739, in send
self.connect()
File "/usr/lib/python2.6/httplib.py", line 720, in connect
self.timeout)
File "/usr/lib/python2.6/socket.py", line 547, in create_connection
for res in getaddrinfo(host, port, 0, SOCK_STREAM):

The Xbee is no longer being treated as a generic serial interface, as it was in the Watching the Watcher article.  Instead, I’m using the Python XBee library, which reads and writes data using the XBee’s API.

To be honest, there is no great advantage to using the XBee API at this point.  I’ve found it to be quite stable – after the Python code opens the XBee port after startup, the port stays open and keeps working regardless of what’s going on at the sensor end of the connection.  The serial port interface to the XBee was just as stable. However, the API lets me send data to a specific remote sensor device, and lets me know which remote sensor device I’m receiving data from, something which will be necessary later in the project.

The code which communicates with the XBee is similar to the serial interface described in the Show and Tell section of Watching the Watcher.  The only significant difference is that I can now define a callback to activated when data is received, rather than having to poll for incoming  data:


if XBEEPORT:
    try:
        serXBee = serial.Serial(XBEEPORT, BAUDRATE, timeout=TIMEOUT)
        serXBee.close() # workaround for known problem when running on Windows
        serXBee.open()
        xbee = XBee(serXBee, callback=readXBeeData)

The callback function receives a “frame” as its parameter.  To get to the sensor data sent by the FEZ (i.e. the same data that would be received from the XBee when it is used as a serial device), just access the frame.data property.  Note that the frame has a bunch of other potentially useful properties, as shown in the code below.


def readXBeeData(frame):
    global buf
    try:
        frame_id = frame['id']
        # source address is 2-bytes binary (e.g. x00x01)
        # this also works: source_addr = struct.unpack('>h', frame['source_addr'])
        source_addr = ord(frame['source_addr'][0]) * 256 + ord(frame['source_addr'][1])
        # rssi (signal strength) is 1-byte binary
        rssi = ord(frame['rssi'])
        data = frame['rf_data']
        if DEBUG:
            print "read_frame, id=", frame_id, ", source_addr=", source_addr, ", rssi=", rssi, ", data=", data
            log.debug("read_frame, id=" + str(frame_id) + ", source_addr=" + str(source_addr) + ", rssi=" + str(rssi) + ", data=" + data)
        if frame_id == "rx":
            processXbeeData(data)

When sending data to the FEZ, you need to package the data into a frame.  I found that the syntax for doing this is surprisingly unGooglable: the Python XBee library is more commonly used to send the XBee a command (e.g. set D2 high), not a custom data string.  The trick is to format the data in a “TX” command.  Note that I’m adding an ending null to the data – this makes the Python code compatible with the Netduino Plant Light Controller code used in previous blog posts.

        if xbee:
            strData = strPrefix + ":" + strCommand
            # HACK - append null to data to make it look like serial data to the other end
            xbee.send("tx", dest_addr = 'x00x01', data=strData + 'x00')

When sending data to Pachube from Python, I originally used the python-eeml library, as described in the Tweet-A-Watt: Beyond the Twitter article.  However, that library still uses the Pachube V1 API, which was limited to numeric datastream IDs.  Since the XML EEML format contains a bunch of optional data that I’m not using, I decided to simplify things and use Python’s standard urllib2 libraryinstead:


        # Note - the following codes uses the V2 Pachube API and CSV data format
        url = 'http://api.pachube.com/v2/feeds/' + siteconfig["PACHUBE_FEED_ID"] 
           + '/datastreams/' + dataPoint + '.csv?_method=put'
        # HACK round to 3 decimal places and drop trailing zeros : technically not needed, but makes Pachube output nicer looking
        data = ("%.3f" % floatValue).rstrip('0').rstrip('.')
        headers = {'X-PachubeApiKey': siteconfig["PACHUBE_API_KEY"]}
        if DEBUG:
            print url
            print data
            print headers
        req = urllib2.Request(url, data, headers)
        try:
            response = urllib2.urlopen(req)
        except urllib2.HTTPError, e:
            log.exception('Error code ' + e.code + ' sending to pachube, datapoint ' + dataPoint)
            return False
        except urllib2.URLError, e:
            log.exception('Reason code ' + e.reason + ' sending to pachube, datapoint ' + dataPoint)
            return False

Note the code adds an  “X-PachubeApiKey” setting to the HTTP header, something that isn’t well documented for the urllib2 library.

Wrapping Up

Whew, another super-sized article.  Believe it or not, it takes even longer to write than it does to read!  The upside is that I’ve had the code running for over a month now, so I can report that the FEZ XBee Sensor is a reliable platform with no[t too many] bugs.

I’m quite impressed with the FEZ Panda.  Its support for native code and for Output Compare (another Arduino feature that isn’t supported by the .Net Micro Framework) opens up a lot of new opportunities. GHI updates the firmware quite frequently – more often than Secret Labs does with Netduino – and I suspect they will be first out of the gate with support for the newly released .Net Micro Framework 4.2

Next, though, I’m going to turn my attention to the other end of the data stream, the data repositories.

This entry was posted in .Net, Electronics, Programming and tagged , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>