XBee Radios in .NET Gadgeteer Devices

XBee radios are inexpensive and they can be embedded in all kinds of devices.  XBees can be networked so that a failure of one radio does not impar communication between and among others in the network.  Their range exceeds that of Bluetooth connections.  The article Zigbee Networking with XBee Series 2 and Seeed’s Products provides a quick overview of XBee functionality. Robert Faludi‘s book titled Building Wireless Sensor Networks is an excellent tutorial on using XBees in Arduino devices.  This article demonstrates an extensible scenario for using XBee radios with .NET Gadgeteer devices.

The examples in this post demonstrate XBee radios in the AT communication mode, which is the human readable control protocol.  XBee radios can also use API protocol.  Either method requires learning command details and some basic configuration settings.  You’ll want to get the X-CTU tool available from Digi and an Explorer dongle.

This example implements two .NET Gadgeteer devices with XBee radios.  A sensor device sends notifications to another device, which acts as a relay station.  The relay has Internet access via a GHI Electronics WiFi RS21 Module and it has an electrical actuator circuit that closes upon notification from any number of sensor devices.  When a sensor device sends a notification, the relay device turns on the actuator switch, which closes a circuit that can run anything within the power ranges of the Seeed Studio Relay Module for .NET Gadgeteer, up to DC 10 Amps/ 250 Volts, or AC 15 Amps/ 120 Volts.

The two XBee radios that this example uses were configured using the X-CTU utility and the XBee Explorer dongle from SparkFun Electronics as shown in the following illustration (click to enlarge).

XBee Explorer Dongle

XBee Explorer Dongle

Insert the XBee radio with pin 1 aligned to the upper left of the dongle, which has sockets 1 and 20 labeled to correspond with the labels on the XBee circuit board

With the XBee in its socket, we can begin working with X-CTU.  It works very well, often enough to get things done, but it doesn’t always work as expected, so we need to mention a few workarounds.

Configure and Flash XBee Radios using X-CTU

Plug the dongle into an open USB port on a computer with X-CTU installed and then start X-CTU.  Select the USB serial port to which the dongle is plugged.

X-CTU with Dongle on COM9

X-CTU with Dongle on COM9

Click the Test/Query button.  If the dialog box that appears says “Unable to communicate with modem”, close the dialog and click Enable API.  To successfully read the modem, X-CTU has to be in the same mode as the current flashing on the XBee radio (We will use the AT mode in this example, but the radio may have shipped with API flashing).

When pushing the Test/Query button results in a dialog box like the following, we can proceed to the next step in configuring and flashing the XBee

X-CTU Read Modem

X-CTU Read Modem

Go to the Modem Configuration tab of X-CTU.

X-CTU Modem Configuration

X-CTU Modem Configuration

Click the Read button, and, if all goes well, the results will be displayed as in the following illustration.

X-CTU Normal Read Modem Configuration

X-CTU Normal Read Modem Configuration

Now we can set the configuration parameters in X-CTU and write them into the flashing of the XBee radio.  We have to select the XBee modem, the Function Set, and set the PAN ID, the Destination Address High, and the Destination Address Low, of the XBee radio.   The high and low bytes of XBee radios are printed on the radios.  The high byte, as shown in the following illustration, is 0013A200.  This high byte is apparently the same for all X-Bee radios.  The low byte of one of my radios, in the following illustration, is 40790728 (click to enlarge).

XBee Serial Number High and Low Bytes

XBee Serial Number High and Low Bytes

The next illustration shows a Modem setting of XB24-ZB.  My XBee radio is labeled XB24-Z7WIT, but Bob Faludi’s book says it can be configured as XB24-ZB, and, he’s right, it works.  The Function Set drop-down list contains a bunch of options, but the only ones we’ll need are ZIGBEE COORDINATOR AT and ZIGBEE ROUTER AT

We could as well use ZIGBEE END DEVICE AT for one of the radios.  Every network of XBee radios must have one and only one Coordinator.  The network can have many Routers and End DevicesEnd Devices send and receive messages, but they cannot relay messages from one XBee to another.

X-CTU XBee Function Set

X-CTU XBee Function Set

The tool should read the high and low bytes of the serial number, so we don’t have to set them.  The following illustration shows the text box for Destination Address Low in edit mode.

X-CTU Set Destination Address Low

X-CTU Set Destination Address Low

The Destination Address High is 0013A200 for all X-Bee modules, but we have to set the Destination Address Low to the low byte of the Serial Number of the XBee radio to which this radio will send messages.  We also have to set the PAN ID of both radios to the same number; this network identifier can be any number; this example sets it to 1234.

When the modem, PAN ID,  Function Set, Destination Address High, and Destination Address Low are correctly specified in X-CTU, we’re ready to write the configuration to the flashing of the XBee radio plugged into the dongle.  Click the Write button.  The process will begin with something like the following:

X-CTU Flash XBee Write New Flashing

X-CTU Flash XBee Write New Flashing

But it may end with something like this:

X-CTU Flash XBee Write New Flash Error setting AT parameters

X-CTU Flash XBee Write New Flash Error setting AT parameters

In this case, I think, the problem is that we began with API parameter settings and tried to flash AT parameters.  Following the instructions in the error message, we can click Show Defaults in the Parameters section of X-CTU.  This will remove the serial numbers we carefully edited in the previous steps, so we’ll have to put them back and try again.  You get the idea that configuration details take more time than programming the radios in a .NET Gadgeteer application.  In this case I had to go back to the PC Settings tab of X-CTU and uncheck the API option; we apparently succeeded in writing the AT setting during that failed attempt.  The second attempt to re-flash this board worked for me. 

You might run into a situation where X-CTU cannot communicate with the modem and the board won’t take any new flashing.  If that happens, I have a workaround that seems to help.  Briefly, it goes like this: unplug the USB cable with the dongle; start X-CTU; (the COM port that was previously selected will not show in the list); click the User COM Ports tab on the lower section of X-CTU; in Add User COM Port, add a COM port (you may have to close X-CTU and plug the dongle long enough to find out which port USB is using); add the user COM port as shown in the following illustration.

X-CTU Repair Flash XBee

X-CTU Repair Flash XBee

 After adding the user COM port, it will appear and you can select it in the COM Port Setup list.

X-CTU Repair Flash XBee 2

X-CTU Repair Flash XBee 2

Select or deselect the API option depending on the most recent flashing.  Click the Test/Query button.  If the test succeeds, you should be able to re-flash the board from the Modem Configuration tab of X-CTU.  

After you set the Modem and Function Set, be sure to click Show Defaults before you set the PAN ID and destination addresses.  Then try again to write the configuration.  I spent several hours with these procedures, so don’t be surprised if you have to work through this more than once.  You have to do it for the other radio, at least.

Build the Sensor Device using .NET Gadgeteer XBee Adapter

The network of .NET Gadgeteer devices we’re building includes sensor devices and a relay device that receives notifications from the sensor devices.  The relay device activates an electrical circuit or sends data to the Internet.  This is a very versatile scenario. There can be any number of sensor devices.  The relay device can actuate numerous kinds of electrical circuits and send notifications to Web services.  The relay can receive data from Internet users, which is then radioed to the sensor devices to set state on the sensors.  The number of radios in the network limits the communication range of the sensors, but their reach via the Internet is world wide.

The sensor we use in this example is the .NET Gadgeteer compatible Accelerometer by Seeed Studio.   The accelerometer registers multi-axis magnitude and direction of proper acceleration as a vector quantity. If that is too much to swallow, go back to the accelerometer link. An accelerometer can be used to sense orientation, coordinate acceleration, vibration, shock, and falling.  The sensor device containing the accelerometer could be mounted on a fence or gate to detect motion and send notifications when it is disturbed from the stationary position.  Any number of sensors could be used on this model, such as the Passive Infrared Sensor, the Light Sense Module, or the Moisture Sensor, all from GHI Electronics

The following illustration from the .NET Gadgeteer Designer shows the Seeed Accelerometer Module and the GHI XBee Adapter Module for the XBee radio that sends notifications.  The Seeed Oled Display Module  is technically not necessary, but it is useful for testing (click to enlarge).

Sensor Device Modules in .NET Gadgeteer Designer

Sensor Device Modules in .NET Gadgeteer Designer

The code that runs this device is verbose, but it is actually quite simple, because we are using the AT mode to send messages between the XBee radio on the sensor device and the relay device.  The core of the application is the Gadgeteer.Interfaces.Serial assembly.  We instantiate the Serial Interface from the xBee object as follows:

    xBee.Configure(9600, GT.Interfaces.Serial.SerialParity.None,
        GT.Interfaces.Serial.SerialStopBits.One, 8);

    serial = xBee.SerialLine;
    serial.Open();
    serial.LineReceived +=
        new GT.Interfaces.Serial.LineReceivedEventHandler(serial_LineReceived);
    serial.AutoReadLineEnabled = true;

Then we set a timer and request an accelerometer measurement in the tick event.

    void timer_Tick(GT.Timer timer)
    {
        accelerometer.RequestMeasurement();
    }

In the Accelerometer.MeasurementComplete event handler, we check for acceleration on the x axis.  Greater than .05  specific force, positive or negative, indicates some disturbance of the sensor.

    void accelerometer_MeasurementComplete(Accelerometer sender,
                                    Accelerometer.Acceleration acceleration)
    {
        if(acceleration.X > .05 || acceleration.X < -.05)
            serial.WriteLine("XBee3 - Acc X: " + acceleration.X.ToString() +
                "    Y: " + acceleration.Y.ToString() +
                "    Z: " + acceleration.Z.ToString());
    }

The prototype device is shown in the following illustration (click to enlarge).

Accelerometer Sensor Device

Accelerometer Sensor Device

The complete Program.cs file is shown in the following code block.

using Microsoft.SPOT;

using GT = Gadgeteer;
using Gadgeteer.Modules.GHIElectronics;
using Gadgeteer.Modules.Seeed;

namespace XBee3
{
    public partial class Program
    {
        GT.Interfaces.Serial serial;
        uint yIndex;
        GT.Timer timer;

        void ProgramStarted()
        {
            accelerometer.MeasurementComplete +=
                new Accelerometer.MeasurementCompleteEventHandler(accelerometer_MeasurementComplete);

            button.ButtonPressed +=
                new Button.ButtonEventHandler(button_ButtonPressed);

            xBee.Configure(9600, GT.Interfaces.Serial.SerialParity.None,
                GT.Interfaces.Serial.SerialStopBits.One, 8);

            serial = xBee.SerialLine;
            serial.Open();
            serial.LineReceived +=
                new GT.Interfaces.Serial.LineReceivedEventHandler(serial_LineReceived);
            serial.AutoReadLineEnabled = true;

            yIndex = 1;
            timer = new GT.Timer(500);
            timer.Tick += new GT.Timer.TickEventHandler(timer_Tick);

            Debug.Print("Program Started");
        }

        void accelerometer_MeasurementComplete(Accelerometer sender,
                                        Accelerometer.Acceleration acceleration)
        {
            if(acceleration.X > .05 || acceleration.X < -.05)
                serial.WriteLine("XBee3 - Acc X: " + acceleration.X.ToString() +
                    "    Y: " + acceleration.Y.ToString() +
                    "    Z: " + acceleration.Z.ToString());
        }

        void timer_Tick(GT.Timer timer)
        {
            accelerometer.RequestMeasurement();
        }

        void serial_LineReceived(GT.Interfaces.Serial sender, string line)
        {
             // This event handler is mainly for setup and testing of the sensor device.
            if (line != null)
            {
                oledDisplay.SimpleGraphics.DisplayText(line,
                    Resources.GetFont(Resources.FontResources.small), GT.Color.Red, 1, yIndex);

                yIndex += 10;
            }
        }

        void button_ButtonPressed(Button sender, Button.ButtonState state)
        {
            if (!button.IsLedOn)
            {
                accelerometer.Calibrate();

                button.TurnLEDOn();

                oledDisplay.SimpleGraphics.DisplayText("Ready to send or receive",
                    Resources.GetFont(Resources.FontResources.small), GT.Color.Red, 1, yIndex);

                yIndex += 10;
                timer.Start();
            }

            else
            {
                timer.Stop();
                button.TurnLEDOff();
            }

        }
    }
}

Build the .NET Gadgeteer XBee Radio Relay Device

The XBee radio on the device that receives notifications from the sensor device, or devices, also uses an object of type GT.Interfaces.Serial.  We instantiate the Serial interface as previously, but in this case the GT.Interfaces.Serial.LineReceived delegate is the main event instead of only a testing convenience.

    serial = xBee.SerialLine;
    serial.Open();

    serial.LineReceived +=
           new GT.Interfaces.Serial.LineReceivedEventHandler(serial_LineReceived);

When a notification is receieved from a sensor device, the only essential part of the following code is the final line, which turns on the relay circuit. The relay can turn on any DC or AC circuit within the power range of the Seeed Studio Relay Module, up to DC 10 Amps/ 250 Volts, or AC 15 Amps/ 120 Volts.

    void serial_LineReceived(GT.Interfaces.Serial sender, string line)
    {
        if (line != null)
        {
            if (225 < yIndex)
            {
                // Clear if text is near bottom of display.
                display.SimpleGraphics.Clear();

                yIndex = 1; // Reset output to top of display.
            }

            display.SimpleGraphics.DisplayText(line,
                Resources.GetFont(Resources.FontResources.small), GT.Color.Red, 1, yIndex);

            yIndex += 10;
        }

        // Close the circuit on relay1 to start a motor or power any electrical device.
        relays.Relay1 = true;
    }

The rest of the code for the .NET Gadgeteer XBee relay device sets up the GHI Electronics WiFi RS21 Module in order to relay the sensor alerts to a Web service and/or receive state information from an Internet user. The following code only blocks out the Web request.  The request starts a non-blocking asynchronous process that sends and receives data to/from a Web service. The service can be built using the Windows Communication Foundation (WCF) REST service template for C# and version 4.0 of the .NET Framework.

For more information about using the WCF REST Template with .NET Gadgeteer devices, see Sending .NET Gadgeteer Sensor Data to a REST Web Service. For more information about setting state in .NET Gadgeteer devices from Web services, see Remote Control of .NET Gadgeteer Device via REST Web Service and .NET Gadgeteer Relay Actuator via REST Web Service. These posts link to others with useful information.

The .NET Gadgeteer XBee radio relay device code follows. In subsequent posts I’ll add more sensors and relay circuits (the Seeed .NET Gadgeteer module has four relays to which various lights, motors, alarms, etc can be connected).  Check back next week sometime. Right now I want to go to Lowe’s Hardware and see what kinds of electrical components I can find. :0)

using Microsoft.SPOT;

using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using Gadgeteer.Modules.GHIElectronics;
using Gadgeteer.Networking;

namespace GadgeteerXbeeRelay
{
    public partial class Program
    {
        GT.Interfaces.Serial serial;
        uint yIndex;
        GT.Timer timer;

        void ProgramStarted()
        {
            wifi.UseDHCP();
            Gadgeteer.Modules.GHIElectronics.WiFi_RS21.WiFiNetworkInfo info =
                new WiFi_RS21.WiFiNetworkInfo();
            info.SSID = "WiFiSecurityID";
            info.SecMode = WiFi_RS21.SecurityMode.WEP;
            info.networkType = WiFi_RS21.NetworkType.AccessPoint;

            wifi.Join(info, "passphrase");
            wifi.NetworkUp +=
                new GTM.Module.NetworkModule.NetworkEventHandler(wifi_NetworkUp);
            wifi.NetworkDown +=
                new GTM.Module.NetworkModule.NetworkEventHandler(wifi_NetworkDown);

            button.ButtonPressed +=
                new Button.ButtonEventHandler(button_ButtonPressed);

            xBee.Configure(9600, GT.Interfaces.Serial.SerialParity.None,
                GT.Interfaces.Serial.SerialStopBits.One, 8);

            serial = xBee.SerialLine;
            serial.Open();

            serial.LineReceived += new GT.Interfaces.Serial.LineReceivedEventHandler(serial_LineReceived);

            yIndex = 1;

            // Start a timer to report to Web service at one minute interval.
            timer = new GT.Timer(60000, GT.Timer.BehaviorType.RunContinuously);
            timer.Tick += new GT.Timer.TickEventHandler(timer_Tick);
            timer.Start();

            Debug.Print("Program Started");
        }

        void serial_LineReceived(GT.Interfaces.Serial sender, string line)
        {
            if (line != null)
            {
                if (225 < yIndex)
                {
                    // Clear if text is near bottom of display.
                    display.SimpleGraphics.Clear();

                    yIndex = 1; // Reset output to top of display.
                }

                display.SimpleGraphics.DisplayText(line,
                    Resources.GetFont(Resources.FontResources.small), GT.Color.Red, 1, yIndex);

                yIndex += 10;
            }

            // Close the circuit on relay1 to start a motor or power any electrical device.
            relays.Relay1 = true;
        }

        void button_ButtonPressed(Button sender, Button.ButtonState state)
        {
            if (!button.IsLedOn)
            {
                serial.AutoReadLineEnabled = true;
                serial.WriteLine("XBee Relay ready.");
                display.SimpleGraphics.Clear();
                yIndex = 0;

                display.SimpleGraphics.DisplayText("Ready to send or receive data.",
                    Resources.GetFont(Resources.FontResources.small), GT.Color.Red, 1, 1);

                yIndex += 10;
                button.TurnLEDOn();
            }

            else
            {
                serial.AutoReadLineEnabled = false;
                button.TurnLEDOff();
                relays.Relay1 = false;
            }

        }

        void timer_Tick(GT.Timer timer)
        {
            // Send data and poll Web service.
            HttpRequest request = HttpHelper.CreateHttpGetRequest("");
            request.ResponseReceived +=
                  new HttpRequest.ResponseHandler(request_ResponseReceived);

            request.SendRequest();  // Sends a non blocking web request.
        }

        void request_ResponseReceived(HttpRequest sender, HttpResponse response)
        {
            //throw new System.NotImplementedException();
        }

        void wifi_NetworkDown(GTM.Module.NetworkModule sender, GTM.Module.NetworkModule.NetworkState state)
        {
            led.TurnRed();
        }

        void wifi_NetworkUp(GTM.Module.NetworkModule sender, GTM.Module.NetworkModule.NetworkState state)
        {
            led.TurnGreen();
        }
    }
}

, , , , , , , , , , , ,

  1. #1 by Mike on April 27, 2012 - 10:20 AM

    Awesome Mike! This is giving me some more ideas for projects.

    Mike

  2. #2 by Michael Dodaro on April 27, 2012 - 12:05 PM

    I know what you mean. I can’t sleep at night, thinking about all the physiological and environmental sensors that can be networked on this model.

  3. #3 by Lin on September 17, 2012 - 8:08 PM

    Hi, Michael
    when I set the serial.AutoReadLineEnabled = true;
    its show error when debugging.
    “An unhandled exception of type ‘System.InvalidOperationException’ occurred in Microsoft.SPOT.Hardware.SerialPort.dll”
    When I click break, shows..
    Locating source for ‘C:\Gadgeteer\NETMF_42\GadgeteerCore\Libraries\Core\Serial42\Serial.cs’. Checksum: MD5 {ad 54 d4 c0 fe 52 e1 ff ec 4e 2d e0 8a eb 5d af}
    The file ‘C:\Gadgeteer\NETMF_42\GadgeteerCore\Libraries\Core\Serial42\Serial.cs’ does not exist……….

    But when I use the serial.DataReceived, it works fine.
    Could you explain what the different with serial.LineReceived and serial.DataReceived?

    Thanks.

  4. #4 by Michael Dodaro on September 17, 2012 - 8:20 PM

    The serial.LineReceived event gets a line of text, whereas the serial.DataReceived gets byte data. The error occurs on my system now too, and this is an unsolved problem with XBee on Serial interface. I can only get it to work while running in the debugger.
    Unless you want to parse the byte data, I suggest using Paul Mineau’s XBeeClient library. See the newer post for links to the XBeeClient source code and an example: https://mikedodaro.net/2012/05/25/using-xbee-radios-with-net-gadgeteer-and-the-xbeeclient-libraries/ .

  5. #5 by Lin on September 18, 2012 - 4:21 AM

    Thanks,but the XBeeClient library support Series 2 only, no support for 802.15.4
    My all Xbee are 802.15.4, so , I must parse the byte data.

    By the way, I always set “Notify me of follow-up comments via email” but never receive the email.

    • #6 by Michael Dodaro on September 18, 2012 - 7:51 AM

      I don’t know why the comments don’t come to your email inbox. My notifications come in email. You shouldn’t have to subscribe to get them. It must be a WordPress idiosyncrasy.

  6. #7 by Scott Coleman on February 8, 2013 - 11:10 AM

    When I run this I get an exception:
    An unhandled exception of type ‘System.InvalidOperationException’ occurred in Microsoft.SPOT.Hardware.SerialPort.dll

    Running with a Cerbuino board. Any ideas why?

    • #8 by Michael Dodaro on February 8, 2013 - 11:20 AM

      That,to my recollection, is an unsolved problem. I had this scenario running in the debugger, but in a device I couldn’t solve it. You could pursue it on the GHI forum. Or you can use the XBee Client library. See the link in this article.

  7. #9 by Brian on February 19, 2013 - 7:20 PM

    Thank you very much for the tutorial. I’m curious if you solved the problem I’ve been running into. When perfectly horizontal I get good values when moving the accelerometer laterally. However if I tilt the accelerometer slightly along an axis it seems as though I get values of the angle of tilt. Maybe I’m misunderstanding it’s abilities, but is there anyway to ignore tilt values and only look for acceleration on an axis?
    Thank you for any help,
    Brian

    • #10 by Michael Dodaro on February 19, 2013 - 10:08 PM

      Code should be able to read acceleration on any axis relative to the position of the module when you call accelerometer.Calibrate();
      It’s been a while since I worked with the accelerometer module, but I have several other posts that use it. Have a look at the results of this query: https://mikedodaro.net/?s=accelerometer . The physics of the device are not so easy, and I’ve linked some references. Hope this helps.

  8. #11 by Bruce Brown on January 18, 2014 - 11:46 PM

    Hey Mike, I love your tutorials! I am trying to figure out if I can piece together the equivalent of a Belkin WeMo light switch with a couple W-Fi XBees and a relay to control a light switch from a FEZ Raptor mainboard wirelessly. In all your examples, you have the XBees connected to the mainboard, and I am trying to find a low-cost solution that will allow me to actually take, like, an XBee + GHI Relay module, stick it inside a light switch in a wall in my house and control it remotely from the FEZ board + Wi-Fi XBee. National Control Devices sells XBee relay boards that are ~$175 or so, and I was hoping to find a much cheaper alternative.

    It kinda blows my mind that it could cost me >$300 remotely control a light switch over Wi-Fi (unless I buy a WeMo which doesn’t have .Net support — only iOS and Android — so I would have to hack the UPnP interface to figure out what the commands are), and I was hoping to avoid having to build my own standalone circuit.

    Do you have any suggestions for making cheap, standalone Wi-Fi transceivers without having to design and produce my own circuits?

  9. #12 by Michael Dodaro on January 19, 2014 - 7:38 AM

    Bruce, the GHI Cerberus Mainboard is $29.95. Maybe this is worth looking at. It’s been a while since I worked with these XBees and there were some sticking points. I think what you’re suggesting is feasible, but I’m not able to suggest a quick solution.
    https://www.ghielectronics.com/catalog/product/349

    • #13 by Bruce Brown on January 19, 2014 - 11:41 PM

      Gah! That’s a GREAT idea! I was off researching Microchip solutions, but it hadn’t occurred to me to look at the lower end GHI boards. That board is perfect. Thanks!!!

      • #14 by Michael Dodaro on January 20, 2014 - 9:27 AM

        In theory it is feasible, but as I mentioned in my previous comment, I found some sticking points using XBees with .NET Gadgeteer boards. I was only able to get these scenarios to work while running in the debugger. Search the GHI forum for recent discussions or ask questions. There were some developers working with XBees about the same time I wrote these posts, but that was almost two years ago now.

  1. XBee Control of .NET Gadgeteer Robot « Integral Design

Leave a comment