Hello,
thanks for the response.
So, if i understand you correctly, then a sync client or async client should both work on any modbus, but it is a matter of performance.
However, i am trying to make async client using asyncio and cannot make it work with my Sinotimer device, whilst the sync does work.
It seems to connect, then send the request (read_input_register) to the device, but it just hangs and goes nowhere.
I am using debian buster with pymodbus 2.1.0
I then tried the twisted async serial client example and managed to get it to work. So is something going wrong with asyncio?
Code snippet for asyncio:
METER = 0x1a # decimal 26
## start
async def start_async_test(client):
# ----------------------------------------------------------------------- #
# specify slave to query
# ----------------------------------------------------------------------- #
# The slave to query is specified in an optional parameter for each
# individual request. This can be done by specifying the `unit` parameter
# which defaults to `0x00`
# ----------------------------------------------------------------------- #
log.debug("Reading Meter Energy")
myresponse = await client.read_input_registers(0x0100, 2, unit=METER)
await asyncio.sleep(1)
if __name__ == '__main__':
# ----------------------------------------------------------------------- #
# For testing on linux based systems you can use socat to create serial
# ports
# ----------------------------------------------------------------------- #
# socat -d -d PTY,link=/tmp/ptyp0,raw,echo=0,ispeed=9600 PTY,
# link=/tmp/ttyp0,raw,echo=0,ospeed=9600
log.debug("First connect")
loop, client = ModbusClient(schedulers.ASYNC_IO, port="/dev/ttyUSB0",baudrate=9600, method="rtu", parity = 'E')
log.debug("After connect")
log.debug("start loop")
loop.run_until_complete(start_async_test(client.protocol))
log.debug("close loop")
loop.close()
###
Here is output:
2020-08-29 16:39:19,930 MainThread DEBUG async_test_simo:84 First connect
2020-08-29 16:39:19,937 MainThread DEBUG selector_events:53 Using selector: EpollSelector
2020-08-29 16:39:19,939 MainThread DEBUG __init__ :711 Connecting.
2020-08-29 16:39:19,958 MainThread DEBUG __init__ :94 Client connected to modbus server
2020-08-29 16:39:19,959 MainThread INFO __init__ :728 Protocol made connection.
2020-08-29 16:39:19,959 MainThread INFO __init__ :720 Connected to /dev/ttyUSB0
2020-08-29 16:39:19,959 MainThread DEBUG async_test_simo:86 After connect
2020-08-29 16:39:19,959 MainThread DEBUG async_test_simo:87 start loop
2020-08-29 16:39:19,960 MainThread DEBUG async_test_simo:59 Reading Meter Energy
2020-08-29 16:39:19,960 MainThread DEBUG __init__ :125 send: 0x1a 0x4 0x1 0x0 0x0 0x2 0x73 0xdc
2020-08-29 16:39:19,960 MainThread DEBUG transaction :418 Adding transaction 1
I then have to Ctrl+C to exit
Now the twisted snippet:
#####
SERIAL_PORT = "/dev/ttyUSB0"
STATUS_REGS = (0, 2)
STATUS_COILS = (1, 3)
CLIENT_DELAY = 1
UNIT = 0x1a
class ExampleProtocol(ModbusClientProtocol):
def __init__(self, framer):
""" Initializes our custom protocol
:param framer: The decoder to use to process messages
:param endpoint: The endpoint to send results to
"""
ModbusClientProtocol.__init__(self, framer)
log.debug("Beginning the processing loop")
reactor.callLater(CLIENT_DELAY, self.fetch_holding_registers)
def fetch_holding_registers(self):
""" Defer fetching holding registers
"""
log.debug("Starting the next cycle")
#d = self.read_holding_registers(*STATUS_REGS, unit=UNIT)
d = self.read_input_registers(0x100,2, unit=UNIT)
#d.addCallbacks(self.send_holding_registers, self.error_handler)
d.addCallbacks(self.start_next_cycle, self.error_handler)
def start_next_cycle(self, response):
""" Write values of coils, trigger next cycle
:param response: The response to process
"""
log.info(response.getRegister(0))
log.info(response.getRegister(1))
decoder = BinaryPayloadDecoder.fromRegisters(response.registers,byteorder=Endian.Big)
# round to 2 decimals
log.info(round(decoder.decode_32bit_float(),2))
# repeat reads
#reactor.callLater(CLIENT_DELAY, self.fetch_holding_registers)
# stop
#reactor.callLater(1, client.transport.loseConnection) # find serial closing?
reactor.callLater(2, reactor.stop)
if __name__ == "__main__":
proto, client = AsyncModbusSerialClient(schedulers.REACTOR,
method="rtu",
port=SERIAL_PORT,
timeout=2, parity = 'E',
proto_cls=ExampleProtocol)
proto.start()
#proto.stop()
#####
And the output:
DEBUG:pymodbus.client.asynchronous.serial:SK pre-factory
DEBUG:pymodbus.client.asynchronous.serial:SK after-factory
DEBUG:pymodbus:Beginning the processing loop
DEBUG:pymodbus.client.asynchronous.twisted:Client connected to modbus server
DEBUG:pymodbus.client.asynchronous.serial:SK after yieldable
INFO:pymodbus.client.asynchronous.thread:Starting Event Loop: 'PyModbus_reactor'
DEBUG:pymodbus:Starting the next cycle
DEBUG:pymodbus.client.asynchronous.twisted:send: 0x1a 0x4 0x1 0x0 0x0 0x2 0x73 0xdc
DEBUG:pymodbus.transaction:Adding transaction 1
DEBUG:pymodbus.framer.rtu_framer:Getting Frame - 0x4 0x4 0x41 0xf1 0xbd 0x71
DEBUG:pymodbus.factory:Factory Response[ReadInputRegistersResponse: 4]
DEBUG:pymodbus.framer.rtu_framer:Frame advanced, resetting header!!
INFO:pymodbus:16881
INFO:pymodbus:48497
DEBUG:pymodbus.payload:[16881, 48497]
DEBUG:pymodbus.payload:[b'A\xf1', b'\xbdq']
INFO:pymodbus:30.22
###
As you can see, i get the two bytes back and i convert to float and get correct value "30.22".
You can see the hex string sent in both examples is identical.
Any ideas what is wrong with asyncio version?
thanks,
Simon