work in progress ---
Getting Started with Utgard - a tutorial
...
OPC (http://en.wikipedia.org/wiki/OLE_for_process_control) is a an industry standard to allow a unified access to a varied number of devices, be it controller of any kind, sensors, whatever. Many specialized hardware components have their own OPC Server (e.g. WinCC, ABB, ...), but there are quite a few implementors which provide generic "OPC servers" which provide access to devices via a wealth of protocols. Prominent examples are Matrikon (http://www.matrikonopc.de/opc-server/) or Software Toolbox's TOP Server (http://www.toolboxopc.com/index.html).
...
- Windows computer to install the OPC Server (note that Home Editions of Windows might not work due to restrictions on the Windows operating system)
- on the development computer a functional JDK (6 or 7)
- on the development computer a running Eclipse 3.x 5+ or 4.x
Setting up TOP Server
...
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
package org.openscada.opc.tutorial; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.jinterop.dcom.common.JIException; import org.jinterop.dcom.core.JIVariant; import org.openscada.opc.lib.common.ConnectionInformation; import org.openscada.opc.lib.da.AccessBase; import org.openscada.opc.lib.da.DataCallback; import org.openscada.opc.lib.da.Group; import org.openscada.opc.lib.da.Item; import org.openscada.opc.lib.da.ItemState; import org.openscada.opc.lib.da.Server; import org.openscada.opc.lib.da.SyncAccess; public class UtgardTutorial2 { public static void main(String[] args) throws Exception { // create connection information final ConnectionInformation ci = new ConnectionInformation(); ci.setHost("your host"); ci.setDomain(""); ci.setUser("your user"); ci.setPassword("your password"); ci.setProgId("SWToolbox.TOPServer.V5"); // ci.setClsid("680DFBF7-C92D-484D-84BE-06DC3DECCD68"); // if ProgId is not working, try it using the Clsid instead final String itemId = "Channel1.Device1.Tag1"; // create a new server final Server server = new Server(ci, Executors.newSingleThreadScheduledExecutor()); try { // connect to server server.connect(); // add sync access, poll every 500 ms final AccessBase access = new SyncAccess(server, 500); access.addItem(itemId, new DataCallback() { @Override public void changed(Item item, ItemState state) { // also dump value try { if (state.getValue().getType() == JIVariant.VT_UI4) { System.out.println("<<< " + state + " / value = " + state.getValue().getObjectAsUnsigned().getValue()); } else { System.out.println("<<< " + state + " / value = " + state.getValue().getObject()); } } catch (JIException e) { e.printStackTrace(); } } }); // Add a new group final Group group = server.addGroup("test"); // Add a new item to the group final Item item = group.addItem(itemId); // start reading access.bind(); // add a thread for writing a value every 3 seconds ScheduledExecutorService writeThread = Executors.newSingleThreadScheduledExecutor(); final AtomicInteger i = new AtomicInteger(0); writeThread.scheduleWithFixedDelay(new Runnable() { @Override public void run() { final JIVariant value = new JIVariant(i.incrementAndGet()); try { System.out.println(">>> " + "writing value " + i.get()); item.write(value); } catch (JIException e) { e.printStackTrace(); } } }, 5, 3, TimeUnit.SECONDS); // wait a little bit Thread.sleep(20 * 1000); writeThread.shutdownNow(); // stop reading access.unbind(); } catch (final JIException e) { System.out.println(String.format("%08X: %s", e.getErrorCode(), server.getErrorMessage(e.getErrorCode()))); } } } |
---
Until then have a look at this great post: http://clifcarr.The output should look like this:
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
Mai 15, 2013 4:31:30 PM rpc.DefaultConnection processOutgoing
INFO:
Sending REQUEST
Mai 15, 2013 4:31:30 PM rpc.DefaultConnection processIncoming
INFO:
Recieved RESPONSE
<<< Value: [[org.jinterop.dcom.core.JIUnsignedInteger@6f14021e]], Timestamp: Mi Mai 15 16:31:30 MESZ 2013, Quality: 192, ErrorCode: 00000000 / value = 0
Mai 15, 2013 4:31:30 PM rpc.DefaultConnection processOutgoing
INFO:
Sending REQUEST
Mai 15, 2013 4:31:30 PM rpc.DefaultConnection processIncoming
INFO:
Recieved RESPONSE
<<< Value: [[org.jinterop.dcom.core.JIUnsignedInteger@15de3027]], Timestamp: Mi Mai 15 16:31:30 MESZ 2013, Quality: 192, ErrorCode: 00000000 / value = 0
>>> writing value 1
Mai 15, 2013 4:31:31 PM rpc.DefaultConnection processOutgoing
INFO:
Sending REQUEST
Mai 15, 2013 4:31:31 PM rpc.DefaultConnection processIncoming
INFO:
Recieved RESPONSE
Mai 15, 2013 4:31:31 PM rpc.DefaultConnection processOutgoing
INFO:
Sending REQUEST
Mai 15, 2013 4:31:31 PM rpc.DefaultConnection processIncoming
INFO:
Recieved RESPONSE
<<< Value: [[org.jinterop.dcom.core.JIUnsignedInteger@69d5ee81]], Timestamp: Mi Mai 15 16:31:30 MESZ 2013, Quality: 192, ErrorCode: 00000000 / value = 0
Mai 15, 2013 4:31:31 PM rpc.DefaultConnection processOutgoing
INFO:
Sending REQUEST
Mai 15, 2013 4:31:31 PM rpc.DefaultConnection processIncoming
INFO:
Recieved RESPONSE
<<< Value: [[org.jinterop.dcom.core.JIUnsignedInteger@2a4c6a7d]], Timestamp: Mi Mai 15 16:31:31 MESZ 2013, Quality: 192, ErrorCode: 00000000 / value = 1
Mai 15, 2013 4:31:32 PM rpc.DefaultConnection processOutgoing
INFO:
Sending REQUEST
Mai 15, 2013 4:31:32 PM rpc.DefaultConnection processIncoming
INFO:
Recieved RESPONSE
<<< Value: [[org.jinterop.dcom.core.JIUnsignedInteger@17f99aa6]], Timestamp: Mi Mai 15 16:31:31 MESZ 2013, Quality: 192, ErrorCode: 00000000 / value = 1 |
Thats it, pretty much.
Unfortunately, this is in many cases not enough. In this example there is no error handling, and this is quite needed. Within the "OPC Driver" of the openSCADA project, all this stuff is handled for you. So please feel free to peruse the code to get a feel how it works: https://github.com/ctron/org.openscada.atlantis/tree/1.0/org.openscada.da.server.opc/src/org/openscada/da/server/opc
Other tutorials
If you have a tutorial and want to be linked here, please drop us a line.