Automatically disable Wifi when an Ethernet connection (cable) is plugged in on a Mac

Overview

This is a bash script that will automatically turn your wifi off if you connect your computer to an ethernet connection and turn wifi back on when you unplug your ethernet cable/adapter. If you decide to turn wifi on for whatever reason, it will remember that choice. This was improvised from this mac hint to work with Yosemite, and without hard-coding the adapter names. It’s supposed to support growl, but I didn’t check that part. I did, however, add OSX notification center support. Feel free to fork and fix any issues you encounter.

Most the credit for these changes go to Dave Holland.

Installation Instructions

  • Copy toggleAirport.sh to /Library/Scripts/
  • Run chmod 755 /Library/Scripts/toggleAirport.sh
  • Copy com.mine.toggleairport.plist to /Library/LaunchAgents/
  • Run chmod 600 /Library/LaunchAgents/com.mine.toggleairport.plist
  • Run sudo launchctl load /Library/LaunchAgents/com.mine.toggleairport.plist to start the watcher

Uninstall Instructions

  • Run sudo launchctl unload /Library/LaunchAgents/com.mine.toggleairport.plist to stop the watcher
  • Delete /Library/Scripts/toggleAirport.sh
  • Delete /Library/LaunchAgents/com.mine.toggleairport.plist
  • Delete /private/var/tmp/prev_eth_on
  • Delete /private/var/tmp/prev_air_on

Misc

To debug, just run: sudo /Library/Scripts/toggleAirport.sh and add echo’s wherever you’d like

com.mine.toggleairport.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>com.asb.toggleairport</string>
  <key>OnDemand</key>
  <true/>
  <key>ProgramArguments</key>
  <array>
    <string>/Library/Scripts/toggleAirport.sh</string>
  </array>
  <key>WatchPaths</key>
  <array>
    <string>/Library/Preferences/SystemConfiguration</string>
  </array>
</dict>
</plist>

toggleAirport.sh

#!/bin/bash

function set_airport {

    new_status=$1

    if [ $new_status = "On" ]; then
        /usr/sbin/networksetup -setairportpower $air_name on
        touch /var/tmp/prev_air_on
    else
        /usr/sbin/networksetup -setairportpower $air_name off
        if [ -f "/var/tmp/prev_air_on" ]; then
            rm /var/tmp/prev_air_on
        fi
    fi

}

function growl {

    # Checks whether Growl is installed
    if [ -f "/usr/local/bin/growlnotify" ]; then
        /usr/local/bin/growlnotify -m "$1" -a "AirPort Utility.app"
    else
        osascript -e "display notification \"$1\" with title \"Wifi Toggle\" sound name \"Hero\""
    fi

}

# Set default values
prev_eth_status="Off"
prev_air_status="Off"
eth_status="Off"

# Grab the names of the adapters. We assume here that any ethernet connection name ends in "Ethernet"
if [ -z $eth_names ]; then
   eth_names=$(networksetup -listnetworkserviceorder | grep "Hardware Port" | grep "Belkin USB-C LAN" | awk -F':' '{print $3}' |  sed -e "s/ //" | sed -e "s/)//")
elif [ -z $eth_names ]; then
   eth_names=$(networksetup -listnetworkserviceorder | grep "Hardware Port" | grep "Ethernet Adapter" | awk -F':' '{print $3}' |  sed -e "s/ //" | sed -e "s/)//")
fi


#eth_names=`networksetup -listnetworkserviceorder | sed -En 's|^\(Hardware Port: .*Ethernet Adapter, Device: (en.)\)$|\1|p'`
air_name=`networksetup -listnetworkserviceorder | sed -En 's/^\(Hardware Port: (Wi-Fi|AirPort), Device: (en.)\)$/\2/p'`

# Determine previous ethernet status
# If file prev_eth_on exists, ethernet was active last time we checked
if [ -f "/var/tmp/prev_eth_on" ]; then
    prev_eth_status="On"
fi

# Determine same for AirPort status
# File is prev_air_on
if [ -f "/var/tmp/prev_air_on" ]; then
    prev_air_status="On"
fi

# Check actual current ethernet status
for eth_name in ${eth_names}; do
    if ([ "$eth_name" != "" ] && [ "`ifconfig $eth_name | grep "status: active"`" != "" ]); then
        eth_status="On"
    fi
done

# And actual current AirPort status
air_status=`/usr/sbin/networksetup -getairportpower $air_name | awk '{ print $4 }'`

# If any change has occured. Run external script (if it exists)
if [ "$prev_air_status" != "$air_status" ] || [ "$prev_eth_status" != "$eth_status" ]; then
    if [ -f "./statusChanged.sh" ]; then
        "./statusChanged.sh" "$eth_status" "$air_status" &
    fi
fi

# Determine whether ethernet status changed
if [ "$prev_eth_status" != "$eth_status" ]; then

    if [ "$eth_status" = "On" ]; then
        set_airport "Off"
        growl "Wired network detected. Turning AirPort off."
    else
        set_airport "On"
        growl "No wired network detected. Turning AirPort on."
    fi

# If ethernet did not change
else

    # Check whether AirPort status changed
    # If so it was done manually by user
    if [ "$prev_air_status" != "$air_status" ]; then
    set_airport $air_status

    if [ "$air_status" = "On" ]; then
        growl "AirPort manually turned on."
    else
        growl "AirPort manually turned off."
    fi

    fi

fi

# Update ethernet status
if [ "$eth_status" == "On" ]; then
    touch /var/tmp/prev_eth_on
else
    if [ -f "/var/tmp/prev_eth_on" ]; then
        rm /var/tmp/prev_eth_on
    fi
fi

exit 0