让你的PLC支持多连接,多电脑同时访问一个PLC 连接PLC的权限设置,PLC同时多连接
要明白一个技术,首先要明白它到底是解决什么问题的?你是不是有以下的困扰
1. 我有个三菱的PLC,只能配置一个端口,但是有多台电脑需要从PLC进行读写,因为三菱是单链接的,所以直接读写会报错。
2. 我得三菱PLC不希望对所有的客户端都开放权限读写,比如输入正确的用户名密码,才能通信
3. 我得PLC是在一个很小型的现场组网的,和公司内网不一个网络,但是有个工控机既连着PLC,也连着公司内网,但是内网的客户端程序也需要读写PLC,这时候也可以使用下面的注册PLC功能来解决
好了,有了这个需求,我们再来看怎么操作。依旧是使用hslcommunication组价
HslCommunication 软件,详细可以参考下面的地址:
github地址:https://github.com/dathlin/HslCommunication
官网:http://www.hslcommunication.cn
加群咨询学习信息:http://www.hslcommunication.cn/
在Visual Studio 中的NuGet管理器中可以下载安装,也可以直接在NuGet控制台输入下面的指令安装如果需要教程:Nuget安装教程:http://www.cnblogs.com/dathlin/p/7705014.html
1
|
Install-Package HslCommunication |
组件的api地址:http://api.hslcommunication.cn
我们先写服务器的代码:
新建好控制台项目后,我们就可以安装hslcommunication了
然后就是写代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using HslCommunication; using HslCommunication.ModBus; using HslCommunication.MQTT; using HslCommunication.Profinet.Melsec; using HslCommunication.Profinet.Siemens; namespace ConsoleApp1 { internal class Program { static void Main( string[] args ) { MqttServer server; MelsecMcNet melsec; SiemensS7Net siemens; ModbusRtu modbus; melsec = new MelsecMcNet( "118.24.36.220", 6000 ); // ip及端口需要改成你自己实际的参数 melsec.SetPersistentConnection( ); siemens = new SiemensS7Net( SiemensPLCS.S1200, "118.24.36.220" ); // ip需要改成你自己实际的参数 siemens.SetPersistentConnection( ); modbus = new ModbusRtu( 1 ); // 指定站号实例化 modbus.SerialPortInni( "COM2", 9600 ); // 初始化串口信息 modbus.DataFormat = HslCommunication.Core.DataFormat.CDAB; // 根据实际情况设置 server = new MqttServer( ); server.ClientVerification += Server_ClientVerification; // 启动账户密码,如果不需要验证,则注释即可 server.RegisterMqttRpcApi( "MelsecPLC", melsec ); // API分类随便写,方便客户端指定就行,需要唯一 server.RegisterMqttRpcApi( "SiemensPLC", siemens ); // API分类随便写,方便客户端指定就行,需要唯一 server.RegisterMqttRpcApi( "Modbus", modbus ); // API分类随便写,方便客户端指定就行,需要唯一 server.ServerStart( 1883 ); // 启动服务 Console.WriteLine( "已经启动" ); Console.ReadLine( ); } private static int Server_ClientVerification( MqttSession mqttSession, string clientId, string userName, string passwrod ) { // 这里举例只能账户密码登录 // if (userName == "admin" && passwrod == "123456") return 0; // else return 1; //不校验用户名密码 return 0; } } }
我们假设了三种设备需要远程访问的操作。服务器端的代码已经写好了,这时候,这个PLC已经支持从外部直接读写数据了。
大致的架构如图所示:
现在我们可以使用客户端来测试是否可以成功访问了,如果端口拒绝连接,则需要检查防火墙是否端口隔离了。
我们先打开hslcommunicationdemo测试:如果没有demo的话,从这里下载:http://www.hsltechnology.cn/Home/Download
在这里,为了支持注册多个PLC的数据。每个实体通信对象需要指定一个唯一的识别码,也就是上面服务器注册的三个数据
- MelsecPLC
- SiemensPLC
- Modbus
这个数据在客户端时,为了找到唯一的接口对象,则需要指定。也就是Demo测试界面的 设备主题
当然,如果你设备比较多,设备间又有层级的概念,所以使用分隔符 / 来区分,例如
- 分厂一/车间A/硫化机A01
- 分厂一/车间A/硫化机A02
- 分厂一/车间B/成型机B01
我们已经在demo客户端上测试成功。那么我们用代码怎么写呢?
同样是新建一个控制台项目,安装 hslcommunication组件,然后写入代码
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using HslCommunication; using HslCommunication.Core; using HslCommunication.LogNet; using HslCommunication.Profinet.GE; using HslCommunication.BasicFramework; using System.IO.Ports; using HslCommunication.MQTT; namespace NetFrameworkConsole { class Program { static void Main( string[] args ) { // 我们接下来在客户端访问当前的数据信息 MqttRpcDevice rpcMelsec = new MqttRpcDevice( new MqttConnectionOptions( ) { IpAddress = "127.0.0.1", // 服务器的IP地址 Port = 1883, Credentials = new MqttCredential( "admin", "123456" ), // 如果配置了用户名密码 UseRSAProvider = true, // 是否加密通信 }, "MelsecPLC" ); MqttRpcDevice rpcSiemens = new MqttRpcDevice( new MqttConnectionOptions( ) { IpAddress = "127.0.0.1", // 服务器的IP地址 Port = 1883, Credentials = new MqttCredential( "admin", "123456" ), // 如果配置了用户名密码 UseRSAProvider = true, // 是否加密通信 }, "SiemensPLC" ); MqttRpcDevice rpcModbus = new MqttRpcDevice( new MqttConnectionOptions( ) { IpAddress = "127.0.0.1", // 服务器的IP地址 Port = 1883, Credentials = new MqttCredential( "admin", "123456" ), // 如果配置了用户名密码 UseRSAProvider = true, // 是否加密通信 }, "Modbus" ); // 就可以进行读取了,例如读取三菱设备的D100的short值 OperateResult write1 = rpcMelsec.Write( "D100", (short)123 ); OperateResult<short> read1 = rpcMelsec.ReadInt16( "D100" ); Console.WriteLine( "Read Value1 D100: " + read1.Content ); // 例如读取西门设备的float值 OperateResult write2 = rpcSiemens.Write( "M100", 1.23f ); OperateResult<float> read2 = rpcSiemens.ReadFloat( "M100" ); Console.WriteLine( "Read Value2 M100: " + read2.Content ); // Modbus设备读取int值 OperateResult write3 = rpcModbus.Write( "100", 123 ); OperateResult<int> read3 = rpcModbus.ReadInt32( "100" ); Console.WriteLine( "Read Value3 100: " + read3.Content ); // 用法上和普通的三菱,西门子,modbus是没有区别的。 } } }
我们运行它
嗯,非常好。对客户端来说,支持多个设备的实例化对象,和服务器通信时,对于同一个PLC连接而言,内部会自动加锁通信。
所以这种情况不太适合,很多客户端同时频繁读写PLC,大数据的时候,读取的地址也是一样的。这种情况下,适合服务器先采集PLC数据,自动推送到所有的客户端,这样性能可以好很多。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using HslCommunication; using HslCommunication.ModBus; using HslCommunication.MQTT; using HslCommunication.Profinet.Melsec; using HslCommunication.Profinet.Siemens; namespace ConsoleApp1 { internal class Program { static void Main( string[] args ) { MqttServer server; MelsecMcNet melsec; SiemensS7Net siemens; ModbusRtu modbus; melsec = new MelsecMcNet( "118.24.36.220", 6000 ); // ip及端口需要改成你自己实际的参数 melsec.SetPersistentConnection( ); siemens = new SiemensS7Net( SiemensPLCS.S1200, "118.24.36.220" ); // ip需要改成你自己实际的参数 siemens.SetPersistentConnection( ); modbus = new ModbusRtu( 1 ); // 指定站号实例化 modbus.SerialPortInni( "COM2", 9600 ); // 初始化串口信息 modbus.DataFormat = HslCommunication.Core.DataFormat.CDAB; // 根据实际情况设置 server = new MqttServer( ); server.ClientVerification += Server_ClientVerification; // 启动账户密码,如果不需要验证,则注释即可 server.RegisterMqttRpcApi( "MelsecPLC", melsec ); // API分类随便写,方便客户端指定就行,需要唯一 server.RegisterMqttRpcApi( "SiemensPLC", siemens ); // API分类随便写,方便客户端指定就行,需要唯一 server.RegisterMqttRpcApi( "Modbus", modbus ); // API分类随便写,方便客户端指定就行,需要唯一 server.ServerStart( 1883 ); // 启动服务 Console.WriteLine( "已经启动" ); while (true) { Thread.Sleep( 1000 ); // 读取PLC的数据,并且把数据分发出去 OperateResult<short> read1 = melsec.ReadInt16( "D100" ); if (read1.IsSuccess) { // 这里的topic没有什么规则,都是自己设定的,注意不和其他数据冲突就行 server.PublishTopicPayload( "MelsecPLC.A", Encoding.UTF8.GetBytes( read1.Content.ToString( ) ) ); Console.WriteLine( DateTime.Now.ToString( ) + " success! " ); } else { Console.WriteLine( DateTime.Now.ToString( ) + " failed: " + read1.Message ); } } } private static int Server_ClientVerification( MqttSession mqttSession, string clientId, string userName, string passwrod ) { // 这里举例只能账户密码登录 // if (userName == "admin" && passwrod == "123456") return 0; // else return 1; //不校验用户名密码 return 0; } } }
新增加的代码就是
while (true) { Thread.Sleep( 1000 ); // 读取PLC的数据,并且把数据分发出去 OperateResult<short> read1 = melsec.ReadInt16( "D100" ); if (read1.IsSuccess) { // 这里的topic没有什么规则,都是自己设定的,注意不和其他数据冲突就行 server.PublishTopicPayload( "MelsecPLC.A", Encoding.UTF8.GetBytes( read1.Content.ToString( ) ) ); Console.WriteLine( DateTime.Now.ToString( ) + " success! " ); } else { Console.WriteLine( DateTime.Now.ToString( ) + " failed: " + read1.Message ); } }
运行之后的效果:
我们只需要打开hslcommunication的demo,测试mqtt即可。
实际可以根据情况再进行针对性的优化操作。
如果还有什么问题,可以通过最上方的连接找到作者。