ESP8266のSmartConfigのサンプルをそのままESP32で動かすと、上手く動作しません。簡単に言うと、一度SmartConfigでSSID/パスワードを設定しても覚えてくれませんので、毎回設定しなければなりません。
で、調べてみると、ESP32ではこちらの記事のように設定を記憶する不揮発領域の処理は別処理になっているようです。参考にさせていただいて、忘れないようにしてみます。
その機能は Preferneces.h に含まれているようで、そのサンプルソースを見てみると、
- preferences.begin()でアプリケーションのnamespaceを指定して開始
- preferences.clear()で領域をクリア
- preferences.remove(“counter”)で指定したキーの値を削除
- preferences.getUInt(“counter”, 0)の指定したキーの値を取得、キーがなければデフォルト値として2番目のパラメータ(0)が返る
- preferences.putUInt(“counter”, counter)で指定したキーの値を書き込み
- preferences.end()でbegin()で開始したものを終了
ということみたいです。上記はIntを対象にしていますが、ヘッダファイルをみるといろんな型に対応しているようです。
そこで、WiFiのセットアップ部分を以下のようにしてみました。
void setup_wifi() { uint8_t cnt0 = 0, cnt1 = 0; Preferences pref; #define WIFILEN 32 char ssid[WIFILEN]="none",pass[WIFILEN]="none"; delay(10); // We start by connecting to a WiFi network Serial.println(); // delay for 2 sec for smartConfig pinMode(0, INPUT_PULLUP); // configure pin0 Serial.println("2 sec before clear SavedConfig"); blinkBuiltinLed(250,4); // LED点滅させながら2秒待つ // read pullup pref.begin("wifi",false); bool isSmartConfig = !digitalRead(0); if (isSmartConfig == true) { Serial.println("clear config"); blinkBuiltinLed(50,40); pref.clear(); } else { pref.getString("ssid",ssid,WIFILEN); pref.getString("pass",pass,WIFILEN); } pref.end(); // WiFi接続を試行して失敗したら SmartConfig を開始 WiFi.mode(WIFI_STA); WiFi.begin(ssid,pass); while(WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); if(cnt0++ >= 15 || isSmartConfig == true ){ // 接続できなかった場合 または GPIO0が押下されていた場合 Serial.println(); Serial.println("Begin SmartConfig"); WiFi.mode(WIFI_AP); WiFi.beginSmartConfig(); while(1){ delay(500); turnBuiltinLed(); if(cnt1++ >= 40 && isSmartConfig == false){ esp_restart(); // 自動で入り込んだ場合で20秒以内にコンフィグ成功しない場合はソフトウェアリセットをかける } if(WiFi.smartConfigDone()){ Serial.println("SmartConfig Success"); blinkBuiltinLed(100,20); // ここで不揮発性メモリへの書き込み… pref.begin("wifi", false); pref.putString("ssid", WiFi.SSID()); pref.putString("pass", WiFi.psk()); pref.end(); WiFi.mode(WIFI_STA); WiFi.begin(); break; } } } } randomSeed(micros()); Serial.println(""); Serial.println("WiFi connected"); Serial.print("IP address: "); Serial.println(WiFi.localIP()); // time set with NTP configTime( JST, 0, "ntp.nict.jp", "ntp.jst.mfeed.ad.jp"); }
“wifi”というnamespaceに設定を保存しますが、セットアップ時にGPIO0に対応するボタンをが押されていた場合には領域をクリアし、押されていなかった場合にはSSID/パスワードを読み出します。その情報でWiFiの接続を試行して、8秒以内に接続できない場合もしくは領域をクリアした場合にはSmartConfigを試みます。SmartConfigが20秒以内に完了しない場合にはソフトウェアリセットをかけます。これは、電源投入時にWiFiのアクセスポイントがたまたま起動途中で無線を停止していたなどの場合にSmartConfigで無限ループに入るのを防止するためです。SmartConfigが成功したら、SSIDとパスワードを不揮発領域に保存します。
同様に、MQTTの接続の部分にも失敗時に再接続を試みるループがありますので、ここも同様に3回失敗したらソフトウェアリセットをかけて再起動させます。
void reconnect() { uint8_t cnt = 0; while (!client.connected()) { Serial.print("Attempting MQTT connection..."); String clientId = "ESP32Client-"; clientId += String(random(0xffff), HEX); if (client.connect(clientId.c_str(),mqtt_user,mqtt_pass)) { Serial.println("connected"); client.subscribe(InTopic); } else { Serial.print("failed, rc="); Serial.println(client.state()); // 改行追加 char buf[256]; // SSLエラー表示のためのバッファ確保 espClient.lastError(buf,256); // エラーメッセージ取得 Serial.print("SSL error: "); // エラーメッセージ表示 Serial.println(buf); // Serial.println(" try again in 5 seconds"); // Wait 5 seconds before retrying delay(5000); cnt++; if(cnt >= 3){ esp_restart(); // 3回失敗したらソフトウェアリセットをかける } } } }
これでSmartConfigが実用的に使えるようになりました。