特定APの起動をトリガーに、ラズパイの無線接続先を自動切替
近いAPへ自動接続してほしい
自宅の中でRaspberry Pi Zero WH (以下ラズパイZero) の稼働を開始している。無線接続は次のような状態にしていて、
- 自宅LANの中で2つの無線アクセスポイントAP-MainとAP-Subを運用していて、どちらのAPも共通のSSID
MY_HOUSE_AP
で運用している - 24時間起動のラズパイZeroを、SSID
MY_HOUSE_AP
に無線接続している - AP-SubはラズパイZeroに近接しているが、省エネのために、部屋内の人間が必要なときだけAP-Subの電源をON/OFFしている
- AP-Subが起動していない時は、多少の通信ロスは許容するので、ラズパイZeroは遠くのAP-Mainに自動的に接続していてほしい
- AP-Subが起動している時は、通信ロスを極力抑えるため、ラズパイZeroはすばやく自動的に、無線接続をAP-Mainから近接のAP-Subへ切り替えてほしい
箇条書きした各要素を、AP別に表にまとめるとこうなる。
AP-Main | AP-Sub | |
---|---|---|
SSID | MY_HOUSE_AP | MY_HOUSE_AP |
稼働時間 | 24時間連続 | 不定期に電源ON/OFF |
ラズパイZeroとの距離 | 遠い | 近接 |
接続優先度の希望 | Low | High |
上記の状態のうち、4はAP-Subへ接続できないことからフォールバック的に自動的に行われるのだが、5は、ラズパイZeroがAP-Mainに接続を維持できている間は起こらないように思う。そこで5を実現するため、AP-Subの起動を検出したらラズパイZeroの無線を再接続させる仕掛けを作ってみた。
ラズパイZeroなどのIoTデバイスを無線接続で利用する上で、圏内の無線アクセスポイントを全台かならずしも常時電源ONにはしていない、という場合のひと工夫として、ご紹介です。
無線を再接続させるスクリプト
内容・ロジック
仕掛けは、ラズパイZeroで実行するbashスクリプトの形で、reconnect_wlan.sh
と名付けた。ソースコードは最後に掲載。Raspberry Pi OS (Raspbian GNU/Linux 10 (buster)) で動作確認を行っている。
スクリプトのロジックは次のとおり。無線の再接続の後は自動的に、電波強度の強い (= 近い) ほうの無線アクセスポイントにラズパイZeroが繋がることを暗に期待している。
- AP-Mainには接続しているはずのラズパイZeroから、AP-Sub (固定IPアドレスを想定) へのping疎通を確認できたら、AP-Subが起動していると見なす
- さらに現時点の接続先APがAP-Subではない場合に、
wpa_cli
のreconfigureを実行して、無線の再接続を行わせる
使い方
スクリプトreconnect_wlan.sh
をchmod +x
した後、root権限で定期的にcron実行しておく。
*/1 * * * * timeout 55s /home/foo/reconnect_wlan.sh >/dev/null 2>&1
スクリプトが想定通りに動作し、AP-Subの起動を検知して無線の再接続が行われる際には、/var/log/syslog
に次のようなログが記録される。ここでは、「D8:07:B6:XX:XX:XX」はAP-Subの、「6C:E4:DA:YY:YY:YY」はAP-MainのMACアドレスである。
Mar 3 23:19:01 raspi0 reconnect_wlan.sh[32492]: wlan1: target = D8:07:B6:XX:XX:XX, now = 6C:E4:DA:YY:YY:YY
Mar 3 23:19:01 raspi0 reconnect_wlan.sh[32492]: wlan1: trying to reconnect...
Mar 3 23:19:32 raspi0 reconnect_wlan.sh[32492]: wlan1: target = D8:07:B6:XX:XX:XX, now = D8:07:B6:XX:XX:XX
P.S. iwlist wlanN scanning
今回の、pingを用いるreconnect_wlan.sh
スクリプトを書き終えて満足した後に、近接のAP-Subの電波が飛んでいるかどうかを、定期的に $ sudo iwlist wlanN scanning
で調べてみるという方法もアリと気づいた。ああ、このほうが電波強度も参考情報として取り入れられるしスマートな気がする。orz
TP-Link WiFi 無線LAN 子機 AC600 433Mbps + 200Mbps Windows/Mac OS 対応 ナノ設計 デュアルバンド 3年保証 Archer T2U Nano
TP-Link
Raspberry Pi Zero W - ヘッダー ハンダ付け済み - ラズベリー・パイ ゼロ W ワイヤレス
Raspberry Pi
ソースコード
reconnect_wlan.sh
#!/bin/bash
# reconnect_wlan.sh (ver.20210303) for root@raspi0
TARGET_AP='MY_HOUSE_AP' # Name of Access Points
TARGET_IPADDRESS='192.168.1.NNN' # Nearest AP's IP address
TARGET_MAC='D8:07:B6:XX:XX:XX' # Nearest AP's MAC address
TARGET_NIC=`basename /run/wpa_supplicant/*`
CMD_LOGGER="logger -p user.info -t `basename $0`[$$]"
CMD_ACTION="sudo /usr/sbin/wpa_cli -i ${TARGET_NIC} reconfigure"
function get_mac() {
local TMP_MAC=`/usr/sbin/iwconfig ${TARGET_NIC} 2>/dev/null | grep -A1 "${TARGET_AP}" | grep "Access Point:" | awk '{print $6}'`
echo ${TMP_MAC}
}
function make_log_msg() {
local TMP_MSG="${TARGET_NIC}: target = ${TARGET_MAC}, now = ${NOW_MAC}"
echo ${TMP_MSG}
}
ping ${TARGET_IPADDRESS} -c 1 >/dev/null
if [ $? == 0 ]; then
# Nearest AP is online
NOW_MAC=`get_mac`
if [ ${NOW_MAC} != ${TARGET_MAC} ]; then
# reconnect
LOG_MSG=`make_log_msg`; ${CMD_LOGGER} "${LOG_MSG}"
LOG_MSG="${TARGET_NIC}: trying to reconnect..."; ${CMD_LOGGER} "${LOG_MSG}"
sleep 10
${CMD_ACTION}
sleep 20
NOW_MAC=`get_mac`
LOG_MSG=`make_log_msg`; ${CMD_LOGGER} "${LOG_MSG}"
fi
fi