Smart Home Automation Part II - Appliance Hacking [LINUX]
Converting Existing Technology
There are three classical forms of hacking: software, hardware, and wetware (also known as social engineering). More recently, firmware hacking has become prominent because low-cost hardware utilizing embedded Linux has opened the door to software hackers unable to build hardware. It is hardware hacking, and its associated software, that I will cover in this chapter.
Software Hacks
For most developers, software is an easier hack, since the chance of breaking something irrevocably is much reduced compared to hacking hardware. In fact, when Steve Wozniak and Steve Jobs were building machines at the Homebrew Computer Club, they reasoned that for every one hacker who was interested in hardware, there were 100 who were keen on software, so they focused on the software capabilities of the Apple computer.
Linksys NSLU2
This device, also known as “the Slug,” is a small, embedded Linux device intended to function as a network addressable storage (NAS) device. You plug in power, a network cable, and (up to) two USB hard drives, and you’re able to retrieve the data stored on it from any machine on the same network subnet using the Samba protocol.
The machine itself is silent, powered by an Intel XScale IXP420, and incorporates 32MB of SDRAM and 8MB of flash memory where the software is stored. Its low price point and openness of firmware makes it attractive to hackers wanting to add or change the software on the machine. The machine was officially discontinued in 2008 but is still available in various stores and online.
In its intended form, the Slug is a suitable machine when only a file server is needed, either to be a remote backup for desktop work (perhaps located under the stairs or in a loft) or to provide music to media players around the house. By changing its firmware, however, it can become the following:
- Web server (Apache, PHP, Perl, and Python are all supported)
- Mail server
- Printer server (the cost of a Slug can be less than the difference between a USB printer and its networked equivalent)
- Media server (shared through Squeezebox Server, iTunes, or just Samba)
Before any software changes take place, you must first install an unrestricted version of Linux into the firmware of the device, which takes place through its built-in web interface. There are two main variations here: Unslung (which uses Optware packages) and SlugOS (formally called OpenSlug) based around OpenEmbedded.
Unslung
For basic improvements and a minimal of fuss, Unslung (www.nslu2-linux.org/wiki/Unslung/HomePage) is the preferred option because it installs over the top of the existing firmware and appears very similar to the end user, since it is based on the original Linksys code. This firmware provides extra functionality such as the ability to use FAT-formatted disks, which is necessary if you want to use an existing hard drive, since any disk used in the Slug needs to be specially formatted (to ext3) before use.
It is also possible to install extra software packages through Optware using commands like the following:
ipkg install apache
However, you need to be careful since they are installed to the internal flash memory, which can run out very quickly and therefore lead to an unbootable device. To prevent this, you need to move the operating system onto either one of the external drives (either a USB memory stick or an entire hard drive, depending on the scope and size of your intended additions) in a process known as “unslinging your Slug.” Alternatively, you can perform a hardware hack to increase the memory.
Several hundred packages are available for an unslung Slug, including the following:
- BitTorrent clients
- Streamers for Xbox Media Server
- Apache web server
- Asterisk VoIP
- CUPS
- Git
- MySQL
- SSH
As you can see, most major packages are available, making this a very low-power machine, capable of providing most home tasks. However, they are all limited by the 2.4 kernel, so for more exotic hardware (like Bluetooth), you will need to adopt SlugOS.
SlugOS
SlugOS is a much larger endeavor and treats the Slug like any other piece of hardware, with a base operating system and separate packages for the main functionality, fitting in with the traditional Unix ideology of “do one thing and do it well.” This also removes the Slug-specific functionality such as the web-based configuration tool and basic services like Samba that you will consequently have to xplicitly install.
If you are using the Slug as the basis for a much larger home automation server, then this provides greater scope in the upgrade path, because it gives you access to the many thousands of packages provided by the OpenEmbedded project on which SlugOS is based. But doing so requires that you devote some, or all, of one of your connected hard drives to the operating system, which is a process that requires you to install a small system into the flash memory and then bootstrap the operating system onto the hard drive. In doing so, SlugOS permits the use of a 2.6-based kernel, as well as RAID and NFS functionality.
When using an external USB drive to hold the operating system, always use a hard drive (as opposed to a memory stick). This is because some applications (such as MySQL) create a lot of memory writes to the swap file, and since flash memory becomes unusable after about 100,000 writes, this can happen sooner rather than later. You could, alternatively, assign the swap file to a second (hard) drive, allowing the operating system to boot and run from a read-only memory stick.
Developing on the Slug
To write your own software for the Slug, you should start with SlugOS because this gives you access to the standard development tools, which run on the device allowing the code to be written, compiled, and tested on the Slug. This is known as native development. First you need to run the following command, along with the other standard build packages (all detailed at www.nslu2- linux.org/wiki/HowTo/SlugOSNativeCompileEnvironment), before developing your code as normal:
ipkg install slugos-native
Without a screen, however, you will not be able to use GUI debuggers such as kdbg, which can be a scary downgrade for some. It is perfectly possible to run the machine headless, however, since you can connect remotely through ssh or telnet. This is preferable since the speed of the machine makes a GUI approach impractical for large applications. You would more likely write and test your application for your desktop machine and then, when it’s ready, cross-compile for the Slug.
Cross compilation is a process whereby a compiler running on machine A is able to produce code suitable for machine B. To do this, you need a new set of compilers, tools, headers, and libraries known together as the toolchain) that are built purposely for the other architecture. These are stored separate from your existing development files since they would otherwise conflict with those running your machine. The compilation process then occurs as normal (through either make or a variant of gcc, such as armeb-linux-gnu-gcc) to produce a suitable executable file, or elf in Linux parlance.
The best introduction for the installation of these tools is at www.nslu2- linux.org/wiki/DebianSlug/CrossCompiling.
Note
that if you’re using only existing packages, compilation tools are not necessary in any form, and you can rely solely on the prebuilt packages.
Hacking Game Consoles
Game consoles are great for playing games. Old game console are great for playing old games—and hacking into Linux machines! As the previous generation of machines becomes cheap and technologically obsolete, old game consoles provide a good embedded platform for media players, web servers, control units, and the like. In this section, you will learn primarily at how these machines can be bent to your will, rather than specific uses for them.
It is not smooth sailing, alas, because the manufacturers do not make the compilers or development environments available to anyone outside the computer games industry, and even then it is only with strict nondisclosure agreements (NDAs). Although this should be enough to satisfy an overzealous legal department, they then build in security measures to make it difficult to run home-brew code on them by encrypting the disc format, BIOS, or executable. This in itself makes it an interesting problem for hackers. And since most manufacturers lose money on the console (knowing they’ll recoup it on the games), the subversive hackers enjoy this process even more.
Despite the ever-decreasing circles of cost, it is not worth buying a new console for the sole purpose of hacking it into a Linux machine, but charity shops and online auctions can provide the hacker with the previous generation of hardware at a cost that makes the time and geek-cred worthwhile. With all technological challenges, however, the interest of those leading these console-hacking projects tends to wane as newer and more powerful machines become available or as the time benefit outweighs the cost of alternative equipment. Therefore, it is likely that some (or all!) of these projects might have fallen out of favor by the time you read this, as the Xbox 360 becomes old hat and the PlayStation 4 is the current console du jour.
Sega Dreamcast
The Dreamcast was a game console released in 1998 in the wake of the ill-fated Sega Saturn. It was the winner of an internal competition in Sega between two teams of engineers, led by IBM researcher Tatsuo Yamamoto and Sega hardware engineer Hideki Sato. The resulting console featured elements from both designs and was based around a 200MHz Hitachi SH4 RISC processor and the PowerVR2 graphics chip from VideoLogic, which is fast enough for video playback.
It also featured an optical GD-ROM drive, which supported a standard CD-ROM partition (on which the OS was included), as well as a proprietary format section for the game. The console also marked Microsoft’s first exploration into the hardware arena by combining the Windows CE OS with its DirectX technology.
The console also included a visual memory unit (VMU), which in addition to being a basic memory cartridge also featured an 8-bit process, 48 ×32 pixel LCD screen, D-pad, and four basic buttons. It was intended to be used as an auxiliary play device, rather than a handheld console in itself, and needed to be plugged into a controller in order to function. It was a good idea (and one reused by Sony years later with its PocketStation device, which also featured IR control), but it was not powerful enough for any significant work, compared to the equivalent technology at that time.
Sega was also ahead of the curve by providing peripherals for the Dreamcast such as a mouse, keyboard, and Ethernet (known colloquially as a broadband adapter, or BBA). The latter two are considered essential for the installation and use of Linux.
LinuxDC (http://linuxdc.sourceforge.net) is an old—almost defunct—project that has recently seen a small spurt of new life. It is a reasonably complete distribution suitable for web browsing (with a BBA), movie playback, and emulation. This itself is a good hack, but there are also cables to provide twoway serial communication, either between the Dreamcast and a PC or between peripherals such as infrared (IR) transmitters and receivers. You can either build this cable yourself using one chip and three capacitors from the circuit shown at http://mc.pp.se/dc/serifc.html or purchase a similarly compatible cable, which is known as a DC coders cable.
There is also Dreamcast emulation software for Linux called LXDream, which provides a quick way to verify the working, or not, of various Dreamcast software hacks. You can find this at www.lxdream.org, which also provides all-important links to prebuilt disc image ISOs of LinuxDC, from www.lxdream.org/wiki/index.php?title=Dreamcast_Linux.
Note
Emulators such as LXDream require an image of the machine’s original BIOS. Since these are usually still under copyright, they are not packaged with the emulator and must be extracted from a machine (that you legally own).
In addition to these, there are various pieces of stand-alone software that can be cross-compiled and uploaded via the serial DC coders cable to the Dreamcast. Some of these are shown on the pages at http://mc.pp.se/dc. This includes example source code for text, graphics, sound, and serial communications. By avoiding an operating system, you can make better use of the comparatively small 16MB of memory and 200MHz processor, at the expense of ease of development.
Sony PlayStation
Sony is now promoting its third generation of PlayStation console, imaginatively titled PlayStation 3 (PS3). It is still too new to make it financially viable to turn the whole machine into an home automation device (and since it’s a very capable media playback device already), but you can install Linux on it if you want. (Note that the Slimline version of the PS3 does not support this.) For software engineers, it is a good platform to learn the CELL architecture, but since the kernel isn’t optimized for this chip, the operating system is comparatively slow, meaning the same money and electricity could be put to better use with a standard PC. However, the newness of this machine means there are two older consoles being neglected that can be had for very little money.
PlayStation 1
The first PlayStation released in 1994 (now referred to as the PlayStation 1, to differentiate itself from the PlayStation brand) had a mere 2MB of RAM, a 33.8MHz CPU, and no memory management unit (MMU), meaning that only the uClinux kernel was suitable for porting, but even then converting the rest of the system was difficult. Only one installation seems to have existed, Runix (originally called PSXLinux), although this is now near impossible to find. This is no great loss because, unlike modern game consoles, it didn’t have a hard drive, which limits its use as a Linux machine.
Instead of using existing Linux software, it is still possible to develop applications from scratch using Net Yaroze and utilizing the 128KB memory card for temporary storage. This comprises a black PlayStation, controllers, cables, software, and manuals for software development, and it was intended to get hobbyists into the field by providing a means of compiling software on a PC and uploading it through the serial cable—which was also used for debugging—to the PlayStation. The machine was sold via mail order and to universities but wasn’t a big success. Ultimately, there aren’t many of these devices available, so they’re mostly traded between enthusiasts for excessive money. However, the speed of the machine makes it unsuitable for video playback, and its lack of communication ports further limits its potential.
A much better use for the PlayStation 1 is not as a computer but as a CD player, especially the first versions. This is because the original console had a much improved DAC inside it over later versions, giving it professional audio quality output when playing CDs. This model can be distinguished by the model number SCPH 100x and the separate audio and video RCA outputs.
PlayStation 2
Sony’s second machine was released in 2000 and called the PlayStation 2 (you might detect a naming pattern here!), and it provided a significant increase in power over its predecessor. It had 32MB of RAM and contained separate chips for I/O, sound, and graphics, and it had a main CPU called the Emotion Engine (running at 294.9MHz or 299MHz depending on whether it was an original or later device). This made it a more realistic specification for Linux. Furthermore, an easy route for doing so was provided by Sony, which sold its own supplementary kit, called PS2 Linux. It provided the end user with a hard drive, a keyboard, mouse, an Ethernet adapter, and the necessary software and manuals to develop software.
These kits are no longer sold or supported, but some are available from old stock and from secondhand dealers. Development is much easier on the eye if you ignore the TV output and use a monitor—you’ll need one that does sync-on-green. The supplied distribution is ultimately based on an old version of Red Hat with a 2.2.x kernel, although newer versions now exist, along with Mozilla, XChat, and various lightweight GUI applications; utilities that make use of the USB ports such as printers and cameras; and the network port. Before you take this route, check the current range of available software and kernels at http://playstation2-linux.com.
Outside of the official Linux distribution, there is a wide selection of home-brew software, such as media players and emulators. You can download them as elfs from sites like http://sksapps.com or www.exploitstation.com, or you can build them yourself on a PC using a set of cross-compilation tools and run from a disc, memory card, network, or USB memory stick.
Persuading a PS2 to run nonapproved software is no longer difficult, because several software-only exploits have been discovered, along with the hardware hacks where a so-called modchip is physically soldered into the computer itself.
One soft hack is called the PS2 Independence Exploit, where a disc from a PlayStation 1 game is used to load a special file from the memory card, which in turn triggers a buffer overrun allowing unsigned code to run. This is explained in detail at http://sksapps.com/index.php?page=exploitinstaller.html.
Free McBoot (http://freemcboot.psx-scene.com) is a newer soft hack, which also allows you to run home-brew software by installing special software tied into the specific memory card. It also works on Slimline PS2s and most newer machines (unlike the Independence Exploit), with the only currently known exceptions being those with a date code of 8c and 8d (BIOS Version v2.30).
In addition to the sites listed, several video-sharing web sites include visual tutorials describing the process. And as always, you may be able to find suitable modchips for hardware hacking.
PlayStation Portable
There is one final PlayStation product to mention, the PlayStationPortable (PSP), which was released in 2004 and is based on the PS2. This is a handheld device and benefits the HA hackers with 802.11b WiFi connectivity. IrDA is also featured on the older PSP-1000 models, with the newer version (PSP Go) supporting Bluetooth. All have dual MIPS R4000 chips running at 333 MHz and 32MB of RAM, making them more than capable devices.
Like most consoles, however, the PSP has been designed to run only signed code created by Sony, thereby eliminating its ability to be a programmable computer in any real sense. And, like most consoles, hackers found ways of circumventing this, by exploiting an issue in the original 1.5 firmware.
This ultimately led to a cat-and-mouse game of firmware upgrades by Sony to close these loopholes (and bribing users to upgrade by including new features like web browsers) as the hackers attempted to reopen them or work out ways of downgrading to 1.5 (without triggering the Trojan code that Sony had placed in the firmware, which would “brick” your machine) to use the old exploit.
A wide range of home-brew software is available for PSP including the YouTube viewer PSPTube and a control application for the Xbox Media Center; a good source is http://dl.qj.net/PSP/catid/106.
However, one of the real benefits of this device is that you don’t even need to hack it in order to install a web browser, since (from version 2.0) the NetFront Browser has been included by default, and from 3.90 it has included Skype for VoIP calls. Since most home automation equipment comes with a web server or one can be written fairly easily, a web browser is enough for a fairly high level of home control.
Note
If you plan on using custom or cracked firmware to run home-brew software, always do it early in the device’s ownership life cycle. That way you won’t lose any personal data if something does go wrong in the firmware update process.
Microsoft Xbox
Like the Sony PlayStation 3, Microsoft’s current game console—the Xbox 360—is probably too new and expensive to be worth hacking into something else, although many people have worked on the problem and created the www.free60.org project in doing so.
The Xbox game console was introduced in 2001 and was probably the first time many people considered the possibilities of using a (near-)standard PC connected to their standard TV. This was no doubt helped by the knowledge that Microsoft was using its Windows and DirectX technologies in the unit, both of which were well known, thus presenting a very low barrier to entry for the hackers.
As a unit, the Xbox is based around a 733MHz Pentium III chip with 64MB of RAM, along with a DVD-ROM and a 10GB hard drive—the only last-generation console to do so—by default. It also has Ethernet support and USB ports but with a proprietary form factor and wiring. This remonstrative oversight caused many companies to generate business plans based solely around the sale of Xbox USB converters, of which there are many!
As a physical unit it is quite large (320 ×100 ×260 mm) and has a fairly noisy fan, although hardware hackers might be able to squeeze this down to laptop size and replace the fan with a silent one. In any case, you will certainly want to locate the machine away from your ears and the speaker system in use.
Running Linux
There is a perverse geek pleasure in running Linux on Microsoft’s first flagship console. Furthermore, because we’re coming in at the end of its life cycle, any breakages, void warranties, or bricked machines are less important to us than they would have been a few years ago. Also, the hacker community has had enough time to improve the hacking process so that even those scared of soldering irons can do it without fear. The primary site is www.xbox-linux.org.
Note
Although all Xboxes are capable of running Linux, there are many issues with version 1.6 since the BIOS is no longer stored in a chip that can be (re)flashed. This chip, known as a thin small outline package (TSOP), is instead hardwired, requiring the use of an extra hardware modification chip loaded with the Cromwell Linux BIOS, and even then the output resolutions possible are much reduced (only composite and S-video with overscan, and up to 480p HDTV) because of the different graphics hardware in use. You can determine the version number with the chart at www.xbox-linux.org/wiki/Xbox_Versions_HOWTO.
As is usual with console hacks, there is a hardware way to do it and a software way. The hardware way involves the purchase and soldering of a modchip; although their use has questionable legality, this provides the most expansive scope for hacking since you can do the following:
- Increase the hard drive size (but less than 137GB is still recommended)
- Replace the DVD with another hard drive or DVD-RW
- Use all the disk space under Linux
After fitting the chip, you need to trick the Xbox into running code that allows you to make use of it. This is done through an exploit, such as the MechAssault Exploit, which uses broken code within the game and a well-crafted save game file, at which point you can transfer arbitrary data onto the Xbox (through the network) and run an application to flash the BIOS with it. The process is simple but fiddly, since you need adapter cables, the correct version of the game, and a separate machine. As mentioned, this is the only (relatively) safe way of introducing Xbox Linux to a version 1.6 machine.
The downside of a hardware hack is that the online component of Xbox games (in other words, Xbox Live) are unavailable, since Microsoft will ban anyone found using Linux on its machine.
The software hack involves most of the same steps, with the few added complications explained in detail at www.xbox-linux.org/wiki/Software_Method_HOWTO. Naturally, being software, the Linux install 57 disappears on each reboot—your data remains, but you must reinstate the hack to boot Linux in order to access it.
There was once The Xbox Chocolate Project, where Xbox Linux users would help would-be users modify their machines. It is still going, but fewer volunteers are available. Asking at your local Linux User Group (aka LUG; see www.linux.org/groups for your local group) might be another idea.
The reason for hacking an Xbox is up to you. If you just want to make it play DVDs, then the Microsoft DVD Playback Kit is a better option, and it comes with its own IR remote control. As a set-top box, it might be a little noisy compared to the other solutions I’ve mentioned (and will mention) by today’s standards. But as a secondary (or even primary) file server, web server, or even desktop machine, it has extremely positive geek credentials.
Xbox Media Center
Despite the name, there are more versions of Xbox Media Center (XBMC) running on non-Xbox platforms than there are on the Xbox, including Live CD, all available from www.xbmc.org! This is because the software can only be compiled using the Xbox development kit (XDK), which is made available only to licensed developers. And since Microsoft isn’t happy with Linux developers writing open source software on its console, this is not available to hobbyists in any form. Consequently, the only native versions of XBMC running in the wild are those compiled by licensed developers and those versions that have leaked out from those developers. The legality of such versions is seriously suspect. In either case, you will still need a modified Xbox to run the code, as you would with Xbox Linux.
Note
If you do have access to the Xbox software, then you can use the IR remote control that is supplied with the Microsoft DVD Playback Kit with XBMC.
As software, XBMC contains a lot of top-end functionality and is still in active development. This includes an initiative to reduce the boot time, making it appear more like a set-top box and less like a computer running software—one goal to which all home automation devices should aspire.
Its functionality includes the ability to play back media of almost every format (coming from hard disks, optical media, network shares, online streams and feeds, and DAAP for iTunes), display photographs, run Python-written plug-ins (for weather reports and the like), and play games. It is also able to support the media with data services from IMDb (the Amazon-owned Internet Movie Database) and FreeDB (for CD track listings). For many, the main XBMC hackjoy concerns its skinnability, allowing anyone with a minimum of knowledge to create custom interfaces for the software.
Despite its prominence, there are several forks of XBMC: Boxee, with integration into social networking applications; MediaPortal, a Windows-centric version with PVR handling; Plex, which focuses on the Mac OS X and associated Apple platform-oriented functionality (such as the iTunes app store); and Voddler, which supports media streaming from its (commercial) video-on-demand site.
Hardware Hacks
The hacks in this category will involve changes you can make either to existing hardware or to new hardware you can easily build that controls, or is controlled by, an existing computer.
Linksys NSLU2
The existing NSLU2 unit (aka the Slug) requires no hardware hacks to make it run any of the custom Linux firmwares covered earlier. However, you can improve the unit with various hacks.
Always On
Like most consumer hardware, the Slug has an on/off button. For normal operation, this is fine. But for a home automation system, which is generally intended to work 24/7 (like the rest of the house), this can cause problems whenever there is a brief power outage, since the machine then needs to be manually switched back on. Also, if you are controlling the Slug’s power remotely, maybe through a timed X10 appliance module or stand-alone timer, it won’t fully turn on since it needs the button to be pressed.
In the first instance, there are obvious solutions here, such as putting the Slug onto a UPS or keeping it accessible so you can manually control it. However, these negate the benefits of it being cheap, hidden, and (importantly for HA) controllable.
You can solve this by invalidating your warranty by performing one of several hardware hacks to ensure the machine always switches on when the power is applied. These vary from using USB Y-cables in various configurations to soldering components to the board. All are detailed, with their relative merits online (www.nslu2-linux.org/wiki/HowTo/ForcePowerAlwaysOn).
Overclocking
Prior to 2006, all Slugs ran slower than necessary since their CPUs were clocked at 133MHz, despite the chip being designed to run at 266MHz. This technically meant the original versions were underclocked, which means the following hack is known as de-underclocking, rather than overclocking. If you log into your Slug (through telnet or ssh, depending on your firmware) and type the following:
cat /proc/cpuinfo
you’ll see a BogoMIPS value, indicating the currently speed. If this is within 10 percent of the 133 value, then you can improve the speed by removing the resistor shown in Figure 2-1.
Figure 2-1. The de-underclocking resistor (second from the bottom in the R84 stack). Image from http://www.nslu2-linux.org/gallery/hardware released under cc-by-sa. |
You can remove it using nail clippers, a soldering iron, a saw, or any combination of the above. Just be sure to not to damage any other components.
Serial Port
You can use a standard serial port for two-way communication between many pieces of old technology such as joysticks, along with LCD text displays and other forms of home-brew electronics. It also provides a way of controlling the Slug through getty when other routes, such as the network, are failing.
There is already a serial port hidden away at J2 on the Slug motherboard. Alas, its control voltages are 0/+3.3v, and not the +/-12V necessary for the standard RS-232 serial port, which means you’ll require a power-level converter. (However, strictly speaking, the standard requires hardware to differentiate between voltages in the range of +/- 3–15V.) Some converters can be purchased as a single chip (such as the MAX3232) or already included in some mobile phone data cables. You can find full details on the web site (www.nslu2-linux.org/wiki/HowTo/AddASerialPort).
There are also circuits available that allow you to connect an LCD character display (such as the HD44780) to the Slug with a minimum of effort, providing a basic (and very low-power) display to report the current media playing or the machine status. However, this also requires opening your Slug to make hardware adjustments. If you’d prefer, the Pertelian plugs into the external USB and achieves the same effect. It is supported through the standard software available in OpenSlug, thereby making this the most effective way of having a display on the Slug available in a silent environment.
LEGO Mindstorms
First released in 1998, LEGO Mindstorms was originally known as the Mindstorms Robotics Invention System (RIS) Kit and contained a control brick known as RCX to which you uploaded a program with infrared. The software would then run, control the various motors and sensors connected to the RCX brick, and communicate with others via IR. This naturally had the usual problems associated with IR as covered in Chapter 1 (primarily line of sight). There were two versions of RCX released, and both operated the IR at different carrier frequencies (although both RCX modules can transmit on either frequency) but were functionality identical.
The programming could be done in many languages, including cut-down versions of Java, C/C++, Lisp, and Forth, provided it was compiled into suitable code for the internal microcontroller, a Renesas H8/300. Because of its age, it is now available fairly cheaply, although the supplied IR transmitter has no support for any 64-bit operating systems and is losing support for newer 32-bit ones.
From RCX, LEGO moved to Mindstorms NXT in 2006. This increased the specification of the main brick by improving the processor (now a 32-bit ARM7/TDMI chip) and communications devices (it now included USB, Bluetooth, and an onboard 100 ×64 pixel LCD matrix). This upgrade in processor has necessitated a change in control software, but that is to be expected, and most of the RIS code has now been ported to NXT. The LEGO components also improved, as shown in Table 2-1.
Since 2009, Mindstorms has been on its third iteration (NXT 2.0) and consists of the same RCX brick as NXT version 1.0, some alternative LEGO Technic bricks, and a change in sensor from sound to color.
This was an odd change, since now all NXT 2.0 robots are deaf by default! This might have been a ploy to sell more add-on sensors, however, but for the wily hacker, these can be made much more cheaply using standard electronic components using instructions found on the Web or in various books, such as Extreme NXT.6Where LEGO Mindstorms excels is its ability to rapidly prototype hardware that can be controlled by the computer, as well as remote sensors that can relay information back to it. This provides a method whereby the computer’s state can be demonstrated by something in the real world.
Similarly, it allows the real world to be understood, to some degree, by the computer.
Home automation is full of ideas, and not all of them have the staying power to enhance your living once their novelty has worn off. This makes LEGO perfect as a means of building proof-of-concept hardware before devoting time and money on PIC chips, motors, and cases that will be used for only one project. Here are some ideas:
- Create a robot that waves, or gestures, when an email, private instant message, or phone call is received.
- Use the LCD on the NXT processor block to relay information, such as weather.
- Create a robot to open the fridge and bring beer into the living room.
- Create a Bluetooth gateway for sensors and devices around the house (for a cat flap or pressure mats).
The handling of each sensor and motor is very simple since it’s simply a matter of programming, using one of the available Linux environments, such as leJOS NXJ (Java for LEGO Mindstorms) or NXC (Not eXactly C). There are books and web articles abound on the subject, including this useful start point: http://vikram.eggwall.com/computers/nxt.html.
Arduino as an I/O Device
The Arduino and its clones are microcontroller boards that you can think of as grown-up LEGO—it provides a simple way of interfacing the real world with the computer, handling basic processing tasks on a chip (instead of in software), and working with hardware motors and sensors.
There are many forms of Arduino, based on simple microcontrollers, but the most common development version is the Arduino Diecimila based on the ATmega168 chip, although this is being superseded by the Arduino Duemilanove using the Atmega 328. It supports 14 digital pins that can be configured as either input or output and 6 analog inputs. The missing part here is analog output, which can be provided by using pulse width modulation (PWM) on 6 of the 14 existing digital outputs or with additional electronics. Power can be provided by the USB port, by a power socket, or by connecting the wires from a battery clip to the board. An onboard jumper is used to switch between USB and external power sources.
To those used to large machines, the specification of the ATMega168 chip appears rather small:
- 14KB of available Flash memory, for software
- 1KB of SRAM, for data
- 512 bytes of EEPROM, for permanent data; acts like a mini hard disk
- 16MHz clock speed
Even the ATMega328, with double the memory capabilities, seems less than adequate. However, the tasks the Arduino will generally perform are very simple and usually in the realm of comparing various inputs and performing simple logic, so this specification is more than large enough. The complex tasks found in operating systems, like TCP/IP stacks, are not usually necessary since you can transmit requests to a connected PC for these tasks. And when they’re not, the problem is generally solved in hardware by building the appropriate circuit and including the necessary driver software for that hardware component.
If you’re experienced with other microcontrollers or PIC chips, the Arduino isn’t different in any technical way to them, so you can continue to use whatever chips you have used previously. However, the Arduino offers many benefits to those less used to electronics:
- A C-based language and development environment, instead of assembler.
- USB input/output control as standard.
- A large community of hackers, publishing project designs and sharing tips.
- Robust development boards that are less likely to blow up if you wrongly connect something.
- A wide range of prebuilt, compatible circuit boards (called shields) to provide more complex functionality such as wireless communication. You’ll see some examples later in the chapter in the “Arduino Hardware” section.
- And, for the purists, open source hardware and architecture. This is an often overlooked point.
The scope of possible projects is similar to that of the LEGO Mindstorms, although now the circuits can be very much smaller, involving more discrete components and wider functionality achieved through the aforementioned shields. Whereas a LEGO device might be able to beep or play a short sound to indicate the arrival of an e-mail, the Arduino can use speech synthesis or full audio playback.
Installation and Setup
All Arduino software is written on a PC and transmitted to the board through USB. This is also used to receive any data the Arduino chooses to transmit, by default through /dev/ttyUSB0. (Remember to add your user into the dialout group so that /dev/ttyUSB0 is accessible.) The development can take place in any fashion you desire, but it is simplest with the Java-based IDE. Even if you adopt a command-line approach, the code will need to be compiled using the avr-gcc toolchain, which can be installed under Debian with this:
apt-get install gcc-avr avr-libc avrdude
Java, if uninstalled, will need an extra line, like this:
apt-get install openjdk-6-jre
From here, it’s a simple matter of installing the IDE. This is provided as a single archive from the web site at http://arduino.cc/en/Main/Software. Extract this to an appropriate directory (root access is not required for any of these steps), and run ./arduino from the directory. You should then set up the appropriate USB device and type of Arduino (Tools ➤ Serial Port and Tools ➤ Board, respectively) before use.
You can begin a project by selecting File ➤ New from the menu. This creates what the Arduino IDE calls a sketch. This involves a subdirectory in the Arduino working folder and a primary source file.
Other
source files can be added into the sketch (through Sketch ➤ Add File) and will be automatically included into the project build. There is no Makefile equivalent here, and every file added to the sketch, even if it is a library file from another directory, is copied into the sketch directory. Note that despite the visual similarity to C code, all files are given the extension .pde for clarity.
Then verify the build, and if everything is working, upload it to the Arduino.
Note
You cannot create a sketch of a given name. Instead, you must create a blank new sketch and then select Save As as a separate step.
The build process itself is handled behind the scenes using avr-gcc, a cross-compilation toolchain for the Atmel AVR RISC processors, of which the ATmega168 is one. It creates a separate applet directory inside the sketch folder and copies all the header files into it, along with a concatenation of all the source files (ending in .pde). It is this (.cpp) source file that is then cross-compiled into hex for upload to the Arduino.
Arduino Software
The simplest circuit that most people build to test their setup is that of a flashing light. Pin 13 on the Arduino Diecimila board has a built-in resistor, allowing you to directly connect an LED to it and the 0v supply without damaging it. Some boards also have a surface-mount LED, so you don’t even need that!
The blink tutorial code, which can be loaded from the IDE (File ➤ Examples ➤ Examples), is simply this:
- int ledPin = 13; // LED connected to digital pin 13
- void setup() // run once, when the sketch starts
- {
- pinMode(ledPin, OUTPUT); // sets the digital pin as output
- }
- void loop() // run over and over again
- {
- digitalWrite(ledPin, HIGH); // sets the LED on
- delay(1000); // waits for a second
- digitalWrite(ledPin, LOW); // sets the LED off
- delay(1000); // waits for a second
- }
It is easy to understand this code, with many of the usual C/C++/Java-ism being unnecessary:
- No header files are needed.
- Main has been replaced by two functions: setup and loop.
- There is no event loop or callbacks. You must read the pin states each time around a loop.
If you are a classically trained developer, who vehemently opposes the blocking function delay that’s used here, then there are examples that demonstrate the use of the millis function to infer the timing without blocking.
For most complex software and libraries, you can, of course, reference header files, but remember that any additional source files added to the project will be copied. It is certainly possible to create your own libraries, but on such small-scale projects, it often proves to be a bigger time sink.
Reading Digital Inputs
These are the simplest circuit to build, because they consist of a single resistor and switch combination, as shown in Figure 2-2.
Figure 2-2. Reading a digital switch on the Arduino |
In this configuration, pin 2 is used as an example and reports a 1 (high) voltage to the Arduino at all times the switch is open. This is because of the “pull-up” resistor, R1. Without it, the pin is effectively disconnected, so its voltage may fluctuate to any value between 0 and 5v, causing false readings. (Most of the time, however, it will float up to 1.) When the switch is closed, the pin is connected directly to the 0v ground rail, causing a 0 to be read. The Arduino code then watches for this change as follows:
- int inputSwitchPin = 2;
- int lastState = HIGH;
- void setup() {
Serial.begin(9600);
pinMode(inputSwitchPin, INPUT);
- }
- void loop() {
int pinState = digitalRead(inputSwitchPin);
if (pinState != lastState) {
Serial.println(pinState?"released":"pressed");
lastState = pinState;
- }
- }
This will work in some situations but not all, since hardware isn’t that simple! Switches, being mechanical beasts, have a tendency to “bounce” between on and off a few times when they’re pressed.
If
this switch was connected to a light, you probably wouldn’t see it switch on and off, however, since the time involved is measured in milliseconds. But a computer is fast enough to spot it, so you need to program the code to ignore any state changes that occur within, say, 100 ms of each other.
- int inputSwitchPin = 2;
- int lastState;
- long timeLastPressed;
- long debouncePeriod = 100;
- void setup() {
Serial.begin(9600);
pinMode(inputSwitchPin, INPUT);
lastState = digitalRead(inputSwitchPin);
timeLastPressed = millis();
- }
- void loop() {
int pinState = digitalRead(inputSwitchPin);
if (pinState != lastState && millis() - timeLastPressed > debouncePeriod) {
Serial.println(pinState?"released":"pressed");
timeLastPressed = millis();
lastState = pinState;
- }
- }
The switch I’ve used here is normally open and, as the name suggests, remains open (so that no current flows between the contacts) under normal circumstances and is closed when the switch is pressed.
Some switches are marked as normally closed, in which case you simply reverse the output in the example. It is also possible to use analog devices, such as a light sensor, to report a digital on/off input when you’re are not concerned with the quantity involved. In this example, you might be interested in whether it is light outside but not how bright the light was. You can amend the circuit as shown in Figure 2-3.
Figure 2-3. Reading the light on the Arduino |
This circuit is known as a potential divider circuit, since the voltage (known formally as potential) is divided proportionally by the resistors placed across the supply rails. R2 is a light-dependent resistor (LDR), which has a very high resistance (like an open switch) when it is dark but acts almost like a closed switch (that is, low resistance) when it is light. (This is an oversimplification of the process but is enough to get things working.) The exact resistance of the LDR under these conditions is governed by the specific LDR, and not all manufacturers or suppliers provide this information, so you might have to experiment.
This basic circuit can be used to switch on lights when it gets dark (remembering to point the LDR away from the light in question!) and can be used to monitor people passing by the sensor because their shadow is usually enough to switch the LDR off. You can also get infrared transmitters and receivers that work in similar fashion, which can be placed on either side of a doorway or front gates, so you can get forewarning when someone is approaching your house.
Note
When you’re interested in the state change from off to on, this is known as a rising edge trigger. And changes from on to off are called falling edge triggers.
Reading Analog Inputs
These detect a continuous range of values. Unlike the digital pins, which can be used as either input or output, the analog pins on an Arduino are hardwired, so there is no need for initial configuration. This leaves you nothing to do except read their value.
int analogInputPin = 0;
int value = analogRead(analogInputPin);
The result of value will be in the range 0 to 1023 and represents the voltage on the pin, between 0 and 5v. If you reuse circuit from Figure 2-3, feeding the input to an analog pin instead of a digital one, you can watch the range of values being output by using this:
Serial.print("LDR brightness = ");
Serial.println(value);
This allows you to determine the precise brightness of the light empirically. You will notice a lot of fluctuations with this data, so the best approach is to determine whether it’s bright or dark enough to control the light, by having two limits and a dead band in the middle. That is, if the number drops from greater than X to less than X, then it’s considered light, and if it increases from less than X+N to greater than X+N, then it’s dark.
You can then add a variable resistor into the circuit to fine-tune this brightness, as shown in Figure 2-4.
Figure 2-4. Controlling the brightness at which the Arduino is controlled |
In addition to light, you can also measure temperature (thermistors), distances (ultrasonic range finders), and rotary positions (by attaching a handle or wheel to the spindle of a potentiometer).
Sending Digital Outputs
This is as simple as it sounds and includes those cases where you want to send nothing more than a simple on/off to something like a light switch or small motor. The code requires a simple setup and invocation like this:
int outputLightPin = 2;
pinMode(outputLightPin, OUTPUT);
//
digitalWrite(outputLightPin, bState ? TRUE : FALSE);
From here, it’s all about the circuit.
Each pin on the Arduino is able to source current, up to around 40 milliamps. This is enough for most small loads such as lights, buffers, and some small motors. If your device uses no more than 300 milliamps, then you can draw this from the circuit board itself using the Arduino as a switch only with a circuit like that in Figure 2-5.
Figure 2-5. A transistor switch circuit, allowing you to draw up to 300mA |
For anything larger, you will need to employ a relay and separate power source, as shown in Figure 2-6.
Figure 2-6. Using a relay to control high power loads |
Note
In reality, the Arduino is good for higher power loads up to 800mA. But for dirty loads, such as motors, the 300mA is probably more conservatively sensible.
Sending Analog Outputs
As mentioned previously, analog output is available on the basic Arduino only when using PWM. This is supported only on pins 3, 5, 6, 9, 10, 11, and 21. The pulsing of the output pin to provide the output is handled automatically, including the setup, so you need only to write this:
analogWrite(analogWritePin, value); // value is between 0 and 255, inclusive
This will allow you to vary the brightness of LEDs and the volume of piezo-buzzers and speakers, but not a lot else. In reality, you won’t need a lot else in home automation environs. Moving a motor to a specific position, for example, is better done with servo or stepper motors, and many other forms of positioning should be done through the use of feedback loops—switching the motor on to begin movement and switching it off when a sensor reveals it has gone far enough.
Creating Audio Outputs
This is one of the simplest forms of human-friendly feedback the Arduino can provide, because the circuit needs only a buzzer attached to a digital output pin. The code is a simple loop changing the output state between on and off 440 times a second, for example, to produce the A note above middle C.
The examples on the main Arduino site provide the necessary code to make it beep and play short tunes. For those looking for more advanced music control, there is Armstrong (www.bluedust.dontexist.com/armstrong), the Arduino music system, which provides a small melody processor allowing you to play the chimes of Big Ben with code like this:
- ancInitialize(OUTPUT_LOCAL);
- ancAssignChannelToPin(CHANNEL_OUTPUT_PIEZO_SPEAKER, piezoPin);
- char *pChimesPhrase1 = "L32O4edcL64O3g";
- char *pChimesPhrase2 = "L32O4cedL64O3g";
- char *pChimesPhrase3 = "L32O4cdeL64c";
- char *pChimesPhrase4 = "L32O4ecdL64O3g";
- char *pChimesPhrase5 = "L32O3gO4deL64c";
- // a quarter past
- ampPlayString(CHANNEL_OUTPUT_PIEZO_SPEAKER, pChimesPhrase1);
- // half past
- ampPlayString(CHANNEL_OUTPUT_PIEZO_SPEAKER, pChimesPhrase2);
- ampPlayString(CHANNEL_OUTPUT_PIEZO_SPEAKER, pChimesPhrase3);
- // a quarter to
- ampPlayString(CHANNEL_OUTPUT_PIEZO_SPEAKER, pChimesPhrase4);
- ampPlayString(CHANNEL_OUTPUT_PIEZO_SPEAKER, pChimesPhrase5);
- ampPlayString(CHANNEL_OUTPUT_PIEZO_SPEAKER, pChimesPhrase1);
- // top of the hour
- ampPlayString(CHANNEL_OUTPUT_PIEZO_SPEAKER, pChimesPhrase2);
- ampPlayString(CHANNEL_OUTPUT_PIEZO_SPEAKER, pChimesPhrase3);
- ampPlayString(CHANNEL_OUTPUT_PIEZO_SPEAKER, pChimesPhrase4);
- ampPlayString(CHANNEL_OUTPUT_PIEZO_SPEAKER, pChimesPhrase5);
Using the various shields provides more complex audio output, including sample playback.
Communication with a PC
The basic Arduino allows bidirectional communication with a PC through its built-in USB port. This uses the same serial port that’s used to upload the program in the first place. It must be set up first before data can be sent or received, both of which are supported with this method:
Serial.begin(9600);
The Arduino can read data from the PC only on a byte-by-byte basis, so you will need to read it within a loop using code like this:
int incomingData = Serial.read();
Note
however, that this function is blocking. That is, it will not return from the read function until there is data on the serial port. If your device responds only to messages, then this will work fine.
However, it is more usual to place this at the start of your loop, surrounded with this:
if (Serial.available() > 0) { /* ... */ }
Writing data from the Arduino back to the PC, however, is easier since the size of the data is already known. This can be handled by the Serial.print or Serial.println function for quick and easy string messages. Or individual bytes can be written using Serial.write:
Serial.write(byteData);
This is useful for applications wanting to transfer a lot of data. But for testing and development, I find a simple ASCII-based protocol easier to work with, because a simple serial terminal allows me to send and receive messages in human-readable text. The Minerva feature, MINX (Minerva INput transfer), uses the delimiters <| and |> to surround control messages, allowing an Arduino to pass messages back to the PC so that further processing can take place, without affecting any other debugging or trace messages. I’ll cover this fully in Chapter 7.
Note
Some models of Arduino, such as the Mega, have three additional serial ports addressable as Serial1, Serial2, and Serial3.
On the PC side of this transmit-receive equation, you have a much simpler job since everything in Linux is treated like a file. You can therefore issue this:
tail -f /dev/ttyUSB0
To see all the data that is sent back from the Arduino and introduce commands to the board, use this:
echo -n send data > /dev/ttyUSB0
It is from this that demonstrates the benefit of an ASCII-based protocol. In the simplest case, you can issue this:
Serial.print("1");
from the Arduino to switch the PC control program into an on state, with an equivalent for off. This makes the C program very simple:
- // USB script trigger
- #include <stdio.h>
- char *szUSBDevice = "/dev/ttyUSB0";
- int main() {
- char v;
- FILE *fp = fopen(szUSBDevice, "r");
- if (!fp) {
- printf("Failed to open USB...");
- return 1;
- }
- while(1) {
- if (fread(&v, 1, 1, fp)) {
- if (v == '1') {
- // button pressed
- } else if (v == '0') {
- // button released
- } else {
- printf("%c", v);
- fflush(stdout);
- }
- }
- }
- return 0;
- }
This also includes the functionality to write noncontrol codes to stdout, which may be redirected to a log file. If you compile the previous program with g++ as arduino_read, you can start it as a process in the background, making it daemon-like for very little effort:
./arduino_read > logfile 2>&1 &
Arduino Hardware
For some complex applications, the ATmega168 chip on the Arduino board is not powerful enough to handle the task. So, in common with other computers, additional chips are necessary to ease the burden. In keeping with the modular design of the Arduino, these chips are built up into stand-alone boards with the necessary interfacing circuitry so that they can be directly mounted on top of the existing Arduino board. For this reason, they are known as shields. Most shields also include a passthrough so that other shields can be placed on top of it. There is then a separate software library that is used to control the device and that is copied into the Arduino/hardware/libraries directory.
Note
Not all shields are compatible with all models of Arduino.
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.
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;
- }
- 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 emails 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.
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}; 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 ...
This might be to record the sound with vox_record.sh:
- #!/bin/bash
- LOGFILE=/var/log/voxrecordpid
- DIR_INCOMING=/usr/local/media/voxrecord
- if [ "$1" == "start" ]; then
- FILENAME=`mktemp -p $DIR_INCOMING`.wav
- arecord -f cd -t wav $FILENAME >/dev/null >/dev/null 2>&1 &
- PID=$!
- echo $PID >$LOGFILE
- fi
- if [ "$1" == "stop" ]; then
- PID=`cat $LOGFILE`
- kill $PID
- rm $LOGFILE
- fi
or play back each sound in the directory with vox_play.sh:
#!/bin/bash DIR_INCOMING=/usr/local/media/voxrecord for F in "$DIR_INCOMING"/*.wav do play $F done
or even delete them all through vox_delete.sh:
#!/bin/bash DIR_INCOMING=/usr/local/media/voxrecord rm -f $DIR_INCOMING/*
Naturally, there is a lot more scope here to support the deletion of individual recordings, and so on.
But this represents the idea.
Note
The Minerva system abstracts these ideas out into Minx, which eliminates the need for separate executables for each Arduino application. Minerva will be covered in Chapter 7.
Joysticks for Input
Joysticks, particularly old ones, make wonderful input devices because they interface with the parallel port on most standard sound cards and are physical rugged. This enables the buttons to be reused, particularly as foot pedals, to control software. Indeed, this provides a very cheap way of adding a dictation module to your machine, without the need for an Arduino providing the input. In addition to triggering individual events on a Linux machine, such as requesting a weather report or the state of the machine, it can also feed messages to other applications. mplayer, for example, can operate in slave mode, allowing commands to be fed to it from the standard input or a named pipe. Similarly, the X Window TV-viewing software, xawtv, comes with xawtv-remote to change channel and volume (as per most remote controls), giving you capture on/off and screenshot facilities. This makes it possible to freeze frame magic shows to see how they do it!
You can read the joystick directly from /dev/js0, but it is usually better to use an abstraction, like the Simple DirectMedia Layer (SDL). This allows you to port the code elsewhere if necessary, avoid the vagaries that come with a reliance on the device hierarchy, and make it easier for others to add and adapt your code.
The code to read and process the joystick is a very simple loop of C code:
- #include <SDL/SDL.h>
- int main() {
- if (SDL_Init(SDL_INIT_JOYSTICK) < 0) {
- fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
- exit(1);
- }
- SDL_JoystickEventState(SDL_ENABLE);
- SDL_Joystick *pJoystick = SDL_JoystickOpen(0);
- SDL_Event event;
- while(SDL_PollEvent(&event)) {
- switch(event.type) {
- case SDL_JOYBUTTONDOWN:
- // Use event.jbutton.which, event.jbutton.button, event.jbutton.state
- break;
- }
- }
- SDL_JoystickClose(pJoystick);
- return 0;
- }
Other Input Controllers
Hacking Laptops
Your Own X10 Devices
Figure 2.8 Connecting an AM12W to a mains-powered device |
Figure 2-9. The AD10 module |
0 Response to "Smart Home Automation Part II - Appliance Hacking [LINUX]"
Post a Comment