0

I'm using Modbus server example code from pymodbus library to make a data forwarder (reading some serial data, formatting and then assigning data to modbus registers for Modbus master to read). My issue is serial delay (reading from 6 different devices, each device has a 5 sec delay, but it's random, they not sending data at the same time). In this example they use LoopingCall, which is bad for my timing. How do I get rid of it, so I can call function myself?

I tried just to get rid of :

time = 2 # Update delay
loop = LoopingCall(f=updating_writer, a=(context,))
loop.start(time, now=False)

And simply call:

updating_writer()

But obviously I'm missing some arguments:

a=(context,)

Part of my code:

def data_decoder6():
    ser_read_JB1 = ser_JB6.read(386)
    if len(ser_read_JB1) != 0:
        # convert ascii to hex
        aTOh_JB1 = "".join("{:02x}".format(c) for c in ser_read_JB1)
        # convert to string
        iTOs_JB1 = str(aTOh_JB1)
        lokacija = [258,422,426,414,402,406,266,274,270,558,
                    530,534,538,322,326,330,334,338,342,346,
                    350,354,358,362,366,370,374,378,382,386,
                    390,394,398
                        ]
        values_JB1 = [0 for d in range(33)] 
        values_2_JB6 = [0 for e in range(33)]
        for x in range(0, 33):
            values_JB1[x] = (iTOs_JB1[lokacija[x]] + iTOs_JB1[lokacija[x]+1] 
                           + iTOs_JB1[lokacija[x]+2] + iTOs_JB1[lokacija[x]+3])
            #values1 = values.replace('"', '') 
            values_2_JB6[x] = int(values_JB1[x], 16)
            #values.append( 2009 )
        return values_2_JB6
    else:
    values_2_JB6 = [0 for e in range(33)]
    return values_2_JB6

def updating_writer(a):
    allValues = [0 for d in range(198)]
    allValues = (data_decoder1() + data_decoder2() + data_decoder3() + 
    data_decoder4() + data_decoder5() + data_decoder6())
    # modbus part
    log.debug("updating the context")
        context  = a[0]
        register = 0x03
        slave_id = 0x01
        address  = 0x01
        values   = context[slave_id].getValues(register, address, count=198)
        values   = allValues
        log.debug("new values: " + str(values))
        context[slave_id].setValues(register, address, values)

def run_updating_server():
    store = ModbusSlaveContext(
        di = ModbusSequentialDataBlock(0, [0]*1),
        co = ModbusSequentialDataBlock(0, [0]*1),
        hr = ModbusSequentialDataBlock(0, [0]*198),
        ir = ModbusSequentialDataBlock(0, [0]*1))

    context = ModbusServerContext(slaves=store, single=True)
    identity = ModbusDeviceIdentification()
    identity.VendorName  = 'pymodbus'
    identity.ProductCode = 'PM'
    identity.VendorUrl   = 'http://github.com/bashwork/pymodbus/'
    identity.ProductName = 'pymodbus Server'
    identity.ModelName   = 'pymodbus Server'
    identity.MajorMinorRevision = '1.0'

    time = 2 # Update delay
    loop = LoopingCall(f=updating_writer, a=(context,))
    loop.start(time, now=False)
    StartTcpServer(context, identity=identity, address=("10.10.10.253", 502))

run_updating_server()
Sanju
  • 1,974
  • 1
  • 18
  • 33
coddr
  • 29
  • 1
  • 5
  • Have a look at the [serial_forwarder](https://github.com/riptideio/pymodbus/blob/master/examples/contrib/serial_forwarder.py) example from pymodbus examples. It does what you are trying to achieve unless your down stream device is also modbus serial device (rtu/ascii). Otherwise I would suggest to use the update time greater than the read time out to get proper values. – Sanju May 23 '18 at 11:26

1 Answers1

0

This code

loop = LoopingCall(f=updating_writer, a=(context,))
loop.start(time, now=False)

causes

updating_writer(context)

every time seconds (with no call made immediately on the call to loop.start).

So, if you want to get rid of the LoopingCall, you can replace it with equivalent calls to updating_writer(context) scheduled however you prefer.

Jean-Paul Calderone
  • 47,755
  • 6
  • 94
  • 122