pymodbus-dev / pymodbus

A full modbus protocol written in python
Other
2.22k stars 907 forks source link

Serial Modbus v3.5.4, when error reading/writing: self.transport.close() has no attribute 'close' #1902

Closed bsense-rius closed 8 months ago

bsense-rius commented 9 months ago

Versions

Pymodbus Specific

Description

In the previous version 3.5.2, with AsyncModbusSerialClient, whenever an error occurred: slave not responding (e.g. incorrect address, timeout, ...) the library raised a ModbusException and everything was fine.

However in latest version 3.5.4, the very same code, under the same circumstances of error, the library returns what it seems to be an error: "2023-12-04 20:47:12.083 - INFO - ERROR! Exception catched: 'NoneType' object has no attribute 'close'"

The traceback helps to properly locate the point in the transport file

Code and Logs

# code and logs here.
"""Pymodbus asynchronous client example"""
import asyncio
import logging
import traceback
import pymodbus.client as modbusClient
from pymodbus.framer import ModbusRtuFramer
from pymodbus import pymodbus_apply_logging_config
from pymodbus import __version__ as pymodbusVersion

# Logging with custom formatter
logger      = logging.getLogger()
time_format = "%Y-%m-%d %H:%M:%S"
formatter   = logging.Formatter(fmt='%(asctime)s.%(msecs)03d - %(levelname)s - %(message)s', datefmt=time_format)
handler     = logging.StreamHandler()
handler.setFormatter(formatter)
logger.addHandler(handler)
#pymodbus_apply_logging_config("DEBUG")

# Set the log level (optional, can be DEBUG, INFO, WARNING, ERROR, CRITICAL)
logger.setLevel(logging.DEBUG)

def setup_async_client(description=None, cmdline=None):
    """Run client setup."""
    logger.info("### Create client object")

    client = modbusClient.AsyncModbusSerialClient(
        "/dev/ttyUSB0",
        # Common optional parameters:
        framer=ModbusRtuFramer,
        timeout=0.500,
        retries=0,
        retry_on_empty=False,

        # Other optional parameters:
        close_comm_on_error=False,
        strict=True,
        reconnect_delay=0.001,
        reconnect_delay_max=0.004,

        # Serial setup parameters
        baudrate=9600,
        #    bytesize=8,
        #    parity="N",
        #    stopbits=1,
        #    handle_local_echo=False,
    )
    return client

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

async def run_infinite_calls(client):
    """Test connection works."""
    while True:
        await asyncio.sleep(0.001)    # Device needs modbus idle for some time.
        try:
            resp = await client.read_discrete_inputs(0, 8, slave=0xf0)
            logger.info(f"Digital Inputs: {resp.bits}")
        except Exception as e:
            logger.info(f"ERROR! Exception catched: {e}")
            traceback.print_exc()
            pass

async def main(cmdline=None):
    """Combine setup and run."""
    logger.info(f"STARTING SERIAL COMM TESTER - PYMODBUS v{pymodbusVersion}")
    testclient = setup_async_client(description="Run client.", cmdline=cmdline)
    await run_async_client(testclient, modbus_calls=run_infinite_calls)

if __name__ == "__main__":
    asyncio.run(main(), debug=True)  # pragma: no cover

# LOGS
2023-12-04 21:22:58.332 - DEBUG - Using selector: EpollSelector
2023-12-04 21:22:58.334 - INFO - STARTING SERIAL COMM TESTER - PYMODBUS v3.5.4
2023-12-04 21:22:58.334 - INFO - ### Create client object
2023-12-04 21:22:58.334 - INFO - ### Client starting
2023-12-04 21:22:58.334 - DEBUG - Connecting to /dev/ttyUSB0.
2023-12-04 21:22:58.334 - DEBUG - Connecting comm
2023-12-04 21:22:58.337 - DEBUG - Connected to comm
2023-12-04 21:22:58.337 - DEBUG - callback_connected called
2023-12-04 21:22:58.339 - DEBUG - send: 0xf0 0x2 0x0 0x0 0x0 0x8 0x6c 0xed
2023-12-04 21:22:58.340 - DEBUG - Adding transaction 240
2023-12-04 21:22:58.361 - DEBUG - recv: 0xf0 old_data:  addr=None
2023-12-04 21:22:58.361 - DEBUG - Processing: 0xf0
2023-12-04 21:22:58.366 - DEBUG - Connection lost comm due to Server not responding
2023-12-04 21:22:58.367 - DEBUG - Connection lost comm due to None
2023-12-04 21:22:58.368 - DEBUG - Getting transaction 240
2023-12-04 21:22:58.368 - INFO - ERROR! Exception catched: 'NoneType' object has no attribute 'close'
Traceback (most recent call last):
  File "/home/smartvending/smartvending/test_read_DI.py", line 67, in run_infinite_calls
    resp = await client.read_discrete_inputs(0, 8, slave=0xf0)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/smartvending/smartvending/venv/lib/python3.11/site-packages/pymodbus/client/base.py", line 206, in async_execute
    self.close(reconnect=True)
  File "/home/smartvending/smartvending/venv/lib/python3.11/site-packages/pymodbus/client/base.py", line 153, in close
    self.connection_lost(asyncio.TimeoutError("Server not responding"))
  File "/home/smartvending/smartvending/venv/lib/python3.11/site-packages/pymodbus/transport/transport.py", line 300, in connection_lost
    self.transport_close(intern=True)
  File "/home/smartvending/smartvending/venv/lib/python3.11/site-packages/pymodbus/transport/transport.py", line 419, in transport_close
    self.transport.close()
    ^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'close'
janiversen commented 9 months ago

hmmm that looks like a bug, but I believe it is solved on dev.

bsense-rius commented 9 months ago

mmm. how could I manually install the develop version and try it? (just zip download from github and replace the pymodbus folder in venv, virtual environment folder?.

I will test asap and give you feedback

janiversen commented 9 months ago

download the zip from github and replace the folder should do it.

Thanks for testing.

alexrudd2 commented 9 months ago

Specifically here's what we think fixed it: https://github.com/pymodbus-dev/pymodbus/pull/1890

Regarding testing the development version, assuming you have git installed and are using pip: pip install git+https://github.com/pymodbus-dev/pymodbus@dev

janiversen commented 8 months ago

v3.6.2 solves this issue.