The popularity of internet-connected devices built with Arduino shields or single-board computers like the Raspberry Pi and Beaglebone has exploded, but for simple tasks like controlling a relay, reading a sensor, watering your garden or lighting LEDs there's an overlooked (and often free) option: old wifi routers and access points.
Used APs and routers are wasting away in our homes, offices, and landfills, and though they won't match the hardware of a Pi or Beaglebone, they do usually have a few GPIO pins, a serial port, wireless and ethernet connectivity, possibly even a USB host port or Power-over-Ethernet support!
Businesses and institutions in particular may have dozens or hundreds of obsolete access points of a similar make and model, providing a great opportunity for creative reuse and enough potential benefit to work out quirks, limitations and annoyances, develop tools to automate an installation and setup process.
(A handful of routers, like the Linksys WRT54G or TP-Link WR703N, have developed a strong following online and have many well documented mods, but plenty of others are far less explored)
What you need:
* A old wifi router or access point
* 3.3v serial cable
* An ethernet cable
* Soldering iron, solder, wire, basic hand tools
Step 1: Check for compatibility with OpenWrt
Routers, access points and networking devices may already run some variant of Linux, many can be flashed with an embedded linux distribution called OpenWrt, which allows for more possibilities. Visit the OpenWrt web site to check compatibility and find installation instructions and support for your device.
The installation process can vary quite a bit between products: for some routers it is a simple point and click, in other cases it involves using TFTP and a serial console, and in other circumstances manufacturers have made the re-flashing process very difficult.
A FTDI/serial cable @ 3.3v can come in handy in the flashing process. As can a refresher on how to use TFTP. To flash some routers you may have to use a JTAG programmer.
The router I'm going to re-purpose is from Meraki, and to install vanilla OpenWrt I have to use TFTP and a serial console.
If you don't have a router at home check thrift stores, craigslist, friends, hackerspaces and e-waste recycling centers. You can find one for free or at a nominal cost.
Step 2: Examine the circuit board for IO pins and interfaces
Examine your router's circuit board for IO pins and interfaces.
Labeling of pins and ports varies among manufacturers and even models, ranging from crystal clear to intentionally obfuscated. In my case Meraki made things very easy --- you can see labelled GPIO pins (connected to the board's LEDs) in the upper left, even an I2C bus! The device's serial console is on the right, with headers already attached and 3.3V, RX, TX, GND labelled.
If you don't want to take your router apart yet to get a look at the insides you can find the product's FCC ID, printed on the case and circuit board, and look that number up at the FCC Equipment Authorization database. There you'll be able to see some specifications and photos of the interior and exterior of the device.
Step 3: Flash OpenWrt onto your router ... and deal with any funny quirks
Per the Meraki Mini instructions I need to flash my router with a kernel and root filesystem using a serial console and TFTP. This process can seem a bit intimidating, if you follow instructions piece by piece they tend to work (Saying this, whenever possible I recommend using a router that lets you flash OpenWrt the easy way, via a web interface). To do this you will need to connect a 3.3V serial cable, like an FTDI cable you might use with an Arduino, the the router's serial port, and an Ethernet cable to the RJ-45 connector closest to the power jack.
You can find pre-built images that work with this router here
When OpenWrt is successfully installed you'll be able to visit an administrative interface at http://192.168.1.1/ or connect via ssh. Read more about your first login.
edit: Flashing made easier --- SudoMesh received large donation of these APs and created an easy to use tool to flash them, if you have a Meraki like me use this instead! You'll still need to connect Ethernet and serial cables, but this takes much of the hassle out of fumbling with TFTP or sending the right sequence of commands.
A particular quirk with this model is that it has a watchdog that will restart the device every 5 minutes unless pinged. This made the device challenging to re-purpose, through some clever hacking a fix has been documented.
There are more elegant solutions, but by adding a simple shell script to your crontab that runs once a minute, restarts are no longer an issue:
* * * * * /sbin/watchdog.sh
/usr/bin/gpioctl dirout 6
/usr/bin/gpioctl set 6
/usr/bin/gpioctl clear 6
Step 4: Success! Now let's toggle I/O pins
Now that OpenWrt is installed we can try toggling GPIO pins.
On my Meraki router I can see GPIO pin 4 is connected to a LED, if it set it HIGH I expect it will power the LED, if LOW the LED will go off again.
I can use openwrt's gpioctl utility at the command line to toggle this pin:
gpioctl set 4
gpioctl clear 4
When tested this works just as one might expect.
Let's make this I/O pin accessible via the web.
OpenWRT's default web admin interface is called LuCI. To change web server settings you can look in /etc/config/uhttpd, but for simplicity's sake I'm going to keep these as-is for now, add files around what already exists.
Our web root is /www and executable scripts go in /www/cgi-bin
Create a file ledOn (and ledOff), as shell scripts that look something like this:
echo "Content-type: text/html"
echo "LED ON"
/usr/bin/gpioctl set 4
When you're done make sure you set correct permissions on these files (chmod 755). Then visit them in your browser:
With this working you can take things a step further and create a HTML page that uses AJAX requests to control the pin state (pictured, see attached code)
Step 5: Attach something interesting
I made an on-board LED blink, but that's not very interesting. So let's attach a more useful device to the router that we can control from the web.
I'm going to use a homemade grow lamp (made with high powered LEDs, a recycled laptop adapter and heatsink) as an example, but you can use virtually anything (ex: turn on or off a valve to water your garden, lock or unlock an electric strike at your front door, remotely switch an appliance on or off via a relay).
Solder wire leads to the router's GPIO and GND pins. I needed to use some flux to help solder flow nicely into the joints.
The router's pins cannot output or sink a lot of current --- so you should not use them to drive another device directly: our best option is to use a pin to toggle a transistor, relay or opto-isolator. In my case, my LED driver has a built-in on/off toggle, making my installation task really easy.
Finally, after everything is attached make sure the ground of your router and attached device(s) are connected together.
Watch this light in action
On occasion you will get lucky and your router and peripheral have the same input voltage and can share the same power supply. If you do this still be sure to run separate power leads to each, rather than all the power through the wifi router, as it may not be designed to carry the amount of current needed for an additional device!
I'm using my GPIO pins as outputs, but can these act as an input with something like a magnetic switch or push button? Yes! Using gpioctl to read a pin works as follows:
gpioctl dirin 3 (Set pin to input)
gpioctl get 3 (Returns state HIGH / LOW)
You can read further about strategies for accessing gpio pins with openwrt here.