本篇记录 PiBoard 从运行问题修复到 v0.1.2 发布的过程,依据公开源码和 2026 年 11 月 12 日的验收记录整理。本文整理于 Nov 13, 2026,没有在写作时重新连接设备或复测外部服务。
前面几篇分别讨论了内容结构、数据来源和点阵排版。等这些部分能够协作之后,另一个问题变得越来越重要:怎样确认树莓派上运行的,确实是准备发布的那份代码?
看到屏幕亮着只能回答很小一部分问题。网页长连接可能堵住普通请求,错误参数可能已经写入配置,旧字体补丁也可能被误当成完整新版本。这一篇把运行修复与验收过程放在一起记录。

WebSocket 连上了,HTTP 却不能等着

控制台通过 HTTP 读取和提交数据,再通过 WebSocket 接收状态。早期单线程服务会被 WebSocket 长连接占住,普通请求也就跟着等待。
当前启动方式启用了请求线程,并移除了应用层的空闲断开逻辑。验证时不能只分别打开两个地址,而要保持 WebSocket 连接,再检查 HTTP 是否仍能响应,随后确认同一条 WebSocket 还能接收状态。
pygame 绘制仍然留在主线程。网页请求、后台数据获取和屏幕绘制分工不同,把服务改成可并发处理请求,也不意味着可以让任意线程调用 pygame。

状态恢复先完成检查,再替换

配置文件会保存页面、布局、来源和设备设置。读取时如果直接逐项覆盖全局状态,后面才遇到损坏字段,就可能留下部分新值和部分旧值。
现在的恢复逻辑先在副本中检查结构、补齐默认值,再整体替换;失败时保留原状态。保存则先写临时文件、同步数据,再通过 os.replace() 替换目标文件。
这些做法降低了半写入和半恢复的风险,但没有让配置天然免疫所有故障。例如旧版本迁移还要保留手动城市的意图,不能先套上默认值,再把用户的选择误判成自动定位。恢复流程正确与迁移语义正确,是两个都要检查的问题。

运行中的写入也要校验

只在启动时检查文件还不够。控制台运行期间,HTTP 和 WebSocket 都能修改状态,错误结构仍可能进入持久化文件,甚至影响显示主循环。
v0.1.2 增加了共享写入校验,在状态修改前检查 JSON 对象、字段类型、布局和枚举值。例如 slots 需要是由合法来源标识组成的数组,不能塞进对象;Custom 标题也不能是数字。
输入问题
处理目标
JSON 顶层是数组或其他错误结构
拒绝进入状态修改流程
未知布局、来源或非法 slots
拒绝错误配置
数字进入应为字符串的标题字段
在绘制前阻止类型错误
WebSocket 消息不合法
返回错误,同时保留可继续使用的连接
回归记录新增了 8 项写入校验检查。设备验收还用少量无效 HTTP 写入确认返回 400 且状态不变;更广的错误组合放在隔离测试中,不拿私人配置反复试错。
这层校验解决了已覆盖的结构、类型和枚举问题。多设备设置冲突、完整业务语义以及身份认证,仍然是另外的工作。

补丁验收和整版验收要分开

在正式整合之前,项目已经分别把显示调整与人工确认的字体部署到树莓派。这些记录证明对应补丁在设备上工作,但不能自动证明后来加入的全部运行修复也已经部署。
因此历史记录保留了不同状态:旧正式版、局部 overlay、v0.1.2-rc.1 候选版,以及最终 v0.1.2。候选版文档里“尚未完成完整设备验收”的描述,应该结合它自己的时间点理解。
正式发布时需要重新对齐三件事:
  1. 本地准备发布的干净提交和版本标签。
  1. 树莓派实际部署的源文件与构建标记。
  1. 正在运行的服务通过 /api/version 返回的版本和提交。
设备端不一定有 Git 仓库,所以仅比较版本字符串还不够。此次部署同步 Git 跟踪的文件,生成运行标记,并逐文件校验 SHA256,使代码身份有独立证据。

部署要保留用户的数据

天气地点、列车配置和私人订阅属于设备上的运行数据,不应被公共示例配置覆盖。
这次发布先在项目内部保留代码归档与私人状态备份,再同步公开跟踪文件,不使用删除式同步去清理整个目录。验收过程中临时切换页面,结束后恢复原来的布局、当前应用和轮播设置,并比较解析后的持久化 JSON。
失败时也需要一条可执行的恢复路径:停止原服务,恢复项目归档和原状态,再启动同一个服务,读回旧标记和配置。单纯说“有 Git,可以回滚”,不足以处理设备端没有仓库、代码与状态又分开保存的情况。
这里记录的是项目自身的部署策略,没有通过改路由、DNS 或系统配置来掩盖运行问题。

验收结果,按证据能回答的问题来写

v0.1.2 的公开记录包含本地和 Pi 两侧的编译检查、41 项 unittest、6 项发布 smoke 与 4 项视觉 smoke,以及多个桌面和手机宽度的控制台检查。服务 active/enabled,实际进程使用 kmsdrm 后端,五个页面的 API 切换后渲染进程仍存活。
这些结果覆盖软件运行路径,但还需要逐个解释真实数据:
来源
当次验收结果
不能据此推出的结论
天气
保存地点的 Open-Meteo 获取与映射成功
自动定位必然正确,或所有天气服务都通过
日历
已有私人 iCal 获取和解析成功,窗口内 0 事件
重复规则和跨日事件已完整支持
列车
两个已配置上游返回 HTTP 500,显示等待或不可用
实时车次已经验收成功
Custom
手工内容路径可用
属于实时数据
列车外部服务失败时,设备仍能处理错误并保持运行,这可以算错误路径通过;实时数据可用性则需要明确保留为未通过。把这两个结果分开,后续查问题时才不会被“全部通过”误导。
在树莓派上离屏渲染的 Overview 安全样例
在树莓派上离屏渲染的 Overview 安全样例
此图是整合运行期间在 Pi 上离屏渲染的公开样例:日历和列车使用演示数据,天气使用公开 London 请求。它不展示私人日程或地点,不是物理面板照片,也不证明私人列车来源已经恢复。

性能数字要注明测量条件

整合运行的短时采样记录为:温度 48.3°C,CPU 约为单核的 6.4%(5 秒窗口),RSS 约 115 MiB,节流标记 0x0。这些是当次历史测量,不是本文写作时的新结果,也不是最终每个运行状态的固定数值。
这些数字没有全部达到早期静态 CPU 小于 3%、内存小于 80MB 的目标。保留低频静态重绘机制,与已经达成性能目标,是两件不同的事。
长时间运行、长中文内容、持续动画、面板光学效果还要继续观察。离屏测试和短采样都不能替代热稳定性或真实观看体验。

给以后自己的检查入口

阅读公开记录时,可以从这些层次查证:
  • 先看版本标签、提交与 /api/version,确认正在讨论哪份代码。
  • 再看服务、HTTP / WebSocket 与页面切换,确认软件能持续运行。
  • 然后检查来源成功、空结果、演示和过期状态,确认数据含义。
  • 最后看配置恢复、资源占用与硬件画面,确认部署后的实际表现。
仓库提供了 tests/pi_release_acceptance.py 用于复现部分验收。它带有临时切页与恢复行为,需要先准备明确的私人配置备份,不能把它当成完全只读的健康检查随手运行。
控制台目前仍没有登录保护,只适合受信任的局域网;状态接口可能返回私人配置。新增参数校验不改变这个使用边界。iCal 完整语义、OpenWeatherMap 概览兼容、多控制端覆盖和列车上游可用性,也仍是后续工作。

这次发布留下了什么

对 PiBoard 而言,v0.1.2 让几处已经发现的运行问题有了修复,也让“验证过什么”有了更清楚的记录。以后再继续改功能时,可以从这份基线往前走,而不用只凭某张截图猜测设备状态。
这个系列先记录到这里:从一个车站屏的视觉想法,到共享内容结构、点阵排版,再到实际部署。剩下的问题继续留在记录里,等它们有了新的证据,再写下一篇。

源码与记录

PiBoard 系列

  1. 项目总览:把英式车站屏做成树莓派个人信息屏
  1. 数据接入:让天气、日历和列车共用一块信息板
  1. 字体与排版:点阵字体里,一个点也会影响可读性
  1. 运行与部署:从本地能跑,到树莓派上的版本验收