. はじめに
はじめに
はじめに

はじめに

OTAWebUpdater はじめに

Webを使ったOTAアップデート(Over The Air: この場合無線でスケッチを書き込むこと)の使い方です。

動作確認は、ESP32 2.0.2のときのものです。

プログラム

定義等

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 #include <WiFi.h> #include <WiFiClient.h> #include <WebServer.h> #include <ESPmDNS.h> #include <Update.h> const char* host = "esp32"; const char* ssid = "xxx"; const char* password = "xxxx"; WebServer server(80); /* * Login page */ const char* loginIndex = "<form name='loginForm'>" "<table width='20%' bgcolor='A09F9F' align='center'>" "<tr>" "<td colspan=2>" "<center><font size=4><b>ESP32 Login Page</b></font></center>" "<br>" "</td>" "<br>" "<br>" "</tr>" "<tr>" "<td>Username:</td>" "<td><input type='text' size=25 name='userid'><br></td>" "</tr>" "<br>" "<br>" "<tr>" "<td>Password:</td>" "<td><input type='Password' size=25 name='pwd'><br></td>" "<br>" "<br>" "</tr>" "<tr>" "<td><input type='submit' value='Login'></td>" "</tr>" "</table>" "</form>" "<script>" "function check(form)" "{" "if(form.userid.value=='admin' && form.pwd.value=='admin')" "{" "window.open('/serverIndex')" "}" "else" "{" " alert('Error Password or Username')/*displays error message*/" "}" "}" "</script>"; /* * Server Index Page */ const char* serverIndex = "<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>" "<form method='POST' action='#' enctype='multipart/form-data' id='upload_form'>" "<input type='file' name='update'>" "<input type='submit' value='Update'>" "</form>" "<div id='prg'>progress: 0%</div>" "<script>" "$('form').submit(function(e){" "e.preventDefault();" "var form = $('#upload_form')[0];" "var data = new FormData(form);" " $.ajax({" "url: '/update'," "type: 'POST'," "data: data," "contentType: false," "processData:false," "xhr: function() {" "var xhr = new window.XMLHttpRequest();" "xhr.upload.addEventListener('progress', function(evt) {" "if (evt.lengthComputable) {" "var per = evt.loaded / evt.total;" "$('#prg').html('progress: ' + Math.round(per*100) + '%');" "}" "}, false);" "return xhr;" "}," "success:function(d, s) {" "console.log('success!')" "}," "error: function (a, b, c) {" "}" "});" "});" "</script>";

hostは、mDNSで登録するESP32のホスト名です。

ssidとpasswordは、WiFiアクセス用のSSID/パスフレーズです。

WebServer::WebServer()型の変数serverを定義します。ポート番号80で待ち受けます。

loginIndexはログインページで表示するHTMLデータ/JavaScriptプログラム、serverIndexはファイルを選択、送信する際のHTMLデータ/JavaScriptプログラムです。

setup()

100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 /* * setup function */ void setup(void) { Serial.begin(115200); // Connect to WiFi network WiFi.begin(ssid, password); Serial.println(""); // Wait for connection while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.print("Connected to "); Serial.println(ssid); Serial.print("IP address: "); Serial.println(WiFi.localIP()); /*use mdns for host name resolution*/ if (!MDNS.begin(host)) { //http://esp32.local Serial.println("Error setting up MDNS responder!"); while (1) { delay(1000); } } Serial.println("mDNS responder started"); /*return index page which is stored in serverIndex */ server.on("/", HTTP_GET, []() { server.sendHeader("Connection", "close"); server.send(200, "text/html", loginIndex); }); server.on("/serverIndex", HTTP_GET, []() { server.sendHeader("Connection", "close"); server.send(200, "text/html", serverIndex); }); /*handling uploading firmware file */ server.on("/update", HTTP_POST, []() { server.sendHeader("Connection", "close"); server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK"); ESP.restart(); }, []() { HTTPUpload& upload = server.upload(); if (upload.status == UPLOAD_FILE_START) { Serial.printf("Update: %s\n", upload.filename.c_str()); if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { //start with max available size Update.printError(Serial); } } else if (upload.status == UPLOAD_FILE_WRITE) { /* flashing firmware to ESP*/ if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) { Update.printError(Serial); } } else if (upload.status == UPLOAD_FILE_END) { if (Update.end(true)) { //true to set the size to the current progress Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize); } else { Update.printError(Serial); } } }); server.begin(); }

107行目から114行目はWiFiアクセスポイントへの接続です。

WiFi.begin()でアクセスポイントに接続します。WiFi.status()は、現在の接続状態を返却します。アクセスポイントに接続しているときは、WL_CONNECTEDが返ってきます。

MDNS.begin()で、mDNSにホスト名を登録します。

130行目から162行目はHTTPアクセス時のハンドラ定義です。server.on()で、指定したURIにアクセスがあった時に呼び出す関数を登録します。server.sendHeader()でHTTPヘッダを追加し、server.send()で、実際にレスポンスを返します。

130行目は、/にアクセスがあった場合に呼び出される関数として、loginIndex()を登録します。この関数は、ログインページを表示します。下記に、画面を示します。

mDNSの機能を利用しているので、IPアドレス指定ではなく、http://esp32.local/ という指定でESP32にアクセスすることができています。

loginIndexで設定したHTML/JavaScriptプログラムでは、Username、Passwordともadminを入力することで、/serverIndexに遷移することになっています。ただし、セッション等は利用していないので、/serverIndexに直接アクセスすれば、ログインページをスキップできてしまいますが…

134行目は、ログイン後に表示する/serverIndexを登録しています。この関数は、アップロードするプログラムの選択と、アップロード状態を示すページです。以下に、画面を示します。

このページに遷移直後は、ファイルは選択されておらず、ファイルの送信の進捗率も0%です。

139行目から162行目は、/updateに対するPOSTメソッドの定義を行っています。これは、serverIndexのページで、Updateボタンを押したときに呼び出されます。

第3引数の関数(138行目から141行目)はPOSTメソッドでリクエストボディが送信された後に呼び出される関数です。Update.hasError()で、更新にエラーがあるかどうかを判定しエラーがある場合はFAIL、ない場合は、OKをクライアントに返却します。その後、ESP.restart()でESP32を再起動します。

第4引数の関数は、リクエストボディを受信中に実行する関数です。

server.upload()により、リクエストボディ受信中の状態を取得します。

状態が、UPLOAD_FILE_STARTの場合は、Update.begin()により、スケッチの更新を開始します。更新の開始に失敗したときは、Update.printError()により、エラー情報を出力します。

状態が、UPLOAD_FILE_WRITEの場合は、Update.write()を使い、スケッチを書き込みます。

状態が、UPLOAD_FILE_ENDの場合は、Update.end()で、スケッチの更新を終了します。

スケッチの更新中は、以下のように更新状況を表示します(これは、ESP32側の処理ではなく、ブラウザ側の処理です)。

更新が完了すると、progressが100%になって終了します。

最後に、server.begin()で、ウェブサーバを開始します。

loop()

166 167 168 169 void loop(void) { server.handleClient(); delay(1); }

server.handleClient()で、HTTPリクエストを処理します。

バージョン Hardware:ESP-WROOM-32Software:Arduino core for the ESP32 2.0.4 最終更新日

September 4, 2022

📎📎📎📎📎📎📎📎📎📎