在工控现场摸爬滚打久了,你大概率会遇到这么个场景:中控室里放着几台甚至十几台图控电脑,每台都跑着Wonderware InTouch,各自监控着不同的工段或者设备区域。平时操作员各看各的,但一旦发生报警,特别是夜班或者现场没人盯着的时候,信息的汇总和推送就成了一个大麻烦。你总不能让操作员同时盯着十几块屏幕,也不能让每一台电脑都接一个独立的报警器。这时候,有人会想到用SMSAlarm这类短信报警网关来统一处理报警信息,但问题随之而来:SMSAlarm怎么才能把多台InTouch图控电脑的数据整合起来?是每台电脑都装一套,还是只装一套然后通过网络去抓数据?报警优先级怎么区分?数据源怎么配置才不会冲突?
这些问题我当年都踩过坑。这篇文章不跟你讲虚的,直接拆解一个我实际落地过的整合方案,把SMSAlarm在多台InTouch图控电脑环境下做数据整合的架构思路、关键配置、踩坑实录都拿出来讲一遍。无论你现在是刚接触InTouch的组态新手,还是已经在现场被多节点报警折腾得焦头烂额的老工程师,这篇文章都能给你一个可以直接“抄作业”的参考路径。
1. 项目整体设计与思路拆解
1.1 多台InTouch图控电脑的典型架构与痛点
先说场景。一个典型的化工车间或者水处理厂,通常会按工艺段划分监控区域。比如A区是原料进料,B区是反应釜,C区是成品灌装。每个区域放一台工控机,运行各自的InTouch应用,通过OPC或者DDE从PLC采集数据。这个架构本身没毛病,问题出在报警的“孤岛效应”上——每台InTouch只处理自己那一亩三分地的报警,操作员只能看到当前这台电脑绑定的区域,其他区域的情况要么不知道,要么得跑过去看。
更麻烦的是,当某台InTouch电脑死机或者重启的时候,这个区域的报警就彻底失明了。现场仪表还在报警,但上位机不叫不响,等操作员发现异常往往已经过了半天。所以,我们需要一个独立于单台InTouch之外的报警汇总机制,SMSAlarm就是干这个用的。
SMSAlarm本质上是一个短信报警网关,它可以把来自不同数据源的报警信息,按照预设的规则转换成语义明确的短信内容,然后通过GSM模块或者短信猫发到值班人员的手机上。它本身不替代InTouch,也不替代PLC,它做的是“报警的最后一公里投递”。
但这里的核心难点是:SMSAlarm的数据从哪来?如果只接一台InTouch的串口或者OPC,那其他电脑的报警根本拿不到。所以,整合多台InTouch的数据,关键不在于SMSAlarm本身,而在于你如何把分散在各台InTouch里的报警状态统一“抽”出来,再喂给SMSAlarm。
1.2 SMSAlarm在多节点环境下的三种集成路径
要整合多台InTouch电脑的数据,我梳理下来有三条路可以走,各有适用场景。
第一条路,叫“数据库中间表方案”。让每台InTouch在有报警发生时,把报警记录写入一个共享的数据库服务器,SMSAlarm轮询这个数据库表,发现新记录就发短信。这个方案架构最干净,InTouch只负责写数据,SMSAlarm只负责读数据,两者完全解耦。
第二条路,叫“OPC聚合方案”。所有InTouch电脑的报警状态先汇聚到一个中间OPC服务器,SMSAlarm通过OPC客户端接口去订阅报警变量。这个方案实时性最好,但部署复杂度高,需要确保OPC服务器的稳定性和网络链路质量。
第三条路,叫“多串口网关方案”。每台InTouch通过串口直接连接SMSAlarm的多个串口,SMSAlarm本身就是一台工控机,同时接多路串口卡,每路串口对接一台InTouch。这个方案听着土,但在早期串口设备为主的现场很常见,现在基本不怎么用了,因为布线麻烦,而且串口距离受限。
我在实际项目里最后选了第一条路,也就是共享数据库中间表。为什么?因为现场条件不允许铺太多网线,而且OPC服务器资源有限,不想在OPC层面引入额外故障点。数据库中间表方案最稳妥,只要网络通、数据库通,数据就不会丢。当然,有得必有失,这个方案的短板在于实时性会有1到2秒的延迟,但对于短信报警这种应用场景,2秒延迟完全可接受。
提示:不要一开始就纠结SMSAlarm的型号和品牌。先把数据流架构想清楚,SMSAlarm顶多算个执行终端,真正决定项目成败的是报警数据的汇聚逻辑。
1.3 为什么说报警数据的“源头归一”比报警发送更关键
很多人在做这类项目时有一个误区:以为买了SMSAlarm,事情就成了一半。其实恰恰相反,SMSAlarm的短信发送功能非常成熟,反而“多台InTouch的报警异构性”才是最大的坑。
什么叫异构性?举个例子,A区的InTouch写的报警记录表里,报警级别可能是“高、中、低”这样的枚举值;B区可能用的是“1、2、3”这样的数字代码。A区的变量名是REACTOR_TEMP_HH,B区可能是T_ALM_01。如果不做归一化,SMSAlarm拿到手的报警信息五花八门,短信内容会非常混乱,值班人员光看短信都不知道这是哪台设备的什么报警。
所以,整个项目的核心思路应该是:先建一个“标准报警模型”,然后让每台InTouch的报警都向这个模型靠拢。可以定义一张标准报警表,字段包括:报警编号、报警时间、区域标识、设备标识、报警描述、报警级别、报警状态。每台InTouch的脚本负责把自己本地的报警翻译成这个标准格式,写入共享库。SMSAlarm只认这张表,不关心具体是哪台电脑写的。这样,整合就从“多对一的消息杂乱拼接”变成了“多对一的标准化汇聚”,SMSAlarm发送的短信永远是一眼可读的。
这个思路一旦确立,后面所有配置都有了主心骨。不管是新增一台InTouch,还是调整报警级别,你只需要改一台电脑的脚本映射即可,SMSAlarm那边纹丝不动。
2. 核心细节解析与实操要点
2.1 InTouch报警输出的主流方式对比
在InTouch里,要把报警状态送到外部系统,通常有三种做法:DDE、OPC(SuiteLink)、以及本地脚本+SQL。这里我不做全量技术对比,只从“多台整合”这个视角告诉你该怎么选。
先说说DDE。DDE是老古董了,很多新工控机装完系统都不再默认支持完整的DDE服务,而且DDE传输效率低,多台电脑同时往外推数据容易丢包。如果现场还是用DDE来跨机器传递数据,我建议尽早换掉。
再说OPC。InTouch对OPC的支持比较成熟,但要注意,InTouch主要是作为OPC客户端去读PLC数据,如果InTouch要作为OPC服务器把自己的数据“发布”出去,一般还需要装相应的DA或UA Server包,这会让每台InTouch机器背上额外的服务进程,对工控机的稳定性是个考验。另外,当SMSAlarm作为外部客户端去订阅多台OPC服务器的变量时,只要网络有波动,就容易出现断连重连的告警,维护工作量大。
最后说本地脚本+SQL。这是我最常用也最推荐的方式。InTouch自带的脚本语言支持SQL查询函数,比如SQLConnect()、SQLInsert()等。你可以在报警发生时,通过脚本把报警信息写入SQL Server或MySQL数据库。这个方案不引入额外协议,只依赖Windows网络和数据库访问,稳定性和通用性都最强。
用SQL方案还有个额外好处:后续如果你想做历史报警查询、按班组统计报警次数、或者跟MES系统对接,这些数据已经在数据库里了,你不需要再额外开发数据导出功能。
注意:SQL脚本方案对InTouch开发者的脚本能力有一定要求。但放心,InTouch的SQL脚本没那么难,本质上就是“连接数据库 -> 执行INSERT语句 -> 断开连接”这三板斧。
2.2 共享数据库表结构的关键设计
既然选了数据库中间表方案,那表结构设计就至关重要。设计得不好,后面每台InTouch往表里塞数据时,总会在兼容性上卡壳。我总结出一套能直接用的报警记录表结构,你可以照着建。
核心表可以命名为Alarm_Records,字段如下:
| 字段名 | 类型 | 说明 |
|---|---|---|
| AlarmID | INT IDENTITY | 自增主键,用来区分每条报警记录 |
| AlarmTime | DATETIME | 报警发生时间,统一由InTouch本地时间生成 |
| AreaCode | VARCHAR(20) | 区域编码,比如A区是AREA_A,B区是AREA_B |
| DeviceName | VARCHAR(50) | 设备名称,比如P-101泵或T-201罐 |
| TagName | VARCHAR(50) | InTouch中的标记名,方便回溯到具体点 |
| AlarmDesc | VARCHAR(200) | 报警描述,比如“反应釜温度高报” |
| AlarmLevel | INT | 报警级别,建议统一为1/2/3,对应低/中/高 |
| AlarmState | TINYINT | 报警状态,1表示触发,0表示恢复 |
| SourcePC | VARCHAR(30) | 来源电脑标识,方便后期排查哪台电脑发的 |
| IsSent | TINYINT | 是否已发送短信,SMSAlarm会更新这个字段 |
有几个字段特别要留意。
AlarmTime,必须用InTouch的本地时间,不要用数据库服务器的默认时间。理由是,多台电脑之间可能有时间偏差,但至少每台电脑自己内部的时间是一致的,你可以在接通短信网关前统一校准一次工控机时间,这样报警时间的相对顺序是可信的。
AreaCode和DeviceName,必须用统一编码规则。建议在项目一开始就拉一张编码对照表,比如A区进料泵就是AREA_A_P-101,不要出现有人写成A区101泵,有人写成A/P101这种混乱情况。
IsSent字段,是SMSAlarm的“工作指针”。SMSAlarm每扫描一次表,只拿IsSent=0的记录来发短信,发成功后就更新为1。这样即使发送中途断了,重启后也不会重复发送。这是数据整合里非常重要的一个细节,相当于“断点续传”。
2.3 InTouch脚本侧的历史遗留问题与陷阱
说实话,InTouch的脚本写入数据库这一环,看起来简单,实际坑不少。我把自己踩过最深的几个坑,在这里集中说一遍。
第一个坑是“SQL连接饥饿”。如果你在报警脚本里每次都是现连数据库、写完断开的写法,那在高频报警时(比如同一个点在一分钟内反复报警恢复),数据库连接对象的创建和销毁会非常频繁。资源倒不至于立刻耗尽,但容易造成数据库端的大量的连接握手握手超时。后来我改成用一个全局连接,脚本里只做数据的INSERT,InTouch通过SQLConnect()一次建立连接窗口,然后在主界面关闭时或者无人值守模式下用定时脚本维持心跳,整体应答速度快了很多。
第二个坑是“字符串转义”。InTouch脚本里处理字符串时,单引号和双引号的转义规则和高级语言不太一样,尤其是报警描述里如果包含了英文撇号,比如Level's High,直接拼SQL语句很容易把语法搞崩。我的建议是:所有报警描述在写入数据库前,先做一个“清洗”函数,把特殊字符替换成全角字符,或者在InTouch脚本层面就把报警描述统一成不带撇号的写法。
第三个坑是“报警恢复记录的丢失”。很多人在写报警脚本时只处理了“报警触发”的情况,忽略了“报警恢复”也需要写记录。这样一来,如果SMSAlarm已经发送了“温度高”的短信,24小时后温度恢复正常了,现场却没有任何一条恢复短信,值班人员还以为报警还在持续,造成误判。所以在InTouch脚本里,对报警条件变化的两个边沿——上升沿和下降沿——都要捕捉,分别写入两条记录,AlarmState分别置1和0。
这个点最好是在项目验收前就自查一遍,否则后期改脚本要一台一台电脑重新部署,非常费时间。
3. 实操过程与核心环节实现
3.1 准备工作与网络环境确认
在动手写脚本前,先把基础设施确定下来。你需要准备以下内容:
- 一台数据库服务器(如果现场没有现成的,也可以在某一台比较稳定的InTouch电脑上装SQL Server,但我不推荐这么做,毕竟工控机最好专职专用)
- 一个共享的数据库用户账号,每台InTouch都能用这个账号写表
- 每台InTouch电脑上装好SQL Server Native Client或者ODBC驱动
- SMSAlarm网关设备,以及对应的配置软件
网络层面,要确保所有InTouch电脑到数据库服务器的TCP 1433端口都能通。如果现场存在多个网段,提前让网络管理员把路由配好。这里有个经验之谈:先不要急着连SMSAlarm,你先手动用数据库管理工具在每台电脑上测试一下能不能远程写入数据库,这个通了再往下走。
3.2 数据库与表结构的部署脚本
直接在数据库服务器上执行以下脚本,创建中间表:
CREATE TABLE [dbo].[Alarm_Records] ( [AlarmID] INT IDENTITY(1,1) PRIMARY KEY, [AlarmTime] DATETIME NOT NULL, [AreaCode] VARCHAR(20) NOT NULL, [DeviceName] VARCHAR(50) NOT NULL, [TagName] VARCHAR(50) NULL, [AlarmDesc] VARCHAR(200) NOT NULL, [AlarmLevel] INT NOT NULL DEFAULT 2, [AlarmState] TINYINT NOT NULL DEFAULT 1, [SourcePC] VARCHAR(30) NOT NULL, [IsSent] TINYINT NOT NULL DEFAULT 0 ); CREATE INDEX IDX_Alarm_IsSent ON dbo.Alarm_Records (IsSent);IsSent字段上的非聚集索引,是为了提升SMSAlarm扫描时的查询速度。如果表里的历史报警数据积累到几万条,没有索引的话,每次扫描未发送记录都会全表扫一遍,CPU占用会明显升高。
注意:索引不是越多越好,这里只要保证“未发送查询”和“按时间范围查询”的速度即可,不要给这个中间表加太多索引,毕竟它本质上是高频写入的表。
3.3 InTouch侧脚本编写要点
在InTouch里新建一个应用脚本,把这个脚本挂到“条件脚本”或者“数据变化脚本”中。InTouch支持标记名变化触发脚本,这个特性很实用。举例来说,如果你在InTouch里定义了一个内存离散型标记名Alarm_Trigger_Temp_HH,你可以在它的“值变化”事件里写如下脚本逻辑。
伪代码如下:
IF Alarm_Trigger_Temp_HH == 1 THEN SQLConnect("conn", "Provider=SQLOLEDB;Data Source=数据库IP;Initial Catalog=报警库;User ID=user;Password=pwd;"); SQLInsert("conn", "Alarm_Records", "AlarmTime, AreaCode, DeviceName, TagName, AlarmDesc, AlarmLevel, AlarmState, SourcePC", ":AlarmTimeVar, :AreaCodeVar, :DeviceNameVar, :TagNameVar, :AlarmDescVar, :AlarmLevelVar, 1, :SourcePCVar"); SQLDisconnect("conn"); ENDIF;这里的几个TagName变量,你要在InTouch的标记名字典里定义成同名的内存变量,脚本里用冒号前缀引用。需要注意,SQLInsert语法要求每个字段对应一个内存变量,也就是说,如果你要插入10个字段,你需要提前定义至少10个变量。在大型InTouch应用里,这些变量可以通过组的绑定自动赋值,不用手动逐个写值。
对于报警恢复的记录,再写一段类似的脚本,只是把AlarmState置为0,同时AlarmDesc可以写成类似“反应釜温度恢复正常”的描述。
为了方便调试,建议在InTouch的画面里预留一个“数据库连接状态指示灯”,通过返回值来判断SQL操作是否成功。比如SQLConnect()会返回一个整数结果,非0代表失败,你可以把这个结果显示在界面上,或者用一个变量存下来,这样报警时如果数据库连接断了,操作员能第一时间发现,而不是等短信迟迟不来才去查。
3.4 SMSAlarm的规则配置与发送策略
SMSAlarm的配置软件通常本身也是一个工程管理界面,你需要新建一个“数据源”指向刚才的Alarm_Records表。这个步骤不同品牌的设备界面不一样,但核心逻辑都差不多:SMSAlarm会隔几秒查一次表,查到新记录就触发短信任务。
发送策略上要特别注意分组轮巡规则。你不能把每一条报警都发给所有人,那样值班人员手机会被狂轰滥炸。合理做法是:
- 低级报警(AlarmLevel=1):只在工作时间发送,且放到短信列表中延迟等待
- 中级报警(AlarmLevel=2):立即发送,但只发送给当班组长
- 高级报警(AlarmLevel=3):立即发送,并且可以支持“同组连续报警合并为一条”的规则,避免同一设备反复报警时短信重复轰炸
“同组连续报警合并”是SMSAlarm整合多台电脑数据时非常有价值的一个功能。你可以配置成:同一DeviceName在5分钟内的重复报警只发第一条和最后一条,中间抑制掉。这个在设备频繁波动时会极大降低值班人员的厌烦感。
发送优先级这里还有一个小技巧:把AlarmState=1(触发)和AlarmState=0(恢复)两种记录,设置成不同的短信模板。触发短信模板是“【报警】A区P-101泵故障停机”,恢复短信模板是“【恢复】A区P-101泵已恢复运行”。这样操作员不需要看一堆附加数字,扫一眼就知道是报警还是恢复。
3.5 多台InTouch逐步接入的验证步骤
不要一次性把所有InTouch电脑的脚本都部署完,那样出了故障没法定位到具体哪台机器。我的习惯是“先一台,验证全链路,再批量推广”。
第一步,选一台区域较独立的InTouch,部署好脚本,并手动模拟一个报警条件,比如在界面上强制一个标记名为1。此时去数据库里查Alarm_Records表,看有没有新记录写入,字段值是否准确。
第二步,确认SMSAlarm已经能把这条记录发送成短信。手机收到短信后,再撤销报警条件,看恢复记录是否也写入表,短信是否也正常下发。
第三步,测试断电异常场景。比如先拔掉InTouch电脑和交换机之间的网线,然后触发报警,看数据库里是否有记录。注意,如果网络断了,InTouch的SQLConnect()会失败,这个报警就会丢。这个痛点我们在2.3节提到过,为了避免网络瞬断丢报警,我会建议把InTouch的报警脚本设计成“本地暂存 + 补传”的模式。简单说就是当SQL写入失败时,把报警数据先缓存在本地文本文件里,每隔几秒或者网络恢复后,再把这些缓存记录补插到数据库。
这个“本地暂存 + 补传”模式在刚开始做的项目里不一定用得上,但对于7x24小时连续生产的现场,绝对是保命功能。别省这个力气。
等第一台稳定跑了一个星期,再逐步把其余电脑的脚本部署上去,每接入一台,就在SMSAlarm的规则里加一个区域标识,同时检查有没有乱码或者字段错位。
3.6 SMSAlarm配置与多源关联的小经验
这里再多说一句SMSAlarm本身配置的“多源关联”问题。有些SMSAlarm设备内置多张SIM卡,你可以把不同区域的报警映射到不同SIM卡通道。比如A区报警用SIM1发,B区报警用SIM2发。这个在整合多台InTouch时很有用,因为你可以只靠短信的发送号码来判断报警来源,不依赖短信内容是否被值班人员看完整。
当然,这个功能不是必须的,如果只有一张卡也完全可行,但如果你手头的SMSAlarm设备支持多卡,建议把区域编码跟SIM卡通道绑定。
另外,SMSAlarm的短信猫模块,要特别注意SIM卡余额或者资费套餐。工业现场报警短信量通常不大,但一旦发生批量报警(比如全厂停电),可能几秒钟就会产生几十条短信额度消耗。如果用的是一张普通手机卡,月流量很小、单条短信贵,可能会导致报警发到中途欠费停机。我自己一般会建议用办理过“批量短信套餐”的物联网卡,按条计价,成本可控。
4. 常见问题与排查技巧实录
4.1 数据库写入正常但SMSAlarm不触发短信
这应该是最常见的问题。数据库里明明已经有IsSent=0的新记录,SMSAlarm却一直不动。排查时不要先怀疑设备坏了,绝大多数情况是配置问题。
优先级最高的检查点:SMSAlarm的查询语句里,有没有正确地过滤“仅查询未发送记录”。有些配置界面默认的SQL语句是SELECT * FROM Alarm_Records,它会反复查询所有历史记录,导致每次都把一个月前的报警重新发一遍,看着像是“不触发新短信”,实际上是老短信发不完,把提交队列堵死了。
解决方案是把SMSAlarm的查询SQL改成:
SELECT TOP 10 * FROM Alarm_Records WHERE IsSent = 0 ORDER BY AlarmTime ASC这样每轮扫描只拿最早10条未发送记录,发送成功后更新IsSent=1,一轮一轮消化。
另外,很多SMSAlarm配置里有一个“关联字段”或者“主键字段”需要手动指定,如果你没有把AlarmID指定成唯一键,设备也会无法判断哪条记录是新的。一定记着在配置里标定AlarmID为记录的唯一标识。
4.2 时间不同步导致报警顺序混乱
前面提到,AlarmTime用的是InTouch本机时间,那三台InTouch电脑之间的时间如果不一致,会造成报警顺序在短信里看起来是倒的。比如A区电脑比B区电脑快了2分钟,B区先报警,但A区的报警先入库,短信发出来就成了B区的报警在前、A区的在后,实际时间对不上。
根治方法是启用Windows的NTP时间同步,或者每周手动校时一次。如果现场不能联外网,可以在局域网上架一台NTP时间服务器,把所有InTouch电脑和数据库服务器都指向它。配置方法不复杂,但很多系统集成商到了工期最后阶段才会想起这茬,结果总体验收时被甲方一顿怼。建议在项目部署的前三天就把时间同步方案落地。
4.3 短信乱码问题
中文短信乱码,大多是因为SMSAlarm的配置软件里的字符集和InTouch写入数据库时的NLS设置不一致。
InTouch脚本写库时,通常会用系统默认的ANSI编码。如果SQL Server的字段类型是VARCHAR,且数据库排序规则是Chinese_PRC_CI_AS,那一般不会有问题。但如果数据库排序规则用了英文排序,就可能会出现“中文调用正常写入,SMSAlarm读取时变成乱码”的现象。
经验做法是:库表设计时,涉及中文描述的字段统一使用NVARCHAR类型。同时SMSAlarm侧的连接字符串里,显式指定字符编码为UTF-8或GBK,与InTouch保持一致。这需要在项目初期就确定,否则后期改表结构在连续生产的环境中是件很痛苦的事。
4.4 报警并发量大时的性能瓶颈
假设一个全厂停电的极端场景,多台InTouch同时触发几十个报警,全部涌向数据库和SMSAlarm。此时数据库的Alarm_Records表写入压力增大,SMSAlarm的查询频率也变高。如果表没加索引,查询就会慢,甚至锁表。
我在实际项目里遇到过报警风暴把数据库CPU打满的情况。后来做了两个优化:一是把IsSent的更新语句改成“批量更新”,比如一次性更新本次已取走的10条记录的IsSent=1,而不是一条一条更新;二是在业务层加了一个“报警去抖”机制——即同一个设备、同一个报警点,在60秒内如果重复触发报警,只更新最近一次的时间,不新增记录。这个去抖逻辑可以放在InTouch脚本侧,也可以放在数据库的存储过程里,反正最终目的就是降低无效报警短信的数量,减轻SMSAlarm和数据库的压力。
去抖机制虽然会损失一部分“每一次波动都记录在案”的粒度,但在实际生产中,操作员看的不是“波动了几次”,而是“现在是什么状态、什么时候开始报警的”。所以去抖不仅不误事,反而让报警信息更聚焦。
4.5 多台InTouch电脑同时掉线后的恢复补偿
在稳定生产现场,偶尔会因为交换机重启或者核心故障导致所有InTouch电脑都短暂掉线。此时,如果InTouch脚本里的SQL写入失败,而你又没做本地暂存补传,那掉线期间的报警就彻底丢光了,事后想查都无从查起。
前文提到的“本地暂存 + 补传”机制可以解决这个问题。具体实现上,可以在每台InTouch电脑的本地磁盘建一个报警缓存目录,脚本在写入数据库失败时,把报警记录序列化到文本文件里(纯文本,按行分割,字段间用特殊分隔符),同时启动一个定时任务,每隔30秒尝试重新连接数据库,一旦成功就把本地缓存的文本逐行解析,重新INSERT进Alarm_Records表。文件写完后要重命名或者删除,防止重复补传。
这里有一个细节——补传的记录要遵循严格的时序条件。因为缓存记录发生时数据库里还没有这条记录,补传的时候AlarmTime应该保留原始的报警时间,不可以“补传时生成当前时间”,否则后续做报警统计时会发现历史报警时间与真实故障时间对不上。这个坑我记忆犹新,曾经因为补传逻辑没注意,导致某次分析的报警报表里,所有报警都集中在晚上8点,完全失真。
聊到这里,整套多台InTouch整合短信报警的方案轮廓,应该已经清晰了。我个人实际操作下来的体会是,这类项目真正花时间的不是配SMSAlarm,而是把报警模型梳理清楚,同时把每一台InTouch的脚本调校扎实。项目里有条铁律:数据库中间表设计得再漂亮,如果每台电脑的报警语义不统一,短信内容照样会让值班人员骂娘。所以建议你先在自己最熟悉的一台InTouch电脑上把整套链路跑一遍,再往其他电脑铺开。产品支持上,也尽量选那些允许自定义SQL查询、支持多SIM卡绑定的SMSAlarm网关,这样后续运维时你能有更大的自主空间。希望这篇文章能帮你少走点弯路。