ESP32でSmartConfig

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が実用的に使えるようになりました。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)