从零制作 ESP32 触摸屏状态看板
ESP32 · ILI9341 · XPT2046 · SHT40 · Cloudflare Workers / D1 · Windows / Mac 采集器
整理日期:2026 年 10 月 28 日。本文按本次制作过程整理,功能范围截至温湿度趋势、远程显示设置完成并验收。
这是一块放在桌面上的小看板:上方看 Codex 剩余额度、重置时间和可用额度重置卡,中间看近 30 分钟 Token,下方看网站访问情况;接入 SHT40 后,还能显示温湿度和趋势。手机负责配网,电脑负责采集,Cloudflare 负责汇总和网页管理,ESP32 负责显示与触摸交互。
阅读与隐私说明:所有域名、账号名称、额度、温湿度和画面中的数据均为示例;设备序列号、MAC、真实 Wi-Fi、密码、令牌和个人环境照片均未收录。成品摆放图为建议方案,网页图为功能结构示意,均不代表实拍。教程 ZIP 不包含项目源码、固件、采集器或私人配置。

1. 做完后能得到什么
| 部分 | 完成后的能力 |
|---|---|
| 屏幕 | 中文看板、四种配色、四种布局、额度和网站详情、触摸翻页 |
| 配网 | 手机填写 2.4 GHz Wi-Fi、HTTPS 接口地址和设备令牌,成功后保存 |
| Codex | 按实际返回的额度窗口显示剩余比例、重置时间、重置卡数量与可取得的到期信息 |
| Token | 显示已接入设备近 30 分钟的用量,区分完整、部分和不可用 |
| 网站 | 云端每分钟检查;网页可调整监控列表,板端随摘要更新 |
| 环境 | SHT40 每 5 秒本地采样;屏幕看近 1 小时趋势,网页看最多 7 天历史 |
| 管理 | 网页修改配色、布局、自动翻页和刷新间隔,显示设备的真实应用结果 |
| 运行 | 开机自动运行;Windows / Mac 登录后后台采集,每 60 秒上报 |
这次制作的顺序是:先确认串口和备份固件,再点亮屏幕、设置开机自启和手机配网;随后接通 Cloudflare 与电脑采集器,最后加入触摸、温湿度、趋势和远程设置。按这个顺序复刻,每一步都能单独判断是否成功。
复刻前要准备两类文件:一类是本文和配图,用于理解与接线;另一类是与本文对应的完整 ESP 项目源码、成品固件及采集器发行包。后者应从项目维护者取得。本文没有假定存在公开下载仓库,也没有把维护者本机的私人文件作为公共依赖。只有通用 MicroPython、最小测试代码的部分可以脱离整套成品独立完成。
命令默认在 macOS / Linux 的项目根目录 ESP/ 执行;Windows 的采集器安装命令另行标注。示例串口名必须替换成自己的实际串口。
阅读路线:第一次搭建按第 2~11 节顺序操作;已有成品的用户可直接看第 12~17 节;遇到故障先看第 18 节,再按现象回到对应测试阶段。
2. 物料怎么选
| 物料 | 数量 | 选购要点 |
|---|---|---|
| 经典 ESP32 开发板 | 1 | 本项目为 ESP32-D0WD-V3、4 MiB Flash;接口与板载 USB 转串口应可用 |
| ILI9341 SPI 彩屏 | 1 | 本项目为 2.8 英寸、240×320、14 针模块,带 XPT2046 电阻触摸 |
| SHT40 模块 | 1 | 选择已焊接排针、可查供电和 VCC/GND/SDA/SCL 定义的模块 |
| 400 孔面包板 | 1~2 | 单块可以做原型,但宽 ESP32 容易遮住取线孔;完整装配建议两块,或选 830 孔板 |
| 公母杜邦线 | 一组 | 连接排针与面包板;建议准备 20~30 根短线,留出分线余量 |
| 公公跳线 / 面包板硬跳线 | 一组 | 用于同一信号分线、供电与跨槽连接 |
| USB 数据线 | 1 | 必须支持数据,不能只有充电功能 |
| USB 电源 | 1 | 稳定的 5 V 电源,供电能力和线材质量都要合适 |
| 亚克力底板、螺柱、螺丝、脚垫 | 可选 | 最终固定时再按孔位和走线空间选尺寸 |
| 万用表 | 建议 | 排查面包板连通、供电和接触问题时很有帮助 |
不要只按“2.8 寸屏”购买。并口屏、无触摸屏、不同控制器和不同供电电路可能外观相似,但不能直接套用本教程接线。DHT11 曾作为候选讨论,实际成品采用的是 SHT40。
400 孔面包板够不够,取决于开发板宽度和屏幕摆放。屏幕适合单独用螺柱固定在底板上,排针只负责电气连接;ESP32 插在面包板上,USB 口朝外,SHT40 放在通风处。不要让较重的屏幕长期靠排针悬挑。
面包板背面的双面胶用于最终粘贴固定。先保持离型纸不撕,完成接线和测试后再定位;裸露焊点或排针底部应与导电表面隔开。亚克力方案属于后续整理建议,本次实物验证不以完成亚克力外壳为前提。
3. 先理解面包板和两个按钮

普通面包板上,同一编号的 a~e 五孔相通,f~j 五孔也相通,但两组之间隔着中槽。相邻编号不相通。两侧红蓝电源轨可能中间断开,也不默认左右相通,应以实物测通结果为准。
因此,没有一分二杜邦线也能分线:将 ESP32 的一个 GPIO 接到某一组连通孔,再从该组其他孔分别引向屏幕和触摸。只能分出同一信号,不能把两个不同 GPIO 插在同一组连通孔里。
开发板上的 D18 指 GPIO18,不是第 18 个排针,也不是面包板第 18 行。面包板行号会随重新布局而变化,教程以模块丝印与 GPIO 为准。
| 按钮 | 作用 | 日常使用 |
|---|---|---|
| EN / RESET | 重启 ESP32,保留已保存配置 | 需要重启或重新开放开机配网窗口时短按 |
| BOOT | 配合复位进入下载模式 | 自动下载正常时不用按;不等同于“清除 Wi-Fi”按钮 |
自动烧录连不上时,才按工具提示尝试按住 BOOT、短按 EN,连接成功后松开 BOOT。误入下载模式时,松开 BOOT 后短按 EN。按键位置以板上丝印为准,不凭左右方向记忆。
4. 屏幕、触摸和 SHT40 的完整接线
4.1 先确认屏幕供电条件
本项目红色屏幕背板有 U1 稳压器和 J1 跳线位置。与其布局相符的 LCDWiki MSP2807 参考原理图规定:
| 屏幕模块条件 | 屏幕 VCC 接法 |
|---|---|
| 确认具有对应的板载 3.3 V 稳压电路,且 J1 开路 | 接 ESP32 的 VIN / 5V;ESP32 此时由 USB 供电 |
| 对应电路的 J1 已桥接 | 接 3V3 |
| 模块电路或 J1 状态不明确 | 先查商家资料或确认电路,再通电 |
这个条件不能推广到所有红色模块。VIN 名称也不保证每块开发板在 USB 供电时都能提供相同输出,要核对自己的开发板。
屏幕 LED、SHT40 和所有 ESP32 GPIO 均使用 3.3 V。5 V 只用于上表确认适用的屏幕 VCC。 每次改线先拔 USB;初次下载固件可先不接外设。
4.2 先点亮屏幕:8 根线
先跳过触摸,最容易缩小问题范围。
| 屏幕丝印 | ESP32 | 说明 |
|---|---|---|
| VCC | VIN / 5V,或按上节改接 3V3 | 必须先确认 J1 / 稳压电路 |
| GND | GND | 共地 |
| CS | D27 / GPIO27 | 显示片选 |
| RESET | D25 / GPIO25 | 显示复位 |
| DC | D26 / GPIO26 | 命令 / 数据选择 |
| SDI / MOSI | D23 / GPIO23 | ESP32 向屏幕发送数据 |
| SCK | D18 / GPIO18 | SPI 时钟 |
| LED | 3V3 | 本模块背光控制输入 |
这个阶段,SDO/MISO、五根 T_… 触摸针和 SD 卡焊孔全部留空。屏幕能显示后再加触摸,不需要一开始就把所有线接完。
4.3 加入 XPT2046 触摸
| 触摸丝印 | ESP32 | 与屏幕的关系 |
|---|---|---|
| T_CLK | D18 / GPIO18 | 与屏幕 SCK 共用时钟 |
| T_CS | D32 / GPIO32 | 独立片选,不能与 LCD CS 短接 |
| T_DIN | D23 / GPIO23 | 与屏幕 SDI/MOSI 共用发送数据 |
| T_DO | D19 / GPIO19 | 触摸向 ESP32 返回数据 |
| T_IRQ | D33 / GPIO33 | 按下为低、松开为高,程序启用输入上拉 |
最终屏幕 14 针中连接 13 针,屏幕的 SDO/MISO 仍然空着。本驱动只写显示器,GPIO19 专供触摸 T_DO 使用,SDO 不接 GND。SD 卡接口本轮不用。
4.4 接入 SHT40:以最终实物验证为准
| SHT40 丝印 | ESP32 | 备注 |
|---|---|---|
| VCC / + | 3V3 | 与屏幕 LED 可共用 3V3 分线 |
| GND / − | GND | 与开发板、屏幕共地 |
| SDA | D22 / GPIO22 | 本项目最终采用的 I²C 数据脚 |
| SCL | D21 / GPIO21 | 本项目最终采用的 I²C 时钟脚 |
这里特别容易接反:网上常见 ESP32 示例使用 SDA21/SCL22;本项目最终实物验证的是 SDA22/SCL21,软件已同步适配。不要一边按本文接线,一边使用另一套默认引脚代码。
带外壳模块必须确认排针顺序。相似外壳、商家通用示意图和杜邦线颜色都不能代替实际丝印。本次排查在打开外壳确认 VCC/GND/SDA/SCL 后才取得可靠读数。若不便拆壳,应让商家提供与所购型号一致、明确观察方向的引脚定义。
传感器放远离 ESP32、稳压器和屏幕背光的位置,保留空气流通,避免把自身发热误认为室温变化。Sensirion SHT40 产品资料可用于核对芯片接口与供电范围;零售模块的外围电路仍以实物资料为准。
4.5 哪几个位置需要一对多

| 分线点 | 引向哪里 |
|---|---|
| D18 | 屏幕 SCK、触摸 T_CLK |
| D23 | 屏幕 SDI/MOSI、触摸 T_DIN |
| 3V3 | 屏幕 LED、SHT40 VCC;只有 J1 桥接供电方案才再接屏幕 VCC |
| GND | 屏幕 GND、SHT40 GND |
显示和触摸共用 SPI(2),但速率不同:显示 10 MHz、触摸 500 kHz,均为 mode 0。驱动在切换速率前释放两路片选,避免一个外设干扰另一个。
5. 配置项目环境、识别芯片和备份
5.1 工具隔离在项目中
本次使用项目内 .venv/ 和 .cache/,未改全局 Python、Shell 配置或系统执行策略。已验证的工具组合是 esptool 4.12.0、mpremote 1.29.0、mpy-cross 1.29.0.post2,固件基于 MicroPython 1.29.0。复现时优先使用项目锁定版本,升级工具后重新验证。
若拿到的是源码而没有虚拟环境,在项目根目录创建环境,安装锁定依赖;这是开发机操作,不是 ESP32 上的命令:
python3 -m venv .venv
mkdir -p .cache/pip .cache/tmp
PIP_CONFIG_FILE=/dev/null PIP_CACHE_DIR="$PWD/.cache/pip" \
.venv/bin/python -m pip install --index-url https://pypi.org/simple -r requirements.lock
./tools/python.sh -m pip check
./tools/python.sh -m esptool version
./tools/mpremote.sh --version
Python 版本须与锁定依赖兼容;本项目初始环境为 Python 3.9。tools/python.sh 固定使用项目解释器,tools/mpremote.sh 使用项目串口工具。不要为了复刻而修改全局 pip 源或全局安装权限。
5.2 找串口、确认芯片
关闭其他串口监视器,同一个端口只交给一个工具使用。
./tools/python.sh -c 'from serial.tools import list_ports; [print(p.device) for p in list_ports.comports() if p.vid is not None]'
把实际端口赋给变量;下面是占位名,不能原样使用:
PORT=/dev/cu.usbserial-DEMO
./tools/python.sh -m esptool --chip auto --port "$PORT" --baud 115200 flash_id
本项目识别到经典 ESP32-D0WD-V3、4 MiB Flash,自动复位正常。Windows 对应端口通常显示为 COMx;如果连串口都没有,先确认 USB 是数据线,再查接口、转串口驱动和端口占用。
5.3 先完整备份,再检查安全状态
以下备份命令适用于已经确认的 4 MiB 经典 ESP32。新建自己的备份目录,不覆盖既有原厂镜像。
mkdir -p backups/first-board
chmod 700 backups/first-board
./tools/python.sh -m esptool --chip esp32 --port "$PORT" --baud 115200 \
read_flash 0x0 0x400000 backups/first-board/factory-4MiB.bin
./tools/python.sh -m esptool --chip esp32 --port "$PORT" --baud 115200 \
verify_flash 0x0 backups/first-board/factory-4MiB.bin
shasum -a 256 backups/first-board/factory-4MiB.bin \
> backups/first-board/factory-4MiB.sha256
./tools/python.sh -m espefuse --chip esp32 --port "$PORT" summary
备份文件应为 4,194,304 字节,设备比对必须成功。完整 Flash 可能包含原程序、Wi-Fi 和其他凭据,应保存在私人目录,不能随教程公开。espefuse summary 只读查看安全启动、Flash 加密和下载状态;不烧写 eFuse、不使用强制绕过参数。
只有确认芯片、容量、安全状态符合普通刷写路径后,才继续。启用了安全启动或 Flash 加密的板子,需要适配原有安全配置的升级方案,不能照搬普通擦除流程。本项目初始板未启用这些功能。
本次曾遇到高波特率读取异常,降低到 115200 后取得并验证完整备份。备份慢几分钟可以接受;本地生成了 SHA-256,并不等于已经与板上内容比对,两个检查各有用途。
6. 首次安装 MicroPython,与日后升级分开
6.1 首次刷入官方通用固件
从 MicroPython ESP32_GENERIC 官方下载页取得与经典 ESP32 匹配的固件。不要把 ESP32-S3、C3 或其他板型镜像混用;本项目没有依赖额外 PSRAM。
以下擦除会替换原程序及板上文件。 仅在上一节备份、比对和安全检查完成后用于首次初始化。把下载文件命名为示例路径,先核对实际来源与版本:
./tools/python.sh -m esptool --chip esp32 image_info firmware/ESP32_GENERIC.bin
./tools/python.sh -m esptool --chip esp32 --port "$PORT" erase_flash
./tools/python.sh -m esptool --chip esp32 --port "$PORT" --baud 115200 \
write_flash 0x1000 firmware/ESP32_GENERIC.bin
./tools/python.sh -m esptool --chip esp32 --port "$PORT" --baud 115200 \
verify_flash 0x1000 firmware/ESP32_GENERIC.bin
官方通用合并镜像在本板的起始地址是 0x1000。这与后面的完整备份、应用单独升级地址不同。
6.2 运行第一个串口测试
源码中已有不操作外设的 examples/hello.py:
./tools/mpremote.sh connect "$PORT" run examples/hello.py
看到运行时信息和连续心跳,说明 USB 串口、下载、MicroPython 运行链路基本可用。这个命令在 RAM 中运行脚本,不等于把它设成开机自启。需要交互时使用:
./tools/mpremote.sh connect "$PORT" repl
按 Ctrl-] 退出。维护工具会中断正在运行的应用,操作结束后短按 EN,恢复正常启动。
6.3 三种镜像不能混用地址
| 内容 | 本项目对应地址 | 使用条件 |
|---|---|---|
| 官方 ESP32_GENERIC 合并安装镜像 | 0x1000 | 首次安装,按官方说明执行 |
| 本项目冻结版应用镜像 | 0x10000 | 只适用于已核对的相同分区布局和该应用产物 |
| 从 0x0 读取的 4 MiB 完整备份 | 0x0 | 恢复完整 Flash,会覆盖当前系统与文件 |
成品日常升级不再执行整片擦除。 本项目后期采用冻结应用,把代码放入固件,保留文件系统中的配网、令牌、触摸校准和界面设置。应用区升级需要核对发布清单、分区边界、SHA-256,写后回读,并确认受保护文件仍一致。不能仅凭扩展名 .bin 推断地址。
7. 点亮屏幕、校准触摸、设置自启
7.1 手动显示测试
先按 8 线方案接屏幕,再运行源码中的显示测试:
./tools/mpremote.sh connect "$PORT" mount peripherals run peripherals/display_test.py
应依次出现纯色,再显示三色色条、白色边框、对角线和 TL/TR/BL/BR 四角文字。此处要看实物;串口显示“写入完成”不能证明屏幕已经响应。
mount peripherals 只把外设子目录临时挂载给板上测试,避免挂载整个项目及私人备份。挂载运行不会安装程序;拔掉电脑后,主机上的脚本不会自动跟着运行。
7.2 原始触摸、校准和画点
补齐五根触摸线后依次运行,每项结束再做下一项:
./tools/mpremote.sh connect "$PORT" mount peripherals run peripherals/touch_raw_test.py
轻压、滑动、松开,应能取得随位置变化的原始坐标。电阻屏需要轻微压力,使用圆润塑料笔尖,不要用尖锐金属。原始轴互换或反向可以由校准修正,但完全没有有效采样不能靠校准解决。
./tools/mpremote.sh connect "$PORT" mount peripherals run peripherals/touch_calibrate.py
按提示完成 3 个校准点,再完成 2 个独立检查点。每点按住约半秒并松开,等待目标换位。两个检查点都通过后才保存,因此总共看到五个十字,但不是五点拟合。
./tools/mpremote.sh connect "$PORT" mount peripherals run peripherals/touch_draw_test.py
在中央与四边划线,绿色点应跟随笔尖,松手后停止新增。本次实物通过了这个检查。
校准工具首先把文件写到主机的 peripherals/touch-calibration.json。正式运行还须安装到板上的 /touch-calibration.json:先备份旧文件,上传暂存文件,验证哈希、屏幕宽高与旋转,再原子替换,重启后复核。不要把另一个人的校准系数当作通用值。更改屏幕方向或更换面板后应重新校准。
7.3 开机自启与成品安装
MicroPython 正常启动会执行板上根目录的 /main.py。早期我们用它自动显示色条;看板完成后,已关闭每次开机色条自检,改为直接进入配网和看板。诊断测试保留为手动入口。
对于刚刷好的空白板,可先做一个仅显示测试图的自启练习。先在主机新建 examples/main_display_demo.py:
from display_test import main
main()
在尚无 /lib/ 的空白板上创建目录,再安装显示依赖与入口;已有该目录时跳过创建,不要删除重建:
./tools/mpremote.sh connect "$PORT" fs mkdir :/lib
for module in board board_config ili9341 spi_bus; do
./tools/mpremote.sh connect "$PORT" fs cp "peripherals/lib/$module.py" ":/lib/$module.py"
done
./tools/mpremote.sh connect "$PORT" fs cp peripherals/display_test.py :/lib/display_test.py
./tools/mpremote.sh connect "$PORT" fs cp examples/main_display_demo.py :/main.py
重启后不连主机挂载也能显示,才算持久安装成功。该练习只说明自启原理,不适合覆盖已有成品的入口。
完整成品还需要字体、HTTPS 信任材料、触摸校准、网络与看板模块。本项目最终使用与 MicroPython 版本匹配的冻结版固件,其入口源码为 peripherals/main.py。复刻完整成品应取得对应发布清单和安装流程,不能只把这一份入口复制到空板,就期待所有功能出现。
已运行冻结版时,往 /lib/ 复制同名 .mpy 也不一定覆盖冻结模块;应按该版本的加载顺序和升级方式操作,避免源码、字节码和固件混用。
8. 手机配置 Wi-Fi 和接口地址
正常开机显示网络状态,设备会开放配置热点。最新版本也可从触摸菜单“设置 → 手机配网”重新开放热点,换网络环境时不需要拆线。
- 手机连接屏幕显示的
ESP-Setup-XXXXXX,密码使用屏幕KEY,不要把它当作家中 Wi-Fi 密码。 - 提示“无互联网”时继续连接,在浏览器地址栏输入
http://192.168.4.1。没有自动弹窗也能手动打开。 - 扫描或输入自己的 2.4 GHz Wi-Fi,填写密码。不要把 5 GHz 网络当成这块经典 ESP32 的可用目标。
- 填写完整摘要地址,例如
https://api.example.com/api/v1/dashboard。云端未部署时可先留空,先验证 Wi-Fi。 - 在手机本地填写这块开发板专用的设备令牌。
- 点击“保存并连接”,等页面明确显示连接并保存成功,屏幕出现
CONNECTED/ IP 后,再切回日常 Wi-Fi。
试连成功才保存,错误密码或超时不会覆盖原先可用配置。设备试连可能切换无线频道,手机临时离开热点时需重新连接。
对于已有配置,同一接口地址下令牌留空会保留原值;换接口地址而令牌留空会清除原令牌,因此迁移服务时要填写新服务的设备凭据。带令牌的公网接口必须用 HTTPS,令牌不放在 URL 查询参数里。
连接成功后的配置热点会按窗口关闭;错过窗口可短按 EN,或从触摸菜单重新开启。旧网络找不到时也可重新配网。BOOT 不负责清除网络。
Wi-Fi 在线 只说明接入了无线网络;还要取得合法业务摘要,才能认为接口正常。页面显示“地址已保存”也不代表云端鉴权、数据库或采集已经通过。
9. 云端架构:让 ESP32 只取小摘要

最初考虑过 VPS,最后采用 Cloudflare Workers + D1 + 静态网页。它把几类工作分开:
| 角色 | 主要职责 |
|---|---|
| Windows / Mac 采集器 | 使用当前用户的 Codex 登录状态,读取额度与 Token 元数据并上报 |
| Worker | 鉴权、去重、选择有效来源、检查网站、生成小摘要、处理设置与环境数据 |
| D1 | 保存最新状态、网站配置、版本、温湿度历史等 |
| 登录网页 | 展示详细数据、修改网站列表、查看趋势和远程设置 |
| ESP32 | 拉取摘要、显示、触摸、读取传感器、上传读数和设置回执 |
板端摘要限制在 4 KiB 内,避免把网页历史、完整重置卡明细或大型响应直接塞进开发板。人看的网页可以有更多信息,设备用的 API 保持紧凑。
这块板的 4 MiB 是 Flash,不是可以随意分配的运行内存。完整 240×320 RGB565 帧缓冲就要 240×320×2 = 153,600 字节,约 150 KiB,还没算 TLS、Wi-Fi、Python 对象和字体。本项目使用分块绘制、位图字库和冻结模块,HTTPS 请求串行执行,避免同时申请多份大缓冲。
本地 60 点趋势使用定长数组,数据区约 480 字节;这不包含对象和绘图等额外开销。动态数字、翻页、小曲线能运行,连续全屏动画、大图和多路并行 TLS 则会明显提高内存压力。
三种凭据各管各的事
| 凭据 | 放在哪里 | 用来做什么 |
|---|---|---|
| 采集器令牌 | Windows / Mac 本机私人配置 | 上报该设备的 Codex 数据 |
| ESP32 设备令牌 | 手机配网输入,板上配置保存 | 读取摘要;显式授权后可上传自身环境数据和设置回执 |
| 网页用户名 / 密码 | 本人密码管理器或本地私人文件 | 登录人类使用的管理网页 |
Cloudflare 的 Wrangler 登录授权属于部署权限,与上述业务凭据不同。屏幕不保存 Cloudflare API Token,也不保存 Codex 登录凭据。历史文件里的 reader / “只读令牌”命名表示设备角色;环境写入、设置回执需要额外明确授权,不会因此获得任意管理权限。
10. 在自己的 Cloudflare 部署网页和 API
这一章操作的是复刻者自己的账号和服务。需要完整项目中的 cloudflare/、tools/ 和相关发行文件;命令不是只有本 Markdown 就能独立执行。不要复制原作者的账户 ID、域名配置、OAuth 缓存或 private/。
10.1 准备账号、域名和本地工具
准备一个自己控制、已接入 Cloudflare 的域名,例如以 example.com 表示它;这只是保留示例域名,实际操作必须替换成自己的。
建议拆成两个入口:
| 示例入口 | 用途 |
|---|---|
https://dashboard.example.com/ | 登录网页,手机和电脑浏览 |
https://api.example.com/ | ESP32 和桌面采集器使用的稳定 API |
两者可以路由到同一个 Worker。修改网页布局或入口时,设备 API 地址可以保持稳定。
在项目根目录执行;tools/npm.sh 会自动进入 cloudflare/,将 npm 和 Wrangler 缓存放在项目中:
./tools/npm.sh ci
./tools/npm.sh exec -- wrangler login
按官方 OAuth 流程在正常浏览器中登录并授权。内置浏览器打不开时,可以使用已登录的 Chrome 完成官方授权,无需提取或复制浏览器 Cookie。缺少 Workers Scripts 等必要权限时,在官方授权页补齐。
10.2 创建 D1 并修改自己的部署配置
./tools/npm.sh exec -- wrangler d1 create esp-status-board
将返回的数据库标识填入自己项目的 cloudflare/wrangler.jsonc。配置重点如下;它展示本教程所需内容,项目若还有其他功能配置应按自己的需求保留。
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "esp-status-board",
"account_id": "YOUR_ACCOUNT_ID",
"main": "src/worker.mjs",
"compatibility_date": "2026-07-01",
"workers_dev": false,
"preview_urls": false,
"assets": {
"directory": "./public",
"binding": "ASSETS",
"run_worker_first": true
},
"triggers": { "crons": ["* * * * *"] },
"routes": [
{ "pattern": "dashboard.example.com", "custom_domain": true },
{ "pattern": "api.example.com", "custom_domain": true }
],
"d1_databases": [{
"binding": "DB",
"database_name": "esp-status-board",
"database_id": "YOUR_D1_DATABASE_ID",
"migrations_dir": "migrations"
}],
"vars": {
"BOARD_CONFIG": "{\"selected_account\":\"personal\",\"selected_bucket\":\"codex\",\"sites\":[]}"
}
}
personal 是逻辑账号名,不是登录邮箱。codex 是本项目选定的额度桶标识,应与实际采集和服务配置一致,不能为了让屏幕出现数字而静默换成别的桶。
自定义域名要使用自己账号中有效的域名区域;先处理同名冲突记录。可通过 Wrangler 的 custom_domain 配置或控制台的 Domains & Routes 添加,按 Cloudflare Custom Domains 文档核对要求。
接手已有项目时,还要检查源码中的域名重定向与生成配置文件的默认地址。例如网页迁移跳转、设备初始化工具的默认端点都应改为自己的入口,不能只改 DNS。
10.3 生成独立业务凭据
node tools/init-dashboard-credentials.mjs init
node tools/init-web-dashboard-access.mjs
工具使用随机值生成新安装的凭据,已有凭据则保留,不应靠反复删除文件来“修复”连接问题。
| 本地文件 | 含义与处理 |
|---|---|
private/credentials.json | 原始设备 / 采集器令牌,严禁公开 |
private/auth-config.json | 服务端的令牌哈希及绑定,也按私人配置保管 |
private/worker-secrets.json | 提交 AUTH_CONFIG 的 Secret 文件 |
private/web-dashboard-credentials.json | 网页原始凭据和会话材料,严禁公开 |
private/web-dashboard-secret.json | 网页密码派生值和会话 Secret |
private/web-dashboard-access.txt | 本人查看网页登录信息的文件,严禁公开 |
初始化后必须在本机编辑器把 credentials.json 的 endpoint 改成自己的 API 根地址,例如 https://api.example.com,然后重新执行 init 更新派生文件。当前项目工具保留了原部署的默认地址,复制到新账号时不能沿用。网页访问说明中的地址也应改为自己的网页入口。不要将含真实值的文件内容粘贴到命令行、聊天或教程。
原始业务令牌保留在对应客户端;服务端 AUTH_CONFIG 只保存其哈希和权限绑定。网页使用独立密码派生值与会话密钥,不把业务令牌嵌入公开 JavaScript。
10.4 迁移、部署并配置 Secret
先执行测试与构建预览,再迁移自己的数据库:
./tools/npm.sh test
./tools/npm.sh exec -- wrangler deploy --dry-run --outdir ../.cache/worker-build
./tools/npm.sh exec -- wrangler d1 migrations apply esp-status-board --remote
首次服务需要先存在 Worker 才能上传 Secret,可先部署一次,再提交 Secret 并确认部署结果;缺少认证配置时业务接口应拒绝服务,不能临时去掉鉴权:
./tools/npm.sh exec -- wrangler deploy
./tools/npm.sh exec -- wrangler secret bulk ../private/worker-secrets.json
./tools/npm.sh exec -- wrangler secret bulk ../private/web-dashboard-secret.json
后续只改代码时继续使用正常部署流程;新增表时先执行对应迁移。不要删除 D1 来处理上报异常。D1 入门、数据库迁移和 Workers Secrets可用于核对平台步骤。
10.5 打开环境上传和远程设置权限
对于沿用本项目默认逻辑绑定 esp32 / personal 的安装,已有工具会先迁移、部署,再为这一设备启用环境写入与设置回执能力:
./tools/python.sh tools/deploy-sht40.py --settings
它复用已有令牌,不重新生成;迁移失败则停止,不升级套餐。若修改了设备 ID、逻辑账号或服务名称,先适配工具与配置,再运行,不能将此命令当成任意安装的一键脚本。手工配置时对应能力字段为 environment_write: true 和 settings_sync: true,仅授予需要的设备。
10.6 设置网站监控与确认部署成功
Cron 使用 * * * * *,每分钟运行网站检查;新触发器传播可能需要时间。平台使用 UTC,规则应按 Cron Triggers 文档核对。
登录网页后,在“网站管理”添加自己的 HTTPS 首页或专用健康检查地址,设置名称、预期 HTTP 状态;需要业务级判断时再配置明确的 JSON 契约。当前最多管理 8 个站点。保存到 D1 后以数据库配置为准,初始化 BOARD_CONFIG.sites 不会不断覆盖网页保存的列表。
curl --fail --show-error https://api.example.com/healthz
/healthz 只检查服务存活。完整验收还包括:能网页登录;未授权业务请求被拒绝;采集器首次上报成功;网页能读到更新;ESP32 用自己的令牌获得摘要;网站检查时间前进;环境上传及设置回执成功。healthz=200 不代表 D1、认证、采集和板端都正常。
Cloudflare 的请求、读写和存储额度按实际套餐管理。温湿度历史每 5 分钟才存代表样本,但最新状态、心跳等仍有数据库开销,不能据此认为“每设备只写 288 次/天”。遇到配额限制应查看具体错误和用量,不自动开通付费服务。
10.7 主要接口速查
| 接口 | 使用者 | 用途 |
|---|---|---|
GET /api/v1/dashboard | ESP32 | 小摘要与待应用的显示设置 |
POST /api/v1/collectors/codex | 桌面采集器 | 额度、重置时间和重置卡 |
POST /api/v1/collectors/tokens | 桌面采集器 | 设备 Token 元数据 |
POST /api/v1/device/environment | 授权的 ESP32 | 温湿度与采样时间 |
POST /api/v1/device/settings/ack | 授权的 ESP32 | 设置应用结果 |
POST /api/v1/web/session | 浏览器 | 创建网页登录会话 |
GET /api/v1/web/devices | 已登录浏览器 | 设备连接和环境状态 |
GET / PUT /api/v1/web/sites | 已登录浏览器 | 管理网站列表 |
所有公网业务访问使用 HTTPS。客户端令牌使用 Authorization 请求头;网页登录使用安全会话 Cookie。不要通过 URL 携带令牌,也不要将带真实认证信息的请求原文作为公开排障截图。
11. Windows / Mac 采集器:登录后后台运行
11.1 选择正确的包
| 电脑 | 选择的架构 |
|---|---|
| 普通 Intel / AMD Windows | windows-amd64,也常称 x64 |
| Windows ARM | windows-arm64 |
| Apple Silicon Mac | darwin-arm64 |
| Intel Mac | darwin-amd64 |
发行包包含采集程序、安装管理脚本和说明,不包含 Codex 程序、账号登录态、业务令牌或真实服务配置。仅做交叉编译不能代替目标系统实测。
维护者有匹配源码与 Go 环境时,可以在项目根目录构建四种发行包:
./tools/build-dashboard.sh collector
产物放在 dist/codex-collector/。构建本身不会替开发机注册后台任务。
11.2 Windows 第一次安装
- 在当前 Windows 用户下安装并登录官方 Codex CLI。
- 完整解压匹配架构的采集器 ZIP,不在压缩包预览窗口内运行。
- 双击
start.cmd,填写自己服务的上报地址,例如https://api.example.com/api/v1/collectors/codex。 - 填写对应设备 ID、逻辑账号和专属上报令牌。本项目默认用
windows-main/personal;它们须与服务端绑定一致。 - Codex 路径先让向导查找;手动选择时必须是实际的
codex.exe,不能选择 npm 生成的codex.cmd或codex.ps1。 - 等待首次读取、上传和后台运行检查成功,再确认安装完成。
专属令牌从自己服务生成的 private/credentials.json 对应 collector 条目取得,通过本地向导输入。不要使用 ESP32 的设备令牌、Cloudflare 部署令牌或其他账号的凭据。也不要让所有电脑共用一份设备身份。
安装器会注册当前用户的登录任务 ESP-Codex-Collector。可以在 Windows“任务计划程序 → 任务计划程序库”看到它,触发器为当前用户登录;无需再手动创建每分钟启动一次的任务。
程序与脚本安装在 %LOCALAPPDATA%\ESP-Codex-Collector\bin,私人配置保存在上一级目录。使用已经登录 Codex 的同一个普通用户即可,不以管理员运行作为默认解决办法。
11.3 查看状态、升级与停止
在完整解压的发行目录打开 PowerShell:
powershell -NoProfile -ExecutionPolicy Bypass -File .\status.ps1
额度部分 code 为 ok、last_upload_at 持续前进,才说明最近上报正常。Token 还要单独查看 token_usage 的状态及覆盖情况,不能用额度成功代替 Token 完整。
已有安装升级时,完整解压新版到新目录,使用原用户双击:
upgrade.cmd
升级器会保留原配置、令牌与身份绑定,暂存新程序、备份旧版、停止旧实例,再验证新版首次读取和上传。失败时按升级器结果处理恢复,不直接覆盖正在运行的 EXE。start.cmd 是首次安装 / 启动入口,不能代替已有安装的升级入口。
其他常用操作:
# 停止当前实例,保留登录自启配置
powershell -NoProfile -ExecutionPolicy Bypass -File .\stop.ps1
# 重新配置
powershell -NoProfile -ExecutionPolicy Bypass -File .\install.ps1 -Configure
# 卸载自身任务与程序;按脚本说明处理保留的私人配置
powershell -NoProfile -ExecutionPolicy Bypass -File .\uninstall.ps1
这里的 ExecutionPolicy Bypass 只影响这次 PowerShell 进程,不要求修改全局执行策略。若旧版出现 Set-Acl / SeSecurityPrivilege 错误,使用已修正的新版安装包;新版只设置所需目录访问权限,不申请审计特权。
11.4 每分钟上报,锁屏和睡眠有什么差别
当前发行版的周期固定为 60 秒:进程启动立即采集一次,之后由内部循环每 60 秒开始一轮;不会并发叠加多轮,当前没有向导中的自定义间隔选项。上传失败通常等下一轮重新采集并上传,不在本轮无限重试。
| 电脑状态 | 能否继续采集 |
|---|---|
| 锁屏,但系统仍醒着、用户未退出 | 可以 |
| 仅关闭显示器,系统仍醒着 | 可以 |
| 睡眠、休眠、关机 | 不可以 |
| 退出该 Windows 用户 | 当前用户后台任务不持续运行 |
| 唤醒后 | 读取当前状态,不补跑每一轮积压任务 |
因此屏幕显示“几十分钟前上报”时,要先检查采集电脑是否睡眠。不要把“登录任务”理解为无人登录时也持续运行的 Windows 系统服务。
11.5 Mac 作为偶尔使用的补充来源
Mac 对应入口为 start.command,状态为 status.command,停止为 stop.command,卸载为 uninstall.command。安装后通过用户 LaunchAgent local.esp.codex-collector 运行,同样依赖登录用户和系统清醒状态。
Windows 为优先来源,Mac 为后备来源:服务端选择新鲜且成功的数据;优先来源失效或超过配置有效期后,才使用新鲜后备数据。两台电脑必须确认为同一实际 Codex 账号才能绑定同一逻辑账号。额度不相加,账号身份改变也不自动合并。
12. 额度、Token 和“上报时间”如何正确显示
12.1 额度窗口由实际数据决定
本项目曾固定放置五小时和七天两个区域,后改成按真实返回窗口展示:
| 接口实际情况 | 屏幕行为 |
|---|---|
| 只有七天窗口 | 只显示七天额度,不占用五小时区域 |
| 返回两个窗口 | 显示对应的两个窗口及各自重置时间 |
| 没有可用窗口 / 读取失败 | 显示等待、未知或保留的最近有效值,并说明状态 |
没有返回五小时窗口,只能说明此次没有该窗口信息,不能据此写成“无限额度”。额度大字显示的是剩余百分比,不是剩余 Token 数量。后来按实际观看体验移除了进度条,把空间给数字、时间、Token 和网站。
重置卡数量使用实际返回的可用数量。没有取得数量时显示未知,不写成零;有数量但没有完整到期信息时,应明确“时间未提供”或只展示已知部分。到期时间到达后等待新数据确认,不在看板里自动消费卡或擅自扣减。
12.2 近 30 分钟 Token 的范围
采集器读取可确认账号归属的本机 token_count 元数据,不上传对话正文。服务端按事件时间汇总最近 1800 秒滚动窗口,并去重已接入设备上报的事件。
这表示“已接入设备、能读取到的记录”,不是整个账号所有客户端的实时账单。只安装 Windows 采集器,不会自动取得 Mac 上未上报的活动。
| 数值 | 含义 |
|---|---|
| 输入 Token | 包含缓存输入 |
| 输出 Token | 包含推理 Token |
| 缓存输入 | 输入的子集 |
| 推理 Token | 输出的子集 |
| 总量 | 输入 + 输出,不能把四项全部再相加 |
首次接入从身份绑定后的记录逐步建立覆盖,前 30 分钟可能标记“部分记录”;无法读取、未安装新版或无有效数据时显示等待 / 不可用。成功上传一个包,并不代表时间窗口已经完整。
如果对应版本还提供官方账号用量快照,应与设备日志明细分别理解,不能把账号汇总和设备明细相加,也不能用额度百分比变化倒算 Token。
12.3 三个时间要分开
| 时间 | 含义 |
|---|---|
sampled_at | 采集器取得这份数据的时间 |
reported_at | 服务端收到当前保留成功样本的时间 |
server_time | 这一次服务端生成响应的时间 |
屏幕用成功样本的 reported_at 显示“X 分钟前上报”。即使 ESP32 刚刚成功请求接口,只要服务端仍返回旧样本,这个年龄也不能归零。重复提交和失败心跳也不能刷新最后成功样本的时间。
按本次选择,过期后保留最近额度数值,同时显示真实年龄和接口状态。这样能看见最后状态,也能判断数据是否值得信任。
13. 配色、布局和触摸如何融入看板

四种配色与四种布局可独立组合,图中只展示其中四种搭配:
| 配色 | 布局 | 更适合的场景 |
|---|---|---|
深海蓝 ocean | 分栏 split | 额度与重置卡分区明确 |
纸白绿 paper | 总览 ledger | 浅色、文字信息集中 |
炭黑琥珀 amber | 大字 focus | 抬眼看剩余额度 |
雾蓝灰 mist | 清单 list | 同时看更多网站 |
页面不再保留大块“状态看板”标题。顶部留给温湿度与重置卡,额度使用醒目的数字,中间放 Token,下方放网站;底栏用小字展示 Wi-Fi、API 与上报年龄。
触摸承担进一步查看和设置,不要求把所有信息挤在 240×320 的主页:
| 触摸位置 / 入口 | 操作 |
|---|---|
| 额度区域 | 查看额度、重置等详情 |
| 近 30 分钟 Token 区域 | 查看输入、输出及统计覆盖等明细 |
| 网站相关页面 | 选择站点,查看 HTTP 状态和延迟 |
| 上一页 / 下一页 | 手动翻页 |
| 设置 | 预览配色、布局并应用,修改自动翻页等 |
| 设置 → 手机配网 | 重新开放本地配网入口 |
| 设置 → 温湿度趋势 | 查看本地双曲线 |
触摸按下和松开需要可靠识别,避免长按期间重复触发。测试和正式运行应使用同一几何方向及校准文件。新布局不能只验证“画面画出来了”,还要验证点击区域与视觉位置一致。
14. 读取 SHT40,并让面板与网页一起显示
14.1 先用独立小程序确认真实通信
断电核对 SDA22/SCL21、3V3/GND,再连接电脑。本项目最终在 0x44 取得应答,序列号与测量数据的 CRC 校验均通过。扫描出地址只是第一步,不能代替有效测量。
下面是教学用的独立检查脚本,运行时会中断看板。新建 examples/sht40_check.py,写入以下内容;它不修改配网或校准文件:
from machine import I2C, Pin
import time
def crc8(data):
crc = 0xFF
for value in data:
crc ^= value
for _ in range(8):
crc = ((crc << 1) ^ 0x31) & 0xFF if crc & 0x80 else (crc << 1) & 0xFF
return crc
i2c = I2C(0, sda=Pin(22), scl=Pin(21), freq=100000, timeout=20000)
address = 0x44
addresses = i2c.scan()
print("I2C:", [hex(item) for item in addresses])
if address not in addresses:
raise OSError("SHT40 0x44 not found; check power and wiring")
for _ in range(6):
i2c.writeto(address, b"\xfd")
time.sleep_ms(10)
frame = i2c.readfrom(address, 6)
if crc8(frame[:2]) != frame[2] or crc8(frame[3:5]) != frame[5]:
raise ValueError("SHT40 CRC mismatch")
raw_t = frame[0] * 256 + frame[1]
raw_rh = frame[3] * 256 + frame[4]
t100 = -4500 + (17500 * raw_t + 32767) // 65535
rh100 = -600 + (12500 * raw_rh + 32767) // 65535
rh100 = max(0, min(10000, rh100))
print("T: %.2f C, RH: %.2f %%" % (t100 / 100, rh100 / 100))
time.sleep(5)
运行命令:
./tools/mpremote.sh connect "$PORT" run examples/sht40_check.py
这是针对本项目接线和地址的小程序,不是对所有温湿度模块的通用驱动。不能取得应答时,不继续在未知供电下轮换大量 GPIO;先查物理接线。读数完成后短按 EN,恢复成品看板。
14.2 正式程序的采集与上传
正式程序使用 peripherals/lib/sht40.py,配置集中在 board_config.py:
SHT40_SDA = 22
SHT40_SCL = 21
正式驱动使用有界 I²C 操作、CRC 和数据校验,转换等待期间让出执行机会。每 5 秒读取,只有有效数据才刷新温湿度。断线、CRC 错误、总线超时分别记录状态,不把异常读数写成 0°C / 0%。
| 环节 | 节奏与行为 |
|---|---|
| 本地测量 | 每 5 秒,失败不覆盖上次有效值 |
| 本地过期 | 30 秒没有有效样本时标记过期 |
| 环境上传 | 目标每 30 秒一次,网络失败按策略退避 |
| 网页最新值 | 显示采样时间与状态,超过对应新鲜期标记过期 |
| 上传范围 | 当前读数,不建立离线历史补传队列 |
环境 POST 与看板 GET 复用一个 TLS 通道,各自有调度和退避,不同时握手。目标 30 秒不等于任何网络环境下都保证精确 30 秒到账。
屏幕左上显示当前读数;网页登录后在“设备连接”中查看设备温湿度与采样年龄。已有公开分享视图不新增这些私人环境数据。
15. 温湿度趋势:本地一小时、网页七天

15.1 屏幕的本地趋势
点“设置 → 温湿度趋势”,可以看温度与湿度两张图、当前读数和样本情况;点返回回到看板。进入趋势页后仍持续采集。
本地每分钟保留第一个有效点,最多 60 点,放在 RAM 环形数组里:
- 温度、湿度分别使用自己的纵轴,避免把不同单位混在同一比例上。
- 某分钟没有有效样本就留空,不补零,也不跨缺口画出连续曲线。
- 断电或重启后重新积累,本地一小时记录不写入 Flash。
- Wi-Fi 掉线后仍能读传感器、看本地趋势;云端数据可能停止更新。
15.2 网页的历史趋势
网页登录后选择对应设备的“温湿度趋势”,支持近 1 小时、24 小时、7 天。云端每 5 分钟保存一个有效代表样本,保留 7 天;7 天视图按小时汇总,并标注有效样本数量。
| 视图 | 数据密度 |
|---|---|
| 近 1 小时 | 最多 12 个五分钟代表点 |
| 近 24 小时 | 最多 288 个五分钟代表点 |
| 近 7 天 | 最多 168 个小时聚合桶,取决于已有有效记录 |
它不是每 5 秒保存一次的完整原始曲线,也不会补造启用前或设备断网期间的历史。刚部署时只有少量数据是正常现象,等运行后逐步积累。
16. 远程管理:保存成功不等于设备已应用

ESP32 位于家中局域网,网页无需直接连入它。网页将期望设置保存在 Cloudflare;设备下一次主动拉取摘要时取得新版本,应用并上传回执。
| 可远程设置 | 范围 |
|---|---|
| 配色 | 深海蓝、纸白绿、炭黑琥珀、雾蓝灰 |
| 布局 | 分栏、总览、大字、清单 |
| 网站自动翻页 | 开 / 关 |
| 看板拉取间隔 | 15 / 30 / 60 秒 |
这里的刷新间隔只改变正常状态下板端摘要拉取节奏,不改变 Windows 的 60 秒采集、SHT40 的 5 秒采样、环境上传目标或网站云端检查周期。
操作步骤:
- 登录网页,进入对应设备的“设备设置”。
- 修改配色、布局等,保存后先显示“待同步”。
- 等待设备拉到新版本;设备完成持久保存和显示应用后提交回执。
- 网页显示该版本“已应用”,再观察实物是否一致。
设备离线时保持待同步;保存或应用失败时保留原设置并反馈失败。不能在网页请求返回 200 时就显示“设备已应用”。
版本控制避免两处编辑互相覆盖;重复收到同一版本不会反复覆盖后来在屏幕上做的本地修改,网页再次保存新版本才会再下发。触摸预览期间也不会突然强行切换界面。回执带启动代次与序号,迟到结果不能覆盖较新的状态。
本轮远程管理的范围是显示设置和现有网站管理,没有实现任意远程命令、远程改 Wi-Fi 密码、远程改校准或 OTA 固件升级。网站列表保存在云端,设备读取更新后的摘要即可,不需要为改一个网站重新烧录。
17. 成品使用与展示

这张图是为了说明网页的信息组织,使用重绘布局和演示数据,不是生产后台截图。屏幕配色图和趋势图则由本项目渲染器使用合成数据生成,保留了真实 240×320 排版。
建议最终摆放:屏幕靠左,ESP32 与面包板靠右,USB 向外;SHT40 放在远离热源、能接触室内空气的位置。电源线和 SPI 短线沿底板边缘整理,信号线不要被屏幕或螺柱压住。先电气验收,再粘贴面包板背胶、固定螺柱和底板。
日常抬眼看额度、Token、网站与温湿度;需要细节时触摸进入。外出换网络用手机配网;在电脑上维护网站和显示偏好。屏幕不承担 Codex 登录和大规模历史查询,复杂工作留在电脑与云端。
本次对话中已经确认的验收
| 阶段 | 实际确认结果 |
|---|---|
| 串口与固件 | 识别芯片、自动复位、原固件备份比对、MicroPython 心跳通过 |
| 显示 | 色条、边框与四角文字正常;之后开机自启验证正常 |
| 手机配网 | 用户完成连接并保存,屏幕显示 CONNECTED 和 IP |
| 中文布局 | 真实数据及中文正常,额度和网站新布局文字完整 |
| 触摸 | 校准及画点跟随正常,松开后停止;主题切换和应用正常 |
| SHT40 | 拆壳核对引脚后取得有效 CRC 读数,用户确认温湿度与原看板正常 |
| 趋势与管理 | 曲线、读数和返回正常;远程设置完成真实应用与恢复的往返验证 |
温湿度趋势版本在 2026 年 10 月 27 日的历史验收还包括:Python 与 Node 检查、字节码与原生镜像编译通过;正常运行观察有连续有效采样和多次摘要同步。带只读观察器的运行测试中,最低观测空闲堆约 66 KiB,这只是当时场景的测量值,不是可供任意新功能消耗的固定余量。
本节记录历史验收,不表示文档生成时重新对开发板或云服务执行了测试。本次整理没有刷写设备、修改生产配置或重新部署服务。
18. 故障排查:按现象缩小范围
18.1 屏幕白屏,但背光亮
白屏只说明背光和部分供电可能存在,不证明 SPI 初始化成功。按以下顺序检查:
- 断电核对屏幕 VCC、J1 和 GND;LED 亮不能证明屏幕逻辑供电正确。
- 核对
CS27 / RESET25 / DC26 / MOSI23 / SCK18,按丝印追到对应 GPIO。 - 检查面包板是否跨了中槽、错了一行,开发板排针下方是否接触可靠。
- 暂时断开新增模块,恢复已经验证过的最小显示接线。
- 运行手动显示测试;必要时降低 SPI 速率做对照,每次只改一个因素。
本次重新布局后即使拔下 SHT40,屏幕也曾持续白屏,因此不能单凭“刚加传感器”就认定它是原因。应分别验证显示链路和 I²C 链路。
18.2 触摸没反应,显示却正常
显示和触摸是两个片选不同的设备。检查 T_CS32 / T_DO19 / T_IRQ33,再检查 T_CLK18 / T_DIN23 的分线;确认 LCD CS 没有与 T_CS 短接。原始测试先要有按下、松开和坐标,再校准;不要直接用大量坐标映射常数掩盖无数据问题。
18.3 SHT40 扫不到或 CRC 错误
先核对实际丝印、观察方向、供电与共地,再核对 SDA22 / SCL21。壳上没有丝印时查匹配资料,不凭线色猜。
若怀疑模块把总线拉低,断电后断开模块再测试空载引脚,区分 ESP32 / 面包板 / 线材与模块。没有万用表时可以做受控连通验证,但必须由明确的输入模式、限流或供电检查方案指导,不能任意把电源和 GPIO 短接。无法确认供电时,借用万用表比继续猜线更有效。
有地址但 CRC 错误,要检查接触、线长和总线干扰;不能忽略 CRC 后把随机字节当温湿度。SHT40 接好不代表立刻有云端历史,先看本地有效测量,再看上传与历史。
18.4 Wi-Fi 在线,但“接口失联”
先把问题分成两段:电脑 → 云端,以及 ESP32 → 云端。
| 观察 | 下一步 |
|---|---|
| 网页上的最后采集也在变旧 | 检查电脑是否睡眠、采集器状态、Codex 登录和上传错误 |
| 网页采集持续更新,只有屏幕失联 | 查板端 DNS、TCP、TLS、HTTP、鉴权与响应处理 |
/healthz 正常,业务仍失败 | 查 Secret、D1、迁移、配额与具体业务错误 |
| 401 / 403 | 检查对应角色令牌和权限,不靠高频重试解决 |
| 429 / 503 | 查看限流或平台状态,遵守 Retry-After |
| 网站仍在翻页、时间年龄继续增加 | 主界面循环仍在运行,重点查网络任务和数据新鲜度 |
本次“接口失联但网站继续翻页”的现象,说明不能直接归因于整个主循环卡死。也不能只凭 1 A 充电头就认定供电故障。可保持位置、Wi-Fi 和 USB 线不变,仅切换供电,记录复现情况;多变量同时变化会失去判断依据。
最终网络方案使用分阶段超时、整轮截止、DNS 短缓存和备用解析、至多两个地址顺序尝试,以及独立退避。临时失败大致按 3、8、15、30 秒等待并加入少量抖动;持续失败维持退避,权限或证书问题采用较长等待。请求取消后先完成清理再启动下一轮,不堆积握手或不断重启整块板。
网络恢复后会再次同步,但不会把旧成功样本伪装成刚刚上报。
18.5 明明一直采样,却出现时间顺序冲突
这是本次长期测试遇到的一处有代表性的细节:经典 ESP32 的该 MicroPython 构建使用单精度浮点,直接把约十亿量级的 Unix 秒转换为浮点运算,会丢失秒级精度。不同采样可能得到相同时间,服务端因而拒绝乱序 / 冲突数据。
不应这样计算大时间戳:
# unix_now 是大整数,age 是浮点时,会引入大数的浮点舍入
sampled_at = int(unix_now - age)
本项目将小范围经过时间先处理成整数,再与整数 Unix 时间相减。示意如下:
age = mono_now - sampled_mono
age_seconds = int(age)
if age > age_seconds:
age_seconds += 1
sampled_at = int(unix_now) - age_seconds
这里假定 unix_now 本来就是校验过的整数,且 age 非负。完整程序还要处理时钟回退、重启和错误状态。温湿度显示中的小数运算范围很小,并不等于所有浮点运算都不能使用。
18.6 网页修改后设备没有变化
先看“待同步 / 已应用 / 失败”,再查设备是否在线、是否拉取了新版本、是否有设置同步权限,以及是否完成了对应版本回执。查看触摸预览是否仍未退出。本地修改后同一云端版本不会反复覆盖,这是保留本地操作的设计;需要网页再次保存新版本。
19. 验收、维护和公开分享
19.1 从最小功能逐步验收
- 物料型号、供电和 GPIO 定义已确认,USB 串口能识别。
- 原固件完整备份、设备比对与安全状态检查完成。
- 官方 MicroPython 和串口心跳通过。
- 仅接屏幕时,颜色、四角和边框正常。
- 触摸有原始数据,校准和画点正常,校准文件已持久安装。
- 无需主机挂载,重启后自动进入配网 / 看板,日常不再跑色条自检。
- 手机配网成功,错误配置不覆盖旧设置。
- Cloudflare 认证、数据库、网站定时检查和业务接口逐项验证。
- 采集器首次上传、登录后台运行、状态查询与升级验证通过。
- 没有返回的额度窗口隐藏,未知值不变零,上报年龄真实。
- SHT40 有连续 CRC 有效样本,面板和登录网页都能看到。
- 本地趋势能进入和返回,网页历史逐步积累,缺样不补造。
- 网页设置先待同步,设备应用回执后才显示已应用。
- 最后再做固定、理线和更长时间的独立供电观察。
19.2 升级前保留哪些东西
| 内容 | 为什么要留 |
|---|---|
| 完整 Flash 备份与 SHA-256 | 出现升级问题时有可核对的原始恢复点 |
/config/network.json、/config/setup.json | Wi-Fi、接口和配置热点身份,包含私人信息 |
/touch-calibration.json | 这块面板的几何校准 |
/dashboard-ui.json | 本地显示偏好与已应用的远程版本 |
/dashboard-ui.json.generation | 设置回执使用的持久启动代次,不手工删改或跨设备覆盖 |
| 已安装版本与发布清单 | 判断固件、字体、字节码和分区是否匹配 |
云端 D1 与本地 private/ | 数据、身份、权限和客户端凭据分别备份 |
冻结版升级前做当前状态备份,升级后校验应用区及保留文件,不只保留很早的原厂备份。不要靠清空文件系统解决普通网络故障,也不要把配置 / 状态文件从另一块设备直接覆盖过来。
凭据轮换采用“增加新凭据 → 更新对应设备 → 验证成功 → 撤销旧凭据”的顺序。共享源代码时检查 .gitignore 并不够,打 ZIP 也必须使用明确文件清单,不能直接压缩整个工作目录。
19.3 教程公开前的隐私检查
- 使用保留示例域名,移除真实主页、API 与后台地址。
- 不公开 SSID、热点 KEY、Wi-Fi 密码、网页登录信息或任何令牌。
- 不包含 Cloudflare account ID、D1 database ID、OAuth 缓存和私钥。
- 实拍去掉设备 MAC / 二维码、电脑用户名、桌面通知、订单和其他个人环境信息;无法确认时使用重绘示意。
- 额度、Token、重置卡和温湿度都使用明确的演示数据,不能把画面当作实时账号状态。
- 排除
private/、backups/、配置快照、原始调试响应与含真实数据的报告。
本教程采用重绘接线 / 布局图和合成数据渲染,未收录原始个人照片;公开范围仅为这份 Markdown 与配套八张 PNG。
附录 A:项目文件地图
以下是完整项目中的主要入口,帮助找到代码;它们不是教程 ZIP 的额外附件。
ESP/
├── requirements.lock # 项目 Python 依赖
├── examples/hello.py # 最小串口测试
├── peripherals/
│ ├── main.py # 正式启动入口源码
│ ├── display_test.py # 手动显示诊断
│ ├── touch_raw_test.py
│ ├── touch_calibrate.py
│ ├── touch_draw_test.py
│ ├── touch-calibration.json # 本机生成,勿当通用标定
│ └── lib/
│ ├── board_config.py # GPIO 与屏幕几何
│ ├── board.py / spi_bus.py # 共用 SPI 与设备初始化
│ ├── ili9341.py / xpt2046.py
│ ├── calibration.py
│ ├── dashboard_model.py # 状态和显示语义
│ ├── dashboard_async.py # 异步 HTTPS 与超时
│ ├── dashboard_screen.py # 绘制
│ ├── dashboard_ui.py # 布局与页面状态
│ ├── sht40.py # CRC 温湿度驱动
│ ├── environment_history.py # 本地趋势
│ └── device_settings.py # 远程显示设置
├── dashboard/ # Go 桌面采集器与安装器
│ └── packaging/
├── cloudflare/
│ ├── wrangler.jsonc # 使用自己的部署配置
│ ├── src/worker.mjs # API、鉴权和路由
│ ├── migrations/ # D1 版本迁移
│ └── public/ # 登录网页资源
├── tools/ # 隔离启动器、构建与部署工具
├── private/ # 私人凭据,不分发
├── backups/ # 私人备份,不分发
└── dist/ # 发行产物
源码包含上游驱动时保留其许可证与来源信息。本项目显示驱动来自 rdagger/micropython-ili9341,项目内锁定了具体版本;不要用随手下载的最新版替换后跳过兼容性验证。
附录 B:八张配图与文件打包方式
| 文件 | 用途 |
|---|---|
assets/finished-layout.png | 亚克力底板上的建议摆放,非成品实拍 |
assets/breadboard.png | 面包板连通关系 |
assets/shared-buses.png | SPI 与电源一对多分线 |
assets/architecture.png | 电脑、云端与设备数据流 |
assets/screen-themes.png | 四种配色 / 布局的演示渲染 |
assets/screen-trends.png | 本地温湿度趋势演示渲染 |
assets/remote-settings-flow.png | 设置下发与真实回执过程 |
assets/web-dashboard-demo.png | 网页功能结构示意 |
保存、转移或发布时,将 Markdown 与 assets/ 放在一起,保留相对位置:
ESP32看板教学文档/
├── ESP32触摸屏看板制作教程.md
└── assets/
└── 八张配图.png
大多数 Markdown 编辑器会自动显示相对图片;发布到代码托管平台或博客时,连同图片目录上传。教程中的域名、串口和配置占位值需要替换后才能用于实际部署。
附录 C:官方资料与进一步阅读
以下外部页面用于核对平台和硬件步骤,平台界面及版本可能变化;项目已经验证的引脚与版本以本文对应源码和发布说明为准。
从零制作 ESP32 触摸屏状态看板
https://java.li/archives/espcZZqUK9B
评论