Revision history for pyModbusTCP

0.4.0a1 xxxx-xx-xx (alpha: the command line tools, their options and output, may still change before 0.4.0)

    Breaking changes:

    - DataBank: remove deprecated class methods (get_bits, set_bits, get_words and set_words).
    - DataBank: set_*() methods raise a TypeError on non-integer items and a ValueError on registers values out of
                the 0-65535 range (values were silently converted before, see below).
    - ModbusClient: non-integer arguments raise a TypeError, custom_request() checks its pdu argument
                    (TypeError/ValueError) and auto_open, auto_close and no_delay only accept bool or int values.
    - ModbusClient: the function code of a reply must match the request (or with the exception flag), else the
                    request fails with MB_RECV_ERR (this also applies to custom_request()).
    - ModbusServer: idle_timeout (300 s) and max_connections (64) are active by default: an idle client session is
                    closed after 5 min (its next request fails once, then the client reconnects), set them to None
                    to get the previous behavior.
    - ModbusServer: start() raises a NetworkError if the server is already running (the call was silently ignored).
    - ModbusServer: the internal request handler class ModbusService is replaced by ModbusRequestHandler and
                    CustomThreadingTCPServer, is_run is deprecated (use is_running).
    - examples: client_serial_gw.py and server_serial_gw.py are removed, replaced by the gateways of
                pyModbusTCP.tools ("python -m pyModbusTCP.tools tcp2rtu/rtu2tcp", or the commands mbtcp-tcp2rtu and
                mbtcp-rtu2tcp of pyModbusTCP-cli).

    Changes:

    - docs: README.rst converted to Markdown (README.md), like the other docs of the repository.
    - docs: Sphinx documentation rewritten: up to date quick start, user guides for the client (connection, errors,
      threads), the server (data bank, change callbacks, custom handler, access restrictions) and the data conversion
      functions, new pages for the command line tools (with their generated --help), the security policy, the
      changelog and the constants, every example documented. tools/build_docs.sh builds it (HTML, PDF...) in a
      temporary venv, the docs build is checked by the CI (warnings are errors).
    - pyModbusTCP.client and pyModbusTCP.server are now packages (one module per concern: main class, Modbus
      functions, TCP layer, argument checks...) with the same layout for both. No change for the users: same
      imports, same logger names, nested names kept (ModbusServer.PDU, ModbusServer.NetworkError...). Exceptions
      of the server are now shown as pyModbusTCP.server.errors.NetworkError (and so on) in tracebacks.
    - new module pyModbusTCP.tools: command line tools (Modbus/TCP server and client, TCP to RTU and RTU to TCP
      gateways), run them with "python -m pyModbusTCP.tools {server,client,tcp2rtu,rtu2tcp}". The gateways need
      pyserial, a new optional dependency: "pip install pyModbusTCP[serial]".
    - new package pyModbusTCP-cli (directory of the same name, no code): installs the tools as the commands
      mbtcp-server, mbtcp-client, mbtcp-tcp2rtu and mbtcp-rtu2tcp, with pyserial. Install it with
      "pip install pyModbusTCP[tools]" or "pipx install pyModbusTCP-cli". A plain "pip install pyModbusTCP" puts
      no command in the PATH and still has no dependency.
    - build: migrate from setup.py to pyproject.toml, with the hatchling build backend (no more MANIFEST.in, tests are
      no longer in the sdist).
    - fix ModbusClient: is_open is now False only for a closed socket (file descriptor 0 is valid).
    - fix ModbusClient: non-integer arguments (float, str...) now raise a TypeError instead of an uncaught struct.error.
    - fix ModbusClient: treat socket.gaierror as MB_CONNECT_ERR (like any other connect error).
    - fix ModbusClient: timeout is now a limit for the whole request (send + receive) and no more for each socket I/O. A
                        server sending its response byte by byte could hold the client much longer than timeout.
    - fix ModbusClient: validate write_multiple_coils items to reject non-integer values (like 'a', None, [], 1.5),
                        matching write_single_coil behavior.
    - fix ModbusClient: write_multiple_coils() and write_multiple_registers() now set last_error (MB_RECV_ERR) when the
                        server reply does not match the request, they returned False with last_error == MB_NO_ERR.
    - fix ModbusClient: close the connection on an invalid MBAP header in a reply (the stream can't be trusted).
    - fix ModbusClient: use an incremental MBAP transaction ID (from a random start value) instead of a random one at
                        each request, a late reply to the previous request is always detected.
    - fix ModbusClient: avoid an AttributeError in __del__() when __init__() fails.
    - fix ModbusServer: close the session on send timeout (a partial send leaves the TCP stream out of sync).
    - fix ModbusServer.PDU: is_valid property was inverted.
    - fix ModbusServer: an unexpected exception during a request (like one raised by a user callback) is now logged and
                        answered with a SLAVE_DEVICE_FAILURE (0x04) exception instead of dropping the TCP session.
    - fix ModbusServer: a malformed request PDU (too short...) is answered with ILLEGAL DATA VALUE (0x03) and a request
                        with a function code >= 0x80 with ILLEGAL FUNCTION (0x01), the session was closed before.
    - fix ModbusServer: a data handler that returns a wrong number of items gets a SLAVE_DEVICE_FAILURE (0x04).
    - fix ModbusServer: start() no longer modifies class attributes of socketserver, since ThreadingTCPServer can be
                        shared with the rest of the process.
    - fix ModbusServer: close the listening socket when start() fails to bind.
    - fix ModbusServer: make function Write/Read Multiple Registers (0x17) atomic to prevent writing when the read range
                        is out of bounds.
    - fix ModbusServer: ensure Write Single Coil (0x05) complies fully with the Modbus specification.
    - fix ModbusServer: for functions 0x0F, 0x10 and 0x17 the byte count must exactly match the quantity.
    - fix ModbusServer: Read Device Identification (0x2B/0x0E) compliance with the spec (stream access restarts at the
                        first object of the category, an unknown object in individual access gets exception 0x02).
    - fix ModbusServer: support MBAP header length from 2 to 253.
    - fix ModbusServer: limit client info to (address, port) for IPv6 peers.
    - fix DataBank: set_coils(), set_discrete_inputs(), set_holding_registers() and set_input_registers() now check
                    their input. Non-integer items (float, str, None...) raise a TypeError (numpy integers and
                    booleans are accepted), and register values out of the 0-65535 range raise a ValueError.
                    Before, they were silently converted (a value like 70000 or -1 was truncated to 16 bits).
    - fix utils: valid_host() returns False for an empty host or a host with a NUL char, it raised an IndexError or a
                 ValueError (so ModbusClient(host='') raised an IndexError instead of a ValueError).
    - improve ModbusClient: decode/encode registers and bits in one pass (faster reads and writes).
    - improve ModbusClient: set TCP_NODELAY on connect (new no_delay argument, on by default) to reduce latency on small
                            request/response frames.
    - improve ModbusClient: improve socket lifecycle, parameter validation, and timeout safety.
    - improve ModbusClient: add context manager support (with ModbusClient(...) as c:), closes the connection on exit.
    - improve ModbusServer: decode/encode registers and bits in one pass for requests 0x01, 0x02, 0x0F, 0x10 and 0x17
                            (like the client), instead of one Python loop iteration per bit or register.
    - improve ModbusServer: stop() is now faster, the main loop polls the stop request every 50 ms instead of 500 ms.
    - improve ModbusServer: stop() now closes the active sessions and waits for the server thread.
    - improve ModbusServer: add request_timeout (default 30 s): a client session with a stalled request (incomplete MBAP
                            header or PDU) is now closed, it was kept (with its thread) until the client closed it.
                            Set request_timeout=None to get the previous behavior.
    - improve ModbusServer: add idle_timeout (close a session without any request for this time, default 300 s) and
                            max_connections (reject connections over this limit, default 64), None disables them.
    - improve ModbusServer: add allowed_hosts (whitelist of client IP addresses or networks, CIDR notation) and
                            read_only (refuse the write functions 0x05, 0x06, 0x0F, 0x10 and 0x17), see SECURITY.md.
    - improve ModbusServer: increase the listen backlog from 5 to 128, a burst of simultaneous connections (like clients
                            reconnecting together) no longer waits for a TCP retransmission (1 s or more).
    - improve ModbusServer: allow dynamic TCP port allocation (port=0), start() returns the bound (host, port).
    - improve ModbusServer: add is_running, wait(), active_sessions and shutdown_sessions().
    - improve ModbusServer: an exception raised by an external engine (ext_engine) is logged and closes the session.
    - improve DataBank: set_coils() and set_holding_registers() now compare the whole slice before writing, and
                        only build the list of changes when a server request needs it for the on_*_change()
                        callbacks. Writing unchanged values is much faster.
    - improve DeviceIdentification: support the "in" operator, an object value over 244 bytes raises a ValueError.
    - improve typing: type hints on the whole package and add py.typed (PEP 561).
    - add SECURITY.md (threat model, deployment recommendations, server and client protections).
    - add tools/ (benchmark, server fuzzing, code audit) and init_dev_venv.sh (test and build venv).
    - examples: add server_dynamic_port.py, add type hints to examples.

0.3.1 2026-09-29

    - fix ModbusServer: debug messages now include OSError exceptions produced by getpeername (thanks to Pär Åhlund).
    - fix ModbusClient: prevent incomplete frame transmission by using sendall (thanks to aamir-azeez).
    - updated compatibility test (python versions): remove 3.8/3.9, add 3.13/3.14.

0.3.0 2024-09-04

    - pyModbusTCP.client: now use the standard logging method as in the server part.
    - ModbusClient: debug flag is removed (see examples/client_debug.py).

0.2.2 2024-07-31

    - fix ModbusServer: wrong check of discrete inputs length in DataBank (thanks to OTnetproj).
    - updated compatibility test (python versions): remove 3.7, add 3.12.

0.2.1 2023-11-21

    - fix ModbusServer: wrong check of input registers length in DataBank (thanks to monsieurvor).
    - improve hostname validation in utils (thanks to MCXIV and schmocker).
    - experimental add of read_device_identification() (over modbus encapsulated interface) to client and server.
    - experimental add of write_read_multiple_registers() function (code 0x17) to client and server (thanks to tanj).
    - updated compatibility test (python versions): remove 3.5/3.6, add 3.11.

0.2.0 2022-06-05

    - ModbusClient: parameters are now properties instead of methods (more intuitive).
    - ModbusClient: now TCP auto open mode is active by default (auto_open=True, auto_close=False).
    - ModbusClient: add custom_request method for send user define PDU to modbus server.
    - ModbusClient: remove RTU mode.
    - ModbusClient: clarify some things (private methods and internal vars rename).
    - ModbusServer: big redesign to improve readability and maintainability.
    - ModbusServer: no longer use hard linked class DataBank (it now return a deprecation warn).
    - ModbusServer: add of ModbusServerDataHandler and DefaultDataBank class for easy customize.
    - add or update server examples for new modbus server design.
    - some updates on tests, fix random arrays generation on client test part.
    - clarify usage of root privilege for open tcp/502 (avoid Errno 13) in server example.
    - python 2 end of support.

0.1.10 2021-03-02

    - word_list_to_long() and long_list_to_word(), now support 64 bits long long with opt long_long.
    - encode_ieee() and decode_ieee(), now support double-precision format with opt double.
    - add shortcut alias for functions with long names in utils.
    - rewrite of some functions in utils.
    - improve test_utils readability.
    - server DataBank enforce type check on set data methods to avoid server crash (thanks to xuantw).
    - now get_2comp can deal with negative python int.
    - remove reference to devel github branch.
    - improve last_error_txt() and last_except_txt().

0.1.9 2021-02-26

    - add module error MB_SOCK_CLOSE_ERR (occur if frame send on close socket).
    - add modbus exception EXP_NEGATIVE_ACKNOWLEDGE (code 0x07) to constants.
    - add last_error_txt() and last_except_txt() for produce human readable status.
    - add EXP_TXT, EXP_DETAILS and MB_ERR_TXT dicts to constants (text representation of codes).
    - update of the compatibility test for python version: remove 2.6/3.2/3.3, add 3.7/3.8/3.9.
    - conform to PEP 396 (add pyModbusTCP.__version__ field).

0.1.8 2018-10-15

    - fix ModbusServer: avoid hard coded TCP port (thanks to akobyl).
    - add stop() and is_run property to ModbusServer (thanks to Rugiewitz).

0.1.7 2018-08-20

    - fix ModbusServer issue on Windows (thanks to andreascian).

0.1.6 2018-05-14

    - fix multiple TCP packets recv issue in ModbusClient and ModbusServer (thanks Farin94).

0.1.5 2017-11-23

    - add long_list_to_word to utils.
    - add float support as example.

0.1.4 2017-11-13

    - fix port and host accessors, change check now use "==" and not "is".

0.1.3 2017-09-29

    - setup now use setuptools.

0.1.2 2017-09-28

    - fix 'Rx' label on error.
    - change file mode for server.py example.
    - fix compatibility with modbus unit_id = 0 (thanks to mfkenney).
    - fix compatibility for modbus frame with garbage.

0.1.1 2016-05-30

    - add toggle_bit() to utils.
    - add server.py example.
    - add HOWTO for safe PyPI upload.

0.1.0 2016-05-30

    - fix some issues in PEP 8 conformance and inline doc.
    - client modbus RTU: move crc16 compute to utils.
    - add write_multiple_coils() function (code 0x0f).
    - add test_bit(), set_bit(), reset_bit() to utils.
    - add a modbus/TCP multithreaded server through ModbusServer class (for test only).

0.0.13 2015-12-24

    - add auto_open and auto_close to README.rst and quickstart doc.
    - add example min_read_bit.py for show minimal code approach.

0.0.12 2015-12-11

    - add auto_open and auto_close mode to ModbusClient.
    - add accessor function for socket timeout.
    - close TCP socket if hostname change
    - close TCP socket if port change

0.0.11 2015-03-27

    - fix sock.settimeout missing (thanks to bonaime).
    - fix PEP 8 style (thanks to bonaime).

0.0.10 2015-01-22

    - Add timeout parameter to ModbusClient constructor (thanks to bonaime).

0.0.9 2014-10-10

    - Fix rx_byte_count check in ModbusClient class.

0.0.8 2014-09-23

    - Catch excepts on socket send/recv.
    - Sphinx documentation include a quickstart and examples.

0.0.7 2014-08-31

    - Add unit test (see test/).
    - Add params host/port/unit_id/debug on ModbusClient constructor.
    - Add utils module for modbus data mangling.

0.0.6 2014-08-25

    - Fix "socket error" message when call open() on dual stack IPv6/4 host.
    - Check rx byte count field in functions 1 to 4.
    - Fix max bit number problem in functions 1 and 2 (from 125 to 2000).
    - Add debug message, if _send() call on close socket.
    - Rename module name from const to constants.
    - Update MANIFEST.in to remove docs and examples from sdist archive.
    - Update README.rst sample code for Python3.

0.0.5 2014-08-08

    - Now deal with IPv6 host.
    - Fix Python3 issue in _crc().
    - Improve modbus RTU receive code.
    - Secure frame size before struct.unpack invocation.

0.0.4 2014-08-07

    - Add class documentation (add doc/ and sphinx/ directory).
    - Add sphinx docstring in client.py.

0.0.3 2014-08-05

    - Fix padding problem in write_single_coil().
    - Add new examples.

0.0.2 2014-08-05

    - Compatibility with Python 3 and 2.7.
    - Use RST format for README instead of markdown, now set long_description.
    - Add a MANIFEST.in file and include examples/ on sdist.

0.0.1 2014-08-04

    - First release of pyModbusTCP.
