Archives For xbee

Continuing with the description of the wireless mailbox sensor, I was missing the information on the coordinator: an arduino mega with an ethernet shield and an Xbee attached.

Originally I had two Regular Xbee Series 1. I chose series 1 because of the simplicity for non complex projects. I read in many sources they are easier to handle when starting out with Xbee and also they support multi-point communication. Weather to use a physical antenna or on-chip antenna I think doesn’t matter much. The problem I had was that the signal from the regular Xbees didn’t reach from my mailbox (which is downstairs outside my apartment) to the location of the coordinator inside my apartment. I finally had to buy a Xbee Series 1 Pro with a wire antenna. Pro and Regular Xbees are compatible with only few minor changes, more importantly the Pro version consumes more power given the larger reception range. The coordinator runs on a connected power source so I didn’t really mind this increase in power consumption.

The coordinator is always listening for upcoming Xbee transmissions, in case it receives something, it will check the source sensor the transmission is coming from and the message (mailbox opened, new letter received, etc). After “decoding” the message it will connect via the Ethernet Shield to a php script I have in my hosting that will handle the push notification using Google Cloud Messaging (GCM) for Android. I will write about the use of GCM and the android app in a separate post.

Here is the full code for the arduino handling the reception of messages:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetClient.h>
#include <Xbee.h>
#include <Ilos.h>
 
// Xbee related stuff
XBee         xbee       = XBee();
XBeeResponse response   = XBeeResponse();
Rx16Response rx16       = Rx16Response();
Rx64Response rx64       = Rx64Response();
 
// Ethernet related stuff
boolean     lastConnected   = false;
byte        mac[]           = { 0x00, 0xAA, 0xBB, 0xCC, 0xDA, 0x02 };
IPAddress   ip(192,168,1,234);
char        server[]        = "www.adrova.com";
EthernetClient client;
 
// Input and outputs
int statusLED = 13;
 
void setup(){
 
    // Setup pin modes
    pinMode(statusLED, OUTPUT);
 
    // Setup serial interfaces for debugging
    Serial.begin(9600);
 
    // Setup serial interface for Xbee
    Serial1.begin(9600);
    xbee.setSerial(Serial1);
 
    // Start the Ethernet connection:
    if (Ethernet.begin(mac) == 0) {
        Serial.println("Failed to configure Ethernet using DHCP");
        Ethernet.begin(mac, ip);
    }
 
    // Give the Ethernet shield a second to initialize:
    delay(1000);
 
}
 
void loop(){
 
    // Consume data if available from the Ethernet client
    if (client.available()) {
        char c = client.read();
        Serial.print(c);
    }
 
    // If there's no net connection, but there was one last time
    // through the loop, then stop the client:
    if (!client.connected() && lastConnected) {
        Serial.println();
        Serial.println("Disconnecting...");
        client.stop();
    }
 
    xbee.readPacket();
 
    if (xbee.getResponse().isAvailable()) {
        // We've got something to read
 
        if (xbee.getResponse().getApiId() == RX_16_RESPONSE ) {
            // We've got a rx packet
 
            int sourceAddress;
 
            xbee.getResponse().getRx16Response(rx16);
 
            uint8_t option = rx16.getOption();
            sourceAddress  = rx16.getRemoteAddress16();
 
            //uint8_t analogHigh = rx16.getData(0);
            //uint8_t analogLow = rx16.getData(1);
 
            uint8_t message = rx16.getData(0);
 
            //int value = analogLow + (analogHigh * 256);
 
            Serial.println(message);
 
            // Flash led to indicate success
            flashLed(statusLED, 5, 50);
 
            if(sourceAddress == XMAIL_ADDRESS){
                switch(message){
                    case XMAIL_MSG_RESET_CODE:
                        sendNotification(XMAIL_NAME, XMAIL_MSG_RESET); break;
                    case XMAIL_MSG_NEW_LETTER_CODE:
                        sendNotification(XMAIL_NAME, XMAIL_MSG_NEW_LETTER); break;
                }
            } else if (sourceAddress == XWASH_ADDRESS){
                // TODO for the next sensor
            }
 
        } else {
            // Not something we were expecting
            flashLed(statusLED, 2, 1000);
        }
 
    } else if (xbee.getResponse().isError()) {
 
        //nss.print("Error reading packet.  Error code: ");
        //nss.println(xbee.getResponse().getErrorCode());
        flashLed(statusLED, 2, 1000);
    }
 
    // Store the state of the connection for next time through
    // the loop:
    lastConnected = client.connected();
 
}
 
// Function that will flash a led n times with a delay of wait between each flash
void flashLed(int pin, int times, int wait) {
 
    for (int i = 0; i < times; i++) {
        digitalWrite(pin, HIGH);
        delay(wait);
        digitalWrite(pin, LOW);
 
        if (i + 1 < times) {
            delay(wait);
        }
    }
}
 
// Function that will connect to the GCM service and send the notification
void sendNotification(const char* sensor, const char* message) {
 
//    Serial.println(sensor);
//    Serial.println(message);
//    Serial.println();
 
    if (client.connect(server, 80)) {
        // If there's a successful connection:
        Serial.println("Connecting...");
 
        char getURL[] = "GET /normandy/server/send.php?secret=XXXXXXXXXX&sensor=";
        strcat(getURL, sensor);
        strcat(getURL, "&message=");
        strcat(getURL, message);
        strcat(getURL, " HTTP/1.1");
 
        // Send the HTTP PUT request:
        client.println(getURL);
        client.println("Host: www.adrova.com");
        client.println("User-Agent: arduino-ethernet");
        client.println("Connection: close");
        client.println();
    } else {
        // if you couldn't make a connection:
        Serial.println("Connection failed.");
        Serial.println("Disconnecting.");
        client.stop();
    }
}

As you can see, I have the function sendNotification defined which loads the php script with the sensor and messaged passed in the query string. I don’t really need to handle the result (You could potentially handle errors or check if the server is down here to retry to send the notification later). I added a secret variable for “authorization” purposes since a notification is sent every time the page is loaded. The code itself is self-explanatory, just loading the website and that’s it.

Wireless mailbox sensor

June 27, 2013 — 2 Comments

I normally check my mailbox (snail mail) every day before entering my apartment. One day I thought “Wouldn’t it be nice if I know if I have new letters without having to check the mailbox?” That’s how I came up with the idea to install a wireless sensor that will notify me when somebody leaves something from me in the mailbox.

The idea itself it’s nothing new and it’s very common among Arduino enthusiasts. What I think is unique is the combination of tools I used (or at least I couldn’t find a similar solution to the setup I have).

In this posts I will just describe the wireless mailbox sensor. It’s basically one home-made Arduino (you can see this post on how you can build your own one) with an Xbee Series 1 transmitter and a couple of sensors: A DFRobot DFR0028 Tilt Sensor and a Snap-Action switch (similar to this one).

The sensors

This is the planned sensor setup

This is the planned sensor setup

The tilt sensor will detect when a new letter arrives and it’s placed in the small cover of the mailbox. It will trigger when the mailbox lid is lifted. Originally I thought of having a light sensor in there, but it was just easier to have an on-off sensor because I only need to recognize these two states. The snap-action switch will detect when I open the mailbox with the key (to reset the detection) and it’s placed right where the lock mechanism is resting. The snap-action switch is normally closed and when I use the key and rotate the lock mechanism, the switch will open, thus triggering the sensor. Every time a sensor is triggered, the Arduino will send a message to the coordinator (i.e. another Arduino I have in my apartment also with an Xbee attached).

The power source

I started my prototype based on this post from the adafruit forum. It also provided me with a solution to run the sensor on batteries. Originally I had no idea how to deal with that. The simple setup should not consume a lot of power, but the Xbee could, so the idea from this guy was to cut the Xbee power when it’s not sending anything, and only power it up when you need to send something (BTW, that implies one-way communication, which I don’t like since I want to be able to reset the mailbox not only with the key, but also remotely, but I will try to achieve this on a further version of the sensor). Another tip from that same post to save some power, was to put the processor to sleep when is not doing anything. Basically the atmega328 has the capability to be put to sleep, and be woken up by interrupts in two pins (2 and 3). More information about this here. This way, the Arduino will wake up every time a sensor triggers, the it will give some power to the Xbee and send the corresponding message, then cut the power again to the Xbee and finally it the will go back to sleep.

The Xbee communication

Because I’m thinking this sensor will be just a component of a bigger mesh of sensors, I wanted to avoid using broadcast messages and direct my messages to a particular Xbee (so called the coordinator). I’m using the xbee-arduino library for doing this. For using API mode (i.e. this library) you will need to configure manually the Xbees on your mesh. In windows you can use the X-CTU application Digi provides to configure and update Xbee firmware. For mac, you can use moltosenso iron which is free and provides the basic functionalities to configure your Xbees. I use DFRobot Basic Breakout to program my microcontrollers, and it is also useful to configure the Xbee. I also use the Sparkfun’s Xbee Explorer Regulated to manage the 5V to 3.3 Voltage conversion is needed to power the Xbees. It’s also handy to plug some headers into the board that fit for example a breadboard. If you want to configure the Xbee using this two boards, you just need to connect the VCC of the Basic Breakout to 5V of the Explorer, GND to GND, RX of the Breakout to DOUT (CAREFUL: RX in the DFROBOT Breakout is actually TX), and TX to DIN. Doing this, you would normally get access to the Xbee configuration.

Once you have access to the Xbee on your computer, you need to set up the following parameters in your Xbee (this information is for Series 1 which I use):

For the coordinator:

PAN: 965  -> This is you network id, the number you use here should be use in all Xbees in the network for communicate with each other.
MY: 1000 -> This will be the 16-bit address of this particular Xbee.
CH: C -> This is the newtork channel, this value will need also to be the same for all Xbees in the network.
CE: 1 -> This indicates this Xbee is a Coordinator.
AP: 2 -> This indicates this Xbee will use API mode.

For all other Xbees the configuration would be the same except for:

MY: 1001 -> This will be the 16-bit address of this particular Xbee.
CE: 0 -> This indicates this Xbee is NOT a Coordinator.

More information about this configuration and also configuration for Xbees Series 2 here: XBeeConfiguration.

The software

You can see the code for the mailbox sensor here:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#include <XBee.h>
#include <avr/sleep.h>
 
// Constant definitions
const uint8_t XMAIL_MSG_NEW_LETTER_CODE = 0;
const uint8_t XMAIL_MSG_RESET_CODE = 1;
 
// Pin definitions
int ledPin            = 10;
int xBeeTransistorPin = 13; // xBee Powered when HIGH
int newLetterPin      = 2;  // Mailbox opened (letter introduced)
int mailboxOpenedPin  = 3;  // Mailbox opened (with key)
 
// Control variables
boolean flag_error;
boolean flag_start;
 
// Store the message to send
uint8_t message[] = {0};
 
// Set up XBee configuration
XBee xbee = XBee();
 
void setup(){
 
    // Set up pin modes
    pinMode(newLetterPin, INPUT);
    pinMode(mailboxOpenedPin, INPUT);
    pinMode(xBeeTransistorPin, OUTPUT);
    pinMode(ledPin, OUTPUT);
 
    // Set up Serial XBee
    Serial.begin(9600);
    xbee.setSerial(Serial);
 
    // Set up initial values
    turnXBeeOff();
    digitalWrite(ledPin, LOW);
    flag_error = false;
    flag_start = true;
}
 
void loop() {
 
    // If the arduino was just powered up, do nothing
    if(flag_start){
        flag_start = false;
        SleepNow();
    }
 
    //payload[0] = message >> 8 & 0xff;
    //payload[1] = message & 0xff;
 
    // 16-bit addressing: Enter address of remote XBee, typically the coordinator
    Tx16Request tx = Tx16Request(0x1000, message, sizeof(message));
    // Prepare a response
    TxStatusResponse txStatus = TxStatusResponse();
    // Turn on XBee power
    turnXBeeOn();
    // Give it some time
    delay(2000);
    // Send signal...
    xbee.send(tx);
 
    // ... and wait for a response
    if (xbee.readPacket(3000)) {
        // Should be a znet tx status
        if (xbee.getResponse().getApiId() == TX_STATUS_RESPONSE) {
 
            xbee.getResponse().getZBTxStatusResponse(txStatus);
            // get the delivery status, the fifth byte
 
            if (txStatus.isSuccess()) {
                // success.  time to celebrate
                flag_error = false;
            } else {
                // the remote XBee did not receive our packet. is it powered on?
                flag_error = true;
            }
        } else {
            // Not something we were expecting
        }
    } else if (xbee.getResponse().isError()) {
        //nss.print("Error reading packet.  Error code: ");
        //nss.println(xbee.getResponse().getErrorCode());
        flag_error = true;
    } else {
        // local XBee did not provide a timely TX Status Response.  
        // Radio is not configured properly or connected
        flag_error = true;
    }
 
    // Cut off power to XBee
    delay(3000);
    turnXBeeOff();
    delay(2000);
 
    // TODO Retry 3 times
    if(!flag_error){
 
        // Back to sleep
        SleepNow();
    }
 
}
 
void turnXBeeOn() {
    digitalWrite(xBeeTransistorPin, HIGH);
}
 
void turnXBeeOff() {
    digitalWrite(xBeeTransistorPin, LOW);
}
 
// Interrupt functions which will save from where the wake up was triggered
void aNewLetterArrived()
{
    sleep_disable();     // first thing after waking from sleep: disable sleep...
    detachInterrupt(0);  // disables both interrupt {0,1} so the wakeUpNow{0,1} code
    detachInterrupt(1);
    message[0] = XMAIL_MSG_NEW_LETTER_CODE;
}
 
void mailboxWasOpened()
{
    sleep_disable();     // first thing after waking from sleep: disable sleep...
    detachInterrupt(0);  // disables both interrupt {0,1} so the wakeUpNow{0,1} code
    detachInterrupt(1);
    message[0] = XMAIL_MSG_RESET_CODE;
}
 
// Function to put the Arduino to sleep
void SleepNow()
{
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
 
    sleep_enable();
 
    attachInterrupt(0, aNewLetterArrived, LOW);
    attachInterrupt(1, mailboxWasOpened, LOW);
 
    sleep_mode();
}
 
// Function to flash the status led
void flashLed(int times, int wait) {
 
    for (int i = 0; i < times; i++) {
        digitalWrite(ledPin, HIGH);
        delay(wait);
        digitalWrite(ledPin, LOW);
        delay(wait);
    }
}

I had some issues sending two bytes instead of only one. So at the end I opted for just sending a byte (uint8_t) of information with the Xbee, anyways this would allow for 256 of different encoded messages (I only needed two). I still have yet to deal with errors, so far I assume no communication problem occurred.

So far everything works fine. I’m trying to make a custom PCB to reduce some space… I’ll upload the schematics once I have them.

It's a bit hairy, but the next step after some weeks of testing will be to print a PCB

It’s a bit hairy, but the next step after some weeks of testing will be to print a PCB

Schematic