很多做设备维护的朋友问过我同一个问题:现场的西门子S7-1200已经在跑了,手边没电脑,能不能掏个手机就把关键点位的数据看了,甚至改个参数。以前我的回答是“得先装个专用工具”,后来干脆自己写了一套东西。这个项目就是拿C#在VS2019里搭一套手机端组态APP,让手机通过无线WiFi直接跟S7-1200 PLC通信,组态的画面、点位、报警都能在工程文件里改,不用改一行代码。整套源代码工程不只包含APP端,还包括通信封装、组态工程解析和界面运行时,适合搞工控上位机、接私活做设备监控、或者想把手里的S7-1200项目做成手机可看的朋友。
先别急着要源码,我要先泼一盆冷水:手机组态APP和普通的上位机软件完全不同,通信链路变长、现场环境比办公室恶劣得多,很多问题不是代码写不出来,而是整个架构没想清楚。这篇文章我把这个项目的设计思路、通信链路、组态数据模型、关键代码和联调踩坑全部复盘一遍,基本能当一份“复现手册”用。
1. 这套系统的本质:不是写死页面,而是做“可用组态运行时”
1.1 组态APP和写死功能的APP差在哪
很多初学C#的人做PLC监控,最常见的做法是窗体上拖一个TextBox,然后在定时器里不断读DB块,把它填进去。界面简单、点位少的时候完全够用。但一旦到了现场,你会发现需求永远是:把压力显示的控件挪个位置、把某台设备的报警阈值改一下、把电流值从这页挪到那页。这时候如果界面是写死的,每次都要重新编译APK再装一遍,客户还催得紧,基本就是灾难。
组态这个词在工控里的意思,就是“把用户能改的东西全部外置成配置”。我们做手机端监控,不能只做画面,要做一套能解析配置文件的运行时。工程文件里面定义了什么变量、什么画面、什么控件样式,APP启动后就按文件渲染出来,数据源指向哪里就去哪里读。这样一来,现场改点位名称、加一个仪表盘、换一个数据刷新周期,都不需要动代码,只要把新的工程文件发到手机上就能生效。
1.2 这个项目的目标场景和适合谁用
我当初定这个项目范围时,目标场景锁定在以下几个地方:
- 设备调试现场:PLC程序还在调,工程师蹲在设备旁边,用手机就能看DB块里的关键值,不用开电脑连博途。
- 售后远程协助:老板打电话问你设备运行数据,你手机连上现场WiFi就能看到当前温度、压力、设备状态。
- 小型产线巡检:一天走好几条线,每条线配一个WiFi终端,手机轮着连,比拿着对讲机问主控室省事得多。
- 做非标设备的公司:给客户交付设备后,顺带送一个手机监控APP,前提是可维护、可改配置、不产生重复开发成本。
所以说,这套代码的定位不是“又一个串口调试助手”,而是一个“带组态能力的远程监控终端”。如果你需要的只是临时连一次PLC看看数据,不必用这么完整的架构;但如果是给多个现场做通用监控,组态化思路才能救你。
1.3 系统里的三个角色,缺一不可
一套能跑起来的手机监控方案里,看似只是“手机读PLC”,实际包含三个角色:
- S7-1200 PLC:数据源头。通常用自带PROFINET口或CP扩展口,运行在以太网协议栈上。
- WiFi接入链路:让S7-1200的以太网数据包走无线网络,并保证手机处于同一二层网络或可路由网络。
- 手机端的C#运行时:连接PLC的通信服务、组态工程解析器、画面渲染引擎和UI刷新逻辑。
这里的第二点特别重要。S7-1200本体没有WiFi,你要是直接说“手机通过WiFi连PLC”,中间必然有一个无线桥接设备。这个设备怎么选、怎么接、怎么配,直接决定你后面写代码时是爽快还是难受。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. S7-1200没有WiFi口,无线链路到底该怎么做
2.1 四种无线接入方式,哪种适合你的现场
我在标题里写“无线WiFi通信”,不是说PLC插了根天线就行。S7-1200的RJ45口走的是工业以太网,要变成无线,常见有四种做法:
| 方案 | 硬件组成 | 稳定性 | 成本 | 适合场景 |
|---|---|---|---|---|
| 工业无线客户端/AP桥接 | PLC网线接无线终端,手机连同一AP | 高,工业级 | 中 | 固定产线、设备本体监控 |
| 西门子IWLAN模块 | 如CP 1243-1 WLAN,扩展在PLC左侧或由网络管理 | 很高,但配置门槛高 | 高 | 西门子成套系统、移动设备上下线 |
| 家用/商用路由器做WiFi到有线网桥 | PLC插路由器LAN口,手机连路由器SSID | 一般,受环境和电源影响 | 低 | 实验室、调试间、展厅演示 |
| IoT网关中转 | 网关通过有线读PLC,再通过WiFi/4G提供数据和页面 | 高 | 中高 | 远程监控、多协议转换 |
我自己的项目在开发阶段用的是第三种,家用路由器把PLC网线和手机拉到同一个局域网的网段。现场测试版本用第一种,一台工业级无线客户端/AP,既能当无线终端,又能给PLC透传数据包,手机连接后实测定点刷新100ms以内是稳定的。
必须强调一句:如果PLC控制的是有安全风险的设备,比如电机启停、气缸动作,无线链路绝对不建议作为唯一控制通道,尤其是手机这种可能锁屏、断WiFi的终端。无线通信适合监视和参数整定,关键安全信号走硬接线或者独立安全PLC。
2.2 通信协议选型:S7comm、Modbus TCP和OPC UA怎么选
无线链路打通之后,下一个问题是用什么协议跟S7-1200对话。
- S7comm:西门子自己的S7通信协议,默认走TCP 102端口,S7-1200通过“允许来自远程对象的PUT/GET通信”开启外部访问。C#里面用社区生态比较成熟的S7库,能直接读DB、M区、I/O区。
- Modbus TCP:S7-1200通过功能块或固件支持,协议公开、调试简单,但要做数据映射,PLC程序里得把变量搬到一个专门的Modbus保持寄存器区。
- OPC UA:S7-1200高版本固件自带OPC UA服务器,跨平台和安全模型更好,但手机端要做证书管理,开发复杂度比前两者高一些。
这个项目里我选的是S7comm。原因很直接:S7-1200的原始DB结构和M区地址能直接读,PLC侧不用为了通信单独写一堆映射代码。S7comm虽然和西门子自己的博途环境绑定比较紧,但在C#领域已经有很多可参考的实现,实际用下来的坑是可控的。
2.3 S7-1200必须留意的数据块设置
这里有一段极其重要的博途配置,如果你不看,后面手机APP怎么都读不出正确数据,那不是代码问题,是PLC侧没放行。
在TIA Portal里,S7-1200的数据块默认可能是“优化的块访问”。优化块访问会把变量偏移量交给系统自动分配,外部S7通信找不到固定的字节地址,所以在做第三方通信时,通常要把你需要外部访问的DB块改成“非优化访问”,并取消勾选“优化的块访问”。
另外在PLC的“防护与安全”设置里,要勾选“允许从远程伙伴(PUT/GET通信)进行访问”。不勾这个,C#程序连上之后读取也会被CPU拒绝,现象就是连接成功但数据返回错误。
这块配置还牵扯到现场安全。开启PUT/GET等于向局域网开放了PLC数据通道,所以工程交付时一定要叮嘱客户把WiFi网络的密码策略做起来,不要让无关设备随便接入网段。
3. 组态工程的核心:点位表、画面配置和消息轮询
3.1 组态工程文件是整套软件的“灵魂”
写源代码之前,我先设计了一套JSON格式的组态工程文件。之所以用JSON不用XML,是因为手机端解析简单,而且VS2019里Newtonsoft.Json或者System.Text.Json都支持得很好。工程文件分成两大块:设备点位表和页面配置。
设备点位表里每一条记录对应PLC里的一个变量。包括变量名、数据类型、DB块号、起始字节偏移、位偏移、缩放倍数、工程单位。页面配置里则描述了这个监控画面包含哪些图元、每个图元在什么坐标、字体大小、绑定点位名称。
这样的设计一个最大好处是:APP和组态画面完全解耦。同一个APP,你换一套JSON工程文件,监控的完全是另一条设备线。
3.2 VS2019解决方案结构应该怎么组织
“全套源代码”听起来吓人,实际拆开看就是四个C#项目:
code复制MobileScada.sln
|-- MobileScada.Core // 组态核心类库
| |-- TagSystem // 点位表定义与数据绑定
| |-- Protocol // S7通信封装、握手与收发
| |-- ProjectArchive // JSON工程文件读写
| |-- Engine // 画面渲染与定时刷新引擎
|-- MobileScada.App // Xamarin.Forms手机端
|-- ScadaDesigner // WPF/WinForms组态设计器(可选)
|-- ScadaSimulator // 模拟器,没PLC时也能调试界面
如果不想跨平台,把MobileScada.App改成Android的Xamarin.Android项目也可以;但如果希望代码以后能扩展到iOS,建议直接上Xamarin.Forms或后来的.NET MAUI,VS2019对Xamarin.Forms的支持已经很成熟。
我建这个解决方案时有一个原则:协议层不依赖任何UI库。也就是说,手机端断网、页面跳转、主线程刷新这些事情,通通不许写进通信代码里。通信层只负责维护连接、读取点位、抛出数据事件,UI层自己去订阅需要关心的数据。这样无论你以后是改成WinForms测试,还是换成安卓手机端,通信代码一份都不用动。
3.3 设计点位表的数据结构,要预留哪些字段
点位表是很多人会偷懒的地方,觉得不就是“DB号+地址+类型”吗,直接写死就行。但现场跑一圈你就会发现,数据不是这么简单。我最后用的数据结构是这样的:
code复制DeviceId 设备编号,一个工程可以连接多台PLC
TagName 点位名称,比如“#1炉温”
FriendlyName 显示名称,比TagName更友好
Area DB、M、I、Q,访问区域
DbNumber DB块号,Area为DataBlock时有效
ByteAddress 字节起始偏移
BitAddress 位偏移,Bool类型用
DataType Bool、Int、Real、String
Scale 显示缩放系数
Unit 工程单位
ReadWrite 只读/读写权限
RefreshRate 点位独立刷新周期(毫秒)
Scale这个字段很关键。PLC里存的可能是原始工程值,比如温度传感器出来的是0到1000,而你想显示0到100.0,那就不必在PLC程序里做缩放,直接在组态工程的Scale里填0.1即可。这样做的好处是PLC工程师和上位机开发者的职责边界清楚了:PLC只存原始数据,上位机负责显示换算。
4. S7通信连接和点位代码,从连接、读到写完整拆解
4.1 建立S7连接:先解决“连得上”的问题
通信类我封装在Protocol项目里,核心就是用C#的S7库连接PLC。以S7.Net库为例,连接代码很直观:
code复制using S7.Net;
using S7.Net.Types;
public class S7TcpClient : IDisposable
{
private Plc _plc;
private readonly object _lock = new object();
public bool Connect(string ip, int rack, int slot, int timeout = 1500)
{
lock (_lock)
{
_plc = new Plc(CpuType.S71200, ip, rack, slot);
_plc.ReadTimeout = timeout;
_plc.WriteTimeout = timeout;
_plc.Open();
return _plc.IsConnected;
}
}
public void Disconnect()
{
lock (_lock)
{
_plc?.Close();
}
}
public bool IsConnected => _plc != null && _plc.IsConnected;
}
需要注意,S7-1200的机架号和槽位号和S7-300不一样。绝大多数通过以太网连接S7-1200的场景,机架号是0,槽位号是1。如果你用的是CPU 1214C DC/DC/DC,连接参数就是这样。连接失败时先检查IP是否通了,再检查CPU是否允许PUT/GET,这两个问题占了我调试时的八成时间。
从Windows测试转真机时尤其容易犯一个错误:模拟器或开发机直连没问题,但手机通过WiFi连接时,PLC的IP网段必须和手机能访问到的网段一致,并且路由器不能开AP隔离。AP隔离开启后,两个无线设备之间连Ping都通不了,更别说走TCP 102端口了。
4.2 读取DB块里的Real类型数据,完整过程是什么
连接建立后,读取DB块里的浮点数用S7库封装好的方法就能实现。比如读取DB1的第0个字节开始的4字节浮点值:
code复制public float ReadReal(int dbNumber, int byteIndex)
{
lock (_lock)
{
if (!IsConnected) return float.NaN;
byte[] buffer = _plc.ReadBytes(DataType.DataBlock, dbNumber, byteIndex, 4);
return buffer == null ? float.NaN : Real.FromByteArray(buffer);
}
}
这里有个很关键的点,S7-1200本体是little-endian,S7库的Real.FromByteArray内部默认会按照S7协议的规范去解析数据,所以一定不要自己手动去做BitConverter.ToSingle,否则在部分型号上你会得到完全错误的值。用库自身的解析方法,比自己魔改字节序靠谱得多。
如果读的是Int类型,就是2字节;Bool类型则要指定位偏移。比如DB1的字节2的bit 5,要通过字节地址2和位地址5两个参数去访问。容易出错的地方是,字节序按0开始计数,博途里如果显示从0开始,那就不要多加1。
4.3 点位批量采集和UI刷新,不能一个点位一个线程
很多人写监控程序喜欢给每个点位开一个定时器,每个定时器自己去读PLC。点位少的时候没问题,点位一旦超过几十个,PLC的连接资源会被迅速占满。S7-1200的连接资源是有限度的,不是说随便开几十个TCP连接CPU都能扛得住。
我建议的做法是:一个APP进程对应一个S7连接,维护一个轮询线程,按固定周期把所有需要刷新的点位刷新一遍。为了提高效率,可以把刷新周期分成快慢两类,比如设备运行状态100ms刷新一次,温度等缓变量500ms刷新一次。更新完数据后,把点位值和采集时间打包成一个事件抛出去,由UI层根据当前页面是否可见来决定是否更新。
简化后的轮询逻辑大致是这样:
code复制public void StartPolling()
{
_pollTask = Task.Run(async () =>
{
Stopwatch sw = new Stopwatch();
while (!_cancelled)
{
sw.Restart();
var snapshot = new Dictionary<string, object>();
foreach (var tag in _fastTags)
snapshot[tag.TagName] = ReadByTag(tag);
foreach (var tag in _slowTags)
if (_lastSlowTick++ % 5 == 0)
snapshot[tag.TagName] = ReadByTag(tag);
if (snapshot.Count > 0)
DataUpdated?.Invoke(this, new DataEventArgs(snapshot));
var remain = _intervalMs - (int)sw.ElapsedMilliseconds;
if (remain > 0)
await Task.Delay(remain);
}
});
}
UI层监听到DataUpdated事件后,不要马上执行复杂的转换逻辑,因为事件可能来自后台线程。Xamarin.Forms里要切回主线程再刷新界面。跨线程更新UI是必踩的坑,不处理的话界面会出现不可预期的闪烁甚至直接崩溃。
4.4 写入操作的安全设计:该拦的时候就拦
手机APP不只是用来看数据,通常还会有“手动启动”“修改设定值”这种操作。凡是涉及写入的,我在通信层都做了两层保护。
第一层是点位表权限控制。组态工程里定义一个点位是只读还是读写,通信层在写入前检查权限,没有写权限直接拒绝,而不是让UI层的按钮来控制。第二层是业务层的确认弹窗和操作密码。用户点了启动按钮后,先在手机端弹一个二次确认弹窗,要求输入操作密码,密码验证通过后才会真正调用写入方法。
从写入数据格式来说,浮点写入会先用Real.ToByteArray把C#的float转成S7传输字节,再调用WriteBytes:
code复制public bool WriteReal(int dbNumber, int byteIndex, float value)
{
lock (_lock)
{
if (!IsConnected) return false;
byte[] bytes = Real.ToByteArray(value);
return _plc.WriteBytes(DataType.DataBlock, dbNumber, byteIndex, bytes);
}
}
写入完成后,我建议立刻做一次读回校验。WiFi链路偶尔会有丢包或延迟,写入指令发出后看似返回成功,实际上可能没有真正落到PLC里。读回校验的做法是写入后等100ms再读一次相同地址,对比目标值,误差在合理范围内才算操作成功。这个习惯能让你少处理很多莫名其妙的客户投诉。
5. 手机端组态界面怎么做,才能不把时间耗死在UI上
5.1 图元控件和点位绑定的画面模型
手机组态APP不是重新做一遍图形界面库,而是要建立“图元+点位绑定”的画面模型。我在组态工程里定义了一套轻量控件描述:
code复制{
"id": "temp_meter_01",
"type": "meter",
"left": 20,
"top": 80,
"width": 160,
"height": 120,
"title": "反应釜温度",
"unit": "℃",
"bindTag": "Reactor.Temp",
"range": { "min": 0, "max": 400 }
}
这套JSON描述的好处是,不仅WiFi环境下的S7-1200能用,以后换成Modbus设备或者OPC UA服务器,只要点位表里的变量名映射对了,界面根本不用动。运行时会解析这个模板,在画布上创建对应的图元实例,并把这个实例挂到点位绑定表上。
源码里我会给出一组常用图元:数字显示框、仪表盘、水平进度条、指示灯、开关按钮、报警列表、实时趋势线。这些图元全部继承自同一个基类,只暴露BindTag和UpdateValue接口。这样一来,新增一个图元类型不需要动运行时的核心逻辑,只要在模板解析注册表里加一个类即可。
5.2 触摸屏操作为什么不建议用系统自带控件直接堆
手机端布局有个很现实的约束:屏幕尺寸小、控件密度大、触摸手势多。如果你用Xamarin.Forms的Grid和StackLayout一个一个去搭画面,工程文件越大越难维护,缩放平移、横竖屏切换、不同分辨率适配都会让你怀疑人生。
我在这个项目里选择的方案是:用绝对定位的画布来渲染组态画面,所有图元根据设备的逻辑分辨率做等比缩放,画布支持双指缩放和单指拖动,放大后能精准点击按钮。这样做牺牲了一点“系统级控件的外观”,换来了组态运行时的灵活性和统一性。实际看起来就像一个工控HMI的APP版。
渲染引擎这一层,核心是把上面的JSON模板解释成画面树。每个图元有一个渲染函数,负责在给定的矩形区域内画自己。如果是仪表盘,就用绘图API把表盘背景、指针和当前值画出来;如果是指示灯,就根据bool值画成绿色或红色。这样一套纯自绘方案,在性能上反而比频繁创建和销毁控件更可控,因为每帧只需要在画布上做局部重绘,不会触发整个View树的重新布局。
5.3 组态工程文件的更新和校验机制
现场改组态工程是常有的事。如果每次改配置都要重新安装APP,那这个组态就失去了意义。我做了两个更新通道:本地导入和WiFi下发。本地导入是把JSON文件放到手机指定目录,APP启动时自动检测并应用;WiFi下发是电脑端通过HTTP接口上传新工程到手机APP,APP收到后校验JSON结构、检查点位表是否存在非法地址,确认无误后热加载画面。
校验机制不能省,原因很简单:你写了一个错误的DB块地址,如果校验不拦截,运行时整页数据刷不出来,客户以为控制系统坏了,其实是组态工程写错了。我惯用的做法是加载工程时先做语法校验和语义校验。语法校验用JSON解析库直接做,语义校验要遍历所有绑定点位,检查每个Tag在点位表里是否存在,数据类型是否匹配,如果有问题就在日志里列出来,并拒绝加载。
这套机制后来在现场帮了大忙。有一次客户自己改了设备编号,把多个点位地址整体偏移了2个字节,没改页面配置就直接下发。结果整个画面数据错全了,但程序没崩,而且我日志里明确提示“部分点位读取结果与类型定义不匹配”,很快定位到是地址偏移错误,而不是通信断掉。
6. 实地联调最容易翻车的几个坑,每一条都有对应解法
6.1 连上但读不到数据,先查DB块的“优化访问”开关
不少朋友第一次用C#连接S7-1200时,现象是APP显示连接成功,但所有变量数据都是0或者异常值。排查半天,最后发现是TIA Portal里DB块默认开了“优化的块访问”。优化的块访问是S7-1200/1500系列的一大特色,数据块内部变量没有固定的字节偏移,随便外部访问当然拿不到按地址解析出来的数据。
解决方案前面提过:在DB块属性里取消“优化的块访问”,重新编译下载。需要注意,这个操作会导致原DB里的变量地址重新分配,如果PLC程序其他地方依赖这些地址,改动前要先做备份。从项目一开始就规划好哪些DB块供外部通信,比后期去改要省太多事。
6.2 WiFi信号满格却频繁断连,大概率是AP隔离或省电策略
手机连WiFi看着信号满格,但APP每隔几十秒就断一次,这种问题几乎跟PLC代码没有任何关系。先检查路由器的AP隔离有没有开启,然后检查无线接入点的最大客户端数量。工业现场用手机调试时,很多人随手拿了一个家用路由器顶上,家用路由器在带机量超过十个以后,因为转发性能不足或内存溢出会随机丢弃TCP连接,表现就是S7通信时好时坏。
还有一个容易忽略的点是手机的WiFi休眠策略。手机屏幕熄灭一段时间后,系统为了省电会主动断开空闲WiFi连接或限制后台网络,S7连接自然就断了。解决方法是,在手机端申请前台服务或使用部分唤醒锁,同时把WiFi设为“屏幕关闭后保持连接”。C#里可以通过注册平台相关的生命周期事件,在APP进入后台前提示用户保持前台运行,而不是默默重新连接。如果是安卓8.0以上的系统,还要注意后台联网限制,否则App切到后台几分钟后网络就被冻结。
6.3 写入看似成功,实际PLC没反应,别急着怀疑协议
S7写入有一个典型的“成功但没生效”场景。写过布尔量或整数值后,PLC程序里面对应的逻辑没有反应,读回的值还是原来的。这时候先看PLC程序里这个DB地址是否有其他程序块在反复覆写。S7-1200虽然以循环扫描方式运行,但如果某个OB块每个周期都对同一个地址赋值,外部写入的数据在下个扫描周期就会被覆盖掉。
换句话说,通信层只是负责把数据放进对应的DB位置,真正能不能起作用取决于PLC程序的逻辑设计。如果你要远程设定一个运行模式,这个模式变量应该由通信写入,然后PLC程序去读取它,而不是通信层直接修改程序正在使用的临时标志位。
正确的联调顺序是:先在手机APP里读回确认写入值已经变了,再到博途监控表里看该地址的实时值,如果博途里已经变了但设备动作不对,那就要回PLC程序里面查谁在覆盖它。这样一层层排查,比盲改代码要快得多。
6.4 界面刷新卡成PPT,往往是点位的读取方式没有批量
手机上显示画面卡顿,很多人第一反应是性能不行,换一台高端手机测试还是卡,那就得反思通信调度了。最典型的错误是在UI绑定的属性变更事件里直接读取PLC数据,每刷新一个值就发起一次S7请求。假设画面有20个点位,每个点位每100ms发一次请求,一秒钟就是200次TCP往返。WiFi链路再快也扛不住,再加上UI线程还要处理控件刷新,不卡才怪。
正确的做法是先把所有点位读取集中到通信线程,按一定周期批量读出快照,再一次性推给UI层。UI层拿到数据以后只做当前可见页面的局部刷新。需要细看某个点位时,还可以把单点位的独立刷新周期调高,但不要全局每个点位都开独立定时器。实测下来,40个点位、500ms刷新周期、WiFi连接条件下UI帧率能保持稳定。
6.5 安卓9以上HTTP明文流量被拦,别怪通信库
如果你在工程里用了HTTP接口做配置下发或者告警上传,在安卓9及以上版本默认禁止明文HTTP流量。如果你没有在AndroidManifest里配置usesCleartextTraffic="true",你会发现HTTP请求直接报错,但S7的自定义TCP通信不受这个限制。
这个坑在VS2019里特别容易遇到,因为开发时PC上的调试工具都是http访问的,手机上跑起来却突然失败。解决方案有两个方向:要么配置网络安全策略允许特定域名的明文流量,要么把配置下发改成局域网内的自有TCP服务。我后来为了让配置下发不仅限局域网,还把工程配置的传输改成了加密通道,安全性高了不少。
6.6 防现场误操作:无线监控要设置好点位冻结和操作权限
最后要说一个可能被很多人忽略的工程性问题。手机通过WiFi连接S7-1200,一旦断网,画面上的数据通常会变成空值或者上一次的旧值。如果点位是设备状态灯,断网后仍然显示绿色,操作员容易误以为设备还在运行,这是有安全隐患的。
我在数据引擎里做了“数据新鲜度”概念。每个点位在收到新数据时记下时间戳,一旦超过设定阈值(比如2秒没有更新),这个点位状态就标记为过期。UI层显示数值时,会先检查点位是否新鲜,过期数值变灰并在右上角显示一个“!”图标。这样即使WiFi断了,操作员也能一眼看出不是实时数据。触摸操作按钮在点位过期时直接禁用,防止误触。
操作权限方面,我建议至少分两级:观察员只能看数据和趋势,操作员可以修改参数和启停设备。密码不要明文存在组态工程文件里,至少要做一个哈希校验。现场使用无线网络时,如果PLC有支持的安全协议,尽量开启加密和访问列表。
7. 这套代码的扩展空间,后续可以怎么改
整个架构搭好以后,如果你要把它改造成正式交付的产品,我个人的建议有三条路。
第一,把PC端的ScadaDesigner做得更成熟。手机端界面再怎么好用,在手机上一格一格画图元还是效率太低,大屏组态设计器更适合配置复杂工程,设计器保存的JSON工程由手机端加载运行。这样你就有了一个真正的“组态软件家族”:PC画图、手机运行、PLC通信协议层共用。
第二,增加本地历史存储和告警记录。WiFi通信不会每时每刻都在线,关键数据断网期间的缺口可以用PLC内部的保持性存储来补偿,也可以把手机端收到每一次变化记录到本地SQLite里,后面做曲线回放和报表导出都很方便。
第三,把协议层抽出来做多语言版本。如果不局限于C#,这套组态工程文件模型完全可以复用到Node-RED或者Web组态里;如果仍然坚持C#生态,把S7通信层换成OPC UA客户端后,就能同时兼容1200、1500、300/400以及第三方支持OPC UA的控制器。我在设计点位表时已经把DeviceId放进去,就是为了以后一台手机同时监控多台PLC甚至多种协议。
老实说,做手机组态APP最花时间的不是通信代码,而是如何把一个工控项目拆成“可组态的数据+可组态的画面+稳定的通信内核”。我在这套源码里已经把这些拆好的工程结构全部保留了下来,如果你动手能力比较强,拿到手以后不建议直接改通信库,先把点位表模型和画面模板吃透,再考虑功能扩展。这样你改出来的版本才能不偏离这套代码的初衷,也不至于越改越像硬编码的调试助手。
