BrewUI:从传感器到PID的智能酿造控制仪表盘实战 📅 发布时间:2026/9/19 10:11:23 👁 浏览次数: 从把第一锅麦汁煮糊到能稳定复现同一款社交型IPA中间隔着一条长长的仪表盘之路。BrewUI这个项目就是我在这个过程中攒出来的一个面向自酿爱好者和家庭精酿玩家的Web端酿造管理界面。它不只是在手机上显示个温度数字那么简单而是一个集配方管理、酿造流程编排、传感器数据采集、加热设备控制、发酵跟踪于一体的自托管系统。如果你正在捣鼓自己的酿造设备或者想给自己的酿造间加一套能看曲线、能控温度、能存配方的交互界面这篇内容应该能帮你省掉不少弯路。我最早用的是某商业温控器的配套App功能封闭传感器数据拉不出来想改个分步温度曲线得蹲在设备前按半天。后来干脆用ESP32加PT100传感器把数据通过MQTT推到家里的小服务器上再自己写了BrewUI这套界面来管理整个酿造过程。整套系统跑下来已经有半年多从糖化阶段的温度跟踪到煮沸阶段的功率控制再到发酵间的温度记录都用这一套界面在管。下文把整个项目的设计思路、核心模块、实现细节和踩坑记录都摊开来讲。1. 项目整体设计与思路拆解1.1 为什么选择Web端的仪表盘架构BrewUI的核心定位是给酿造过程提供一个实时、可交互、可回看的控制面板。之所以选Web架构而不是桌面应用或手机原生App有几个非常现实的原因第一酿造间里往往不止一台设备温度传感器、加热棒、循环泵、电子秤可能分布在不同的位置Web界面在任何一台手机、平板、电脑上打开浏览器就能看到不需要为每台设备单独装客户端第二传感器数据和酿造记录需要长期保存放在一台常开的小主机上跑一套Web服务比让手机App在后台偷偷挂着靠谱得多第三开发调试方便前端改了个样式、后端加了条API刷新页面就能生效迭代速度比原生应用快出好几个量级。这套架构选型在技术圈里叫“前后端分离加消息中间件”听起来唬人拆开其实就是三条线前端页面负责任务看板、曲线展示和操作入口后端服务负责配方存储、会话状态管理和数据聚合消息中间件负责在传感器与后端之间搬运实时温度数据。BrewUI用的是MQTT协议来承载设备数据。为什么是MQTT而不是HTTP轮询或者WebSocket直连因为MQTT的发布订阅模型适合设备端频繁上报小体积数据也不会因为连接数量多了把后端拖垮。1.2 功能边界与模块划分在动手写代码之前我把BrewUI的功能边界划得特别清楚避免做着做着变成一个什么都要管的怪物项目。核心功能只锁定四块配方管理麦芽、酒花、酵母、水的用量记录步骤化的糖化温度曲线和煮沸时间参数酿造会话控制创建一次酿造任务从配方中载入流程按步骤推进自动记录每个阶段的时间与温度实时数据可视化温度传感器数据秒级刷新展示糖化和发酵阶段的实时曲线设备控制输出通过继电器或智能插座控制加热棒和泵支持手动开关和按曲线自动调节这四块之外的功能比如库存管理、成本核算、社区分享我全部砍掉了。后来实际使用中发现这个克制非常关键。项目能做到快速上线并且稳定运行很大程度上就是因为每一块功能背后都有明确的使用场景没有多余的东西分散精力。界面设计上我也坚持了信息密度优先的原则一屏内能看到当前步骤、剩余时间、实时温度和下一阶段动作不需要来回切换页面。2. 核心细节解析与实操要点2.1 传感器选型与数据采集链路温度传感器是整个系统的眼睛。我对比过DS18B20、PT100和NTC热敏电阻最终选的是PT100加MAX31865转换模块的组合。原因很直接DS18B20在0到100摄氏度范围内勉强够用但到了煮沸阶段探头离加热管近一点读数就开始飘NTC需要自己做标定不同批次的传感器一致性差换成新的就得重新校准。PT100虽然贵一些但线性度和长期稳定性都更好配合MAX31865模块温度分辨率能到0.01摄氏度对付酿造场景绰绰有余。传感器数据采集链路我用了比较保守的架构ESP32开发板通过SPI接口读取MAX31865的转换结果然后通过WiFi把温度值打包成MQTT消息发到局域网里的MQTT Broker上。MQTT消息主题设计成扁平结构brewui/sensor/temp/mash_tun- 糖化桶温度brewui/sensor/temp/boil_kettle- 煮沸锅温度brewui/device/status- 设备在线状态2.2 温度控制策略为什么不能只靠开关加热功率控制是酿造自动化里最容易翻车的环节。很多DIY方案干脆让加热棒全功率运行温度到了设定值就断电低于设定值就重新通电。这个逻辑在煮热水的时候没什么问题但是用在糖化上就很灾难。麦汁是黏稠液体热传导不均匀加热棒周围的温度先到探头的温度还没跟上断电之后余热继续传导最后整锅温度能冲过设定值两三度。对糖化来说温度区间差两三度出糖效率和口感就完全不一样了。BrewUI在功率控制上走了PID调节的路子配合固态继电器实现可控硅斩波调功。简单解释就是系统根据当前温度和目标温度的偏差加上温度变化趋势计算出每秒应该给加热棒多少百分比的功率而不是简单通断。加热阶段全功率推进接近目标温度时自动降功率让温度平滑落在设定区间内。实际的功率输出频率控制在一个比较低的频率比如每秒调节一次避免对电网造成太大冲击也减轻继电器触点的磨损。PID参数我一开始是手动调的后来发现直接用经典Ziegler-Nichols方法整定先把系统打成临界振荡记下临界周期和临界增益再套公式算参数就能得到一个不错的起点。2.3 配方的数据化表达酿造配方在系统里不只是几张图片或者一段文字而是一份结构化的数据。BrewUI把配方拆成三层基础信息层、原料清单层、工序步骤层。基础信息层记录配方名称、风格类型、目标产量、目标原麦汁浓度原料清单层按麦芽、酒花、酵母、其他添加物分类每种原料记录名称、用量和使用时间节点工序步骤层是整个配方的灵魂定义了从糖化到煮沸再到冷却的完整时间线。每个工序步骤是一个独立的对象包含步骤类型、目标温度、持续时间、升温速率、搅拌或循环动作等字段。系统执行酿造会话时就是按顺序加载这些步骤配合实时温度数据推进流程。举个例子分段出糖的配方可以这样定义蛋白质休止52°C保持10分钟糖化休止63°C保持30分钟糖化强化68°C保持30分钟灭酶78°C保持5分钟这套数据模型是整个BrewUI的基石前端、后端、设备控制都围绕它来协作。3. 实操过程与核心环节实现3.1 前端界面搭建与技术栈选择前端我选的是React加Vite的组合状态管理用Zustand图表用EChartsUI组件库用的是Ant Design。这套组合在BrewUI这个场景下有几个实际的考量React生态成熟网上资料多遇到问题好查Vite的开发时热更新非常快改完代码一两秒就能在浏览器里看到效果Zustand比Redux轻量得多对于酿造会话这种不算特别复杂的状态同步完全够用ECharts画温度曲线不需要额外封装折线图、面积图开箱即用。界面布局上我把仪表盘设计成了三栏结构。左侧是会话信息栏显示当前配方的名称、步骤序号、酿造的进度条和关键指标中间是主操作区包含实时温度曲线和当前步骤的操作按钮右侧是设备状态栏显示加热棒功率、泵的启停状态、传感器在线情况。移动端通过媒体查询做了响应式适配实际使用中大部分时间还是用平板看曲线手机端主要看个大概。3.2 后端API与实时通信后端服务用Node.js的Express框架搭配SQLite存数据。为什么选SQLite而不是MySQL或者PostgreSQL因为这个项目的使用场景是家庭自托管数据量不大QPS也很低SQLite单文件部署、不需要单独维护数据库服务备份的时候直接把文件拷走就行。后期如果真要多设备并发访问再迁移到PostgreSQL也不迟数据访问层我做了隔离切换成本不高。API设计遵循RESTful风格重要的接口有几个。POST /api/sessions创建新的酿造会话GET /api/sessions/:id获取会话详情POST /api/sessions/:id/start启动酿造流程POST /api/sessions/:id/step/:stepId/complete手动标记当前步骤完成GET /api/sessions/:id/temperature获取历史温度数据实时数据推送走WebSocket。MQTT收到传感器数据之后后端一方面写入时序数据库另一方面通过WebSocket广播给所有在线前端页面。实现的时候遇到一个问题MQTT消息频率太高的时候WebSocket广播会拖垮主进程。后来在广播逻辑里加了节流每两秒批量推送一次最新温度值前端拿到数据之后用ECharts的appendData方法增量更新曲线性能一下子就上来了。3.3 数据存储与时序数据处理酿造过程会产生大量的时序数据。糖化阶段温度每两秒一条发酵阶段每三十秒一条一锅酿造下来大概产生几千条记录一年几十锅数据量也就是几十万条级别。这个量级在SQLite里完全扛得住关键是要建好索引。我在温度记录表里对session_id和timestamp建了联合索引查询某一次会话的完整曲线时很快就能返回结果。温度记录表的结构是这样设计的CREATE TABLE temperature_logs ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_id INTEGER NOT NULL, sensor_type TEXT NOT NULL, temperature REAL NOT NULL, recorded_at INTEGER NOT NULL ); CREATE INDEX idx_temp_logs_session_time ON temperature_logs(session_id, recorded_at);配方表、步骤表、原料表也都遵循了外键关联的规范写法保证数据完整性。会话结束后系统会自动生成一份HTML格式的酿造报告包含完整的温度曲线、步骤执行时间和原料清单导出之后可以作为自己的酿造笔记存档。3.4 设备控制模块的实现细节设备控制是BrewUI里和物理世界交互的部分。ESP32除了上报传感器数据还订阅了控制主题后端通过MQTT向设备下发控制指令。加热棒接到固态继电器上控制频率是一秒数据库里记录每一秒的功率百分比方便事后分析。控制指令的消息格式用JSON{ device: heater_mash_tun, action: set_power, power: 45, timestamp: 1699999999 }ESP32端解析这条消息之后通过PWM或者定时通断来调节输出功率。PID计算放后端做而不是放在设备端好处是调参不用重新刷固件改完参数界面上一保存下一次控制周期就生效。4. 常见问题与排查技巧实录4.1 温度读数漂移和探头故障PT100本身很稳定但整个链条上还是有不少地方会出问题。最典型的故障是接线松动。MAX31865模块和ESP32之间的连接线如果用了杜邦线时间久了或者震动之后会接触不良读出来温度一会是20度一会是120度。排查方法很简单看前端曲线如果出现脉冲式的毛刺多半就是接线问题。后来我把所有传感器接线都换成了航空插座固定牢靠这种问题就再也没出现过。还有一种情况是探头位置放得不对。探头如果太靠近加热棒测出来的温度明显偏高导致PID系统以为温度到了实际麦汁整体温度还没到位。我现在的做法是把探头放在糖化桶的循环回路中间让麦汁从底部抽出、经过泵和探头再回到顶部实时测的是循环之后的混合液温度这个位置更能代表整体糖化温度。如果你用的是静态糖化桶没有循环建议把探头放在桶壁中下部并且加一个轻柔的搅拌避免局部温度分层。4.2 WebSocket连接不稳定用了一段时间之后发现前端页面偶尔会卡在启动页面日志里报WebSocket连接失败。排查发现是家里路由器在长时间没有数据交互的情况下会断开TCP连接前后端之间没有心跳机制连接断了之后前端不知道一直等消息看起来就像卡死了。解决办法是让前端每隔30秒发送一次Ping消息后端收到后立即回Pong如果连续三次Ping没有收到回复前端就主动重连。同时在后端WebSocket的配置里也加了自动检测连接空闲超过60秒会主动发送探测包。加了这套保活机制之后页面挂一天都不会掉线。4.3 加热功率失控的风险保护设备控制一定要考虑一件事软件或者网络出问题的时候加热器能不能停下来。我踩过一次坑PID服务进程崩溃了ESP32没有收到新的控制指令然而后端的控制逻辑默认是保持上一次的输出状态于是加热棒就按着上一次的功率一直烧差点把麦汁煮过头。这套逻辑放在酿造里虽然不至于出大事故但是把糖化温度推到80度以上一锅麦汁就废了。现在我把安全逻辑做了双保险第一层ESP32端设置一个看门狗如果超过5秒没有收到后端的心跳消息就自动进入待机状态切断加热输出第二层后端每次发送控制指令时带上过期时间设备收到后只在这个时间窗内执行超时自动归零。酿造过程中系统再出崩溃最多损失几秒钟的加热不会出现持续加热的失控场景。4.4 温度曲线波动过大如果你看到的温度曲线像锯齿一样上下乱跳先别看PID参数先检查采样数据本身。我遇到过传感器数据本身就带噪声的情况原因是ESP32的电源用的是劣质开关电源纹波太大影响了模拟信号转换的稳定性。换了一个质量好的线性电源之后数据干净多了。另外在软件层面我加了简单的移动平均滤波取最近五次的平均值作为展示值和控制值这个处理基本看不出数据延迟但波动明显减小。如果不是数据噪声的问题那就是PID参数太激进了表现为温度在目标值附近振荡。这时候把比例增益调小一点同时适当加大积分时间让系统慢下来稳定优先。4.5 数据库会话状态异常中途断电或者强制重启服务器可能会让酿造会话状态卡在中间前端一直显示某个步骤未完成。BrewUI的处理方式是在启动时扫描所有状态为“进行中”的会话提示用户选择恢复或者终止。恢复的逻辑是回到上次完成步骤的末尾重新加载后续步骤终止的逻辑是保留已记录的数据将会话标记为已中断存档备查。5. 功能增强与扩展空间5.1 多用户权限与分享能力目前的BrewUI本质上是一个单用户系统登录鉴权只是简单的一层保护。不过在实际使用中酿造圈的朋友互相交流配方是个很常见的需求。我后续计划加入一个轻量的用户系统让每个用户可以创建公开配方或者私有配方公开配方可以通过链接分享给其他人直接导入。这样不同酿造者之间交流配方会方便很多不需要再发Excel表格或者手打的配方截图。5.2 与自动化酿造设备深度集成现在BrewUI的控制输出主要面向加热棒和循环泵后续想接入更多设备。比如电控阀门的开关、水流计的流量记录、pH计的数据采集。这些设备的接入路径和温度传感器相似都是走MQTT协议上报后端增加对应的数据类型解析即可。架构上不需要大改扩展性已经留好了。5.3 发酵阶段的长期监控与糖化和煮沸阶段的实时控制不同发酵是一个持续数天甚至数周的过程。BrewUI目前对发酵的支持还比较基础主要是温度和时间的记录。后面计划加入发酵度估算功能通过记录起始和结束比重自动计算表观发酵度并在界面上画出发酵曲线。这样一瓶酒什么时候能倒桶、什么时候能装瓶看一眼界面心里就有数了。对于已经把设备凑齐的自酿爱好者来说BrewUI这套东西最大的价值不是帮你把酿造变得全自动而是让你每一次酿造的数据都有迹可循。我自己在用了半年之后最大的变化是同一款配方的复现率明显提高——不是靠运气而是靠每一锅记录下来的温度曲线和步骤日志。好的酿造不是玄学是一组可量化的过程参数配合一个能把参数记录下来的工具仅此而已。