半夜两点手机响,那头是值班小伙子略带慌张的声音:“X工,2号线又停了,中控室这个画面红灯一直闪,我看不懂是啥故障。”我明白,他看不懂的其实不是画面,而是这个点该不该打扰我。这种场景,搞WinCC运维的基本都经历过。WinCC作为老牌SCADA,稳定是真稳定,报警画面、趋势归档、事件记录都做得规规矩矩,可惜一切都被锁在中控室里。人一离开操作台,现场就像断了线的风筝,啥也看不见。要是车间没配短信猫,连个自动拨号都没有,全靠值班员那一嗓子。
这篇聊聊我自己解决这个问题的方案:不碰老WinCC系统,在它旁边塞一台基于Node-RED的边缘计算网关,把报警直接推到企业微信。这套做法成本极低,硬件几百到两三千,部署快,而且对原有系统几乎零侵入。适合谁参考?老产线不能停机、预算有限、又想随时随地用手机看到设备报警的自动化工程师、车间设备管理员,以及负责工厂IT/OT融合的运维团队。
1. 老WinCC报警能力的真实短板,以及为什么我选“外挂”而不是升级
先说说我面对的实际情况。现场是一套跑了快十年的WinCC 7.4 SP1,服务器是台老款戴尔塔式机,下挂两条S7-300产线,以太网早就通了,但报警系统还停留在“中控室看得见、出了门就瞎”的阶段。白天人在中控室还没事,到了晚上、周末、节假日,设备一停,等值班员电话打到你这里,往往已经过去半小时了。
WinCC原厂不是没给报警扩展能力,但算下来都不划算。官方有个WebUX选件,能把画面发到浏览器上,可它要单独授权,价格按变量点数算,老版本升级还要过一遍兼容性测试。再往上走,升级到V8.x意味着操作系统、数据库、授权狗全要换,服务器硬件大概率也得跟着升级,停机窗口至少按周末算,车间根本抽不出这个时间。对很多厂来说,WinCC本身没坏,坏的是“报警出不了门”这件事,为这个去动手术换心脏,亏。
所以我当时定的调子是“外挂”:
- 旁路部署:网关接在控制网交换机上,逻辑上跟WinCC并行,谁也不是谁的前提。
- 只读优先:网关只从PLC或WinCC侧读数据,绝不写任何控制相关的内容。
- 独立生存:网关挂了、断电了、网络断了,原WinCC系统毫发无损,生产画面照常跑。
- 低成本试错:硬件加调试两天内搞定,觉得不行拔了网线就撤,没有任何历史包袱。
这套思路本质上就是“边缘计算网关”最常见的落地姿势:把老系统的数据在边缘侧接出来,做现代应用需要的活。WinCC负责它擅长的SCADA监控,Node-RED负责它擅长的接口粘合和消息推送,各干各的,互不添乱。
2. 数据从哪儿来:四种取数路线的取舍,我最后选了哪条
报警要推出去,第一步是让Node-RED拿到现场状态。看起来简单,实际操作里有四条路线,坑的深浅完全不一样。
2.1 路线A:Node-RED直接读PLC——最稳,但要有图纸
既然WinCC下面的PLC本来就是通过以太网通信的,Node-RED完全可以直接跟PLC对话,把WinCC整个绕开。S7-300/400支持ISO-on-TCP的S7通信协议,端口102,Node-RED生态里有现成的node-red-contrib-s7节点,装上以后填PLC的IP、机架号、槽号,就能按字节、字、位去读DB块和标志位。报警点位如果是存在DB里的位,轮询周期设1秒到3秒,基本能做到“现场变化,手机秒收”。
这条路最大的优点是完全不碰WinCC,老系统稳如泰山。缺点也很明显:你得知道报警点在PLC程序里的具体地址。老项目的图纸如果还在,问题不大;图纸丢了,或者厂家当初加密了程序块,那就麻烦了。我这边还好,主设备的报警字集中在DB10和DB11里,每个字节对应一台设备的若干个故障位,拿地址表一对照就出来了。
2.2 路线B:从WinCC的OPC服务器取数——理论上美,配置上烦
如果PLC程序地址拿不到,可以退一步,让WinCC当数据源。WinCC自带OPC DA服务器,你甚至可以把WinCC画面里的变量直接暴露出去,Node-RED这边用OPC UA客户端去连。但坑来了,WinCC 7.4自带的还是OPC DA 2.0,DCOM那一套跨机器配置相当折腾:Windows防火墙要开135端口和动态端口范围,DCOM组件里要给匿名用户加权限,用户名密码得跟WinCC服务器本地账户对上。我调试那两天,一半时间耗在“OPC客户端连上了,读一秒卡十秒”和“明明同一网段,却提示拒绝访问”这种问题上。
如果你一定要走这条路,建议让Node-RED去连一个OPC UA网关(比如Kepware或者软网关),由网关去跟WinCC的DA通信,再以UA协议暴露给Node-RED。等于多一层,但把最难的DCOM问题隔离在了网关和WinCC之间,后面Node-RED侧就清爽很多。
2.3 路线C:直接读WinCC后台SQL库——最不建议
WinCC的历史数据、报警记录都存在自带的SQL Server里,懂点SQL的工程师自然会想:能不能直接查数据库拿报警?我的回答是能,但强烈不建议。一是WinCC的归档表结构属于内部实现,官方不承诺兼容,你查表的SQL这次能用,下个补丁包一打可能就不能用了;二是实时性不行,SQL Server里的过程值经过归档周期延迟,少则几十秒,多则分钟级;三是最要命的,如果你只读还好,万一查询条件写得不合适,把WinCC的数据连接拖垮了,那问题就大了,你本来是来解决报警的,结果把监控搞挂了。这条路线我直接排除。
2.4 路线D:让WinCC脚本导出CSV文件——做补充可以,做主力别想
也有一种思路:在WinCC里写个全局脚本,把报警信息定时写成CSV文件,Node-RED通过共享文件夹或者FTP去读。实现简单,适合WinCC侧不方便开OPC、PLC地址表也拿不到的场景。缺点同样明显:脚本跑在WinCC服务器上,WinCC负载高的时候脚本会卡;文件轮转要处理;两台机器之间还得搞网络共享。我把它定位为“临时顶一下”的方案,不推荐当作长期主力。
2.5 我的最终选择
综合考虑,我选了:PLC直接读(路线A)为主,OPC DA转UA(路线B)做补充。因为S7直读最稳实时性最好,还不依赖WinCC的状态;只有个别拿不到地址的点,才从WinCC变量里绕一下。下面对比表是我当时做决定用的,也放出来供你参考:
| 取数路线 | 实时性 | 对原系统侵入性 | 实施难度 | 维护成本 |
|---|---|---|---|---|
| S7直读PLC | 秒级 | 极低,仅占用通信资源 | 低,需要地址表 | 低 |
| WinCC OPC DA转UA | 秒级到数秒 | 低,需配置DCOM | 较高,依赖OPC网关 | 中 |
| 查SQL Server归档表 | 分钟级 | 高,有拖垮库的风险 | 中,表结构不公开 | 高 |
| WinCC脚本导出CSV | 秒级到数十秒 | 中,脚本跑在WinCC上 | 低 | 中,文件轮转繁琐 |
3. 报警流的核心设计:Node-RED里别只做“转发”
很多教程让你装个节点、拉根线、连上微信就完事。真按那个做,上线当晚你就得被报警刷屏刷到怀疑人生。我这边刚开始就是吃了这个亏,后来把报警逻辑重写了一遍,才消停。
3.1 轮询、变化检测和去抖
Node-RED里用S7节点定时读报警字,默认就是周期轮询。最简单的做法是每个周期把读到的值直接发到微信,结果就是:只要某个位是1,微信每秒钟响一次,手机直接变震动棒。所以第一步必须做变化检测。在function节点里把本次读的值跟上次的值做异或,只有发生变化的位才进入后续判断。
第二步是去抖。工业现场电磁干扰、接触器吸合、通信瞬时中断,都会让点位状态闪一下。我踩过一次,一夜之间推了四十多条假报警,全是机柜里一个24V继电器抖动带出来的。后来加了个“连续三次读到同一个状态才确认为真”的规则,误报基本归零。代价是报警延迟增加了几秒,但对微信通知来说完全可接受。
下面是我这个function节点里去抖和变化检测的核心思路,供参考:
// 假设msg.payload是S7读回的报警字(数值) let current = msg.payload; let ctx = context.get("alarm-filter") || { last: null, count: 0, confirmed: null }; // 如果当前值与上一次一致,累计计数;否则置零 if (ctx.last === current) { ctx.count = Math.min(ctx.count + 1, 3); } else { ctx.count = 1; ctx.last = current; } // 连续3次一致,才认为状态稳定 if (ctx.count >= 3 && ctx.confirmed !== current) { ctx.confirmed = current; context.set("alarm-filter", ctx); // 此时才把数据交给后续消息分发节点 return msg; } context.set("alarm-filter", ctx); return null; // 不满足条件,流程到此为止3.2 报警级别、恢复通知和防刷屏
不是所有报警都值得半夜把人吵醒。我按现场重要性把报警分成两级:一级报警是设备停机、安全回路断开这类,必须立即推送;二级报警是温度偏高、压力波动这类,白天推送、晚上合并到次日早报里。Node-RED里实现很直接,判断点在变化检测之后,根据报警字对应的位掩码决定走哪条分支。
恢复通知容易被忽略,但不做的话,你半夜被叫醒处理完故障,刚要睡,报警还是挂在那里。我在状态机里加了一个“从报警到正常”的翻转判断:某一位从1变回0,就推一条“XX设备报警恢复”的消息。这样值班人员看到“恢复”两个字,就知道事情翻篇了。
防刷屏同样是刚需。如果现场出了大故障,几十个点同时报警,就算做了去抖,微信也会瞬间收到几十条。我加了个简单聚合:一分钟内如果报警条数超过10条,后面就不再逐条推,改成每5分钟推一条汇总,比如“当前共15个报警,最新:2号线主电机过载”。真正常见的故障场景,用这一招基本能压住。
3.3 状态存哪里,以及网关重启后的恢复
Node-RED的上下文默认存在内存里,一重启,之前“是否在报警中”的记性全没了。更尴尬的是:如果网关半夜自动重启,而现场刚好有报警,重启后Node-RED读到报警位是1,但由于没有历史状态对比,它可能认为状态没变化,就不推送了。
解决方法是把上下文改成文件持久化,在settings.js里配置contextStorage,Node-RED会把context存到本地文件。然后加一个启动节点(inject节点设为“启动时触发一次”),让流程启动后主动把所有报警点位的当前值读一遍,跟文件里保存的“上次确认状态”做比较,如果发现本来就该报警却没推过,立即补推一条“网关重启,当前设备处于报警状态”。这个细节,实测能避免大部分“网关重启导致漏报”的背锅。
4. 微信通道怎么选:企业微信群机器人还是应用消息
数据拿到手、逻辑判完了,接下来就是最后一公里:怎么把消息送到人的手机上。微信通道这块,我试过几条路,结论比较明确。
4.1 个人微信方案,我不推荐碰
有人会提“用个人微信的hook协议”去发消息,实现起来看起来很简单,但我劝你别碰。原因有三:一是个人微信没有官方开放接口,所有hook都处于灰色地带,随时可能被限制甚至封号;二是工厂的报警消息属于生产数据,走一个不稳定的通道,哪天半夜悄无声息挂了,你压根不知道;三是维护成本全在你身上,账号一掉线,第一责任人就是你。做自动化运维的,稳定压倒一切,这种方案再省事也pass。
4.2 企业微信群机器人:最简单的广播通道
企业微信里可以创建一个群,把设备运维、车间值班的人都拉进去,然后在群设置里添加一个“群机器人”,会得到一个Webhook地址。Node-RED这边不需要装任何额外节点,用HTTP Request节点POST一段JSON就够了:
{ "msgtype": "markdown", "markdown": { "content": "## 2号线停机报警\n设备:主电机过热\n时间:2025-01-15 02:13:45\n建议:请值班人员立即到配电柜检查" } }请求地址是https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=你的机器人key。群机器人最大的优势是简单,不涉及token获取、用户管理,二十分钟就能通。缺点是只能往群里推,不能精确指定某个人,所有人一视同仁。
4.3 企业微信应用消息:能@到具体责任人的定向通道
如果想要“白天推值班群、晚上只推车间主任”这种精细化规则,就得用企业微信的自建应用。流程稍微绕一点:先在企业管理后台创建一个“报警通知”应用,拿到CorpID、Secret和AgentId;Node-RED里先请求gettoken接口换取access_token,有效期7200秒,建议缓存起来别每次都换;然后调用message/send接口按用户账号发消息。请求体大致是:
{ "touser": "zhangsan", "msgtype": "text", "agentid": 1000002, "text": { "content": "2号线主电机过载,请立即处理。" } }实际用下来,应用消息和群机器人不是二选一,而是组合使用:一般报警走群机器人广播到值班大群;严重报警走应用消息点对点推给车间主任和设备员。另外提醒一句,企业微信接口有频率限制,群机器人官方限制是每分钟20条,正常报警场景完全够用,但如果你的报警聚合逻辑没做好,触发了频控,微信侧会返回错误码,这时Node-RED里要做错误重试,不然消息就悄悄丢了。
4.4 第三方推送服务也能用,但工厂场景慎选
市面上还有Server酱、PushPlus这类推送服务,注册后给个Key,HTTP请求一发,消息就到微信。个人项目或设备数量很少的场景可以玩,但我没把它作为生产主力,原因是数据要经过第三方服务器,报警点位、设备名称这些信息等于裸奔给外部,很多工厂的信息安全要求不允许。企业微信是官方通道,消息不出企业域,合规性上踏实得多。
5. 边缘网关硬件选型与现场部署的几个关键决定
Node-RED本身对硬件要求很低,一块树莓派就能跑。但“能跑”和“能稳定跑在工业现场”是两码事,硬件选型上我有几个实际经验。
5.1 几种硬件方案的对比
| 方案 | 成本 | 稳定性 | 推荐程度 |
|---|---|---|---|
| 树莓派4B/5 | 300-600元 | SD卡容易坏,工业现场慎用 | 不推荐作主力 |
| 二手迷你工控机(如戴尔3050微型机) | 300-800元 | 配SSD后很稳定 | 推荐 |
| 全新工业防火墙/边缘网关 | 2000-4000元 | 高,有商业支持 | 预算充足选这个 |
| 复用现有服务器开虚拟机 | 0-1000元 | 高,但依赖宿主机 | 看现场条件 |
我最后用的是二手迷你工控机,i5处理器、8G内存、256G SSD,价格五百出头。Node-RED只占其中很小一部分资源,剩下的算力我还顺便跑了一个Modbus TCP采集服务,把几台老变频器的数据也接进来了。工业现场不建议用树莓派的SD卡,我见过太多“跑着跑着文件系统只读”的案例,换成SSD以后基本不会犯病。另外电源一定要原装或工业级适配器,最好再挂一个小的UPS。网关电源挂了的案例,比网关本身坏掉的还多。
5.2 网络接线和访问控制
网关接在PLC同一台交换机上,IP规划要避开WinCC服务器、工程师站和触摸屏,设一个固定IP。接下来是容易被忽略的一点:只放行必要流量。我在网关的操作系统里用iptables做了限制,入方向只允许以下几类:
- PLC的102端口(S7通信)
- 如果走OPC UA,则允许OPC UA服务端口(通常4840)
- 本机SSH、Node-RED管理端口(1880)只允许工程师站IP访问
出方向只允许HTTPS到企业微信接口域名。这个规则我强烈建议你按同样思路做一遍。边缘网关一旦暴露太开,等于给控制网开了个口子,哪怕内网相对可信,多一层隔离多一分安心。Node-RED的管理界面也要设置用户名密码,默认无认证直接访问,这在工控网里太危险了。
5.3 成本算总账
硬件五百多,加上调试两天的人力,总成本不到两千块。对比官方WebUX选件几万块的报价,或者升级V8整套工程几十万的花费,这套方案基本等于“不要钱”。而且网关后续还能干很多事,采集设备OEE数据、做能耗统计、给MES系统喂数据,相当于花一次钱,搭了一个长期的边缘数据底座。
6. 上线半年踩过的坑,以及现在的运行习惯
方案跑到现在小半年了,从最初“半夜群里闹翻天”到现在的“安静到快忘了它的存在”,中间踩了不少坑,挑几个值得说说的。
6.1 坑一:S7连接资源被占满了
Node-RED通过S7协议跟S7-300通信,占的是CPU的PG/OP连接资源。老款S7-300这块资源本来就紧张,WinCC占了两个,工程师站的编程器占了一个,触摸屏再占一个,Node-RED再挤进去,CPU直接报“通信连接资源不足”。一开始我百思不得其解,明明昨天还好好的,过了一天就断了。后来去硬件组态里看CPU属性里的通信资源,才发现连接数已经顶格。
解决办法有几个:一是把Node-RED的轮询周期从1秒放到3秒,连接资源占用会明显下降;二是如果还有富余的通信处理器(CP卡),把连接放到CP卡上;三是换用OPC UA路线,避开这个资源问题。我最后是“降频+规范重启时间”双管齐下才消停。
6.2 坑二:DCOM时好时坏,差点劝退
第一次尝试OPC DA的时候,DCOM问题简直是我那两天的噩梦。白天配好了能读,到了晚上WinCC服务器一锁屏或者安全策略一刷新,又连不上了。后来我看清楚了,DCOM的坑不在于配置项本身,而在于Windows环境和域策略一变化就得重来。这也是为什么我更推荐直接走S7协议的原因——它根本不依赖Windows那一堆用户权限模型,TCP 102端口一开,通信干干净净。
6.3 坑三:报警抖动,半夜被误报“轰炸”
去抖逻辑是上线后第二周补上的。当时2号线的冷却风机一启动,接触器吸合的瞬间,PLC输入模块上有个备用点信号闪了一下,Node-RED检测到变化就直接推了“风机故障”报警。值班员跑过去一看,风机转得好好的。这种事一晚上发生三次,群里怨声载道。加了“连续三次确认”的去抖之后,这种物理抖动基本被过滤干净了。小经验:去抖的确认次数不要设太大,否则真实报警也会被拖得响应很慢,三次是个不错的平衡点。
6.4 坑四:网关重启后状态丢失,漏报
有一次厂里检修,顺便给网关所在的机柜断电了。恢复供电后网关自己起来了,WinCC和PLC都正常,但Node-RED内存里的状态全没了。最尴尬的是,当时恰好有一台泵处于报警状态,但因为“没有状态变化”,Node-RED认为无需推送,一直没发消息。第二天早上我是看到现场值班记录才发现这个漏报。从那以后我就做了两件事:第一,context持久化到文件,这是必须的;第二,在Node-RED启动时增加“全量状态核对”逻辑,把所有报警位读一遍,凡是没有推送过且当前确实处于报警状态的,补发一条“网关重启后恢复报警上下文”。这两件事做完,“重启丢状态”这个隐患彻底解决。
6.5 坑五:时间不同步,报警时间戳对不上
网关的时间和PLC时间如果差了五分钟,报警消息里显示的时间和WinCC趋势图的时间就对不上,排查故障的时候会把方向带偏。解决很简单,在网关里配了NTP同步,指向厂里的时间服务器,同时把PLC的时钟同步也打开,两边时间严格对齐。这个细节看着小,但等你真靠时间戳去倒查故障前因后果的时候,就知道有多重要了。
6.6 现在的运行习惯
- 每周自动备份:Node-RED的流程存在
flows.json里,我写了个定时任务,每周打包一次备份到另一台机器。 - 网关自监控:给网关本身加了个心跳机制,每隔5分钟往值班群推一条“心跳正常”消息。如果群里超过10分钟没看到心跳,就说明网关可能挂了,值班员会第一时间通知我。代价是群里多了点无用消息,但换来的安心感值了。
- 升级前先测:Node-RED生态更新很快,但我不在生产环境随便升级节点库。每次都是先在备用环境测一天,确认不破坏现有流程再动手。
这套微信报警方案,其实只是边缘计算网关在老产线上的一次小试水。数据既然已经能从PLC里出来了,后面能做的东西还有很多,比如设备OEE统计、能耗分析、关键参数趋势预测。对我个人来说,最大的体会就一条:老系统能不动就不动,用最小的改动,去解决现场最痛的问题。微信报警只是起点,边缘侧的玩法,才刚刚拉开序幕。