© Charles Bell 2020
C. BellBeginning Sensor Networks with XBee, Raspberry Pi, and Arduinohttps://doi.org/10.1007/978-1-4842-5796-8_4

4. XBee-Based Sensor Nodes

Charles Bell1 
(1)
Warsaw, VA, USA
 

Thus far into our journey of sensor networks, we have discovered how sensor networks can be formed, the type of nodes, and their roles that comprise a sensor network, and we’ve spent some time learning about XBee modules and how to program them with MicroPython.

Now it is time to see how we can use XBee modules to read sensor data. As you will see, this can be accomplished in one of two ways: using the extensive native capabilities of the XBee to read sensors and broadcast the data to several or even a single node and using MicroPython written to read and manage sensor data passing it on to other nodes. We will concentrate on the first method, but we will see a short example of both methods.

Let’s begin with a brief overview of what we can do with the XBee modules.

How to Host Sensors with XBee

There are two basic methods1 of hosting sensors with an XBee module. You can configure the XBee module to sample a sensor and send its data on a time schedule (XBee hardware option), or you can write a MicroPython script (MicroPython option) to do the same. There is one major difference. Using the MicroPython option means you can do some additional processing on the sensor data prior to transmitting it. This can include basic error handling, data transformation, and more. If you need to do any work on the sensor data prior to transmitting it or if you want to control other devices connected to the XBee module, MicroPython is a clear advantage.

For example, you could connect an LED to the XBee that you turn on whenever data is read from a sensor. This might be helpful in solutions such as a radio frequency identification (RFID) reader where swiping a card over the sensor unlocks a door. In this case, you can use MicroPython to trigger a light-emitting diode (LED) to let the user know when the lock is disengaged (or engaged).

Conversely, the hardware option permits you to configure the XBee to capture the sensor data in its raw form and there is no provision to modify it (easily). Thus, the data sent is the raw data the sensor generated. While this is one of the best practices—storing the data in its raw form—sometimes you may want to manipulate the data prior to transmission. We will see how to do that with the MicroPython option.

In both cases, sensors are connected directly to the XBee via the input/output pins. More specifically, you connect your sensor(s) to the XBee, read the data, and send it to one or more XBee modules on your network. You can send the data to a specific module by address or you can broadcast the data sending it to all modules on the network.

In the next section, we will see examples of both methods using the same hardware setup for a simple environmental sensor.

Building an XBee Environment Sensor

The XBee environmental sensor node in this example is a single XBee module with a simple analog temperature sensor (TMP36) connected to one of the analog input pins, which uses an analog-to-digital converter (ADC) to convert voltage to a number in range 0–1024. For this project, you tell the XBee to send data using short time periods; but for a real project, you would want to consider using a slower sampling rate or perhaps using sleep mode, in which the XBee sleeps for some time, then sends data, and repeats. We set the sampling rate when we configure the XBee module later in this chapter. For now, let’s let the XBee send samples more frequently so you can see something happening.

The XBee also has a really nifty feature for monitoring battery power. You can tell the XBee to send the current supply power as part of the data packet. In this case, it sends whatever voltage is being supplied to the XBee. This is helpful because it allows you to build into your solution a trigger to remind you to change the batteries in your sensor node(s).

If you have a home or apartment with smoke detectors, you may have already experienced a similar circuit in the form of a tone or alarm that sounds when the battery voltage drops. For those of us with homes that have multiple smoke detectors, it can be somewhat of a “Where’s Waldo?” game to find the detector that is chirping! This is why whenever the first detector starts chirping, I change the batteries in all of them.

Hardware Setup

To keep the project easy to build, you will use a breadboard for the sensor node. Using a breadboard makes it easier to experiment with the components, and once you perfect the circuit, you can move them to printed circuit board (PCB) breadboards for semi-permanent installation or perhaps design and build your own custom PCB for your sensor nodes.

The hardware for the XBee sensor node consists of a breadboard, a breadboard power supply, a TMP36 temperature sensor, and a 0.10mF capacitor. You also need an XBee Explorer board and a set of male headers (0.1" spacing for breadboards) like those available from Adafruit or SparkFun. Figure 4-1 shows the SparkFun regulated explorer board. The regulated board is a bit more expensive, but it has power regulation built in, so if you accidentally connect 5V, it won’t fry your XBee. As an owner of a now completely useless XBee (it’s not even big enough to use as a coaster), I can tell you that it is worth the extra cost.
../images/313992_2_En_4_Chapter/313992_2_En_4_Fig1_HTML.jpg
Figure 4-1

SparkFun regulated XBee Explorer (courtesy of SparkFun)

Note

Most breakout boards do not come with the breadboard headers installed. You have to solder them yourself, get someone to do it for you.

Once you have the components assembled, plug them in to your breadboard as shown in Figure 4-2. Notice the figure is shown without the XBee module installed so you can see the connections clearly. Be sure to set the breadboard power supply to 3.3V.

Caution

Be sure to double-check your wiring before powering on the sensor node.

There is no need to install the XBee module just yet since you need to configure its settings before you can use it with the circuit. You do that in the next section.
../images/313992_2_En_4_Chapter/313992_2_En_4_Fig2_HTML.jpg
Figure 4-2

XBee temperature sensor node

It is important to note that the drawing shows positive power going to pin 1 of the XBee. Be sure to check the pins on your breakout board to be certain you are connecting to the right pin. For example, the SparkFun regulated explorer input voltage is not on pin 1.

Note

The breadboard power supply can be any 6V to 12V power supply. The 9V wall wart that most use to power their Arduino will do nicely.

Notice that you also connect your data line from the TMP36 to pin 17 (analog 3 on the XBee or DIO3 on the explorer board), and you connect ground to the ground pin on the breakout board (or explorer). Be sure to orient the TMP36 with the flat side as shown in the drawing. That is, with the flat side facing you, pin 1 is on the left and is to be connected to input power, the middle pin is data, and pin 3 is to be connected to ground. You can place the capacitor in either orientation, but be sure it is connected to pins 1 and 3 of the TMP36.

Caution

Ensure your breakout board power supply is set to 3.3V.

Alternative to a Breadboard Power Supply

If you plan to make a few XBee sensor nodes for semi-permanent installation, you may not want to use a breadboard. Rather, you may want to use a PCB breadboard and solder your XBee breakout board, sensor, and supporting electronics in place. In this case, a breadboard power supply might not be convenient. Similarly, if you want to keep costs down, you can build a basic power supply from a few parts that can accept up to 12V and still regulate the power to your XBee at 3.3V.

All you need are a 7833-voltage regulator, a 1mF capacitor, a 10mF, and a two-terminal terminal block (or similar power connector). In total, you should be able to buy these components for a few dollars even at an electronics retail store—and less from an electronics online store. Arranging the circuit is easy. The following picture shows the components wired to a breadboard.
../images/313992_2_En_4_Chapter/313992_2_En_4_Figa_HTML.jpg

You need only a little imagination and some wire to transfer the circuit to a PCB breadboard. Notice the orientation of the capacitors—keep the white strip on the negative side!

Now that we have the hardware portion set up, let’s see how to enable the sensor on the XBee with each method described earlier.

For each option, we will test the sensor node using the XCTU application to observe the data. This will allow us to test reading the sensor without setting up a complete sensor network. In fact, it is recommended that you test each sensor node in a similar manner. Once all of the nodes are working with a single connection, you can start connecting them together in a larger network. This will save you untold time and frustration later.2

We will start with the XBee hardware option.

XBee Hardware Option

In this section, we will use the hardware configuration options of the XBee module to read temperature data from the TMP36 sensor and pass it on to another XBee module on the network. We will use a ZigBee network to keep things simple. More specifically, we will not be using the destination address (DH and DL codes) to set a target node. This will permit the XBee acting as a sensor node to broadcast the data using a data sample packet.

We will need one XBee module to read the sensor and another to receive the data. To keep the example simple and easy to set up, we will use XBee series 2 modules for this example. You can use one of the modules you used in Chapter 2 for the sensor node, provided you don’t use the coordinator and you clear the destination address (DH and DL). You will use the XBee module configured as the coordinator to test the XBee sensor node. The following section details all of the settings you will need to make.

Configuring the XBee Sensor Node

The XBee module you use as the XBee sensor node is either an end device or a router with API firmware. You use the XCTU application to connect to the XBee with a USB adapter. Recall, we must connect the XBee using the USB dongle, then open XCTU, and add the module (or search for all modules). Once the module is found, open the configuration mode tab. From there, we will set several settings to enable the XBee to read the sensor. If you have not uploaded the router or end device firmware, you should do that first.

In this case, you want the XBee module to send data every 15 seconds (15,000 milliseconds), read data on analog line 3 (digital I/O 3 or DIO3), and include the reference voltage. Thus, in the XCTU application, you want to change the corresponding settings. Table 4-1 shows the settings you need to change. Use the code shown in the search box to find each setting quickly. Recall that all values are entered in hexadecimal and that you can change the value in XCTU by searching for the code and then either choosing a value or typing it into the text box for that setting. Change the settings as shown, and then click Write to save the settings to the XBee module.
Table 4-1

XBee Sensor Node Options and Values

Code

Setting Name

Description

Value

D3

AD3/DIO3

Trigger analog or digital data recording

2—ADC

ID

PAN ID

Id for the network

8088

IR

I/O Sampling Rate

Time to wait to send data

3A98—15,000ms

NI

Node Identifier

Name for the node

Sensor Node

V+

Supply Voltage Threshold

Supply voltage

FFFF (always send)

Setting Up the Coordinator

Next, remove the XBee sensor node and plug it into the explorer on the breadboard. Make sure you have loaded the coordinator firmware and use the settings in Table 4-2.
Table 4-2

XBee Coordinator Options and Values

Code

Setting Name

Description

Value

ID

PAN ID

Id for the network

8088

NI

Node Identifier

Name for the node

Coordinator

Now we are ready to test our sensor node.

Testing the XBee Sensor Node

To test the XBee sensor node, you use your XBee coordinator with API firmware installed on the USB adapter connected to your PC. Do this first so the coordinator can be up and running when you start the XBee sensor node. Plug it into your computer, and open the XCTU application. Use XCTU to discover the XBee module and then open a terminal. See Chapter 2 for instructions on how to do this.

Next, connect your power supply to your XBee sensor node. It will take a few moments for the XBee to connect to the coordinator and join the network. Once it does, you start to see the coordinator receiving data, as shown in Figure 4-3.

Tip

It can take some time for the network to form. If you do not see data samples on the coordinator, power off the sensor node and power it on again. If you still do not see any data, double-check your settings to ensure both nodes are on the same network PAN ID.

../images/313992_2_En_4_Chapter/313992_2_En_4_Fig3_HTML.jpg
Figure 4-3

Serial monitor output

You should see one or more IO Data Sample receive RX Indicator packets. Notice in the image that the first row begins with 7E (hex). This is the start-of-packet delimiter. You should see to the right data that looks like the following. This is a series of hexadecimal values.
7E 00 14 92 00 13 A2 00 40 A0 D4 5C FC F1 01 01 00 00 88 02 41 0A BC 28
All ZigBee packets have a specific format or layout. Table 4-3 shows the layout for the IO Data Sample RX Indicator packet.
Table 4-3

IO Data Sample Rx Indicator Packet

Value

Field Name

Notes

7E

Start delimiter

 

00 14

Packet length

20 bytes to checksum

92

Frame type

I/O Data Sample Rx Indicator

00 13 A2 00 40 A0 D4 5C

64-bit address

Address of XBee sensor node

FC F1

16-bit address

 

01

Options

 

01

Number of samples

1 data sample

00 00

Digital mask

Digital pins that have data

88

Analog mask

Analog pins that have data

02 41

Sample

Temperature from sensor

0A BC

Supply voltage

 

28

Checksum

 

This data packet represents the data sent from the XBee sensor node. In this case, you set the XBee to send any value from the analog pin 3 (digital IO 3) every 15 seconds. You also set the option to send the value of the supply voltage. Notice the value for the analog mask: the value 88 in hexadecimal is converted to 1000 1000 in binary. The first part of the byte is an indicator that the supply voltage is also included in the data packet. The second part of the byte indicates that AD3/DIO3 (pin 3) was the source of the sample. If you were sampling multiple sensors, the mask would have the bits for the data pin set or 0001 for pin 0, 0010 for pin 1, and 0100 for pin 2.

From the table, you see there is indeed one data sample with a value of 02 41 (hex, 577 decimal). The value is 577 because this is the voltage in millivolts read from the sensor. To calculate the temperature, you must use the following formula:
temp =  ((sample * 1200/1024) - 500)/10
Thus, you have ((577 * 1200/1024)-500)/10 = 17.61 degrees Celsius. The supply voltage is a similar formula:
voltage = (sample * 1200/1024)/1000

Here, you convert the data read to volts rather than millivolts. Thus, the data packet contained 0A BC (hex, 2748), and the voltage read is 3.22 volts. If you are powering an XBee sensor from a battery, you can use this value to determine when you need to change or charge the battery.

Take a few moments to study the other samples in the example and check the data samples for the temperature read. If you are really careful, you can place your finger on the TMP36 and observe the temperature change (it should start increasing after one or two more samples). Once you are convinced your XBee sensor node is sending similar data, you can conclude that the sensor node is working correctly.

Next, let’s look at the MicroPython option.

MicroPython Option

In this section, we will use a MicroPython script on the XBee module to read temperature data from the TMP36 sensor and pass it on to another XBee module on the network. We will use a ZigBee network to keep things simple. More specifically, we will supply the destination address (DH and DL codes) to send the data to a specific node.

We will need one XBee module to read the sensor and another to receive the data. We must use an XBee series 3 module for the sensor node in this example, but we can use the same coordinator from the previous example. You can use one of the modules you used in Chapter 2 for the sensor node, provided you don’t use the coordinator and you clear the destination address (DH and DL). You will use the XBee module configured as the coordinator to test the XBee sensor node. The following section details all of the settings you will need to make.

Configuring the XBee Sensor Node

The XBee module you use as the XBee sensor node is either an end device or a router with API firmware configured to run MicroPython. Once again, you use the XCTU application to connect to the XBee with a USB adapter.

Recall, we will be placing the XBee module into MicroPython mode. While will we still be using the ZigBee network, we will set up the module to connect to (join) the network. Thus, we will require one coordinator. Fortunately, we can use the same coordinator as the last section.

Table 4-4 shows the settings you need to change. Recall that all values are entered in hexadecimal and that you can change the value in XCTU by searching for the code and then either choosing a value or typing it into the text box for that setting. Change the settings as shown, and then click Write to save the settings to the XBee module.
Table 4-4

XBee Sensor Node Options and Values

Code

Setting Name

Description

Value

AP

API Enabled

Set API mode

4—MicroPython

BD

UART Baud Rate

Speed of serial connection

115200

CE

Device Role

Role in ZigBee Network

0—Join Network

D3

AD3/DIO3

Trigger analog or digital data recording

2—ADC

ID

PAN ID

Id for the network

8088

NI

Node Identifier

Name for the node

Python TMP36

PS

MicroPython Auto start

Auto start REPL

1—Enabled

Programming the Sensor Node

Go ahead and make the configuration changes for the sensor node and then write (save) them to the module. Recall from Chapter 2, we can either write our MicroPython script interactively and then save it to a file or write it to a file and upload it to the module. In this example, we will see the interactive mode.

Next, we will open the MicroPython Terminal by selecting it from the menu as shown in Figure 4-4.
../images/313992_2_En_4_Chapter/313992_2_En_4_Fig4_HTML.jpg
Figure 4-4

Open MicroPython Terminal

Once the MicroPython Terminal is opened, press Enter a few times to get a response. You should see the prompt >>>. If you are reusing an XBee module from a previous project that was loaded with a MicroPython script where the main.py script was overwritten either by copying a file or using the interactive mode of the REPL console, you may need to press Ctrl+C to stop the main.py script.

Next, we are going to type in the code shown in Listing 4-1. You can download the source code for this book and open the example file named listing4-1.py and copy and paste the code once in interactive file mode. You can omit the comment lines if you’d like. Also recall you must press Ctrl+C to interrupt a MicroPython script that you've loaded previously. You can then place the terminal in file mode with Ctrl+F.
#
# Beginning Sensor Networks 2nd Edition
#
# XBee Sensor Node Example: Reading a TMP36 temperature sensor.
#
# Dr. Charles Bell
#
from machine import ADC
from time import sleep
import xbee
# Target address to send data
TARGET_64BIT_ADDR = b'x00x13xA2x00x40x8CxCDx0F'
wait_time = 15 # seconds between measurements
cycles = 10 # number of repeats
for x in range(cycles):
    # Read temperature value & print to debug
    temp_pin = ADC("D3")
    temp_raw = temp_pin.read()
    print("Raw pin reading: %d" % temp_raw)
    # Convert temperature to proper units
    temp_c = ((float(temp_raw) * (1200.0/4096.0)) - 500.0) / 10.0
    print("Temperature: %.2f Celsius" % temp_c)
    temp_f = (temp_c * 9.0 / 5.0) + 32.0
    print("Temperature: %.2f Fahrenheit" % temp_f)
    # Send data to coordinator
    message = "raw: %d, C: %.2f, F: %.2f" % (temp_raw, temp_c, temp_f)
    print("Sending: %s" % message)
    try:
        xbee.transmit(TARGET_64BIT_ADDR, message)
        print("Data sent successfully")
    except Exception as e:
        print("Transmit failure: %s" % str(e))
    # Wait between cycles
    sleep(wait_time)
Listing 4-1

Reading a TMP36 Sensor

Listing 4-2 shows the interactive session to copy and paste the preceding code (without comments). Notice at the end, we used Ctrl+D to save the file to main.py, pressing Y to confirm.

Tip

If you encounter problems when you copy and paste the entire file, try copy and paste one line at a time. This can happen if you omit the blank lines, which trigger the REPL console to close code blocks and execute code.

flash compile mode; Ctrl-C to cancel, Ctrl-D to finish
   1^^^ from machine import ADC
   2^^^ from time import sleep
   3^^^ import xbee
   4^^^
   5^^^ # Target address to send data
   6^^^ TARGET_64BIT_ADDR = b'x00x13xA2x00x40x8CxCDx0F'
   7^^^ wait_time = 15 # seconds between measurements
   8^^^ cycles = 10 # number of repeats
   9^^^
  10^^^ for x in range(cycles):
  11^^^     # Read temperature value & print to debug
  12^^^     temp_pin = ADC("D3")
  13^^^     temp_raw = temp_pin.read()
  14^^^     print("Raw pin reading: %d" % temp_raw)
  15^^^
  16^^^     # Convert temperature to proper units
  17^^^     temp_c = ((float(temp_raw) * (1200.0/4096.0)) - 500.0) / 10.0
  18^^^     print("Temperature: %.2f Celsius" % temp_c)
  19^^^     temp_f = (temp_c * 9.0 / 5.0) + 32.0
  20^^^     print("Temperature: %.2f Fahrenheit" % temp_f)
  21^^^
  22^^^     # Send data to coordinator
  23^^^     message = "raw: %d, C: %.2f, F: %.2f" % (temp_raw, temp_c, temp_f)
  24^^^     print("Sending: %s" % message)
  25^^^     try:
  26^^^         xbee.transmit(TARGET_64BIT_ADDR, message)
  27^^^         print("Data sent successfully")
  28^^^     except Exception as e:
  29^^^         print("Transmit failure: %s" % str(e))
  30^^^
  31^^^     # Wait between cycles
  32^^^     sleep(wait_time)
  33^^^
Erasing /flash/main.mpy...
Compiling 1008 bytes of code...
Saved compiled code to /flash/main.mpy (619 bytes).
Automatically run this code at startup [Y/n]? Y
Stored code will run at startup.
Listing 4-2

Interactive File Mode for TMP36 Sensor Example

Once you save the file, we can run the file by pressing Ctrl+R as shown in Listing 4-3. However, remember that we are using the REPL console, which will execute the code interactively. Since we have not connected the TMP36 sensor yet, you may see spurious values when the code executes. Let it run for a few iterations and then press Ctrl+C to stop execution.
MicroPython v1.11-1290-g9da1b0c on 2019-11-14; XBee3 Zigbee with EFR32MG
Type "help()" for more information.
Press CTRL-R in the REPL to run the code at any time.
Try running it with CTRL+R. Interrupt with CTRL+C.
Loading /flash/main.mpy...
Running bytecode...
Raw pin reading: 4095
Temperature: 69.97 Celsius
Temperature: 157.95 Fahrenheit
Sending: raw: 4095, C: 69.97, F: 157.95
Data sent successfully
Raw pin reading: 4095
Temperature: 69.97 Celsius
Temperature: 157.95 Fahrenheit
Sending: raw: 4095, C: 69.97, F: 157.95
Data sent successfully
Raw pin reading: 4095
Temperature: 69.97 Celsius
Temperature: 157.95 Fahrenheit
Sending: raw: 4095, C: 69.97, F: 157.95
Data sent successfully
Traceback (most recent call last):
  File "<stdin>", line 32, in <module>
KeyboardInterrupt:
>>>
Listing 4-3

Interactive Execution of TMP36 Example

Now, let’s return to the code paying attention to the formulas for calculating the Celsius value from the raw input shown as follows for clarity. You may notice that the formula uses a different value for the maximum value read (4096 instead of 1024). This is because MicroPython returns a range of 0–4095 from the ADC so we must take that into consideration in the formula.
    temp_raw = temp_pin.read()
    print("Raw pin reading: %d" % temp_raw)
    # Convert temperature to proper units
    temp_c = ((float(temp_raw) * (1200.0/4096.0)) - 500.0) / 10.0

Once you are convinced this formula is correct, you can shut down the MicroPython Terminal, disconnect your XBee from XCTU, and remove the USB explorer. Next, move the XBee module to the breadboard set up from before.

You do not need to power on the circuit, but if you have already configured the coordinator or are using from the previous example, you can power on the circuit skipping the following section.

Setting Up the Coordinator

Next, remove the XBee sensor node and plug it into the explorer on the breadboard. If you are reusing the coordinator from the last section, you do not need to make the changes. If you are using a new XBee module or one from another project, make sure you have loaded the coordinator firmware and use the settings in Table 4-5.
Table 4-5

XBee Coordinator Options and Values

Code

Setting Name

Description

Value

ID

PAN ID

Id for the network

8088

NI

Node Identifier

Name for the node

Coordinator

Once the settings are written and the sensor node is powered on, take a look at the network to ensure your module is connecting. Figure 4-5 shows an example of what you should see. Recall, you can select the coordinator, open the network view from the main window, and then click Scan.
../images/313992_2_En_4_Chapter/313992_2_En_4_Fig5_HTML.jpg
Figure 4-5

Checking the network

Tip

It is always a good idea to check your ZigBee network to ensure the modules have connected correctly. If you do not see the modules you expect, double-check all settings and rescan the network.

Now we are ready to test our sensor node.

Testing the XBee Sensor Node

To test the XBee sensor node, you use your XBee coordinator with API firmware installed on the USB adapter connected to your PC. Do this first so the coordinator can be up and running when you start the XBee sensor node. Plug it into your computer, and open the XCTU application. Use XCTU to discover the XBee module and then open a terminal. See Chapter 2 for instructions on how to do this.

Next, connect your power supply to your XBee sensor node. It will take a few moments for the XBee to connect to the coordinator and join the network. Once it does, you start to see the coordinator receiving data, as shown in Figure 4-6.
../images/313992_2_En_4_Chapter/313992_2_En_4_Fig6_HTML.jpg
Figure 4-6

Serial monitor output

You should see one or more Explicit RX Indicator packets. We get this packet instead of the broadcast because we’re transmitting the packet directly to the coordinator by address. Notice in the image that the first row begins with 7E (hex). This is the start-of-packet delimiter. You should see to the right data that looks like the following. This is a series of hexadecimal values.
7E 00 2F 91 00 13 A2 00 41 92 DB A4 94 CC E8 E8 00 11 C1 05 01 72 61 77 3A 20 32 32 37 30 2C 20 43 3A 20 31 36 2E 35 30 2C 20 46 3A 20 36 31 2E 37 31 24
You may be wondering where the message is we transmitted. It is there, but hard to see in the hexadecimal output. It appears at the end of the message. The following shows the message from the example.
72 61 77 3A 20 32 32 37 30 2C 20 43 3A 20 31 36 2E 35 30 2C 20 46 3A 20 36 31 2E 37 31
If you convert the hex values to American Standard Code for Information Interchange (ASCII),3 you will see the message. A somewhat tedious lookup using an ASCII chart will reveal the following 29 hexadecimal values are represented in ASCII as follows. Nifty, yes?
raw: 2270, C: 16.50, F: 61.71
Now, let’s take a closer look at the packet. All ZigBee packets have a specific format or layout. Table 4-6 shows the layout for the Explicit RX Indicator packet.
Table 4-6

Explicit Rx Indicator Packet

Value

Field Name

Notes

7E

Start delimiter

 

00 2F

Packet length

47 bytes to checksum

91

Frame type

Explicit Rx Indicator

00 13 A2 00 41 92 DB A4

64-bit address

Address of XBee sensor node

94 CC

16-bit address

 

E8

Source endpoint

 

E8

Destination endpoint

 

00 11

Cluster Id

 

C1 05

Profile Id

 

01

Receive options

0x01—Packet Acknowledged

0A BC

Supply voltage

 

N bytes

Received data

Example: 29

N+1 byte

Checksum

Example: 0x24

This data packet represents the data sent from the XBee sensor node. In this case, you set the XBee to send any value from the analog pin 3 (digital IO 3) every 15 seconds for ten cycles.4

Take a few moments to study the other samples in the example and check the data samples for the temperature read. If you are really careful, you can place your finger on the TMP36 and observe the temperature change (it should start increasing after one or two more samples). Once you are convinced your XBee sensor node is sending similar data, you can conclude that the sensor node is working correctly.

Next, we will look at an example of this project done a bit easier using a different form of sensor.

Example: Using XBee Modules to Gather Data

In this example, we will kick up the configuration a bit by switching to an easier (but slightly more expensive) option to connect sensors to XBee modules. We will also see a different form of sensor that communicates with a different interface.

We will use the XBee Grove Development Board to host our XBee module as shown in Figure 4-7. The XBee Grove Development Board has several connectors along with six grove connectors, user controllable button and LED, and much more. For complete details about the board, see the guide at www.digi.com/resources/documentation/Digidocs/90001457-13/.
../images/313992_2_En_4_Chapter/313992_2_En_4_Fig7_HTML.jpg
Figure 4-7

XBee Grove Development Board

Grove is a hardware prototyping standard made by Seeed Studio (seeedstudio.com) designed to simplify connecting devices together using a simple, four-wire connection. You can find all manner of sensors and output components for creating your projects quickly. See the Seeed Studio wiki about the Grove system to learn more (http://wiki.seeedstudio.com/Grove_System/).

The sensor we will use is the BMP280 temperature/humidity sensor. You can find this sensor at Adafruit (adafruit.com) or SparkFun (sparkfun.com). Figure 4-8 shows the BMP280 module from Adafruit. You can get one here at www.adafruit.com/product/2651. There is a Grove module for the BMP280 (http://wiki.seeedstudio.com/Grove-Barometer_Sensor-BMP280/), but it is harder to find because it is an older module.
../images/313992_2_En_4_Chapter/313992_2_En_4_Fig8_HTML.jpg
Figure 4-8

BMP280 breakout board

This sensor uses the Inter-Integrated Circuit (I2C) interface5 with 7-bit addressing. This requires four connections: power, ground, clock (SCL), and data (SDA). Since you can connect multiple sensors to the same I2C bus, each sensor has its own address so that you can “talk” to the sensor you want. Unfortunately, each I2C sensor (device) has its own communication protocol, so communicating with the module to get data requires a special library (called a driver) to use the sensor. Fortunately, there is a MicroPython I2C driver for the BMP280. We will download it and copy it to our XBee module. However, since it is written to a MicroPython version that is a bit different than the XBee MicroPython, we need to make some minor alterations.

While this example is terse and shows the bare minimal needed to get it working, we will learn more about I2C interfaces in the next two chapters.

Let’s begin by configuring the hardware for the XBee sensor node.

Hardware Setup

Setting up the hardware for this project is easier than the previous examples. All you need is a Grove to Female Jumper cable or (4) female-to-female jumper wires, the XBee Grove Development Board, and the BMP280 module. If your BMP280 module doesn’t have the header soldered, you may need to solder it yourself or find someone to solder it for you.

To connect the sensor to the board, we will be using only four of the connections on the BMP280. The module from Adafruit supports I2C and x (SPI) interfaces, so we only need those for I2C. These are marked on the board as follows: 3V0 (3V power), GND (ground), SDK (SCL on the development board), and SDI (SDA on the development board). We can use the Grove PWM connector for power and ground, but must use the Grove D10 connector for the I2C interface. Several options for making the connections are shown as follows. Go ahead and make the connections now. Do not insert the XBee module or connect the board to your PC at this time.

BMP280 with Jumper Wires

If you want to use individual jumper wires, you should use two of the Grove connectors: the first for the SCL and SDA connections and another for power. This is because the jumper wires are slightly larger than the pins in the Grove connectors.
../images/313992_2_En_4_Chapter/313992_2_En_4_Fig9_HTML.jpg
Figure 4-9

Connecting the BMP280 breakout board using jumper wires

BMP280 with Grove Breakout Cable

The Grove breakout cable from Seeed Studio is an excellent alternative to jumper wires. These have a Grove connector on one end and female connectors for each wire on the other end, making them ideal for connecting to breakout boards like the BMP280 in this example. See www.seeedstudio.com/Grove-4-pin-Female-Jumper-to-Grove-4-pin-Conversion-Cable-5-PCs-per-Pack.html for more details. Like the Grove BMP280 module, these cables are harder to find. They also make a Grove to male cable. See www.seeedstudio.com/Grove-4-pin-Male-Jumper-to-Grove-4-pin-Conversion-Cable-5-PCs-per-Pack.html.

Figure 4-10 shows how to make the connections using the Grove to jumper wire cable.
../images/313992_2_En_4_Chapter/313992_2_En_4_Fig10_HTML.jpg
Figure 4-10

Connecting the BMP280 breakout board using Grove to jumper wire cable

Grove BMP280 Module Connections

If you purchased the BMP280 Grove module, all you need to do is connect the module to the board using a Grove cable as shown in Figure 4-11.
../images/313992_2_En_4_Chapter/313992_2_En_4_Fig11_HTML.jpg
Figure 4-11

Connecting the BMP280 Grove module

Next, let’s configure the XBee sensor node.

Configuring the XBee Sensor Node

The XBee module you use as the XBee sensor node is either an end device or a router with API firmware configured to run MicroPython. Once again, you use the XCTU application to connect to the XBee. In this case, we will use the XBee Grove Development Board.

Simply connect your XBee module to the board and then connect the board to your PC using the provided micro-USB cable. This will act like the USB explorer that we’ve been using in the other projects. If you are reusing the XBee module we used as the sensor node from the previous, many of the settings will remain the same except for the digital IO pin setting (D1).

Table 4-7 shows the settings you need to change. Recall that all values are entered in hexadecimal and that you can change the value in XCTU by searching for the code and then either choosing a value or typing it into the text box for that setting. Change the settings as shown, and then click Write to save the settings to the XBee module.
Table 4-7

XBee Sensor Node Options and Values

Code

Setting Name

Description

Value

AP

API Enabled

Set API mode

4—MicroPython

BD

UART Baud Rate

Speed of serial connection

115200

CE

Device Role

Role in ZigBee Network

0—Join Network

D1

DIO1

Digital data read/write

6—I2C SCL

ID

PAN ID

Id for the network

8088

NI

Node Identifier

Name for the node

Python BMP280

PS

MicroPython Auto start

Auto start REPL

1—Enabled

Programming the Sensor Node

Go ahead and make the configuration changes for the sensor node and then write (save) them to the module. Recall from Chapter 2, we can either write our MicroPython script interactively and then save it to a file or write it to a file and upload it to the module. In this example, we will see the file copy mode.

In this case, we will need to copy the BMP280 I2C library to the lib folder on the XBee module and copy our MicroPython script to the XBee module renaming it as main.py. Rather than jumping into the project by blindly copying the files, let’s learn how to use custom MicroPython libraries using the BMP280 library.

When you want to use an I2C sensor or device, you will need to have a MicroPython driver library for it. Recall, this is because each device has its own protocol requiring writing certain values to a specific byte or bytes to trigger or set some option and then read the data using yet another address. Sound complicated? It can be. Fortunately, someone has done all the work for us.

Use your browser and navigate to https://github.com/dafvid/micropython-bmp280/. This library was written by David Wahlund and is an excellent example of how to write an I2C driver in MicroPython. If you want to write your own driver for another I2C device, this code is a very good template to follow.

To download the driver, click the Clone or download button and save the Zip file to your PC. Once it has downloaded, open the Zip library and extract the files. You will need to find the bmp280.py file. We will be copying this file to our XBee module after we modify it.

Tip

A modified version of the module is available on the source code download for the book from the Apress website.

In short, we must add a new import and comment out a few lines in the constructor. These modifications will permit the code to work on the XBee modules. We also need to remove some of the methods in the module because the code size is a bit too large for the XBee.

Caution

If you find other modules you want to use with your XBee and encounter memory errors, you may need to reduce the size of the module. You can do so by removing unneeded methods, constants, and similar features. Be careful to only remove things you don’t need (and are not needed by the remaining methods).

Open the downloaded file and add this line at the top of the file:
from micropython import const
Next, locate the following lines and either comment them (placing a # at the start of the line). You will find both in the constructor. You may encounter errors such as an invalid I2C operation or memory error if you forget to remove these lines:
self._bmp_i2c.start()
self.use_case(BMP280_CASE_HANDHELD_DYN)

Finally, to reduce the size of the module, remove all methods after the pressure() method and then save the file. Listing 4-4 shows the resulting code. Your edits should be very similar (allowing for minor improvements by the author of the module).

Tip

Also included in the source code for the book is a difference file (bmp280.diff) that you can use to apply to the code if you are familiar with diff and patch.

from micropython import const
from ustruct import unpack as unp
# Author David Stenwall Wahlund (david at dafnet.se)
# Power Modes
BMP280_POWER_FORCED = const(1)
BMP280_POWER_NORMAL = const(3)
BMP280_SPI3W_ON = const(1)
BMP280_SPI3W_OFF = const(0)
BMP280_TEMP_OS_SKIP = const(0)
BMP280_TEMP_OS_1 = const(1)
BMP280_TEMP_OS_2 = const(2)
BMP280_TEMP_OS_4 = const(3)
BMP280_TEMP_OS_8 = const(4)
BMP280_TEMP_OS_16 = const(5)
BMP280_PRES_OS_SKIP = const(0)
BMP280_PRES_OS_1 = const(1)
BMP280_PRES_OS_2 = const(2)
BMP280_PRES_OS_4 = const(3)
BMP280_PRES_OS_8 = const(4)
BMP280_PRES_OS_16 = const(5)
# Standby settings in ms
BMP280_STANDBY_0_5 = const(0)
BMP280_STANDBY_62_5 = const(1)
BMP280_STANDBY_125 = const(2)
BMP280_STANDBY_250 = const(3)
BMP280_STANDBY_500 = const(4)
BMP280_STANDBY_1000 = const(5)
BMP280_STANDBY_2000 = const(6)
BMP280_STANDBY_4000 = const(7)
# IIR Filter setting
BMP280_IIR_FILTER_OFF = const(0)
BMP280_IIR_FILTER_2 = const(1)
BMP280_IIR_FILTER_4 = const(2)
BMP280_IIR_FILTER_8 = const(3)
BMP280_IIR_FILTER_16 = const(4)
# Oversampling setting
BMP280_OS_ULTRALOW = const(0)
BMP280_OS_LOW = const(1)
BMP280_OS_STANDARD = const(2)
BMP280_OS_HIGH = const(3)
BMP280_OS_ULTRAHIGH = const(4)
# Oversampling matrix
# (PRESS_OS, TEMP_OS, sample time in ms)
_BMP280_OS_MATRIX = [
    [BMP280_PRES_OS_1, BMP280_TEMP_OS_1, 7],
    [BMP280_PRES_OS_2, BMP280_TEMP_OS_1, 9],
    [BMP280_PRES_OS_4, BMP280_TEMP_OS_1, 14],
    [BMP280_PRES_OS_8, BMP280_TEMP_OS_1, 23],
    [BMP280_PRES_OS_16, BMP280_TEMP_OS_2, 44]
]
# Use cases
BMP280_CASE_HANDHELD_LOW = const(0)
BMP280_CASE_HANDHELD_DYN = const(1)
BMP280_CASE_WEATHER = const(2)
BMP280_CASE_FLOOR = const(3)
BMP280_CASE_DROP = const(4)
BMP280_CASE_INDOOR = const(5)
_BMP280_CASE_MATRIX = [
    [BMP280_POWER_NORMAL, BMP280_OS_ULTRAHIGH, BMP280_IIR_FILTER_4, BMP280_STANDBY_62_5],
    [BMP280_POWER_NORMAL, BMP280_OS_STANDARD, BMP280_IIR_FILTER_16, BMP280_STANDBY_0_5],
    [BMP280_POWER_FORCED, BMP280_OS_ULTRALOW, BMP280_IIR_FILTER_OFF, BMP280_STANDBY_0_5],
    [BMP280_POWER_NORMAL, BMP280_OS_STANDARD, BMP280_IIR_FILTER_4, BMP280_STANDBY_125],
    [BMP280_POWER_NORMAL, BMP280_OS_LOW, BMP280_IIR_FILTER_OFF, BMP280_STANDBY_0_5],
    [BMP280_POWER_NORMAL, BMP280_OS_ULTRAHIGH, BMP280_IIR_FILTER_16, BMP280_STANDBY_0_5]
]
_BMP280_REGISTER_ID = const(0xD0)
_BMP280_REGISTER_RESET = const(0xE0)
_BMP280_REGISTER_STATUS = const(0xF3)
_BMP280_REGISTER_CONTROL = const(0xF4)
_BMP280_REGISTER_CONFIG = const(0xF5)  # IIR filter config
_BMP280_REGISTER_DATA = const(0xF7)
class BMP280:
    def __init__(self, i2c_bus, addr=0x76):
        self._bmp_i2c = i2c_bus
        self._i2c_addr = addr
        self.chip_id = self._read(_BMP280_REGISTER_ID, 2)
        # read calibration data
        # < little-endian
        # H unsigned short
        # h signed short
        self._T1 = unp('<H', self._read(0x88, 2))[0]
        self._T2 = unp('<h', self._read(0x8A, 2))[0]
        self._T3 = unp('<h', self._read(0x8C, 2))[0]
        self._P1 = unp('<H', self._read(0x8E, 2))[0]
        self._P2 = unp('<h', self._read(0x90, 2))[0]
        self._P3 = unp('<h', self._read(0x92, 2))[0]
        self._P4 = unp('<h', self._read(0x94, 2))[0]
        self._P5 = unp('<h', self._read(0x96, 2))[0]
        self._P6 = unp('<h', self._read(0x98, 2))[0]
        self._P7 = unp('<h', self._read(0x9A, 2))[0]
        self._P8 = unp('<h', self._read(0x9C, 2))[0]
        self._P9 = unp('<h', self._read(0x9E, 2))[0]
        # output raw
        self._t_raw = 0
        self._t_fine = 0
        self._t = 0
        self._p_raw = 0
        self._p = 0
        self.read_wait_ms = 0  # interval between forced measure and readout
        self._new_read_ms = 200  # interval between
        self._last_read_ts = 0
    def _read(self, addr, size=1):
        return self._bmp_i2c.readfrom_mem(self._i2c_addr, addr, size)
    def _write(self, addr, b_arr):
        if not type(b_arr) is bytearray:
            b_arr = bytearray([b_arr])
        return self._bmp_i2c.writeto_mem(self._i2c_addr, addr, b_arr)
    def _gauge(self):
        # TODO limit new reads
        # read all data at once (as by spec)
        d = self._read(_BMP280_REGISTER_DATA, 6)
        self._p_raw = (d[0] << 12) + (d[1] << 4) + (d[2] >> 4)
        self._t_raw = (d[3] << 12) + (d[4] << 4) + (d[5] >> 4)
        self._t_fine = 0
        self._t = 0
        self._p = 0
    def reset(self):
        self._write(_BMP280_REGISTER_RESET, 0xB6)
    def load_test_calibration(self):
        self._T1 = 27504
        self._T2 = 26435
        self._T3 = -1000
        self._P1 = 36477
        self._P2 = -10685
        self._P3 = 3024
        self._P4 = 2855
        self._P5 = 140
        self._P6 = -7
        self._P7 = 15500
        self._P8 = -14600
        self._P9 = 6000
    def load_test_data(self):
        self._t_raw = 519888
        self._p_raw = 415148
    def print_calibration(self):
        print("T1: {} {}".format(self._T1, type(self._T1)))
        print("T2: {} {}".format(self._T2, type(self._T2)))
        print("T3: {} {}".format(self._T3, type(self._T3)))
        print("P1: {} {}".format(self._P1, type(self._P1)))
        print("P2: {} {}".format(self._P2, type(self._P2)))
        print("P3: {} {}".format(self._P3, type(self._P3)))
        print("P4: {} {}".format(self._P4, type(self._P4)))
        print("P5: {} {}".format(self._P5, type(self._P5)))
        print("P6: {} {}".format(self._P6, type(self._P6)))
        print("P7: {} {}".format(self._P7, type(self._P7)))
        print("P8: {} {}".format(self._P8, type(self._P8)))
        print("P9: {} {}".format(self._P9, type(self._P9)))
    def _calc_t_fine(self):
        # From datasheet page 22
        self._gauge()
        if self._t_fine == 0:
            var1 = (((self._t_raw >> 3) - (self._T1 << 1)) * self._T2) >> 11
            var2 = (((((self._t_raw >> 4) - self._T1)
                      * ((self._t_raw >> 4)
                         - self._T1)) >> 12)
                    * self._T3) >> 14
            self._t_fine = var1 + var2
    @property
    def temperature(self):
        self._calc_t_fine()
        if self._t == 0:
            self._t = ((self._t_fine * 5 + 128) >> 8) / 100.
        return self._t
    @property
    def pressure(self):
        # From datasheet page 22
        self._calc_t_fine()
        if self._p == 0:
            var1 = self._t_fine - 128000
            var2 = var1 * var1 * self._P6
            var2 = var2 + ((var1 * self._P5) << 17)
            var2 = var2 + (self._P4 << 35)
            var1 = ((var1 * var1 * self._P3) >> 8) + ((var1 * self._P2) << 12)
            var1 = (((1 << 47) + var1) * self._P1) >> 33
            if var1 == 0:
                return 0
            p = 1048576 - self._p_raw
            p = int((((p << 31) - var2) * 3125) / var1)
            var1 = (self._P9 * (p >> 13) * (p >> 13)) >> 25
            var2 = (self._P8 * p) >> 19
            p = ((p + var1 + var2) >> 8) + (self._P7 << 4)
            self._p = p / 256.0
        return self._p
Listing 4-4

Modified bmp280.py Module

To copy the modified file to our XBee module, connect your XBee to your PC using the Grove Development Board and then open the File System Manager using the Tools menu as shown in Figure 4-12.
../images/313992_2_En_4_Chapter/313992_2_En_4_Fig12_HTML.jpg
Figure 4-12

Open the File System Manager

Once the File System Manager is open, you will need to connect to the XBee. If you select the XBee module in XCTU before opening the File System Manager, you can click the Open button and the manager will connect to your module. Otherwise, you can use the Settings button to choose the UART (serial) parameters for the XBee and then connect to it.

Use the manager to locate the bmp280.py file using the left side of the interface and navigate to the lib folder on the XBee using the right side of the interface. Then, click bmp280.py and drag it to the right and drop it. This will copy the file to your XBee module. The result should resemble Figure 4-13.
../images/313992_2_En_4_Chapter/313992_2_En_4_Fig13_HTML.jpg
Figure 4-13

Copying the BMP driver using the File System Manager

Now, let’s test the library using a bare minimal script. We’ll use the MicroPython Terminal in interactive mode to do that. But first, click the Close button in the upper left and then the Close button in the lower right to close the manager.

Next, open the MicroPython Terminal from the Tools menu and then connect to your XBee module. Recall, you may need to press ENTER or Ctrl+C to get the >>> prompt. Once there, enter the following lines of code:
from machine import I2C
from bmp280 import BMP280
bmp280 = BMP280(I2C(1, freq=100000), 0x77)
print(bmp280.temperature)
print(bmp280.pressure)
This code shows how to use the I2C BMP280 driver by telling the driver the sensor is on DIO 1 and use a sample frequency of 100,000 and the I2C address of 0x77 (hexadecimal). We then read the temperature, print it, and repeat for the barometric pressure. The following code shows the results you should see (values may differ):
>>> from machine import I2C
>>> from bmp280 import BMP280
>>> bmp280 = BMP280(I2C(1, freq=100000), 0x77)
>>> print(bmp280.temperature)
21.71
>>> print(bmp280.pressure)
102357.4
>>>

If you get errors such as address or NOENV errors, double-check your wiring connections. Sometimes the jumper wires can be a little loose. Crimp them on the development board side and the connection should improve.

Now that we have the BMP driver copied and tested, we can write the script for reading the sensor. Listing 4-5 shows the complete code. It should look very familiar as it follows the same template as the previous examples. Take a moment to examine the code to see how it works.
#
# Beginning Sensor Networks 2nd Edition
#
# XBee Sensor Node Example: Reading a BMP280 sensor.
# This demonstrates how to use an I2C driver.
#
# Dr. Charles Bell
#
from machine import I2C
from bmp280 import BMP280
import xbee
# BMP280 address
BMP_ADDR = 0x77
# Target address to send data
TARGET_64BIT_ADDR = b'x00x13xA2x00x40x8CxCDx0F'
wait_time = 15 # seconds between measurements
cycles = 10 # number of repeats
bmp280 = BMP280(I2C(1, freq=100000), BMP_ADDR)
for x in range(cycles):
    # Read temperature & barometric pressure
    temp_c = bmp280.temperature
    pressure = bmp280.pressure
    # Convert temperature to proper units
    print("Temperature: %.2f Celsius" % temp_c)
    temp_f = (temp_c * 9.0 / 5.0) + 32.0
    print("Temperature: %.2f Fahrenheit" % temp_f)
    print("Barometric Pressure: %.4f" % pressure)
    # Send data to coordinator
    message = "C: %.2f, F: %.2f, B: %.4f" % (temp_c, temp_f, pressure)
    print("Sending: %s" % message)
    try:
        xbee.transmit(TARGET_64BIT_ADDR, message)
        print("Data sent successfully")
    except Exception as e:
        print("Transmit failure: %s" % str(e))
    # Wait between cycles
    sleep(wait_time)
Listing 4-5

Reading a BMP280 Sensor

If you have downloaded the sample code from the Apress book website, you can extract this file and copy it to your PC. Rename it as main.py and then copy it to your XBee using the File System Manager like we did earlier. Be sure to copy it to the root folder on the XBee as shown in Figure 4-14.
../images/313992_2_En_4_Chapter/313992_2_En_4_Fig14_HTML.jpg
Figure 4-14

Copying the main.py using the File System Manager

Now we are ready to test our sensor node.

Testing the XBee Sensor Node

To test the XBee sensor node, you use your XBee coordinator with API firmware installed on the USB adapter connected to your PC. Do this first so the coordinator can be up and running when you start the XBee sensor node. Plug it into your computer, and open the XCTU application. Use XCTU to discover the XBee module and then open a terminal. See Chapter 2 for instructions on how to do this.

Next, connect your power supply to your XBee sensor node. It will take a few moments for the XBee to connect to the coordinator and join the network. Once it does, you start to see the coordinator receiving data, as shown in Figure 4-15.
../images/313992_2_En_4_Chapter/313992_2_En_4_Fig15_HTML.jpg
Figure 4-15

Serial monitor output

You should see one or more Receive Packet packets. We get this packet instead of the broadcast because we’re transmitting the packet directly to the coordinator by address. Notice in the image that the first row begins with 7E (hex). This is the start-of-packet delimiter. You should see to the right data that looks like the following. This is a series of hexadecimal values.
7E 00 2E 90 00 13 A2 00 41 92 DB A4 94 CC 01 43 3A 20 31 39 2E 36 39 2C 20 46 3A 20 36 37 2E 34 34 2C 20 42 3A 20 31 30 32 33 37 38 2E 32 34 39 32 58
You may be wondering where the message is we transmitted. It is there, but hard to see in the hexadecimal output. It appears at the end of the message. The following shows the message from the example:
43 3A 20 31 39 2E 36 39 2C 20 46 3A 20 36 37 2E 34 34 2C 20 42 3A 20 31 30 32 33 37 38 2E 32 34 39 32
If you convert the hex values to ASCII, you will see the message revealed as follows:
C: 19.69, F: 61.44, B: 102378.2492
Now, let’s take a closer look at the packet. All ZigBee packets have a specific format or layout. Table 4-8 shows the layout for the Receive Packet packet.
Table 4-8

Receive Packet Packet

Value

Field Name

Notes

7E

Start delimiter

 

00 2E

Packet length

47 bytes to checksum

90

Frame type

Receive Packet Indicator

00 13 A2 00 41 92 DB A4

64-bit address

Address of XBee sensor node

94 CC

Reserved

 

01

Options

0x01 = Packet was a broadcast packet

N bytes

Received data

Example: 34

N+1 byte

Checksum

Example: 0x58

Take a few moments to study the other samples in the example and check the data samples for the temperature read. If you are really careful, you can place your finger on the BMP280 and observe the temperature change (it should start increasing after one or two more samples). Once you are convinced your XBee sensor node is sending similar data, you can conclude that the sensor node is working correctly.

Component Shopping List

You need a number of components to complete the projects in this chapter. Table 4-9 lists them. Note that the Grove components can be considered option if you do not intend to implement the last example.
Table 4-9

Components Needed

Item

Vendors

Est. Cost USD

Qty Needed

XBee-ZB (ZB) Series 2, 2.5, or 3

www.sparkfun.com

$25.00–48.00

2

www.adafruit.com

BMP280 breakout board

www.adafruit.com/product/2651

$9.95–14.95

1

www.sparkfun.com/products/15440

BMP280 Grove Sensor (optional)

www.seeedstudio.com/catalogsearch/result/?q=bmp280

$8.95

1

Grove to Female Jumper (optional)

www.seeedstudio.com/Grove-4-pin-Female-Jumper-to-Grove-4-pin-Conversion-Cable-5-PCs-per-PAck.html

$3.90

1

XBee Grove Development Board (optional)

www.digikey.com/products/en?mpart=76000956&v=602

$25.00

1

Breadboard (not mini)

www.sparkfun.com/products/9567

$4.95

1

Breadboard jumper wires

www.sparkfun.com/products/8431

$3.95

1

XBee Explorer Regulated with headers

www.sparkfun.com/products/11373

$10.95

1

TMP36 sensor

www.sparkfun.com/products/10988

$1.50

1

www.adafruit.com/products/165

0.10uF capacitor

www.sparkfun.com/products/8375

$0.25

1

Summary

The XBee modules are a fantastic inexpensive way to transmit data wirelessly from one device to another. They can also be used to collect data in the form of hosting (connecting) one or more sensors.

We can either configure the XBee to collect the raw data from the sensor and transmit (broadcast) it to other nodes in the network—without programming. Or, we can use the robust MicroPython programming language to write a script to read the data and format it or perform calculations before sending it to another node.

In this chapter, we saw examples of both forms of hosting sensors. We learned how to connect sensors to the XBee module using an analog temperature sensor (TMP36) as well as an I2C digital sensor (BMP280).

We also saw a short glimpse at the Grove prototyping platform offered by Seeed Studio. Grove makes connecting sensors easier by removing the need to build circuits on a breadboard. We will see more about Grove sensors in later chapters.

In the next chapter, we will explore the Raspberry Pi including a short tutorial on how to use the Raspberry Pi as well as example projects on how to host sensors.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.116.51.117