OTA - Over the air update of the firmware 即 空中固件更新。這是樂(lè)鑫SDK中極為之Cool的功能!
平時(shí)做Arduino 或者 ESP8266的開(kāi)發(fā)都要很苦逼地用USB插著板子枝冀,如果用ESP-01的話(huà)還得接FDTI232的轉(zhuǎn)換板,我是不知道是我的機(jī)器有問(wèn)題還是驅(qū)動(dòng)程序的問(wèn)題塞颁,經(jīng)常在iMac上插拔轉(zhuǎn)接線(xiàn)的話(huà)連接ESP8266的串口就會(huì)丟失过咬,不重新啟動(dòng)機(jī)器是沒(méi)有辦法再更新ESP8266的固件大渤,總之我很討厭那根USB的數(shù)據(jù)線(xiàn),無(wú)線(xiàn)總比有線(xiàn)的好掸绞!
上面這種只是在實(shí)驗(yàn)室環(huán)境下的情況泵三,還有另一種最實(shí)際的應(yīng)用:當(dāng)我們的將實(shí)驗(yàn)環(huán)境中的ESP8266做成產(chǎn)品并交付到客戶(hù)手上之時(shí)應(yīng)該如何來(lái)更新產(chǎn)品中的ESP8266的固件呢?難到要用戶(hù)拿到服務(wù)中心來(lái)更新衔掸?如果是這樣那這個(gè)產(chǎn)品一是失敗之作烫幕,而且也一定做不下去的,至少我們現(xiàn)在還沒(méi)有遇到過(guò)這么坑爹的產(chǎn)品吧敞映。這個(gè)時(shí)候OTA所能發(fā)揮的作用就非常大了较曼,通過(guò)無(wú)線(xiàn)網(wǎng)絡(luò)對(duì)固件進(jìn)行重新的分發(fā)與更新是WIFI智能產(chǎn)品的一個(gè)最基本也是最重要的功能。
如果使用NodeMCU Lua 的話(huà)是沒(méi)有這個(gè)功能的驱显,NodeMCU的GitHub上這個(gè)問(wèn)題被放在ISSUSE中很久了诗芜,至今還沒(méi)有辦法解決。但我曾找過(guò)一些相關(guān)的文獻(xiàn)資料但也并不是很完美: ESP8266 OTA LUA with WEB UI MANAGEMENT / Nodemcu firmware
但如果你是用Arduino Core For ESP8266 的話(huà)這就是小菜一碟了埃疫。首先我們得先從理論入手伏恐,了解一下OTA的本質(zhì)是什么它又是怎么樣工作的。我們都知道栓霜,當(dāng)使用串口線(xiàn)來(lái)更新ESP8266固件時(shí)是通過(guò)ESP8266中的SerialBootLoader來(lái)的進(jìn)行引導(dǎo)與寫(xiě)入的翠桦,這是一種默認(rèn)方式。OTA則是“繞過(guò)”了SerialBootLoader而通過(guò)WIFI向ESP8266中的"WIFI Boot Loader"進(jìn)行通信胳蛮,由WIFI Boot Loader 來(lái)引導(dǎo)無(wú)線(xiàn)固件寫(xiě)入更新销凑。當(dāng)然這個(gè)WIFI Boot Loader 就需要我們自已先通過(guò)串行線(xiàn)預(yù)先寫(xiě)入到的ESP8266中。換句話(huà)說(shuō)仅炊,我們得在代碼內(nèi)嵌入用于OTA的 WIFI Boot Loader 斗幼。
悻然,這個(gè)過(guò)程并不需要我們來(lái)寫(xiě)抚垄,因?yàn)锳rduino For ESP8266 已經(jīng)為我們配置一個(gè)系列極棒的示例代碼蜕窿,其中就有OTA的WIFI Boot Loader 代碼,只是它并不是叫這個(gè)名稱(chēng)而已呆馁。
好了理論很重要桐经,但不如實(shí)踐!我們直接動(dòng)手浙滤,先試試將ESP8266做成可以支持OTA阴挣。
打開(kāi)Arduino IDE 從示例菜單里面打開(kāi)一個(gè)叫"BasicOTA" 項(xiàng)(這個(gè)名稱(chēng)是不是很LOW)
具體代碼如下所示:
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
const char* ssid = "..........";
const char* password = "..........";
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 8266
// ArduinoOTA.setPort(8266);
// Hostname defaults to esp8266-[ChipID]
// ArduinoOTA.setHostname("myesp8266");
// No authentication by default
// ArduinoOTA.setPassword((const char *)"123");
ArduinoOTA.onStart([]() {
Serial.println("Start");
});
ArduinoOTA.onEnd([]() {
Serial.println("\nEnd");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
});
ArduinoOTA.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();
}
然后我們將SSPI和Password兩個(gè)變量設(shè)定為你現(xiàn)在所接連的WIFI名稱(chēng)與密碼:
const char* ssid = "你的WIFI連接名稱(chēng)";
const char* password = "你的WIFI密碼";
然后果決地寫(xiě)入到你的ESP8266中。寫(xiě)入成功后纺腊,打開(kāi)串口監(jiān)視器你會(huì)看到如下的內(nèi)容:
注意:
- 你一定要打開(kāi)串口監(jiān)視器畔咧,否則下一步的內(nèi)容你將會(huì)啥也看不到茎芭。
- 關(guān)閉Arduino IDE 然后重新打開(kāi)。
然后在工具菜單的端口項(xiàng)中你會(huì)發(fā)現(xiàn)多了一個(gè) "esp8266-xxxxx 192.168.1.130" 的菜單項(xiàng)盒卸,選中它
然后骗爆,想看一下效果的話(huà)將Setup函數(shù)中的打印信息改一下次氨,改成 "Read for OTA"蔽介,拔掉串口線(xiàn),用外部電源接上ESP8266并啟動(dòng)它煮寡,等上20來(lái)秒后虹蓄,在Arduino IDE上點(diǎn)擊上傳,盯著你的ESP8266看就會(huì)發(fā)現(xiàn)它的內(nèi)置LED在燒寫(xiě)時(shí)狂閃幸撕,一切就大功告成了薇组!
現(xiàn)在我們對(duì)上述的OTA代碼進(jìn)行一下分析就會(huì)發(fā)現(xiàn)它的實(shí)現(xiàn)邏輯其實(shí)非常的簡(jiǎn)單,主要是以下這么幾步:
- 連接WIFI
- 配置 ArduinoOTA 對(duì)象的事件函數(shù)
- 啟動(dòng) ArduinoOTA 服務(wù)
ArduinoOTA.begin()
- 在
loop()
函數(shù)將處理權(quán)交由ArduinoOTA.handle()
清楚這個(gè)代碼邏輯后坐儿,我們就可以按照實(shí)現(xiàn)的開(kāi)發(fā)需要對(duì)其進(jìn)行更改律胀。例如可以加入一個(gè)標(biāo)志位 flag
,用于標(biāo)識(shí)當(dāng)前運(yùn)行狀態(tài)
-
flag = 0
普通工作模式 -
flag = 1
刷機(jī)模式
然后通過(guò)硬件(按鈕)或者軟件(如MQTT或其它通信協(xié)議)方式來(lái)控制這個(gè)標(biāo)志位以控制ESP8266的運(yùn)行模式:
void loop() {
if (flag ==0 ) {
// 正常工作狀態(tài)的代碼
} else {
ArduinoOTA.handle();
}
}
這樣我們就可以隨時(shí)通過(guò)WIFI對(duì)ESP8266的固件進(jìn)行更新了貌矿。