The scripting function system.opc.rawModbus()
has now been implemented with the signature shown above. The user manual hasnât been updated yet, but yâall can play with it:
For Ignition v8.1
For Ignition v7.9
Note that this function is available in Gateway scope only. For use elsewhere, like in the Designerâs script console, I recommend a gateway message handler of this form:
def handleMessage(payload):
from java.lang import Throwable
import traceback
dev, unit, func, pay, rsplen = [payload.get(x, None) for x in ['devName', 'unit', 'functionCode', 'payload', 'responseLen']]
try:
return system.opc.rawModbus(dev, unit, func, pay, rsplen).get()
except Throwable, t:
return serialization.stringException(t)
except:
return traceback.format_exc()
In a designer script console, @plarochelleâs desired use of function 23 would look like this:
from java.io import ByteArrayInputStream, ByteArrayOutputStream, DataInputStream, DataOutputStream
from com.inductiveautomation.ignition.common.model.values import QualifiedValue
# Raw implementation of write/read multiple registers, function 23.
# Start by constructing the payload of the Modbus PDU. It is
# a UINT read starting address and a UINT number of read registers (<=125),
# then UINT write starting address and UINT number to write (<=121),
# then USINT bytes to follow, then INT/UINT per register.
baos = ByteArrayOutputStream()
dos = DataOutputStream(baos)
# Read start address and quantity
dos.writeShort(0x2006)
dos.writeShort(1)
# Write start address and quantity
dos.writeShort(0x2006)
dos.writeShort(11)
# Write registers bytes to follow
dos.writeByte(22)
# Write registers
dos.writeShort(0x5753)
dos.writeShort(1)
dos.writeShort(5)
dos.writeFloat(654.321)
dos.writeFloat(123.456)
# Ensure data is in the byte stream
dos.flush()
rpcPayload = {'devName': 'P540Rack485', 'unit': 1, 'functionCode': 23, 'payload': baos.toByteArray(), 'responseLen': 3}
retv = system.util.sendRequest('ModbusTest', 'RawModbus', rpcPayload)
if isinstance(retv, QualifiedValue):
if retv.quality.good:
bais = ByteArrayInputStream(retv.value)
dis = DataInputStream(bais)
bCount = dis.readByte()
print "Bytes to follow=%d" % bCount
while bCount > 0:
bCount -= 2
register = dis.readShort()
print "Register = %d" % register
else:
print repr(retv)
else:
print retv
I donât actually have a device that accepts that function code, so I get a bad QV that indicates the function is unsupported. Testing from someone with such a device would be appreciated, of course.
If you wish to test with something more common, the following is a raw implementation of the common âread holding registersâ function 3:
from java.io import ByteArrayInputStream, ByteArrayOutputStream, DataInputStream, DataOutputStream
from com.inductiveautomation.ignition.common.model.values import QualifiedValue
# Raw implementation of read multiple registers, function 3.
# Start by constructing the payload of the Modbus PDU. It is
# a UINT starting address and a UINT number of registers (<=125).
baos = ByteArrayOutputStream()
dos = DataOutputStream(baos)
dos.writeShort(0)
dos.writeShort(5)
dos.flush()
rpcPayload = {'devName': 'P540Rack485', 'unit': 2, 'functionCode': 3, 'payload': baos.toByteArray(), 'responseLen': 11}
retv = system.util.sendRequest('ModbusTest', 'RawModbus', rpcPayload)
if isinstance(retv, QualifiedValue):
if retv.quality.good:
bais = ByteArrayInputStream(retv.value)
dis = DataInputStream(bais)
bCount = dis.readByte()
print "Bytes to follow=%d" % bCount
while bCount > 0:
bCount -= 2
register = dis.readShort()
print "Register = %d" % register
else:
print repr(retv)
else:
print retv
{ Edited to remove links. See below. }