Recently, I purchased some very cheap mobile routers for a project idea. That project didn’t work out, so I needed something do with them. Fortunately, I had another problem which needed to be solved, and this gave me a good excuse to do a little hardware hacking!
SO… Dropbox and I are breaking up. Well, cutting back at least. Also, I met someone new. Here’s the “why”, the “who”, and the “how”.
Why?
The cloud is becoming unavoidable. I’ve been using Dropbox for a while now, and it’s a wonderful service. When they announced that you could get free, bonus storage for enabling automatic photo uploads, I jumped at the opportunity.
For a while, it was great. I’d take a picture from my phone, Dropbox would upload it automatically, my desktop and laptop would download it automatically… all was right with the world.
And then it wasn’t.
What happened? Well, I ran out of space while I was in the Philippines. I took SOOO many pictures while I was there, and it didn’t take long to eat up the rest of my 5 or 6gb. To make matters worse, the camera on my phone will only save photos to the internal storage, which kept running out of space – so I had to keep moving images manually to the SD card. So I had some pictures on the SD card, some on the internal storage, some in my Dropbox, and some moved out of my Dropbox and into a plain folder on my laptop to make room for new photos.

STILL WORSE: Dropbox RENAMES YOUR PICTURES when automatically uploaded from your camera. So while I was trying to combine all of the photos from all of these places, many of them were duplicates but with different filenames. ARGH!
Eventually, I sorted all of it out – but it was a pain. Wouldn’t have been an issue if I had more space though.. so I started shopping. Google Drive, Box.com, Amazon S3, etc, etc. None of them fit all of my needs (linux client, android client, automatic photo uploads), and none of them had enough space. I thought about separating my files – pictures on Dropbox, documents on Google Drive, code on Box.com… but that sounded messy. Besides, even if I moved all of the non-photos from Dropbox, it still wasn’t enough room.
Who?
Would I bite the bullet and drop money on this? Would I have to switch back to traditional backup methods? Negative. Enter: OwnCloud.
It’s open source, which means – if you have a computer, you can host your own file server, available anywhere you have an Internet connection. It’s also extensible with it’s plugin API. Great! But does it have a Linux client? YES! Alright, but does it have an Android client? YES! Does it support auto-photo-uploads? YES! Even the Android client is open source ($1 in the Google Play store… or FREE if you download the source and build the .apk yourself!).
I heard about this project when they first started, but it was quite lacking. It’s come a long way, and not a moment to soon.
How?
Naturally, my instinct was to load the code on domstyle.net - unfortunately, it requires a newer version of PHP than my hosting company has installed. I asked what their upgrade schedule was, and they seemed confused about the word “schedule.” No problem, the PC I built a few years ago is underused and has an 80gb hard drive with nothing on it… PERFECT!
Format hard drive, install a LAMP stack, SSL cert, install OwnCloud, DONE! In less than an hour I was moving files out of the Dropbox and into the OwnCloud folder. Plugged the PC in downstairs in the laundry room – out of site, out of mind.
“So, what… you just leave your computer on 24/7? That’s not very green, Dom!”
Totally agree. So I built a Wake-On-Wifi solution. Wake-On-LAN has existed for a long time, but not all hardware supports it. And some that claim to support don’t actually work correctly. Even if it did work properly on my machine, I had no way to send the magic wake-up packet to the computer through the router.
Thankfully, I had another router which was looking for a purpose. Enter: the TP-Link 703n. As is, this little device can’t help me…
First step: replace the firmware with OpenWRT. That’s right, we’re putting Linux on it.
Second step: hijack some GPIO pins and tap into the power. There are two pins on the processor inside this thing which aren’t being used. With linux installed, I can control them. And by controlling them, I can control other things… like a relay.
Third step: wire it up to the relay!
Fourth step: wire it up to the power button on the PC
Final step: code! The final step is really a two-parter – code on the router to wake up the computer, and code on the computer to shutdown when idle.
The computer was easy. A cron job runs every 5 minutes which monitors network activity for the next 10 (yes, the overlap is intentional). If the computer sends and receives less than 1kb during that period, it sends a shutdown signal with a 2 minute warning.
The router pings the PC to see if it’s alive.
- If it isn’t alive, the router borrows the PC’s static IP address so it can monitor for traffic. As soon as the router hears any traffic on port 443 or port 80, it activates the relay for 1 second, which simulates the power button being pressed. It also gives up the IP address and takes back its own.
- If it is alive, the router pings the PC at regular intervals and does nothing while it continues receiving a response.
How well does it work?
So far, so good! The PC takes ~20 seconds to fire up, which is quick enough that requests don’t timeout while waiting. So I can snap a pic on my phone, it attempts the upload, the router hears the request and powers on the PC, the PC takes over the IP address and processes the request! Likewise, I can turn on the OwnCloud sync client on any of my computers, and 10 minutes after I turn it off, the computer shuts itself down. Over-engineered? Probably. A hack-job? Perhaps… but I am very pleased nonetheless!
UPDATE
By request, here’s the server code which is ran via cron job:
#!/bin/bash
#/root/shutdown-if-idle.sh
# Dominic Canare
# dom@domstyle.net
shutdownDelay=2 # minutes to wait before shutdown
samplePeriod=300 # seconds to query network per sample
sampleCount=2 # number of samples
threshold=1 # kb threshold for idle status
iface=wlan0 # interface to watch
# get current net stats | look at the average for our iface || get total transfer | truncate to integer
usage=$(sar -n DEV $samplePeriod $sampleCount | grep "Average: *$iface" | tr -s " ")
tx=$(echo "$usage" | cut -d " " -f 5 | cut -d "." -f 1)
rx=$(echo "$usage" | cut -d " " -f 6 | cut -d "." -f 1)
echo "Usage is '$tx' + '$rx' vs '$threshold' $(date)" >> /tmp/usage.log
usage=$(($tx + $rx))
if [ "$usage" -lt "$threshold" ]; then
cp /tmp/usage.log /root/usage.log
/sbin/shutdown -hP +$shutdownDelay "System is idle. You have $shutdownDelay minutes to save your work." &> /tmp/test-shutdown-log
else
killall shutdown
fi
and the router code
#!/bin/sh
#/root/wake-me-up.sh
# Dominic Canare
# dom@domstyle.net
IP_SUBSCRIPTION=192.168.1.8
IP_HEARTBEAT=192.168.3.2
STANDBY_IP=192.168.1.3
tcpdump=/tmp/usr/sbin/tcpdump
GPIO_PIN=29
GPIO_PATH=/sys/class/gpio/gpio$GPIO_PIN
sleeping=0
killEverything() {
kill 0
}
trap killEverything SIGINT
trap killEverything SIGTERM
installDependencies() {
opkg update
# there isn't enough flash memory, but there's plenty of RAM
# this will install tcpdump binaries to RAM
opkg -d ram install tcpdump
}
setupGPIO() {
# enable pin 29 on the processor for output
# default it to 0 (low)
echo "$GPIO_PIN" > /sys/class/gpio/export
echo "out" > $GPIO_PATH/direction
echo "0" > $GPIO_PATH/value
}
pressButton() {
echo "1" > $GPIO_PATH/value
sleep 1
echo "0" > $GPIO_PATH/value
}
setIP() {
# if the requested IP address is not currently set, set it and ping the router, so the router knows who we are
currentIP=`ifconfig wlan0 | grep "inet addr" | tr ":" " " | awk '{ print $3 }'`
if [ "$currentIP" != "$1" ]; then
ifconfig wlan0 $1
ping -W 1 -c 1 192.168.1.1 &>/dev/null &
fi
}
checkForClient() {
while [ 1 ];
do
if [ $sleeping -eq 1 ]; then
setIP $STANDBY_IP
else
# send one PING to the server
ping -c 1 $IP_HEARTBEAT
if [ "$?" -eq 0 ]; then
# the server is awake, we should be standing by
setIP $STANDBY_IP
else
# the server is asleep, we should hijack his IP
setIP $IP_SUBSCRIPTION
fi
fi
sleep 10
done
}
waitForWakeUp() {
echo "Waiting for wakeup call..." &> /tmp/status
# listen for web traffic on the wireless interface
$tcpdump -vv -c 1 -i wlan0 "dst $IP_SUBSCRIPTION and (dst port 80 or dst port 443)" > /tmp/tcpdump
echo "POWER button press" &> /tmp/status
pressButton
date > /tmp/last-wakeup
setIP $STANDBY_IP
# wait a bit while the server starts up
sleeping=1
sleep 300
sleeping=0
}
if [ ! -e "$tcpdump" ]; then
installDependencies
fi
if [ ! -e "$GPIO_PATH" ]; then
setupGPIO
fi
checkForClient &
while [ 1 ];
do
waitForWakeUp
done
Which is installed as a service via /etc/init.d/wake-me-up:
#!/bin/sh /etc/rc.common
#/etc/init.d/wake-me-up
START=99
start() {
/root/wake-me-up.sh &
}
stop() {
killall -9 wake-me-up.sh
}






It’s really impressing what you did here, awesome work, awesome post. Thank you very much!
Greetings from Buenos Aires, Argentina.
I would be very grateful if you can post the script of the router and the cron job. Thanks again!!
code is posted :)
Thank you very much! Very nice work.
I’d love to see how you controlled the GPIO on the router!
That’s something I would find extremely interested in doing myself.
it was actually pretty simple. i had to de-solder a resistor and add a wire. within linux, the high/low state can be controlled via /sys/class/gpio files. have a look at the code i posted for the router
hey Dom nice work man.. i hv been looking for dis kind of solution and ur one just work for me… i going to try it. Thanks ya. :)
thanks, and good luck on yours! if there’s anything i can help you out with, let me know :)
Very nice!
Now i have got a good solution for wake on wireless lan =)
1) Why do you use different heartbeat and subscription ips?
2) I think it would be better to use a transistor and a reverse diode for circuit protection and for better stability of the relay
Greets Greg
originally, i tried to use a single IP, but it did not work well if i powered up the server manually. i tried putting the router’s wifi in monitor mode to detect packets coming from the server, but it was unreliable. in the end, sending the heartbeat ping over wired ethernet was simpler and far more reliable.
and you’re absolutely right about needing to add the transistor/diode to the relay. i still need to do this!
For those of you who either can’t handle or don’t want to handle the DIY solution, Bitcasa offers unlimited cloud storage and auto upload of photos from iOS and Android.
http://l.bitcasa.com/.HBpcBa-
I don’t work for them or anything (that is a referral link) but it might be a solution for the less technical.
You could have used Microsoft SkyDrive to supplement Dropbox. This gives you 7GB of free storage and retains your original file names and file sizes.
SkyDrive comes free with a Microsoft email account so you could easily make it 14GB of free storage by opening an Outlook.com account, and so on.
SkyDrive supports drag-and-drop uploading but you can also have sync accounts on your various computers.
decent, but 14gb is still far smaller than the 80gb drive i had serving no other purpose. and if i run out of that space, upgrading is a one-time cost (instead of paying $X every month for extra space. also, does SkyDrive have linux and android clients?
Very nice job!
very cool! I haven’t had reliability with WOL, but do use a low power <4W pogo 1.2ghz running arch linux arm with a large usb stick or usb drive (that will sleep and wake). to create a fast in-house sharing solution.
Love your code! Clean and documented! How rare is that!
Nice work on the project.
Great piece to learn bash scripting!
you could use GPIO8 to switch off 5V USB power and control a relay.
Outstanding!
Could you help me, I´m interested in the project, and want to make one of my own
I’d be happy to help however I can! what do you need help with?
WOW! I’m very excited to find someone else that is doing this! I had been working on a solution just like this for my own owncloud server but was stuck at how to wake the server up without WOL support. With the cost you posted I should be able to utilize my raspberry pi to wake it up. Thank you again, this makes me very excited!
this was a fun project, indeed! but probably overkill.
say, if you’ve got a Raspberry Pi lying around and plan on keeping it up 24/7, why don’t you just host OwnCloud on your Pi?
My owncloud server had several terabytes of disk in a raidz2. It would be hard for my pi to support that much space via USB. My pi is already on 24/7 for other things anyway. I’ll probably make a small modification to your setup and instead of having the pi change its ip, I’ll stand up a virtual ethernet interface and assign the IP to it so my pi can remain online with its normal IP add well.
now THAT sounds like a proper OwnCloud setup! I only have my one lonely hard drive :-p
virtual ethernet interface, you say? where can i go to learn more about this?
Just specify another network interface. If your primary interface is eth0 than you name the virtual interfaces eth0:n where n is another arbitrary number, typically starting at 1 and increasing by 1 for each additional adapter. The basic way create a temporary interface on a network using 192.168.1.0/24 would be, “sudo ifconfig eth0:1 192.168.0.xxx netmask 255.255.255.0″. Click Herr for a better explanation http://serverfault.com/questions/83234/how-do-i-create-a-linux-virtual-network-interface-alias-with-a-real-interface
Well that is interesting and 100% new to me – thank you for sharing!
Awesome read, awesome project.
Great piece of crafty work.
I like to tweak router setup and need your help.
From the two gpio pins, since only one is used to drive the relay, how do I use the other as an input?.
In your checkforclient() routine, instead of pinging to see if the server is live, how do I use the 2nd gpio pin to monitor low/high status?
Then when the 2nd gpio pin goes low, how do I set the router interface up and set the router ip as the server ip?
When powering on the server, instead of setting a standbyip as the router ip, how do I set the router interface administratively down?
Also instead of sending one pulse to relay, how do I keep that pin high?
Thanks Dom
Two thumbs up from Toronto, Canada
Have a look at the setupGPIO function:
The first line tells the system that you’re going to start controlling that pin.
The second line says that it’s an output. To use it as an input, you would echo “in” instead.
Then, to read the value, you can simply cat the file:
and you can test it with an if statement:
I’m not sure I fully understand your goal though. Do you want to hook the second GPIO pin up to the server to monitor power status of the server? I tried to keep the server and router as separate circuits (hence the relay). To keep with this idea, you could use a phototransistor to detect the power LED on the server.
Lastly, if you want to maintain a GPIO pin high, set it’s value to 1 and just leave it at one. In my code, I set it to 1, sleep for a second, and then set it to 0. If I left it high, it would be equivalent to holding down the power button.
Dom – thanks for the input.
I like to adapt this work for a HP 8150 network printer. When the printer goes to power-save mode, it is using about 63 watts and noisy. The only thing it does (visibly at least) is turn the back-light of display off and say “power save mode” on the displayl. The on-off button shuts it down (incl. nic) so no one can print to it.
Here’s the plan:
Make a Y connection to the cat5 cable, one goes to printer and other to the tp-link.
1. Tp-link will monitor printer traffic destined to printer ip at port 9600
2. When there is traffic, it will drive a relay to turn the power-on.
3. Tp-link will turn its interface down or set to a non-used ip.
4. Tp-link will sleep until next gpio pin goes to low (when the power-save mode of printer kicks in)
5. It will then turn relay off (printer power off), turn the interface back on and hijack the printer ip and listen on port 9600 for printer traffic.
Hi,
This is a fantastic project. Do you know if it is doable on a Linksys WRT54 router instead of a TP-Link?
Yes, the WRT54g has a handful of GPIO pins you can control: http://wiki.openwrt.org/oldwiki/port.gpio
Very impressed with the concept of monitoring network traffic and cycling the sleep functionality. I for one will be making use of this code ;)
Really nice work!
and yet no surprise by unattented power on?
Until your machine is the target “attack”(scan, attack etc)?
nothing like that so far! i keep a log of power events, and every one of them (so far) has been expected
Love your project.
I have a question if you don’t mind. Besides the GPIO29 what is the other non-used gpio pin?
Thanks.
GPIO7 is also unused.
You can control other GPIO’s as well, but they serve purposes (controlling the LED, USB power, etc).
More information here: http://wiki.openwrt.org/toh/tp-link/tl-wr703n/ar9331_pinout