Between my officemate and me, we have dozens of devices drawing power in our office: two laptops, two monitors, four or five lamps, a few hard drives, a soldering iron, Ethernet hubs, speakers, and so forth. Even when we’re not here, the room is drawing a lot of power. What devices are turned on at any given time depends largely on which of us is here, and what we’re doing. This project is a system to reduce our power consumption, particularly when we’re not there.
When either of us comes into the room, all we have to do is tap our key fobs on a reader mounted by the door, and the room turns on or off what we normally use. Each of us has a keyring with an RFID-tag key fob. The reader by the door reads the presence or absence of the tags.
The reader is connected to a microcontroller module that controls the AC power lines using a device called the PowerSwitch Tail, shown in Figure 4-1. Each of the various power strips is plugged into one of these. Depending on which tag is read, the microcontroller knows which power strip to turn on or off.
The Arduino Uno is a good model of Arduino to get started with, and it will work for all the microncontroller-based projects in this book.
Parallax’s RFID Reader Module, available from Maker Shed as part of a starter pack or by itself.
The starter pack includes several tags, and you can buy them separately.
You can use a half-size or mini breadboard to make connections between the reader and the USB-to-TTL serial adaptor.
Each one can control 15 amps of current. They are available from Maker Shed.
The RFID module is connected to the microcontroller as in Chapter 3. Connect the microcontroller to the PowerSwitch Tails as shown in Figure 4-2:
“1: +in” to Arduino digital pin 2
“2: -in” to breadboard ground
“1: +in” to Arduino digital pin 3
“2: -in” to breadboard ground
This project controls high-voltage, high-current alternating current. Even though the PowerSwitch Tail is designed to make this safe, you should take extra care when wiring or rewiring the circuits for this project. Make sure everything is wired correctly and mounted securely before you plug either the Arduino or the PowerSwitch Tails in.
Run this sketch to test the PowerSwitch Tail:
/* PowerSwitch Tail test language: Wiring/Arduino */ const int switchOne = 2; // the first PowerSwitch Tail control pinconst int switchTwo = 3; // the second PowerSwitch Tail control pin void setup() { pinMode(switchOne, OUTPUT); // Configure the pins
pinMode(switchTwo, OUTPUT); digitalWrite(switchOne, LOW); // Make sure they are off
digitalWrite(switchTwo, LOW); } void loop() { // turn on first power strip, turn off the second
digitalWrite(switchOne, HIGH); digitalWrite(switchTwo, LOW); delay(2000); // turn on second power strip, turn off the first digitalWrite(switchTwo, HIGH); digitalWrite(switchOne, LOW); delay(2000); }
Here’s what happens in the sketch:
First, the sketch initializes two variables, switchOne
and switchTwo
, to hold the pin numbers of the
two PowerSwitch Tail units you have connected.
In setup()
, you configure the
pins to be OUTPUT
s.
Next, we make sure the pins are off (this is the default, but it makes it clear that your sketch expects to start with everything off).
The loop()
function
repeatedly turns the first switch on and the second off, then waits
two seconds, and does the opposite.
The result is that each PowerSwitch Tail will turn on and off every two seconds. You probably don’t want to leave this running for very long, unless you’re trying to do endurance tests for light bulbs (or whatever you have plugged in).
Now that you’ve got control over your PowerSwitch Tails, you can combine the RFID and the PowerSwitch Tail code.
The following sketch will toggle the state of each PowerSwitch Tail when the corresponding RFID tag is held up to the reader. You can now use the RFID reader like a light (or power strip) switch:
/* RFID–to-PowerSwitch Tail control language: Wiring/Arduino */ #include <SoftwareSerial.h> // Bring in the software serial libraryconst int tagLength = 10; // each tag ID contains 10 bytes const int startByte = 0x0A; // Indicates start of a tag const int endByte = 0x0D; // Indicates end of a tag const int rxpin = 6; // Pin for receiving data from the RFID reader const int txpin = 7; // Transmit pin; not used String currentTag; // String to hold the tag you're reading
String tag[] = { "04162F7CAC", "0415EA09BE"}; // List of tags
int numTags = 2; // Number in that list // PowerSwitchTail unit pins and unit states:
int numUnits = 2; // Two PowerSwitch Tails int unit[] = {2, 3}; // Pins 2 and 3 int unitState[] = {LOW, LOW}; // Both start in the off position long lastRead; // the time when we last read a tag long timeOut = 1000; // required time between reads SoftwareSerial rfidPort(rxpin, txpin); // create a Software Serial port void setup() { lastRead = millis(); // Initalize to the sketch's start time
// begin serial communication with the computer Serial.begin(9600); // begin serial communication with the RFID module rfidPort.begin(2400); // Initialize all the PowerSwitchTail controller pins.
for (int thisUnit = 0; thisUnit < numUnits; thisUnit++) { pinMode(unit[thisUnit], OUTPUT); // Enable this pin for output digitalWrite(unit[thisUnit], unitState[thisUnit]); } } void loop() { // read in and parse serial data:
if (rfidPort.available()) { readByte(); } } void readByte() { char thisChar = rfidPort.read(); // Read a character from the port
// depending on the byte's value, // take different actions: switch(thisChar) { // if the byte == startByte, you're at the beginning
// of a new tag: case startByte: currentTag = ""; break; //if the byte == endByte, you're at the end of a tag:
case endByte: checkTags(); break; // other bytes, if the current tag is less than
// 10 bytes, you're still reading it: default: if (currentTag.length() < 10) { currentTag += thisChar; } } } void checkTags() { // iterate over the list of tags:
for (int thisTag = 0; thisTag < numTags; thisTag++) { // if the current tag matches the tag you're on:
if (currentTag.equals(tag[thisTag])) { // Only flip a switch if the tag has been away for a while
if (lastRead + timeOut < millis()) { // unit number starts at 1, but list position starts at 0: Serial.print("unit " + String(thisTag +1)); // change the status of the corresponding unit:
if (unitState[thisTag] == HIGH) { unitState[thisTag] = LOW; Serial.println(" turning OFF"); } else { unitState[thisTag] = HIGH; Serial.println(" turning ON"); } // Set the switch to the new state. (16) digitalWrite(unit[thisTag], unitState[thisTag]); } lastRead = millis(); // mark the last time you got a good tag (17) } } }
The top part of the sketch is essentially the same as what you saw in the example in Chapter 3.
This string contains the tag that’s currently being read. As the RFID reader collects each byte of the tag ID, it will add it to this string until it’s full.
This array contains a list of tags that the sketch will accept.
This array should have the same number of elements as the array
(unit[]
) that you’ll see later.
That’s because each element in this array corresponds to one
PowerSwitch Tail unit. That means that the first RFID tag in the
tag[]
array will turn the first
PowerSwitch Tail on and off, and the second RFID tag will turn the
second PowerSwitch Tail on and off.
Here’s where you set up an array (unit[]
) containing the Arduino pin number
corresponding to a single PowerSwitch Tail. You also set up an array
to track the current state (HIGH
or
LOW
) of each unit.
This variable is used to make sure you don’t continuously toggle a switch on and off as long as you hold a tag in place. The Parallax reader continuously transmits a tag as long as you hold it in place. Later on, you’ll see that the sketch requires that you keep the tag away for at least one second before it will let you toggle a switch.
This loop goes over each pin in the unit()
array and sets its initial state
(LOW
, or off).
In the loop()
function, you
look for any serial activity from the RFID reader, and call readByte()
if there is any.
Here, we read one character from the RFID reader.
This switch
statement takes
action based on what was read from the RFID reader. If it sees the
start of tag byte, it initializes the currentTag
string.
If you reached the end of a tag, call checkTags()
.
Otherwise, keep appending the character to the currentTag
string, as long as you don’t
exceed the maximum tag length.
At the top of checkTags()
,
start a loop that iterates over the list of tags.
For each of the tags in the list, check to see if it matches the one you just read from the RFID reader.
This line checks the lastRead
variable to make sure you’ve waited long enough before toggling a
switch.
Here’s where you toggle the switch’s state: if it’s on, set it
to LOW
, or off. If it’s off, set it to
HIGH
, or on.
This line calls digitalWrite()
to turn a PowerSwitch Tail on
or off.
Finally, set lastRead
to the
current time (the time at which you last read a valid tag).
Note that the reader lacks the ability to read multiple tags if more than one tag is in the field. That’s an important limitation. It means that you have to design the interaction so that the person using the system places only one tag at a time, then removes it before the second one is placed. In effect, it means that two people can’t hold their key tags to the reader at the same time. In other words, users of the system need to take explicit action to make something happen. Presence isn’t enough. That’s why I mounted the reader vertically on a wall, so that tags wouldn’t just lay on the antenna all the time.