ESP8266 OTA之服务器更新

简介: 我之前介绍了两篇关于ESP8266的OTA更新方法:基于 Arduino OTA "ESP8266 OTA之Arduino IDE更新"基于 浏览器的 OTA "ESP8266 OTA之浏览器更新"说实话以上这两种方案除有点好玩其实没有什么实用性,由其在开发产品时上述的两种方案就是一种鸡肋,甚至可以说是不可用的。

我之前介绍了两篇关于ESP8266的OTA更新方法:

说实话以上这两种方案除有点好玩其实没有什么实用性,由其在开发产品时上述的两种方案就是一种鸡肋,甚至可以说是不可用的。那现在市面上的各种智能设备是怎么更新固件的呢?

我使用过的绝大多数会进行固件更新的IoT设备都是先在手机上提示有新的固件可以更新,如果一确定以后就会自动下载并进行更新。那我们的ESP8266是否也能做到这样的效果呢?

答案显然是肯定的。本文所讲述的OTA做法其实才是做产品的正道。

首先你要准备一台静态文件服务器,并将某个目录作为更新文件存储。当然,如果你希望以后更方便地管理你发布的更新,那么你的更新文件就需要有良好的命名规则,关于这方面可以到百度上去搜一下找个命名规范或者按自己需要定义一套就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;
        }
    }
}

看完以上代码是否是会有种想骂人的冲动?我当时找资料看ESP的OTA使用的正确姿势时也有种想骂娘的冲动:太TMD简单了!

原理就只是ESPhttpUpdate.update这个方法,调用一下就可以从服务器下载固件并自动更新了!

这个update方法是有多个重载版本的,上面只是用了其中一个最简单的重载版本,因此只有一个参数指向更新文件。

   // 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); // 获取最后出错的错误编号
String getLastErrorString(void); // 获取出错的信息描述

固件更新服务器

以下是ESPhttpUpdate产生的请求头内容:

[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

你可以在更新服务器中检测这些请求头是符合法,同时也可以检测当前发出请求的ESP所使用的固件版本是最新的,如果服务端有新的版本可用就重定向到该文件然后就使ESP进行自更新。

以下是用PHP来写一个最简单的更新服务器:

<?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);
相关文章
|
7月前
|
JSON Linux Android开发
ESP8266透传:发送数据到HTTP服务器
ESP8266透传:发送数据到HTTP服务器
260 0
|
7月前
|
Linux C语言 Android开发
ESP8266透传:利用STM32f103zet6发送数据到HTTP服务器
ESP8266透传:利用STM32f103zet6发送数据到HTTP服务器
177 0
|
9月前
|
传感器 网络架构 智能硬件
STM32通过esp8266连接WiFi接入MQTT服务器
STM32通过esp8266连接WiFi接入MQTT服务器
542 1
|
网络协议 物联网
STM32封装ESP8266一键配置函数:实现实现AP模式和STA模式切换、服务器与客户端创建
STM32封装ESP8266一键配置函数:实现实现AP模式和STA模式切换、服务器与客户端创建
461 0
STM32封装ESP8266一键配置函数:实现实现AP模式和STA模式切换、服务器与客户端创建
|
网络协议 测试技术
9-51单片机ESP8266学习-AT指令(测试TCP服务器--51单片机程序配置8266,C#TCP客户端发信息给单片机控制小灯的亮灭)
http://www.cnblogs.com/yangfengwu/p/8780182.html 自己都是现做现写,如果想知道最终实现的功能,请看最后     先把源码和资料链接放到这里   链接:https://pan.
2017 0
|
移动开发 网络协议 测试技术
7-51单片机ESP8266学习-AT指令(测试TCP服务器--51单片机程序配置8266,用手机TCP调试助手发信息给单片机控制小灯的亮灭)
http://www.cnblogs.com/yangfengwu/p/8759294.html  如不做任何说明默认最头上的链接为上一篇链接,末尾的链接为下一篇链接     先把源码和资料链接放到这里       链接:https://pan.
2736 0
|
存储 网络协议 测试技术
8-51单片机ESP8266学习-AT指令(测试TCP服务器--51单片机程序配置8266,做自己的手机TCP客户端发信息给单片机控制小灯的亮灭)
http://www.cnblogs.com/yangfengwu/p/8776712.html   先把源码和资料链接放到这里 链接:https://pan.baidu.com/s/10MxI8-Q33-M_R2WEHqEi1A 密码:j1sz 先做手机的,然后做C#的 详细点的可以看我这篇文章,请参考着这篇看这篇文章,这篇文章会解决一些细节问题 http://www.
1651 0
|
Web App开发 网络协议 测试技术
6-51单片机ESP8266学习-AT指令(测试TCP服务器--使用串口调试助手--不连接路由器)
上一篇连接  http://www.cnblogs.com/yangfengwu/p/8757513.html 注意:更加详细的操作请参考, http://www.cnblogs.com/yangfengwu/p/5205570.
1817 0