上次上线后,产线师傅在配料秤校验页面反馈:选了第三料仓、时间拉到 6 小时,料位显示 -12.4 kg,负数。我打开后端 PlcjyServiceImpl 一看,聚合逻辑写的是 windowEndValue - windowStartValue。但 IoTDB 里存的根本不是绝对料位,而是每个采集周期的下降增量(0.3~1.2 kg 这种小数值)。拿两个增量相减,结果当然可能是负数。
需求文档里写的是"30 分钟窗口内累积求和",我当初抄了另一模块的写法没改口径,埋了这颗雷。这次一并修掉。
先确认谁在调 plcjy 接口
项目里有个 belt-scale 页面,名字看着像配料秤,打开一看是产量日报,跟 plcjy 模块半毛钱关系没有。
真正调用 plcjy 后端接口的是 batching-scale/index.vue。页面已具备的基础:
- 默认选中第一料仓
- 时间范围 24h
- 30 min 轮询自动刷新
- 用户手动筛选后暂停刷新
缺口也很明确:
- "恢复页面刷新"按钮缺失(暂停后没法手动恢复)
- 后端聚合口径错误(上段说的首尾相减)
- IoTDB 设备/测点不存在时,页面直接白屏,没有兜底
确认完差距,再动手,避免改完发现改错了文件。
聚合口径:把首尾相减改成窗口累积求和
IoTDB 的数据模型是:每个采集周期(比如 5 秒)写入一条下降量,数值在 0~1.5 kg 之间。料位消耗 = 窗口内所有下降量求和。
原代码:
java
// 错误:拿窗口首尾两个点的值相减
BigDecimal consumption = endValue.subtract(startValue);
改成:
java
// 正确:窗口内所有增量 SUM
String sql = "SELECT SUM(`decrease`) FROM " + device + "." + measurement
+ " WHERE time >= " + windowStart + " AND time < " + windowEnd;
改完编译通过,拿测试库跑了一下,第三料仓 6h 窗口消耗 847.2 kg,和 DCS 历史曲线对得上。
IoTDB 设备不存在时的兜底
现场新加的料仓,IoTDB 里还没建点。原逻辑是查不到就抛异常,前端白屏。
我在 PlcjyServiceImpl 里加了建点兜底:
- 查询前先
SHOW TIMESERIES确认测点存在 - 不存在则执行
CREATE TIMESERIES建点 - 再往新点写一条 0.0 的模拟数据,保证后续查询不报错
扩展了 IoTDB 客户端,原来只封装了查询,现在补了非查询执行(executeNonQuery)和单条写入(insertOne)。不用启动整个服务,直接探活验证:
scss
// 连通性探活(不部署,本地跑)
INSERT INTO root.plcjy.test(ts,decrease) VALUES(now, 0.0)
// 返回 200,链路通
前端补刷新恢复 + 文档同步
batching-scale/index.vue 里加了"恢复页面刷新"按钮,点击后重新计时 30 min 轮询,同时把模式状态(自动/暂停)显示在页面顶部,师傅一眼能看出当前是不是在自动刷。
点位文档同步更新 4 处 + 新增 1 个小节(记录 plcjy 模块的测点命名规则和设备映射)。不写文档,下一个人接手又得翻一遍代码。
可带走的几条
- 改聚合口径前先确认数据模型。IoTDB 里存的是增量还是绝对值,决定你用 SUM 还是首尾相减,翻一下建表 SQL 比猜快。
- 页面定位别靠文件名猜 。
belt-scale看着像配料秤,其实是产量日报。grep 一下接口路径比看目录结构靠谱。 - 时序库做兜底要建点+写模拟值 。只建不写,后续
SELECT还是空结果,前端照样炸。两条都做了才叫兜底。 - 文档跟着代码一起改。4 处修改看着不多,但少改一处,半年后查问题的人就会对着旧文档怀疑人生。
做自动化这几年,最耗时间的从来不是写代码,是摸清每个平台的脾气。
这篇里提到的坑,都是真金白银踩出来的。 如果你手上也有重复度很高的活儿------批量发布、数据搬运、有固定规则的机械操作 ------可以在评论区说说你的场景,我看看能不能自动化掉。