导读:这篇文章专治西门子设备想接Telegram发告警的疑难杂症。从机器人创建、网络权限到账号封控风险,全部按实操顺序拆解,附具体报错码和超时参数,照着做基本能通。
📖 本文目录
群里最近好几个人问西门子PLC或者WinCC能不能直接发消息到Telegram,我都回了同一句话:能,但别一上来就找API文档硬啃,先把这个东西拆成三块看——机器人怎么建、网络怎么通、数据怎么塞进去。今天我把这些年处理过的工控用户案例整理一下,分几步给你捋明白。
一、西门子对接Telegram,最基本的机器人先搞对
用BotFather创建机器人这一步可以说是全网教程最多的,但我发现工控圈的朋友老在token上栽跟头。你找BotFather要token的时候,它会给你一串类似 123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11 的字符,注意这串东西是分两段的,冒号前面是bot ID,冒号后面才是密钥。很多人复制的时候把空格带进去了,或者从聊天记录里复制时被自动换行截断,结果HTTP请求一直返回401。我处理过最快的一例是5分钟内解决的,就是重新复制token,去掉首尾空格。你要是用WinCC自带的脚本功能,建议把token存在一个单独的DB块里,别直接写死在程序里,毕竟WinCC项目文件传来传去,token泄露了别人就能控制你的机器人。
另外,机器人建好之后,你必须先去和它聊一句,比如发个 /start,不然机器人没法主动给你发消息。这一步看起来多余,但常被忽略,尤其是你在用TIA Portal V17及以上版本做集成时,如果忘了这个动作,后面测试时API会返回 403 Forbidden。这个坑我见过至少20次,每次都是远程帮人点一下 /start 就好了。
二、工控网段访问Telegram,网络策略比想象中麻烦
西门子设备大多在生产网段,而Telegram的服务器在境外,这就牵扯到防火墙和代理。先给你一组实测数字:如果你直接允许TCP 443出站,不带任何代理,从PLC所在地(比如苏州某工厂)访问 api.telegram.org,平均延迟在180ms左右,发一条文本消息从触发到送达大概0.6秒到1.2秒。这个速度对告警推送来说完全够用。麻烦的是很多工厂的安全策略只允许白名单域名,而Telegram的API域名经常换IP,今天解析出来是 149.154.167.220,明天可能就变成 149.154.175.50,你没法在防火墙上按IP锁定。我的建议是你在防火墙上单独给 api.telegram.org 和 core.telegram.org 开一条HTTP代理规则,别跟其他工控流量混在一起。
还有一点很多人不知道:Telegram机器人API对TLS的指纹有要求,如果你的防火墙做了SSL解密(就是中间人那种),机器人会报 500 Internal Server Error,代码里面啥也看不出来。我们在实验室测过,只要把SSL解密策略关掉,单对单通信马上恢复。所以别一上来就查PLC程序,先把网络工程师拉过来,确认Telegram的流量没有被HTTPS过滤设备动过手脚。要是你的环境实在改不了策略,那就考虑用一台在办公网段的边缘网关做转发,把告警数据先通过S7协议送到网关,再让网关上网发Telegram。这套方案我们给一个汽车零部件厂部署过,网关用的是树莓派4B,成本大概800块,稳定跑了14个月没重启过。
三、PLC数据推给机器人,S7协议和HTTP请求怎么写不踩坑
到这一步,你的PLC得能把告警文本和chat_id拼成一个HTTP请求发出去。西门子S7-1200和S7-1500从固件V4.4开始支持TCON和TSEND_C指令走TCP,但是用它们拼HTTP的POST请求很痛苦——你要手动构造报头,Content-Length算错一个字节,服务器就回400。我给你一个绕过办法:直接用S7-1500的 HTTP_Request 指令,我用的版本是V6.0的库函数,它可以直接发GET和POST。举例说,你想发一条文本:"报警: 1号炉温度过高",URL编码后变成 %E6%8A%A5%E8%AD%A6... 这一串东西,你把它们拼在请求体里,数据长度别超过4096字节,这是HTTP_Request的最大限制。超了的话,返回码是 8220,意思是数据块长度溢出。
不过我没建议你在PLC里直接处理文本编码,那太占资源了。更顺手的做法是让WinCC的全局脚本C脚本去跑WinHTTP请求,因为WinCC这边可以直接在画面里拖一个报警控件,把报警文本变量拿来用。C脚本里用 WinHttpOpen 和 WinHttpSendRequest,注意设置超时时间——我建议连接超时设3000ms,接收超时设5000ms,这是调过的经验值。太短了网络抖动一下就超时,太长了报警堆积,万一Telegram那边卡了,你的脚本会一直挂着占内存。我们实测过,如果在WinCC报警记录里触发100条报警,同时并发发HTTP请求,Telegram会限流,返回429 Too Many Requests。这时你需要控制发送速率,每秒钟最多发1条,不行的话每10秒发1条。我们现场调的就是每秒1条,连续发30条没问题。
四、Telegram账号被封或受限,工控告警中断的救急方案
这里要聊一个大家不爱听但必须面对的事:你的机器人账号可能被封,或者被限制发送。别问我为什么知道——我用官方API给三个不同工厂做告警,其中一个用的个人Telegram号码注册的bot,在连续高频率群发后(比如每分钟发60条以上),隔天那个号就被限制只能加入已存在的群聊,无法主动发起新对话,等于告警全哑了。那事发生在一个周末凌晨2点,值班人员没收到预警,后来去现场才发现设备停机了。后来我给那个厂换成了官方Bot API配合本地轮询模式(setWebhook删掉,用getUpdates拉取消息),频率控制在每秒最多5条,跑了半年没再出问题。你要知道,Telegram对bot的限制阈值大概是每条消息之间最少间隔20ms,但实际推荐是每次请求之间间隔100ms以上,不然容易出现 429 错误。429错误出现过5次以上,你的bot可能会被系统标记,然后禁止调用API 2个小时左右。
所以我在给客户做方案时,通常会建议他们买一个长期稳定的API号来当机器人载体,别用自己私人手机号注册的号去搞生产告警。你像我们站里提供的 缅甸API高权老号 和 加拿大API稳定号,都是注册超过一年且没被风控过的,专门拿来跑这种自动化推送,就算触发限流,封的也不是你的主号。曾经有个用尼日利亚号跑推送的客户,连续运行9个月没出过问题,那个号到现在还活着。

五、告警消息太长或格式乱,Telegram渲染格式的坑
很多工程师喜欢在告警里塞一大段描述,什么设备型号、具体位置、PLC程序块名,全拼在一起。结果发到Telegram上发现内容被截断,或者链接没法点。Telegram对单条消息的长度上限是4096个字符,超过这个数会直接报错,API不给你发送。我们用WinCC拼过一条最长3000字符的消息,里面包含中英文和换行,发出去显示正常。你要是需要在一条告警里放多个信息点,建议用HTML格式的parse_mode,把重点内容加粗或者用标签圈起来。但注意,Telegram的HTML解析器对不闭合的标签很敏感,比如你写了一个但忘了加,API会返回400 Bad Request。我自己写脚本时,会先在本地把字符串用文本替换函数转义掉 &、<、> 这些字符,再拼接标签。
还有个体验问题:你发过去的报警如果是一长串数字,Telegram可能会把超过15位的数字自动识别成链接(因为它觉得可能是电话号码)。解决办法很简单,在数字前后加空格或者用反引号包起来。像我们给一个水处理厂做的推送,液位值 12.345678 就被识别成电话号码,对方手机上显示成蓝色下划线,点一下就尝试拨号。后来在格式里加了一个不可见字符(U+200B零宽空格)在数字尾端,这个问题就地解决了。什么你是WinCC7.5?那没关系,脚本里用 sprintf 就能插入这个字符。
六、多级告警和值班人换班,chat_id管理是门学问
告警不能只发给一个人,车间主任、设备科长、夜班值班员,不同级别要收到不同的内容。Telegram里一个用户一个chat_id,你在脚本里得维护一张对应表。有的人图省事,把几个相关人都拉进一个群,然后把消息发到群里,chat_id用群ID。这方法可行,但有个坑:群里的任何人都能通过 /setchatphoto 或 /newtitle 改群设置,要是不小心把机器人移除群,或者群里有人恶意开了私聊禁言,你的告警就发不进去了。我建议用频道(Channel)而不是群,频道没有成员管理权限,机器人发布的任何消息都不能被成员删除。把频道设为公开或私有都行,私有频道你只需要把值班员的账号添加为订阅者就行。频道ID格式一般是 -100XXXXXXXXXX,很长,别抄错。
换季或项目变更时,值班人名单要改,你不可能每次去刷PLC程序。更好的方式是把值班人对应的chat_id和班组表存在一个CSV文件里,放在一个共享文件夹中,每次脚本启动时读取。我们用这个办法给一个钢厂做过,他们每条产线有3个班组,每班组5个人,总共15个chat_id,用CSV管理,增删改都不需要碰PLC。CSV文件里每一行是一个班组名和一个组ID,告警消息里带着产线编号,通过正则表达式匹配组ID来选发送目标。这段逻辑用C脚本写大概要200行,但一劳永逸。你要是不愿意自己写,也可以在WinCC的Global Script里跑VBScript,用ADODB读Excel表格,但那个每次都要装Excel驱动,碰上64位系统还容易报“未找到提供程序”的错误。我踩过那坑,后来干脆直接用CSV,任何文本编辑器都能改。
七、告警频率过高导致的信息轰炸,降噪策略怎么定
设备闪断的时候,报警和恢复消息可能在几十秒内来回切换,你要是每个状态变化都发一条,人家手机能被打爆。在PLC里生成报警时,我们通常做一个延迟确认功能:比如温度超过80度这个条件持续5秒才触发报警,低于75度且持续10秒才恢复。这个参数需要根据工艺调整,我建议你在WinCC报警类别里把应急等级设为“需要延迟确认”,延迟时间设5000ms。还有一种是绝对禁止的:不要用同一个设备同一个报警代码在1分钟内重复发,就算状态变了也不要。Telegram虽然有频率限制,但你自己的告警接收人会觉得被骚扰,久而久之他们就把这个聊天置为免打扰了,反而错过真正的严重故障。我们给一个光伏电站做过统计,他们平均每天产生2000条报警记录,但真正需要推送到手机的每天不超过150条。过滤规则就三条:报警优先级大于等于P2、持续时间超过30秒、没有在最近10分钟内重复出现过。这三条规则写下来,他们的推送数量骤降到每天40条左右,值班员好评如潮。
八、调试时最容易冤枉人的几个报错,对照着查
有的朋友遇到问题就怀疑是PLC程序错,其实不少是HTTP封装的问题。我列几个高频的报错:报错 400 Bad Request,查一下URL是否包含空格或者中文没编码,尤其是getUpdates返回的chat_id里面有负号,你可能把它当字符串处理时丢掉负号了。报错 401 Unauthorized,查token是否少了一位或多了空格。报错 404 Not Found,很可能是你调用了旧版的API方法,现在Bot API已经到7.3版本了,sendMessage得指定chat_id,不能简写成chatID。报错 409 Conflict,这个烦人,表示你同时用了getUpdates和setWebhook两种方式都开启了。你必须手动调一次deleteWebhook(把它设置为true)再改用轮询模式。在WinCC中调用HTTP请求时,建议你先用Postman把请求测通,再到脚本里复制粘贴——这能帮你区分是网络问题还是代码问题。
还有一点,你如果从S7-1500直接发HTTP请求,一定要看返回的状态码200,但状态码200不代表消息真正发到用户手机了。Telegram API的响应体里会有“ok”:true字段,你得解析响应体才能确认。很多工控工程师只看HTTP码,结果响应体里明明写着“ok”:false,原因是chat_id填错成了一个不存在的数字。我们在用HTTP_Request的时候,常常用它的StatusCode 加 输出的响应字符串来判断。响应字符串里若有“chat":{"id":123456789”,你再去和数据库对照一下那个id,基本不会出岔子。给一个具体的检查步骤:先用浏览器打开 https://api.telegram.org/bot<你的token>/getMe,能看到机器人信息就说明token没问题,然后再用 getUpdates 配合手动发一条消息去查chat_id。这招能解决掉80%的“发不出去”问题。
最后顺带提一句,如果你不想自己维护bot注册、网络踢皮球,也可以直接找现成的稳定通道资源,比如我们站内整理的尼日利亚API老号或者加拿大号,注册时长和使用权重都比较理想。我们在实际帮客户部署时,60%的故障都不是代码问题,而是账号被封或受限导致的。所以建议你把账号稳定性当做一个基础设施来对待,别等到报警推送断了才想起来去换号。
常见问题
西门子1200怎么发信息到Telegram,需要额外买什么硬件吗?
S7-1200从固件V4.4起CPU本体就可以发TCP请求,不需要额外硬件。但要用HTTP_Request指令,前提是你得把固件升级到V4.4及以上。如果固件太老(比如V4.0),那就只能外接一个树莓派或者ESP32来转发。
我去BotFather申请了token,为什么发消息一直提示401?
401大概率是token复制的问题,检查一下token里有没有空格或换行。最稳的验证方法是把整个token拼在 https://api.telegram.org/bot 后面,粘贴到浏览器地址栏打开,能看到返回一串JSON就说明token有效,然后再去检查你脚本里的变量赋值。
告警消息发到Telegram之后,手机不弹通知怎么办?
先确认你是把告警发到和机器人对话的私聊还是群里。私聊默认有通知,但群聊里的机器人必须先把群设为“全部通知”或“提醒我所有消息”,不然容易静音。还有一个坑:如果你的手机开了省电模式,Telegram后台可能被冻结,收不到推送,建议在系统电池优化里把Telegram设为不限制,不然延迟能到半小时。