ESP32 OTA升级功能的MirPython开发指南

系列文章目录

mircopython 开发ESP32


提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档

前言

一、mircopython开发ESP32需要哪些工具?

二、使用Tonny烧录固件

总结


前言

ESP32提供了mircopython固件库,用python语言开发项目功能,缩短开发周期,并且上手简单。本文章主要介绍用mircopython开发遇到的的一些问题,分享一些经验,希望大家能多多交流


提示:以下是本篇文章正文内容,下面案例可供参考

一、mircopython开发ESP32需要哪些工具?

1、软件:Tonny(新手适用),链接:Thonny, Python IDE for beginners

2、mircopython固件:MicroPython – Python for microcontrollers,注意选择合适的固件版本,python版本管控是一个重要的知识点

3、esp32开发板:这里选择自己需要的就好,我选用的是esp32-wroom-32

二、使用Tonny烧录固件

三、OTA升级功能思路

先对要更新的.py进行打包压缩,将打包压缩的.py放在服务器指定目录下,由设备主动获取,设备获取到固件压缩包之后,在本地解压。主要有验证:md5或者crc,这里我使用的是md5。

                                        流程图

1、打包压缩工具:

压缩包的数据结构:

这样设计的数据结构的原因:由于esp32的内存资源有限,我们需要分段式的读取每个文件压缩包,避免内存溢出,以时间换取空间方式解决内存紧张问题。

代码如下(示例):

import zlib
import os


def compress_folder(folder_path):
    # 初始化一个空列表来存储文件名、压缩后数据大小和压缩后数据
    compressed_files_info = []

    # 获取指定文件夹下的所有文件名
    file_list = os.listdir(folder_path)
    for file_name in file_list:
        # 检查是否为普通文件
        full_path = os.path.join(folder_path, file_name)
        if os.path.isfile(full_path):
            # 打开当前文件,并读取文件内容
            with open(full_path, 'rb') as file:
                file_data = file.read()
                # 压缩文件内容
                compressed_data = zlib.compress(file_data)
                # 获取压缩后数据大小
                compressed_size = len(compressed_data)

                # 将文件名、压缩后数据大小和压缩后数据添加到列表中
                compressed_files_info.append((file_name, compressed_size, compressed_data))

    return compressed_files_info


def create_flash_image(compressed_files_info):
    # 定义分隔符和包尾数据
    separator1 = '|'
    separator2 = ':'
    separator3 = ';'
    package_tail = b'END'  # 包尾数据

    # 创建一个字节数组来存储信息段
    info_segment = bytearray()

    # 将每个文件的信息构造为子信息段
    for file_info in compressed_files_info:
        file_name, compressed_size, compressed_data = file_info

        # 创建子信息段
        sub_info_segment = f"{file_name}{separator1}{compressed_size}{separator2}{separator3}"
        info_segment.extend(sub_info_segment.encode('utf-8'))

    # 确保信息段不超过1KB
    if len(info_segment) > 1024:
        raise ValueError("信息段超过1KB限制")

    # 填充信息段到1KB
    info_segment.extend(b'\x00' * (1024 - len(info_segment)))

    # 将信息段和压缩数据组合在一起,每个压缩数据后面加上包尾数据
    final_data = info_segment
    for _, _, data in compressed_files_info:
        final_data += data + package_tail

    return final_data


if __name__ == '__main__':
    folder_path = './python'
    compressed_files_info = compress_folder(folder_path)

    # 创建最终的 Flash 映像数据
    final_data = create_flash_image(compressed_files_info)

    # 将数据写入到输出文件
    output_file = 'PR_APP_V04.zlib'
    with open(output_file, 'wb') as f:
        f.write(final_data)

    # 输出有几个文件被压缩了
    num_compressed_files = len(compressed_files_info)
    print(f"总共有 {num_compressed_files} 个文件被压缩。")

    # 打印每个被压缩存储的文件的信息
    print("以下文件已成功压缩并存储到 Flash(output_flash.bin):")
    for file_info in compressed_files_info:
        print(f"文件名: {file_info[0]}, 压缩后大小: {file_info[1]} bytes")

    # 输出最后压缩包的名字和大小
    compressed_package_size = os.path.getsize(output_file)
    print(f"压缩包的名字为: {output_file}, 大小为: {compressed_package_size} bytes")

注意:要压缩的.py文件需要存放在当前./python目录下,生成的压缩包output_flash.bin会直接放在当前目录./下。

2、解压工具

import zlib
import os

def extract_flash_image(input_file_path, output_folder):
    # 确保输出文件夹存在
    if not os.path.exists(output_folder):
        os.makedirs(output_folder)

    # 定义分隔符
    separator1 = '|'
    separator2 = ':'
    separator3 = ';'
    package_tail = b'END'

    # 读取信息段(前 1024 字节)
    with open(input_file_path, 'rb') as f:
        info_segment = f.read(1024).rstrip(b'\x00').decode('utf-8')

    # 解析信息段
    file_infos = info_segment.split(separator3)[:-1]  # 最后一个是空字符串,去掉

    # 处理每个文件
    with open(input_file_path, 'rb') as f:
        f.seek(1024)  # 移动到数据起始位置
        for file_info in file_infos:
            file_name, compressed_size_str = file_info.split(separator1)
            compressed_size = int(compressed_size_str.split(separator2)[0])

            # 分块读取压缩数据
            compressed_data = bytearray()
            bytes_read = 0
            while bytes_read < compressed_size:
                chunk = f.read(min(compressed_size - bytes_read, 1024))
                if not chunk:
                    break
                compressed_data.extend(chunk)
                bytes_read += len(chunk)

            # 跳过包尾数据
            f.read(len(package_tail))

            # 解压缩数据
            decompressed_data = zlib.decompress(compressed_data)

            # 写入解压后的文件
            output_file_path = os.path.join(output_folder, file_name)
            with open(output_file_path, 'wb') as out_file:
                out_file.write(decompressed_data)

    print("文件解压完成,已保存到:", output_folder)

if __name__ == '__main__':
    input_file = 'PR_APP_V03.zlib'
    output_folder = './extracted_files'#这里要改成.,直接是当前目录即可。
    extract_flash_image(input_file, output_folder)  

四、用ampy+uzlib向Esp32内“烧录固件”

由于使用tonny,想要将文件烧录到esp32中,只能通过新建文件方式。但是对于有多个.py文件,如果我们要给多块板子烧录多个.py文件,通过给每个板子新建文件方式,会很繁琐。

所以我们可以先将要烧录的.py文件打包压缩成xxx.uzlib文件,通过ampy工具传输到esp32里,然后把解压程序decompress.py也放入esp32里,通过ampy 去执行decompress.py将xxx.uzlib文件解压,多个.py就可以放入到esp32里面了,就不需要频创建新文件了。

解压后的文件就可以看见了


总结

这里讲的是esp32的ota升级和烧录,希望对大家有所帮助,大家有好多建议希望能多多分享!!!

作者:苏狗子

物联沃分享整理
物联沃-IOTWORD物联网 » ESP32 OTA升级功能的MirPython开发指南

发表回复