pymodbus-dev / pymodbus

A full modbus protocol written in python
Other
2.24k stars 913 forks source link

async client doesn't work #1453

Closed looninho closed 1 year ago

looninho commented 1 year ago

Versions

Pymodbus Specific

Description

I'm able to make communication in serial sync client mode but not in async mode. Please help me what I was missing.

Code and Logs

# code and logs here.
import asyncio
import logging

from pymodbus.client import AsyncModbusSerialClient
from pymodbus.framer.rtu_framer import ModbusRtuFramer
from pymodbus.pdu import ExceptionResponse

_logger = logging.getLogger()

async def run_async_client(client, modbus_calls=None):
    """Run sync client."""
    _logger.info("### Client starting")
    await client.connect()
    assert client.connected
    if modbus_calls:
        await modbus_calls(client)
    await client.close()
    _logger.info("### End of Program")

async def _handle_holding_registers(client):
    """Read/write holding registers."""
    _logger.info("### write holding register and read holding registers")
    rr = await client.read_holding_registers(0, 10, slave=1)
    return rr

async def run_async_calls(client):
    await _handle_holding_registers(client)

if __name__ == "__main__":
    client=AsyncModbusSerialClient(
        port="COM7", # /dev/ttyUSB0
        framer=ModbusRtuFramer,
        baudrate=115200,
        bytesize=8,
        parity="O",
        stopbits=1,
        strict=False                      
    )

    asyncio.run(run_async_client(client, modbus_calls=run_async_calls))

# please use the following to format logs when posting them here

pymodbus.pymodbus_apply_logging_config("Exception in callback SerialTransport._call_connection_lost(None)
handle: <Handle SerialTransport._call_connection_lost(None)>
Traceback (most recent call last):
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.2800.0_x64__qbz5n2kfra8p0\lib\asyncio\events.py", line 80, in _run
    self._context.run(self._callback, *self._args)
  File "E:\ws\6dof\6dof-env\lib\site-packages\pymodbus\client\serial_asyncio\__init__.py", line 427, in _call_connection_lost
    self._serial.flush()
AttributeError: 'NoneType' object has no attribute 'flush'")
janiversen commented 1 year ago

your code looks OK, you probably have another error hidden in the log, the problem is that AsyncModbusSerialClient could not create a transport (self._serial). And it seems you had connection but lost it.

Your log output is scrambled, you cannot call pymodbus_apply_logging_config, with the text string.

You need to a activate a proper debug log (as the issue asked you to do, when you created it). Without the proper debug log, I cannot tell you more.

looninho commented 1 year ago

Thank you @janiversen,

I test with this very simple code and it works for one time, the next call will return RuntimeError: Event loop is closed.

import asyncio

from pymodbus.client import AsyncModbusSerialClient
from pymodbus.framer.rtu_framer import ModbusRtuFramer
from pymodbus.pdu import ExceptionResponse

async def test (client):
    await client.connect()
    rr = await client.read_holding_registers(0,8,slave=1)
    return rr

client=AsyncModbusSerialClient(
    port="COM7", # /dev/ttyUSB0
    framer=ModbusRtuFramer,
    baudrate=115200,
    bytesize=8,
    parity="O",
    stopbits=1,
    strict=False
)

asyncio.run(test(client), debug=True)

So I comment the line await client.close() in run_async_client() and it works too.

BTW, what must I do to recall asyncio.run() without RuntimeError?