Thursday, July 10, 2014

Detecting WiFi clients on TP-LINK routers using Python and telnetlib

Inspired by this project on Hackaday where submitter Mattia used Python to nmap scan his WiFi network, triggering alerts when particular MAC addresses are found, and with my dreams of home-automation in mind, I came up with a slightly different way of achieving the same thing.

My router is a cheapo TP-LINK, but it does come with a "currently connected MAC addresses" page in the web interface so my first thought was using BeautifulSoup to do some parsing. Then I found references to a telnet interface.

Connecting to the Telnet interface I quickly found that the command "wlctl assoclistinfo" gave me this output:

Associated stations:4
Num     Mac Address        Time
1    F0:C1:F1:22:xx:xx    00:02:30:04
2    90:21:55:B0:xx:xx    01:02:20:26
3    00:0F:54:10:xx:xx    03:09:17:28
4    74:E1:B6:2C:xx:xx    30:04:37:48 

Firing up Python and the telnetlib telnet-automation module meant that 10 minutes later I was printing comma-separated MAC addresses to the console using this snippet of code:

Finally, I am triggering this in my Raspberry Pi via a simple crontab entry:

* * * * * logger `python /home/pi/wlan_sensor/sense.py`

This gives me per-minute logging of WiFi clients, giving me the information I need to the first of my home-automation projects - turning on the lights when I get home.

11 comments:

  1. Have you used this in your home automation project? Is it a reliable presence indicator?

    ReplyDelete
  2. Hi Gilson. It's pretty good, though there is a slight lag - about 60 seconds - before my phone connects, after I park in the driveway. This is frustrating but if I move the wireless router nearer to the front of the house I expect it will be a bit quicker.

    ReplyDelete
  3. Hi Robert, thanks for answering. Is this lag constant even if you increase the cron job frequency? Would it affect the router performance?

    ReplyDelete
  4. Hi Gilson - no probs, it's nice to get a non-spam question :-)

    The answer is yes and no... I found the response improved to about 30 seconds when running in a loop in a bash script. My telnet interface could handle at the request every 5 seconds without any issues cropping up with the router. In the end I stayed with the per-minute checks as my biggest issue was the range to the front of the house + my phone being a bit slow to connect. This gives me about a 1.5-2 minute response in the real world.

    Once I've moved the router I'll aim to speed it up a bit and I'll comment here to let you know how it turns out.

    Cheers, Robert

    ReplyDelete
  5. Hi Robert,
    I'm running a loop in Python, but have not figured out how to do so without establishing a new session every time. Is it possible?
    Thanks,
    Gilson

    ReplyDelete
  6. Hi Gilson,

    I'm not sure without testing but off the top of my head you should be able to call the tn.write("wlctl assoclistinfo\n") and tn.read_all() lines one after the other as many times as you need. I'd just print out the tn.read_all() first though as I'm not sure what output there'd be and whether my mess of lambdas would handle it...

    Cheers,
    Robert

    ReplyDelete
  7. Hi Robert,
    With or without read_all() it seems that successive calls to write("wl assoclist") and write("exit\n") result in a [Errno 32] Broken Pipe which indicates a closed connection.
    Not sure how to circuntent that yet...
    Thanks,
    Gilson

    ReplyDelete
  8. Hi Robert,
    Had to remove write("exit\n") and replace read_all() with read_until("# "). Seems logical now, doesn't it?
    Thanks,
    Gilson

    ReplyDelete
  9. Hi Gilson,
    You beat me to it, by about 5 minutes... I just finished a proof-of-concept using tn.read_very_eager(), which works too but needs a small sleep between the write(...) and it to stop unnecessary blocking. Glad you got it to work.
    Cheers,
    Robert

    ReplyDelete
  10. Hi Robert,
    I've been playing with presence detection and your article was just what I needed on the wifi front. There are other methods that use Arp or Tshark but they all have their weak points. Don't work well with iOS or are cumbersome, for example. So far reading the assoclist seems to be the best for my use case. Will let the code run for a few days to see how reliable it is and poslish it to deal with connection failures... Thank you!

    ReplyDelete
  11. Broadband speed has become a critical factor in having a reliable and enjoyable internet connection. With the birth of Internet TV, you need a good download speed to have interruptible playback. We have all at one time or another enjoyed watching a movie online only for it to constantly be 'buffering' or unable to connect.RouterReset

    ReplyDelete