はじめに
皆さんはMiroPythonをインストールしたRaspberryPi Pico WやESP32等のマイクロコントローラをWi-Fiに接続して使用するようなシーンにおいて接続したいWi-FiのSSIDやパスワードをソースコードに直書きせず、なんらかの手法で後から自由に変更できるような形で設定したいと思ったことはないでしょうか?私はあります。
アクセスポイントモードで起動したデバイスにスマホ等を接続し表示されたWEBページからSSIDやパスワードを設定する、さらにWEBページのURL等を覚えていなくてもCaptivePortalとして勝手に設定ページが立ち上がる...そんな機能を実装したので紹介します。
この記事で触れないこと
RaspberryPi PicoやESP32等へのMicroPythonのインストール、Thonny等の開発環境構築・操作等に関しては触れません。
wifi-setupライブラリ
概要
前述のとおりMicroPythonにてCaptivePortalを実装し、表示されるページ上でMicroPythonデバイスが接続してほしいWi-FiのSSIDやパスワードを設定できるものです。
※MicroPythonでのCaptivePortal実装にはmicropython-captiveportalを大いに参考にしました
※RaspberryPi Pico W & MicroPython v1.23.0で動作確認しています
リポジトリはこちら:
ライブラリのインストール
リポジトリ上のwifi_setup
フォルダ一式をMicroPythonデバイスのlib
フォルダ内にコピーします。
root
└─lib
└─wifi_setup
├─wifi_setup.py
├─__init__.py
│
└─web
├─error.html
├─index.html
├─style.css
└─success.html
サンプルコードのコピー
起動時に処理されるboot.py
とその処理完了後に実行されるmain.py
のサンプルをリポジトリ上のsample
フォルダ内からコピーします。
※RaspberryPi Pico Wでの利用を想定したサンプルコードとしています
boot.py
ではボタン(RaspberryPiのBOOTSELボタン)が押下されている場合にWi-Fiの設定を削除するサンプルとなっています。
boot.py サンプルコード
import time
from wifi_setup import WifiConfig
# Sample of deleting settings when some button is pressed at boot.
# For RaspberryPi Pico W
if WifiConfig().check():
time.sleep_ms(3000)
if rp2.bootsel_button() == 1:
WifiConfig().delete()
main.py
ではWi-Fiが未設定の場合はWi-Fi設定用のポータルを起動、設定済みの場合は設定情報に基づいてWi-Fiへの接続とメインルーチンを実行するサンプルとしています。
main.py サンプルコード
import time
from network import (
WLAN,
STA_IF,
STAT_GOT_IP,
STAT_NO_AP_FOUND,
STAT_CONNECT_FAIL,
STAT_WRONG_PASSWORD,
)
from machine import reset
from wifi_setup import WifiConfig, WifiSetupPortal
class IoTDevice:
def execute(self) -> None:
try:
if not WifiConfig().check():
print("start wifi setup portal")
WifiSetupPortal().execute()
else:
print("start iot device")
if not self._connect_wifi():
raise Exception("cannot connect wifi")
self._main_routine()
except Exception as e:
print(f"{e=}")
time.sleep(1)
reset()
def _connect_wifi(self) -> bool:
ssid: str
key: str
ssid, key = WifiConfig().get()
wlan: WLAN = WLAN(STA_IF)
wlan.active(True)
wlan.connect(ssid, key)
while True:
time.sleep(1)
status: int = wlan.status()
if status == STAT_NO_AP_FOUND or status == STAT_CONNECT_FAIL:
break
elif status == STAT_WRONG_PASSWORD:
print("cannot connect wifi because incorrect password so wifi_config reset")
WifiConfig().delete()
reset()
break
elif status == STAT_GOT_IP:
return True
return False
def _main_routine(self) -> None:
# Your main routine here
print("main routine")
if __name__ == "__main__":
IoTDevice().execute()
スマホからのWi-Fi設定
- サンプルを実行するとMicroPythonデバイスが無線アクセスポイントモード(デフォルトではSSID:
IoTDeviceSetUp
のセキュリティ無し)で起動します - スマホ等を使用し無線アクセスポイントモードで起動してきたMicroPythonデバイスのSSIDに接続します
- CaptivePortalとして実装しているので(Androidでは)「Wi-Fiネットワークにログイン」の通知及びWi-Fi設定画面へ自動遷移します
- 表示された
Wi-Fi設定画面
にてMicroPythonデバイスが接続してほしいWi-FiのSSID
及びPassword
を入力し、Submit
します - リクエストに成功するとMicroPythonデバイスが再起動し
boot.py
やmain.py
が再度実行され、サンプルコードではWi-Fi設定済み時の処理(無線APへの接続やメインルーチンの実行)が行われます
補足
無線アクセスポイントモード時のSSIDやパスワードのカスタマイズ
MicroPythonデバイスにWi-Fi設定を行う時の無線アクセスポイントのSSID
やパスワード
、設定ページのドメイン
はWifiSetupPortal
クラスのインスタンス生成時に指定できます。
WifiSetupPortal(
ssid="SetUpSSID",
key="SetUpPassword",
domain="setup.local"
)
Wi-Fi設定情報へのアクセス
Wi-Fiの設定情報はMicroPythonデバイスのroot直下にwifi_config.json
として保存され直接のアクセスも可能ですが、WifiConfig
クラスから操作できます。
-
WifiConfig().get()
:設定されたSSID
とパスワード
をタプルで返します -
WifiConfig().check()
:設定ファイルの存在確認と設定情報を正しく読み込み可能か確認し結果をboolで返します -
WifiConfig().save()
:与えられたSSID
とパスワード
を設定ファイルに保存します -
WifiConfig().delete()
:設定ファイルを削除します
最後に
CaptivePortalをWi-Fiを使用しようとする者の認証以外の用途で使用してもいいものか?は悩みましたが、スマホ等で設定画面に自動で遷移するという利便性・魅力の前に考えることをやめて実装しました。
個人の趣味としての電子工作等の用途であればWi-Fi設定のためにアプリ等を必要とせず、自動で画面遷移するためMicroPythonデバイスのIPアドレスやURL等を覚えておく必要がないため便利なんじゃないかなと思います。