CodeSys OPC UA服务器与访问
我们在 CodeSys
中 建立一个OPC UA
服务端,并把相关变量通过OPC UA
的方式暴露出来。然后,我们会通过第三方成熟且免费的UaExpert
客户端,对服务端变量进行访问;最后,我们会以编程的方式,自己写代码实现对服务端变量的监视和控制。
OPC UA 服务端建立
为了测试,让我们编写一个简单程序:
PROGRAM PLC_PRG
VAR
prod : INT;
a : INT;
b: INT;
END_VAR
prod := a * b;
a := a + 1;
符号配置
首先,右击Application
,依次选择Add Object
/Symbol Configuration
:
在弹出的符号配置对话框中,勾选 Support OPC UA features:
确认后,在弹出的Symbol Configuration
标签页中,把要通过 OPC UA监控的变量勾选上即可。
注意:对应新增加的变量,要先点击Build
,才会在符号配置表中呈现。
如果改变符号配置的话,会在下一次 download 或者 online change 时被传输到目标机器中。
到此为止,我们已经基本完成了 OPC UA 服务器上配置。但是客户端大概率是没法连接的,因为服务器并没有自身安全证书。这个证书的机制类似于https
证书,用于标识自己是谁和加密通信。
OPC UA 服务器证书
打开菜单 View
,点击 Security Screen
菜单项:
在Security Screen
标签页中,点击刷新按钮,选中具体设备,找到OPC UA Server
项,如果有标注 Not Available
,则表示目标机器还没有相应的证书:
在选中OPC UA Server
项的前提下,点击其左上角的create a new certificate on the device
按钮,即可在目标机器上创建一个新的证书:
在完成相应的证书配置后,我们可以把服务端证书导出到本地进行备份,在将来需要时(比如给目标设备刷机),可以再将备份的证书导入到设备中。
使用UaExpert客户端
为了简单起见,我们先用成熟的第三方客户端 UaExpert 来连接服务器。 UaExpert 是一款可以免费使用的 OPC UA GUI客户端。
建立连接
UaExpert在第一次启动的时候,会提示我们生成客户端证书。在尝试连接的时候,客户端选择连接类型为Basic256Sha256 – Sign & Encrypt (uatcp-uasc-uabinary)
,表示安全类型为签名和加密。
但这里有两个问题:
- 服务端的证书,是自签名的,客户端并不认可。所以要让客户端信任服务端证书。在第一次连接服务器的时候,会弹出一个对话框提示证书校验错误,点击临时接受这个服务器证书即可。或者我们也可以把服务端证书安装到本地系统中。
- 客户端的证书,也是自签名的,服务端也不认可。所以也要手动把客户端证书添加到目标服务器设备上的受信证书中。具体操作办法参见下面的动画:
监控变量
使用C#编程
// 创建一个应用配置对象,用于设置应用名称、唯一标识、类型、证书和安全策略
using Opc.Ua;
using Opc.Ua.Client;
using Opc.Ua.Configuration;
ApplicationConfiguration config = await PrepareOpcUaAppConfigAsync();
// 创建一个应用实例对象,用于检查证书
var application = new ApplicationInstance(config);
bool check = await application.CheckApplicationInstanceCertificate(false, 2048);
Console.WriteLine($"证书验证结果:{check}");
Session session = await CreateSessionAsync(config);
Console.WriteLine($"会话已创建");
// 读取节点
while (true)
{
DataValue value = await session.ReadValueAsync(nodeId: "ns=4;s=|var|CODESYS Control Win V3 x64.Application.PLC_PRG.prod");
Console.WriteLine("{0}, {1}, {2}", value.Value, value.SourceTimestamp, value.StatusCode);
}
其中,准备应用实例的实现为:
/// 准备OPC UA App Config
static async Task<ApplicationConfiguration> PrepareOpcUaAppConfigAsync()
{
var config = new ApplicationConfiguration()
{
ApplicationName = "MyClient",
ApplicationUri = Utils.Format(@"urn:{0}:MyClient", System.Net.Dns.GetHostName()),
ApplicationType = ApplicationType.Client,
SecurityConfiguration = new SecurityConfiguration
{
ApplicationCertificate = new CertificateIdentifier { StoreType = @"Directory", StorePath = @"%CommonApplicationData%\OPC Foundation\CertificateStores\MachineDefault", SubjectName = "MyClientSubjectName" },
TrustedIssuerCertificates = new CertificateTrustList { StoreType = @"Directory", StorePath = @"%CommonApplicationData%\OPC Foundation\CertificateStores\UA Certificate Authorities" },
TrustedPeerCertificates = new CertificateTrustList { StoreType = @"Directory", StorePath = @"%CommonApplicationData%\OPC Foundation\CertificateStores\UA Applications" },
RejectedCertificateStore = new CertificateTrustList { StoreType = @"Directory", StorePath = @"%CommonApplicationData%\OPC Foundation\CertificateStores\RejectedCertificates" },
AutoAcceptUntrustedCertificates = true,
RejectSHA1SignedCertificates = false,
MinimumCertificateKeySize = 1024,
NonceLength = 32,
},
TransportConfigurations = new TransportConfigurationCollection(),
TransportQuotas = new TransportQuotas { OperationTimeout = 15000 },
ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = 60000 },
TraceConfiguration = new TraceConfiguration()
};
// 验证应用配置对象
await config.Validate(ApplicationType.Client);
// 设置证书验证事件,用于自动接受不受信任的证书
if (config.SecurityConfiguration.AutoAcceptUntrustedCertificates)
{
config.CertificateValidator.CertificateValidation += (s, e) => { e.Accept = (e.Error.StatusCode == StatusCodes.BadCertificateUntrusted); };
}
return config;
}
创建session的实现为:
static async Task<Session> CreateSessionAsync(ApplicationConfiguration config)
{
// 创建一个会话对象,用于连接到 OPC UA 服务器
var discoveryUrl = "opc.tcp://DESKTOP-7PT7CEQ:4840";
EndpointDescription epDescription = CoreClientUtils.SelectEndpoint(discoveryUrl, true);
EndpointConfiguration epConfiguration = EndpointConfiguration.Create(config);
ConfiguredEndpoint endpoint = new ConfiguredEndpoint(null, epDescription, epConfiguration);
Session session = await Session.Create(config, endpoint, false, false, "DataCollector", 60000, new UserIdentity("teset-runtime", "123456"), null);
return session;
}