What's new

Custom application/script: Iterate through WiFi devices, compare, send information to server

  • SNBForums Code of Conduct

    SNBForums is a community for everyone, no matter what their level of experience.

    Please be tolerant and patient of others, especially newcomers. We are all here to share and learn!

    The rules are simple: Be patient, be nice, be helpful or be gone!

birgersp

Occasional Visitor
Hello,

I am about to install Merlin on my Asus-AC86U router.

I want to create a lightweight application or script that has one job: notify my server whenever a WiFi device enters or leaves my network.

My inital idea is: Add a small script that runs on boot. The script loops endlessly (with 1 sec delay between each iteration). The script somehow retrieves a list of all WiFi devices currently connected to my network, compares with data from the previous iteration. If there is a difference in the datasets, it means devices have entered or left the WiFi network area. Then, send this information to my server (that part I can figure out on my own, I think).

So a couple of questions:

1) Can scripts that are executed on start run in a neverending loop, or will this not work? Will it block execution of other applications on my router?
2) How can I retrieve data (mac addresses) of each device currently connected to or in the area of my WiFi network? Preferably in a bash script, but I'm all ears for e.g. Python/native application solutions.
3) If the scripts cannot run in a neverending loop, how should I store the data about the connected devices between each execution of the script?
 
There are already scripts posted in these forums that do this. Use the Better Search function to find them and modify them to your own needs. Here is an example.
 
Thanks! So I can add this script to `/jffs/scripts/services-start/somescript`? And will this not block?
 
Thanks! So I can add this script to `/jffs/scripts/services-start/somescript`? And will this not block?
services-start is a script not a directory. So you would need something like this as the minimum contents of that script.
Code:
#!/bin/sh
/jffs/scripts/wireless_monitor.sh &
Note the ampersand to run it in the background.
 
Awesome! For anyone interested I will also add this script to kill the wireless_monitor.sh script if needed:

(EDIT: removed incorrect script)
 
Last edited:
Awesome! For anyone interested I will also add this script to kill the wireless_monitor.sh script if needed:

Bash:
#!/bin/bash
ps -ef | grep '[w]ireless_monitor.sh' | awk '{print $2}' | xargs kill -9

That script is incompatible with the router's shell. You should use something like this:
Code:
#!/bin/sh
ps | grep '[w]ireless_monitor.sh' | awk '{print $1}' | xargs kill -9

P.S. Don't use /bin/bash. Even though some routers have a symlink for it the router's shell is not bash compatible.
 
Thanks! Now my next problem is; how can I send data from my router to my server?

I was thinking just to send a single UDP packet, but the examples I find online doesn't really work.

Code:
echo -n "hello world" | /dev/udp/serverip/15243
# /dev/udp/ doesnt exist

# or

echo -n "hello world" | nc -4u -w0 serverip 15243
# fails with 4 being an invalid option

# or

echo -n "hello world" | nc -u -c serverip 15243
# fails with u being an invalid option
 
Cutting and pasting random examples from the internet usually doesn't work on the router because it's not a full blown Linux distribution.

What data is your server actually expecting to receive?
 
My idea is to send the MAC address of each device that is connected.

Code:
#!/bin/sh

msg=""
for iface in $(nvram get wl_ifnames) $(nvram get wl0_vifs) $(nvram get wl1_vifs)
do
    msg=$msg$(wl -i $iface assoclist | sed "s/assoclist/$iface/g")
done

echo "$msg" # <--- send this data
 
Cutting and pasting random examples from the internet usually doesn't work on the router because it's not a full blown Linux distribution.

What data is your server actually expecting to receive?

To answer your question: My server is expecting to receive a UDP packet with a small data amount. The server will parse the data and act accordingly (but this part I don't need help with). What I don't quite understand is how to send messages from my router to some host (preferably using UDP).
 
Do you really need to add the interface name to output data or will just the MAC addresses be sufficient?

The router's built-in nc doesn't support UDP connections. Can you use TCP or does it have to be UDP?
 
Do you really need to add the interface name to output data or will just the MAC addresses be sufficient?

The router's built-in nc doesn't support UDP connections. Can you use TCP or does it have to be UDP?

MAC addresses would be sufficient. It can be TCP, but the reason I wanted UDP was that I feel it is less chance for the script to crash. In my head it sounds better that the router just sends this information regardless if someone will pick it up or not. The router shouldn't have to worry about handshaking etc. But yes it can be TCP if that is easier.
 
So I got this to work. Not UDP but I guess it will be fine.

Code:
#!/bin/sh

msg=""
for iface in $(nvram get wl_ifnames) $(nvram get wl0_vifs) $(nvram get wl1_vifs)
do
        msg=$msg$(wl -i $iface assoclist | sed "s/assoclist/$iface/g")
done
echo "$msg" | nc -w0 10.0.0.11 42069
 
Can't post the text for some reason, so....

Untitled.png

N.B. there should be a space separator when concatenating the $msg strings.
 
Last edited:
Perfect! So here's the end result that is running on my router now:

Code:
#!/bin/sh

echo "Starting wireless device observer"
while sleep 2
do
        msg=""
        for iface in $(nvram get wl_ifnames) $(nvram get wl0_vifs) $(nvram get wl1_vifs)
        do
                msg="$msg $(wl -i $iface assoclist | awk '{print $2}')"
        done
        echo $msg | nc -w0 10.0.0.11 42069 2>/dev/null
done

Tested it on the receiving end aswell, works like a charm.

I'm so grateful for your help. Thank you friend!
 
Although you got it working, another approach, and a style I personally prefer, would be to have your router simply collect and store the data and let your server get it when necessary.

I use this approach for a number of reasons, but mainly to have the source device do as little "work" as possible (and potentially removing the need for a USB drive, entware, etc).

For example in your case, you could have a simpler script that stored all active connection information in a text file. By placing this file in a shared location the server in your case could read it and do all the necessary processing, storage, logs, etc.

Not in any way suggesting your approach is bad, just giving you more ideas to consider.

Thanks for sharing how you got it working. It is always great to see the tweaks and mods people make and I'm sure this will be useful for someone else too.
 
Although you got it working, another approach, and a style I personally prefer, would be to have your router simply collect and store the data and let your server get it when necessary.

I use this approach for a number of reasons, but mainly to have the source device do as little "work" as possible (and potentially removing the need for a USB drive, entware, etc).

For example in your case, you could have a simpler script that stored all active connection information in a text file. By placing this file in a shared location the server in your case could read it and do all the necessary processing, storage, logs, etc.

Not in any way suggesting your approach is bad, just giving you more ideas to consider.

Thanks for sharing how you got it working. It is always great to see the tweaks and mods people make and I'm sure this will be useful for someone else too.

Appreciate the feedback! And yes I agree, it would be better if the router didn't have to worry about conveying the information. It should just store it so other applications can read it.

But, I want the "detection" of a new device to be fast, so the script that stores the information should be run at least once every 2 seconds. And I do feel like that would create an unnecessary amount of writing to and reading from the router's drive. But maybe that is irrational? I just don't want to burn out my routers SSD or whatever with my scripts.

Also, how would you configure the data to become available?

I changed my script to use UDP instead of TCP, and been testing it a lot today. For whatever reason, after about 70 minutes then my server no longer gets UDP packages from the router, even though the script (neverending loop) is still presumably running (the process is alive). I am not 100% sure if this is because of my server or the router, but I suspect the router because I have other, similar applications running on my server and this is the first time I have encountered this error...

So I am wonder if perhaps there is a better way to schedule the script to run every 2 seconds, rather than putting it in a neverending loop with a sleep. With cru I can run it at no shorter than 1 minute intervals.
 
Also, how would you configure the data to become available
Save it to a location that is accessible vis samba, or ftp,...
 
Thanks!

So it turns out that my phone connects to my WiFi network just a little too slow for this system to work as intended.

Now I am wondering: is it possible for my router to detect that my phone is in WiFi range, even when the phone hasn't (yet) connected to my WiFi network?
 
Last edited:

Sign Up For SNBForums Daily Digest

Get an update of what's new every day delivered to your mailbox. Sign up here!
Top