Revision history for pyModbusTCP

0.4.0a4 2026-10-28 (alpha: the command line tools, their options and output, may still change before 0.4.0)

    Summary of the changes since 0.3.1 (0.4.0a1 to 0.4.0a3 included). The details are in the documentation
    (https://pymodbustcp.readthedocs.io/), the security choices in SECURITY.md.

    Breaking changes, client:

    - stricter argument checks: TypeError/ValueError instead of a silent conversion or truncation; the flags
      (auto_open, auto_close, tcp_no_delay, broadcast=) are bools only, an address, a count or an id is never a bool,
      coil values still accept integers.
    - ModbusClient(host=...) refuses the legacy IPv4 forms ("127.1", "192.168.010.1"...).
    - the arguments of ModbusClient after auto_close are keyword-only, no_delay is renamed tcp_no_delay.
    - the request methods use the same argument names: address, count, value, values (write_address, write_values,
      read_address, read_count for write_read_multiple_registers()); the old names (bit_addr=, reg_nb=...) raise
      TypeError.
    - an invalid reply (header, function code, size, echo or extra data that don't match the request) sets
      last_error to MB_FRAME_ERR, MB_RECV_ERR is a network error only.
    - a host name that can't be resolved sets last_error to MB_RESOLVE_ERR (it was MB_CONNECT_ERR).

    Breaking changes, server:

    - DataBank and DataHandler are replaced by a data store (MemoryStore), see "Migrating from DataBank and
      DataHandler" in the server guide.
    - secure defaults: idle_timeout (300 s), request_timeout (30 s), max_connections (128) and max_connections_per_host
      (16), None disables them; start() raises NetworkError if already running.
    - with max_connections reached, a new client takes the place of the most idle session (evict_idle=True,
      --no-evict-idle for the tools to refuse it instead).
    - the arguments of ModbusServer after no_block are keyword-only, no_block and ipv6 must be bools.
    - an empty host or a legacy IPv4 form ("0", "127.1"...) is refused, use '0.0.0.0' or '::' for every interface;
      a host given by name is resolved once by start(), and refused if it resolves to the wildcard address.
    - allowed_hosts is a tuple of str; in an allow list (allowed_hosts, AccessControl, -A/--allow), an entry with host
      bits set, a link-local entry or an entry with an interface is refused, an IPv4-mapped entry becomes IPv4.
    - the typed shortcuts of the store take a byte_order (ByteOrder, default ABCD) instead of big_endian.
    - a ModbusException subclass with a code out of 1 to 255 is refused at its definition (ValueError).
    - the check function of a Guard must return True to allow an access: any other value (None included) refuses it.

    Breaking changes, tools, utils and examples:

    - mbtcp-tcp2rtu and mbtcp-rtu2tcp relay only the standard data functions by default (the others get exception
      0x01), "--functions all" relays every function.
    - the short options mean the same thing in every tool: mbtcp-client -b/--byte-order becomes -B/--byte-order,
      mbtcp-rtu-scan -f/--function becomes -F/--function.
    - mbtcp-tcp2rtu gets -6/--ipv6 and --idle-timeout, like mbtcp-server; both refuse an IPv6 -H address without -6.
    - utils: word_list_to_long() raises ValueError when the number of words is not a multiple of 2 (4 with
      long_long).
    - examples: client_serial_gw.py and server_serial_gw.py are removed (replaced by the gateways of the tools),
      server_schedule.py no longer needs the schedule package.

    New features:

    - server: transactions (every request is atomic), access rules (ReadOnly, AccessControl, Guard), one store per unit
      id, read_only, allowed_hosts, ipv6_host_prefix; the settings are properties that apply at once to a running
      server. A space of MemoryStore can start at any address (MemoryStore(0, holding_registers=range(40_000,
      41_000)), MemoryStore.addresses()); a ChangeEvent gives the ranges written (writes) and the changes.
    - codec: Codec(DataType, ByteOrder) for 16/32/64 bits integers and IEEE floats, for the client and the store.
    - client: context manager, timeout for the whole request, broadcast (unit id 0), connect retries with backoff
      (connect_retries, connect_retry_delay).
    - tools: mbtcp-server, mbtcp-client, the gateways mbtcp-tcp2rtu and mbtcp-rtu2tcp (RS-485 mode, function filter,
      broadcasts) and mbtcp-rtu-scan (finds the serial settings and the address of RTU slaves), with
      "python -m pyModbusTCP.tools" or the commands of "pip install pyModbusTCP[cli]".
    - type hints on the whole package (py.typed), documentation rewritten, SECURITY.md.
    - DeviceIdentification(objects_id=) is renamed objects_by_id= (objects_id still works, with a DeprecationWarning).

    Fixes:

    - client: robustness (timeouts, invalid replies, transaction ids, is_open); a request reset while waiting for its
      reply is no longer sent again (the server may have executed it); a link-local IPv6 address needs its interface.
    - server: Modbus compliance (0x05, 0x0F, 0x10, 0x17, 0x2B/0x0E, MBAP length); a malformed request, a function
      code 0 or an invalid handler response gets an exception response, the session goes on; Request.reply() and
      unpack() keep the byte order of their format; read_only also refuses 0x15 and 0x16, a fallback handler only
      gets the read functions; a session evicted for a new client never processes the request it just received.
    - security: no port hijacking on Windows; the errors of user code are logged with a rate limit; the queue of the
      change events is bounded (MemoryStore.notify_queue_size and notify_queue_values); mbtcp-server --log-changes
      can't flood the log; no formula injection in the csv of mbtcp-client device-id.
    - tools: mbtcp-tcp2rtu never takes a late reply of a slave for the response of another request, shares the serial
      line fairly between the client hosts and never writes a malformed broadcast on the bus; mbtcp-rtu2tcp no
      longer blocks the serial line during a broadcast; stricter checks of the options.
    - codec: decode() refuses a register out of 0 to 65535; utils: valid_host() edge cases.

    Packaging: pyproject.toml with hatchling, Python 3.10 to 3.14; pyModbusTCP[cli]==X installs exactly
    pyModbusTCP-cli X, which requires exactly pyModbusTCP X. The files on PyPI come with their attestation (PEP 740).

0.4.0a3 2026-10-27 (alpha)

    See 0.4.0a4.

0.4.0a2 2026-10-17 (alpha)

    See 0.4.0a4.

0.4.0a1 2026-10-15 (alpha)

    See 0.4.0a4.

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.
