赞
踩
操作系统:windows10 版本1909
注意:与kepserver的通讯对windows版本的要求很高,目前所了解到的必须是1909版本以前,或者1903版本,windows11 使用21H2的版本。
原因是:微软给修复了docm的安全漏洞,发了补丁的原因,导致了一些新版本的windows不支持opcda的写法。
用户名:OPCServer 【自定义即可】
密码:123456 【自定义即可】
添加用户步骤完成
找到DCOM-IN
上面两个DOCM-IN都是一样的操作。
新建入站规则
然后一直下一步,直到【名称】,然后点击完成
新建入站规则--程序--找到server_runtime.exe
其他步骤同上一个规则一样即可。
因为自定义的编辑都是一样的,所以我下面只演示一个。
和上面一样,这三个都点自定义,编辑中把新增的用户添加进去,把允许的权限全部打开
下面是JAVA代码
所需依赖
- <dependency>
- <groupId>org.openscada.utgard</groupId>
- <artifactId>org.openscada.opc.lib</artifactId>
- <version>1.5.0</version>
- <exclusions>
- <exclusion>
- <groupId>org.bouncycastle</groupId>
- <artifactId>bcprov-jdk15on</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <groupId>org.bouncycastle</groupId>
- <artifactId>bcprov-jdk15on</artifactId>
- <version>1.65</version>
- </dependency>
- <dependency>
- <groupId>org.openscada.utgard</groupId>
- <artifactId>org.openscada.opc.dcom</artifactId>
- <version>1.5.0</version>
- </dependency>

连接配置
- @Configuration
- @ConfigurationProperties(prefix = "kep-server")
- @Slf4j
- @Data
- public class KepServerConfig implements Serializable {
- private String host;
- private String domain;
- private String user;
- private String password;
- private String clsid;
-
- @Bean(name = "opcServer")
- public Server server() {
- ConnectionInformation connectionInformation = new ConnectionInformation();
- connectionInformation.setHost(host);
- connectionInformation.setDomain(domain);
- connectionInformation.setUser(user);
- connectionInformation.setPassword(password);
- connectionInformation.setClsid(clsid);
- // 连接到服务
- Server server = new Server(connectionInformation, null);
- try {
- server.connect();
- log.info("opc 服务端连接成功........");
- } catch (UnknownHostException e) {
- log.error("opc 地址错误:", e);
- } catch (JIException e) {
- log.error("opc 连接失败:", e);
- }catch (AlreadyConnectedException e) {
- log.error("opc 已连接:", e);
- }
- return server;
- }
-
- }

【注意:为了不误人子弟,下面的读取方法是有BUG的,正确代码有空修改,当你看见这句话时,还没有修改】
批量读取kepserver中的数据
- package com.hangcheng.opc.common.scheduledTasks;
-
- import com.hangcheng.opc.common.constant.CommonConstant;
- import com.hangcheng.opc.common.constant.DictTagsConstant;
- import com.hangcheng.opc.common.constant.KepServerConstant;
- import com.hangcheng.opc.common.constant.RedisKeyConstant;
- import com.hangcheng.opc.common.pojo.DataTags;
- import com.hangcheng.opc.common.pojo.EarlyWarning;
- import com.hangcheng.opc.common.utils.opc.OpcTypeConversionUtils;
- import com.hangcheng.opc.common.utils.redis.RedisCacheUtils;
- import com.hangcheng.opc.service.EarlyWarningService;
- import com.hangcheng.opc.service.TagsDataService;
- import lombok.extern.slf4j.Slf4j;
- import org.jinterop.dcom.core.JIVariant;
- import org.openscada.opc.dcom.da.OPCSERVERSTATE;
- import org.openscada.opc.lib.da.*;
- import org.springframework.beans.factory.annotation.Qualifier;
- import org.springframework.stereotype.Service;
-
- import javax.annotation.Resource;
- import java.util.*;
- import java.util.stream.Collectors;
-
- @Service
- @Slf4j
- public class OpcDaClient {
- @Resource
- private TagsDataService tagsDataService;
- @Resource
- @Qualifier("opcServer")
- private Server server;
- @Resource
- private RedisCacheUtils redisCacheUtils;
- @Resource
- private EarlyWarningService earlyWarningService;
-
- /**
- * PLC批量读操作
- */
- public void configureTasks() {
- //下面这段是为了解决断线重连的问题
- try {
- // 这里会出现空是应为 OPCServer 为 null,但是单独拿OPCServer来判断null并不严谨,因为还有一些其他报错会导致OPCServer为空,
- // 并不是只有连接失败导致,所以这里进行多次判断
- if (server.getServerState() == null) {
- log.info("OPCServer为空,尝试一次连接");
- // 尝试一次连接,一般情况连接失败就直接被下面的catch捕获了
- server.connect();
- } else if (server.getServerState() != null && server.getServerState().getServerState().equals(OPCSERVERSTATE.OPC_STATUS_RUNNING)) {
- log.info("与服务端的连接是正常的,继续执行业务代码");
- } else {
- return;
- }
-
- // 创建组
- Group group = server.addGroup();
- // 转数组
- String[] items = keyList.toArray(new String[]{});
- // 把所有的标记添加到组里
- Map<String, Item> itemResult = group.addItems(items);
- // map转set,避免重复
- Set<Item> itemSet = new HashSet<>(itemResult.values());
- // 创建一个 itemSet 大小的数组
- Item[] itemArr = new Item[itemSet.size()];
- // 将 itemSet集合 复制到 itemArr数组
- itemSet.toArray(itemArr);
- // 一次性读取全部标记的值,非常滴爽
- Map<Item, ItemState> resultMap = group.read(true, itemArr);
- // resultMap 就是读出来的所有数据
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- }

写操作
- /**
- * PLC批量写操作
- *
- * @param tagValueMap 指定标识与指定值集合
- */
- public void writePlcValues(Map<String, String> tagValueMap) {
- try {
- // 添加一个Group
- Group group = server.addGroup();
- Map<String, String> itemIdAndRWMap = redisCacheUtils.hmEntries(RedisKeyConstant.ITEM_ID_AND_R_W_MAP);
-
- Iterator<String> iterator = tagValueMap.keySet().iterator();
-
- while (iterator.hasNext()) {
- String tag = iterator.next();
- String key = itemIdAndRWMap.get(tag);
- // 如果标识不存在那么代表传参有误,直接去除即可
- if (key == null || !key.equals(RedisKeyConstant.R_W)) {
- iterator.remove();
- }
- }
- int i = 0;
- WriteRequest[] writeRequests = new WriteRequest[tagValueMap.size()];
- for (Map.Entry<String, String> entry : tagValueMap.entrySet()) {
- String key = entry.getKey();
- String value = entry.getValue();
- WriteRequest writeRequest = new WriteRequest(group.addItem(key), new JIVariant(value));
- writeRequests[i++] = writeRequest;
- }
- group.write(writeRequests);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }

完毕,剩下的再补,没时间写了
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。