LoginSignup
2
1

More than 5 years have passed since last update.

macbook airでWi-Fiに繋がらない時、自動的にbluetoothテザリングに接続するシェルスクリプト

Last updated at Posted at 2018-05-03

はじめに

 macbook airを持ち歩いて、スマホのbluetooth経由でテザリングしていたのだけれども、スリープしたり、macから離れる度に接続が切れて、切れて、切れまくる!

 毎回、ステータスバーのbluetoothのアイコンをクリックして接続し直していたんだけれども、あまりにも頻繁なので、wifiに接続できない時は自動的にbluetoothテザリングに接続するシェルスクリプトを書いてみた。

 bitbarというステータスバーにスクリプトを常駐させるアプリを使って、スクリプトを実行すれば、スマホだけで常時接続なmacのできあがり。ありがとう、bitbar!

[bitbarからスクリプトを実行]
dtz_image.jpeg

[メニュー画面]
btz_menu_image.jpeg

できること

  • wifiに接続できない場合、bluetoothテザリングに接続。wifiに接続できるようになったら、bluetoothテザリングを切断。bitbarからこのスクリプトを起動することで、常駐してこの作業を定期的に実行できるようになる。
  • 安全のため、1回の最大連続通信量(300MB)を超えると自動的に切断するようにした。(再度使用可能にするには、メニューから Reset DATA OVER を選択してください)

必要な環境

  • MacBook Air (13-inch, 2017)〜たぶんmacbookでも動くと思う
  • macOS High Sierra 10.13.3
  • bitbarがインストール済み https://getbitbar.com
  • macがスマホとbluetooth接続でテザリングできるように設定されている
  • データ通信の定額プランに加入している(問答無用で勝手に接続しに行くスクリプトなので、これとっても重要!従量制の人は決して使ってはいけない)
  • スマホはandroidスマホ Nexus 5X で確認(iphoneは持っていないので試せなかった)
  • スマホはiphoneとandroid Nexus 5Xで確認

スクリプトの使い方

1. bitbarをインストール

  • メニューバーからスクリプトを定期的に起動するアプリ bitbar を https://getbitbar.com からダウンロードし、インストール。

2. wifiに接続できない時は自動的にbluetoothテザリングに接続するシェルスクリプト btz.30s.sh を設定

  • 下にあるシェルスクリプトをテキストエディットにコピペして、btz.30s.shというファイル名で、ホームフォルダ以下の適当なフォルダに保存。
  • btz.30s.shの先頭部分にある必須設定の欄のBT_DEVICEに自分のスマホのデバイス名を記入して保存。
    • BT_DEVICEは、システム環境設定 -> Bluetoothで表示されているデバイス名を大文字、小文字、スペースも含めて正しく記述してあげてください。
  • btz.30s.shはシェルスクリプトなので、ファイルに実行権限を付与してあげる。(ターミナルで先程作成したディレクトリに移行後、chmod +x btz.30s.sh)
  • 監視間隔はシェルスクリプトのファイル名の30sの部分で設定(30sで30秒毎に起動。40sなら40秒毎に起動。基本デフォルトでOK)。

3. bitbarの設定

  • bitbarのメニューのPreferences -> Change Plugin Folder...で先程作成したフォルダを指定。
  • 画面最上段のステータスバーに青色で[BT tethering OFF]が表示されたら、WI-Fiをオフにする。30秒以内にbluetoothテザリングが開始されたら成功。

シェルスクリプト

  • 2018年05月07日 関数名を訂正しました (bt_swith_onoff → bt_switch_onoff) khskさんありがとう。
  • 2019年02月17日 iphoneでも動作を確認。
btz.30s.sh
#!/bin/bash

# 必須設定(必ず自分で設定してください)
#############################################################################
#   テザリングするときに使用するBluetoothデバイス名
#   (例 BT_DEVICE="iphone" or BT_DEVICE="Nexus 5X")
BT_DEVICE="iPhone"
#############################################################################

#############################################################################
# Btz.30s.sh - bluetoth tethering auto connect.
# 2018/01/10-04/30. edited by simizut.
# for mac osx 10.13.2(high sieera)
# Usage     : btz.30s.sh [-hwWbB]
#             * 30s is bitbar refresh time.
# no option : no wifi. connect to bluetooth tethering.
# -h        : help
# -w        : check wifi is on             (return 0:on 1:off)
# -W        : switch wifi on off           (return 0:on 1:off)
# -b        : check bluetooth is on        (return 0:on 1:off)
# -B        : switch bluetooth on off      (return 0:on 1:off)
# -n        : ckeck network is on          (return 0:on 1:off)
# -M        : ckeck bluetooth tethering MB
#############################################################################


# その他設定
#############################################################################
# ■以下は変更しなくても大丈夫
#   1回の最大連続通信制限[MB(メガバイト)] (例 MAXDATA="300")
MAX_DATA="300"
#   ログファイル名 .(ドット)で始まること
LOG_FILE=".btz.log"
#   最大通信量を超えた場合にフラグとして作成されるファイル名 .(ドット)で始まること
ERR_FILE=".btz.err"
#   bluetooth接続のメニュー文字列
BT_ON_MENU_STR="ネットワークへ接続"
#   bluetooth切断のメニュー文字列
BT_OFF_MENU_STR="ネットワークから接続解除"
#############################################################################

# 以下、スクリプト本体
#############################################################################
# 実行ファイルのディレクトリをカレントディレクトリに
HOME_DIR=`dirname $0`
cd ${HOME_DIR}
#  Wi-Fi、Bluetoothのネットワークデバイス名の取得
WIFI_DEV_NAME=$(networksetup -listnetworkserviceorder | grep '^(Hardware Port: Wi-Fi' | grep -o 'en.')
BT_DEV_NAME=$(networksetup -listnetworkserviceorder | grep '^(Hardware Port: Bluetooth' | grep -o 'en.')


# 以下、関数()
#############################################################################
# network_is_on - check network is on
# Arguments:
#   None
# Returns:
#   0:network on
#   1:network off
#############################################################################
network_is_on(){
    ping yahoo.co.jp -c1 -Q > /dev/null 2>&1
    if [ $? -eq 0 ]; then return 0
    else return 1
    fi
}

#############################################################################
# bt_is_on - check bluetooth tethering is on
# Arguments:
#   None
# Returns:
#   0:bluetooth tethering on
#   1:bluetooth tethering off
#############################################################################
bt_is_on(){
    networksetup -getinfo 'Bluetooth PAN' | Grep -wq '^IP address'
    if [ $? -eq 0 ]; then return 0
    else return 1
    fi
}

#############################################################################
# wifi_is_on - check wifi is on
# Arguments:
#   None
# Returns:
#   0:wifi on
#   1:wifi off
#############################################################################
wifi_is_on(){
    networksetup -getinfo 'Wi-Fi' | grep -wq '^IP address:'
    if [ $? -eq 0 ]; then return 0
    else return 1
    fi
}

#############################################################################
# bt_switch_onoff - switch bluetooth tethering on off
# Arguments:
#   None
# Returns:
#   0:bluetooth tethering on
#   1:bluetooth tethering off
#############################################################################
bt_switch_onoff(){
    osascript <<EOD
    try
    tell application "System Events"
        tell application process "SystemUIServer"
            tell menu bar 1
                set bt to item 1 of (menu bar items whose description is "bluetooth")
            end tell
            tell bt
                click it
                click menu item "${BT_DEVICE}" of menu 1
#Nexus5X            set str to name of (menu item 2 of menu 1 of menu item "${BT_DEVICE}" of menu 1)
#iPhone             set str to name of (menu item 1 of menu 1 of menu item "${BT_DEVICE}" of menu 1)
                    try
                        set str to name of (menu item "${BT_ON_MENU_STR}" of menu 1 of menu item "${BT_DEVICE}" of menu 1)
                    on error
                        set str to name of (menu item "${BT_OFF_MENU_STR}" of menu 1 of menu item "${BT_DEVICE}" of menu 1)
                    end try
                click menu item str of menu 1 of menu item "${BT_DEVICE}" of menu 1
                display notification str with title "${BT_DEVICE}"
            end tell
        end tell
    end tell
    on error
        display notification "error" with title "${BT_DEVICE}"
    end try
EOD
sleep 8s #ネットワークが安定するまでウエイト
bt_is_on
}

#############################################################################
# wifi_switch_onoff - switch wifi on off
# Arguments:
#   None
# Returns:
#   0:wifi on
#   1:wifi off
#############################################################################
wifi_switch_onoff(){
    networksetup -getairportnetwork ${WIFI_DEV_NAME} | Grep -wq '^Current Wi-Fi Network'
    if [ $? -eq 0 ]; then networksetup -setairportpower ${WIFI_DEV_NAME} off
    else networksetup -setairportpower ${WIFI_DEV_NAME} on
    fi
    wifi_is_on
}

#############################################################################
# bit_menu - display bitbar menu
# Arguments:
#   bitbar title text (ex. foo)
# Returns:
#   None
#############################################################################
bit_menu(){
    if [ ! -e ${LOG_FILE} ]; then # ログファイルがなければ、通信量は0に
        today_byte=0
        month_byte=0
    else
        today_byte="$(cat ${LOG_FILE} |grep ^$(date '+%Y/%m%d') |awk '{a+=$2} END{print a}')"
        month_byte="$(cat ${LOG_FILE} |grep ^$(date '+%Y/%m') |awk '{a+=$2} END{print a}')"
    fi
    echo "$1"
    echo '---'
    echo "BT Tethering auto connect : Check now| refresh=true"
    echo "Tethering Data : ${today_byte}MB/DAY ${month_byte}MB/MONTH"
    if [ -e $ERR_FILE ]; then # フラグファイルが存在する場合の処理
        echo "Reset DATA OVER | terminal=false bash=/bin/rm param1=${HOME_DIR}/${ERR_FILE} refresh=true"
    fi
}

#############################################################################
# bt_mbyte - calculate bluetooth tethering Mbyte
# Arguments:
#   None
# Returns:
#   None (bletoothパケット通信量(MB)を標準出力に表示)
#############################################################################
bt_mbyte(){
    ipt_byte=$(netstat -I ${BT_DEV_NAME} -b | grep '<Link' | awk '{print $7}')
    out_byte=$(netstat -I ${BT_DEV_NAME} -b | grep '<Link' | awk '{print $10}')
    all_mbyte=$(((ipt_byte+out_byte)/1048576))  #1048576 is 1024*1024 ( byte -> kbyte -> mbyte )
    echo ${all_mbyte}
}

#############################################################################
# save_log - save bluetooth traffic log
# Arguments:
#   None
# Returns:
#   None
#############################################################################
save_log(){
    date_str=$(date '+%Y/%m%d/%H%M' |tr -d '\n')                # 記入するログデータの作成
    byte_str=$(bt_mbyte |tr -d '\n')
    log_line="${date_str} ${byte_str} MB"
    if [ ! -e ${LOG_FILE} ]; then                               # ログファイルがなければ、ファイルを作成
        echo "DATE           traffic" >> ${LOG_FILE}
        echo "----------------------" >> ${LOG_FILE}
        echo "${log_line}" >> ${LOG_FILE}                       # ログデータの記入(これは必ず残る)
        echo "${log_line}" >> ${LOG_FILE}                       # ログデータの記入(これは消えるかも)
    fi
    last_bt_byte=$(tail -n1 ${LOG_FILE} | awk '{print $2}')     # ログの最終行から前回のデータ通信量を抽出
    if [ $(($(bt_mbyte))) -ge $((${last_bt_byte})) ]; then      # データ通信量が増加していたら、最終行を削除
        sed -i '' -e '$d' ${LOG_FILE}                           # BSD GREPなので上書きオプション-iに''が必須
    fi
    echo "${log_line}" >> ${LOG_FILE}                           # ログデータの記入
}

# コマンド引数処理
#############################################################################
CMDNAME=`basename $0`
while getopts hwWbBpnM OPT
do
    case $OPT in
        "h" ) FLG_H="TRUE" ;;
        "w" ) FLG_w="TRUE" ;;
        "W" ) FLG_W="TRUE" ;;
        "b" ) FLG_b="TRUE" ;;
        "B" ) FLG_B="TRUE" ;;
        "p" ) FLG_p="TRUE" ;;
        "n" ) FLG_n="TRUE" ;;
        "M" ) FLG_M="TRUE" ;;
        * ) echo "Usage: $CMDNAME [-hwWbBpnM]" 1>&2
                    exit 1 ;;
    esac
done

if [ "$FLG_H" = "TRUE" ]; then
    echo "Usage: $CMDNAME [-hwWbBpnM]" 1>&2
    echo "  no option : no wi-fi. connect to bluetooth tethering" 1>&2
    echo "  -h        : help" 1>&2
    echo "  -w        : check wifi is on                    (return 0:on 1:off)" 1>&2
    echo "  -W        : switch wifi on off                  (return 0:on 1:off)" 1>&2
    echo "  -b        : check bluetooth tethering is on     (return 0:on 1:off)" 1>&2
    echo "  -B        : switch bluetooth tethering on off   (return 0:on 1:off)" 1>&2
    echo "  -n        : ckeck network is on                 (return 0:on 1:off)" 1>&2
    echo "  -M        : ckeck bluetooth tethering MB" 1>&2
    exit 0
fi

if [ "$FLG_w" = "TRUE" ]; then
    wifi_is_on
    exit $?
fi
if [ "$FLG_W" = "TRUE" ]; then
    wifi_switch_onoff
    exit $?
fi
if [ "$FLG_b" = "TRUE" ]; then
    bt_is_on
    exit $?
fi
if [ "$FLG_B" = "TRUE" ]; then
    bt_switch_onoff
    exit $?
fi
if [ "$FLG_n" = "TRUE" ]; then
    network_is_on
    exit $?
fi
if [ "$FLG_M" = "TRUE" ]; then
    bt_mbyte
    exit 0
fi

# 以下、メイン
#############################################################################
# wifiの接続状況に応じてbluetoothテザリングを接続、切断
# それに応じて、bitbar のメニュー表示を変更
#############################################################################

# スリープ復帰後を考えて、ネットワークが安定するまでウエイト
sleep 5s

# 1回の通信が最大連続通信量を超えた時、bluetoothテザリングを強制切断
# 今後、bluetoothテザリングできないよう、フラグとなるファイルを作成
if (($(bt_mbyte)>${MAX_DATA})); then
    touch $ERR_FILE
fi
if [ -e $ERR_FILE ]; then
    bit_menu "[DATA OVER]| color=red"
    bt_is_on && bt_switch_onoff
    exit 1
fi

# wifiの接続状況に応じてbluetoothテザリングを接続、切断
# それに応じて、bitbar のメニュー表示を変更
if wifi_is_on; then                 # wifi is on
    bit_menu "[Tethering OFF]| color=blue"
    bt_is_on && bt_switch_onoff      # -bluetooth is on なら bluetoothの切断
else                                # wifi is off
    if bt_is_on; then               # -bluetooth is on
        bit_menu "[Tethering $(bt_mbyte)MB]| color=red"
        :                           # --何もしない
    else                            # -bluetooth is off
        if network_is_on; then      # --Eather is on
            bit_menu "[Tethering OFF]| color=blue"
            :                       # ---何もしない
        else                        # --Eather is off.
            if bt_switch_onoff; then # ---bluetoothの接続処理をして、その結果on
                bit_menu "[Tethering $(bt_mbyte)MB]| color=red"
            else                    # ---bluetoothの接続処理をして、その結果off
                bit_menu "[Tethering can't connect]| color=red"
            fi
        fi
    fi
fi
save_log                            # bluetooth通信量をログに書き込む
exit 0


 apple scriptでbluetooth接続するところは「Takayuki Yuasa」さんの 「【Mac】 Bluetoothテザリングの接続にショートカットキーを割当」を参考にしました。この部分はシェルスクリプトで実現できなかったので、とても感謝してます。
http://ytkyk.info/blog/2015/03/06/bluetooth_tethering_shortcut_key/

2
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1