Rss

  • youtube
  • linkedin
  • google

Archives for : February2013

Dropping Dropbox + Hardware Hacking

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.IMG_20130209_181712

IMG_20130209_181854

Third step: wire it up to the relay!

IMG_20130215_162927

Fourth step: wire it up to the power button on the PC

IMG_20130215_165046

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
}