How Java uses KEPserver to implement S71500 OPC communication

1.PLC and OPC

PLC used: Siemens PLC S7-1500

OPC server software used:

KEPServer V6

2. Connection test

OPC is an interface standard for hardware and software used in the fields of industrial control and production automation to efficiently read and write data between applications and process control equipment. O stands for OLE (object linking and embedding), P (process), C (control).

OPC server includes three types of objects (Object): Server object (Server), Item object (Item) and Group object (Group).

The OPC standard adopts the C/S mode, and the OPC server is responsible for continuously providing data to the OPC client.

maven dependencies

<!--utgard -->
        <dependency>
            <groupId>org.openscada.external</groupId>
            <artifactId>org.openscada.external.jcifs</artifactId>
            <version>1.2.25</version>
        </dependency>
        <dependency>
            <groupId>org.openscada.jinterop</groupId>
            <artifactId>org.openscada.jinterop.core</artifactId>
            <version>2.1.8</version>
        </dependency>
        <dependency>
            <groupId>org.openscada.jinterop</groupId>
            <artifactId>org.openscada.jinterop.deps</artifactId>
            <version>1.5.0</version>
        </dependency>
        <dependency>
            <groupId>org.openscada.utgard</groupId>
            <artifactId>org.openscada.opc.dcom</artifactId>
            <version>1.5.0</version>
        </dependency>
        <dependency>
            <groupId>org.openscada.utgard</groupId>
            <artifactId>org.openscada.opc.lib</artifactId>
            <version>1.5.0</version>
        </dependency>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.61</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.3.0-alpha4</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.3.0-alpha4</version>
            <scope>test</scope>
        </dependency>

Read the point value of PLC

import java.util.concurrent.Executors;

import org.jinterop.dcom.common.JIException;
import org.jinterop.dcom.core.JIString;
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.Item;
import org.openscada.opc.lib.da.ItemState;
import org.openscada.opc.lib.da.Server;
import org.openscada.opc.lib.da.SyncAccess;

public class UtgardTutorial1 {

public static void main(String[] args) throws Exception {
// connection information
final ConnectionInformation ci = new ConnectionInformation();
ci.setHost(“192.168.0.1”); // Computer IP
ci.setDomain(“”); // Domain, just leave it empty.
ci.setUser(“OPCUser”); // The user name created by yourself on the computer (previously configured by DCOM)
ci.setPassword(“123456”); // Password (username and password)

// Configuration using MatrikonOPC Server
// ci.setClsid(“F8582CF2-88FB-11D0-B850-00C0F0104305”); // The registry ID of MatrikonOPC can be seen in “Component Services”
// final String itemId = “u.u”; // The name of the item configured on MatrikonOPC Server is based on actual

// Use KEPServer configuration
ci.setClsid(“7BC0CC8E-482C-47CA-ABDC-0FE7F9C6E729”); // The registry ID of KEPServer can be seen in “Component Services”
final String itemId = “u.u.u”; // The name of the item configured on KEPServer. There is no actual PLC. The simulator used is: simulator (KEPServer establishes channels, establishes equipment, and establishes points). Locate the point to be read by marking the point name. value
// final String itemId = “Channel 1. Device 1. Tag 1”;

// Start service
final Server server = new Server(ci, Executors.newSingleThreadScheduledExecutor());

try {
// Connect to service
server.connect();
// add sync access, poll every 500 ms, start a synchronous access to read the value on the address, the thread pool reads the value every 500ms
// This is used to read values in a loop. You don’t need to do this if you only read the value once.
final AccessBase access = new SyncAccess(server, 500);
// This is a callback function, which is to execute the printing after reading the value. It is written using an anonymous class. Of course, it can also be written outside.
access.addItem(itemId, new DataCallback() {
@Override
public void changed(Item item, ItemState itemState) {
int type = 0;
try {
type = itemState.getValue().getType(); // The type is actually a number, defined with a constant
} catch (JIException e) {
e.printStackTrace();
}
System.out.println(“The data type of the monitoring item is: —–” + type);
System.out.println(“The timestamp of the monitoring item is: —–” + itemState.getTimestamp().getTime());
System.out.println(“The detailed information of the monitoring item is: —–” + itemState);

// If the value read is a short type value
if (type == JIVariant.VT_I2) {
short n = 0;
try {
n = itemState.getValue().getObjectAsShort();
} catch (JIException e) {
e.printStackTrace();
}
System.out.println(“—–short type value: ” + n);
}

// If the value read is a string type
if(type == JIVariant.VT_BSTR) { // The type of string is 8
JIString value = null;
try {
value = itemState.getValue().getObjectAsString();
} catch (JIException e) {
e.printStackTrace();
} // Read by string
String str = value.getString(); // get string
System.out.println(“—–String type value: ” + str);
}
}
});
// start reading, start reading value
access.bind();
// wait a little bit, there is a 10 second delay
Thread.sleep(10 * 1000);
// stop reading, stop reading
access.unbind();
} catch (final JIException e) {
System.out.println(String.format(” X: %s”, e.getErrorCode(), server.getErrorMessage(e.getErrorCode())));
}
}
}

Reading values and writing values

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
 
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 {
 
        // connection information
        final ConnectionInformation ci = new ConnectionInformation();
        
        ci.setHost("192.168.0.1"); // Computer IP
        ci.setDomain(""); // Domain, just leave it empty.
        ci.setUser("OPCUser"); // User name, configured when configuring DCOM
        ci.setPassword("123456"); // Password
        
        // Configuration using MatrikonOPC Server
        // ci.setClsid("F8582CF2-88FB-11D0-B850-00C0F0104305"); // The registry ID of MatrikonOPC can be seen in "Component Services"
        // final String itemId = "u.u"; // The name of the item is based on the actual
 
        //Use KEPServer configuration
        ci.setClsid("7BC0CC8E-482C-47CA-ABDC-0FE7F9C6E729"); // The registry ID of KEPServer can be seen in "Component Services"
        final String itemId = "u.u.u"; // The name of the item is based on actual, there is no actual PLC, the simulator used is: simulator
        // final String itemId = "Channel 1. Device 1. Tag 1";
        
        // create a new server, start the service
        final Server server = new Server(ci, Executors.newSingleThreadScheduledExecutor());
        try {
            // connect to server, connect to service
            server.connect();
 
            // add sync access, poll every 500 ms, start a synchronous access to read the value on the address, the thread pool reads the value every 500ms
            // This is used to read values in a loop. You don't need to do this if you only read the value once.
            final AccessBase access = new SyncAccess(server, 500);
            // This is a callback function, which is executed after reading the value and then executing the following code. It is written using an anonymous class. Of course, it can also be written outside.
            access.addItem(itemId, new DataCallback() {
                @Override
                public void changed(Item item, ItemState state) {
                    // also dump value
                    try {
                        if (state.getValue().getType() == JIVariant.VT_UI4) { // If the value type read is UnsignedInteger, that is, an unsigned integer value
                            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, add a group, this is used to read or write the value once, instead of reading or writing in a loop
            // The name of the group is arbitrary. The reason for naming the group is that the server can addGroup or removeGroup. When reading the value once, it first adds the group and then removes the group. After reading the value again, it adds and then deletes it.
            final Group group = server.addGroup("test");
            // Add a new item to the group,
            // Add an item to the group. The item name is the name of the item built on MatrikonOPC Server or KEPServer, such as: u.u.TAG1, PLC.S7-300.TAG1
            final Item item = group.addItem(itemId);
 
            // start reading, start loop reading values
            access.bind();
 
            // add a thread for writing a value every 3 seconds
            //Writing once is item.write(value). If you write in a loop, a thread will be started to execute item.write(value) all the time.
            ScheduledExecutorService writeThread = Executors.newSingleThreadScheduledExecutor();
            writeThread.scheduleWithFixedDelay(new Runnable() {
                @Override
                public void run() {
                    final JIVariant value = new JIVariant("24"); // write 24
                    try {
                        System.out.println(">>> " + "Write value: " + "24");
                        item.write(value);
                    } catch (JIException e) {
                        e.printStackTrace();
                    }
                }
            }, 5, 3, TimeUnit.SECONDS); // Execute the code for the first time 5 seconds after startup, and then execute the code every 3 seconds.
 
            // wait a little bit, delay 20 seconds
            Thread.sleep(20 * 1000);
            writeThread.shutdownNow(); // Shut down the thread that has been writing
            // stop reading, stop loop reading values
            access.unbind();
        } catch (final JIException e) {
            System.out.println(String.format(" X: %s", e.getErrorCode(), server.getErrorMessage(e.getErrorCode())));
        }
    }
}

The knowledge points of the article match the official knowledge files, and you can further learn related knowledge. Java Skill TreeHomepageOverview 138,710 people are learning the system