みなさん、こんにちは。
Raspberry Pi 4B をヘッドレス運用していると、設置先のWi-Fi変更時に困ることがあります。
私の場合は、Flaskで作った管理画面からWi-Fi設定を書き換えられるようにしていたのですが、設定済みのアクセスポイントに接続できなくなると、当然ながら管理画面にアクセスできなくなってしまいます。
そこで、
- 通常はWi-Fiクライアントとして動作
- Wi-Fi接続に失敗した場合のみAPモードへ切り替え
- スマホで接続して再設定
という仕組みを Raspberry Pi OS で実装してみました。
なお、今回は wpa_supplicant を使用した方法です。
Raspberry Pi OS Bookworm 以降は、NetworkManager がデフォルトで使用されるようになっているため、そのままでは今回の方法は使えません。しかし、私は以前のプログラムとの互換性のために、Bookworm / Trixie でも wpa_supplicant を使用するように設定しています。詳しくは以下の記事も参考にしてみてください。
やりたかったこと
市販のIoT機器によくある、次のような動作の流れを実現したかったのです。
起動
↓
Wi-Fiへ接続
↓
失敗
↓
設定用SSIDを起動
↓
スマホで接続
↓
ネットワーク再設定
↓
再起動
私の環境では既にFlaskアプリが自動起動しており、ネットワーク設定画面も作成済みだったため、今回は「接続失敗時にAPモードへ切り替える機能」だけを追加することにしました。
動作環境
- Raspberry Pi OS Bullseye(Bookworm / Trixie では wpa_supplicant 化が必要)
- Flask管理画面
- DHCPは有効化(Wi-Fi接続成功時のため)
hostapddnsmasq- TP-Link Archer T3U
- ※Raspberry Pi内蔵Wi-Fiは通信安定化のために無効化しています
なお、使用する無線モジュールによってはAPモードに対応していない場合もあります。今回使用した T3U は AP モードに対応していました。
設定手順
それでは、必要な設定を順番に行っていきましょう!
まずは必要なパッケージをインストールします。
sudo apt install hostapd dnsmasq
自動起動は一旦無効化しておきます。
sudo systemctl disable hostapd
sudo systemctl disable dnsmasq
1. hostapdの設定
/etc/hostapd/hostapd.conf を作成します。
interface=wlan0
driver=nl80211
ssid=RaspberryPi-Setup # SSIDは任意のものに変更してください
hw_mode=g
channel=6
auth_algs=1
wpa=2
wpa_passphrase=PASSWORD # パスワードは任意のものに変更してください
wpa_key_mgmt=WPA-PSK
rsn_pairwise=CCMP
続いて、/etc/default/hostapd を作成し、設定ファイルの場所を指定します。
DAEMON_CONF="/etc/hostapd/hostapd.conf"
2. dnsmasqの設定
/etc/dnsmasq.conf を以下のように設定します。
interface=wlan0
bind-interfaces
dhcp-range=192.168.4.10,192.168.4.100,255.255.255.0,24h
bind-interfaces を追加することで、DHCP配布が安定するようになります。
3. AP起動スクリプト
/usr/local/bin/start-ap.sh を作成します。
#!/bin/bash
ip addr flush dev wlan0
ip addr add 192.168.4.1/24 dev wlan0
systemctl start dnsmasq
systemctl start hostapd
作成したら、実行権限を付与します。
sudo chmod +x /usr/local/bin/start-ap.sh
sudo /usr/local/bin/start-ap.sh を実行すると、APモードが起動し、設定したSSIDとパスワードを使ってスマホからRaspberry Piに接続できるようになります。
4. Wi-Fi接続チェック
続いて、起動時にWi-Fiの接続状態を確認するスクリプトを /usr/local/bin/check-wifi.sh として作成します。
#!/bin/bash
sleep 60
if wpa_cli -i wlan0 status | grep -q "wpa_state=COMPLETED"
then
exit 0
fi
/usr/local/bin/start-ap.sh
こちらも実行権限を付与します。
sudo chmod +x /usr/local/bin/check-wifi.sh
5. systemdサービス
Wi-Fi接続チェックを自動起動するために、systemdサービスを作成します。/etc/systemd/system/wifi-fallback.service ファイルを作成してください。
[Unit]
Description=WiFi Fallback Access Point
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/check-wifi.sh
[Install]
WantedBy=multi-user.target
作成後はサービスを有効化します。
sudo systemctl daemon-reload
sudo systemctl enable wifi-fallback.service
以上で設定は完了です!
ハマったポイント
実際に構築する中で、いくつか躓いたポイントがありました。
- hostapdが起動しない
- 状態を確認すると、Plaintext
hostapd.service Loaded: maskedとなっていたため、以下のコマンドでマスクを解除する必要がありました。sudo systemctl unmask hostapd
- 状態を確認すると、Plaintext
- APが見えない
- 最初は起動スクリプトの問題だと思っていましたが、実際には
sleep 60が非常に重要でした。無線LANアダプタの初期化やWi-Fi接続に予想以上の時間がかかり、当初設定した30秒では接続途中になってしまうことがありました。60秒待つことで正常に判定できるようになりました。
- 最初は起動スクリプトの問題だと思っていましたが、実際には
- 169.254.x.x のIPアドレスになる
- DHCPが有効なので
169.254.xxx.xxxが割り当てられていましたが、これはDHCPが正常に動作しないときによく現れるリンクローカルアドレスです。結果的には、bind-interfacesを追加した dnsmasq の設定で無事に解決しました。
- DHCPが有効なので
Flaskとの連携
私の管理画面では、設定保存後に再起動する設計にしています。Pythonで次のように書くだけです。
os.system("reboot")
再接続処理やAP停止処理はあえて行っていません。起動時に自動で
- Wi-Fi成功 → AP起動しない
- Wi-Fi失敗 → AP起動
と判定してくれるためです。
完成した動作
最終的な動きの流れは次のようになりました。
起動
↓
60秒待機
↓
Wi-Fi接続成功?
│
├─ Yes
│ ↓
│ 通常運用
│
└─ No
↓
AP起動スクリプト実行
↓
スマホ接続(もちろんPCでも構いません)
↓
Flask設定画面
↓
新しいWi-Fi設定保存
↓
再起動
↓
新Wi-Fiへ接続
これでディスプレイもキーボードも不要になり、設置先でWi-Fi環境が変わってもスマホだけで再設定できるようになりました。IoT機器らしい使い勝手になったので、ヘッドレス運用の Raspberry Pi を作る場合にはとてもおすすめの構成です。
時間ができたら NetworkManager版 も作ってみたいと思います。
本日も最後までお読みいただきありがとうございました。
それでは、よいRaspberry Piライフを!
「Raspberry Piで試作はできた。でも、これを24時間365日動かし続けられるのか?」——多くのプロジェクトがつまずくのは、実はここからです。
ビューローみかみでは、構想段階の壁打ちからPoC・実装・現場導入まで、現場で「使い続けられる」ものづくりを支援しています。
シングルボードコンピューターを用いた試作から、現場で実際に動き続けている運用ノウハウまで。「動くもの」を「動き続けるもの」にするお手伝いをします。
▶ Raspberry Pi受託開発サービスの詳細はこちら
気になることがあればお気軽にご相談ください。



