Table of Contents
WiFi Monitoring
This is the other side of the equation from This Airport Basestation Monitoring solution. In that case you want to monitor your airport basestations to make sure they are still available and get your external IP from them. If you have an XTension machine that is connected via wifi then you may want to monitor that connection and make sure it stays up.
This was born out of an unusual problem I had with a remote XTension machine that was connected via wifi. I wanted the machine to be signed into my iCloud account so that I could use Back To My Mac as a last ditch way to connect to it if all else was failing. That also meant that it was getting my list of known WiFi access points and passwords. You wouldn’t think that would be a problem except that once in a while a very far away xfinity wifi station was visible and every so often the wifi/DSL modem in the place restarts or goes down for a time and the machine had a tendency to switch to that other network. While this incorrect wifi network was visible and the airport thought it had connected to it, it wasn’t actually usable at that distance and so every attempt to connect failed. Not to mention that it couldn’t reach the other devices on the local network if it switched to that. It took it 4 days to switch back at one point.
You can set a preferred airport network by dragging the list of airports around. But it won’t switch back to your preferred network when it becomes available again if it’s already logged into another one. I’m also not entirely certain what it will do if your only network is not available when it starts up and becomes available later. Will it reliably re-join later if it’s not there at startup? I have seen both behaviors so this script can be used to make sure it’s both connected and connected to the correct network.
There are command line tools you can use to both check what wifi network you’re connected to as well as change what wifi you’re connected to. This AppleScript checks the current wifi SSID that you are connected to, and if it’s not what you want it to be connected to then it will execute the command to change your wifi connection to the network you want. Since it was also available in the output I am also assigning the RSSI or signal strength, noise level and transmit rate just for graphing in XTdb not because there is a particular problem but it is interesting to watch especially the tx rate, when more people are connected or when there are more active wifi networks on the same channel within range. There may be other parameters you wish to scan for and you can alter the script to set those values to units too.
If you just wish to collect the data on signal strength, noise level and transmit rate you can set the property “checkSSID” to false in the script below. It will then ignore the SSID settings and not make any attempts to change your airport network. Here’s an example of the data from the machine in question. You can see the values are all over the place because it’s a very busy building with LOTS of wifi networks within range causing all sorts of interference. It’s a 2.4ghz only network and I’m doing a scan every 5 minutes to generate this graph.
Setting the Airport SSID
The command line tool that can change the airport network is called networksetup In order to set the airport network you’ll first need to know the device name of the airport network. This is not the same across all Macs so be sure to run this on the machine you’re going to be running the script on. To find that out open a terminal window and type:
networksetup -listallhardwareports
that will result in a list of all your potential physical networking ports out of the machine. You’re looking for the line that says Wi-Fi or if you have more than one wifi adaptor you’ll need to figure out which is the one that points to the device you’re wanting to configure. On my system the info looks like this:
Hardware Port: Wi-Fi Device: en0 Ethernet Address: 00:00:00:00:00:00
It’s that Device line that is important, so on my machine thats “en0”
As an aside you can also get the name of the current airport network from this same tool by doing a:
networksetup -getairportnetwork en0
replacing the en0 with whatever it is on your machine of course. This will output the name of the airport network as well as what we’re going to do later, but it doesn’t give you the airport statistics that I found interesting enough to want to parse out and save to the database.
Airport Command Line Tool
Hidden deep in the system is a command line tool called just airport that you can use to get the current airport info and set a lot of other parameters about it. Unfortunately it is not in the path of the terminal by default and the new protections on system level files in OSX make it difficult to add it to the path. I’m sure there is a user path that you can add it to but I couldn’t get that to work for some reason. The full path to the tool is: /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport and to get all your airport status info you can run it with the “-I” switch like this:
/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I
or switch to it’s parent directory and then run it just as ./airport -I but we will use the full path in the script.
That results in a report something like this:
/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I agrCtlRSSI: -52 agrExtRSSI: 0 agrCtlNoise: -86 agrExtNoise: 0 state: running op mode: station lastTxRate: 117 maxRate: 144 lastAssocStatus: 0 802.11 auth: open link auth: wpa2-psk BSSID: 00:00:00:00:00:00 SSID: WIFI_NETWORK_NAME MCS: 14 channel: 1
on all of my machines the parameters agrExtRSSI and agrExtNoise are always 0 so I’m not sure what those are for exactly. The parameters that are interesting are the ctlRSSI the CtlNoise and the lastTxRate as well as the SSID line of course. If you’re connected to a 5ghz router then the channel line will have 2 values separated by a comma showing the 5ghz channel and the 2.4ghz channel numbers. For example on my better router at home I currently see 152,1. The MCS or modulation and coding scheme may be interesting to some also. I believe it is from that that the data rate is calculated but not important for us at the moment.
Create Units
You’ll need a few pseudos to hold the parameters of interest. My units are named:
- WIFI RSSI
- WIFI Noise
- WIFI TxRate
They should be set to dimmable as well as “ignore clicks” so that they just display in the unit lists and don’t offer you a toggle switch control which would be the default otherwise.
The Global Script
Cut and paste this script into a new Global Script in XTension. You’ll need to fill in some of the script parameters with the device id you got above, as well as the desired wifi SSID and password as well as the names of the pseudo units into which to place the other parsed data. It may actually not be necessary to specify the password if the machine has already remembered the password for that network. Since this is designed for unattended use however it’s probably a good idea to specify it anyway as you don’t want any dialogs popping up or any command line requests for the password if the keychain is locked or if something else similar happens. You can avoid all that by entering it into the script though it will require you to type the password in plain text into the script. I would consider this a minor security risk as if someone is sitting in front of your computer or already logged into your computer you have bigger problems then them also being able to join your wifi network.
-- -- WIFI Status and SSID Verification Script -- v 1.0 7/21/2018 james@sentman.com -- http://MacHomeAutomation.com/doku.php/tutorials/wifi -- free as in beer, no support or expectations of usability -- -- edit these lines to hold your specific info -- the device id or “port” you got from the networksetup line above property wifiPort:”en0” -- set to false if you just want to collect wifi info and do not wish it to -- try to reset your SSID. property checkSSID: true -- your desired wifi information property desiredSSID:”name of network you want to be connected to” property wifiPass:”yourpassword” -- the names of your pseudo units to hold the other info property RSSIUnit:”WIFI RSSI” property NoiseUnit:”WIFI Noise” property TxRateUnit:”WIFI TxRate” -- this is the end of the configurable parameters property getStatusCommand:"/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I” -- run the airport status command -- this command executes quickly so the use of an [[dictionary:more:asyncshell|async shell script]] is not necessary set myResult to do shell script getStatusCommand -- results look like -- agrCtlRSSI: -52 -- agrExtRSSI: 0 -- agrCtlNoise: -86 -- agrExtNoise: 0 -- state: running -- op mode: station -- lastTxRate: 117 -- maxRate: 144 --lastAssocStatus: 0 -- 802.11 auth: open -- link auth: wpa2-psk -- BSSID: 00:00:00:00:00:00 -- SSID: CURRENT_SSID_NAME -- MCS: 14 -- channel: 1 -- we’re going to walk each line until we find the things we are interested in -- first convert it into a list for easier walking set theLines to split( myResult, return) repeat with thisLine in theLines -- look for the SSID entry -- note that this comparison string must have a space in front of it or we also -- match the BSSID line above which is not helpful if checkSSID is true then if “ SSID:” is in thisLine then set currentSSID to item 2 of split( thisLine, “SSID: “) if currentSSID is not equal to desiredSSID then write log “SSID is incorrect. Current SSID is: “ & currentSSID & “ attempting to rejoin desired network” color red -- you could also do other notification here, send an email or a Prowl alert. -- the network setup command takes some time to complete and so we will run it in an async shell script -- add quotes around the wifi SSID and password just in case they contain shell unfriendly characters like spaces -- quotes inside of applescript strings must be escaped with the backslash set theCommand to “networksetup -setairportnetwork “ & wifiPort & “ \”” & desiredSSID & “\” \”” & wifiPass & “\”" do async shell script theCommand callback handler “networksetupResult” timeout 5 * minutes -- normally done in 10 seconds or so end if end if end if -- look for RSSI line if “agrCtlRSSI:” is in thisLine then -- wrap these in try lines as the cast to number can fail if something else is in the value but a valid number try set currentRSSI to item 2 of split( thisLine, “agrCtlRSSI: “) as number -- only update the unit if the value has actually changed if (value of RSSIUnit) is not equal to currentRSSI then set value of RSSIUnit to currentRSSI end if on error write log “error parsing wifi RSSI line: “ & thisLine color red end try end if -- look for the noise line if “agrCtlNoise:” is in thisLine then try set currentNoise to item 2 of split( thisLine, “agrCtlNoise: “) as number if (value of NoiseUnit) is not equal to currentNoise then set value of NoiseUnit to currentNoise end if on error write log “error parsing wifi Noise line: “ & thisLine color red end try end if -- look for lastTxRate line if “lastTxRate:” is in thisLine then try set currentRate to item 2 of split( thisLine, “lastTxRate: “) as number if (value of TxRateUnit) is not equal to currentRate then set value of TXRateUnit to currentRate end if on error write log “error parsing tx rate line: “ & thisLine color red end try end if end repeat -- -- NETWORK SETUP RESULT -- -- the result of the networksetup command to change the SSID will end up here -- on networksetupResult( resultCode, output, executionTimeMS) -- the result code will be 0 if all went well -- re-run the getStatusCommand and write it to the log just for verification later if resultCode is equal to 0 then write log “networksetup command returns OK new settings: “ & (do shell script getStatusCommand) else -- there was some error, write that to the log write log “networksetup returns code “ & resultCode color red write log “output: “ & output color red write log “current airport info: “ & (do shell script getStatusCommand) color red end if end networksetupResult -- -- SPLIT -- -- a helper handler for making it easier to split strings into lists -- on split( theData, theDelim) set AppleScript’s text item delimiters to {theDelim} set theResult to every text item of theData -- important to always reset these to the empty list or hilarity will ensue later in your script set AppleScript’s text item delimiters to {} return theResult end split
Create The Event
Once you’ve completed the script above you can run it manually just to test but you’ll want it to run regularly so you’ll need to create a Scheduled Event to run the global script every 10 or 15 minutes. Since the script executes quickly there should be no problem with running it as often as every 5 minutes if you’re interested in collecting more wifi performance and signal strength data and such. I would not run it more often then that as the timeout for the networksetup command is also 5 minutes. You don’t want the script to run again while the networksetup command might still be running in that async shell command. Trying to set the network again while another command is already trying to set the network might result in unpredictable and undesired results.