Nixie Indicator 篇二:让辉光管显示真正有用的数据
数据采集、固件设计到配套桌面客户端的设计实现过程分享

两只辉光管亮起来以后,这个设备已经有了想要的样子。不过,桌上摆着一个会发光的数字,离每天愿意看一眼的小工具,还差软件控制上的实现。最初那个“让 AI 给自己打工”的想法,也要到这里才算接上:电脑上的 Codex 额度,得真正出现在管子里。

本篇继续聊固件与桌面客户端:数据从哪里来,两位数字怎样表达信息,以及怎样用一块小屏幕和一个旋钮,把配置与日常操作串起来。

简化客户端额度卡片与设备模型并排,显示相同的剩余额度 26%
图 1. 从电脑里的额度,到桌上的数字(效果示意)

数据链路

起初,我想让设备直接兼容 ChatGPT 桌面端的原生协议,自己读取额度数据。同时,面向更专业的观测场景,再支持 Prometheus 查询。设备连上网络后,就能直接向对应的服务取数。

但实际尝试后,这条路没有想象中顺手。客户端的默认启动方式只监听本机回环地址,不能直接从局域网里的 ESP32 访问。另一方面,原生协议长期也有一定的不确定性,如果每次适配变化都要重新刷固件,维护起来就很麻烦。

索性在中间加一层桌面客户端,把采集与显示解耦。客户端在电脑本机调用应用专用协议,处理连接、查询和返回数据,再将结果整理成统一的 Metrics 指标,通过局域网提供给设备。原生协议的连接过程和账户相关操作都留在电脑端,ESP32 只需要按配置读取指标,不必跟着理解每个来源的内部协议。

基于这样的设计,上游协议变化时,可以集中修改客户端的采集适配,已有的指标接口保持不变,设备也就不必为这类变化重新刷固件。CPU 负载、内存使用率、温度和游戏帧率等 PC 指标也能沿用这条路径。设备侧仍负责取数、有效性判断和显示,只是这些逻辑不再与某个具体应用绑在一起。

最终保留了两种接入方式:

  • Metrics 直连:设备直接读取桌面客户端或其他 exporter 提供的指标,适合只想显示当前值的场景。

  • Prometheus:设备查询已有的监控服务,可以进一步显示历史趋势,也能使用服务端的查询与计算能力。

桌面客户端是一个数据来源,设备本身仍是通用的指标显示器。 如果已经有自己的监控服务,就不必为了使用设备再运行这个客户端。直连模式也不要求额外搭建一套 Prometheus。

桌面采集经 Metrics 直连或 Prometheus 查询到达设备,并由辉光管与 LCD 显示
图 2. 一条指标的旅程:Metrics 直连与 Prometheus 查询

固件设计与实现

框架选型

和硬件部分一样,我与 Codex 的配合仍然采用设计文档先行、渐进式推进的规格驱动(Spec-driven Development)开发方式:先讨论并写清各部分的职责、接口与约束,再分阶段实现与验证,调整后的设计也同步回文档。基础组件的选型如下:

  • PlatformIO 与 ESP-IDF:组织工程、构建固件,并接入网络和硬件外设。

  • LVGL 与 esp_lvgl_port:负责小屏幕上的控件、菜单与界面刷新。

  • esp_lcd 与 SPI DMA:连接界面绘制和实际 LCD 输出。

  • NVS:保存网络、指标规则和显示偏好,运行中的数值与临时状态留在内存里。

  • Wokwi:作为固件仿真方案,提前检查界面显示与输入交互。

早前的其他项目,我主要用 Arduino 框架。这次有了 AI,工程框架的搭建和维护工作量大大减轻,也就果断换到了自由度更高的 ESP-IDF,可以按项目需要更细致地组织任务、管理外设和调整底层配置。

固件基于 ESP-IDF 集成的 FreeRTOS 进行任务调度。架构上则采用领域隔离与拆分的设计理念,先明确各部分负责的业务、持有的状态和对外接口,再组织它们之间的协作:

  1. 网络通信:负责数据采集,以及远程访问与管理。

  2. 设备控制:接收数据和操作请求,统一决定硬件输出。

  3. 界面交互:展示指标数据和设备状态,将用户操作交回控制侧。

各领域通过明确的接口协作,后续增加页面或接入新数据源时,也能将修改集中在对应领域。

交互入口、应用协调、业务领域与底层支持的分层关系
图 3. 固件的领域划分与分层协作(架构概览)

实现过程中,先通过单元测试覆盖主要逻辑,再结合仿真检查交互与数据链路,大致跑通全链路后,再进行实机测试。

GUI 显示与菜单操控

固件实现中,我最先考虑的是屏幕上的 GUI 和系统菜单:日常显示哪些信息,设置入口放在哪里,页面之间怎样切换。LCD 界面采用成熟的 LVGL 绘制,我先围绕这些使用场景梳理页面与导航关系。

LVGL 负责界面组织与绘制。主指标、趋势图和系统菜单按场景拆分,菜单行、焦点框与状态图标则复用同一套组件。这样调整样式或操作反馈时,可以让各个页面保持一致。

画面到屏幕之间,通过 esp_lvgl_port 与 esp_lcd 衔接,再由 SPI DMA 传输像素数据。LVGL 生成待刷新的区域,驱动提交传输,完成后再通知界面继续使用对应缓冲区。界面绘制与数据传输的配合,也就成为屏幕刷新实现中的重点。

旋钮用于日常的指标切换、亮度调整和自检,操作请求由固件内统一的控制层逻辑处理。网络取回数据后,也走同一条输出路径。

基于帮助文档的界面示意,说明长按进入菜单、旋转选择与短按确认的操作
图 4. 指标浏览、系统菜单与指标选择(界面示意)

实际验收时,我会评估整体交互是否符合使用常见设备时的直觉,同时关注页面布局、信息层次和视觉感受,再根据实际体验逐步优化。

字符集与多语言支持

除了中文和英语,我们还做了日语和德语的国际化。嵌入式屏幕需要把用到的字形随固件一起打包,翻译好文案只是其中一步。正文字体选择了 Noto Sans 系列,再转换成 LVGL 字库。日语需要对应的字形,德语长词也需要检查是否挤占布局。

自定义指标标题的字符范围则需要单独考虑。我们从核心、通用和行业三层的中日指标词库中提取字符,再补上字母、数字、单位和必要符号,覆盖常见的自定义标题。

字库在固件体积中占了不小的比例,中日文字形和多种字号叠加后,空间开销尤其明显。因此,固定文案按实际用字裁剪,自定义标题按词库补充,大字号只保留数字和必要符号,部分中日文字库再采用无损压缩。字符覆盖、字号和可读性需要一起取舍,给其他功能和后续升级留出空间。

日文系统菜单
日文菜单

辉光管控制

前一篇在介绍 74HC595 驱动原理时,提到了数字与实际管脚之间的映射。固件根据这份映射生成串行数据,通过独立 SPI 总线更新,亮度则由 BLANK 的 PWM 控制。LCD 使用另一条 SPI 总线,避免大块画面传输占用辉光管更新的总线。

指标信息可能长时间保持不变,因此固件设计了每小时一次的阴极轮换,让各个数字轮流点亮,同时提供显示休息和逐个数字自检功能。

辉光管的维护与阴极中毒

辉光管里的每个数字都是独立的阴极。放电时,离子轰击会使工作阴极发生溅射与材料损耗,释放出的材料可能沉积在其他阴极表面。长期只显示少数数字时,较少点亮的阴极上会逐渐形成堆积,影响正常放电,出现局部不亮、笔画显示不完整等阴极中毒(Cathode Poisoning)现象。

定期让所有数字轮流点亮,是常见的预防性维护方式,也是这里加入每小时阴极轮换的原因。

辉光管显示 00~99 的两位整数,LCD 补充完整数值、名称、单位和状态。小数取整,越界数值限制在两位显示范围内,原始数值仍保留在 LCD 上。具体显示规则如下:

整数补零、小数取整、超出两位范围与无有效数据时的显示对照
图 5. 辉光管与 LCD 的数值显示(规则示意)

取不到数据,不能当成数值为零。 以额度显示为例:

  • 服务暂时不可达和额度真的耗尽,是完全不同的两件事。

  • 旧值可以在规则允许的时间内保留,但需要标明状态,避免被误认为刚刚更新的数据。

配网

配网采用常见的 SoftAP 热点配网方案:设备先开启临时热点,手机连接后通过网页填写家庭 Wi-Fi 信息,再由设备连接目标网络。LCD 提供配网入口和状态提示。

设备开启热点、手机提交网络信息、设备联网保存和手机切回同一网络的配网流程
图 6. 从临时热点切换到家庭 Wi-Fi

连接成功后,设备保存配置并结束临时热点,手机切回同一 Wi-Fi,就可以通过设备的新地址访问管理页面。连接失败时,修改信息后重试。日常断网会自动重连,需要更换网络时再从菜单进入配网。

设备配网二维码、Wi-Fi 配置表单和连接成功页,网络与地址为示例
图 7. 连接设备热点、填写 Wi-Fi 与完成配网(界面示意)

固件升级

设备接入网络后,我也把 OTA 更新纳入了固件设计,方便后续迭代时直接通过网页或客户端上传固件。当前先采用本地选择文件、局域网上传的方式,USB 烧录则作为维护入口保留。

升级方案采用双应用槽策略:Flash 中留出两个固件分区,一个运行当前版本,另一个接收新版本。更新时保留当前固件,等备用槽中的镜像完整写入并通过校验后,再切换启动目标。这样,传输中断或校验失败时,仍然可以继续使用原来的版本。

新固件第一次启动时,还会先检查存储、控制任务和界面等基础功能,运行稳定后才确认这个版本。如果试启动失败,便按回滚机制退回仍然有效的旧版本。确认成功后,两槽角色交换,下一次更新再写入另一槽。代价是要为两份固件预留空间,这也让前面提到的字库体积控制有了实际约束。

当前槽保留旧固件,备用槽写入新固件,校验后试启动,正常则确认,失败则回退旧版本
图 8. 双应用槽的更新与回退策略

后续的 OTA 扩展

有了设备端的更新基础,后续可以让客户端检查新版本、展示更新说明并下载匹配的固件,再交给现有上传流程。也可以进一步支持设备直接从更新服务获取固件,配合签名校验和稳定版、测试版通道管理。这些仍是后续扩展方向,当前先把局域网更新做好。

远程管理与桌面端

Web 远程管理

设备连上局域网后,可以通过 Web 管理页面完成小屏幕上不方便操作的配置。页面资源随固件提供,通过设备地址就能打开。浏览器提出授权请求后,需要在设备上确认,再进入管理页面。

网页主要承担显示偏好、数据源配置和固件更新,也支持配置 PromQL 并预览查询结果,便于确认最终要显示的指标信息。这些操作通过统一的管理接口完成,页面负责呈现和提交请求,配置规则由设备端处理。桌面端也复用这套接口,让两个入口保持一致。

指标配置页把查询条件和预览放在一起:左侧设置 PromQL、显示名称、单位和图表样式,右侧查看当前数值与历史趋势。调整表达式后就能对照结果,判断采集到的信息是否符合预期。

浏览器中的指标配置页面,左侧设置 PromQL 与显示信息,右侧预览数值和历史趋势
图 9. Web 指标配置与查询预览(界面示意)

桌面端实现

桌面端围绕 采集指标配置与设备快速管理 展开,采用 Tauri 2、Rust 和 TypeScript:界面负责配置与查看,Rust 后台负责采集、提供 Metrics 和连接设备。采集与窗口分开运行,关闭窗口后仍可以通过托盘保持后台工作。

采集来源以独立卡片呈现,可以按需启用,并查看采集状态和当前数值:

  • 系统信息:CPU 与内存使用情况。

  • 硬件监测:GPU 负载、显存和可用的温度传感器。

  • FPS 采集:跟随前台应用获取帧率。

  • Codex 观测:读取本机配额信息,目前仍标为 Beta。

回到最初的用途,Codex 观测在电脑端读取配额,再按返回的额度窗口导出剩余百分比。设备读取的仍是一条普通指标,应用协议和账户相关处理都留在客户端。这里显示的是配额窗口的剩余比例,而非逐个 Token 的精确余额。

配对设备后,可以从本机采集结果中选择要显示的指标,调整顺序、设置主指标并预览取数,也能快速进入设备设置和固件更新。本机采集配置与设备配置分别保存,让采集什么、设备显示什么都能在客户端里集中调整。

左侧启用采集来源并查看当前值,右侧选择展示指标、调整顺序和主指标
图 10. 桌面端的采集配置与设备快速管理(界面示意)

指标扩展

新增数据来源时,可以在客户端增加独立的采集模块,将结果交给统一的采集调度和 Metrics 出口,沿用已有的设备显示链路。来源协议变化时,修改也能集中在对应模块。

设备端也可以独立接入其他 Metrics 服务或 Prometheus,将显示范围扩展到其他设备或观测场景。

派对模式

除了看指标,这两只辉光管也可以成为桌上的小玩具。为了让设备有更丰富的可玩性,客户端里增加了“派对模式”,把随机数、倒计时和数值展示做成几个随手就能玩的入口:

  • 赛博摇骰子:把随机范围设为 1~6,看数字快速跳动、逐渐放慢,最后停在这一回合要走的步数上。换个范围,也能用来抽签或聚会猜大小。

  • 限时挑战:用辉光数字倒计时,给桌游或小游戏增加一点紧张感。

  • 桌游记分:手动提交一个数字,让管子显示当前分数。

这些玩法复用同一套数值序列播放能力,客户端安排数字与节奏,设备负责播放。退出派对模式后,就恢复日常指标显示。原本只是抬头看一眼的数据,也因此多了一个让朋友参与进来的理由。

辉光管设备显示 06,与骰子和桌游棋子组成的派对场景
图 11. 让辉光数字参与桌游

小结

软件工程本就是 LLM 已经持续迭代多年的能力。在这个项目里,从固件到桌面端,AI 已经能够承担相当完整的实现工作。更值得思考的是,当代码编写的成本降低以后,设计者的精力应该放在哪里。

人的参与,更多集中在设计决策与工程规范的把控。 设备与客户端如何分工,领域和模块怎样划分,哪些状态由谁维护,都会影响后续修改的成本。开发过程中,还需要坚持 DRY(Don’t Repeat Yourself)原则,让共用的业务规则有统一的实现,避免相似功能各写一套、逐渐产生差异。命名、接口、错误处理和测试等代码质量要求,也需要作为持续约束,贯穿每一轮开发与验收。

这也是设计文档先行、渐进式推进的价值:先把边界和约定写清楚,再逐步实现,并将验证后的调整同步回文档。生成代码越容易,保持工程一致性就越需要明确的规则。 如果只追着功能逐项增加,局部可用的实现也可能不断堆积,最后把维护成本留给后续迭代。

另一个变化,是底层 SDK 适配、工具链配置和开发环境搭建这些准备工作,现在也可以交给 AI 完成。这降低了尝试陌生框架的成本,让选型更能围绕项目需要展开。以前主要用 Arduino,这次转向 ESP-IDF,正是这种变化的体现。节省下来的精力,可以更多用于架构取舍、交互体验和实际验收,也让个人开发者更有余力维护一套跨固件、网页与桌面端的完整系统。

对业余 DIY 来说,开发节奏也变了。以前做一个项目,往往需要把业余时间全身心投入进去,从构思到具体实现都得亲自推进。现在更多时间花在构思方案、明确要求和检查结果上,具体执行交给 Agent。等它编写代码、运行测试的时候,也可以抽空刷刷视频,等有了结果再回来继续讨论和调整。项目仍然需要持续关注,但不必每一步都守在电脑前,这让利用零散时间推进项目变得更轻松。

设计者一边观看视频,一边关注 Agent 的代码实现与测试进度
图 12. 从设计决策到 Agent 执行

下一篇番外,再来聊聊怎样把硬件项目做成带有商业质感的演示动画,以及输出高质量的介绍图片。


最后修改于 2026-11-06