ESP32 · 4.2" 三色墨水屏固件 · 最后一次烧录版
AI 墨水屏固件
业务逻辑全解
台历页课程表页天气页
专业版业务逻辑 + 大白话业务逻辑 + 术语对照表
固件版本:fix16 系列(main.cpp @ 2026-08-19 21:44)· 编译目标 pio run -e z98
← → 翻页 · 章节快捷跳转 · 手机左右滑动
Overview · 设备与固件总览
它是什么:一台会自己醒来的电子台历
深度睡眠省电版 · 三屏轮换 · 自动配网 · 断电不丢数据
硬件平台
主控:ESP32(4MB Flash),4.2" 三色墨水屏 SSD1683 / GDEY042Z98
接线:SPI —— CS=5 / DC=17 / RST=16 / BUSY=4 / SCK=18 / MOSI=23
按键 GPIO14(低电平触发,兼深度睡眠唤醒)· 红灯 GPIO22
电池 1000mAh + USB 串口芯片,目标数周一充
软件栈:Arduino + GxEPD2 + OneButton + WiFiManager + ArduinoJson + Preferences(NVS)
接线:SPI —— CS=5 / DC=17 / RST=16 / BUSY=4 / SCK=18 / MOSI=23
按键 GPIO14(低电平触发,兼深度睡眠唤醒)· 红灯 GPIO22
电池 1000mAh + USB 串口芯片,目标数周一充
软件栈:Arduino + GxEPD2 + OneButton + WiFiManager + ArduinoJson + Preferences(NVS)
三屏显示
01 台历页 —— 周一为首,农历/节气/干支生肖,今日红框,周末红标
02 课程表页 —— 美丽沙九小 四(16)班 真实课表 5×6,今日列红高亮,顶部带天气
03 天气页 —— 三色气象志:大号红温度、四格参数、未来 N 日预报、日出日落
02 课程表页 —— 美丽沙九小 四(16)班 真实课表 5×6,今日列红高亮,顶部带天气
03 天气页 —— 三色气象志:大号红温度、四格参数、未来 N 日预报、日出日落
状态持久化 —— RTC 内存(深睡保留):显示模式 g_mode / 已绘日期 g_lastDayKey / 上次联网时刻 / 上次失败时刻
· NVS 闪存(断电保留):WiFi 已知网络表(≤5 条,多地点切换)· OWM 天气配置 · 最近一次天气缓存
PRO 专业版 · 一、整体骨架
一条主循环:唤醒 → 判断原因 → 干活 → 再睡
setup() 末尾必然进入深度睡眠,loop() 从不执行 —— 一切逻辑都发生在「被唤醒之后」
TIMERA · 定时唤醒
每 15 分钟 / 夜间 1 小时自动醒
轮换页面 + 每小时限一次的联网更新
轮换页面 + 每小时限一次的联网更新
EXT0B · 按键唤醒
GPIO14 低电平触发
4 秒交互窗口识别 单击 / 双击 / 长按
4 秒交互窗口识别 单击 / 双击 / 长按
POWERC · 上电 / 复位
拔电重插、配网保存后重启
验收卡 → 三级联网 → 对时刷天气
验收卡 → 三级联网 → 对时刷天气
↓↓↓ 三种唤醒,殊途同归
干完活 → display.powerOff()(墨水屏断电保图)→ ledSet(LED_OFF) → 计算下次唤醒 → esp_deep_sleep_start()
白天 900s / 夜间 3600s 定时唤醒 + 按键 ext0 双保险;RTC 内存保住模式与状态,醒来无缝继续
白天 900s / 夜间 3600s 定时唤醒 + 按键 ext0 双保险;RTC 内存保住模式与状态,醒来无缝继续
关键:墨水屏是「记忆型」显示 —— 断电后画面不消失,所以睡眠期间屏幕保持最后一帧,唤醒只需重绘新内容。
PRO 专业版 · 二、三种唤醒分支
定时 / 按键 / 上电:各自做什么
依据 esp_sleep_get_wakeup_cause() 分流,互不干扰
A定时唤醒
① 联网闸门:距离上次联网 ≥ 1h 且非失败退避期,才尝试连 WiFi(8s 超时)
② 成功 → 清失败标记 → NTP 对时 → 刷新天气缓存 → 记录跨天日期
③ 失败 → 记录失败时刻,未来 6h 不再尝试(防离线时反复白耗电)
④ 夜间(23:00~07:00,需时钟可信)→ 驻留课表页,只保数据不翻页
② 成功 → 清失败标记 → NTP 对时 → 刷新天气缓存 → 记录跨天日期
③ 失败 → 记录失败时刻,未来 6h 不再尝试(防离线时反复白耗电)
④ 夜间(23:00~07:00,需时钟可信)→ 驻留课表页,只保数据不翻页
B按键唤醒
① 补偿机制:唤醒瞬间按键已释放 → 补记一次单击(保证首按生效)
② 进入 4 秒交互窗口,逐帧喂 OneButton 状态机
③ 单击 → 切换模式 + 立即重绘(离线也切屏),联网为附加动作
④ 双击 → 开配网 AP + 屏显配网提示,最长 180s
⑤ 长按 3s → 恢复出厂
② 进入 4 秒交互窗口,逐帧喂 OneButton 状态机
③ 单击 → 切换模式 + 立即重绘(离线也切屏),联网为附加动作
④ 双击 → 开配网 AP + 屏显配网提示,最长 180s
⑤ 长按 3s → 恢复出厂
C上电 / 复位
① 先画「验收卡」(硬件到手首日验证屏,不依赖网络)
② provisionConnectOrPortal() 三级联网(见右)
③ 连上 → 对时 + 刷天气 + 画当前模式;失败 → 慢闪灯 + 配网提示页
④ 深睡,等下次唤醒
② provisionConnectOrPortal() 三级联网(见右)
③ 连上 → 对时 + 刷天气 + 画当前模式;失败 → 慢闪灯 + 配网提示页
④ 深睡,等下次唤醒
C-2三级联网
① 已知网络表:NVS 里最多 5 条 WiFi 逐个试(每条 ≤8s)→ 换办公室自动切换
② 预置家庭 WiFi「410」(编译期注入,2.4G,≤10s)
③ 都失败 → 开 WiFiManager 配网 AP「墨水屏-Setup」,阻塞 ≤180s
② 预置家庭 WiFi「410」(编译期注入,2.4G,≤10s)
③ 都失败 → 开 WiFiManager 配网 AP「墨水屏-Setup」,阻塞 ≤180s
PRO 专业版 · 三、定时唤醒(重点)
15 分钟轮换 × 每小时联网 × 夜间驻留 × 失败退避
这是省电与实时性的核心博弈点
TIMER 唤醒
esp_deep_sleep 自动恢复
联网闸门判定
≥1h 且非 6h 退避
连 WiFi
8s 超时 wifiEnsure
成功 → 对时+刷天气
NTP / OWM dt updateWeather
失败 → 记退避
s_lastNetFail 6h 不试
日夜分流
23-07 夜停课表 · 白天 +1 轮换
重绘 → 深睡
powerOff 900s/3600s
定时唤醒期间不发按键逻辑,纯自动化流水线 —— 人不在旁边,机器也要自己把日子过对。
每小时联网一次
s_lastNetFetch 记录「尝试时刻」| 成败都记录 → 网络异常时不至于每 15 分钟重试 | 成功抓天气后才写 NVS(≤1 次/小时)
失败 6h退避
s_lastNetFail 记录失败时刻 | 退避期内跳过联网闸门 | 避免离线环境每小时白耗 8s 射频
夜间驻留课表页
validTime 闸门:时钟 <2024 一律当白天 | 防 1970 假时间 →「永久夜间」冻结轮换 | 夜间 1h 醒一次,只保数据不翻页
PRO 专业版 · 四、按键交互
一个按钮,三种手势,四秒窗口
OneButton 事件 → ISR 置位 g_btnReq → 主流程消费,不在中断里干重活
1
单击 REQ_REFRESH —— 切换模式
g_mode = (g_mode + 1) % 3,立即重绘(离线也切屏,先给可见反馈)| 再尝试 8s 内联网:成功 → NTP 对时 + 刷天气 + 用新数据重绘 | 联网失败不阻塞、不回滚 —— 留给下一轮定时唤醒
2
双击 REQ_CONFIG —— 进配网 AP
startConfigPortal() 非阻塞开 AP「墨水屏-Setup / 12345678」| 屏上立刻画「配网提示」(含红块调侃文案)—— 双击不像没反应 | 180s 窗口:成功保存 WiFi → ESP.restart() 干净重启;失败/超时 → 关 AP+射频 → 重绘当前页
3
长按 3s REQ_RESET —— 恢复出厂
wm.resetSettings() + 清已知网络表 + 清整个 NVS → ESP.restart() | 所有 WiFi 凭据与天气配置全部抹掉,回到首次开机状态
PRO 专业版 · 五、联网链路
连接 → 对时 → 天气 → 持久化
四条链路串联:WiFi 连接、时间同步(含兜底)、天气拉取与缓存落盘
时间同步 syncTime()
主路径:configTime(UTC+8) → NTP 双服务器(pool.ntp.org / time.nist.gov)| 验证:6s 内连续取时间,年份 ≥ 2025 才认成功
兜底路径:NTP 被路由器/ISP 拦截(UDP 123)时,取天气接口返回的 dt(Unix 时间戳)用 settimeofday() 补上 —— 两条路总有一条通
兜底路径:NTP 被路由器/ISP 拦截(UDP 123)时,取天气接口返回的 dt(Unix 时间戳)用 settimeofday() 补上 —— 两条路总有一条通
天气数据 OWM 2.5
当前天气:/data/2.5/weather(含 dt 兜底对时、日出日落、风向风力换算)| 五日预报:/data/2.5/forecast,3h 粒度 → 按本地日期聚合 hi/lo
「未来 N 日」不含今日:跳过今日日期槽 → 白天 4 天 / 晚间 5 天,列宽自适应 | 配置优先级:配网页填写 > 编译期默认(海口美丽沙)
「未来 N 日」不含今日:跳过今日日期槽 → 白天 4 天 / 晚间 5 天,列宽自适应 | 配置优先级:配网页填写 > 编译期默认(海口美丽沙)
持久化 NVS —— 「AI_INK」命名空间:WiFi 已知网络表(wifi_ssid_N / wifi_pass_N,≤5 条,满则覆盖最旧)+ OWM 天气配置
「wx」命名空间:天气缓存逐字段序列化(WeatherInfo 含 String 动态堆,不能整包 putBytes,否则只存指针)—— 断电/离线唤醒也能显示旧天气
「wx」命名空间:天气缓存逐字段序列化(WeatherInfo 含 String 动态堆,不能整包 putBytes,否则只存指针)—— 断电/离线唤醒也能显示旧天气
PRO 专业版 · 六、省电与恢复设计
把「电」花在刀刃上
深度睡眠为主体,联网/翻页都受节流约束,异常路径全部有退路
☾深度睡眠主循环
墨水屏断电保图(记忆型显示);ESP32 仅保留 RTC,3~5mA 级待机;定时 + 按键双唤醒
⏱唤醒节流
白天 900s 轮换一页;夜间 3600s 停课表页;联网 ≤1 次/h;失败 6h 退避
✓时钟有效性闸门
validTime = 年份≥2024;1970 假时钟一律按白天处理,防止「永久夜间」冻结轮换
◉LED 状态机
FreeRTOS 独立任务:常亮=已联网 / 慢闪=离线 / 快闪=连网中 / 三快闪=配网模式;配网阻塞时仍能闪烁
⚠异常兜底
配网失败直接深睡不重启;天气失败显示缓存;时钟失效按白天;每次联网成败都记账
↻断电恢复
RTC 内存保留模式/日期/节流状态;NVS 保留 WiFi 表与天气缓存;上电先恢复再联网
预期寿命:1000mAh + 15 分钟唤醒节奏 ≈ 5~7 天一充;WiFi 每小时约 8s 是第二大耗电源。
大白话版
说人话:这玩意儿到底怎么工作?
不带技术词,就当给家里人讲一遍这台小屏是怎么活的
大白话 · 一、它是个什么玩意儿
一台会自己醒来的电子台历
大部分时间在睡觉,醒了干点正事,然后又睡 —— 这就是它的全部人生
😴睡觉 = 省电
不干活的时候它就「睡着」(深度睡眠),几乎不耗电。屏幕上的画面断电也不会消失,睡醒直接换新内容。
⏰闹钟叫醒 = 定时器
白天每 15 分钟醒一次:翻一页、顺手看看要不要联网;晚上 11 点到早上 7 点改成 1 小时醒一次,少折腾省电。
🔘按按钮也叫醒 = 按键
你按一下小黑钮它也会醒,听你指挥:翻页、配网、或者恢复出厂。
一句话:它平时躺着,醒了要么自己翻页,要么听你按键,干完活接着躺 —— 躺得越多,电越耐用。
配套装置:旁边那个小红灯 —— 常亮=上网了,慢闪=没网,快闪=正在找网,滴答滴答三下=进配网模式
大白话 · 二、它会翻的三张页面
挂历、课程表、天气预报
翻来翻去就这三张,每张都有自己的用途
1台历页(默认)
跟挂历一模一样:今天是几号、农历几月初几、啥节气、今年是啥生肖、第几周 | 周末和节日标红,今天的格子用红框圈起来
2课程表页
孩子的上课表:周一~周五,一天 6 节课 | 今天星期几,那列就标红;顶上还顺手显示温度湿度和风
3天气页
一整屏天气预报:大号温度、体感、湿度风速气压能见度、日出日落 | 底下还有未来几天的预报,最晚能看 5 天
翻页顺序:台历 → 课表 → 天气 → 又回到台历,循环。半夜自动翻页时,它只停在课程表页 —— 晚上没人看天气,省电。
小细节:课程表和天气页显示的是「上次联网拿到的数据」—— 就算断网,屏幕也不会白着,顶多是旧数据。
大白话 · 三、就一个按钮,三个手势
单击翻页 · 双击配网 · 长按恢复出厂
小黑钮按法不同,它干的事完全不同 —— 记住这三个就行
1
单击 —— 翻一页
台历→课表→天气→台历。先立刻换画面(断网也换),然后偷偷试一下连网:能连上就顺手把时间和天气更新一遍,画得更准。
2
双击 —— 教它认新 WiFi
屏幕会显示「配网模式」和操作说明(还会红底白字调侃你两句「不懂瞎按!手欠!」)。用手机连它开的 WiFi,填好密码它就记住并重启。
3
长按 3 秒 —— 恢复出厂
把它记的所有 WiFi 和设置全部抹掉,回到刚买回来那样。慎用 —— 用完又得重新配网。
贴心设计:深睡后醒来,如果你手已经松开了,它会自动当作「单击」处理 —— 第一次按键永远有效,不用跟它较劲。
大白话 · 四、第一次见面:怎么教它上网
手机三步配网,一次教会,永久记住
换地方也不怕 —— 它最多能记住 5 个 WiFi,家里/办公室自动切换
1 · 双击按钮
屏幕变成「配网模式」提示页
2 · 手机连它开的 WiFi
墨水屏-Setup,密码 12345678
3 · 浏览器填你家 WiFi
页面自动弹出,选网络输密码
4 · 点保存
它自己重启,从此认路
最多记 5 个 WiFi:在家连「410」,带去办公室连办公室的网 —— 它会自己挨个试,哪个通用哪个,不用你手动切。新 WiFi 超过 5 个,最老的那个被顶掉。
三个注意:① 只能连 2.4G 的 WiFi(它不支持 5G,所以别选「410-5G」);② 配网超时 3 分钟没操作,它会自己放弃去睡觉,不白耗电;③ 配网成功后必须等它重启完,别急着拔电。
大白话 · 五、时间准不准、天气哪来的
上网自动对表,天气抄进小本本
你什么都不用管,它自己会过日子
时间:上网对表
连上网自动跟「网络时间服务器」对表,日期小时分都校准 | 如果运营商把对时间的小门(UDP 123)堵了,它会从天气接口返回的时间戳里偷个准点 —— 两条路总有一条通 | 每天过了午夜,台历自动换日期
屏幕上显示「1970-01-01」? = 还没连上网、没对到时间。单击重试联网,或双击重新配网;它自己也会每小时试着对一次。
屏幕上显示「1970-01-01」? = 还没连上网、没对到时间。单击重试联网,或双击重新配网;它自己也会每小时试着对一次。
天气:抄在小本本上
用免费的 OpenWeatherMap 天气接口,位置默认海口美兰美丽沙(想要别的地方,配网页里可以改)| 每小时最多查一次,查到了就「抄进小本本」(机身闪存)—— 断网时显示上次抄的,不会白屏
未来预报不含今天:白天看未来 4 天,晚上 6 点后看未来 5 天 | 原因:免费接口从「此刻」往后算,今天必占一格
未来预报不含今天:白天看未来 4 天,晚上 6 点后看未来 5 天 | 原因:免费接口从「此刻」往后算,今天必占一格
一句话:时间靠网络,天气靠缓存 —— 网络是源头,小本本是保险。
大白话 · 六、为什么能撑一个礼拜
省电全靠「多睡 + 少折腾」
五个省电习惯,换来 5~7 天一充
😴平时躺着
不干活就深度睡眠,待机电流只有几毫安 —— 屏幕断电也不掉画面
⏱️白天 15 分钟才醒一次
醒一次翻一页就接着睡,不赖床
🌙晚上更省
23:00~7:00 改成 1 小时醒一次,且停在课程表页 —— 夜里没人看天气
📵没网不硬试
连不上就记一笔,6 小时内不再折腾 —— 省得离线时每小时白耗 8 秒射频
🔁联网也限次
每小时最多查一次天气,查完抄进小本本,不重复劳动
🔌电用完了怎么办
直接 USB 充电。1000mAh 电池按这个节奏 ≈ 5~7 天充一次
常见问题速查:显示 1970-01-01 → 没网没对时,单击重试/双击配网 · 双击没反应 → 屏上其实有配网提示(还调侃你)· 天气是旧的 → 每小时限一次/失败 6h 退避,属正常
术语对照 · 同一件事,两种说法
专业版 ↔ 大白话版
技术讨论用左边,跟家人解释用右边
专业说法
大白话
深度睡眠 + RTC 定时唤醒
睡觉,用闹钟定时醒
g_mode = (g_mode+1) % MODE_COUNT 轮换
单击翻页,台历→课表→天气→台历
WiFiManager Captive Portal 配网
开个热点,教它认 WiFi
configTime() NTP 对时(UTC+8)
上网跟对表师傅对时间
OWM dt 字段 settimeofday 兜底对时
对表被拦了,偷看天气接口的时间
Preferences NVS 持久化
机身小本本,断电也不忘事
天气缓存逐字段序列化落盘
把天气抄在小本本上,断网也能看
s_lastNetFail 6 小时退避
没网就歇 6 小时,不瞎折腾
ESP_SLEEP_WAKEUP_EXT0 按键唤醒
按按钮把它叫醒
时钟有效性闸门(年份≥2024)
分不清今夕何夕时,就按白天算
drawWeatherIcon 天气图标绘制
画个小太阳/小云朵
RTC_DATA_ATTR 深睡状态保留
睡着也不忘自己翻到第几页
一句话总结
一台会自己醒来的电子台历
睡觉(深睡省电)→ 醒来(定时/按键)→ 干活(翻页 / 联网 / 对时 / 刷天气)→ 又睡
白天 15 分钟一页,晚上睡大觉;上网每小时一次,连不上歇 6 小时;断电失忆靠小本本(NVS)找回记忆。
白天 15 分钟一页,晚上睡大觉;上网每小时一次,连不上歇 6 小时;断电失忆靠小本本(NVS)找回记忆。
配套工具:墨水屏排版模拟器 →
在模拟器里亲手排一排这三张页面
libofu.cn · 美丽沙 · 2026-08