Write Values to an Modbus/TCP Slave Device

Description

This script sets a value inside a Modbus/TCP slave device.

This is used if you want to link the form system back into your control or information systems to advise that that a job - such as an isolation - has been completed.

In turn, you could use this to indicate isolation in SCADA, route around the isolated equipment in your plant logic, or simply keep a history of events in your historian product without having to add additional data sources.

In the example below, the target Modbus address to be set is a property of the asset. We read the target address from the ARDI API before we set it.

We also set a fixed value (in this case, 1) to the address. Alternatively, you could set timestamps, strings etc.

Full Script

import requests
import pymodbus
from datetime import datetime
import os
import sys
import traceback
import warnings
from pymodbus.client.sync import ModbusTcpClient
 
#Set default details
 
#The ARDI server to query
server="localhost/s/bm"
 
#The ARDI property containing the Modbus address
mbaddressid=47
 
#Modbus connection details
ipaddress="localhost"
unit=1
port=502
register=0
offset=0
 
#The value to write
valuetoset=1
 
asset = "Unknown Asset"
checklist = "Unknown Checklist"
user = "Unknown User"
assetid = "1"
tm = datetime.now().strftime("%Y/%m/%d %H:%M:%S")
 
#Get submission details from environment variables
try:
    asset = os.environ["assetname"]
except:
    print "No Asset Provided"
    sys.exit(0)
 
try:
    assetid = os.environ["assetid"]
except:
    print "No Asset ID Provided"
    sys.exit(0)
 
try:
    checklist = os.environ["checklist"]
except:
    print "No Checklist Provided"
    sys.exit(0)
 
try:
    user = os.environ["user"]
except:
    print "No User Provided"
    sys.exit(0)
 
def Sub(st,ass,chk,usr,dt):
    return st.replace("{checklist}",chk).replace("{asset}",ass).replace("{user}",usr).replace("{date}",dt)
 
#Get isolation modbus address from server (assumes a Guest Mode server, otherwise we need to authenticate!)
url = "http://" + server + "/api/asset/property?id=" + str(assetid) + "&property=" + str(mbaddressid)
resp = requests.get(url)
 
data = resp.content
 
 
#Read the address from ARDI
ind = data.find("<text>")
if ind > 0:
    indx = data.find("</text>")
    totaloffset = ind + 6
    value = data[totaloffset:indx]
 
    #Adjust the value based on the type of I/O point we are talking about.
    if len(value) > 3:
        if value[0] == '1':
            register = 1
            offset = 1000
            if len(value) > 4:
                offset = 10000
        if value[0] == '3':
            register = 3
            offset = 3000
            if len(value) > 4:
                offset = 30000
        if value[0] == '4':
            register = 4
            offset = 4000
            if len(value) > 4:
                offset = 40000
 
 
    #Connect to modbus device
    client=ModbusTcpClient(ipaddress,port=port)
    client.connect()
    address = int(value)-offset
 
    #Write data at correct location...
    if register == 3:
        client.write_input_register(address,int(valuetoset),unit=unit)
    if register == 4:
        client.write_register(address,int(valuetoset),unit=unit)
    if register == 1:
        if valuetoset == 1:
            valuetoset = True
        else:
            valuetoset = False
        client.write_discrete_input(address,valuetoset,unit=unit)
    if register == 0:
        if valuetoset == 1:
            valuetoset = True
        else:
            valuetoset = False
        client.write_coil(address,valuetoset,unit=unit)
 
#If everything worked out, send the word 'OK'.
print 'OK'