This blog post details how I hacked the office WiFi to play entrance theme music for my colleagues when they entered the building each morning. If you only want to see the finished product and are not interested in the details, here is a little video demonstration (including some seriously underreceived overacting):
I was a pretty normal 90's kid. My brother and I spent more than our fair share of time watching and emulating our favourite WWF (ahem, WWE) superstars.
We didn't get wrestling on television in Australia and so we were limited to watching the VHS releases on Coliseum Video. And watch them we did! Every Friday night we would take advantage of the "5-for-5" deal at our local video shop, which allowed us to hire five weekly videos for just $5. Typically, at least three of these would have been classics like Wrestlemania X, SummerSlam '95 and Royal Rumble '94.
One of the most satisfying parts of the wrestling events was the theme music that each wrestler would get when they were first entering the ring (or squared circle, as I should say). For those uninitiated into the world of very-much-not-fake-I'm-sure-of-it wrestling, the average entrance looked something like this:
I'm sure you noticed the uncanny similarities between myself and "Stone Cold" Steve Austin.
Growing up, I thought it was only fair that I got my own theme music. And I figured that if I got theme music, then my colleagues also deserved their own (even if they disagreed).
Luckily, we already had a bunch of Internet connected Sonos speakers in the office that I could communicate with over the LAN. So I knew the actual playing of music would be easy enough. And so the main problems were now:
- Detect when someone entered the office
- Determine who it was
- Determine if this is their first visit today
- Perform 1, 2 and 3 without any input from the user (aka magically)
My first thought was to use a proximity sensor on the main door 1 . This was short-lived as I determined that users would need to buy-in to the idea by installing an app on their phone and agreeing to some terms and conditions. Not to mention the fact that I'm way too tight to actually buy those sensors.
After what was probably an embarrassing amount of time pondering the problems, I eventually realized that the WiFi was a perfectly suitable way of determining when people entered and left the office area. And because our office WiFi signal is strong enough to reach the footpath out the front, it would have the added benefit of playing a users theme song slightly before they entered the building (you know, for added realism).
I started digging around in the office router control panel hoping I'd find some way of easily detecting WiFi events like connect and disconnect. After some time I came to the conclusion that it wasn't going to be that easy! Whilst I didn't find a way of detecting events 2, I did see that this particular router had pretty comprehensive logs. I thought that perhaps a quick and dirty approach would be to continuously poll the logs looking for useful events. It wasn't great, but it was something.
After some further investigation I found that I was able to forward the router logs over TCP to a remote syslog server. This was important because it meant that the router could push the events to me instead of me having to continuously tail a log file. I started to see how this thing was going to come together. So I found an old computer in a closet, installed a flavour of Linux on it, connected it to the LAN and had syslog listen on TCP port 514 (the syslog standard port).
It worked! I tailed
/var/log/syslog and started seeing logs like this almost instantly:
DATA 127.0.0.1: <14>Dec 12 15:15:20 10.our.host.com.au (\"YO,v220.127.116.1189 libubnt: w event.cust(): EVENT_STA_JOIN ath0: 00:34:da:58:8d:a6 / 3
Every time a device connect and disconnected from the network, a log including the devices unique mac address was appended 3. Awesome! But there was a lot of noise. There were logs for connections, disconnections, roamings, handshakes, failed connections, rate limiting, etc. I eventually decided that there were only two events that I was actually interested in:
EVENT_STA_LEAVE. So I added some syslog configuration that would
- Find logs that matched my desired events
- Forward them onto local TCP port
10514(Where I'd have a simple TCP server running to handle the next step)
- Ignore everything else
The syslog configuration ended up looking like this:
if $msg contains "EVENT_STA_JOIN" or $msg contains "EVENT_STA_LEAVE" then
action(type="omfwd" Target="localhost" Port="10514" Protocol="tcp")
So now the problem was much simpler. Every time someone connected or disconnected from the WiFi, my little computer in the corner of the room was sent the devices mac address and an indication of the event type (
LEAVE). All I needed to do now was to read those incoming messages, map the mac address to a Human and then play the appropriate song.
I wrote a TCP server in the Rust programming language, which you can check out on Github 4. It simply reads the byte stream into a string, parses out the useful information and then takes the appropriate action on the Sonos.
In terms of knowing who was triggering the WiFi event, I kept it simple and just created a JSON file that mapped mac addresses to names, songs, greetings, etc. It looks something like this:
"name": "Andrew", // In case I want it later (and for logging)
"state": "UNSEEN", // IN | OUT | UNSEEN
"join": "Welcome to the office, Bunts",
"leave": "See you later, Bunts",
"lastEvent": 1490436790 // Unix Epoch timestamp
"join": "Welcome back, Mel",
"leave": "I hope to see you soon, Mel",
Each night at midnight I have a little cron job that resets each users
UNSEEN. I use this to ensure that a particular theme song is only played the first time the given user connects to the WiFi. Any subsequent events trigger a greeting or exit message to be vocalized over the Sonos. This was achieved using the great Google Text-to-Speech service.
The only thing left to do was to add in some minor smarts to prevent the office from being spammed with "hellos" and "goodbyes". I noticed that certain devices would often lose, and then quickly reestablish, their connection, which would cause their greetings to be fired in succession even though the user didn't actually leave and re-enter the office. I tackled this by ensuring that certain events had to match criteria in order to be considered valid. For example, in order for a
JOIN event to be considered valid, the user in question must:
- Be in the
- Not have fired any events in the past 15 seconds
I also allowed for the
leave keys to have an optional array of strings, in which a random greeting would be chosen and vocalised. This gave the whole thing a bit of variation and prevented people from tiring of the same greetings every day.
The final product was now ready to rock and roll! After adding in some logging, I ended up with something like this:
As for next steps, creating a simple GUI to wrap the JSON file (or perhaps I should do the right thing and move it to a database) would be pretty simple. This would provide users with a simple way to actually write their own greetings and upload their own favourite theme music. And, at least theoretically, this system could be used for more practical tasks such as a slack bot that could tell an employee if a certain colleague was in the office.
I believe this type of passion project is a great way to get out my creative energy whilst also giving the office a refreshing spin. Thanks for reading!
- In case you were wondering - no, unfortunately we don't have any type of swipes or user identification processes in place when people enter the office.
- I later found out that the router actually shipped with a minimal HTTP API that may have been sufficient - but finding documentation and examples proved difficult.
- Yes, I know that some mobile operating systems spoof mac addresses. But this is not a problem in the short term as once a device connects to a WiFi network, it's reported mac address tends to stay the same. Spoofed mac addresses are more of a concern for WiFi networks that are trying to track unconnected devices across nodes.
- I've since moved some of the higher-level details to a Node-based web service for reasons totally uninteresting to the reader. I've decided not to mention that explicitly in the article as it derails the technical details unnecessarily.