Skip to main content

Converting Your DD-WRT Router to a clock!

So the other night I suddenly woke up in the middle of the night. I was fumbling through my extremely messy desk, which was next to my pillow, to find my phone so that I could see the time. Alas my desk was far too messy to find my phone in the dark. I was far too lazy to take the effort of turning on the lights just to see the time. That was when my eyes glanced upon the ominous green blinking LEDs blinking fervently on my router docked on my wall. I wished I had an LED clock instead and boom it hit me! I have a linux-based DD-WRT router, that means I have full control over it :P. So that was how I began my quest on converting a piece of network equipment to a digital clock!

TP-Link WR740N Router
The next day, I set upon my quest to find out how I could control the blinking LEDs on my router. I noticed that my router had a total of 9 LEDs , and I figured that was more than sufficient to display the time in binary to a sufficient degree. My plan was originally to use 4 LEDs to display the hours (0-11) and 4 more to display the minutes (0-60) with a 5 minute granularity. And use one LED in between as a separator. I never really cared much for the actual LED indicators , since they never really told me much. I mean the most frequent connectivity issue I have, is that of a loose Ethernet cable and not once have I actually glanced to find out if the LED was on or not while troubleshooting it. I simply jammed both ends of the cable in till it eventually connected my laptop :P

The first thing to do was to somehow figure out how to turn on/off some of the LEDs. After a bit of googling and research, I came to know that these LEDs are usually controlled through an interface called the GPIO. And it seems DD-WRT uses this very Hardware interface to provide control over LEDs as well as other I/O such as buttons on the router which could be used for input. For e.g on my TP-LINK WR-740N router , I have a QSS switch , which I never use (nor should you), which can be used as an input device accessible using GPIO.

So how do we actually use this GPIO to control our LEDs? Well there appear to be two simple methods. Before that you need to ensure that your router’s kernel has the GPIO module enabled. First lets ssh to the router so that we can start playing with the LED controls. You can check that the GPIO module has been added by heading over to /proc/gpio . There you will find several nodes corresponding to control points of several GPIO pins. GPIO has several “output” pins which we can use to control the LEDs. We can directly use these files to control the LEDs, however a simpler command line tool called “gpio” exists to simplify the process.

$ gpio
gpio <poll | enable | disable> <pin>
$ gpio enable 27
$g pio disable 27

Basically “gpio enable/disable pin” enables/disables the output pin specified. The next question would be to figure out which pin number corresponds to which LED on the router. This page provides several example scripts which control LEDs, along with several GPIO pin mappings to LEDs for several devices. Unfortunately my device wasn’t among them :( . So I had to resort to figuring out which pin mapped to which LED manually. Eventually though it ended up being fun :P , I managed to write short shell scripts , which would flash a set of pins on off repeatedly so that , I could test several subset of pins at once, and observe the corresponding effects on the LEDs in order to finally identify the mapping for my device. After some effort I obtained the mapping for my router:

26 : QSS Input Button
LED s From Left-to-Right
? : Power LED: I couldn't find this one, I suspect it is hardwired and can't be controlled
27 : Some led with a gear symbol. (No idea what its for)
0 : Wifi Indicator
14 : LAN1 Indicator
15 : LAN2 Indicator
16 : LAN3 Indicator
17 : LAN4 Indicator
13 : Internet Indicator
1 : Lock Symbol : Again not sure , Guesing WPS/QSS indicator

Some of these had inverted effects such as 27,17 which would turn off when enabled with gpio instead of turning on like other pins.

After obtaining the mappings, I set about writing a script in bash, keeping these mappings in an array for easy use. But alas , I realised a bit later that the router does not use bash, but uses busybox’s ash. And ash does not support arrays in scripts.

This put me in a bit of a dilemma and I was considering writing a C-program compiled for the MIPS architecture of my Atheros router. I was trying to avoid a an inefficently written shell script to avoid overloading my router’s CPU. But cross-compiling for MIPS to run on my router was no easy task. I took great efforts to compile gcc and binutils for mips but that didn’t work very well either. Firstly I failed to compile even the hello world program for mips using gcc. And worse a blank binary I generated by compiling “main()” in C , did not even run on my router.

Eventually I gave up on the cross-compilation and much later sat down to write it in pure shell. After a few minutes of quick hacking I had a simple short script , which although inefficient ought to get the job done. Some debugging later, I ran the script, and was trying to make sense of the time. I had used a “usleep 5000” , i.e a refresh rate of 5000 micro-seconds as the optimal refresh rate. I didn’t figure out how to disable the LED indicators of their normal use, and so decided to over-ride it with a higher refresh rate. Unfortunately the script was soo slow and inefficient that even without a usleep to slow it, it ran at too slow a rate, that I couldn’t make sense of the time.

After some brainstorming, I decided that I could just make do with a single LED , displaying the time in a morse code like encoding! I figured it would be a reasonable compromise, and would be a much more efficient solution in terms of reducing the CPU load! So I finally managed to write the shell script and lo and behold , I now have my router reading out the time for me 😀:D

# Script by Phinfinity
# This script displays the time through two segments of 4 short/long blinks to
# convey the current hour and minutes.

pin=1 # Using the QSS LED for displaying time
flash() { # Rapidly flash 10 times , to act as separator between hours/minutes readings
#echo "."
while [[ $i != 0 ]]
gpio enable $pin
usleep 1000
gpio disable $pin
usleep 1000
pause() { # Puase between blinks
gpio disable $pin
usleep 500000
short() { # Short blink - used as a binary "1"
#echo 1
gpio enable $pin
usleep 250000
gpio disable $pin
long() { # Long blink - used as a binary "0"
#echo 0
gpio enable $pin
usleep 700000
gpio disable $pin
while true
min=$(( ($(date +1%M) - 100)/5)) #4bits
# The "+1%M" & "-100" : hack for removing the zero pad to prevent octal interpretation
# busybox date doesn't support format flags like _,- etc. to disable padding
hr=$(date +%l) #4bits
# minute is in the range {0..11}*5 and hr is in the range {0..11}

#Flash longer before begining time

# Blink the Hour
[[ $(( hr&8 )) != 0 ]] && short || long
[[ $(( hr&4 )) != 0 ]] && short || long
[[ $(( hr&2 )) != 0 ]] && short || long
[[ $(( hr&1 )) != 0 ]] && short || long
# Blink the Minute
[[ $(( min&8 )) != 0 ]] && short || long
[[ $(( min&4 )) != 0 ]] && short || long
[[ $(( min&2 )) != 0 ]] && short || long
[[ $(( min&1 )) != 0 ]] && short || long

A single LED is used. First the LED flashes rapidly to indicate start. 4 blinks with read out the hour and rapid flashing indicates starting the minute. 4 more blinks read out the minute.You could set this up inside the startup script to autostart every time. Some other considerations are to make sure that you have an NTP server setup on your router to make sure that the correct time is used each time.

Now all that remains , is to see if this actually helps :P, after a few times, I can read the time in a single attempt, the real question is can I do it from my bed when I am half-asleep ;)

Let me know if you have a better idea to implement this, or any suggestions/comments below in the comments!


Popular posts from this blog

Setting up a transparent pass-through proxy with iptables

Update: Part 2 for https posted in separate post!

So for a very long now I’ve had a nagging issue with proxies. My primary source of internet is through my college HTTP Proxy and this adds a couple of issues whenever I am dealing with applications that don’t have proxy support coded in them. I have this issue often both on my laptop as well as on my android tablet (Youtube streaming!). Its a very distressing situation and I’ve always wanted to set-up a transparent proxy solution which could re-direct the traffic out of such applications to a sort of secondary proxy server which can interpret the requests and forward them to my college proxy server. Recently I managed to get this working!

The main tool used for this was iptables. For those of you who haven’t heard of iptables at a glance it is a flexible firewall which is now part of the Linux kernel by default. But iptables is actually much more powerful and flexible than just a simple firewall to block ports. iptables is capable of …

Transparent Pass-through proxy with iptables – Part 2 (for HTTPS)

This is part 2 of my earlier post on how to set configure to use a http proxy transparently. This post deals with extending the same for transparent HTTPS proxying. Click Here for my earlier post which deals with HTTP proxying. For a quick-fix solution and list of files mentioned in this post skip to the bottom of the post.

After setting up a transparent http proxy on my dd-wrt router to transparently proxy my HTTP requests I haven’t had any issues for more than a year and was happily able to use it. But up until recently my local network used to allow direct HTTPS connections to external IP addresses. Now my network has disabled that, which means I need to forcefully use the HTTP proxy in order to be able to make HTTPS connections. Surprisingly this caused many more problems than I had anticipated. Lots of applications on android which seemed to work fine after setting proxy settings started failing badly! Notably gmail, hangouts, facebook messenger all only worked very sporadically…

Some useful SSH configurations

Lately I was tired of having to repeatedly type my user name for my ssh connections. In my current setup I often ssh to two servers inside the IIIT (my college) network. merely typing ssh would try to use the username as my local computer’s login user name. So I was trying to get a workaround for this. A simple approach would be to rename my local computer’s user name to the IIIT server user name , but now that would be very lame. So I figured there must be some simple configuration available and looked up man ssh_config which gave an extremely detailed list of all the possible configuration options. Finally my configuration file looked like this :

Host * mirage web
User iiit_login_user
Host *
ControlMaster auto
ControlPath /home/phinfinity/.ssh/%r@%h:%p
GSSAPIAuthentication no

The first line specifies the categories for which the configuration below are to be used. Here I have specified the configuration to be applied for 3 possible categories “*”,mira…

Welcome to my Site!

Hello! I am Anish Shankar. I am a guy who likes to try out new stuff. Technology interests me a lot. I currently work as a software engineer at Google in the bay area, and have worked on various networking & infrastructure. In the past I've participated in a lot of programming competitions and used to go by the handle "phinfinty". I've since retired from competitive programming, but the handle has stuck with me!
I am a Linux enthusiast and love open source. I use Arch Linux currently for most of my personal work.