冯工聊数采NodeSCADA · 工控老兵手记 · PLC数据推送MES HTTP JSON对接 数据格式映射
上一篇聊了几种对接方式的选型思路,这篇来说HTTP推送的具体操作。
大多数情况下,拦住人的不是"推不推得出去",而是"格式对不上"。本篇就围绕这一个问题说清楚。

先说说这个项目的背景
去年做了一个注塑车间的数采项目,现场十几台海天注塑机,原来靠人工抄表,老板想上MES做产量统计和异常预警。
MES是他们之前招人搭建的,预留了一个HTTP接口,要求每分钟推一次数据,格式是这样的:
{
"factoryCode": "HT",
"reportTime": "2025-05-20T08:30:00+08:00",
"devices": [
{
"deviceCode": "INJ-01",
"cycleTime": 28.5,
"shotCount": 128,
"status": 1
}
]
}
字段都是他们系统里定义好的,改不了。
采集这边从注塑机读出来的原始数据长这样——点位名是按我自己的命名规范来的,值是直接从寄存器读出来的:
INJ01_cycle_time = 28.5
INJ01_shot_count = 128
INJ01_run_status = 1
字段名对不上,结构也不一样,这就是每次做HTTP对接基本上都会遇到的问题。
为什么不能直接推
很多人遇到这个问题的第一反应是:在采集软件里把点位名改成MES要的字段名不就行了?
改是能改,但有几个麻烦:
网关不支持。 你可以调研一下,市面上网关对于数据格式的自定义支持非常有限,比如有人网关是基于字符串替换做的,不支持数组,除非你没一个都手动编辑进去。可替换的数据也十分有限,不支持时间格式的自定义
命名规范冲突。 采集点位通常有自己的命名规范,方便在采集层做监控、报警、历史存储。如果为了迁就MES把命名改掉,采集这边的逻辑全乱了,其他用到这些点位的地方都得跟着改。
一份数据可能要给多个系统用。 这个项目里,同样的数据还要推给老板的看板大屏,那边要的格式又是另一套。你没法让采集点位同时满足两边的命名要求。
MES接口会变。 IT部门偶尔升级系统,接口字段名调整了,你不可能跑去改一遍所有点位名。
正确的做法是:采集层保持自己的命名规范不动,在推送这个环节做一次格式转换,把数据按对方要求的结构"重新组装"一遍再推出去。
自定义推送模板是怎么解决这个问题的
我现在用类似于NodeSCADA做这类项目,它的HTTP推送支持自定义模板,用的是art-template语法,模板里可以跑完整的JavaScript逻辑。说白了不只是"把点位值填进去",而是可以在推出去之前对数据做任意处理。
先说最基本的用法。对应上面那个注塑机的例子,模板大概是这么写的:
{
"factoryCode": "HT",
"reportTime": "{{ date(new Date(), 'yyyy-MM-ddTHH:mm:ss+08:00') }}",
"devices": [
{
"deviceCode": "INJ-01",
"cycleTime": {{ INJ01_cycle_time }},
"shotCount": {{ INJ01_shot_count }},
"status": {{ INJ01_run_status }}
}
]
}
模板里写MES要的字段名,花括号里填采集侧的点位名,推送时自动把当前值填进去。采集点位命名不用动,MES字段改了只改模板,要给第二个系统推就再配一套模板,互不影响。
但这只是入门用法。真正让我觉得好用的,是模板里能跑JavaScript这件事。
数据筛选。 比如MES只想收采集数据中部分数据。模板里直接加判断:

上面逻辑中筛选了名称中带 _推送 的数据点, 当然也可以灵活地 设置 推送A 推送B 给不同的系统推送不同的数据
数据换算。 采集出来的原始值有时候需要转换单位或者做量程换算。比如从寄存器读出来的压力值是原始整数,要换算成实际工程量:
"pressure": {{ $value * 0.1 }}
直接在模板里算好再推,MES收到的就是可以直接用的工程值。
联合计算。 这个项目里有个需求,MES要的是综合OEE里的"性能开动率",需要用理论节拍除以实际节拍计算出来,而理论节拍是固定值,实际节拍是采集值。这种跨点位的计算,在模板里同样能直接做:
"performanceRate": {{ (28.0 / $value* 100).toFixed(1) }}
推过去的就是百分比数值,MES不需要知道这个数是怎么算出来的。
这些能力加在一起,意味着大多数"数据格式对不上"的问题,都可以在推送模板这一层解决掉,不需要在采集侧和MES侧之间再搭一个专门做数据处理的中间服务。
const a1 = V('a1'); // 电流
const v1 = V('v1'); // 电压
const p1 = a1 * v1 // 功率
推送失败了怎么办
格式配好之后,第二个要考虑的是可靠性。
网络在工厂里不是百分之百稳定的,MES那边也有重启维护的时候。推送失败了,这段数据是就这么丢了,还是有机制补回来?
这个问题很多数采软件压根没考虑。我碰过一个案例,某品牌网关做HTTP推送,网络抖了两分钟,这两分钟的数据直接没了,MES那边产量数据出现缺口,报表对不上,搞了半天才查出原因。
NodeSCADA在这块把两种场景分开处理,我觉得设计得比较务实。
第一种:推送当前状态。 每次触发推送时,直接取最新的采集值组装发出去。网络断了会自动重连,恢复之后继续推。这种方式轻量,适合MES只关心"现在是什么值"的场景——比如设备运行状态、当前转速、实时温度,断线那段时间的历史数据本来也用不上。
第二种:从本地数据库推送。 采集数据先落库,推送任务维护一个时间指针,每次从上次推送的位置往后取数据发出去。推送失败了,指针不往前移,下次重试还是从失败那条开始,数据不会漏。这种适合对数据完整性要求高的场景——比如产量计数、能耗统计,每一条记录都不能丢。
这个注塑机项目用的是第二种,MES那边做产量报表,断线期间的数据必须完整,选历史库推送,网络恢复之后自动补上,MES这边完全感知不到中间断过。
两种方式按需选,看你MES那边对数据的要求。
推送频率设置好
还有一个细节经常被忽略——推送频率。
采集侧1秒刷新一次是正常的,但HTTP推送1秒一次,对大多数MES来说压力不小,尤其是自建系统,接收处理能力有限。我习惯在对接之前先问IT那边:你们接口能承受多少并发,每秒能处理多少条请求。
这个注塑机项目,最终定的是每分钟推一次,每次把这一分钟内的最新值打包推过去。产量统计用不着秒级数据,MES那边也稳定,皆大欢喜。
如果确实需要高频推送,就得考虑换MQTT,那是下一篇的内容了。
如果你在做类似的项目,可以去看看NodeSCADA(nodescada.cn),HTTP推送、自定义模板、两种数据源都支持,文档里有详细说明,省得自己从头搭。
冯工聊数采NodeSCADA · 持续更新工控数采实战经验
246



被折叠的 条评论
为什么被折叠?



