Query WiFi status via CLI?

Hi,

I'm looking for the most efficient way to obtain WiFI status information from the command line or in a shell script. By that I mean two things:

  1. Query whether my wifi interfaces (2.4G and 5G) are up.
    I'm aware that
    ubus call network.wireless status
    holds this information in JSON format. I have been trying to mangle this by piping it to sed/awk/grep in order to only get the information whether my two interfaces are up. This worked (via a somewhat ugly and long pipe sequence of sed, awk and grep), but it wasn't really efficient (the command took 2-3s to complete on my device).

  2. Count the number of connected clients per interface.
    This seems to be easily done via
    iwinfo <interface> assoclist | grep -cE '^([0-9A-F]{2}:){5}[0-9A-F]{2}'
    which is already faster than the first command. But is this really the most efficient way?

The reason I'm asking for the quickest and most efficient way is that I'd like to monitor and log the Wi-Fi status with a script that is exectued in regular intervals. Hence I would like to keep the overhead of this as low as possbile.

Any hints are appreciated! Thanks!

You could write a Lua script which uses libiwinfo. Here's a little example:

#!/usr/bin/lua

require "iwinfo"

local device = "wlan0"

function getinfo(ifname, func)
	local driver_type = iwinfo.type(ifname)
	if driver_type and iwinfo[driver_type][func] then
		return iwinfo[driver_type][func](ifname)
	end

	return nil
end
    
local opmode = getinfo(device, "mode")
if opmode then
	print("Device " .. device .. " is up with mode " .. opmode)

	local assoclist = getinfo(device, "assoclist")
	if assoclist then
		local count = 0
		local mac, info
		for mac, info in pairs(assoclist) do
			print("Client #" .. mac .. ": " .. info.signal .. "dB")
			count = count + 1
		end

		print("There are " .. count .. " clients")
	else
		print("Unable to fetch associated client list")
	end
else
	print("Device " .. device .. " appears to be down")
end
3 Likes

You can use the standard jsonfilter utility to efficiently extract the informaton:

root@lede:~# ubus call network.wireless status | jsonfilter -e '@.radio0.up'
true
2 Likes

Thanks a lot for the detailed answer and sample script. I quickly tested the various options against each other and it seems the lua script is the quickest and cleanest way to do this.

One more question though: I see you use "mode" as an indicator whether the device is up or not. Is that equal to the ubus wireless node radio{0,1}.up being set to true? Or are there corner cases where mode would still return "Master" but the radio would actually be disassociated?
I'm asking this because in the past I had issues with the ath10k firmware where it would crash or not be loaded during boot under certain circumstances. In these situations, iirc, the 5G radio would be shown as "disassociated" in LuCI.

So, I modified your script to return the information I'd like to collect. Apologies for any errors or style issues that I might have added to the code, but this is the first time I acutally played with LUA. Yet, it works fine so far:
#!/usr/bin/lua

require "iwinfo"

local devices = {}
devices["5G"] = "wlan0"
devices["2.4G"] = "wlan1"

function getinfo(ifname, func)
        local driver_type = iwinfo.type(ifname)
        if driver_type and iwinfo[driver_type][func] then
                return iwinfo[driver_type][func](ifname)
        end
        return nil
end

local key, device
for key, device in pairs(devices) do
        local opmode = getinfo(device, "mode")
        if opmode == "Master" then
                local count = 0
                local assoclist = getinfo(device, "assoclist")
                if assoclist then
                        local _
                        for _ in pairs(assoclist) do
                                count = count + 1
                        end
                end
                print(key .. " radio is up, " .. count .. " clients connected")
        else
                print(key .. " radio appears to be down")
        end
end

Here's how it looks:
root@lede:~# ./wifi_info.lua
2.4G radio is up, 7 clients connected
5G radio is up, 5 clients connected

I can now answer my own question as I experienced such an ath10k driver crash again. At least in my case, the "mode" property is not a good indicator for the radio being up or not. When the ath10k driver crashes, "mode" would still return "Master", but the radio is actually down. iwinfo would instead show that the properties "signal" and "bit rate" return "unknown" (or "nil" inside the lua script) and "link quality" would show "unknown/70". So I changed the script to check for the value of "signal" as well when there are no clients connected. If there are 0 clients and signal is "nil", my script would report the radio is down or in failed state.