ESP32 WebSocket OTA更新字节丢失问题求助
问题:ESP32 OTA更新出现premature end错误(丢失1456字节)
场景描述
我使用Flutter应用连接ESP32上基于links2004/websockets库搭建的WebSocket服务器,通过二进制Socket传输固件。每帧数据会添加:
- 1个更新状态标识字节
- 1个结束标识字节(0xFF标记最后一帧)
- 帧末尾1个校验和字节(基于帧数据计算)
两端已校验校验和与数据量,但更新时报错:
premature end: res:0, pos:864256/1966080
Linux系统显示固件文件firmware.bin大小为865712字节,但更新时丢失了1456字节(865712-864256=1456)。
相关代码与调试日志
ESP32端处理代码
esp_err_t Updater::handleUpdateData(const uint8_t *data, size_t length) { //debug vars. static int k; static int j; if (!isUpdateInProgress) { logger().log("Fatal error, the update isn't started", debug_info_t::WARNING_D); return ESP_FAIL; } if (length < 3) { //As I said, I add 3 bytes, therefore at least the frame must contain 3 bytes logger().log("Frame length is incosistent, frame is broken", debug_info_t::WARNING_D); return ESP_FAIL; } //To check that it is the last frame, I mark it with the 0xff flag bool isLastFragment = (data[1] == 0xFF); //the last byte of the frame contains the checksum uint8_t receivedChecksum = data[length - 1]; uint8_t calculatedChecksum = getChecksum(data + 2, length - 3); if (calculatedChecksum != receivedChecksum) { //At this point, if the checksum does not match it would throw an error logger().log("Checksum mismatch.", debug_info_t::WARNING_D); return ESP_FAIL; } k+=length-3; logger().log(std::to_string(k).c_str()); //We write the data to the OTA partition and store its result, to verify that it is exactly //the length received minus the 3 bytes that are not from the firmware size_t result=Update.write(const_cast<uint8_t *>(data) + 2, length - 3); if ( result!= length - 3) { logger().log("Failed to write OTA update data.", debug_info_t::WARNING_D); return ESP_FAIL; }else{ //debug to check how many bytes are being written to each packet std::string s="Packet"+std::to_string(j)+" writted"+ std::to_string(result); j++; logger().log(s.c_str()); } if (isLastFragment) { std::string lastPacket="Last packet length: "+std::to_string(length-3); logger().log(lastPacket.c_str()); if (!Update.end()) { logger().log("Failed to finalize OTA update.", debug_info_t::WARNING_D); return ESP_FAIL; } else if (Update.isFinished()) { logger().log("OTA update completed successfully.", debug_info_t::DEBUG_D); ESP.restart(); } else { logger().log("OTA update not finished.", debug_info_t::WARNING_D); return ESP_FAIL; } } return ESP_OK; }
调试日志
Flutter端
I/flutter ( 5132):packet 0=> 10048 ..... I/flutter ( 5132):packet 85=> 864128 I/flutter ( 5132):packet 86=> 865712
ESP32端
[INFO]: Packet0 writted=>10048 [INFO]: total=>10048 .... [INFO]: Packet85 writted=>10048 [INFO]: total=> 864128 [INFO]: Packet86 writted=>1584 [INFO]: total=> 865712
问题排查与解决建议
1. 核心问题:OTA初始化时未设置正确的固件大小
错误中的1966080是2MB,这很可能是你调用Update.begin()时传入的固定值,而实际固件大小只有865712字节。ESP32的OTA库会校验写入总字节数是否等于初始化时设置的大小,如果不匹配就会抛出premature end错误。
解决方法:
在启动OTA前,获取固件的实际大小并传入Update.begin():
// 假设firmwareSize是从Flutter端获取的固件总大小(865712) if (!Update.begin(firmwareSize)) { logger().log("Failed to start OTA update.", debug_info_t::ERROR_D); return ESP_FAIL; }
2. 验证OTA内部统计的写入量
在调用Update.end()之前,打印OTA库内部统计的写入进度,对比你自己统计的k值:
if (isLastFragment) { std::string totalWritten = "OTA internal progress: " + std::to_string(Update.getProgress()); logger().log(totalWritten.c_str()); std::string yourTotal = "Your calculated total: " + std::to_string(k); logger().log(yourTotal.c_str()); // 后续的Update.end()逻辑... }
如果两者数值不一致,说明Update.write()的实际写入量和你计算的length-3存在差异,需要排查WebSocket帧的完整性。
3. 检查WebSocket帧传输完整性
虽然两端日志显示总字节数一致,但可能存在WebSocket帧被分片传输,而ESP32的websockets库未正确拼接的情况。可以:
- 在Flutter端,确保每帧发送的固件数据长度正确(前85包10048字节,最后一包1584字节),且数据是从文件中连续读取的。
- 在ESP32端,打印每帧的
length值,确认帧总长度等于固件数据长度+3(标识+结束+校验和)。
4. 重置静态统计变量
代码中k和j是静态变量,如果更新失败后未重置,会导致下一次更新时统计错误。建议在启动更新时重置这两个变量:
// 在启动OTA的代码中添加 isUpdateInProgress = true; k = 0; j = 0;
5. 验证分区表配置
确认ESP32的分区表中,OTA分区的大小至少大于固件实际大小(比如设置为1MB或2MB)。可以通过idf.py partition_table命令查看和修改分区表。
内容的提问来源于stack exchange,提问作者WikiLift
相关产品推荐
相关产品推荐

