前情提要
网上搜了很多发现都是把软件介绍从官网贴过来了,于是自己摸索了下写了JAVA如何在没有PLC的情况下通过模拟器来进行OPC UA调试。
背景:PLC对接久了之前一直用寄存器的方式,通过电器工程师给的偏移量直接访问对应的寄存器地址来进行对接,突然有一天要对接西门子PLC,我拿到接口文档一看,懵逼了。
字段都是中文,问了下对方,人家说用字符的方式好,这样以后再加字段就不会没有偏移地址干扰了,我想了想,人家说的很有道理。需求变更很正常,加减字段也很正常。可是我没对接过呀。
于是去网上搜了搜“PLC字符对接”,网上要么是PLC对接也没讲什么字符的方式啊,感情是对方瞎编的方式。我把之前对接过的所有电器工程师都问了一遍,全都说没见过没用过,这种方式在圈内都这么罕见的么,感情科班不教这个啊。
然后我对甲方说:你这接口得改,java没有字符对接的。他说他们之前都是字符对接的啊,怎么到我这就不行了?于是我在VX群内里也告诉他们领导,这种方式不行,他们领导也是技术出身,表示之前都是字符方式对接的啊,后来一看代码全是C#的开发对接。
过了一会群里告诉我好像java确实不行,那他们换偏移量的方式。
这事我以为就这么翻篇了,后来又一个项目也是对接PLC的,又给了一份全是字段的对接文档,在项目会议上甲方工程师说PLC跟上位通过OPC UA的方式,后来一查还真有。感情之前一溜的技术都被我的无知给忽悠住了呀。
有了关键词那网上资料多了,于是确定了JAVA技术栈就使用milo,这时候问题来了,代码根据接口文档写好了,想网上搜个模拟器来试试的。
发现全网这方面的不可谓说是一篇都没,简直就是一篇都没。那就根据我的经验来写下了。
软件
模拟器我用的是 Prosys OPC UA Simulation Server
软件官方下载地址:https://downloads.prosysopc.com/opc-ua-simulation-server-downloads.php
如果你的电脑是Windows就把我圈出来的下载下来好了.
直接上手版本
JAVA代码部分:
- 引jar包,注意版本要跟我一样,版本高的方法不一样。
<dependency>
<groupId>org.eclipse.milo</groupId>
<artifactId>sdk-client</artifactId>
<version>0.6.8</version>
</dependency>
- 项目启动时候进行连接,类似websocket,需要把连接信息记录下来,后续如果要读取和写拿到对应的连接进行操作就行了,我这里就不需要验证那些了,我也是贴网上的。
public static Map<String, OpcUaClient> opcUaClientMap = new ConcurrentHashMap<>();
public static void geOpcUaClient(String deviceName, String url) {
try {
SecurityPolicy securityPolicy = SecurityPolicy.None;
List<EndpointDescription> endpoints;
try {
endpoints = DiscoveryClient.getEndpoints(url).get();
} catch (Throwable ex) {
// 发现服务
String discoveryUrl = url;
if (!discoveryUrl.endsWith("/")) {
discoveryUrl += "/";
}
discoveryUrl += "discovery";
endpoints = DiscoveryClient.getEndpoints(discoveryUrl).get();
}
EndpointDescription endpoint = endpoints.stream()
.filter(e -> e.getSecurityPolicyUri().equals(securityPolicy.getUri()))
.findFirst()
.orElseThrow(() -> new Exception("没有连接上端点"));
OpcUaClientConfig config = OpcUaClientConfig.builder()
.setApplicationName(LocalizedText.english("eclipse milo opc-ua client"))
.setApplicationUri("urn:eclipse:milo:examples:client")
//.setCertificate(loader.getClientCertificate())
//.setKeyPair(loader.getClientKeyPair())
.setEndpoint(endpoint)
//根据匿名验证和第三个用户名验证方式设置传入对象 AnonymousProvider(匿名方式)UsernameProvider(账户密码)new UsernameProvider("admin","123456")
.setIdentityProvider(new AnonymousProvider())
.setRequestTimeout(UInteger.valueOf(5000))
.build();
opcUaClientMap.put(deviceName, OpcUaClient.create(config));
} catch (Exception e) {
System.out.println("创建客户端失败");
}
}
- 读取不同PLC设备的不同字段名称(identifier),我这里是读string,你可以根据你的定义改为其他值,NodeId默认都是3,如果人家有变更你可以问人家。
public static String readStrValue(String deviceName, String identifier) throws Exception {
//创建连接
opcUaClientMap.get(deviceName).connect().get();
NodeId nodeId = new NodeId(3, identifier);
DataValue value = opcUaClientMap.get(deviceName).readValue(0.0, TimestampsToReturn.Both, nodeId).get();
String result = String.valueOf(value.getValue().getValue());
log.info("opc_ua 值为 {} 读取字符: {} ", result, identifier);
return result;
}
- 根据identifier写入值。
public static void writeValue(String deviceName, boolean value, String identifier) throws Exception {
// 获取全局opcUaClient创建连接
opcUaClientMap.get(deviceName).connect().get();
StatusCode statusCode = opcUaClientMap.get(deviceName).writeValue(new NodeId(3, identifier), new DataValue(new Variant(value), null, null)).get();
log.info("opc_ua: 写入值为 {} 写入字符: {} ", value, identifier);
if (statusCode.isGood()) {
log.info("opc_ua 写入回复成功!");
}
}
- 写个main测试下是否能读到值。opc.tcp://Kino:53530/OPCUA/SimulationServer这是要根据你模拟器的url贴过来,add也是模拟器创建的字段名称。
public static void main(String[] args) throws Exception {
geOpcUaClient("PLC1", "opc.tcp://Kino:53530/OPCUA/SimulationServer");
String result = readStrValue("PLC1", "add");
System.out.println("读取内容:" + result);
}
模拟器Prosys OPC UA Simulation 准备
-
下载完后打开软,直接复制 链接地址,贴到上面Main函数中
-
创建自己的对象,右击新增对象。
-
新建对象时候这个NodeId Type可以根据你接口情况选择string或者数字啥的,这里的NodeId Value命名是全局唯一的。
-
确定后再新建字段。
-
字段NodeId Value命名为add,dataType为DataValue。
-
最终字段的信息如图。
-
设置值为十五001的家。
-
最终执行读取设置的内容。
其他
这软件可能是我搜到的唯一有免费版本的模拟器了,值得吐槽的是他用一段时间会自动死掉,需要重启,其他都还可以。