ESP8266 OTA之服務(wù)器更新

我之前介紹了兩篇關(guān)于ESP8266的OTA更新方法:

說實(shí)話以上這兩種方案除有點(diǎn)好玩其實(shí)沒有什么實(shí)用性质欲,由其在開發(fā)產(chǎn)品時(shí)上述的兩種方案就是一種雞肋隔披,甚至可以說是不可用的饶氏。那現(xiàn)在市面上的各種智能設(shè)備是怎么更新固件的呢?

我使用過的絕大多數(shù)會(huì)進(jìn)行固件更新的IoT設(shè)備都是先在手機(jī)上提示有新的固件可以更新鬼雀,如果一確定以后就會(huì)自動(dòng)下載并進(jìn)行更新。那我們的ESP8266是否也能做到這樣的效果呢?

答案顯然是肯定的桨菜。本文所講述的OTA做法其實(shí)才是做產(chǎn)品的正道。

首先你要準(zhǔn)備一臺(tái)靜態(tài)文件服務(wù)器捉偏,并將某個(gè)目錄作為更新文件存儲(chǔ)倒得。當(dāng)然,如果你希望以后更方便地管理你發(fā)布的更新夭禽,那么你的更新文件就需要有良好的命名規(guī)則霞掺,關(guān)于這方面可以到百度上去搜一下找個(gè)命名規(guī)范或者按自己需要定義一套就OK了。

然后將自更新邏輯寫入固件:

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>
#define USE_SERIAL Serial

ESP8266WiFiMulti WiFiMulti;

void setup() {

    USE_SERIAL.begin(115200);
    // USE_SERIAL.setDebugOutput(true);

    USE_SERIAL.println();
    USE_SERIAL.println();
    USE_SERIAL.println();

    for(uint8_t t = 4; t > 0; t--) {
        USE_SERIAL.printf("[SETUP] WAIT %d...\n", t);
        USE_SERIAL.flush();
        delay(1000);
    }

    WiFi.mode(WIFI_STA);
    WiFiMulti.addAP("SSID", "PASSWORD");
}

void loop() {
    // wait for WiFi connection
    if((WiFiMulti.run() == WL_CONNECTED)) {

        t_httpUpdate_return ret = ESPhttpUpdate.update("http://server/file.bin"); // 編譯好的固件文件

        switch(ret) {
            case HTTP_UPDATE_FAILED:
                USE_SERIAL.printf("HTTP_UPDATE_FAILD Error (%d): %s", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
                break;

            case HTTP_UPDATE_NO_UPDATES:
                USE_SERIAL.println("HTTP_UPDATE_NO_UPDATES");
                break;

            case HTTP_UPDATE_OK:
                USE_SERIAL.println("HTTP_UPDATE_OK");
                break;
        }
    }
}

看完以上代碼是否是會(huì)有種想罵人的沖動(dòng)讹躯?我當(dāng)時(shí)找資料看ESP的OTA使用的正確姿勢時(shí)也有種想罵娘的沖動(dòng):太TMD簡單了菩彬!

原理就只是ESPhttpUpdate.update這個(gè)方法,調(diào)用一下就可以從服務(wù)器下載固件并自動(dòng)更新了潮梯!

這個(gè)update方法是有多個(gè)重載版本的骗灶,上面只是用了其中一個(gè)最簡單的重載版本,因此只有一個(gè)參數(shù)指向更新文件酷麦。

   // This function is deprecated, use rebootOnUpdate and the next one instead
    t_httpUpdate_return update(const String& url, const String& currentVersion,
                               const String& httpsFingerprint, bool reboot) __attribute__((deprecated));
    t_httpUpdate_return update(const String& url, const String& currentVersion = "");
    t_httpUpdate_return update(const String& url, const String& currentVersion,
                               const String& httpsFingerprint);
    t_httpUpdate_return update(const String& url, const String& currentVersion,
                               const uint8_t httpsFingerprint[20]); // BearSSL

    // This function is deprecated, use one of the overloads below along with rebootOnUpdate
    t_httpUpdate_return update(const String& host, uint16_t port, const String& uri, const String& currentVersion,
                               bool https, const String& httpsFingerprint, bool reboot) __attribute__((deprecated));

    t_httpUpdate_return update(const String& host, uint16_t port, const String& uri = "/",
                               const String& currentVersion = "");
    t_httpUpdate_return update(const String& host, uint16_t port, const String& url,
                               const String& currentVersion, const String& httpsFingerprint);
    t_httpUpdate_return update(const String& host, uint16_t port, const String& url,
                               const String& currentVersion, const uint8_t httpsFingerprint[20]); // BearSSL

以下是ESP8266httpUpdate的其它方法:

void rebootOnUpdate(bool reboot)  // 更新后重啟
int getLastError(void); // 獲取最后出錯(cuò)的錯(cuò)誤編號(hào)
String getLastErrorString(void); // 獲取出錯(cuò)的信息描述

固件更新服務(wù)器

以下是ESPhttpUpdate產(chǎn)生的請(qǐng)求頭內(nèi)容:

[HTTP_USER_AGENT] => ESP8266-http-Update [HTTP_X_ESP8266_STA_MAC] => 18:FE:AA:AA:AA:AA [HTTP_X_ESP8266_AP_MAC] => 1A:FE:AA:AA:AA:AA [HTTP_X_ESP8266_FREE_SPACE] => 671744 [HTTP_X_ESP8266_SKETCH_SIZE] => 373940 [HTTP_X_ESP8266_CHIP_SIZE] => 524288 [HTTP_X_ESP8266_SDK_VERSION] => 1.3.0 [HTTP_X_ESP8266_VERSION] => DOOR-7-g14f53a19

你可以在更新服務(wù)器中檢測這些請(qǐng)求頭是符合法矿卑,同時(shí)也可以檢測當(dāng)前發(fā)出請(qǐng)求的ESP所使用的固件版本是最新的,如果服務(wù)端有新的版本可用就重定向到該文件然后就使ESP進(jìn)行自更新沃饶。

以下是用PHP來寫一個(gè)最簡單的更新服務(wù)器:

<?PHP

header('Content-type: text/plain; charset=utf8', true);

function check_header($name, $value = false) {
    if(!isset($_SERVER[$name])) {
        return false;
    }
    if($value && $_SERVER[$name] != $value) {
        return false;
    }
    return true;
}

function sendFile($path) {
    header($_SERVER["SERVER_PROTOCOL"].' 200 OK', true, 200);
    header('Content-Type: application/octet-stream', true);
    header('Content-Disposition: attachment; filename='.basename($path));
    header('Content-Length: '.filesize($path), true);
    header('x-MD5: '.md5_file($path), true);
    readfile($path);
}

if(!check_header('HTTP_USER_AGENT', 'ESP8266-http-Update')) {
    header($_SERVER["SERVER_PROTOCOL"].' 403 Forbidden', true, 403);
    echo "only for ESP8266 updater!\n";
    exit();
}

if(
    !check_header('HTTP_X_ESP8266_STA_MAC') ||
    !check_header('HTTP_X_ESP8266_AP_MAC') ||
    !check_header('HTTP_X_ESP8266_FREE_SPACE') ||
    !check_header('HTTP_X_ESP8266_SKETCH_SIZE') ||
    !check_header('HTTP_X_ESP8266_CHIP_SIZE') ||
    !check_header('HTTP_X_ESP8266_SDK_VERSION') ||
    !check_header('HTTP_X_ESP8266_VERSION')
) {
    header($_SERVER["SERVER_PROTOCOL"].' 403 Forbidden', true, 403);
    echo "only for ESP8266 updater! (header)\n";
    exit();
}

$db = array(
    "18:FE:AA:AA:AA:AA" => "DOOR-7-g14f53a19",
    "18:FE:AA:AA:AA:BB" => "TEMP-1.0.0"
);

if(isset($db[$_SERVER['HTTP_X_ESP8266_STA_MAC']])) {
    if($db[$_SERVER['HTTP_X_ESP8266_STA_MAC']] != $_SERVER['HTTP_X_ESP8266_VERSION']) ) {
        sendFile("./bin/".$db[$_SERVER['HTTP_X_ESP8266_STA_MAC']]."bin");
    } else {
        header($_SERVER["SERVER_PROTOCOL"].' 304 Not Modified', true, 304);
    }
    exit();
}

header($_SERVER["SERVER_PROTOCOL"].' 500 no version for ESP MAC', true, 500);
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末母廷,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子糊肤,更是在濱河造成了極大的恐慌琴昆,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件馆揉,死亡現(xiàn)場離奇詭異业舍,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門舷暮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來态罪,“玉大人,你說我怎么就攤上這事下面「淳保” “怎么了技扼?”我有些...
    開封第一講書人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵唉地,是天一觀的道長。 經(jīng)常有香客問我床绪,道長机杜,這世上最難降的妖魔是什么帜讲? 我笑而不...
    開封第一講書人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮椒拗,結(jié)果婚禮上似将,老公的妹妹穿的比我還像新娘。我一直安慰自己蚀苛,他們只是感情好玩郊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著枉阵,像睡著了一般。 火紅的嫁衣襯著肌膚如雪预茄。 梳的紋絲不亂的頭發(fā)上兴溜,一...
    開封第一講書人閱讀 51,604評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音耻陕,去河邊找鬼拙徽。 笑死,一個(gè)胖子當(dāng)著我的面吹牛诗宣,可吹牛的內(nèi)容都是我干的膘怕。 我是一名探鬼主播,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼召庞,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼岛心!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起篮灼,我...
    開封第一講書人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤忘古,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后诅诱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體髓堪,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了干旁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片驶沼。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖争群,靈堂內(nèi)的尸體忽然破棺而出回怜,到底是詐尸還是另有隱情,我是刑警寧澤祭阀,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布鹉戚,位于F島的核電站,受9級(jí)特大地震影響专控,放射性物質(zhì)發(fā)生泄漏抹凳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一伦腐、第九天 我趴在偏房一處隱蔽的房頂上張望赢底。 院中可真熱鬧,春花似錦柏蘑、人聲如沸幸冻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽洽损。三九已至,卻和暖如春革半,著一層夾襖步出監(jiān)牢的瞬間碑定,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來泰國打工又官, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留延刘,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓六敬,卻偏偏與公主長得像碘赖,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子外构,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容