A simple OPC UA/ModbusTCP gateway (Python)

        Using the content of my previous blog posts, I can use Python to write the simplest OPC UA /ModbusTCP gateway.

From this program it can be seen that:

  1. It is not difficult to apply OPC UA, and now we can apply it to engineering applications, even DIY projects. There is no need to use complex tool software.
  2. It is a good choice to use Python to build prototype programs in the field of industrial automation.

OPCUA_modbus gateway

import sys
sys.path.insert(0, "..")
import time
from opcua import  Server
from pyModbusTCP.client import ModbusClient # Modbus TCP Client
from pyModbusTCP import utils 
if __name__ == "__main__":

    # setup our server
    server = Server()
    server.set_endpoint("opc.tcp://127.0.0.1:48400/freeopcua/server/")
    # setup our own namespace, not really necessary but should as spec
    uri = "http://examples.freeopcua.github.io"
    idx = server.register_namespace(uri)

    # get Objects node, this is where we should put our nodes
    objects = server.get_objects_node()

    # populating our address space
    myobj = objects.add_object(idx, "MyObject")
    myvar = myobj.add_variable(idx, "MyVariable", 6.7)
    myvar.set_writable()    # Set MyVariable to be writable by clients
    ModbusInterface = ModbusClient(host="localhost", port=502, unit_id=1, auto_open=True, auto_close=False) 
    
    # starting!
    server.start()
    
    try:
        count = 0
        while True:
            time.sleep(1)
            reg_l=ModbusInterface.read_input_registers(0,2)
            val=utils.word_list_to_long(reg_l)
            print(utils.decode_ieee(val[0],False)) 
            myvar.set_value(utils.decode_ieee(val[0],False))
    finally:
        #close connection, remove subcsriptions, etc
        server.stop()

modbusTCP server program

import argparse
from pyModbusTCP.server import ModbusServer, DataBank
from pyModbusTCP import utils
from datetime import datetime

import numpy as np 
Fs = 8000
f = 50
x=0
coil_state=True 
class MyDataBank(DataBank):
    """A custom ModbusServerDataBank for override get_holding_registers method."""

    def __init__(self):
        # turn off allocation of memory for standard modbus object types
        # only "holding registers" space will be replaced by dynamic build values.
        super().__init__(virtual_mode=True)
    def get_coils(self, address, number=1, srv_info=None):
        global coil_state
        coil_state=not coil_state
        return coil_state
            
    def get_holding_registers(self, address, number=1, srv_info=None):
        """Get virtual holding registers."""
        # populate virtual registers dict with current datetime values
        now = datetime.now()
        return now.second
       
    def get_input_registers(self, address, number=1, srv_info=None):
        global x
        wave=np.sin(2 * np.pi * f * x / Fs)*10
        x=x+1
        b32_l=[utils.encode_ieee(wave,False)]
        b16_l = utils.long_list_to_word(b32_l)
        print(b16_l)              
        return  b16_l
 
if __name__ == '__main__':
    # parse args
    parser = argparse.ArgumentParser()
    parser.add_argument('-H', '--host', type=str, default='localhost', help='Host (default: localhost)')
    parser.add_argument('-p', '--port', type=int, default=502, help='TCP port (default: 502)')
    args = parser.parse_args()
    # init modbus server and start it
    server = ModbusServer(host=args.host, port=args.port, data_bank=MyDataBank())
    server.start()

        Finally, access the OPCUA Server through the uaExpert program. You can see that the myVar variable is changing.

 OPCUA client 

import sys
sys.path.insert(0, "..")
import numpy as np 
import matplotlib.pyplot as plt
from opcua import Client

x = np.arange(0,1000,1,dtype=np.int16)
y=np.arange(-10,10,0.02,dtype=np.float32)
if __name__ == "__main__":

    client = Client("opc.tcp://localhost:48400/freeopcua/server/")
    # client = Client("opc.tcp://admin@localhost:4840/freeopcua/server/") #connect using a user
    try:
        client.connect()

        # Client has a few methods to get proxy to UA nodes that should always be in address space such as Root or Objects
        root = client.get_root_node()
        print("Objects node is: ", root)
        # Node objects have methods to read and write node attributes as well as browse or populate address space
        print("Children of root are: ", root.get_children())
        while True:
            myvar = root.get_child(["0:Objects", "2:MyObject", "2:MyVariable"])
            obj = root.get_child(["0:Objects", "2:MyObject"])
            print("myvar is: ", myvar.get_value())
            y=np.append(y,myvar.get_value())
            y=np.delete(y, 0, axis=0)      
            plt.clf()
            plt.plot(x, y, ls="-", lw=2, label="plot figure")
            plt.legend()
            plt.show()
            plt.pause(0.1)
        # Stacked myvar access
        # print("myvar is: ", root.get_children()[0].get_children()[1].get_variables()[0].get_value())

    finally:
        client.disconnect()

You can see that these programs are short and neat. Writing programs is the best way to learn computer network protocols.

Guess you like

Origin blog.csdn.net/yaojiawan/article/details/131494145