Quick Test Please? “Wi-Fi Disconnected” Macro (KM_8.2.4)

Quick Summary & Request

If you have a MacBook, can you try networksetup -setairportpower en0 off and see if AirPort gets turned off?

If it does, run networksetup -setairportpower en0 on to turn it back on.

(If you have an iMac or Mac Mini, it's probably en1 instead of en0.)

Longer Explanation

I'm trying to figure out if networksetup can be run without sudo — the man page says that it does, but in my limited testing, it does not seem to.

Here's what I am trying to do:

  1. If the Wireless Network disconnects…
  2. run networksetup -setairportpower en0 off
  3. Wait 3 seconds
  4. Run networksetup -setairportpower en0 on

The idea being that sometimes Wi-Fi disconnects when you do not want it to, and one way to get it to come back is to turn AirPort off / on.

This is one of those times when having a bunch of VMs with different versions of clean Mac OS X/OS X/macOS installs would be handy, but I don't have that.

Here's my macro:


Keyboard Maestro 8.2.4 “Wi-Fi Disconnected” Macro

Wi-Fi Disconnected.kmmacros (2.6 KB)

No sudo required for me.

You can feel free to use this script to programmatically turn Wi-Fi on and off:

use framework "CoreWLAN"

property nil : a reference to missing value
property _1 : a reference to reference

# WiFiOn:
#   If +state is a boolean value, then this handler sets the power state of the
#   WiFi interface accordingly: true/yes/1 -> On, false/no/0 -> Off.  Otherwise,
#   the handler retrieves the current power state of the interface.
on WiFiOn:(state as {boolean, anything})
	tell (current application's CWWiFiClient's ¬
		sharedWiFiClient's interface())
		if the state's class ≠ boolean ¬
			     then return powerOn()
		its setPower:state |error|:nil
	end tell
	
	WiFiOn_(null)
end WiFiOn:

1 Like

I have improved the script that I use for this, and it's now on Github. There are copious comments on it that should explain why it is written the way it is, but I tried to take several "edge cases" into consideration.

You seem very determined to get this done in a shell script.


PS. If you want the SSID of the network you'e currently connected to:

use framework "CoreWLAN"

to getSSID()
	tell (current application's CWWiFiClient's ¬
		sharedWiFiClient's interface()) to ¬
		return the ssid() as text
end getSSID

@CJK, thanks for sharing.

This will be obvious to some, but maybe not to those less familiar with scripting.
You need to add a statement to call the handler, like this:

use framework "CoreWLAN"

return my getSSID()  -- ADD THIS STATEMENT

to getSSID()
  tell (current application's CWWiFiClient's ¬
    sharedWiFiClient's interface()) to ¬
    return the ssid() as text
end getSSID

I suppose I fall into the "if your only tool is a hammer" cliché… shell scripts are where I am most comfortable.

I'm not even sure how to use the code that you've provided. Is that ruby or swift or something else?

UPDATE: Oh, it's AppleScript! (Another language that I wish I knew better.) That's handy to know. Thanks!

UPDATE 2: OK, so that AppleScript is handy, but all it does it get the SSID. The shell script I wrote does a bit more than that.

If all you want to do is get the current SSID in a shell script, you can do this in a "one-liner":

airport -I | awk -F': ' '/ SSID/{print $NF}'

Now, I have linked /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport to /usr/local/bin/airport so I can use it more easily, but if you haven't done that, you'll need to use the full path to airport.

But the other thing that airport does it report whether or not the AirPort/Wi-Fi card has been turned off or not. (The AppleScript just says "missing value" which is the same as what it says when there's no Wi-Fi network connected.)

If Wi-Fi has been turned off for some reason, then the script won't do anything because it assumes that was done on purpose.

However, if Wi-Fi is on but not connected to a Wi-Fi network then the script will power-off the AirPort card, wait a few seconds, and then turn it back on. That will often be enough to cause it to rejoin a local Wi-Fi network if it dropped off of it for some reason.

It is also capable of determining the proper Ethernet port for the Wi-Fi (for example, on a MacBook it's probably en0 but on an iMac or Mac Mini it's probably en1). This is handy because I actually sync this macro to a MacBook running Mojave, a Mac Mini running High Sierra, and an iMac running El Capitan.

This is handy if you have a Mac that runs as a headless server in the basement or in an entertainment center that is not connected by Ethernet where it would be a pain to have to hook up some kind of monitor and keyboard in order to manually re-connect to the Wi-Fi network.

The latest change I made was to add a slight delay to the beginning of the script, because if you are changing Wi-Fi networks in the same location for some reason, I found that it was interrupting that process. So I added a brief sleep and then check to see if it is already re-joined a Wi-Fi network, and if it has, then it won't bother with any of the above, because the whole point is to make sure that the computer stays on a Wi-Fi network.

Anyway, that's why I wrote it as a shell script, because I wanted to include this level of complexity to it, and shell scripting is the language that I know best. I'm quite sure you can probably do it in other languages too, but if someone doesn't know any scripting at all, they ought to be able to use my script just by "dropping it in" to Keyboard Maestro.