21 March 2009

tweet-a-w/e using Asus wl-520gu and Xbee

Update: Newegg no longer stocks the Asus WL-520GU router but this is still a cool project. You can find these routers for $10-20 (or more) on eBay. Also someone sent me a comment that the Linksys WRT54G routers have serial ports that could be used in a similar manner. I haven't tried this yet but if a cheap Linksys router comes my way, I'll try and attempt to blog about it.
A few of the geeks that I stalk follow on twitter have done some interesting things with the Asus wl-520gu wireless router. Jeff Keyzer of mightyOhm has a real nice series on using the router where he builds an open source wireless streaming internet radio receiver. He walks you step-by-step on why he chose the wl-520gu, how to load OpenWrt, adding a serial port header, and even interfacing it to an Atmel ATmega168 AVR microcontroller to drive an LCD. Very nice, thanks Jeff.

Mr mightyOhm is also the admin of the Asus Wireless Router Hacks Flickr Pool. Check out a few of the cool things he and others have done with the wl-520gu.

Not to be out done, LadyAda hacked her 520gu and ported her tweet-a-watt xBee code in a 5 hour hack fest. That's her router picture over on the right. Click it and see a brief description of her efforts. She mentions this project on twitter and on flicker but I haven't seen it on her blog. I've been messing with Xbees lately and ladyada's hack is just what i need.

I've been thinking about a tweet-a-temperature project that would monitor my pool temperature and tweet it every so often during the summer months. While I'm toiling away in the office, I could get SMS spam telling how great life is outside work.

Or maybe a tweet-a-lert that let's me know when my super-sekret door has been opened. Or a tweet-a-stalk when a victim with Nike+ shoes runs by a sensor.

Let's lay down the foundation for a tweet-a-whatever (tweet-a-w/e) project by hooking an Xbee to the router and installing a Python client that tweets whatever is received.

Yes, this seems to be very similar to ladyada's tweet-a-watt port. I'm shamelessly copying the hard work of mightyOhm and adafruit to set this up. What's my value-add? I'll ramble a lot and tell you about all my dead-ends.

We'll take a wl-520gu router, install openWrt firmware and configure it as a wireless client to my existing house wireless network. Using the 520gu's serial port, I'll hook up an Xbee in an Adafruit adapter. Next, install Python on an automount USB drive and write a client that reads incoming Xbee data and does the tweet.

So I ordered a wl-520gu from newegg and eventually pretty much followed mightyOhm's instruction for installing header pins on the serial port and installing OpenWrt.

If you've read any of my other ramblings on this blog, you know already that I'm not very original and sometimes not very smart. But I'm decent at stealing reusing other people's work and twisting it to fit my needs.

Let's first talk about the stupid things I did so you can avoid the mistakes in life that I have made.
  • Both mightyOhm and ladyada used OpenWrt by first flashing dd-wrt and then OpenWrt. Me? I choose to use tomato firmware instead because I wanted built-in USB support and the description of its feature sounded great. And because I wanted to waste 3 nights trying to configure it in wireless client mode. I'm not saying tomato is bad, I'm just saying that I struggled big time and I couldn't find many online tips. I finally said "uncle" and followed the mightyOhm's way and installed openWrt. And had it working in under a half-hour.
  • Installing a four-pin header isn't a hard thing. All I had to do was remove 4 blobs of solder and then solder in a header. So ... Why did I somehow brick my router? I was super duper careful removing the blobs (without a de-solder-er iron or a bulb) and then was careful soldering in the pins. I only applied heat for a max of 5 seconds and let it cool for about 5-10 seconds before re-attempting. Yet I did it. After I finished the header, the darn thing wouldn't boot. Nothing, dead to the world. No reset, no LED action, nada. I cussed for a day or two and then ordered a new one from newegg. Before I de-blobbed the new one, I ran down to Rat Shack and bought a desoldering bulb. 20 minutes later, I had a working router - with header pins. Lesson? If at first you don't succeed, spend more money.
  • With the default Asus firmware still installed, I found that logging in via telnet, the user/password was root/admin. Via the browser at, the user/password was admin/admin. Kinda odd, but maybe this tip will save you some hair.
Okay, so where are we in this story? Oh yeah, the start. Buy a wl-520gu router and boot it up fresh from the box. Don't muck with anything yet. Confirm that it starts and you can log in via a wired ethernet cable on a LAN port. The default address, username, password are on the bottom of the router (, admin, admin).

On the 1st router that I bricked, I installed new firmware first, then tried to install the headers. On my working router, I did headers first, then firmware. I don't think it really matters what order you do this. But I ruined a $59 router, so you trusting me?

So do your own thing and follow mightyOhm's excellent instructions. Get headers on the serial port, install openWrt, and meet me back here in a few.

Back already? Good, you should have a router with OpenWrt that acts like a wireless client on your network. You should be able to wirelessly connect via telnet as well as via the serial port.

Yeah, I know the picture over there is kinda blurry but it's the best camera I have (donations accepted). If the picture was clear, you would see that I'm using a USB TTL-232 cable to talk to the router from a USB port to the router's shiny new headers. mightyOhm's picture on this page was very helpful for the pin-outs.

As is, the OpenWrt's filesystem is pretty cramped. There's not much space available to install extras such as Python. I had an extra Sandisk Cruzer laying around so I setup the router to automount the USB stick on /opt.

From either the serial line or a wireless telnet (my preference),
Then using hints from the openWrt wiki, I executed these commands:
  • # opkg update
  • # opkg install kmod-usb-core
  • # opkg install kmod-usb-ohci
  • # opkg install kmod-usb-storage
  • # opkg install kmod-fs-vfat
  • # opkg install kmod-fs-ext3
I installed both vfat and ext3 because my USB stick was currently fat but I wanted to reformat it to ext3. That should be pretty simple to do but as with most things, it was a hassle. I finally found how to do it and did this (click the link).

I want to install Python libraries and other extras on the USB drive so we'll need this auto-mounted at boot time. I couldn't locate clear instructions on this but here's what worked for me. Using tips from this place, I did:
  • Create a mount point
  • # mkdir /opt
  • Create an /etc/rc.d/S11mount file with macsat.com contents from this page.
  • NOTE: macsat's page references this as /etc/init.d/S11mount. For my version to work, I did not put it in init.d but instead put it in rc.d
  • # vi /etc/rc.d/S11mount
  • Paste in macsat's example S11mount content. My file version can be found here.
  • change the MOUNT_DEVICE0 statement to match your device. My USB stick was exactly the same as his example.
We're really making progress now. Next, we want to setup opkg so we can install large packages such as Python to the USB. Again, I'm using tidbit's from macsat.com excellent pages. Here's the good stuff.
  • Edit opkg config file to create an alternative destination for packages
  • # vi /etc/opkg.conf
  • Add this line:
  • dest opt /opt
  • My copy of the opkg.conf file is here.
Now some housekeeping. Since we want to install libraries and stuff on the USB stick, we'll need to continue following macsat's advice and update PATH and LD_LIBRARY_PATH in your /etc/profile. I set mine to:
  • export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/opt/bin:/opt/sbin:/opt/usr/bin:/opt/usr/sbin
  • export LD_LIBRARY_PATH=/lib:/usr/lib:/opt/usr/lib:/opt/lib
If you'll be installing services on /opt that you want to start at system boot time, be sure to check out macsat's script here. I'll be using this after I complete the client app. For now, I'm just manually starting.

At this point, we have a flashed wl-520gu router with OpenWrt, headers soldered to serial port, and configured to mount a USB stick to opt at bootup. Let's keep mushing on.

The line that we added to the top of our opkg.conf file
sets us up to install from the kamikaze 8.09 packages which contain the Python 2.5 that I seek. Do this to install Python on the opt mount:
  • # opkg update
  • # opkg -d opt install python
Assuming that you haven't fallen asleep and you've setup your route similar to mine, after a few minutes, Python and all dependencies will be safely setup on /opt. Give it a try:
  • # python -V
And you should see the proof:
Python 2.5.4
Using the AdaFruit Xbee Adapter that I blogged about last year, the next step is to simply hook it up to the 4-pin serial headers. This is the easiest step of all. 4 wires, hook 'em up.
  • wl-520gu GND -> Xbee GND
  • wl-520gu 3V -> Xbee 3V
  • wl-520gu TX -> Xbee RX
  • wl-520gu RX -> Xbee TX
Since OpenWrt uses the serial port /dev/tts for console login, we need to modify the /etc/inittab file. All this takes is to comment out the tts line:

#tts/0::askfirst:/bin/ash --login

I'm using Python for the client app, so we need to install the pySerial module from SourceForge. Create a temp folder on /opt, CD to it, download pySerial, unzip, untar, and install
All we need now is a app that reads the serial port and tweets. This blog getting pretty long so I'll just explain the serial port read and talk about the tweet part next time.


#!/usr/bin/env python
import serial, time

SERIALPORT = "/dev/tts/0"     # the com/serial port the XBee is connected to
BAUDRATE = 9600               # the baud rate we talk to the xbee
TIMEOUT = 0.5                 # the timeout to wait for buffer fill
NUMCHARS = 140                # the number of characters to attempt to read at once

# open up the FTDI serial port to get data transmitted to xbee
print 'opening serial port ' + SERIALPORT
ser = serial.Serial(SERIALPORT, BAUDRATE, timeout=TIMEOUT)

print 'entering read loop'
while 1 > 0:
data = ser.read(NUMCHARS)
if len(data) > 0:
print "Read " + data
print 'closing serial port'
I've modified the reader.py quite a bit so that it tweets the received data, but the version above simply echoes the data to the terminal.

Run it like this:
# python reader.py
Send the Xbee data from another Xbee and watch it print.

Alright, I'm stopping and will pick up the story in my next entry. Look at this picture to see where we're going.

What do you think? Leave a comment.


Anonymous said...

Thanks for sharing your knowledge. I have found your tutorial useful as I build a Xbee energy monitor for my solar PV system. Could you explain why you placed the USB mount script in rc.d vs init.d. Thanks,


lizard43 said...

hi glen -
thanks! Fighting the init.d vs rc.d issue seems so long ago but I think if I had written the mount script startup file correctly, I wouldn't have had the prob. Take a look at this post:

kamikaze init scriptsi'm messing with other openwrt startup files right now and probably will redo the usb one.

after you make progress on your XBee project, write it up and share! I'm also working on an solar project that I'll blog about this summer.

Andy said...

Excellent tutorial! I was looking at doing something like this as i wanted to use MightyOhms tutorial as a basis, but this has taken it one step further! Thank you!

I had a few problems getting the mount script to work on startup, so after a few hours of playing around i got it to work by doing this;

Create the script file exactly as you (and macsat.com) say. But create it in "/etc/init.d/" I called mine "usbmount".

You then need to make it executable;

chmod a+x /etc/init.d/usbmountNow, you need to make a symlink so it will start at boot time

ln -s /etc/init.d/usbmount /etc/rc.d/S11mountThis works like a charm! And also seems to mirror the other startup scripts in there.

At the moment i've got my router hooked up to an Arduino and it just tweets the ambient room temperature. Once i've got some XBee modules i can start to play with the wireless!

Thanks again for all the info :) it's helped a lot!


David said...

I can't tell you just how helpful this has been to me! Pretty much exactly what I needed.

There are pitfalls everywhere, and I'm relatively new to Linux so little things can be devastating to my progress.

It was almost sad to see exactly what I wanted explained so clearly, like all of the challenge was taken out of the process, but I think I'll just have to build to where you got and go further. Thanks so much.


David said...


I finished my project. Here it is:

Thanks for your great instructions!!!


lizard43 said...

david -
excellent work. do you have a blog or anywhere that you share other projects?

Anonymous said...

I've use 2 xbees to make TED-1001 connect wirelessly to my HPsmartserver. I know it sound silly but TED and HPsmartsever cannot be on the same power-strip as the HP creates so much noise it kills the power-line interface. So I put a Xbee in side the TED-1001 and use another xbee on the HPsmartserver. It works fine, but I find that the range is dismal. I can barely communicate with the TED-1001 immeidately downstairs. Do you have any advice? I'm using 1mw version 1 xbees with chip antenna.


lizard43 said...

hi chin -
the chip antennas have been talked about in some forums of having limited range and very directional. The xbes with wire antennas are a little better.

Try to move your xbees in different positions and "point" the chip antenna towards the other xbee.

Have you done a range test with X-CTU?

I recently bought an xbee with an sma connector to increase my range.


Daniel Collins said...

Hey lizard43,

I have followed your tutorial, and managed to get python running smoothly. I am able to post to twitter whn I am logged into the router via SSH, but as soon as I close the terminal, the python script stops.

How can I run a python script on the router, without any external terminals running?



lizard43 said...

Hi Daniel -

It was in the article but kinda hidden in amongst the ramblings:

If you'll be installing services on /opt that you want to start at system boot time, be sure to check out macsat's script here. I'll be using this after I complete the client app. For now, I'm just manually starting.

Look at the end of http://www.macsat.com/macsat/content/view/16/30/


ben said...

After installing the first 2 usb packages, system says something along the lines of "only 0 blocks of available". Basically, it is trying to tell me that it doesn't have enough memory for the packages I am trying to download and install. I checked my /jffs folder and it is 100% full. Is there something I was missing in the opkg config? Am I installing the modules in the wrong place?

lizard43 said...

hey ben -
kinda sounds like you're not installing to the usb stick. Double check that you've mounted it on /opt and you've set opkg.conf to have opt has a dest:

dest opt /opt

And then you're specifying opt when installing:

opkg -d opt install python

ben said...

Thanks for the quick response. The thing is, I am seeing this error before I have installed the storage, vfat, and ext3 packages. It seems to recognize my usb device though. So I am pretty sure core and ohci were installed correctly. I haven't even gotten to the python part yet. I think part of the problem is that I was mixing mightyohm's steps and yours. If you can't think of a solution to my problem, no worries. I will figure it out and report back. Thanks again.

toolunious said...

For me, the ext3 package wasn't enough... I also had to install kmod-fs-ext2 to mount

Corey said...

Hey Ben I had the same problem and this link is the key.