CHAPTER 2 ■ APPLIANCE HACKING 73 There are many Arduino shields on the market, most with freely available specifications and circuit diagrams. Each shield has a specific task and includes the following problem domains. Ethernet Networking There is the Arduino Ethernet Shield that supports four concurrent connections, working in either client or server mode using TCP or UDP packets. It is based on the Wiznet W5100 chipset and uses digital pins 10–13 to communicate. Wireless Control The main contender here is the Xbee shield, which uses the ZigBee wireless protocol, meaning it is not directly compatible with existing WiFi connections but can act as a radio transmitter and receiver for basic scenarios and has an indoor range of about 30 meters. Sound The LadyAda Wave shield provides playback support for .wav files, up to 16-bit mono 22KHz samples, which is a marked improvement over the PCM examples we saw earlier. To handle the problems of memory, this shield also supports SD cards (provided they’re formatted to FAT16 and have all their files in 8.3 format in the root directory). It is still quite a heavy library, however, occupying 10KB of flash memory, but it is still the best audio solution. It also provides a small power amplifier, able to drive 1/8W 8 ohm speakers. This could be used for a talking clock, a kitchen-based stopwatch, or a virtual pet. Motors Also from LadyAda, the motor shield supports medium power control for DC, servo, and stepper motors. The total number of supported motors and the total power drain are governed by the specific motors themselves, but the quoted specs permit you two DC servos (on 5V) and up to four DC motors, two stepper motors, or one stepper and up to two DC motors. This shield does utilize a lot pins for control, and a lot of power, but can be used to lock cat flaps or build a robot. Example: The Arduino Welcome Mat With this knowledge, you can build a simple circuit, write some Arduino software, and add a Linux-side script to trigger a piece of speech whenever someone enters or leaves the house. I’ll show how to use the Arduino to monitor the state of a pressure mat (using a normally open switch) placed under a rug and transmit messages to the PC. The Arduino will also remember the current state, so once the switch inside the pressure mat has been stepped on, the house state is assumed to be “vacant” since people have left the house, and when the switch is closed again, the state changes to “occupied.” The circuit is a simple switch, as shown in Figure 2-2. CHAPTER 2 ■ APPLIANCE HACKING 74 ■ Note You can also use a pressure mat to determine whether you’ve gotten out of bed after your alarm has gone off, and you can use the act of leaving the bedroom as a means to stop the alarm from sounding. The Arduino software is slightly more complex since you are looking for the case when the switch goes from the closed state to the open, since people might stand on the mat for a minute or more while they put on their coat. I have also included a timer here so that the house state doesn’t change if a second rising edge (caused by someone else stepping on the mat) is detected within two seconds of the first. This is to allow several people to leave the house at once, without the state getting confused. Naturally, this doesn’t solve the problem of only some occupants leaving the house, but it’s a start! int inputSwitchPin = 2; int lastState; long timeLastPressed; long debouncePeriod = 100; int houseState; long doormatUnblockAt; long doormatDelayPeriod = 2000; int blockSteps; void setup() { Serial.begin(9600); pinMode(inputSwitchPin, INPUT); // declare pushbutton as input lastState = digitalRead(inputSwitchPin); timeLastPressed = millis(); blockSteps = 0; houseState = 0; } void loop() { int pinState = digitalRead(inputSwitchPin); if (pinState != lastState && millis() - timeLastPressed > debouncePeriod) { if (pinState == 0) { // i.e., pressed if (!blockSteps) { houseState = 1-houseState; blockSteps = 1; Serial.print(houseState?"1":"0"); } doormatUnblockAt = millis() + doormatDelayPeriod; } timeLastPressed = millis(); lastState = pinState; } CHAPTER 2 ■ APPLIANCE HACKING 75 if (millis() > doormatUnblockAt) { blockSteps = 0; } } Finally, the USB script trigger code shown previously is adapted to watch for the serial messages of 0 and 1: if (v == '1') { system("enter_house.sh"); } else if (v == '0') { system("leave_house.sh"); as before which runs either the enter_house.sh script for entering: say default welcome home x10control default on lounge_light or the leave_house.sh script for leaving as appropriate: say default Goodbye RAIN=`weatherstatus | head -n 1 | grep -i "[rain|shower]"` if [ "$?" -eq 0 ]; then say default Remember your umbrella it might rain today. say default $RAIN fi In these code samples, I have used simplified commands without paths to demonstrate the process. The commands themselves are the abstractions that appear in the Minerva system, covered in Chapter 7. This “house state” information could be extended to switch on security lights or redirect personal e- mails to a work account, for example. To connect the Arduino output to the rest of the system, you will either need to use a networking shield (either wired or wireless, depending your connection points) or need a local PC with one. The advantage of a PC (such as a Fit-PC2, notebook, or similarly small machine) is that it can be reused as a display and control panel. In this example, having a panel by the door displaying the tasks for the day and printing reminders about the weather can provide a suitable excuse for the extra expense. ■ Note With minor modifications, you could employ two pressure mats (one inside and one outside) to more correctly determine the direction of travel. CHAPTER 2 ■ APPLIANCE HACKING 76 Depending on the type of pressure mat used, you could also place one under a rug by the cat flap, since your pet’s weight is normally enough to trigger it. This would allow you to interface it with a LEGO robot that could then feed the cat when they returned from their customary wander. ■ Caution Most pressure mats cannot be cut to size because of their internal electronics. Example: The Arduino Dictaphone Most people make notes on the back of train tickets and shopping lists because the effort to switch on a computer or find the phone’s notepad application is too much. By combining the interface-less environment of an Arduino and the audio functionality of a monitor-less PC, you can create a very simple voice recorder. You start with the basic switch circuit, but you then replicate it three times—once for each of the record, play, and erase buttons, as shown in Figure 2-7. Figure 2-7. Using three switches and inputs to control a voice recorder You can then adapt the similarly banal Arduino control program to check for three buttons instead of one, remembering to debounce each of them. There’s also a slight change here; since you’re using the record button to govern the length of the record, consequently it sends a start message when the button is pressed and a stop message upon release. int pinStates[3]; int lastStates[3]; long timesLastPressed[3]; int inputSwitchPins[3] = {2,3,4}; CHAPTER 2 ■ APPLIANCE HACKING 77 void setup() { Serial.begin(9600); for(int i=0;i<3;++i) { pinMode(inputSwitchPins[i], INPUT); lastState = digitalRead(inputSwitchPins[i]); timesLastPressed[i] = millis(); } } void loop() { for(int i=0;i<3;++i) { int pinState = digitalRead(inputSwitchPins[i]); if (pinState != lastStates[i] && millis() - timesLastPressed[i] > debouncePeriod) { switch(i) { case 0: // record Serial.print(pinState==0?"B":"E"); break; case 1: // play if (pinState == 0) { Serial.print("P"); } break; case 2: // delete if (pinState == 0) { Serial.print("D"); } break; } timesLastPressed[i] = millis(); lastStates[i] = pinState; } } } Notice that I have also extended the control codes. Instead of a simple 0 and 1, I now have B and E to begin and end the recording, P to play back the sounds, and D to delete them all. You can then adapt the PC-based C code as you did for the doormat to run one of three scripts you’ve written on the PC to control the sound card: if (v == 'B') { system("vox_record.sh start"); } else if (v == 'E') { system("vox_record.sh stop"); } else if (v == 'P') { system("vox_play.sh"); } else if (v == 'D') { system("vox_delete.sh"); as before . build a robot. Example: The Arduino Welcome Mat With this knowledge, you can build a simple circuit, write some Arduino software, and add a Linux- side script to trigger a piece of speech whenever. default welcome home x10control default on lounge_light or the leave_house.sh script for leaving as appropriate: say default Goodbye RAIN=`weatherstatus | head -n 1 | grep -i "[rain|shower]"`. By combining the interface-less environment of an Arduino and the audio functionality of a monitor-less PC, you can create a very simple voice recorder. You start with the basic switch circuit,