原理
在巴法云上传OTA之前的文章已经有介绍,这里不在多说,巴法云提供了https://api.bemfa.com/api/device/v1/bin的地址获取OTA固件的地址.它使用GET接口完整的地址为https://api.bemfa.com/api/device/v1/bin?uid=xxxx&topic=xxxx&type=xxx这几个名字都可以望文生意,这里只说type MQTT设备=1 TCP设备=2 图云=3.具体可以参考巴法开放平台 (bemfa.com)
在VSC里提供了方便的运行脚本的方法,这里可以利用py访问上面这个址即可方便的获取ota固件信息,能过这个信息生成相应的版本宏定义,这里我生成一个名叫ota_version.h的头文件方便引用,通过这个脚本即可在每次编译前获取一次亲了最新的版本号,这个版本号+1即是当前版本号.这想通过对比自己的版本号和远程的版本号即可确定是否需要更新.当然在ESP8266HTTPUpdate的实现其实已经考虑了这个问题,但是巴法云的文档并未说明是否支持这个特性,所以我这里自己检测一下.当然感兴趣的也可以自己测试一下.httpUpdate.update(UpdateClient, otaurl /*, current_ver*/);这个current_ver即是版本号.
步骤
在vsc的资源管理器窗口建立一个叫UpdateVer.py的文件.(顺便一说,要使用py,当然要先安装好py的运行环境,因为我这里使用了新特性,所以需要py3.10版本以上)正常情况你安装了py会在vs的下面显示版本如下图
UpdateVer.py内容如下:
import urllib3
import json
http = urllib3.PoolManager() # 线程池生成请求
res = http.request('GET', 'https://api.bemfa.com/api/device/v1/bin?uid=纟xxxx&topic=xxx&type=1')
'''
5723001 缺少uid字段
5723002 uid值为空或不正确
5723003 缺少type字段
5723004 type值为空或不正确
5723005 缺少topic字段
5723007 获取成功
5724009 固件为空不存在
'''
#{"code":5723007,"data":{"url":"http:\/\/bin.bemfa.com\/b\/.bin","time":"2023-07-11 21:13:46","v":"19","tag":""}}
jsonobject = json.loads(res.data.decode())
successed=False
match jsonobject["code"]:
case 5723001:print('缺少uid字段')
case 5723002:print('缺少uid字段')
case 5723003:print('缺少type字段')
case 5723004:print('type值为空或不正确')
case 5723005:print('缺少topic字段')
case 5723007:
print('获取成功')
successed=True
case 5724009:print('固件为空不存在')
print('当前版本发布号:'+(str(int(jsonobject['data']['v'])+1) if successed else '1'))
with open("ota_version.h",mode='w',encoding='utf-8') as ff:
ff.write( '#define OTA_VER '+str(int(jsonobject['data']['v'])+1) if successed else '#define OTA_VER '+'1')
上面uid topic type需要按实际情况修改.
下面在资源管理器里找到.vscode/arduino.json打开.添加 如下行"prebuild": "py ./UpdateVer.py"
现在就像如上.这样每次编译前就会执行updatever.py.生成 ota_version.h.这样即可保证每次编译的版本号都 比远程的大1.
在8266上检测是否有更新
代码如下
String CheckUpdate(const char *uid, const char *topic, const char *devType)
{
String ota_url;
if (uid == nullptr || topic == nullptr || devType == nullptr)
return ota_url;
// https://api.bemfa.com/api/device/v1/bin/
String otaInfoUrl = R"(https://api.bemfa.com/api/device/v1/bin?uid=)";
// uid=%s&topic=%s&type=%d
otaInfoUrl += uid;
otaInfoUrl += "&topic=";
otaInfoUrl += topic;
otaInfoUrl += "&type=";
otaInfoUrl += devType;
Serial.println(u8"从" + otaInfoUrl + u8"获取ota信息");
std::unique_ptr<BearSSL::WiFiClientSecure> client(new BearSSL::WiFiClientSecure);
client->setInsecure();
HTTPClient httpClient;
httpClient.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS);
if (httpClient.begin(*client, otaInfoUrl))
{
int httpCode = httpClient.GET();
if (httpCode == HTTP_CODE_OK)
{
String json = httpClient.getString(); // 使用getString函数获取服务器响应体内容
DynamicJsonDocument doc(512);
// 反序列数据
if (!deserializeJson(doc, json))
{
//{"code":5723007,"data":{"url":"http:\/\/bin.bemfa.com\/b\/.bin","time":"2023-07-11 21:13:46","v":"19","tag":""}}
if (doc["code"].as<uint64_t>() == 5723007)
{
Serial.println(u8"获取ota信息成功");
String verStr = doc["data"]["v"];
int ver = verStr.toInt();
if (ver > OTA_VER)
{
Serial.print(u8"获取ota url成功:");
ota_url = doc["data"]["url"].as<String>();
Serial.println(ota_url);
}
else
{
Serial.println(u8"当前已经是最新版本,ota无更新");
}
}
else
{
Serial.println(doc["code"].as<uint64_t>());
}
}
else{
Serial.println("json反序列化失败");
}
}
else
{
Serial.print("\r\nServer Respose Code: ");
Serial.println(httpCode);
}
httpClient.end();
}
return ota_url;
}
这样即可正常检测,有更新即返回ota的url.当然 这里可以做理精细处理,比如没有更新时给出原因方便分析.