[ESP32]ArduinoIDEから遠隔でシステム更新する方法(BasicOTA) with Arduino IDE

ESP32

遠隔でシステム更新する方法 with Arduino IDE

はじめに

ESP32のシステムを更新する場合、PCとESP32をmicroUSBで接続してシリアル接続を使用するのが一般的ですが、遠隔でシステム更新するための機能も備わっています。

OTAとは

The OTA update mechanism allows a device to update itself based on data received while the normal firmware is running (for example, over Wi-Fi or Bluetooth.)

https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/ota.html#ota-process-overview

プログラミングガイドによると、「OTA アップデート メカニズムを使用すると、通常のファームウェアの実行中に (Wi-Fi や Bluetooth 経由などで) 受信したデータに基づいてデバイス自体をアップデートできます。」とあり、Wi-Fi や Bluetooth 経由でシステム更新できるようです。

本記事では、Wifi接続でのシステム更新について取り上げています。
また、今回はArduino IDE から更新する方法です。HTMLサーバを立ててビルドしたファイルをアップロードする方法はこちら。

開発環境

OS : Windows 11 Pro
ESP32:ESP-WROOM-32
統合開発環境 : Arduino IDE 2.1.0
使用ライブラリ:なし

作業内容

使用関数の把握

コールバック関数

ArduinoOTA.onStart([]() {})
アップデートが開始した時に呼ばれる処理を記述します。

ArduinoOTA.onEnd([]() {})
アップデートが終了した時に呼ばれる処理を記述します。

ArduinoOTA.onProgress([]() {})
アップデート中に呼ばれる処理を記述します。
分割された1パケットの受信と書き込みが完了するたびに呼ばれます。

ArduinoOTA.onError([]() {})
アップデートでエラーが発生した時に呼ばれる処理を記述します。

ArduinoOTA.setPassword()
アップデートする時のパスワード設定。

引数説明
const char * passwordアップデート時に要求するパスワード。
初期値は「admin」。
戻り値ArduinoOTAClassのインスタンス。

ArduinoOTA.handle()
アップデートを待ち受ける処理。loop()内などの定期的に呼ばれる場所に記述します。

スケッチ作成

「SampleOTA」というフォルダを作り、「SampleOTA.ino」というファイルを作成して、下記スケッチを作成しています。

配置例

「C:\Users\xxxxx\OneDrive\ドキュメント\Arduino\SampleOTA」

<<SampleOTA.ino>>

#include <ArduinoOTA.h>

const char* ssid = "xxxxxxxx";
const char* password = "xxxxxxxx";

void setup() {
  Serial.begin(115200);
  Serial.println("Booting");
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("Connection Failed! Rebooting...");
    delay(5000);
    ESP.restart();
  }

  // Port defaults to 3232
  // ArduinoOTA.setPort(3232);

  // Hostname defaults to esp3232-[MAC]
  // ArduinoOTA.setHostname("myesp32");

  // No authentication by default
  ArduinoOTA.setPassword("admin");

  // Password can be set with it's md5 value as well
  // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
  // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");

  ArduinoOTA
    .onStart([]() {
      String type;
      if (ArduinoOTA.getCommand() == U_FLASH)
        type = "sketch";
      else // U_SPIFFS
        type = "filesystem";

      // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
      Serial.println("Start updating " + type);
    })
    .onEnd([]() {
      Serial.println("\nEnd");
    })
    .onProgress([](unsigned int progress, unsigned int total) {
      Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
    })
    .onError([](ota_error_t error) {
      Serial.printf("Error[%u]: ", error);
      if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
      else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
      else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
      else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
      else if (error == OTA_END_ERROR) Serial.println("End Failed");
    });

  ArduinoOTA.begin();

  Serial.println("Ready");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  ArduinoOTA.handle();
}

3行目と4行目の[ssid]と[password]の内容はご自身の環境に変更してください。

const char* ssid = "xxxxxxxx";
const char* password = "xxxxxxxx";

動作確認

起動してWifi接続に成功すると、Readyと表示され取得したIPアドレスが表示されます。

そして、「ツール」→「ポート」に今回のIPアドレスが表示されていれば、Arduino IDE で認識成功です。シリアルポートから変更することで、書込みできるようになります。

61行目に次のコードを追加してアップデートしてみましょう。

Serial.print("遠隔でシステム更新成功(OTA)");

上記を追加して普段通りにビルド書き込みしてみます。

Password の入力が求められました。ArduinoOTA.setPassword()で登録したパスワード「admin」を入力して実行します。

シリアルモニタに先ほど追加したコードが反映されていれば成功です。
(ポート設定をシリアルポートに戻さないとシリアルモニタには出力されないので注意です。)

おわりに

既に設置したESP32に対して遠隔でシステム更新できると便利ですね。プログラムのアップデートする時にESP32を取りに行く手間が省けます。

ただし、プログラムミスによって起動後すぐにリセットがかかるような場合はこれでは対応できません。そのような場合に備えてアプリのロールバック機能(CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLEオプション)もありますが、初期設定ではOFFになっています。Arduino IDE では、この機能をONにするのは少し手間がかかるため別記事にて取り上げたいと思います。

コメント

タイトルとURLをコピーしました