java opc client 開源Utgard學習及踩坑
阿新 • • 發佈:2018-12-12
最近的專案中需要運用到opc client。需要從opc server中獲取資料,或修改引數。主要運用的語言為java。
準備知識:opc server 協議
- OPC DA: Data Access協議,是最基本的OPC協議。OPC DA伺服器本身不儲存資料,只負責顯示資料收集點的當前值。客戶端可以設定一個refresh interval,定期重新整理這個值。目前常見的協議版本號為2.0和3.0,兩個協議不完全相容。也就是用OPC DA 2.0協議的客戶端連不上OPC DA 3.0的Server
- OPC HDA: Historical Data Access協議。前面說過DA只顯示當前狀態值,不儲存資料。而HDA協議是由資料庫提供,提供了歷史資料訪問的能力。比如價格昂貴的Historian資料庫,就是提供HDA協議介面訪問OPC的歷史資料。HDA的Java客戶端目前我沒找到免費的。
- OPC UA: Unified Architecture統一架構協議。誕生於2008年,摒棄了前面老的OPC協議繁雜,互不相容等劣勢,並且不再需要
COM
口訪問,大大簡化了程式設計的難度。基於OPC UA的開源客戶端非常多。不過由於誕生時間較晚,目前在國內工業上未大規模應用,並且這個協議本身就跟舊的DA協議不相容,客戶端沒法通用。
com:Component Object Model物件元件模型,是微軟定義的一套軟體的二進位制介面,可以實現跨程式語言的程序間通訊,進而實現複用。
dcom:Microsoft Distributed Component Object Model,網路傳輸資料的COM協議,客戶端也可以通過網際網路分佈在各個角落。然後準備開工,一番查詢後,發現存在兩個開源類庫
JEasy是java呼叫動態連線庫,底層用的是jni,dll庫比較老。
Utgard則是純java編寫,就是不支援opc 3.0協議。
JEasy在呼叫的時候,jni總是報錯,無力解決。
最終使用了Utgard的庫,在其官網上學習使用方法http://openscada.org/projects/utgard/,最終還是跑起來了,其中opc服務端的配置,一般工程人員會配置好,不需要操心dcom配置之類的問題。最終專案是maven配置完成。最終執行的時候,發現一個group死活發現不了,跟我說是新增加的,但是opc 服務端卻沒有重新配置,導致無法發現,最後還是研究了手冊,自己手動配置完成了。
關鍵API示例
- 列舉某Server下的所有OPC連線
ServerList serverList = new ServerList("10.1.5.123", "freud",
"password", "");
Collection<ClassDetails> classDetails = serverList
.listServersWithDetails(new Category[] {
Categories.OPCDAServer10, Categories.OPCDAServer20,
Categories.OPCDAServer30 }, new Category[] {});
for (ClassDetails cds : classDetails) {
System.out.println(cds.getProgId() + "=" + cds.getDescription());
}
- 列舉連線下的所有Group和Item
public static void main(String[] args) throws Exception {
ConnectionInformation ci = new ConnectionInformation();
ci.setHost("10.1.5.123");
ci.setDomain("");
ci.setUser("freud");
ci.setPassword("password");
ci.setClsid("F8582CF2-88FB-11D0-B850-00C0F0104305");
Server server = new Server(ci, Executors.newSingleThreadScheduledExecutor());
server.connect();
dumpTree(server.getTreeBrowser().browse(), 0);
dumpFlat(server.getFlatBrowser());
server.disconnect();
}
private static void dumpFlat(final FlatBrowser browser)
throws IllegalArgumentException, UnknownHostException, JIException {
for (String name : browser.browse()) {
System.out.println(name);
}
}
private static void dumpTree(final Branch branch, final int level) {
for (final Leaf leaf : branch.getLeaves()) {
dumpLeaf(leaf, level);
}
for (final Branch subBranch : branch.getBranches()) {
dumpBranch(subBranch, level);
dumpTree(subBranch, level + 1);
}
}
private static String printTab(int level) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < level; i++) {
sb.append("\t");
}
return sb.toString();
}
private static void dumpLeaf(final Leaf leaf, final int level) {
System.out.println(printTab(level) + "Leaf: " + leaf.getName() + ":"
+ leaf.getItemId());
}
private static void dumpBranch(final Branch branch, final int level) {
System.out.println(printTab(level) + "Branch: " + branch.getName());
}
- Item的同步查詢
public static void main(String[] args) throws Exception {
ConnectionInformation ci = new ConnectionInformation();
ci.setHost("10.1.5.123");
ci.setDomain("");
ci.setUser("freud");
ci.setPassword("password");
ci.setClsid("F8582CF2-88FB-11D0-B850-00C0F0104305");
Server server = new Server(ci,
Executors.newSingleThreadScheduledExecutor());
server.connect();
Group group = server.addGroup();
Item item = group.addItem("Random.Real5");
Map<String, Item> items = group.addItems("Random.Real1",
"Random.Real2", "Random.Real3", "Random.Real4");
dumpItem(item);
for (Entry<String, Item> temp : items.entrySet()) {
dumpItem(temp.getValue());
}
server.dispose();
}
private static void dumpItem(Item item) throws JIException {
System.out.println("[" + (++count) + "],ItemName:[" + item.getId()
+ "],value:" + item.read(false).getValue());
}
private static int count;
- Item的非同步查詢
private static final int PERIOD = 100;
private static final int SLEEP = 2000;
public static void main(String[] args) throws Exception {
ConnectionInformation ci = new ConnectionInformation();
ci.setHost("10.1.5.123");
ci.setDomain("");
ci.setUser("freud");
ci.setPassword("password");
ci.setClsid("F8582CF2-88FB-11D0-B850-00C0F0104305");
Server server = new Server(ci,
Executors.newSingleThreadScheduledExecutor());
server.connect();
AccessBase access = new SyncAccess(server, PERIOD);
access.addItem("Random.Real5", new DataCallback() {
private int i;
public void changed(Item item, ItemState itemstate) {
System.out.println("[" + (++i) + "],ItemName:[" + item.getId()
+ "],value:" + itemstate.getValue());
}
});
access.bind();
Thread.sleep(SLEEP);
access.unbind();
server.dispose();
}
- Item的釋出訂閱查詢
private static final int PERIOD = 100;
private static final int SLEEP = 2000;
public static void main(String[] args) throws Exception {
ConnectionInformation ci = new ConnectionInformation();
ci.setHost("10.1.5.123");
ci.setDomain("");
ci.setUser("freud");
ci.setPassword("password");
ci.setClsid("F8582CF2-88FB-11D0-B850-00C0F0104305");
Server server = new Server(ci,
Executors.newSingleThreadScheduledExecutor());
server.connect();
AccessBase access = new Async20Access(server, PERIOD, false);
access.addItem("Random.Real5", new DataCallback() {
private int count;
public void changed(Item item, ItemState itemstate) {
System.out.println("[" + (++count) + "],ItemName:["
+ item.getId() + "],value:" + itemstate.getValue());
}
});
access.bind();
Thread.sleep(SLEEP);
access.unbind();
server.dispose();
}
- 自動重連Item非同步讀取
private static final int PERIOD = 100;
private static final int SLEEP = 2000;
public static void main(String[] args) throws Exception {
ConnectionInformation ci = new ConnectionInformation();
ci.setHost("10.1.5.123");
ci.setDomain("");
ci.setUser("freud");
ci.setPassword("password");
ci.setClsid("F8582CF2-88FB-11D0-B850-00C0F0104305");
Server server = new Server(ci,
Executors.newSingleThreadScheduledExecutor());
AutoReconnectController controller = new AutoReconnectController(server);
controller.connect();
AccessBase access = new SyncAccess(server, PERIOD);
access.addItem("Random.Real5", new DataCallback() {
private int i;
public void changed(Item item, ItemState itemstate) {
System.out.println("[" + (++i) + "],ItemName:[" + item.getId()
+ "],value:" + itemstate.getValue());
}
});
access.bind();
Thread.sleep(SLEEP);
access.unbind();
controller.disconnect();
}
- Item同步寫入
public static void main(String[] args) throws Exception {
ConnectionInformation ci = new ConnectionInformation();
ci.setHost("10.1.5.123");
ci.setDomain("");
ci.setUser("freud");
ci.setPassword("password");
ci.setClsid("F8582CF2-88FB-11D0-B850-00C0F0104305");
Server server = new Server(ci,
Executors.newSingleThreadScheduledExecutor());
server.connect();
Group group = server.addGroup();
Item item = group.addItem("Square Waves.Real4");
final Float[] integerData = new Float[] { 1202f, 1203f, 1204f };
final JIArray array = new JIArray(integerData, false);
final JIVariant value = new JIVariant(array);
item.write(value);
Thread.sleep(2000);
dumpItem(item);
server.dispose();
}
private static void dumpItem(Item item) throws JIException {
System.out.println("[" + (++count) + "],ItemName:[" + item.getId()
+ "],value:" + item.read(true).getValue());
}
private static int count;
- Item非同步寫入