hasseg.org

Keeping AirPort Connected to a Specific Access Point

Filed under Mac, Scripts

keepConnectedToWLANAP application icon The wireless LAN access point we have at our house is an old Belkin box that only supports the 802.11b standard, which is the slowest of the few "versions" of WiFi. The speed hasn't been a big issue -- we rarely need to move large files over the internal network, and if we do, we plug in an Ethernet cable. Even the fact that it sometimes replaces web pages your browser requests with advertisements of some fantastic parental filter feature it has has not annoyed us enough to take action. What has been an issue, though, is the fact that it frequently drops connections with our Macbooks.

The Macbooks' AirPort WLAN adapters have been working in other networks without running into any major problems, and the Belkin access point didn't drop connections with any of the other laptops we've used at home, so this leads me to believe this is some sort of compatibility issue between the AirPort and the Belkin. The AirPort works generally well and just as expected when connected to the access point, but frequently the connection just inexplicably drops, and to get it back, we have to turn AirPort off and then back on again (via the menu bar item, for example,) and even then it sometimes doesn't reconnect, making us repeat the process (maybe a couple of times, depending on how cranky a mood it is in.)

The first solution I made for this was a small script that would reconnect to the access point, which I made an application out of with Platypus, and put on my desktop for some double-clicking action. Whenever the connection would drop, I'd use the Exposé "show desktop" action (I've set it to be triggered whenever I move my mouse to a specific corner of the screen) and double-click to invoke the reconnect app to get me back online. Quite soon, though, having to keep repeating this became a bit annoying as well. So then I decided to extend this script to run a loop that checks the AirPort connection status at regular intervals, and reconnects automatically if the connection has dropped. To enable easy invocation of this script, and to be able to get the output to be displayed in a nice GUI window, I again used Platypus to make it into an application. This has been working pretty well for me so far, so I decided to share the fruits of my labour with you here:

Keep in mind, this is not the most easy-to-use solution since you have to go inside the application bundle, find the script file, open it up in a text editor, and change the settings inside the script to be able to tell it which access point to connect to and with which password.

Download the application here: keepConnectedToWLANAP-v0.8.dmg

Or check out the source here:

#!/bin/bash
# ----------------------------------------
# DESCRIPTION:
# 
# Keep airport associated with a specific
# access point
# 
# 
# Copyright (c) 2008 Ali Rantakari
# http://hasseg.org
# 
# ----------------------------------------





# settings begin here:
# --------------------

# SSID of WLAN AP to connect to
TOSSID="MYSSID"

# WLAN AP password
WITHPW="0xf0f0f0f0f0f0f0f0f0f0f0f0f0"


# where to find the airport utility (it's here in Tiger and Leopard, at least)
AP="/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport"

CHECKINTERVAL=5 # how often to check AirPort status
CHECKINTERVALWHENOFF=20 # how often to check AirPort status if it's been off

TRIES=7 # how many times to retry connecting if not successful
RETRYDELAY=3 # how many seconds to wait before retrying


# ------ settings end here. implementation begins below





#if [ "$1" == "-xv" ];then
#	VERBOSE="true"
#else
#	VERBOSE="false"
#fi
VERBOSE="true"




is_on()
{
	if [ "`$AP --getinfo | grep -c \"AirPort: Off\"`" == "1" ];then
		echo "false"
	else
		echo "true"
	fi
}

is_associated()
{
	if [ "`$AP --getinfo | grep SSID | grep -v BSSID | grep -c $TOSSID`" == "0" ];then
		echo "false"
	else
		echo "true"
	fi
}

connect()
{
	if [ "$VERBOSE" == "true" ];then
		echo " "
	fi
	
	I=0
	while [ "$I" -lt "$TRIES" ]
	do
		if [ "$VERBOSE" == "true" ];then
		#	if [ "$I" == "1" ];then
		#		echo " "
		#		echo "    (trying $(($TRIES-1)) more times)"
		#		echo " "
		#	fi
			echo -n "    Trying to connect to $TOSSID... "
		fi
		$AP --associate=$TOSSID --password=$WITHPW
		if [ "`is_associated`" == "true" ];then
			# ok
			I=$TRIES
			if [ "$VERBOSE" == "true" ];then
				echo "...done!"
			fi
		else
			# not ok -> retry
			I=$(($I + 1))
			if [ "$VERBOSE" == "true" ];then
				if [ "$I" == "$TRIES" ];then
					echo "...unsuccessful."
				else
					echo -n "...unsuccessful."
				fi
			fi
			
			if [ "$I" -lt "$TRIES" ];then
				if [ "$VERBOSE" == "true" ];then
					echo -n " Retrying in "
				fi
				
				J=$RETRYDELAY
				while [ "$J" -gt "-1" ]
				do
					J=$(($J - 1))
					sleep 1
					if [ "$VERBOSE" == "true" ];then
						echo -n "$(($J+1))"
					fi
				done
				
				if [ "$VERBOSE" == "true" ];then
					echo " "
				fi
			fi
			
		fi
	done
	
	if [ "$VERBOSE" == "true" ];then
		echo " "
	fi
}





CURRCHECKINTERVAL=$CHECKINTERVAL
LASTONSTATUS="on"
LASTASSOCIATEDSTATUS="false"
FIRSTRUN="true"

# main loop
while [ "1" == "1" ]
do
	if [ "`is_on`" == "false" ];then
		if [ "$VERBOSE" == "true" ]&&[ "$LASTONSTATUS" == "on" ];then
			echo "- Airport turned off, will not try to connect until it's turned on again."
		fi
		LASTONSTATUS="off"
		CURRCHECKINTERVAL=$CHECKINTERVALWHENOFF
	else
		if [ "`is_associated`" == "true" ];then
			if [ "$VERBOSE" == "true" ]&&[ "$LASTASSOCIATEDSTATUS" == "false" ];then
				echo "- Already connected to $TOSSID."
			fi
			LASTASSOCIATEDSTATUS="true"
		else
			if [ "$VERBOSE" == "true" ]&&[ "$FIRSTRUN" == "false" ];then
				if [ "$LASTONSTATUS" == "off" ];then
					echo "- Airport is on again, initiating connect procedure:"
				else
					if [ "$LASTASSOCIATEDSTATUS" == "true" ];then
						echo "- Connection to $TOSSID lost. Initiating connect procedure:"
					else
						echo "- Trying to connect again:"
					fi
				fi
			fi
			connect
			if [ "`is_associated`" == "true" ];then
				LASTASSOCIATEDSTATUS="true"
			else
				LASTASSOCIATEDSTATUS="false"
			fi
		fi
		LASTONSTATUS="on"
		CURRCHECKINTERVAL=$CHECKINTERVAL
	fi
	sleep $CURRCHECKINTERVAL
	FIRSTRUN="false"
done

2 Comments

Jean June 15, 2008 at 1:39 PM

That is just what need ! But the application always say that root privileges are required when it trying to connect. could you help me please :-)

Ali Rantakari June 16, 2008 at 10:37 AM

This access rights change for the airport command-line utility, I believe, was part of a recent OS update (either the recent security update or 10.5.3,) and it seems to have been causing some trouble here. You can modify the script to run it via sudo, though, but I’ve noticed that even when I get it working like this the airport command-line utility still “hangs” sometimes and fails to return, forcing me to restart the script. To make the script run it via sudo, make the change to this line:

sudo $AP --associate=$TOSSID --password=$WITHPW

Categories