Introduction: Make an Easy Button Wireless
The XBee node -- a popular implementation of the Zigbee protocol of 802.15.4 wireless devices -- is not by any means the cheapest way to create a wireless link to an Arduino-based (or similar) project, but it certainly seems the simplest.
And thus this Instructable -- a rather long telling of a rather simple project.
Step 1: Take It Apart
Pry out the four rubber feet on the bottom and remove the four screws there. Pull the dome and surround off. Unscrew the two screws holding the circuit board -- keep the screws in order; the screws holding the board are the long ones. Pull out the spring plate. Unscrew the last four screws and remove the last big chunk of plastic.
For this project, we need to tear down a little further. De-solder all the components on the circuit board. Desolder and discard the wiring harness. Work the speaker free gently with a screwdriver, cutting some of the glue first with a hobby knife if necessary.
And now we come to the first picture (seriously, if you can't take apart a plastic toy without pictures, you probably shouldn't be trying to wire up an XBee node.) To get a nice space for the parts I wanted I needed to remove the lump of plastic in the center of where the speaker sat. My Dremel made short work of that.
Step 2: Fit the Components
You don't need either, of course. But using a breakout, at least, makes it easier to pull out the XBee for reprogramming or upgrade.
Step 3: Wire It Up
It is hard to see, but the 3.3V from the regulator goes to pin 1 of the XBee, and the grounds (pin 10 of the XBee and the shared ground from the 3.3v step-up) are brought together along with the 3V input of the regulator. Lastly, there is a black "signal" wire on DO0 (pin 20 on the XBee). This is the pin I'm choosing to use for my button signal. I'll explain as soon as we get done soldering!
We are using the original battery compartment for this (makes it easy to change the batteries.) The large lugs on the battery compartment are the closest thing to a proper bus we have, so all the ground leads are brought to this one spot and soldered together there.
The second picture is misleading -- it is from the first time I did this (thus the different colors of wire).
Oh, and late in the day I decided I really wanted an electrolytic capacitor to store up the not-insignificant juice the XBee Pro would demand when transmitting. It is spliced on to the leads of the step-up because there was really no better place to fit it.
Attach the circuit boards to the plastic with double-stick tape, and re-attach the top part of the inner button, pulling the leads through the small gap right by the battery terminals.
Step 4: Silencing
The membrane switch itself doesn't give that nice bounce. The way the button works, the top dome rides on four plastic posts that keeps it aligned, and it presses down on a sheet of spring steel. Two "notches" in the spring steel are bent the opposite way, and as the button descends they are forced to snap through to the other direction. Harder to explain than it is to see. Anyhow; to silence the clicker but keep that nice button feel you take a pair of pliers and straighten out the notches.
Killing the chip was just part of the process of cleaning the wiring. After de-soldering everything, I cut through the traces around the chip with a hobby knife. Your circuit board may look different but the principle is the same. Take out the handy VOM or continuity tester, and figure out which pads are connected when you press the button.
Because of the sliding posts from the button itself, there is not really a lot of space in here. So the neatest way of making sure no stray wire fouled up the button, I put a jumper on the remaining scraps of the circuit board so the pads that connected to the button could be brought out to one edge of the circuit board.
Step 5: Why Are We Doing This?
So, meet the XBee. It is a nicely complicated little digital transceiver. It doesn't just send a signal out into the airwaves and hope it gets picked up without interference. Instead it connects with other nodes, checks the transmission path, reads off signal strength, sends a digitally encoded message multiple times asking for acknowledgment from the receiver...
Anyhow. The XBee is designed for secure, low-BAUD, extremely low power usage digital transmission. Out of the box they act as a nearly-transparent serial connection. Connect one to the serial port on one computer, connect another to a second computer, and what you type into the terminal window will show up with almost no delay on the other. But it has a little trick (on the Series 1 chips at least) that makes them even easier to use for a job like this; I/O Line Passing.
What this means, is, if two XBees are set up correctly, when you change the state on one of the pins on the transmitter, the same pin (or the matching pin for the analog/PWM pins) changes state identically after it gets the radio message.
Which allows something like this project; all we are doing is pulling one pin low. The corresponding pin on the matching device will also go low, which is the same as a button press to an Arduino or similar. Or it The can directly drive a small LED, or (with the right power transistor) a relay or a larger load.
(Pulled down? Well...the XBee has internal pull-up resistors. Which seem to be turned on in the factory default because I've had no trouble doing it this way. When I've gotten more sleep I'm going to look into that closer.)
((The output can be set to default HIGH or default LOW, so you really have a lot of flexibility in how you set up this line passing. And that's not even getting into the analog passing, which gives you a choice of sample rate and number of samples to average before transmission, before summing the ADC input of one into a PWM output of the other. This is clean enough you can actually connect a potentiometer to one XBee and directly control a servo on the other.))
And that's what makes these chips so attractive for projects like this. You don't need a CPU to control it. You don't need the voltage regulator. You don't even need a breakout board (if you are comfortable with soldering to fine-pitched legs.) All you need is the sensor, the XBee, and a power source. And since these are designed for low-power operation (with multiple sleep modes, even), they can last for a very long time in some remote location passing along the output from a sensor to the rest of the networked devices.
You don't need anything but the XBee and a battery...once it is set up, that is. Because out of the box it only does serial data transmission. And unless you really want to play with remote command mode, it is necessary to find a way to connect it to the computer of your choice while you program in the settings you want.
Step 6: Programming
You can talk to one using an ordinary terminal program, but this is inconvenient on OS-X because the XBee doesn't send back the right new line command and all the replies get jumbled together. Fortunately Tom Igoe has stepped in with a simple terminal program written in Processing (and various people have expanded it since). I am using a modified version of Tom's original program, which I entered by hand out of the text in his book "Making Things Talk."
Here's the current version of the code I am using:
import processing.serial.*;
Serial myPort;
String portnum;
String outString = "";
String inString = "";
int receivedLines = 0;
int bufferedLines = 8;
void setup()
{
size(400, 300);
PFont myFont = createFont(PFont.list()[3], 14);
textFont(myFont);
println(Serial.list());
portnum = Serial.list()[3];
myPort = new Serial(this, portnum, 9600);
}
void draw()
{
background(0);
text("Serial port: " + portnum, 10, 20);
text("typed: " + outString, 10, 40);
text("received: " + inString, 10, 80);
}
void keyPressed()
{
switch (key)
{
case '\n':
myPort.write(outString + "\r");
outString = "";
break;
case 8:
outString = outString.substring(0, outString.length() -1);
break;
case 65535:
break;
case '+':
myPort.write(key);
outString += key;
break;
default:
outString += key;
break;
}
if (outString == "+++")
{
delay(2000);
outString = "/n";
}
}
void serialEvent(Serial myPort)
{
// inString = "Serial Event Recieved!";
// delay(2000);
int inByte = myPort.read();
inString += char(inByte);
if (inByte == '\r')
{
inString += '\n';
receivedLines ++;
if (receivedLines > bufferedLines)
{
deleteFirstLine();
}
}
}
void deleteFirstLine()
{
int firstChar = inString.indexOf('\n');
inString = inString.substring(firstChar + 1);
}
Short form here. You are using AT commands, which start with an attention code (+++, no carriage return) to get the chip's attention, then a series of commands each suffixed by "AT." They are all documented in the manual for the XBee, and if you don't want to go that far, the basic commands for setting up a line passing mode are copied in several places on the web -- here, for instance.
As I recall, the only things I had to set on the transmitter end were:
+++ //gets the node's attention, it will reply with "OK"
ATMY2 //this is the node's self-identity
ATDL3 //this is the low byte of the address the node wants to talk to
ATID5555 //this is the PAN ID; the ID for the network both devices are on
ATD03 //this sets up pin 20 -- Digital I/O 0, as a digital input
ATICFF // monitors all the I/O pins and sends a transmission when any of them change. This is a bitfield, if you don't want them all.
ATWR // don't forget this command! It writes the settings into memory
ATAC // this command causes the node to start using the new settings (and close command mode).
You can also force sample at intervals using the IT and IR commands, as well as -- by using the right pin -- have the node sleep when there is no input present.
My recieiver needed to have the reciprocal IDs, and be set up for pin output:
+++
ATRE // reset to factory default -- let's be safe here!
ATMY3
ATDL2
ATID5555
ATD05 // now pin 20 is set to change state depending on data recieved from the transmitter
ATWR
ATAC
As you may have noticed, there is nothing that forces the transmission to be one-way only. Nodes will happily communicate bidirectionally with the serial lines (which haven't been affected by this line passing mode, let me note!) and they will happily echo I/O lines in both directions as well.
I highly recommend getting the XBee nodes talking on the breadboard before you start screwing your button back together.
Oh; and the other end? Detecting a "pulled LOW" is as easy as running a wire from appropriate I/O pin on the XBee to an open I/O pin on an Arduino and writing;
const int xbeePin = 8;
const int ledPin = 13;
void setup()
{
pinMode(xbeePin, INPUT);
pinMode(ledPin, OUTPUT);
}
void loop()
{
if (digitalRead(xbeePin) == LOW)
{
digitalWrite(ledPin, HIGH);
}
else
{
digitalWrite(ledPin, LOW);
}
}
(The above code SHOULD work but I typed it by eye right here in the Instructable. I've gotten far to used to having the Arduino -- or Processing -- IDE check my syntax for me!)
The first use I put my Easy Button to is to connect the receiver XBee to an Arduino I already had set up to spit out a MIDI note message whenever it saw the appropriate trigger signal. We almost used it as game show-type buzzer for the musical "Lucky Duck." A little later I connected the MIDI cable to our lighting console and was able to run light cues from outside of the light booth on one show where the tech staff was short-handed.
The horrible mess in the second picture is me using the button to change programs on the BlinkM I am modifying (aka connected it to my Adafruit ISP and wrote new software within the Arduino IDE). The latter may be a bit wasteful of a $20 radio, but it does show the flexibility of a self-contained wireless button.