Skip to content

Instantly share code, notes, and snippets.

@amekusa
Last active September 26, 2021 21:16
Show Gist options
  • Select an option

  • Save amekusa/168ba3a60517ece3217a3111c8be3058 to your computer and use it in GitHub Desktop.

Select an option

Save amekusa/168ba3a60517ece3217a3111c8be3058 to your computer and use it in GitHub Desktop.
Mac WiFI Monitor; A bash script that keeps checking if the WiFi connection alive on your Mac by continuously sending pings to the router and public DNSes. If the connection seemed lost nonetheless, the script automatically restarts the WiFi adapter.
#!/bin/bash
# Mac WiFi Monitor
# ------------------ ---- -- -
# Keeps checking if the WiFi connection alive
# by continuously sending pings to the router and public DNSes.
# If the connection seemed lost nonetheless,
# automatically restarts the WiFi device on your Mac
# ====================================================
# Author: amekusa.com
# Version: 2.2.0
# Updated: 2021-09-27
# ---- Settings --------
# Network device to monitor (leave it commented out to automatically detect the WiFi device)
# DEV=en1
# NOTE: To list all the devices:
# $ networksetup -listallhardwareports
PING_TO=(192.168.1.1 1.1.1.1 8.8.8.8 4.2.2.2)
PING_INTERVAL=3 # seconds
PING_TIMEOUT=1 # seconds
PING_SIZE=0 # bytes
AUDIBLE_ALERTS=true # true or false
PROMPT_RESTART=false # true or false
LOG_TO_FILE=true # true or false
LOG_FILE="$HOME/.wifi-monitor.log"
SYSLOG=false # true or false
# NOTE: syslog on High Sierra is broken
# ==== END Settings ====
trap _quit SIGINT
_quit() {
echo
_ts; _log "Finished by user input @ $ts"
exit
}
_ts() {
ts=$(date +'%H:%M:%S %b %d, %Y')
}
_log() {
[ "$log" = "$1" ] && return # don't repeat the same message
$LOG_TO_FILE && echo "$1" >> $LOG_FILE
$SYSLOG && syslog -s "[WiFi Monitor] $1"
echo "$1"
log="$1"
}
_active() {
[[ $(networksetup -getairportpower $DEV) == *On ]]
}
_ping() {
ping -c 1 -s $PING_SIZE -t $PING_TIMEOUT -n ${PING_TO[$1]} &> /dev/null
}
_restart() {
_log "Restarting $DEV ..."
networksetup -setairportpower $DEV off
sleep 1
networksetup -setairportpower $DEV on
_state 1
}
_state() {
_ts
case $1 in
0) _log "The device got deactivated @ $ts" ;;
1) _log "The device got activated @ $ts" ;;
2) _log "Internet connection alive @ $ts" ;;
esac
state=$1
}
_loop() {
case $state in
2) # online
i=0
_log "Started pinging to ${PING_TO[$i]} ..."
while [ $i -le $iMax ]; do
if _ping $i; then
if [ $i -gt 0 ]; then
_log " Ping to ${PING_TO[$i]} succeeded"
i=0
fi
sleep $PING_INTERVAL
else # ping failed
if ! _active; then
_state 0; sleep 1
return
fi
if [ $i -eq 0 ]; then
_ts
elif $AUDIBLE_ALERTS && [ $i -lt $iMax ]; then
afplay -v .5 /System/Library/Sounds/Hero.aiff &
fi
_log "!) Ping to ${PING_TO[$i]} failed"
((i++))
fi
done
_log "!) Connection lost @ $ts"
$AUDIBLE_ALERTS && afplay /System/Library/Sounds/Purr.aiff &
if $PROMPT_RESTART; then
while true; do
read -n 1 -p "Restart WiFi device (Y/N) ? " answer
echo
case $answer in
[Yy]) _restart; return ;;
[Nn]) _ts; _log "Resumed monitoring $DEV @ $ts"; return ;;
*) echo "!) Type Y to restart, N to continue monitoring" ;;
esac
done
fi
_restart
;;
1) # device active
i=0
while ! _ping $i; do
_log "Waiting for internet connection ..."
if ! _active; then
_state 0; sleep 1
return
fi
if [ $i -ge $iMax ]; then i=0; else ((i++)); fi
done
$AUDIBLE_ALERTS && afplay -v .5 /System/Library/Sounds/Submarine.aiff &
_state 2; sleep $PING_INTERVAL
;;
0) # device inactive
while ! _active; do
_log "Waiting for the device to be activated ..."
sleep 1
done
_state 1
;;
esac
}
# ---- Initialize --------
# clear the existing log file
$LOG_TO_FILE && [ -f $LOG_FILE ] && true > $LOG_FILE
# initialize variables
[ -z $DEV ] && DEV=$(networksetup -listallhardwareports | awk -F': ' '/Wi-Fi/{getline; print $2;}')
iMax=$((${#PING_TO[@]}-1)) # PING_TO.length - 1
if _active; then
state=1
else
state=0; sleep 1
fi
# ---- Main --------
_log "Monitoring the network device '$DEV' ..."
while _loop; do
: # noop
done
_ts; _log "The script stopped due to an unknown error @ $ts"
@amekusa
Copy link
Author

amekusa commented Aug 18, 2021

This bash script continuously sends pings to public DNSes at 3-seconds intervals to keep internet connection alive.
If the connection was lost nonetheless for whatever reason, the script automatically restarts the WiFi device.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment