提交 | 用户 | 时间
|
e4c3b0
|
1 |
package com.jcdm.main.da.opcuaconfig.client; |
Y |
2 |
|
|
3 |
import com.google.common.collect.ImmutableList; |
|
4 |
import com.jcdm.main.da.opcuaconfig.controller.DaOpcuaConfigController; |
|
5 |
import com.jcdm.main.da.opcuaconfig.domain.DaOpcuaConfig; |
|
6 |
import com.jcdm.main.da.opcuaconfig.domain.NodeEntity; |
|
7 |
import com.jcdm.main.da.opcuaconfig.service.IDaOpcuaConfigService; |
|
8 |
import lombok.extern.slf4j.Slf4j; |
|
9 |
import org.eclipse.milo.opcua.sdk.client.OpcUaClient; |
|
10 |
import org.eclipse.milo.opcua.sdk.client.api.nodes.VariableNode; |
|
11 |
import org.eclipse.milo.opcua.sdk.client.api.subscriptions.UaSubscription; |
|
12 |
import org.eclipse.milo.opcua.stack.core.AttributeId; |
|
13 |
import org.eclipse.milo.opcua.stack.core.BuiltinDataType; |
|
14 |
import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue; |
|
15 |
import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; |
|
16 |
import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; |
|
17 |
import org.eclipse.milo.opcua.stack.core.types.builtin.Variant; |
|
18 |
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned; |
|
19 |
import org.eclipse.milo.opcua.stack.core.types.enumerated.MonitoringMode; |
|
20 |
import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn; |
|
21 |
import org.eclipse.milo.opcua.stack.core.types.structured.MonitoredItemCreateRequest; |
|
22 |
import org.eclipse.milo.opcua.stack.core.types.structured.MonitoringParameters; |
|
23 |
import org.eclipse.milo.opcua.stack.core.types.structured.ReadValueId; |
|
24 |
import org.springframework.beans.factory.annotation.Autowired; |
|
25 |
import org.springframework.stereotype.Service; |
|
26 |
import org.springframework.util.CollectionUtils; |
|
27 |
|
|
28 |
import java.lang.reflect.InvocationTargetException; |
|
29 |
import java.lang.reflect.Method; |
|
30 |
import java.util.ArrayList; |
|
31 |
import java.util.List; |
|
32 |
import java.util.Set; |
|
33 |
import java.util.concurrent.ExecutionException; |
|
34 |
|
|
35 |
/** |
|
36 |
* @ClassName: ClientHandler |
|
37 |
* @Description: 客户端处理 |
|
38 |
* @author Jellyleo |
|
39 |
* @date 2019年12月12日 |
|
40 |
*/ |
|
41 |
@Slf4j |
|
42 |
@Service |
|
43 |
public class ClientHandler { |
|
44 |
|
|
45 |
// 客户端实例 |
|
46 |
public static OpcUaClient client = null; |
|
47 |
|
|
48 |
public List<DaOpcuaConfig> b = null; |
|
49 |
|
|
50 |
@Autowired |
|
51 |
private ClientRunner clientRunner; |
|
52 |
|
|
53 |
@Autowired |
|
54 |
private IDaOpcuaConfigService daOpcuaConfigService; |
|
55 |
|
|
56 |
|
|
57 |
/** |
|
58 |
* |
|
59 |
* @MethodName: connect |
|
60 |
* @Description: connect |
|
61 |
* @throws Exception |
|
62 |
* @CreateTime 2019年12月18日 上午10:41:09 |
|
63 |
*/ |
|
64 |
public String connect() throws Exception { |
|
65 |
|
|
66 |
if (client != null) { |
|
67 |
return "客户端已创建"; |
|
68 |
} |
|
69 |
|
|
70 |
client = clientRunner.run(); |
|
71 |
|
|
72 |
if (client == null) { |
|
73 |
return "客户端配置实例化失败"; |
|
74 |
} |
|
75 |
|
|
76 |
// 创建连接 |
|
77 |
client.connect().get(); |
|
78 |
return "创建连接成功"; |
|
79 |
} |
|
80 |
|
|
81 |
/** |
|
82 |
* @MethodName: disconnect |
|
83 |
* @Description: 断开连接 |
|
84 |
* @return |
|
85 |
* @throws Exception |
|
86 |
* @CreateTime 2019年12月18日 上午10:45:21 |
|
87 |
*/ |
|
88 |
public String disconnect() throws Exception { |
|
89 |
|
|
90 |
if (client == null) { |
|
91 |
return "连接已断开"; |
|
92 |
} |
|
93 |
|
|
94 |
// 断开连接 |
|
95 |
clientRunner.getFuture().complete(client); |
|
96 |
client = null; |
|
97 |
return "断开连接成功"; |
|
98 |
} |
|
99 |
|
|
100 |
/** |
|
101 |
* @MethodName: subscribe |
|
102 |
* @Description: 订阅节点变量 |
|
103 |
* @throws Exception |
|
104 |
* @CreateTime 2019年12月18日 上午10:38:11 |
|
105 |
*/ |
|
106 |
public String subscribe(List<NodeEntity> nodes) throws Exception { |
|
107 |
|
|
108 |
if (client == null) { |
|
109 |
return "找不到客户端,操作失败"; |
|
110 |
} |
|
111 |
|
|
112 |
// 查询订阅对象,没有则创建 |
|
113 |
UaSubscription subscription = null; |
|
114 |
ImmutableList<UaSubscription> subscriptionList = client.getSubscriptionManager().getSubscriptions(); |
|
115 |
if (CollectionUtils.isEmpty(subscriptionList)) { |
|
116 |
subscription = client.getSubscriptionManager().createSubscription(1000.0).get(); |
|
117 |
} else { |
|
118 |
subscription = subscriptionList.get(0); |
|
119 |
} |
|
120 |
|
|
121 |
// 监控项请求列表 |
|
122 |
List<MonitoredItemCreateRequest> requests = new ArrayList<>(); |
|
123 |
|
|
124 |
if (!CollectionUtils.isEmpty(nodes)) { |
|
125 |
for (NodeEntity node : nodes) { |
|
126 |
// 创建监控的参数 |
|
127 |
MonitoringParameters parameters = new MonitoringParameters(subscription.nextClientHandle(), 1000.0, // sampling |
|
128 |
// interval |
|
129 |
null, // filter, null means use default |
|
130 |
Unsigned.uint(10), // queue size |
|
131 |
true // discard oldest |
|
132 |
); |
|
133 |
// 创建订阅的变量, 创建监控项请 求 |
|
134 |
MonitoredItemCreateRequest request = new MonitoredItemCreateRequest( |
|
135 |
new ReadValueId(new NodeId(node.getIndex(), node.getIdentifier()), AttributeId.Value.uid(), |
|
136 |
null, null), |
|
137 |
MonitoringMode.Reporting, parameters); |
|
138 |
requests.add(request); |
|
139 |
} |
|
140 |
} |
|
141 |
|
|
142 |
// 创建监控项,并且注册变量值改变时候的回调函数 |
|
143 |
subscription.createMonitoredItems(TimestampsToReturn.Both, requests, (item, id) -> { |
|
144 |
item.setValueConsumer((i, v) -> { |
|
145 |
handle(i.getReadValueId().getNodeId(), v.getValue()); |
|
146 |
}); |
|
147 |
}).get(); |
|
148 |
|
|
149 |
return "订阅成功"; |
|
150 |
} |
|
151 |
|
|
152 |
/** |
|
153 |
* * @MethodName: write |
|
154 |
* @Description: 回调函数 |
|
155 |
* @CreateTime 2023年10月13日 |
|
156 |
*/ |
|
157 |
public void handle(NodeId id, Variant value){ |
|
158 |
if (b == null || 0 > b.size()) { |
|
159 |
DaOpcuaConfig opcuaConfParam=new DaOpcuaConfig(); |
|
160 |
opcuaConfParam.setSubscribe(1L); |
|
161 |
b=daOpcuaConfigService.selectDaOpcuaConfigList(opcuaConfParam); |
|
162 |
} |
|
163 |
//使用Stream API在List<T>中查找元素 |
|
164 |
DaOpcuaConfig daOpcuaConfig = b.stream() |
|
165 |
.filter(customer ->id.getIdentifier().toString().equals(customer.getNode())) |
|
166 |
.findAny() |
|
167 |
.orElse(null); |
|
168 |
try { |
|
169 |
Class<?> clazz = Class.forName(daOpcuaConfig.getrModule()); |
|
170 |
Method method = clazz.getMethod(daOpcuaConfig.getrFunction(), new Class[] { String.class, String.class }); |
|
171 |
method.invoke(clazz.newInstance(),new Object[] { |
|
172 |
new String(id.getIdentifier().toString()), new String(value.getValue().toString()) }); |
|
173 |
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InstantiationException | |
|
174 |
InvocationTargetException e) { |
|
175 |
e.printStackTrace(); |
|
176 |
} |
|
177 |
} |
|
178 |
|
|
179 |
|
|
180 |
/** |
|
181 |
* @MethodName: write |
|
182 |
* @Description: 变节点量写入 |
|
183 |
* @param node |
|
184 |
* @throws Exception |
|
185 |
* @CreateTime 2019年12月18日 上午9:51:40 |
|
186 |
*/ |
|
187 |
public static Boolean write(NodeEntity node) throws Exception { |
|
188 |
|
|
189 |
if (client == null) { |
|
190 |
log.info("找不到客户端,操作失败"); |
|
191 |
return false; |
|
192 |
} |
|
193 |
|
|
194 |
NodeId nodeId = new NodeId(node.getIndex(), node.getIdentifier()); |
|
195 |
Variant value = null; |
|
196 |
switch (node.getType()) { |
|
197 |
case "int": |
|
198 |
value = new Variant(Integer.parseInt(node.getValue().toString())); |
|
199 |
break; |
|
200 |
case "boolean": |
|
201 |
value = new Variant(Boolean.parseBoolean(node.getValue().toString())); |
|
202 |
break; |
|
203 |
case "short": |
|
204 |
value = new Variant(Short.parseShort(node.getValue().toString())); |
|
205 |
break; |
|
206 |
case "long": |
|
207 |
value = new Variant(Long.parseLong(node.getValue().toString())); |
|
208 |
break; |
|
209 |
case "string": |
|
210 |
value = new Variant(node.getValue().toString()); |
|
211 |
break; |
|
212 |
case "char": |
|
213 |
value = new Variant(node.getValue().toString().charAt(0)); |
|
214 |
break; |
|
215 |
} |
|
216 |
DataValue dataValue = new DataValue(value, null, null); |
|
217 |
|
|
218 |
StatusCode statusCode = client.writeValue(nodeId, dataValue).get(); |
|
219 |
|
|
220 |
return statusCode.isGood(); |
|
221 |
} |
|
222 |
|
|
223 |
/** |
|
224 |
* 方法描述: 读取多个点位的值 |
|
225 |
* |
|
226 |
* @param keys 点位集合 |
|
227 |
* @return {@link List<DataValue>} |
|
228 |
* @throws |
|
229 |
*/ |
4c41b4
|
230 |
// public static List<DataValue> readValues2(Set<String> keys){ |
Y |
231 |
// List<NodeId> nodeIdList=new ArrayList<>(500); |
|
232 |
// keys.forEach(e->{ |
|
233 |
// NodeId nodeId = new NodeId(2, e); |
|
234 |
// nodeIdList.add(nodeId); |
|
235 |
// }); |
|
236 |
// try { |
|
237 |
// List<DataValue> dataValues=client.readValues(0.0, TimestampsToReturn.Both,nodeIdList).get(); |
|
238 |
// return dataValues; |
|
239 |
// } catch (InterruptedException | ExecutionException e) { |
|
240 |
// e.printStackTrace(); |
|
241 |
// } |
|
242 |
// return null; |
|
243 |
// } |
|
244 |
|
|
245 |
|
|
246 |
/** |
|
247 |
* 方法描述: 读取多个点位的值 |
|
248 |
* |
|
249 |
* @param nodeIdList 点位集合 |
|
250 |
* @return {@link List<DataValue>} |
|
251 |
* @throws |
|
252 |
*/ |
|
253 |
public static List<DataValue> readValues(List<NodeId> nodeIdList){ |
e4c3b0
|
254 |
try { |
Y |
255 |
List<DataValue> dataValues=client.readValues(0.0, TimestampsToReturn.Both,nodeIdList).get(); |
|
256 |
return dataValues; |
|
257 |
} catch (InterruptedException | ExecutionException e) { |
|
258 |
e.printStackTrace(); |
|
259 |
} |
|
260 |
return null; |
|
261 |
} |
|
262 |
|
|
263 |
/** |
|
264 |
* @MethodName: read |
|
265 |
* @Description: 读取 |
|
266 |
* @param node |
|
267 |
* @return |
|
268 |
* @throws Exception |
|
269 |
* @CreateTime 2019年12月19日 下午2:40:34 |
|
270 |
*/ |
|
271 |
public String read(NodeEntity node) throws Exception { |
|
272 |
|
|
273 |
if (client == null) { |
|
274 |
return "找不到客户端,操作失败"; |
|
275 |
} |
|
276 |
|
|
277 |
NodeId nodeId = new NodeId(node.getIndex(), node.getIdentifier()); |
|
278 |
VariableNode vnode = client.getAddressSpace().createVariableNode(nodeId); |
|
279 |
DataValue value = vnode.readValue().get(); |
|
280 |
log.info("Value={}", value); |
|
281 |
|
|
282 |
Variant variant = value.getValue(); |
|
283 |
log.info("Variant={}", variant.getValue()); |
|
284 |
|
|
285 |
log.info("BackingClass={}", BuiltinDataType.getBackingClass(variant.getDataType().get())); |
|
286 |
|
|
287 |
return variant.getValue().toString(); |
|
288 |
} |
|
289 |
|
|
290 |
|
|
291 |
/** |
|
292 |
* 方法描述: 写入多个节点的值 |
|
293 |
* |
|
294 |
* @param keys 节点集合 |
|
295 |
* @param values 值集合 |
|
296 |
* @param client 客户端 |
|
297 |
* @return {@link Object} |
|
298 |
* @throws |
|
299 |
*/ |
|
300 |
public static Object writeValues(Set<String> keys, List<Object> values, OpcUaClient client){ |
|
301 |
List<NodeId> nodeIs=new ArrayList<>(keys.size()); |
|
302 |
keys.forEach(e->{ |
|
303 |
NodeId nodeId = new NodeId(2, e); |
|
304 |
nodeIs.add(nodeId); |
|
305 |
}); |
|
306 |
List<DataValue> dataValues=new ArrayList<>(values.size()); |
|
307 |
values.forEach(e->{ |
|
308 |
Variant value=new Variant(Double.parseDouble(e.toString())); |
|
309 |
DataValue dataValue=new DataValue(value); |
|
310 |
dataValues.add(dataValue); |
|
311 |
}); |
|
312 |
try { |
|
313 |
client.writeValues(nodeIs,dataValues).get(); |
|
314 |
} catch (InterruptedException | ExecutionException e) { |
|
315 |
e.printStackTrace(); |
|
316 |
} |
|
317 |
return null; |
|
318 |
} |
|
319 |
} |