Arduino ESP32 HttpUpdate OTA批量更新

前几天找ESP32 OTA升级资料,有用ide指定IP地址升级的,有链接ESP32的网页后,上传文件的。都很麻烦,我这边后期搞60多套本地局域网设备,改一句代码就要一台一台更新,太麻烦了。

前几天找这个标题的资料,必应搜索只有这篇:
链接: esp32使用httpupdate批量自动化程序升级 arduino IDE
看完这篇文章,升级连接写死在程序上,每次升级都要改,不太优雅。
所以我改进了下。

先贴代码:
Arduino部分(HttpClient):

#include 
#include 
#include 
#include 
#include "ESPAsyncWebServer.h"

String getUpDateName;                                         //获取的升级包名
String upDateName;                                            //上次的升级包名
bool UpdateVersionIsOk;                                       //包名判断可以升级的标志位
String getUpdateUrl = "http://172.17.99.99:8989/getFile";     //获取升级包名的URL
String downLoadUpdateUrl = "http://172.17.99.99:8989/update"; //下载升级包的URL

// OTA升级开始回调函数
void update_started()
{
    Serial.println("CALLBACK:  HTTP update process started");
}

// OTA升级完成回调函数
void update_finished()
{
    Serial.println("CALLBACK:  HTTP update process finished");
    Preferences prefs; // NVS读写实例化
    prefs.begin("WiFiConfig");
    prefs.putString("Version", getUpDateName);
    prefs.end();
    upDateName = getUpDateName;
    UpdateVersionIsOk = false;
    Serial.println("升级记录已保存");
}

// OTA升级中回调函数
void update_progress(int cur, int total)
{
    Serial.printf("CALLBACK:  HTTP update process at %d of %d bytes...\n", cur, total);
}

// OTA升级错误回调函数
void update_error(int err)
{
    Serial.printf("CALLBACK:  HTTP update fatal error code %d\n", err);
}

// OTA升级检查线程
void seachUpdate(void *xTaskParameters)
{
    while (true)
    {
        if (WiFi.status() == WL_CONNECTED)
        {
            HTTPClient http;
            http.begin(getUpdateUrl);
            int httpCode = http.GET();
            delay(500);
            if (httpCode > 0)
            {
                if (httpCode == HTTP_CODE_OK)
                {
                    getUpDateName = http.getString();
                    Serial.println(getUpDateName);
                    //判断get的字符串和nvs存储的升级包名不一致
                    if (getUpDateName != "" && getUpDateName != upDateName)
                    {
                        UpdateVersionIsOk = true;
                    }
                    else
                    {
                        UpdateVersionIsOk = false;
                    }
                }
            }
            else
            {
                Serial.println("HTTP GET... failed, error: " + http.errorToString(httpCode));
            }
            http.end();

            WiFiClient upDateClient;
            httpUpdate.onStart(update_started);
            httpUpdate.onEnd(update_finished);
            httpUpdate.onProgress(update_progress);
            httpUpdate.onError(update_error);
            if (UpdateVersionIsOk)
            {
                httpUpdate.update(upDateClient, downLoadUpdateUrl);
            }
        }
        delay(5000);
    }
}

void setup()
{
    Preferences prefs; // NVS读写实例化
    prefs.begin("WiFiConfig");
    if (prefs.isKey("Version"))
    {
        upDateName = prefs.getString("Version");
    }
    xTaskCreatePinnedToCore(seachUpdate, "seachUpdate", 10000, NULL, 1, NULL, 0);
}

void loop()
{
    delay(10);
}

Python(HttpServer):

from http.server import BaseHTTPRequestHandler, HTTPServer
import os

class MyHttpRequestHandler(BaseHTTPRequestHandler):

    def __init__(self,request, client_address, server, folderPath):
        self.folderPath = folderPath
        self.UpDateFileName = self.getFileExtensionPath(self.folderPath, '.bin')
        self.UpDateFilePath = self.folderPath + "\\" + self.getFileExtensionPath(self.folderPath, '.bin')
        super().__init__(request, client_address, server)

    @classmethod
    def Creator(cls, *args, **kwargs):
        def _HandlerCreator(request, client_address, server):
            cls(request, client_address, server, *args, **kwargs)
        return _HandlerCreator
        

    def do_GET(self):
        # 处理逻辑
        path = str(self.path)
        if path == "/getFile":
            self.send_response(200)
            self.send_header(
                "Content-type", "text/plain")
            self.end_headers()
            self.wfile.write(bytes(self.UpDateFileName, "utf-8"))

        elif path == "/update":
            with open(self.UpDateFilePath, 'rb') as resultf:
                buf = resultf.read()
                length = resultf.tell()
            self.send_response(200)  # 文件存在返回状态码
            # 返回请求格式为"application/octet-stream"
            self.send_header("Content-type", "application/octet-stream")
            self.send_header("Content-Length", str(length))
            self.send_header("Content-Disposition",
                             "attachment; filename=\"%s\"" % self.UpDateFileName)
            self.end_headers()
            # 读取文件发送给客户端
            self.wfile.write(buf)

    def do_POST(self):
        pass

    def getFileExtensionPath(self, path, name):
        for root, dirs, files in os.walk(path):  # 遍历该文件夹
            for file in files:  # 遍历刚获得的文件名files
                (filename, extension) = os.path.splitext(file)  # 将文件名拆分为文件名与后缀
                if (extension == name):
                    return file


if __name__ == '__main__':
    ts = HTTPServer(('0.0.0.0', 8989), MyHttpRequestHandler.Creator(os.getcwd()))
    ts.serve_forever()

说一下流程:
ESP32发起get请求:
ESP32 →(http://172.17.99.99:8989/getFile)→ Python

ESP32收到python的响应文本信息(升级包文件名):
升级包名由python程序搜索自身目录下的 .bin 后缀的文件获得。
ESP32 ←(“ota.0.0.0.0.bin”)← Python

ESP32判断nvs区域有无储存这个信息,无就请求真正的升级链接。
ESP32 →(http://172.17.99.99:8989/update)→ Python

Python响应,发送文件给esp32
ESP32 ←(ota.0.0.0.0.bin)← Python

下次打开Python来给ESP32升级前,记得改一下文件名,要和上一次OTA时不一致就可以了。
PlaformIO的编译文件位置:.pio\build\esp32dev\firmware.bin

你可能感兴趣的:(Arduino,ESP32,踩坑,物联网,c++)