用 Python 把一块 20 块钱的无线模块“喂”给云
一、为什么又是 ESP8266?
我手头的项目需要一个「低功耗 + 能发 HTTPS + 成本别超过一顿外卖」的终端节点。ESP32-C3 功耗更香,但淘宝现货贵 8 块;LoRa 模组距离炸裂,却只能点对点。思来想去,还是老朋友 ESP8266 最对胃口:
- 价格:¥19.8(包邮,带天线)
- Flash:4 MB,够用
- 社区:十年沉淀,踩坑贴比 Stack Overflow 还多
唯一不爽的是原厂 AT 固件不支持 TLS 1.2,而甲方爸爸强制 HTTPS。于是我决定自己刷 MicroPython,顺便把云端对接彻底打通。
二、Python 库选型:少即是多
在 PC 端,我的需求只有三件事:串口烧录、批量 OTA、云端日志拉取。调研了一圈,最终留下 3 个库,其他全部踢出 requirements.txt:
| 库名 | 版本 | 作用简述 | 坑点记录 |
|---|---|---|---|
| esptool | 4.7 | 一键擦除+烧录固件 | 在 macOS 14 需关闭 SIP 才能访问串口 |
| mpremote | 1.22 | REPL + 文件同步,比 ampy 稳 | 首次连接需手动 soft-reset |
| minio | 7.2 | 私有 S3 对象存储,当 OTA 服务器 | 记得把 part_size 调到 5 MB,否则上传大固件会 400 |
小贴士:不要装所谓「一键物联网套件」。它们往往包裹了 20 多个依赖,半年后你再看
pip list,已经找不到北。
三、无线模块固件裁剪:省 200 KB,多跑 3 天
MicroPython 官方固件 1.22 默认把 urequests、uasyncio 全塞进去,8266 内存瞬间吃紧。我按 80/20 法则做了裁剪,最终固件 590 KB,空闲 RAM 还剩 46 KB,足够跑主循环 + TLS。
裁剪步骤:
- 克隆源码:
git clone --depth=1 https://github.com/micropython/micropython.git - 修改
ports/esp8266/boards/manifest.py,把不用的库注释掉 make USER_C_MODULES=../../examples/usercmodule编译- 用 esptool 烧录,一气呵成
四、与云服务的握手:自建还是托管?
起初我准备直接上阿里云 IoT 套娃,但一想到要“产品-设备-三元组”三级跳就头大。于是退而求其次:
- 终端 HTTPS POST 到云函数 → 云函数写 Kafka → ClickHouse 持久化
- 控制指令走 MQTT over TLS,双向证书校验,杜绝中间人
架构图如下(ASCII 手绘,凑合看):
+----------+ +------------+ +------------+
| ESP8266 |----->| Cloud Func |----->| ClickHouse |
| NodeMCU |<-----| (Python) |<-----| Broker |
+----------+ +------------+ +------------+
五、代码片段:最简洁的 HTTPS POST
import urequests, ujson, machine
URL = "https://iot.example.com/upload"
def upload(data):
try:
r = urequests.post(URL,
data=ujson.dumps(data),
headers={'Content-Type': 'application/json'})
print('status:', r.status_code)
r.close()
except OSError as e:
print("net fail:", e)
machine.reset()
真·一行多余都没有。8266 的 SSL 证书我直接烧进 cert/cert.der,省得运行时握手再跑 TLS 解析。
六、OTA 全流程:从 Kafka 到 Flash
| 步骤 | 触发条件 | 关键命令/代码片段 | 耗时 |
|---|---|---|---|
| 1 | CI 推送新固件 | mc cp firmware.bin myminio/ota/ |
3 s |
| 2 | 云函数下发通知 | MQTT topic: /ota/<chip_id> |
<1 s |
| 3 | 终端拉取固件 | urequests.get("https://.../firmware.bin") |
8 s |
| 4 | 校验 SHA256 | hashlib.sha256(data).hexdigest() |
1 s |
| 5 | 写 Flash & 重启 | esp.check_fw() + machine.reset() |
2 s |
最难调的是第 3 步:如果一口气读 512 KB,8266 直接 OOM。我改成 4 KB 流式写入,边下载边刷 Flash,才算稳定。
七、功耗实测:数字不会骗人
把板子丢进老化房,3.7 V 锂电 → MCP1700 LDO → 整机,测得:
| 模式 | 平均电流 | 占空比 | 续航估算 (1000 mAh) |
|---|---|---|---|
| DeepSleep | 0.18 mA | 95 % | 约 231 天 |
| 唤醒+发数据 | 82 mA | 5 % |
嗯,三个月换一次电池,客户勉强能接受。
八、踩坑杂烩(排名不分先后)
- MicroPython 的
ussl模块居然不支持 SNI,得打补丁ussl.wrap_socket(..., server_hostname=host)。 - 阿里云函数 Python 3.9 默认时区是 UTC,我日志时间全部错位 8 小时,调了半天。
- 用 macOS 14 的自带
screen进 REPL 会乱码,改用mpremote的connect子命令。 - ESP8266 的
Pin(16)只能做OUT,不能IN,别问我是怎么知道的……
九、结语
折腾到凌晨四点的意义,大概就是第二天早上甲方群里的一句「测试通过」。
源码我放 Gitee 了,仓库名 esp8266-minimal-cloud,欢迎拍砖。如果你也在用 20 块钱的模块干着 200 块钱的事,留言聊聊你的故事吧。
- 点赞
- 收藏
- 关注作者
评论(0)