diff --git a/API_changes.rst b/API_changes.rst index aa3630014..e1727fa10 100644 --- a/API_changes.rst +++ b/API_changes.rst @@ -2,13 +2,15 @@ API changes =========== Versions (X.Y.Z) where Z > 0 e.g. 3.0.1 do NOT have API changes! ------------------ -API changes 3.9.0 +API changes 4.0.0 ----------------- - Python 3.9 is reaching end of life, and no longer supported. Depending on the usage the code might still work -- Start*Server, custom_functions -> custom_pdu (handled by ModbusServer) -- payload removed (replaced by "convert_combined_to/from_registers") +- Start*Server, custom_functions is now custom_pdu (handled by ModbusServer) +- ModbusSlaveContext replaced by ModbusDeviceContext +- payload removed (replaced by "convert_to/from_registers") +- slave=, slaves= replaced by device_id=, device_ids= +- slave request names changed to device API changes 3.8.0 ----------------- diff --git a/doc/index.rst b/doc/index.rst index 92678510f..78c64cc6f 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -8,6 +8,7 @@ Please select a topic in the left hand column. :caption: Contents: :hidden: + source/upgrade_40 source/api_changes source/client source/server diff --git a/doc/source/_static/examples.tgz b/doc/source/_static/examples.tgz index 0c6bb7a14..3c1f328df 100644 Binary files a/doc/source/_static/examples.tgz and b/doc/source/_static/examples.tgz differ diff --git a/doc/source/_static/examples.zip b/doc/source/_static/examples.zip index 14eac6857..dbe97d851 100644 Binary files a/doc/source/_static/examples.zip and b/doc/source/_static/examples.zip differ diff --git a/doc/source/client.rst b/doc/source/client.rst index 57adceaa3..354c32b8a 100644 --- a/doc/source/client.rst +++ b/doc/source/client.rst @@ -127,12 +127,12 @@ Synchronous example from pymodbus.client import ModbusTcpClient - client = ModbusTcpClient('MyDevice.lan') # Create client object - client.connect() # connect to device - client.write_coil(1, True, slave=1) # set information in device - result = client.read_coils(2, 3, slave=1) # get information from device - print(result.bits[0]) # use information - client.close() # Disconnect device + client = ModbusTcpClient('MyDevice.lan') # Create client object + client.connect() # connect to device + client.write_coil(1, True, device_id=1) # set information in device + result = client.read_coils(2, 3, device_id=1) # get information from device + print(result.bits[0]) # use information + client.close() # Disconnect device The line :mod:`client.connect()` connects to the device (or comm port). If this cannot connect successfully within the timeout it throws an exception. After this initial connection, further @@ -147,12 +147,12 @@ Asynchronous example from pymodbus.client import AsyncModbusTcpClient - client = AsyncModbusTcpClient('MyDevice.lan') # Create client object - await client.connect() # connect to device, reconnect automatically - await client.write_coil(1, True, slave=1) # set information in device - result = await client.read_coils(2, 3, slave=1) # get information from device - print(result.bits[0]) # use information - client.close() # Disconnect device + client = AsyncModbusTcpClient('MyDevice.lan') # Create client object + await client.connect() # connect to device, reconnect automatically + await client.write_coil(1, True, device_id=1) # set information in device + result = await client.read_coils(2, 3, device_id=1) # get information from device + print(result.bits[0]) # use information + client.close() # Disconnect device The line :mod:`client = AsyncModbusTcpClient('MyDevice.lan')` only creates the object; it does not activate anything. @@ -160,9 +160,9 @@ anything. The line :mod:`await client.connect()` connects to the device (or comm port), if this cannot connect successfully within the timeout it throws an exception. If connected successfully reconnecting later is handled automatically -The line :mod:`await client.write_coil(1, True, slave=1)` is an example of a write request, set address 1 to True on device 1 (slave). +The line :mod:`await client.write_coil(1, True, device_id=1)` is an example of a write request, set address 1 to True on device 1. -The line :mod:`result = await client.read_coils(2, 3, slave=1)` is an example of a read request, get the value of address 2, 3 and 4 (count = 3) from device 1 (slave). +The line :mod:`result = await client.read_coils(2, 3, device_id=1)` is an example of a read request, get the value of address 2, 3 and 4 (count = 3) from device 1. The last line :mod:`client.close()` closes the connection and render the object inactive. @@ -194,13 +194,13 @@ Client device addressing ------------------------ With **TCP**, **TLS** and **UDP**, the tcp/ip address of the physical device is defined when creating the object. -Logical devices represented by the device is addressed with the :mod:`slave=` parameter. +Logical devices represented by the device is addressed with the :mod:`device_id=` parameter. With **Serial**, the comm port is defined when creating the object. -The physical devices are addressed with the :mod:`slave=` parameter. +The physical devices are addressed with the :mod:`device_id=` parameter. -:mod:`slave=0` is defined as broadcast in the modbus standard, but pymodbus treats it as a normal device. -please note :mod:`slave=0` can only be used to address devices that truly have id=0 ! Using :mod:`slave=0` to +:mod:`device_id=0` is defined as broadcast in the modbus standard, but pymodbus treats it as a normal device. +please note :mod:`device_id=0` can only be used to address devices that truly have id=0 ! Using :mod:`device_id=0` to address a single device with id not 0 is against the protocol. If an application is expecting multiple responses to a broadcast request, it must call :mod:`client.execute` and deal with the responses. @@ -217,7 +217,7 @@ All simple request calls (mixin) return a unified result independent whether it The application should evaluate the result generically:: try: - rr = await client.read_coils(1, 1, slave=1) + rr = await client.read_coils(1, 1, device_id=1) except ModbusException as exc: _logger.error(f"ERROR: exception in pymodbus {exc}") raise exc diff --git a/doc/source/library/datastore.rst b/doc/source/library/datastore.rst index 3c1b570d7..01e1cdd1a 100644 --- a/doc/source/library/datastore.rst +++ b/doc/source/library/datastore.rst @@ -11,7 +11,7 @@ Datastore classes :members: :member-order: bysource -.. autoclass:: pymodbus.datastore.ModbusSlaveContext +.. autoclass:: pymodbus.datastore.ModbusDeviceContext :members: :member-order: bysource diff --git a/doc/source/library/simulator/calls_response.rst b/doc/source/library/simulator/calls_response.rst index 51b89ae17..cdca917e2 100644 --- a/doc/source/library/simulator/calls_response.rst +++ b/doc/source/library/simulator/calls_response.rst @@ -72,7 +72,7 @@ }, { "value": 17, - "text": "report_slave_id", + "text": "report_device_id", "selected": false }, { @@ -131,7 +131,7 @@ }, { "value": 4, - "text": "SLAVE_FAILURE", + "text": "DEVICE_FAILURE", "selected": false }, { @@ -141,7 +141,7 @@ }, { "value": 6, - "text": "SLAVE_BUSY", + "text": "DEVICE_BUSY", "selected": false }, { @@ -164,4 +164,4 @@ "call_rows": [], "foot": "not active", "result": "ok" - } \ No newline at end of file + } diff --git a/doc/source/library/simulator/config.rst b/doc/source/library/simulator/config.rst index 918ba3049..9cf695f04 100644 --- a/doc/source/library/simulator/config.rst +++ b/doc/source/library/simulator/config.rst @@ -87,7 +87,7 @@ Server configuration examples "comm": "tcp", "host": "0.0.0.0", "port": 5020, - "ignore_missing_slaves": false, + "ignore_missing_devices": false, "framer": "socket", "identity": { "VendorName": "pymodbus", @@ -123,7 +123,7 @@ Server configuration examples "port": 5020, "certfile": "certificates/pymodbus.crt", "keyfile": "certificates/pymodbus.key", - "ignore_missing_slaves": false, + "ignore_missing_devices": false, "framer": "tls", "identity": { "VendorName": "pymodbus", @@ -138,7 +138,7 @@ Server configuration examples "comm": "udp", "host": "0.0.0.0", "port": 5020, - "ignore_missing_slaves": false, + "ignore_missing_devices": false, "framer": "socket", "identity": { "VendorName": "pymodbus", diff --git a/doc/source/roadmap.rst b/doc/source/roadmap.rst index 1a1cfb1fc..01cc6b470 100644 --- a/doc/source/roadmap.rst +++ b/doc/source/roadmap.rst @@ -20,12 +20,11 @@ The following bullet points are what the maintainers focus on: - 4.0.0, with: - Simulator datastore, with simple configuration - Remove remote_datastore - - Remove BinaryPayload - Server becomes Simulator - client async with sync/async API - Only one datastore, but with different API`s - 4.1.0, with: - - ModbusControlBlock pr slave + - ModbusControlBlock pr device - New custom PDU (function codes) - New serial forwarder - GUI client, to analyze devices diff --git a/doc/source/upgrade_40.rst b/doc/source/upgrade_40.rst new file mode 100644 index 000000000..5036a1299 --- /dev/null +++ b/doc/source/upgrade_40.rst @@ -0,0 +1,47 @@ +Pymodbus 4.0 upgrade procedure +============================== + +Pymodbus 4.0 contains a number of incompatibilities with Pymodbus 3.x, however +most of these are simple edits. + +Python 3.9 +---------- +Python 3.9 is reaching end of life and from october 2025 no longer receives security updates. + +Pymodbus starting with v4.0 start using python 3.10 features, and thus users need to update to +at least python v3.10 + +Users that cannot upgrade the python version, should not upgrade pymodbus to v4.X + + +StartServer +-------------- +custom_funcion= is changed to custom_pdu= and is handled by ModbusServer. + + +payload classes removed +----------------------- +Please replace by result.convert_from_registers() and/or convert_to_registers() + + +Simple replacements +------------------- + +please replace +- slave= with device_id= +- slaves= with device_ids= +- ModbusServerContext(slaves=) with ModbusServerContext(devices=) + +please rename +- ModbusSlaveContext to ModbusDeviceContext +- RemoteSlaveContext to RemoteDeviceContext +- report_slave_id() with report_device_id() +- diag_read_slave_message_count with diag_read_device_message_count +- diag_read_slave_no_response_count with diag_read_device_no_response_count +- diag_read_slave_nak_count with diag_read_device_nak_count +- diag_read_slave_busy_count with diag_read_device_busy_count +- ReturnSlaveMessageCountRequest with ReturnDeviceMessageCountRequest +- ReturnSlaveNoResponseCountRequest with ReturnDeviceNoResponseCountRequest +- ReturnSlaveNAKCountRequest with ReturnDeviceNAKCountRequest +- ReturnSlaveBusyCountRequest with ReturnDeviceBusyCountRequest +- ReturnSlaveBusCharacterOverrunCountRequest with ReturnDeviceBusCharacterOverrunCountRequest diff --git a/examples/client_async.py b/examples/client_async.py index e59a75ca6..3aab14949 100755 --- a/examples/client_async.py +++ b/examples/client_async.py @@ -125,9 +125,9 @@ async def run_async_client(client, modbus_calls=None): async def run_a_few_calls(client): """Test connection works.""" - rr = await client.read_coils(32, count=1, slave=1) + rr = await client.read_coils(32, count=1, device_id=1) assert len(rr.bits) == 8 - rr = await client.read_holding_registers(4, count=2, slave=1) + rr = await client.read_holding_registers(4, count=2, device_id=1) assert rr.registers[0] == 17 assert rr.registers[1] == 17 diff --git a/examples/client_async_calls.py b/examples/client_async_calls.py index 80f6abc5b..b5623ef3d 100755 --- a/examples/client_async_calls.py +++ b/examples/client_async_calls.py @@ -50,7 +50,7 @@ _logger.setLevel("DEBUG") -SLAVE = 0x01 +DEVICE_ID = 0x01 # -------------------------------------------------- @@ -60,7 +60,7 @@ async def async_template_call(client): """Show complete modbus call, async version.""" try: - rr = await client.read_coils(1, count=1, slave=SLAVE) + rr = await client.read_coils(1, count=1, device_id=DEVICE_ID) except ModbusException as exc: txt = f"ERROR: exception in pymodbus {exc}" _logger.error(txt) @@ -81,30 +81,30 @@ async def async_template_call(client): async def async_handle_coils(client): """Read/Write coils.""" _logger.info("### Reading Coil different number of bits (return 8 bits multiples)") - rr = await client.read_coils(1, count=1, slave=SLAVE) + rr = await client.read_coils(1, count=1, device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert len(rr.bits) == 8 - rr = await client.read_coils(1, count=5, slave=SLAVE) + rr = await client.read_coils(1, count=5, device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert len(rr.bits) == 8 - rr = await client.read_coils(1, count=12, slave=SLAVE) + rr = await client.read_coils(1, count=12, device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert len(rr.bits) == 16 - rr = await client.read_coils(1, count=17, slave=SLAVE) + rr = await client.read_coils(1, count=17, device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert len(rr.bits) == 24 _logger.info("### Write false/true to coils and read to verify") - await client.write_coil(0, True, slave=SLAVE) - rr = await client.read_coils(0, count=1, slave=SLAVE) + await client.write_coil(0, True, device_id=DEVICE_ID) + rr = await client.read_coils(0, count=1, device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert rr.bits[0] # test the expected value - await client.write_coils(1, [True] * 21, slave=SLAVE) - rr = await client.read_coils(1, count=21, slave=SLAVE) + await client.write_coils(1, [True] * 21, device_id=DEVICE_ID) + rr = await client.read_coils(1, count=21, device_id=DEVICE_ID) assert not rr.isError() # test that call was OK resp = [True] * 21 # If the returned output quantity is not a multiple of eight, @@ -114,8 +114,8 @@ async def async_handle_coils(client): assert rr.bits == resp # test the expected value _logger.info("### Write False to address 1-8 coils") - await client.write_coils(1, [False] * 8, slave=SLAVE) - rr = await client.read_coils(1, count=8, slave=SLAVE) + await client.write_coils(1, [False] * 8, device_id=DEVICE_ID) + rr = await client.read_coils(1, count=8, device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert rr.bits == [False] * 8 # test the expected value @@ -123,7 +123,7 @@ async def async_handle_coils(client): async def async_handle_discrete_input(client): """Read discrete inputs.""" _logger.info("### Reading discrete input, Read address:0-7") - rr = await client.read_discrete_inputs(0, count=8, slave=SLAVE) + rr = await client.read_discrete_inputs(0, count=8, device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert len(rr.bits) == 8 @@ -131,25 +131,25 @@ async def async_handle_discrete_input(client): async def async_handle_holding_registers(client): """Read/write holding registers.""" _logger.info("### write holding register and read holding registers") - await client.write_register(1, 10, slave=SLAVE) - rr = await client.read_holding_registers(1, count=1, slave=SLAVE) + await client.write_register(1, 10, device_id=DEVICE_ID) + rr = await client.read_holding_registers(1, count=1, device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert rr.registers[0] == 10 - await client.write_registers(1, [10] * 8, slave=SLAVE) - rr = await client.read_holding_registers(1, count=8, slave=SLAVE) + await client.write_registers(1, [10] * 8, device_id=DEVICE_ID) + rr = await client.read_holding_registers(1, count=8, device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert rr.registers == [10] * 8 - await client.write_registers(1, [10], slave=SLAVE) - rr = await client.read_holding_registers(1, count=1, slave=SLAVE) + await client.write_registers(1, [10], device_id=DEVICE_ID) + rr = await client.read_holding_registers(1, count=1, device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert rr.registers == [10] value_int32 = 13211 registers = client.convert_to_registers(value_int32, client.DATATYPE.INT32) - await client.write_registers(1, registers, slave=SLAVE) - rr = await client.read_holding_registers(1, count=len(registers), slave=SLAVE) + await client.write_registers(1, registers, device_id=DEVICE_ID) + rr = await client.read_holding_registers(1, count=len(registers), device_id=DEVICE_ID) assert not rr.isError() # test that call was OK value = client.convert_from_registers(rr.registers, client.DATATYPE.INT32) assert value_int32 == value @@ -161,27 +161,27 @@ async def async_handle_holding_registers(client): "write_address": 1, "values": [256, 128, 100, 50, 25, 10, 5, 1], } - await client.readwrite_registers(slave=SLAVE, **arguments) - rr = await client.read_holding_registers(1, count=8, slave=SLAVE) + await client.readwrite_registers(device_id=DEVICE_ID, **arguments) + rr = await client.read_holding_registers(1, count=8, device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert rr.registers == arguments["values"] async def async_write_registers_mypy(client: ModbusBaseClient) -> None: """Read/write holding registers.""" regs1: list[int] = [10] * 8 - await client.write_registers(1, regs1, slave=SLAVE) - rr = await client.read_holding_registers(1, count=len(regs1), slave=SLAVE) + await client.write_registers(1, regs1, device_id=DEVICE_ID) + rr = await client.read_holding_registers(1, count=len(regs1), device_id=DEVICE_ID) assert not rr.isError() # test that call was OK # regs2: list[bytes] = [b'\x01\x02', b'\x03\x04'] - # await client.write_registers(1, regs2, slave=SLAVE) + # await client.write_registers(1, regs2, device_id=DEVICE_ID) # NOT ALLOWED async def async_handle_input_registers(client): """Read input registers.""" _logger.info("### read input registers") - rr = await client.read_input_registers(1, count=8, slave=SLAVE) + rr = await client.read_input_registers(1, count=8, device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert len(rr.registers) == 8 @@ -190,7 +190,7 @@ async def async_handle_file_records(client): """Read/write file records.""" _logger.info("### Read/write file records") record = FileRecord(file_number=14, record_number=12, record_length=64) - rr = await client.read_file_record([record, record], slave=SLAVE) + rr = await client.read_file_record([record, record], device_id=DEVICE_ID) assert not rr.isError() assert len(rr.records) == 2 assert rr.records[0].record_data == b'SERVER DUMMY RECORD.' @@ -198,7 +198,7 @@ async def async_handle_file_records(client): record.record_data = b'Pure test ' record.record_length = len(record.record_data) // 2 record = FileRecord(file_number=14, record_number=12, record_data=b'Pure test ') - rr = await client.write_file_record([record], slave=1) + rr = await client.write_file_record([record], device_id=1) assert not rr.isError() @@ -207,24 +207,24 @@ async def async_handle_file_records(client): async def async_execute_information_requests(client): """Execute extended information requests.""" _logger.info("### Running information requests.") - rr = await client.read_device_information(slave=SLAVE, read_code=1, object_id=0) + rr = await client.read_device_information(device_id=DEVICE_ID, read_code=1, object_id=0) assert not rr.isError() # test that call was OK assert rr.information[0] == b"Pymodbus" - rr = await client.report_slave_id(slave=SLAVE) + rr = await client.report_device_id(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert rr.status - rr = await client.read_exception_status(slave=SLAVE) + rr = await client.read_exception_status(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert not rr.status - rr = await client.diag_get_comm_event_counter(slave=SLAVE) + rr = await client.diag_get_comm_event_counter(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert rr.status assert not rr.count - rr = await client.diag_get_comm_event_log(slave=SLAVE) + rr = await client.diag_get_comm_event_log(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert rr.status assert not (rr.event_count + rr.message_count + len(rr.events)) @@ -234,39 +234,39 @@ async def async_execute_diagnostic_requests(client): """Execute extended diagnostic requests.""" _logger.info("### Running diagnostic requests.") message = b"OK" - rr = await client.diag_query_data(msg=message, slave=SLAVE) + rr = await client.diag_query_data(msg=message, device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert rr.message == message - rr = await client.diag_restart_communication(True, slave=SLAVE) + rr = await client.diag_restart_communication(True, device_id=DEVICE_ID) assert not rr.isError() # test that call was OK - rr = await client.diag_read_diagnostic_register(slave=SLAVE) + rr = await client.diag_read_diagnostic_register(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK - rr = await client.diag_change_ascii_input_delimeter(slave=SLAVE) + rr = await client.diag_change_ascii_input_delimeter(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK rr = await client.diag_clear_counters() assert not rr.isError() # test that call was OK - rr = await client.diag_read_bus_comm_error_count(slave=SLAVE) + rr = await client.diag_read_bus_comm_error_count(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK - rr = await client.diag_read_bus_exception_error_count(slave=SLAVE) + rr = await client.diag_read_bus_exception_error_count(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK - rr = await client.diag_read_slave_message_count(slave=SLAVE) + rr = await client.diag_read_device_message_count(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK - rr = await client.diag_read_slave_no_response_count(slave=SLAVE) + rr = await client.diag_read_device_no_response_count(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK - rr = await client.diag_read_slave_nak_count(slave=SLAVE) + rr = await client.diag_read_device_nak_count(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK - rr = await client.diag_read_slave_busy_count(slave=SLAVE) + rr = await client.diag_read_device_busy_count(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK - rr = await client.diag_read_bus_char_overrun_count(slave=SLAVE) + rr = await client.diag_read_bus_char_overrun_count(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK - rr = await client.diag_read_iop_overrun_count(slave=SLAVE) + rr = await client.diag_read_iop_overrun_count(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK - rr = await client.diag_clear_overrun_counter(slave=SLAVE) + rr = await client.diag_clear_overrun_counter(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK - rr = await client.diag_getclear_modbus_response(slave=SLAVE) + rr = await client.diag_getclear_modbus_response(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK - rr = await client.diag_force_listen_only(slave=SLAVE, no_response_expected=True) + rr = await client.diag_force_listen_only(device_id=DEVICE_ID, no_response_expected=True) assert rr.isError() # test that call was OK, error indicate no response diff --git a/examples/client_calls.py b/examples/client_calls.py index e720c1398..05f652f6e 100755 --- a/examples/client_calls.py +++ b/examples/client_calls.py @@ -49,7 +49,7 @@ _logger.setLevel("DEBUG") -SLAVE = 0x01 +DEVICE_ID = 0x01 # -------------------------------------------------- @@ -59,7 +59,7 @@ def template_call(client): """Show complete modbus call, sync version.""" try: - rr = client.read_coils(32, count=1, slave=SLAVE) + rr = client.read_coils(32, count=1, device_id=DEVICE_ID) except client_sync.ModbusException as exc: txt = f"ERROR: exception in pymodbus {exc}" _logger.error(txt) @@ -80,30 +80,30 @@ def template_call(client): def handle_coils(client): """Read/Write coils.""" _logger.info("### Reading Coil different number of bits (return 8 bits multiples)") - rr = client.read_coils(1, count=1, slave=SLAVE) + rr = client.read_coils(1, count=1, device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert len(rr.bits) == 8 - rr = client.read_coils(1, count=5, slave=SLAVE) + rr = client.read_coils(1, count=5, device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert len(rr.bits) == 8 - rr = client.read_coils(1, count=12, slave=SLAVE) + rr = client.read_coils(1, count=12, device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert len(rr.bits) == 16 - rr = client.read_coils(1, count=17, slave=SLAVE) + rr = client.read_coils(1, count=17, device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert len(rr.bits) == 24 _logger.info("### Write false/true to coils and read to verify") - client.write_coil(0, True, slave=SLAVE) - rr = client.read_coils(0, count=1, slave=SLAVE) + client.write_coil(0, True, device_id=DEVICE_ID) + rr = client.read_coils(0, count=1, device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert rr.bits[0] # test the expected value - client.write_coils(1, [True] * 21, slave=SLAVE) - rr = client.read_coils(1, count=21, slave=SLAVE) + client.write_coils(1, [True] * 21, device_id=DEVICE_ID) + rr = client.read_coils(1, count=21, device_id=DEVICE_ID) assert not rr.isError() # test that call was OK resp = [True] * 21 # If the returned output quantity is not a multiple of eight, @@ -113,8 +113,8 @@ def handle_coils(client): assert rr.bits == resp # test the expected value _logger.info("### Write False to address 1-8 coils") - client.write_coils(1, [False] * 8, slave=SLAVE) - rr = client.read_coils(1, count=8, slave=SLAVE) + client.write_coils(1, [False] * 8, device_id=DEVICE_ID) + rr = client.read_coils(1, count=8, device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert rr.bits == [False] * 8 # test the expected value @@ -122,7 +122,7 @@ def handle_coils(client): def handle_discrete_input(client): """Read discrete inputs.""" _logger.info("### Reading discrete input, Read address:0-7") - rr = client.read_discrete_inputs(0, count=8, slave=SLAVE) + rr = client.read_discrete_inputs(0, count=8, device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert len(rr.bits) == 8 @@ -130,15 +130,15 @@ def handle_discrete_input(client): def handle_holding_registers(client): """Read/write holding registers.""" _logger.info("### write holding register and read holding registers") - client.write_register(1, 10, slave=SLAVE) - rr = client.read_holding_registers(1, count=1, slave=SLAVE) + client.write_register(1, 10, device_id=DEVICE_ID) + rr = client.read_holding_registers(1, count=1, device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert rr.registers[0] == 10 value_int32 = 13211 registers = client.convert_to_registers(value_int32, client.DATATYPE.INT32) - client.write_registers(1, registers, slave=SLAVE) - rr = client.read_holding_registers(1, count=len(registers), slave=SLAVE) + client.write_registers(1, registers, device_id=DEVICE_ID) + rr = client.read_holding_registers(1, count=len(registers), device_id=DEVICE_ID) assert not rr.isError() # test that call was OK value = client.convert_from_registers(rr.registers, client.DATATYPE.INT32) assert value_int32 == value @@ -150,8 +150,8 @@ def handle_holding_registers(client): "write_address": 1, "values": [256, 128, 100, 50, 25, 10, 5, 1], } - client.readwrite_registers(slave=SLAVE, **arguments) - rr = client.read_holding_registers(1, count=8, slave=SLAVE) + client.readwrite_registers(device_id=DEVICE_ID, **arguments) + rr = client.read_holding_registers(1, count=8, device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert rr.registers == arguments["values"] @@ -159,7 +159,7 @@ def handle_holding_registers(client): def handle_input_registers(client): """Read input registers.""" _logger.info("### read input registers") - rr = client.read_input_registers(1, count=8, slave=SLAVE) + rr = client.read_input_registers(1, count=8, device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert len(rr.registers) == 8 @@ -168,7 +168,7 @@ def handle_file_records(client): """Read/write file records.""" _logger.info("### Read/write file records") record = FileRecord(file_number=14, record_number=12, record_length=64) - rr = client.read_file_record([record, record], slave=SLAVE) + rr = client.read_file_record([record, record], device_id=DEVICE_ID) assert not rr.isError() assert len(rr.records) == 2 assert rr.records[0].record_data == b'SERVER DUMMY RECORD.' @@ -176,31 +176,31 @@ def handle_file_records(client): record.record_data = b'Pure test ' record.record_length = len(record.record_data) // 2 record = FileRecord(file_number=14, record_number=12, record_data=b'Pure test ') - rr = client.write_file_record([record], slave=1) + rr = client.write_file_record([record], device_id=1) assert not rr.isError() def execute_information_requests(client): """Execute extended information requests.""" _logger.info("### Running information requests.") - rr = client.read_device_information(slave=SLAVE, read_code=1, object_id=0) + rr = client.read_device_information(device_id=DEVICE_ID, read_code=1, object_id=0) assert not rr.isError() # test that call was OK assert rr.information[0] == b"Pymodbus" - rr = client.report_slave_id(slave=SLAVE) + rr = client.report_device_id(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert rr.status - rr = client.read_exception_status(slave=SLAVE) + rr = client.read_exception_status(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert not rr.status - rr = client.diag_get_comm_event_counter(slave=SLAVE) + rr = client.diag_get_comm_event_counter(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert rr.status assert not rr.count - rr = client.diag_get_comm_event_log(slave=SLAVE) + rr = client.diag_get_comm_event_log(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK assert rr.status assert not (rr.event_count + rr.message_count + len(rr.events)) @@ -211,39 +211,39 @@ def execute_diagnostic_requests(client): _logger.info("### Running diagnostic requests.") # NOT WORKING: ONLY SYNC # message = b"OK" - # rr = client.diag_query_data(msg=message, slave=SLAVE) + # rr = client.diag_query_data(msg=message, device_id=DEVICE_ID) # assert not rr.isError() # test that call was OK # assert rr.message == message - rr = client.diag_restart_communication(True, slave=SLAVE) + rr = client.diag_restart_communication(True, device_id=DEVICE_ID) assert not rr.isError() # test that call was OK - rr = client.diag_read_diagnostic_register(slave=SLAVE) + rr = client.diag_read_diagnostic_register(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK - rr = client.diag_change_ascii_input_delimeter(slave=SLAVE) + rr = client.diag_change_ascii_input_delimeter(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK rr = client.diag_clear_counters() assert not rr.isError() # test that call was OK - rr = client.diag_read_bus_comm_error_count(slave=SLAVE) + rr = client.diag_read_bus_comm_error_count(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK - rr = client.diag_read_bus_exception_error_count(slave=SLAVE) + rr = client.diag_read_bus_exception_error_count(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK - rr = client.diag_read_slave_message_count(slave=SLAVE) + rr = client.diag_read_device_message_count(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK - rr = client.diag_read_slave_no_response_count(slave=SLAVE) + rr = client.diag_read_device_no_response_count(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK - rr = client.diag_read_slave_nak_count(slave=SLAVE) + rr = client.diag_read_device_nak_count(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK - rr = client.diag_read_slave_busy_count(slave=SLAVE) + rr = client.diag_read_device_busy_count(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK - rr = client.diag_read_bus_char_overrun_count(slave=SLAVE) + rr = client.diag_read_bus_char_overrun_count(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK - rr = client.diag_read_iop_overrun_count(slave=SLAVE) + rr = client.diag_read_iop_overrun_count(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK - rr = client.diag_clear_overrun_counter(slave=SLAVE) + rr = client.diag_clear_overrun_counter(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK - # NOT WORKING rr = client.diag_getclear_modbus_response(slave=SLAVE) + # NOT WORKING rr = client.diag_getclear_modbus_response(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK - # NOT WORKING: rr = client.diag_force_listen_only(slave=SLAVE) + # NOT WORKING: rr = client.diag_force_listen_only(device_id=DEVICE_ID) assert not rr.isError() # test that call was OK diff --git a/examples/client_performance.py b/examples/client_performance.py index febaf5869..78a78e65e 100755 --- a/examples/client_performance.py +++ b/examples/client_performance.py @@ -37,7 +37,7 @@ def run_sync_client_test(): start_time = time.time() for _i in range(LOOP_COUNT): - rr = client.read_input_registers(1, count=REGISTER_COUNT, slave=1) + rr = client.read_input_registers(1, count=REGISTER_COUNT, device_id=1) if rr.isError(): print(f"Received Modbus library error({rr})") break @@ -64,7 +64,7 @@ async def run_async_client_test(): start_time = time.time() for _i in range(LOOP_COUNT): - rr = await client.read_input_registers(1, count=REGISTER_COUNT, slave=1) + rr = await client.read_input_registers(1, count=REGISTER_COUNT, device_id=1) if rr.isError(): print(f"Received Modbus library error({rr})") break diff --git a/examples/client_sync.py b/examples/client_sync.py index c64234f0a..ce4ded406 100755 --- a/examples/client_sync.py +++ b/examples/client_sync.py @@ -128,9 +128,9 @@ def run_sync_client(client, modbus_calls=None): def run_a_few_calls(client): """Test connection works.""" try: - rr = client.read_coils(32, count=1, slave=1) + rr = client.read_coils(32, count=1, device_id=1) assert len(rr.bits) == 8 - rr = client.read_holding_registers(4, count=2, slave=1) + rr = client.read_holding_registers(4, count=2, device_id=1) assert rr.registers[0] == 17 assert rr.registers[1] == 17 except ModbusException as exc: diff --git a/examples/contrib/drainage_sim.py b/examples/contrib/drainage_sim.py index 8e09dd2a4..e69a57f08 100755 --- a/examples/contrib/drainage_sim.py +++ b/examples/contrib/drainage_sim.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -# Simulates two Modbus TCP slave servers: +# Simulates two Modbus TCP device servers: # # Port 5020: Digital IO (DIO) with 8 discrete inputs and 8 coils. The first two coils each control # a simulated pump. Inputs are not used. @@ -12,7 +12,7 @@ import logging from datetime import datetime -from pymodbus.datastore import ModbusSequentialDataBlock, ModbusSlaveContext, ModbusServerContext +from pymodbus.datastore import ModbusSequentialDataBlock, ModbusDeviceContext, ModbusServerContext from pymodbus.server import StartAsyncTcpServer INITIAL_WATER_LEVEL = 300 @@ -23,9 +23,9 @@ dio_di = ModbusSequentialDataBlock(1, [False] * 8) dio_co = ModbusSequentialDataBlock(1, [False] * 8) -dio_context = ModbusSlaveContext(di = dio_di, co = dio_co) +dio_context = ModbusDeviceContext(di = dio_di, co = dio_co) wlm_ir = ModbusSequentialDataBlock(1, [INITIAL_WATER_LEVEL]) -wlm_context = ModbusSlaveContext(ir = wlm_ir) +wlm_context = ModbusDeviceContext(ir = wlm_ir) async def update(): while True: @@ -50,13 +50,13 @@ async def log(): logging.info(f"{datetime.now()}: WLM water level: {wlm_level}, DIO outputs: {dio_outputs}") async def run(): - ctx = ModbusServerContext(slaves = dio_context) + ctx = ModbusServerContext(device_ids = dio_context) dio_server = asyncio.create_task(StartAsyncTcpServer(context = ctx, address = ("0.0.0.0", 5020))) - logging.info("Initialising slave server DIO on port 5020") + logging.info("Initialising device server DIO on port 5020") - ctx = ModbusServerContext(slaves = wlm_context) + ctx = ModbusServerContext(device_ids = wlm_context) wlm_server = asyncio.create_task(StartAsyncTcpServer(context = ctx, address = ("0.0.0.0", 5021))) - logging.info("Initialising slave server WLM on port 5021") + logging.info("Initialising device server WLM on port 5021") update_task = asyncio.create_task(update()) logging_task = asyncio.create_task(log()) diff --git a/examples/contrib/serial_forwarder.py b/examples/contrib/serial_forwarder.py index 325570634..9b3db60bc 100644 --- a/examples/contrib/serial_forwarder.py +++ b/examples/contrib/serial_forwarder.py @@ -1,7 +1,7 @@ """Pymodbus SerialRTU2TCP Forwarder usage : -python3 serial_forwarder.py --log DEBUG --port "/dev/ttyUSB0" --baudrate 9600 --server_ip "192.168.1.27" --server_port 5020 --slaves 1 2 3 +python3 serial_forwarder.py --log DEBUG --port "/dev/ttyUSB0" --baudrate 9600 --server_ip "192.168.1.27" --server_port 5020 --device_ids 1 2 3 """ import argparse import asyncio @@ -10,7 +10,7 @@ from pymodbus.client import ModbusSerialClient from pymodbus.datastore import ModbusServerContext -from pymodbus.datastore.remote import RemoteSlaveContext +from pymodbus.datastore.remote import RemoteDeviceContext from pymodbus.server import ModbusTcpServer @@ -32,21 +32,21 @@ def __init__(self): async def run(self): """Run the server""" - port, baudrate, server_port, server_ip, slaves = get_commandline() + port, baudrate, server_port, server_ip, device_ids = get_commandline() client = ModbusSerialClient(method="rtu", port=port, baudrate=baudrate) message = f"RTU bus on {port} - baudrate {baudrate}" _logger.info(message) store = {} - for i in slaves: - store[i] = RemoteSlaveContext(client, slave=i) - context = ModbusServerContext(slaves=store, single=False) + for i in device_ids: + store[i] = RemoteDeviceContext(client, device_id=i) + context = ModbusServerContext(device_ids=store, single=False) self.server = ModbusTcpServer( context, address=(server_ip, server_port), ) message = f"serving on {server_ip} port {server_port}" _logger.info(message) - message = f"listening to slaves {context.slaves()}" + message = f"listening to device_ids {context.device_ids()}" _logger.info(message) await self.server.serve_forever() @@ -74,16 +74,16 @@ def get_commandline(): parser.add_argument("--server_port", help="server port", default=5020, type=int) parser.add_argument("--server_ip", help="server IP", default="127.0.0.1", type=str) parser.add_argument( - "--slaves", help="list of slaves to forward", type=int, nargs="+" + "--sdevice_ids", help="list of device_ids to forward", type=int, nargs="+" ) args = parser.parse_args() # set defaults _logger.setLevel(args.log.upper()) - if not args.slaves: - args.slaves = {1, 2, 3} - return args.port, args.baudrate, args.server_port, args.server_ip, args.slaves + if not args.device_ids: + args.device_ids = {1, 2, 3} + return args.port, args.baudrate, args.server_port, args.server_ip, args.device_ids if __name__ == "__main__": diff --git a/examples/contrib/solar.py b/examples/contrib/solar.py index 3106317eb..a3aab32f6 100755 --- a/examples/contrib/solar.py +++ b/examples/contrib/solar.py @@ -59,7 +59,7 @@ def main() -> None: def solar_calls(client: ModbusTcpClient) -> None: """Read registers.""" error = False - + for addr, format, factor, comment, unit in ( # data_type according to ModbusClientMixin.DATATYPE.value[0] (32008, "H", 1, "Alarm 1", "(bitfield)"), (32009, "H", 1, "Alarm 2", "(bitfield)"), @@ -79,15 +79,15 @@ def solar_calls(client: ModbusTcpClient) -> None: sleep(0.1) client.connect() sleep(1) - + data_type = get_data_type(format) count = data_type.value[1] var_type = data_type.name _logger.info(f"*** Reading {comment} ({var_type})") - + try: - rr = client.read_holding_registers(address=addr, count=count, slave=1) + rr = client.read_holding_registers(address=addr, count=count, device_id=1) except ModbusException as exc: _logger.error(f"Modbus exception: {exc!s}") error = True @@ -100,7 +100,7 @@ def solar_calls(client: ModbusTcpClient) -> None: _logger.error(f"Response exception: {rr!s}") error = True continue - + value = client.convert_from_registers(rr.registers, data_type) * factor if factor < 1: value = round(value, int(log10(factor) * -1)) diff --git a/examples/custom_msg.py b/examples/custom_msg.py index 76af0d16f..48624d0a5 100755 --- a/examples/custom_msg.py +++ b/examples/custom_msg.py @@ -16,9 +16,9 @@ from pymodbus import FramerType from pymodbus.client import AsyncModbusTcpClient as ModbusClient from pymodbus.datastore import ( + ModbusDeviceContext, ModbusSequentialDataBlock, ModbusServerContext, - ModbusSlaveContext, ) from pymodbus.exceptions import ModbusIOException from pymodbus.pdu import ModbusPDU @@ -43,9 +43,9 @@ class CustomModbusResponse(ModbusPDU): function_code = 55 rtu_byte_count_pos = 2 - def __init__(self, values=None, slave=1, transaction=0): + def __init__(self, values=None, device_id=1, transaction=0): """Initialize.""" - super().__init__(dev_id=slave, transaction_id=transaction) + super().__init__(dev_id=device_id, transaction_id=transaction) self.values = values or [] def encode(self): @@ -75,9 +75,9 @@ class CustomRequest(ModbusPDU): function_code = 55 rtu_frame_size = 8 - def __init__(self, address=None, slave=1, transaction=0): + def __init__(self, address=None, device_id=1, transaction=0): """Initialize.""" - super().__init__(dev_id=slave, transaction_id=transaction) + super().__init__(dev_id=device_id, transaction_id=transaction) self.address = address self.count = 2 @@ -89,7 +89,7 @@ def decode(self, data): """Decode.""" self.address, self.count = struct.unpack(">HH", data) - async def update_datastore(self, context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, context: ModbusDeviceContext) -> ModbusPDU: """Execute.""" _ = context return CustomModbusResponse() @@ -103,12 +103,12 @@ async def update_datastore(self, context: ModbusSlaveContext) -> ModbusPDU: class Read16CoilsRequest(ReadCoilsRequest): """Read 16 coils in one request.""" - def __init__(self, address, slave=1, transaction=0): + def __init__(self, address, device_id=1, transaction=0): """Initialize a new instance. :param address: The address to start reading from """ - super().__init__(address=address, count=16, dev_id=slave, transaction_id=transaction) + super().__init__(address=address, count=16, dev_id=device_id, transaction_id=transaction) # --------------------------------------------------------------------------- # @@ -121,7 +121,7 @@ def __init__(self, address, slave=1, transaction=0): async def main(host="localhost", port=5020): """Run versions of read coil.""" - store = ModbusServerContext(slaves=ModbusSlaveContext( + store = ModbusServerContext(devices=ModbusDeviceContext( di=ModbusSequentialDataBlock(0, [17] * 100), co=ModbusSequentialDataBlock(0, [17] * 100), hr=ModbusSequentialDataBlock(0, [17] * 100), @@ -140,8 +140,8 @@ async def main(host="localhost", port=5020): # add new modbus function code. client.register(CustomModbusResponse) - slave=1 - request1 = CustomRequest(32, slave=slave) + device_id=1 + request1 = CustomRequest(32, device_id=device_id) try: result = await client.execute(False, request1) except ModbusIOException: @@ -150,7 +150,7 @@ async def main(host="localhost", port=5020): print(result) # inherited request - request2 = Read16CoilsRequest(32, slave) + request2 = Read16CoilsRequest(32, device_id) result = await client.execute(False, request2) print(result) await ServerAsyncStop() diff --git a/examples/datastore_simulator_share.py b/examples/datastore_simulator_share.py index a74f7af8b..247c4a690 100755 --- a/examples/datastore_simulator_share.py +++ b/examples/datastore_simulator_share.py @@ -32,9 +32,8 @@ import asyncio import logging -from pymodbus import pymodbus_apply_logging_config +from pymodbus import ModbusDeviceIdentification, pymodbus_apply_logging_config from pymodbus.datastore import ModbusServerContext, ModbusSimulatorContext -from pymodbus.device import ModbusDeviceIdentification from pymodbus.server import StartAsyncTcpServer @@ -153,7 +152,7 @@ def setup_simulator(setup=None, actions=None, cmdline=None): args.port = int(args.port) context = ModbusSimulatorContext(setup, actions) - args.context = ModbusServerContext(slaves=context, single=True) + args.context = ModbusServerContext(devices=context, single=True) args.identity = ModbusDeviceIdentification( info_name={ "VendorName": "Pymodbus", diff --git a/examples/helper.py b/examples/helper.py index 2f6fabc7a..93fe05649 100755 --- a/examples/helper.py +++ b/examples/helper.py @@ -75,8 +75,8 @@ def get_commandline(server: bool = False, description: str | None = None, extras type=str, ) parser.add_argument( - "--slaves", - help="set number of slaves, default is 0 (any)", + "--device_ids", + help="set number of device_ids, default is 0 (any)", default=0, type=int, ) diff --git a/examples/modbus_forwarder.py b/examples/modbus_forwarder.py index 2a98e16da..b72170a17 100755 --- a/examples/modbus_forwarder.py +++ b/examples/modbus_forwarder.py @@ -33,7 +33,7 @@ from pymodbus.client import ModbusTcpClient from pymodbus.datastore import ModbusServerContext -from pymodbus.datastore.remote import RemoteSlaveContext +from pymodbus.datastore.remote import RemoteDeviceContext from pymodbus.server import StartAsyncTcpServer @@ -56,18 +56,18 @@ async def run_forwarder(args): ) args.client.connect() assert args.client.connected - # If required to communicate with a specified client use slave= - # in RemoteSlaveContext - # For e.g to forward the requests to slave with slave address 1 use - # store = RemoteSlaveContext(client, slave=1) - store: dict | RemoteSlaveContext - if args.slaves: + # If required to communicate with a specified client use device_id= + # in RemoteDeviceContext + # For e.g to forward the requests to device_id with device address 1 use + # store = RemoteDeviceContext(client, device_id=1) + store: dict | RemoteDeviceContext + if args.device_ids: store = {} - for i in args.slaves: - store[i.to_bytes(1, "big")] = RemoteSlaveContext(args.client, slave=i) + for i in args.device_ids: + store[i.to_bytes(1, "big")] = RemoteDeviceContext(args.client, device_id=i) else: - store = RemoteSlaveContext(args.client, slave=1) - args.context = ModbusServerContext(slaves=store, single=True) + store = RemoteDeviceContext(args.client, device_id=1) + args.context = ModbusServerContext(devices=store, single=True) await StartAsyncTcpServer(context=args.context, address=("", args.port)) # loop forever diff --git a/examples/package_test_tool.py b/examples/package_test_tool.py index 8296c432d..5c06f4104 100755 --- a/examples/package_test_tool.py +++ b/examples/package_test_tool.py @@ -49,13 +49,17 @@ import pymodbus.client as modbusClient import pymodbus.server as modbusServer -from pymodbus import FramerType, ModbusException, pymodbus_apply_logging_config +from pymodbus import ( + FramerType, + ModbusDeviceIdentification, + ModbusException, + pymodbus_apply_logging_config, +) from pymodbus.datastore import ( + ModbusDeviceContext, ModbusSequentialDataBlock, ModbusServerContext, - ModbusSlaveContext, ) -from pymodbus.device import ModbusDeviceIdentification from pymodbus.logging import Log from pymodbus.transport import NULLMODEM_HOST, CommParams, CommType, ModbusProtocol @@ -147,13 +151,13 @@ def __init__(self, comm: CommType): """Initialize runtime tester.""" global test_port # pylint: disable=global-statement self.comm = comm - self.store = ModbusSlaveContext( + self.store = ModbusDeviceContext( di=ModbusSequentialDataBlock(0, [17] * 100), co=ModbusSequentialDataBlock(0, [17] * 100), hr=ModbusSequentialDataBlock(0, [17] * 100), ir=ModbusSequentialDataBlock(0, [17] * 100), ) - self.context = ModbusServerContext(slaves=self.store, single=True) + self.context = ModbusServerContext(devices=self.store, single=True) self.identity = ModbusDeviceIdentification( info_name={"VendorName": "VendorName"} ) @@ -210,7 +214,7 @@ async def client_calls(client): """Test client API.""" Log.debug("--> Client calls starting.") try: - resp = await client.read_holding_registers(address=124, count=4, slave=1) + resp = await client.read_holding_registers(address=124, count=4, device_id=1) except ModbusException as exc: txt = f"ERROR: exception in pymodbus {exc}" Log.error(txt) diff --git a/examples/server_async.py b/examples/server_async.py index bec0135da..d60be6437 100755 --- a/examples/server_async.py +++ b/examples/server_async.py @@ -9,7 +9,7 @@ [--framer {ascii,rtu,socket,tls}] [--log {critical,error,warning,info,debug}] [--port PORT] [--store {sequential,sparse,factory,none}] - [--slaves SLAVES] + [--device_ids DEVICE_IDS] -h, --help show this help message and exit @@ -24,8 +24,8 @@ set serial device baud rate --store {sequential,sparse,factory,none} set datastore type - --slaves SLAVES - set number of slaves to respond to + --device_ids DEVICE IDs + set list of devices to respond to The corresponding client can be started as: @@ -47,14 +47,14 @@ for more information.") sys.exit(-1) +from pymodbus import ModbusDeviceIdentification from pymodbus import __version__ as pymodbus_version from pymodbus.datastore import ( + ModbusDeviceContext, ModbusSequentialDataBlock, ModbusServerContext, - ModbusSlaveContext, ModbusSparseDataBlock, ) -from pymodbus.device import ModbusDeviceIdentification from pymodbus.server import ( StartAsyncSerialServer, StartAsyncTcpServer, @@ -91,17 +91,17 @@ def setup_server(description=None, context=None, cmdline=None): # full address range:: datablock = lambda : ModbusSequentialDataBlock.create() # pylint: disable=unnecessary-lambda-assignment,unnecessary-lambda - if args.slaves > 1: + if args.device_ids > 1: # The server then makes use of a server context that allows the server - # to respond with different slave contexts for different slave ids. - # By default it will return the same context for every slave id supplied + # to respond with different device contexts for different device ids. + # By default it will return the same context for every device id supplied # (broadcast mode). # However, this can be overloaded by setting the single flag to False and - # then supplying a dictionary of slave id to context mapping:: + # then supplying a dictionary of device id to context mapping:: context = {} - for slave in range(args.slaves): - context[slave] = ModbusSlaveContext( + for device_id in range(args.device_ids): + context[device_id] = ModbusDeviceContext( di=datablock(), co=datablock(), hr=datablock(), @@ -110,13 +110,13 @@ def setup_server(description=None, context=None, cmdline=None): single = False else: - context = ModbusSlaveContext( + context = ModbusDeviceContext( di=datablock(), co=datablock(), hr=datablock(), ir=datablock() ) single = True # Build data storage - args.context = ModbusServerContext(slaves=context, single=single) + args.context = ModbusServerContext(devices=context, single=single) # ----------------------------------------------------------------------- # # initialize the server information @@ -148,8 +148,8 @@ async def run_async_server(args) -> None: address=address, # listen address # custom_functions=[], # allow custom handling framer=args.framer, # The framer strategy to use - # ignore_missing_slaves=True, # ignore request to a missing slave - # broadcast_enable=False, # treat slave 0 as broadcast address, + # ignore_missing_devices=True, # ignore request to a missing device + # broadcast_enable=False, # treat device 0 as broadcast address, # timeout=1, # waiting time for request to complete ) elif args.comm == "udp": @@ -163,8 +163,8 @@ async def run_async_server(args) -> None: address=address, # listen address # custom_functions=[], # allow custom handling framer=args.framer, # The framer strategy to use - # ignore_missing_slaves=True, # ignore request to a missing slave - # broadcast_enable=False, # treat slave 0 as broadcast address, + # ignore_missing_devices=True, # ignore request to a missing device + # broadcast_enable=False, # treat device id 0 as broadcast address, # timeout=1, # waiting time for request to complete ) elif args.comm == "serial": @@ -182,8 +182,8 @@ async def run_async_server(args) -> None: # parity="N", # Which kind of parity to use baudrate=args.baudrate, # The baud rate to use for the serial device # handle_local_echo=False, # Handle local echo of the USB-to-RS485 adaptor - # ignore_missing_slaves=True, # ignore request to a missing slave - # broadcast_enable=False, # treat slave 0 as broadcast address, + # ignore_missing_devices=True, # ignore request to a missing device + # broadcast_enable=False, # treat device_id 0 as broadcast address, ) elif args.comm == "tls": address = (args.host if args.host else "", args.port if args.port else None) @@ -202,8 +202,8 @@ async def run_async_server(args) -> None: "key" ), # The key file path for TLS (used if sslctx is None) # password="none", # The password for for decrypting the private key file - # ignore_missing_slaves=True, # ignore request to a missing slave - # broadcast_enable=False, # treat slave 0 as broadcast address, + # ignore_missing_devices=True, # ignore request to a missing device + # broadcast_enable=False, # treat device_id 0 as broadcast address, # timeout=1, # waiting time for request to complete ) diff --git a/examples/server_callback.py b/examples/server_callback.py index 5b137a6ae..4db283871 100755 --- a/examples/server_callback.py +++ b/examples/server_callback.py @@ -18,9 +18,9 @@ sys.exit(-1) from pymodbus.datastore import ( + ModbusDeviceContext, ModbusSequentialDataBlock, ModbusServerContext, - ModbusSlaveContext, ) @@ -58,8 +58,8 @@ async def run_callback_server(cmdline=None): queue: asyncio.Queue = asyncio.Queue() block = CallbackDataBlock(queue, 0x00, [17] * 100) block.setValues(1, 15) - store = ModbusSlaveContext(di=block, co=block, hr=block, ir=block) - context = ModbusServerContext(slaves=store, single=True) + store = ModbusDeviceContext(di=block, co=block, hr=block, ir=block) + context = ModbusServerContext(devices=store, single=True) run_args = server_async.setup_server( description="Run callback server.", cmdline=cmdline, context=context ) diff --git a/examples/server_hook.py b/examples/server_hook.py index 45df6abe4..8c4662ccf 100755 --- a/examples/server_hook.py +++ b/examples/server_hook.py @@ -11,9 +11,9 @@ from pymodbus import FramerType, pymodbus_apply_logging_config from pymodbus.datastore import ( + ModbusDeviceContext, ModbusSequentialDataBlock, ModbusServerContext, - ModbusSlaveContext, ) from pymodbus.pdu import ModbusPDU from pymodbus.server import ModbusTcpServer @@ -48,7 +48,7 @@ async def setup(self): pymodbus_apply_logging_config(logging.DEBUG) datablock = ModbusSequentialDataBlock(0x00, [17] * 100) context = ModbusServerContext( - slaves=ModbusSlaveContext( + devices=ModbusDeviceContext( di=datablock, co=datablock, hr=datablock, ir=datablock ), single=True, diff --git a/examples/server_sync.py b/examples/server_sync.py index c85a92483..6eb47c6ec 100755 --- a/examples/server_sync.py +++ b/examples/server_sync.py @@ -9,7 +9,7 @@ [--framer {ascii,rtu,socket,tls}] [--log {critical,error,warning,info,debug}] [--port PORT] [--store {sequential,sparse,factory,none}] - [--slaves SLAVES] + [--device_ids DEVICE_IDS] -h, --help show this help message and exit @@ -24,8 +24,8 @@ set serial device baud rate --store {sequential,sparse,factory,none} set datastore type - --slaves SLAVES - set number of slaves to respond to + --device_ids DEVICE_IDS + set list of devices to respond to The corresponding client can be started as: python3 client_sync.py @@ -74,8 +74,8 @@ def run_sync_server(args) -> None: address=address, # listen address # custom_functions=[], # allow custom handling framer=args.framer, # The framer strategy to use - # ignore_missing_slaves=True, # ignore request to a missing slave - # broadcast_enable=False, # treat slave 0 as broadcast address, + # ignore_missing_devices=True, # ignore request to a missing device + # broadcast_enable=False, # treat device_id 0 as broadcast address, # timeout=1, # waiting time for request to complete ) elif args.comm == "udp": @@ -86,8 +86,8 @@ def run_sync_server(args) -> None: address=address, # listen address # custom_functions=[], # allow custom handling framer=args.framer, # The framer strategy to use - # ignore_missing_slaves=True, # ignore request to a missing slave - # broadcast_enable=False, # treat slave 0 as broadcast address, + # ignore_missing_devices=True, # ignore request to a missing device + # broadcast_enable=False, # treat device_id 0 as broadcast address, # timeout=1, # waiting time for request to complete ) elif args.comm == "serial": @@ -105,8 +105,8 @@ def run_sync_server(args) -> None: # parity="E", # Which kind of parity to use baudrate=args.baudrate, # The baud rate to use for the serial device # handle_local_echo=False, # Handle local echo of the USB-to-RS485 adaptor - # ignore_missing_slaves=True, # ignore request to a missing slave - # broadcast_enable=False, # treat slave 0 as broadcast address, + # ignore_missing_devices=True, # ignore request to a missing device + # broadcast_enable=False, # treat device_id 0 as broadcast address, ) elif args.comm == "tls": address = ("", args.port) if args.port else None @@ -125,8 +125,8 @@ def run_sync_server(args) -> None: "key" ), # The key file path for TLS (used if sslctx is None) # password=None, # The password for for decrypting the private key file - # ignore_missing_slaves=True, # ignore request to a missing slave - # broadcast_enable=False, # treat slave 0 as broadcast address, + # ignore_missing_devices=True, # ignore request to a missing device + # broadcast_enable=False, # treat device_id 0 as broadcast address, # timeout=1, # waiting time for request to complete ) diff --git a/examples/server_updating.py b/examples/server_updating.py index 4dee58cf1..270b5dcaf 100755 --- a/examples/server_updating.py +++ b/examples/server_updating.py @@ -10,7 +10,7 @@ [--framer {ascii,rtu,socket,tls}] [--log {critical,error,warning,info,debug}] [--port PORT] [--store {sequential,sparse,factory,none}] - [--slaves SLAVES] + [--device_ids DEVICE_IDS] -h, --help show this help message and exit @@ -25,8 +25,8 @@ set serial device baud rate --store {sequential,sparse,factory,none} set datastore type - --slaves SLAVES - set number of slaves to respond to + --device_ids DEVICE_IDS + set number of devices to respond to The corresponding client can be started as: python3 client_sync.py @@ -45,9 +45,9 @@ sys.exit(-1) from pymodbus.datastore import ( + ModbusDeviceContext, ModbusSequentialDataBlock, ModbusServerContext, - ModbusSlaveContext, ) @@ -64,14 +64,14 @@ async def updating_task(context): against concurrent use. """ fc_as_hex = 3 - slave_id = 0x00 + device_id = 0x00 address = 0x10 count = 6 # set values to zero - values = context[slave_id].getValues(fc_as_hex, address, count=count) + values = context[device_id].getValues(fc_as_hex, address, count=count) values = [0 for v in values] - context[slave_id].setValues(fc_as_hex, address, values) + context[device_id].setValues(fc_as_hex, address, values) txt = ( f"updating_task: started: initialised values: {values!s} at address {address!s}" @@ -83,9 +83,9 @@ async def updating_task(context): while True: await asyncio.sleep(2) - values = context[slave_id].getValues(fc_as_hex, address, count=count) + values = context[device_id].getValues(fc_as_hex, address, count=count) values = [v + 1 for v in values] - context[slave_id].setValues(fc_as_hex, address, values) + context[device_id].setValues(fc_as_hex, address, values) txt = f"updating_task: incremented values: {values!s} at address {address!s}" print(txt) @@ -101,8 +101,8 @@ def setup_updating_server(cmdline=None): # Continuing, use a sequential block without gaps. datablock = ModbusSequentialDataBlock(0x00, [17] * 100) - slavecontext = ModbusSlaveContext(di=datablock, co=datablock, hr=datablock, ir=datablock) - context = ModbusServerContext(slaves=slavecontext, single=True) + device_context = ModbusDeviceContext(di=datablock, co=datablock, hr=datablock, ir=datablock) + context = ModbusServerContext(devices=device_context, single=True) return server_async.setup_server( description="Run asynchronous server.", context=context, cmdline=cmdline ) diff --git a/examples/simple_async_client.py b/examples/simple_async_client.py index fceac333f..8cbaa6af8 100755 --- a/examples/simple_async_client.py +++ b/examples/simple_async_client.py @@ -68,7 +68,7 @@ async def run_async_simple_client(comm, host, port, framer=FramerType.SOCKET): print("get and verify data") try: # See all calls in client_calls.py - rr = await client.read_coils(1, count=1, slave=1) + rr = await client.read_coils(1, count=1, device_id=1) except ModbusException as exc: print(f"Received ModbusException({exc}) from library") client.close() @@ -80,7 +80,7 @@ async def run_async_simple_client(comm, host, port, framer=FramerType.SOCKET): return try: # See all calls in client_calls.py - rr = await client.read_holding_registers(10, count=2, slave=1) + rr = await client.read_holding_registers(10, count=2, device_id=1) except ModbusException as exc: print(f"Received ModbusException({exc}) from library") client.close() diff --git a/examples/simple_sync_client.py b/examples/simple_sync_client.py index b65071a68..6ca1e365d 100755 --- a/examples/simple_sync_client.py +++ b/examples/simple_sync_client.py @@ -67,7 +67,7 @@ def run_sync_simple_client(comm, host, port, framer=FramerType.SOCKET): print("get and verify data") try: - rr = client.read_coils(1, count=1, slave=1) + rr = client.read_coils(1, count=1, device_id=1) except ModbusException as exc: print(f"Received ModbusException({exc}) from library") client.close() @@ -79,7 +79,7 @@ def run_sync_simple_client(comm, host, port, framer=FramerType.SOCKET): return try: # See all calls in client_calls.py - rr = client.read_holding_registers(10, count=2, slave=1) + rr = client.read_holding_registers(10, count=2, device_id=1) except ModbusException as exc: print(f"Received ModbusException({exc}) from library") client.close() diff --git a/examples/simulator.py b/examples/simulator.py index 4af1fb9cc..a947c17cb 100755 --- a/examples/simulator.py +++ b/examples/simulator.py @@ -23,7 +23,7 @@ async def read_registers( client, addr, count, is_int, curval=None, minval=None, maxval=None ): """Run modbus call.""" - rr = await client.read_holding_registers(addr, count=count, slave=1) + rr = await client.read_holding_registers(addr, count=count, device_id=1) assert not rr.isError() if count == 1: value = rr.registers[0] diff --git a/pymodbus/__init__.py b/pymodbus/__init__.py index 77f613128..62245eee8 100644 --- a/pymodbus/__init__.py +++ b/pymodbus/__init__.py @@ -6,16 +6,18 @@ __all__ = [ "ExceptionResponse", "FramerType", + "ModbusDeviceIdentification", "ModbusException", "__version__", "__version_full__", - "pymodbus_apply_logging_config", + "pymodbus_apply_logging_config" ] from pymodbus.exceptions import ModbusException from pymodbus.framer import FramerType from pymodbus.logging import pymodbus_apply_logging_config from pymodbus.pdu import ExceptionResponse +from pymodbus.pdu.device import ModbusDeviceIdentification __version__ = "4.0.0dev0" diff --git a/pymodbus/client/base.py b/pymodbus/client/base.py index 3cdd45cb1..099a9d956 100644 --- a/pymodbus/client/base.py +++ b/pymodbus/client/base.py @@ -145,7 +145,6 @@ def __init__( ModbusClientMixin.__init__(self) # type: ignore[arg-type] self.comm_params = comm_params self.retries = retries - self.slaves: list[int] = [] # Common variables. self.framer: FramerBase = (FRAMER_NAME_TO_CLASS[framer])(DecodePDU(False)) diff --git a/pymodbus/client/mixin.py b/pymodbus/client/mixin.py index 67f717ae0..dcfffbdc4 100644 --- a/pymodbus/client/mixin.py +++ b/pymodbus/client/mixin.py @@ -54,32 +54,32 @@ def __init__(self): def execute(self, no_response_expected: bool, request: ModbusPDU) -> T: """Execute request.""" - def read_coils(self, address: int, *, count: int = 1, slave: int = 1, no_response_expected: bool = False) -> T: + def read_coils(self, address: int, *, count: int = 1, device_id: int = 1, no_response_expected: bool = False) -> T: """Read coils (code 0x01). :param address: Start address to read from :param count: (optional) Number of coils to read - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: - reads from 1 to 2000 contiguous in a remote device (slave). + reads from 1 to 2000 contiguous in a remote device. Coils are addressed as 0-N (Note some device manuals uses 1-N, assuming 1==0). """ - return self.execute(no_response_expected, pdu_bit.ReadCoilsRequest(address=address, count=count, dev_id=slave)) + return self.execute(no_response_expected, pdu_bit.ReadCoilsRequest(address=address, count=count, dev_id=device_id)) def read_discrete_inputs(self, address: int, *, count: int = 1, - slave: int = 1, + device_id: int = 1, no_response_expected: bool = False) -> T: """Read discrete inputs (code 0x02). :param address: Start address to read from :param count: (optional) Number of coils to read - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: @@ -87,20 +87,20 @@ def read_discrete_inputs(self, Discrete Inputs are addressed as 0-N (Note some device manuals uses 1-N, assuming 1==0). """ - pdu = pdu_bit.ReadDiscreteInputsRequest(address=address, count=count, dev_id=slave) + pdu = pdu_bit.ReadDiscreteInputsRequest(address=address, count=count, dev_id=device_id) return self.execute(no_response_expected, pdu) def read_holding_registers(self, address: int, *, count: int = 1, - slave: int = 1, + device_id: int = 1, no_response_expected: bool = False) -> T: """Read holding registers (code 0x03). :param address: Start address to read from :param count: (optional) Number of registers to read - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: @@ -111,19 +111,19 @@ def read_holding_registers(self, Registers are addressed starting at zero. Therefore devices that specify 1-16 are addressed as 0-15. """ - return self.execute(no_response_expected, pdu_reg.ReadHoldingRegistersRequest(address=address, count=count, dev_id=slave)) + return self.execute(no_response_expected, pdu_reg.ReadHoldingRegistersRequest(address=address, count=count, dev_id=device_id)) def read_input_registers(self, address: int, *, count: int = 1, - slave: int = 1, + device_id: int = 1, no_response_expected: bool = False) -> T: """Read input registers (code 0x04). :param address: Start address to read from :param count: (optional) Number of coils to read - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: @@ -134,14 +134,14 @@ def read_input_registers(self, Registers are addressed starting at zero. Therefore devices that specify 1-16 are addressed as 0-15. """ - return self.execute(no_response_expected, pdu_reg.ReadInputRegistersRequest(address=address, count=count, dev_id=slave)) + return self.execute(no_response_expected, pdu_reg.ReadInputRegistersRequest(address=address, count=count, dev_id=device_id)) - def write_coil(self, address: int, value: bool, *, slave: int = 1, no_response_expected: bool = False) -> T: + def write_coil(self, address: int, value: bool, *, device_id: int = 1, no_response_expected: bool = False) -> T: """Write single coil (code 0x05). :param address: Address to write to :param value: Boolean to write - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: @@ -149,15 +149,15 @@ def write_coil(self, address: int, value: bool, *, slave: int = 1, no_response_e Coils are addressed as 0-N (Note some device manuals uses 1-N, assuming 1==0). """ - pdu = pdu_bit.WriteSingleCoilRequest(address=address, bits=[value], dev_id=slave) + pdu = pdu_bit.WriteSingleCoilRequest(address=address, bits=[value], dev_id=device_id) return self.execute(no_response_expected, pdu) - def write_register(self, address: int, value: int, *, slave: int = 1, no_response_expected: bool = False) -> T: + def write_register(self, address: int, value: int, *, device_id: int = 1, no_response_expected: bool = False) -> T: """Write register (code 0x06). :param address: Address to write to :param value: Value to write - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: @@ -168,12 +168,12 @@ def write_register(self, address: int, value: int, *, slave: int = 1, no_respons Registers are addressed starting at zero. Therefore register numbered 1 is addressed as 0. """ - return self.execute(no_response_expected, pdu_reg.WriteSingleRegisterRequest(address=address, registers=[value], dev_id=slave)) + return self.execute(no_response_expected, pdu_reg.WriteSingleRegisterRequest(address=address, registers=[value], dev_id=device_id)) - def read_exception_status(self, *, slave: int = 1, no_response_expected: bool = False) -> T: + def read_exception_status(self, *, device_id: int = 1, no_response_expected: bool = False) -> T: """Read Exception Status (code 0x07). - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: @@ -183,13 +183,13 @@ def read_exception_status(self, *, slave: int = 1, no_response_expected: bool = accessing this information, because the Exception Output references are known (no output reference is needed in the function). """ - return self.execute(no_response_expected, pdu_other_msg.ReadExceptionStatusRequest(dev_id=slave)) + return self.execute(no_response_expected, pdu_other_msg.ReadExceptionStatusRequest(dev_id=device_id)) - def diag_query_data(self, msg: bytes, *, slave: int = 1, no_response_expected: bool = False) -> T: + def diag_query_data(self, msg: bytes, *, device_id: int = 1, no_response_expected: bool = False) -> T: """Diagnose query data (code 0x08 sub 0x00). :param msg: Message to be returned - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: @@ -197,13 +197,13 @@ def diag_query_data(self, msg: bytes, *, slave: int = 1, no_response_expected: b in the response. The entire response message should be identical to the request. """ - return self.execute(no_response_expected, pdu_diag.ReturnQueryDataRequest(msg, dev_id=slave)) + return self.execute(no_response_expected, pdu_diag.ReturnQueryDataRequest(msg, dev_id=device_id)) - def diag_restart_communication(self, toggle: bool, *, slave: int = 1, no_response_expected: bool = False) -> T: + def diag_restart_communication(self, toggle: bool, *, device_id: int = 1, no_response_expected: bool = False) -> T: """Diagnose restart communication (code 0x08 sub 0x01). :param toggle: True if toggled. - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: @@ -215,24 +215,24 @@ def diag_restart_communication(self, toggle: bool, *, slave: int = 1, no_respons occurs before the restart is update_datastored. """ msg = ModbusStatus.ON if toggle else ModbusStatus.OFF - return self.execute(no_response_expected, pdu_diag.RestartCommunicationsOptionRequest(message=msg, dev_id=slave)) + return self.execute(no_response_expected, pdu_diag.RestartCommunicationsOptionRequest(message=msg, dev_id=device_id)) - def diag_read_diagnostic_register(self, *, slave: int = 1, no_response_expected: bool = False) -> T: + def diag_read_diagnostic_register(self, *, device_id: int = 1, no_response_expected: bool = False) -> T: """Diagnose read diagnostic register (code 0x08 sub 0x02). - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: The contents of the remote device's 16-bit diagnostic register are returned in the response. """ - return self.execute(no_response_expected, pdu_diag.ReturnDiagnosticRegisterRequest(dev_id=slave)) + return self.execute(no_response_expected, pdu_diag.ReturnDiagnosticRegisterRequest(dev_id=device_id)) - def diag_change_ascii_input_delimeter(self, *, delimiter: int = 0x0a, slave: int = 1, no_response_expected: bool = False) -> T: + def diag_change_ascii_input_delimeter(self, *, delimiter: int = 0x0a, device_id: int = 1, no_response_expected: bool = False) -> T: """Diagnose change ASCII input delimiter (code 0x08 sub 0x03). :param delimiter: char to replace LF - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: @@ -241,12 +241,12 @@ def diag_change_ascii_input_delimeter(self, *, delimiter: int = 0x0a, slave: int character). This function is useful in cases of a Line Feed is not required at the end of ASCII messages. """ - return self.execute(no_response_expected, pdu_diag.ChangeAsciiInputDelimiterRequest(message=delimiter, dev_id=slave)) + return self.execute(no_response_expected, pdu_diag.ChangeAsciiInputDelimiterRequest(message=delimiter, dev_id=device_id)) - def diag_force_listen_only(self, *, slave: int = 1, no_response_expected: bool = False) -> T: + def diag_force_listen_only(self, *, device_id: int = 1, no_response_expected: bool = False) -> T: """Diagnose force listen only (code 0x08 sub 0x04). - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: @@ -256,23 +256,23 @@ def diag_force_listen_only(self, *, slave: int = 1, no_response_expected: bool = allowing them to continue communicating without interruption from the addressed remote device. No response is returned. """ - return self.execute(no_response_expected, pdu_diag.ForceListenOnlyModeRequest(dev_id=slave)) + return self.execute(no_response_expected, pdu_diag.ForceListenOnlyModeRequest(dev_id=device_id)) - def diag_clear_counters(self, *, slave: int = 1, no_response_expected: bool = False) -> T: + def diag_clear_counters(self, *, device_id: int = 1, no_response_expected: bool = False) -> T: """Diagnose clear counters (code 0x08 sub 0x0A). - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: Clear ll counters and the diagnostic register. Also, counters are cleared upon power-up """ - return self.execute(no_response_expected, pdu_diag.ClearCountersRequest(dev_id=slave)) + return self.execute(no_response_expected, pdu_diag.ClearCountersRequest(dev_id=device_id)) - def diag_read_bus_message_count(self, *, slave: int = 1, no_response_expected: bool = False) -> T: + def diag_read_bus_message_count(self, *, device_id: int = 1, no_response_expected: bool = False) -> T: """Diagnose read bus message count (code 0x08 sub 0x0B). - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: @@ -280,12 +280,12 @@ def diag_read_bus_message_count(self, *, slave: int = 1, no_response_expected: b remote device has detected on the communications systems since its last restart, clear counters operation, or power-up """ - return self.execute(no_response_expected, pdu_diag.ReturnBusMessageCountRequest(dev_id=slave)) + return self.execute(no_response_expected, pdu_diag.ReturnBusMessageCountRequest(dev_id=device_id)) - def diag_read_bus_comm_error_count(self, *, slave: int = 1, no_response_expected: bool = False) -> T: + def diag_read_bus_comm_error_count(self, *, device_id: int = 1, no_response_expected: bool = False) -> T: """Diagnose read Bus Communication Error Count (code 0x08 sub 0x0C). - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: @@ -293,12 +293,12 @@ def diag_read_bus_comm_error_count(self, *, slave: int = 1, no_response_expected by the remote device since its last restart, clear counter operation, or power-up """ - return self.execute(no_response_expected, pdu_diag.ReturnBusCommunicationErrorCountRequest(dev_id=slave)) + return self.execute(no_response_expected, pdu_diag.ReturnBusCommunicationErrorCountRequest(dev_id=device_id)) - def diag_read_bus_exception_error_count(self, *, slave: int = 1, no_response_expected: bool = False) -> T: + def diag_read_bus_exception_error_count(self, *, device_id: int = 1, no_response_expected: bool = False) -> T: """Diagnose read Bus Exception Error Count (code 0x08 sub 0x0D). - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: @@ -306,12 +306,12 @@ def diag_read_bus_exception_error_count(self, *, slave: int = 1, no_response_exp responses returned by the remote device since its last restart, clear counters operation, or power-up """ - return self.execute(no_response_expected, pdu_diag.ReturnBusExceptionErrorCountRequest(dev_id=slave)) + return self.execute(no_response_expected, pdu_diag.ReturnBusExceptionErrorCountRequest(dev_id=device_id)) - def diag_read_slave_message_count(self, *, slave: int = 1, no_response_expected: bool = False) -> T: - """Diagnose read Slave Message Count (code 0x08 sub 0x0E). + def diag_read_device_message_count(self, *, device_id: int = 1, no_response_expected: bool = False) -> T: + """Diagnose read device Message Count (code 0x08 sub 0x0E). - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: @@ -319,12 +319,12 @@ def diag_read_slave_message_count(self, *, slave: int = 1, no_response_expected: remote device, that the remote device has processed since its last restart, clear counters operation, or power-up """ - return self.execute(no_response_expected, pdu_diag.ReturnSlaveMessageCountRequest(dev_id=slave)) + return self.execute(no_response_expected, pdu_diag.ReturnDeviceMessageCountRequest(dev_id=device_id)) - def diag_read_slave_no_response_count(self, *, slave: int = 1, no_response_expected: bool = False) -> T: - """Diagnose read Slave No Response Count (code 0x08 sub 0x0F). + def diag_read_device_no_response_count(self, *, device_id: int = 1, no_response_expected: bool = False) -> T: + """Diagnose read device No Response Count (code 0x08 sub 0x0F). - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: @@ -332,12 +332,12 @@ def diag_read_slave_no_response_count(self, *, slave: int = 1, no_response_expec remote device, that the remote device has processed since its last restart, clear counters operation, or power-up. """ - return self.execute(no_response_expected, pdu_diag.ReturnSlaveNoResponseCountRequest(dev_id=slave)) + return self.execute(no_response_expected, pdu_diag.ReturnDeviceNoResponseCountRequest(dev_id=device_id)) - def diag_read_slave_nak_count(self, *, slave: int = 1, no_response_expected: bool = False) -> T: - """Diagnose read Slave NAK Count (code 0x08 sub 0x10). + def diag_read_device_nak_count(self, *, device_id: int = 1, no_response_expected: bool = False) -> T: + """Diagnose read device NAK Count (code 0x08 sub 0x10). - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: @@ -346,25 +346,25 @@ def diag_read_slave_nak_count(self, *, slave: int = 1, no_response_expected: boo response, since its last restart, clear counters operation, or power-up. Exception responses are described and listed in section 7 . """ - return self.execute(no_response_expected, pdu_diag.ReturnSlaveNAKCountRequest(dev_id=slave)) + return self.execute(no_response_expected, pdu_diag.ReturnDeviceNAKCountRequest(dev_id=device_id)) - def diag_read_slave_busy_count(self, *, slave: int = 1, no_response_expected: bool = False) -> T: - """Diagnose read Slave Busy Count (code 0x08 sub 0x11). + def diag_read_device_busy_count(self, *, device_id: int = 1, no_response_expected: bool = False) -> T: + """Diagnose read device Busy Count (code 0x08 sub 0x11). - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: The response data field returns the quantity of messages addressed to the - remote device for which it returned a Slave Device Busy exception response, + remote device for which it returned device Busy exception response, since its last restart, clear counters operation, or power-up. """ - return self.execute(no_response_expected, pdu_diag.ReturnSlaveBusyCountRequest(dev_id=slave)) + return self.execute(no_response_expected, pdu_diag.ReturnDeviceBusyCountRequest(dev_id=device_id)) - def diag_read_bus_char_overrun_count(self, *, slave: int = 1, no_response_expected: bool = False) -> T: + def diag_read_bus_char_overrun_count(self, *, device_id: int = 1, no_response_expected: bool = False) -> T: """Diagnose read Bus Character Overrun Count (code 0x08 sub 0x12). - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: @@ -374,12 +374,12 @@ def diag_read_bus_char_overrun_count(self, *, slave: int = 1, no_response_expect overrun is caused by data characters arriving at the port faster than they can be stored, or by the loss of a character due to a hardware malfunction. """ - return self.execute(no_response_expected, pdu_diag.ReturnSlaveBusCharacterOverrunCountRequest(dev_id=slave)) + return self.execute(no_response_expected, pdu_diag.ReturnDeviceBusCharacterOverrunCountRequest(dev_id=device_id)) - def diag_read_iop_overrun_count(self, *, slave: int = 1, no_response_expected: bool = False) -> T: + def diag_read_iop_overrun_count(self, *, device_id: int = 1, no_response_expected: bool = False) -> T: """Diagnose read Iop overrun count (code 0x08 sub 0x13). - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: @@ -387,25 +387,25 @@ def diag_read_iop_overrun_count(self, *, slave: int = 1, no_response_expected: b faster than they can be stored, or by the loss of a character due to a hardware malfunction. This function is specific to the 884. """ - return self.execute(no_response_expected, pdu_diag.ReturnIopOverrunCountRequest(dev_id=slave)) + return self.execute(no_response_expected, pdu_diag.ReturnIopOverrunCountRequest(dev_id=device_id)) - def diag_clear_overrun_counter(self, *, slave: int = 1, no_response_expected: bool = False) -> T: + def diag_clear_overrun_counter(self, *, device_id: int = 1, no_response_expected: bool = False) -> T: """Diagnose Clear Overrun Counter and Flag (code 0x08 sub 0x14). - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: An error flag should be cleared, but nothing else in the specification mentions is, so it is ignored. """ - return self.execute(no_response_expected, pdu_diag.ClearOverrunCountRequest(dev_id=slave)) + return self.execute(no_response_expected, pdu_diag.ClearOverrunCountRequest(dev_id=device_id)) - def diag_getclear_modbus_response(self, *, data: int = 0, slave: int = 1, no_response_expected: bool = False) -> T: + def diag_getclear_modbus_response(self, *, data: int = 0, device_id: int = 1, no_response_expected: bool = False) -> T: """Diagnose Get/Clear modbus plus (code 0x08 sub 0x15). :param data: "Get Statistics" or "Clear Statistics" - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: @@ -415,15 +415,14 @@ def diag_getclear_modbus_response(self, *, data: int = 0, slave: int = 1, no_res operation. The two operations are exclusive - the "Get" operation cannot clear the statistics, and the "Clear" operation does not return statistics prior to clearing - them. Statistics are also cleared on power-up of the slave - device. + them. Statistics are also cleared on power-up of the device, """ - return self.execute(no_response_expected, pdu_diag.GetClearModbusPlusRequest(message=data, dev_id=slave)) + return self.execute(no_response_expected, pdu_diag.GetClearModbusPlusRequest(message=data, dev_id=device_id)) - def diag_get_comm_event_counter(self, *, slave: int = 1, no_response_expected: bool = False) -> T: + def diag_get_comm_event_counter(self, *, device_id: int = 1, no_response_expected: bool = False) -> T: """Diagnose get event counter (code 0x0B). - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: @@ -440,12 +439,12 @@ def diag_get_comm_event_counter(self, *, slave: int = 1, no_response_expected: b The event counter can be reset by means of the Diagnostics function Restart Communications or Clear Counters and Diagnostic Register. """ - return self.execute(no_response_expected, pdu_other_msg.GetCommEventCounterRequest(dev_id=slave)) + return self.execute(no_response_expected, pdu_other_msg.GetCommEventCounterRequest(dev_id=device_id)) - def diag_get_comm_event_log(self, *, slave: int = 1, no_response_expected: bool = False) -> T: + def diag_get_comm_event_log(self, *, device_id: int = 1, no_response_expected: bool = False) -> T: """Diagnose get event counter (code 0x0C). - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: @@ -467,21 +466,21 @@ def diag_get_comm_event_log(self, *, slave: int = 1, no_response_expected: bool chronological order. Byte 0 is the most recent event. Each new byte flushes the oldest byte from the field. """ - return self.execute(no_response_expected, pdu_other_msg.GetCommEventLogRequest(dev_id=slave)) + return self.execute(no_response_expected, pdu_other_msg.GetCommEventLogRequest(dev_id=device_id)) def write_coils( self, address: int, values: list[bool], *, - slave: int = 1, + device_id: int = 1, no_response_expected: bool = False ) -> T: """Write coils (code 0x0F). :param address: Start address to write to :param values: List of booleans to write, or a single boolean to write - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: @@ -489,7 +488,7 @@ def write_coils( Coils are addressed as 0-N (Note some device manuals uses 1-N, assuming 1==0). """ - pdu = pdu_bit.WriteMultipleCoilsRequest(address=address, bits=values, dev_id=slave) + pdu = pdu_bit.WriteMultipleCoilsRequest(address=address, bits=values, dev_id=device_id) return self.execute(no_response_expected, pdu) def write_registers( @@ -497,39 +496,39 @@ def write_registers( address: int, values: list[int], *, - slave: int = 1, + device_id: int = 1, no_response_expected: bool = False ) -> T: """Write registers (code 0x10). :param address: Start address to write to :param values: List of values to write - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: This function is used to write a block of contiguous registers (1 to approx. 120 registers) in a remote device. """ - return self.execute(no_response_expected, pdu_reg.WriteMultipleRegistersRequest(address=address, registers=values,dev_id=slave)) + return self.execute(no_response_expected, pdu_reg.WriteMultipleRegistersRequest(address=address, registers=values,dev_id=device_id)) - def report_slave_id(self, *, slave: int = 1, no_response_expected: bool = False) -> T: - """Report slave ID (code 0x11). + def report_device_id(self, *, device_id: int = 1, no_response_expected: bool = False) -> T: + """Report device ID (code 0x11). - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: This function is used to read the description of the type, the current status and other information specific to a remote device. """ - return self.execute(no_response_expected, pdu_other_msg.ReportSlaveIdRequest(dev_id=slave)) + return self.execute(no_response_expected, pdu_other_msg.ReportDeviceIdRequest(dev_id=device_id)) - def read_file_record(self, records: list[pdu_file_msg.FileRecord], *, slave: int = 1, no_response_expected: bool = False) -> T: + def read_file_record(self, records: list[pdu_file_msg.FileRecord], *, device_id: int = 1, no_response_expected: bool = False) -> T: """Read file record (code 0x14). :param records: List of FileRecord (Reference type, File number, Record Number) - :param slave: device id + :param device_id: device id :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: @@ -553,13 +552,13 @@ def read_file_record(self, records: list[pdu_file_msg.FileRecord], *, slave: int in the expected response, must not exceed the allowable length of the MODBUS PDU: 235 bytes. """ - return self.execute(no_response_expected, pdu_file_msg.ReadFileRecordRequest(records, dev_id=slave)) + return self.execute(no_response_expected, pdu_file_msg.ReadFileRecordRequest(records, dev_id=device_id)) - def write_file_record(self, records: list[pdu_file_msg.FileRecord], *, slave: int = 1, no_response_expected: bool = False) -> T: + def write_file_record(self, records: list[pdu_file_msg.FileRecord], *, device_id: int = 1, no_response_expected: bool = False) -> T: """Write file record (code 0x15). :param records: List of File_record (Reference type, File number, Record Number, Record Length, Record Data) - :param slave: (optional) Device id + :param device_id: (optional) Device id :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: @@ -568,7 +567,7 @@ def write_file_record(self, records: list[pdu_file_msg.FileRecord], *, slave: in and all record lengths are provided in terms of the number of 16 bit words. """ - return self.execute(no_response_expected, pdu_file_msg.WriteFileRecordRequest(records=records, dev_id=slave)) + return self.execute(no_response_expected, pdu_file_msg.WriteFileRecordRequest(records=records, dev_id=device_id)) def mask_write_register( self, @@ -576,7 +575,7 @@ def mask_write_register( address: int = 0x0000, and_mask: int = 0xFFFF, or_mask: int = 0x0000, - slave: int = 1, + device_id: int = 1, no_response_expected: bool = False ) -> T: """Mask write register (code 0x16). @@ -584,7 +583,7 @@ def mask_write_register( :param address: The mask pointer address (0x0000 to 0xffff) :param and_mask: The and bitmask to apply to the register address :param or_mask: The or bitmask to apply to the register address - :param slave: (optional) device id + :param device_id: (optional) device id :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: @@ -593,7 +592,7 @@ def mask_write_register( The function can be used to set or clear individual bits in the register. """ - return self.execute(no_response_expected, pdu_reg.MaskWriteRegisterRequest(address=address, and_mask=and_mask, or_mask=or_mask, dev_id=slave)) + return self.execute(no_response_expected, pdu_reg.MaskWriteRegisterRequest(address=address, and_mask=and_mask, or_mask=or_mask, dev_id=device_id)) def readwrite_registers( self, @@ -603,7 +602,7 @@ def readwrite_registers( write_address: int = 0, address: int | None = None, values: list[int] | None = None, - slave: int = 1, + device_id: int = 1, no_response_expected: bool = False ) -> T: """Read/Write registers (code 0x17). @@ -613,7 +612,7 @@ def readwrite_registers( :param write_address: The address to start writing to :param address: (optional) use as read/write address :param values: List of values to write, or a single value to write - :param slave: (optional) Modbus slave ID + :param device_id: (optional) Modbus device ID :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: @@ -629,13 +628,13 @@ def readwrite_registers( if address: read_address = address write_address = address - return self.execute(no_response_expected, pdu_reg.ReadWriteMultipleRegistersRequest( read_address=read_address, read_count=read_count, write_address=write_address, write_registers=values,dev_id=slave)) + return self.execute(no_response_expected, pdu_reg.ReadWriteMultipleRegistersRequest( read_address=read_address, read_count=read_count, write_address=write_address, write_registers=values,dev_id=device_id)) - def read_fifo_queue(self, *, address: int = 0x0000, slave: int = 1, no_response_expected: bool = False) -> T: + def read_fifo_queue(self, *, address: int = 0x0000, device_id: int = 1, no_response_expected: bool = False) -> T: """Read FIFO queue (code 0x18). :param address: The address to start reading from - :param slave: (optional) device id + :param device_id: (optional) device id :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: @@ -649,19 +648,19 @@ def read_fifo_queue(self, *, address: int = 0x0000, slave: int = 1, no_response_ registers. The function reads the queue contents, but does not clear them. """ - return self.execute(no_response_expected, pdu_file_msg.ReadFifoQueueRequest(address, dev_id=slave)) + return self.execute(no_response_expected, pdu_file_msg.ReadFifoQueueRequest(address, dev_id=device_id)) # code 0x2B sub 0x0D: CANopen General Reference Request and Response, NOT IMPLEMENTED def read_device_information(self, *, read_code: int | None = None, object_id: int = 0x00, - slave: int = 1, + device_id: int = 1, no_response_expected: bool = False) -> T: """Read FIFO queue (code 0x2B sub 0x0E). :param read_code: The device information read code :param object_id: The object to read from - :param slave: (optional) Device id + :param device_id: (optional) Device id :param no_response_expected: (optional) The client will not expect a response to the request :raises ModbusException: @@ -673,7 +672,7 @@ def read_device_information(self, *, read_code: int | None = None, composed of a set of addressable data elements. The data elements are called objects and an object Id identifies them. """ - return self.execute(no_response_expected, pdu_mei.ReadDeviceInformationRequest(read_code, object_id, dev_id=slave)) + return self.execute(no_response_expected, pdu_mei.ReadDeviceInformationRequest(read_code, object_id, dev_id=device_id)) # ------------------ # Converter methods diff --git a/pymodbus/client/tcp.py b/pymodbus/client/tcp.py index 633fb3f16..fb08076bd 100644 --- a/pymodbus/client/tcp.py +++ b/pymodbus/client/tcp.py @@ -270,7 +270,7 @@ def recv(self, size: int | None) -> bytes: break # Timeout is reduced also if some data has been received in order # to avoid infinite loops when there isn't an expected response - # size and the slave sends noisy data continuously. + # size and the device sends noisy data continuously. if time_ > end: break @@ -306,7 +306,7 @@ def _handle_abrupt_socket_close(self, size: int | None, data: list[bytes], durat result = b"".join(data) Log.warning(" after returning {} bytes: {} ", len(result), result) return result - msg += " without response from slave before it closed connection" + msg += " without response from device before it closed connection" raise ConnectionException(msg) def is_socket_open(self) -> bool: diff --git a/pymodbus/constants.py b/pymodbus/constants.py index 446defe9a..472c70e4c 100644 --- a/pymodbus/constants.py +++ b/pymodbus/constants.py @@ -29,22 +29,12 @@ class ModbusStatus(int, enum.Enum): .. attribute:: OFF This indicates that the given modbus entity is off - - .. attribute:: SLAVE_ON - - This indicates that the given modbus slave is running - - .. attribute:: SLAVE_OFF - - This indicates that the given modbus slave is not running """ WAITING = 0xFFFF READY = 0x0000 ON = 0xFF00 OFF = 0x0000 - SLAVE_ON = 0xFF - SLAVE_OFF = 0x00 class Endian(str, enum.Enum): diff --git a/pymodbus/datastore/__init__.py b/pymodbus/datastore/__init__.py index abd350601..ac000986a 100644 --- a/pymodbus/datastore/__init__.py +++ b/pymodbus/datastore/__init__.py @@ -1,18 +1,18 @@ """Datastore.""" __all__ = [ - "ModbusBaseSlaveContext", + "ModbusBaseDeviceContext", + "ModbusDeviceContext", "ModbusSequentialDataBlock", "ModbusServerContext", "ModbusSimulatorContext", - "ModbusSlaveContext", "ModbusSparseDataBlock", ] from pymodbus.datastore.context import ( - ModbusBaseSlaveContext, + ModbusBaseDeviceContext, + ModbusDeviceContext, ModbusServerContext, - ModbusSlaveContext, ) from pymodbus.datastore.simulator import ModbusSimulatorContext from pymodbus.datastore.store import ( diff --git a/pymodbus/datastore/context.py b/pymodbus/datastore/context.py index e18b268bb..c8b624916 100644 --- a/pymodbus/datastore/context.py +++ b/pymodbus/datastore/context.py @@ -6,12 +6,12 @@ # pylint: disable=missing-type-doc from pymodbus.datastore.store import ModbusSequentialDataBlock -from pymodbus.exceptions import NoSuchSlaveException +from pymodbus.exceptions import NoSuchIdException from pymodbus.logging import Log -class ModbusBaseSlaveContext: - """Interface for a modbus slave data context. +class ModbusBaseDeviceContext: + """Interface for a modbus device data context. Derived classes must implemented the following methods: reset(self) @@ -71,9 +71,9 @@ def setValues(self, fc_as_hex: int, address: int, values: Sequence[int | bool]) # ---------------------------------------------------------------------------# -# Slave Contexts +# Device Contexts # ---------------------------------------------------------------------------# -class ModbusSlaveContext(ModbusBaseSlaveContext): +class ModbusDeviceContext(ModbusBaseDeviceContext): """Create a modbus data model with data stored in a block. :param di: discrete inputs initializer ModbusDataBlock @@ -100,7 +100,7 @@ def __str__(self): :returns: A string representation of the context """ - return "Modbus Slave Context" + return "Modbus device Context" def reset(self): """Reset all the datastores to their default values.""" @@ -131,7 +131,7 @@ def setValues(self, fc_as_hex, address, values): self.store[self.decode(fc_as_hex)].setValues(address, values) def register(self, function_code, fc_as_hex, datablock=None): - """Register a datablock with the slave context. + """Register a datablock with the device context. :param function_code: function code (int) :param fc_as_hex: string representation of function code (e.g "cf" ) @@ -142,83 +142,82 @@ def register(self, function_code, fc_as_hex, datablock=None): class ModbusServerContext: - """This represents a master collection of slave contexts. + """This represents a master collection of device contexts. If single is set to true, it will be treated as a single context so every device id returns the same context. If single is set to false, it will be interpreted as a collection of - slave contexts. + device contexts. """ - def __init__(self, slaves=None, single=True): + def __init__(self, devices=None, single=True): """Initialize a new instance of a modbus server context. - :param slaves: A dictionary of client contexts + :param devices: A dictionary of client contexts :param single: Set to true to treat this as a single context """ self.single = single - self._slaves = slaves or {} + self._devices = devices or {} if self.single: - self._slaves = {0: self._slaves} + self._devices = {0: self._devices} def __iter__(self): - """Iterate over the current collection of slave contexts. + """Iterate over the current collection of device contexts. - :returns: An iterator over the slave contexts + :returns: An iterator over the device contexts """ - return iter(self._slaves.items()) + return iter(self._devices.items()) - def __contains__(self, slave): - """Check if the given slave is in this list. + def __contains__(self, device_id): + """Check if the given device_id is in this list. - :param slave: slave The slave to check for existence - :returns: True if the slave exists, False otherwise + :param device_id: device_id The device_id to check for existence + :returns: True if the device_id exists, False otherwise """ - if self.single and self._slaves: + if self.single and self._devices: return True - return slave in self._slaves + return device_id in self._devices - def __setitem__(self, slave, context): - """Use to set a new slave context. + def __setitem__(self, device_id, context): + """Use to set a new device_id context. - :param slave: The slave context to set - :param context: The new context to set for this slave - :raises NoSuchSlaveException: + :param device_id: The device_id context to set + :param context: The new context to set for this device_id + :raises NoSuchIdException: """ if self.single: - slave = 0 - if 0xF7 >= slave >= 0x00: - self._slaves[slave] = context + device_id = 0 + if 0xF7 >= device_id >= 0x00: + self._devices[device_id] = context else: - raise NoSuchSlaveException(f"slave index :{slave} out of range") + raise NoSuchIdException(f"device_id index :{device_id} out of range") - def __delitem__(self, slave): - """Use to access the slave context. + def __delitem__(self, device_id): + """Use to access the device_id context. - :param slave: The slave context to remove - :raises NoSuchSlaveException: + :param device_id: The device context to remove + :raises NoSuchIdException: """ - if not self.single and (0xF7 >= slave >= 0x00): - del self._slaves[slave] + if not self.single and (0xF7 >= device_id >= 0x00): + del self._devices[device_id] else: - raise NoSuchSlaveException(f"slave index: {slave} out of range") + raise NoSuchIdException(f"device_id index: {device_id} out of range") - def __getitem__(self, slave): - """Use to get access to a slave context. + def __getitem__(self, device_id): + """Use to get access to a device_id context. - :param slave: The slave context to get - :returns: The requested slave context - :raises NoSuchSlaveException: + :param device_id: The device context to get + :returns: The requested device context + :raises NoSuchIdException: """ if self.single: - slave = 0 - if slave in self._slaves: - return self._slaves.get(slave) - raise NoSuchSlaveException( - f"slave - {slave} does not exist, or is out of range" + device_id = 0 + if device_id in self._devices: + return self._devices.get(device_id) + raise NoSuchIdException( + f"device_id - {device_id} does not exist, or is out of range" ) - def slaves(self): - """Define slaves.""" - # Python3 now returns keys() as iterable - return list(self._slaves.keys()) + def device_ids(self): + """Define device_ids.""" + return list(self._devices.keys()) diff --git a/pymodbus/datastore/remote.py b/pymodbus/datastore/remote.py index ffd6833eb..02d0ebf08 100644 --- a/pymodbus/datastore/remote.py +++ b/pymodbus/datastore/remote.py @@ -1,5 +1,5 @@ """Remote datastore.""" -from pymodbus.datastore import ModbusBaseSlaveContext +from pymodbus.datastore import ModbusBaseDeviceContext from pymodbus.exceptions import NotImplementedException from pymodbus.logging import Log @@ -7,21 +7,21 @@ # ---------------------------------------------------------------------------# # Context # ---------------------------------------------------------------------------# -class RemoteSlaveContext(ModbusBaseSlaveContext): +class RemoteDeviceContext(ModbusBaseDeviceContext): """TODO. This creates a modbus data model that connects to a remote device (depending on the client used) """ - def __init__(self, client, slave=None): + def __init__(self, client, device_id=None): """Initialize the datastores. :param client: The client to retrieve values with - :param slave: Unit ID of the remote slave + :param device_id: Unit ID of the remote device """ self._client = client - self.slave = slave + self.device_id = device_id self.result = None self.__build_mapping() if not self.__set_callbacks: @@ -58,13 +58,13 @@ def __str__(self): :returns: A string representation of the context """ - return f"Remote Slave Context({self._client})" + return f"Remote Device Context({self._client})" def __build_mapping(self): """Build the function code mapper.""" params = {} - if self.slave: - params["slave"] = self.slave + if self.device_id: + params["device_id"] = self.device_id self.__get_callbacks = { "d": lambda a, c: self._client.read_discrete_inputs( a, count=c, **params diff --git a/pymodbus/datastore/simulator.py b/pymodbus/datastore/simulator.py index fd3802604..42e7ecb02 100644 --- a/pymodbus/datastore/simulator.py +++ b/pymodbus/datastore/simulator.py @@ -8,7 +8,7 @@ from datetime import datetime from typing import Any -from pymodbus.datastore.context import ModbusBaseSlaveContext +from pymodbus.datastore.context import ModbusBaseDeviceContext WORD_SIZE = 16 @@ -373,7 +373,7 @@ def setup(self, config, custom_actions) -> None: raise RuntimeError(f"INVALID key in setup: {self.config}") -class ModbusSimulatorContext(ModbusBaseSlaveContext): +class ModbusSimulatorContext(ModbusBaseDeviceContext): """Modbus simulator. :param config: A dict with structure as shown below. diff --git a/pymodbus/exceptions.py b/pymodbus/exceptions.py index 7c685879b..89e219d02 100644 --- a/pymodbus/exceptions.py +++ b/pymodbus/exceptions.py @@ -8,7 +8,7 @@ "InvalidMessageReceivedException", "MessageRegisterException", "ModbusIOException", - "NoSuchSlaveException", + "NoSuchIdException", "NotImplementedException", "ParameterException", ] @@ -59,15 +59,15 @@ def __init__(self, string=""): ModbusException.__init__(self, message) -class NoSuchSlaveException(ModbusException): - """Error resulting from making a request to a slave that does not exist.""" +class NoSuchIdException(ModbusException): + """Error resulting from making a request to a id that does not exist.""" def __init__(self, string=""): """Initialize the exception. :param string: The message to append to the error """ - message = f"[No Such Slave] {string}" + message = f"[No Such id] {string}" ModbusException.__init__(self, message) diff --git a/pymodbus/framer/rtu.py b/pymodbus/framer/rtu.py index 77321ec20..ebe130b9a 100644 --- a/pymodbus/framer/rtu.py +++ b/pymodbus/framer/rtu.py @@ -24,25 +24,25 @@ class FramerRTU(FramerBase): For client: - a request causes 1 response ! - - Multiple requests are NOT allowed (master-slave protocol) + - Multiple requests are NOT allowed (master controlled protocol) - the server will not retransmit responses this means decoding is always exactly 1 frame (response) For server (Single device) - - only 1 request allowed (master-slave) protocol + - only 1 request allowed (master controlled protocol) - the client (master) may retransmit but in larger time intervals this means decoding is always exactly 1 frame (request) For server (Multidrop line --> devices in parallel) - - only 1 request allowed (master-slave) protocol + - only 1 request allowed (master controlled protocol) - other devices will send responses - the client (master) may retransmit but in larger time intervals this means decoding is always exactly 1 frame request, however some requests - will be for unknown slaves, which must be ignored together with the - response from the unknown slave. + will be for unknown devices, which must be ignored together with the + response from the unknown device. Recovery from bad cabling and unstable USB etc is important, the following scenarios is possible: @@ -78,7 +78,7 @@ class FramerRTU(FramerBase): """ - MIN_SIZE = 4 # + MIN_SIZE = 4 # @classmethod def generate_crc16_table(cls) -> list[int]: diff --git a/pymodbus/pdu/bit_message.py b/pymodbus/pdu/bit_message.py index 723ac6e10..5bf3cacad 100644 --- a/pymodbus/pdu/bit_message.py +++ b/pymodbus/pdu/bit_message.py @@ -4,7 +4,7 @@ from typing import cast from pymodbus.constants import ModbusStatus -from pymodbus.datastore import ModbusSlaveContext +from pymodbus.datastore import ModbusDeviceContext from pymodbus.pdu.pdu import ModbusPDU from pymodbus.utilities import pack_bitstring, unpack_bitstring @@ -33,7 +33,7 @@ def get_response_pdu_size(self) -> int: """ return 1 + 1 + (self.count + 7) // 8 - async def update_datastore(self, context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, context: ModbusDeviceContext) -> ModbusPDU: """Run request against a datastore.""" values = await context.async_getValues( self.function_code, self.address, self.count @@ -91,7 +91,7 @@ def decode(self, data: bytes) -> None: class WriteSingleCoilRequest(WriteSingleCoilResponse): """WriteSingleCoilRequest.""" - async def update_datastore(self, context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, context: ModbusDeviceContext) -> ModbusPDU: """Run a request against a datastore.""" await context.async_setValues(self.function_code, self.address, self.bits) values = cast(list[bool], await context.async_getValues(self.function_code, self.address, 1)) @@ -124,7 +124,7 @@ def decode(self, data: bytes) -> None: self.address, count, _byte_count = struct.unpack(">HHB", data[0:5]) self.bits = unpack_bitstring(data[5:])[:count] - async def update_datastore(self, context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, context: ModbusDeviceContext) -> ModbusPDU: """Run a request against a datastore.""" count = len(self.bits) await context.async_setValues( diff --git a/pymodbus/pdu/decoders.py b/pymodbus/pdu/decoders.py index 27a4d5d42..606534d2a 100644 --- a/pymodbus/pdu/decoders.py +++ b/pymodbus/pdu/decoders.py @@ -29,7 +29,7 @@ class DecodePDU: (o_msg.ReadExceptionStatusRequest, o_msg.ReadExceptionStatusResponse), (o_msg.GetCommEventCounterRequest, o_msg.GetCommEventCounterResponse), (o_msg.GetCommEventLogRequest, o_msg.GetCommEventLogResponse), - (o_msg.ReportSlaveIdRequest, o_msg.ReportSlaveIdResponse), + (o_msg.ReportDeviceIdRequest, o_msg.ReportDeviceIdResponse), (file_msg.ReadFileRecordRequest, file_msg.ReadFileRecordResponse), (file_msg.WriteFileRecordRequest, file_msg.WriteFileRecordResponse), (reg_msg.MaskWriteRegisterRequest, reg_msg.MaskWriteRegisterResponse), @@ -47,11 +47,11 @@ class DecodePDU: (diag_msg.ReturnBusMessageCountRequest, diag_msg.ReturnBusMessageCountResponse), (diag_msg.ReturnBusCommunicationErrorCountRequest, diag_msg.ReturnBusCommunicationErrorCountResponse), (diag_msg.ReturnBusExceptionErrorCountRequest, diag_msg.ReturnBusExceptionErrorCountResponse), - (diag_msg.ReturnSlaveMessageCountRequest, diag_msg.ReturnSlaveMessageCountResponse), - (diag_msg.ReturnSlaveNoResponseCountRequest, diag_msg.ReturnSlaveNoResponseCountResponse), - (diag_msg.ReturnSlaveNAKCountRequest, diag_msg.ReturnSlaveNAKCountResponse), - (diag_msg.ReturnSlaveBusyCountRequest, diag_msg.ReturnSlaveBusyCountResponse), - (diag_msg.ReturnSlaveBusCharacterOverrunCountRequest, diag_msg.ReturnSlaveBusCharacterOverrunCountResponse), + (diag_msg.ReturnDeviceMessageCountRequest, diag_msg.ReturnDeviceMessageCountResponse), + (diag_msg.ReturnDeviceNoResponseCountRequest, diag_msg.ReturnDeviceNoResponseCountResponse), + (diag_msg.ReturnDeviceNAKCountRequest, diag_msg.ReturnDeviceNAKCountResponse), + (diag_msg.ReturnDeviceBusyCountRequest, diag_msg.ReturnDeviceBusyCountResponse), + (diag_msg.ReturnDeviceBusCharacterOverrunCountRequest, diag_msg.ReturnDeviceBusCharacterOverrunCountResponse), (diag_msg.ReturnIopOverrunCountRequest, diag_msg.ReturnIopOverrunCountResponse), (diag_msg.ClearOverrunCountRequest, diag_msg.ClearOverrunCountResponse), (diag_msg.GetClearModbusPlusRequest, diag_msg.GetClearModbusPlusResponse), diff --git a/pymodbus/device.py b/pymodbus/pdu/device.py similarity index 94% rename from pymodbus/device.py rename to pymodbus/pdu/device.py index 541369905..51c9a0213 100644 --- a/pymodbus/device.py +++ b/pymodbus/pdu/device.py @@ -19,7 +19,7 @@ from collections import OrderedDict from pymodbus.constants import INTERNAL_ERROR, DeviceInformation -from pymodbus.events import ModbusEvent +from pymodbus.pdu.events import ModbusEvent from pymodbus.utilities import dict_property @@ -46,13 +46,13 @@ class ModbusPlusStatistics: "data_master_token_failed": [0x00], # 07 lo "program_master_token_owner": [0x00], # 08 hi "data_master_token_owner": [0x00], # 08 lo - "program_slave_token_owner": [0x00], # 09 hi - "data_slave_token_owner": [0x00], # 09 lo - "data_slave_command_transfer": [0x00], # 10 hi + "program_id_token_owner": [0x00], # 09 hi + "data_id_token_owner": [0x00], # 09 lo + "data_id_command_transfer": [0x00], # 10 hi "__unused_10_lowbit": [0x00], # 10 lo - "program_slave_command_transfer": [0x00], # 11 hi + "program_id_command_transfer": [0x00], # 11 hi "program_master_rsp_transfer": [0x00], # 11 lo - "program_slave_auto_logout": [0x00], # 12 hi + "program_id_auto_logout": [0x00], # 12 hi "program_master_connect_status": [0x00], # 12 lo "receive_buffer_dma_overrun": [0x00], # 13 hi "pretransmit_deferral_error": [0x00], # 13 lo @@ -79,9 +79,9 @@ class ModbusPlusStatistics: "global_data_bit_map": [0x00] * 8, # 31-34 "receive_buffer_use_bit_map": [0x00] * 8, # 35-37 "data_master_output_path": [0x00] * 8, # 38-41 - "data_slave_input_path": [0x00] * 8, # 42-45 + "data_id_input_path": [0x00] * 8, # 42-45 "program_master_outptu_path": [0x00] * 8, # 46-49 - "program_slave_input_path": [0x00] * 8, # 50-53 + "program_id_input_path": [0x00] * 8, # 50-53 } ) @@ -320,27 +320,27 @@ class ModbusCountersHandler: not able to calculate the CRC. In such cases, this counter is also incremented. - 0x0D 3 Return Slave Exception Error Count + 0x0D 3 Return device Exception Error Count Quantity of MODBUS exception error detected by the remote device since its last restart, clear counters operation, or power-up. Exception errors are described and listed in "MODBUS Application Protocol Specification" document. - 0xOE 4 Return Slave Message Count + 0xOE 4 Return device Message Count Quantity of messages addressed to the remote device that the remote device has processed since its last restart, clear counters operation, or power-up. - 0x0F 5 Return Slave No Response Count + 0x0F 5 Return device No Response Count Quantity of messages received by the remote device for which it returned no response (neither a normal response nor an exception response), since its last restart, clear counters operation, or power-up. - 0x10 6 Return Slave NAK Count + 0x10 6 Return device NAK Count Quantity of messages addressed to the remote device for which it returned a Negative ACKNOWLEDGE (NAK) exception response, since @@ -348,10 +348,10 @@ class ModbusCountersHandler: responses are described and listed in "MODBUS Application Protocol Specification" document. - 0x11 7 Return Slave Busy Count + 0x11 7 Return device Busy Count Quantity of messages addressed to the remote device for which it - returned a Slave Device Busy exception response, since its last + returned a device Device Busy exception response, since its last restart, clear counters operation, or power-up. Exception responses are described and listed in "MODBUS Application Protocol Specification" document. @@ -371,11 +371,11 @@ class ModbusCountersHandler: __names = [ "BusMessage", "BusCommunicationError", - "SlaveExceptionError", - "SlaveMessage", - "SlaveNoResponse", - "SlaveNAK", - "SLAVE_BUSY", + "DeviceExceptionError", + "DeviceMessage", + "DeviceNoResponse", + "DeviceeNAK", + "DEVICE_BUSY", "BusCharacterOverrun", ] @@ -422,10 +422,10 @@ def summary(self): BusMessage = dict_property(lambda s: s.__data, 0) # pylint: disable=protected-access BusCommunicationError = dict_property(lambda s: s.__data, 1) # pylint: disable=protected-access BusExceptionError = dict_property(lambda s: s.__data, 2) # pylint: disable=protected-access - SlaveMessage = dict_property(lambda s: s.__data, 3) # pylint: disable=protected-access - SlaveNoResponse = dict_property(lambda s: s.__data, 4) # pylint: disable=protected-access - SlaveNAK = dict_property(lambda s: s.__data, 5) # pylint: disable=protected-access - SLAVE_BUSY = dict_property(lambda s: s.__data, 6) # pylint: disable=protected-access + DeviceMessage = dict_property(lambda s: s.__data, 3) # pylint: disable=protected-access + DeviceNoResponse = dict_property(lambda s: s.__data, 4) # pylint: disable=protected-access + DeviceNAK = dict_property(lambda s: s.__data, 5) # pylint: disable=protected-access + DEVICE_BUSY = dict_property(lambda s: s.__data, 6) # pylint: disable=protected-access BusCharacterOverrun = dict_property(lambda s: s.__data, 7) # pylint: disable=protected-access Event = dict_property(lambda s: s.__data, 8) # pylint: disable=protected-access # fmt: on diff --git a/pymodbus/pdu/diag_message.py b/pymodbus/pdu/diag_message.py index 674f367cd..1534c39a6 100644 --- a/pymodbus/pdu/diag_message.py +++ b/pymodbus/pdu/diag_message.py @@ -5,8 +5,8 @@ from typing import cast from pymodbus.constants import ModbusPlusOperation -from pymodbus.datastore import ModbusSlaveContext -from pymodbus.device import ModbusControlBlock +from pymodbus.datastore import ModbusDeviceContext +from pymodbus.pdu.device import ModbusControlBlock from pymodbus.pdu.pdu import ModbusPDU from pymodbus.utilities import pack_bitstring @@ -65,7 +65,7 @@ def get_response_pdu_size(self) -> int: """ return 1 + 2 + 2 - async def update_datastore(self, _context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, _context: ModbusDeviceContext) -> ModbusPDU: """Implement dummy.""" response = { DiagnosticBase.sub_function_code: DiagnosticBase, @@ -104,7 +104,7 @@ class ReturnDiagnosticRegisterRequest(DiagnosticBase): sub_function_code = 0x0002 - async def update_datastore(self, _context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, _context: ModbusDeviceContext) -> ModbusPDU: """update_datastore the diagnostic request on the given device.""" register = pack_bitstring(_MCB.getDiagnosticRegister()) return ReturnDiagnosticRegisterResponse(message=register, dev_id=self.dev_id, transaction_id=self.transaction_id) @@ -121,7 +121,7 @@ class ChangeAsciiInputDelimiterRequest(DiagnosticBase): sub_function_code = 0x0003 - async def update_datastore(self, _context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, _context: ModbusDeviceContext) -> ModbusPDU: """update_datastore the diagnostic request on the given device.""" char = (cast(int, self.message) & 0xFF00) >> 8 _MCB.Delimiter = char @@ -139,7 +139,7 @@ class ForceListenOnlyModeRequest(DiagnosticBase): sub_function_code = 0x0004 - async def update_datastore(self, _context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, _context: ModbusDeviceContext) -> ModbusPDU: """update_datastore the diagnostic request on the given device.""" _MCB.ListenOnly = True return ForceListenOnlyModeResponse(dev_id=self.dev_id, transaction_id=self.transaction_id) @@ -164,7 +164,7 @@ class ClearCountersRequest(DiagnosticBase): sub_function_code = 0x000A - async def update_datastore(self, _context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, _context: ModbusDeviceContext) -> ModbusPDU: """update_datastore the diagnostic request on the given device.""" _MCB.reset() return ClearCountersResponse(dev_id=self.dev_id, transaction_id=self.transaction_id) @@ -181,7 +181,7 @@ class ReturnBusMessageCountRequest(DiagnosticBase): sub_function_code = 0x000B - async def update_datastore(self, _context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, _context: ModbusDeviceContext) -> ModbusPDU: """update_datastore the diagnostic request on the given device.""" count = _MCB.Counter.BusMessage return ReturnBusMessageCountResponse(message=count, dev_id=self.dev_id, transaction_id=self.transaction_id) @@ -198,7 +198,7 @@ class ReturnBusCommunicationErrorCountRequest(DiagnosticBase): sub_function_code = 0x000C - async def update_datastore(self, _context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, _context: ModbusDeviceContext) -> ModbusPDU: """update_datastore the diagnostic request on the given device.""" count = _MCB.Counter.BusCommunicationError return ReturnBusCommunicationErrorCountResponse(message=count, dev_id=self.dev_id, transaction_id=self.transaction_id) @@ -215,7 +215,7 @@ class ReturnBusExceptionErrorCountRequest(DiagnosticBase): sub_function_code = 0x000D - async def update_datastore(self, _context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, _context: ModbusDeviceContext) -> ModbusPDU: """update_datastore the diagnostic request on the given device.""" count = _MCB.Counter.BusExceptionError return ReturnBusExceptionErrorCountResponse(message=count, dev_id=self.dev_id, transaction_id=self.transaction_id) @@ -227,87 +227,87 @@ class ReturnBusExceptionErrorCountResponse(DiagnosticBase): sub_function_code = 0x000D -class ReturnSlaveMessageCountRequest(DiagnosticBase): - """ReturnSlaveMessageCountRequest.""" +class ReturnDeviceMessageCountRequest(DiagnosticBase): + """ReturnDeviceMessageCountRequest.""" sub_function_code = 0x000E - async def update_datastore(self, _context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, _context: ModbusDeviceContext) -> ModbusPDU: """update_datastore the diagnostic request on the given device.""" - count = _MCB.Counter.SlaveMessage - return ReturnSlaveMessageCountResponse(message=count, dev_id=self.dev_id, transaction_id=self.transaction_id) + count = _MCB.Counter.DeviceMessage + return ReturnDeviceMessageCountResponse(message=count, dev_id=self.dev_id, transaction_id=self.transaction_id) -class ReturnSlaveMessageCountResponse(DiagnosticBase): - """ReturnSlaveMessageCountResponse.""" +class ReturnDeviceMessageCountResponse(DiagnosticBase): + """ReturnDeviceMessageCountResponse.""" sub_function_code = 0x000E -class ReturnSlaveNoResponseCountRequest(DiagnosticBase): - """ReturnSlaveNoResponseCountRequest.""" +class ReturnDeviceNoResponseCountRequest(DiagnosticBase): + """ReturnDeviceNoResponseCountRequest.""" sub_function_code = 0x000F - async def update_datastore(self, _context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, _context: ModbusDeviceContext) -> ModbusPDU: """update_datastore the diagnostic request on the given device.""" - count = _MCB.Counter.SlaveNoResponse - return ReturnSlaveNoResponseCountResponse(message=count, dev_id=self.dev_id, transaction_id=self.transaction_id) + count = _MCB.Counter.DeviceNoResponse + return ReturnDeviceNoResponseCountResponse(message=count, dev_id=self.dev_id, transaction_id=self.transaction_id) -class ReturnSlaveNoResponseCountResponse(DiagnosticBase): - """ReturnSlaveNoResponseCountResponse.""" +class ReturnDeviceNoResponseCountResponse(DiagnosticBase): + """ReturnDeviceNoResponseCountResponse.""" sub_function_code = 0x000F -class ReturnSlaveNAKCountRequest(DiagnosticBase): - """ReturnSlaveNAKCountRequest.""" +class ReturnDeviceNAKCountRequest(DiagnosticBase): + """ReturnDeviceNAKCountRequest.""" sub_function_code = 0x0010 - async def update_datastore(self, _context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, _context: ModbusDeviceContext) -> ModbusPDU: """update_datastore the diagnostic request on the given device.""" - count = _MCB.Counter.SlaveNAK - return ReturnSlaveNAKCountResponse(message=count, dev_id=self.dev_id, transaction_id=self.transaction_id) + count = _MCB.Counter.DeviceNAK + return ReturnDeviceNAKCountResponse(message=count, dev_id=self.dev_id, transaction_id=self.transaction_id) -class ReturnSlaveNAKCountResponse(DiagnosticBase): - """ReturnSlaveNAKCountResponse.""" +class ReturnDeviceNAKCountResponse(DiagnosticBase): + """ReturnDeviceNAKCountResponse.""" sub_function_code = 0x0010 -class ReturnSlaveBusyCountRequest(DiagnosticBase): - """ReturnSlaveBusyCountRequest.""" +class ReturnDeviceBusyCountRequest(DiagnosticBase): + """ReturnDeviceBusyCountRequest.""" sub_function_code = 0x0011 - async def update_datastore(self, _context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, _context: ModbusDeviceContext) -> ModbusPDU: """update_datastore the diagnostic request on the given device.""" - count = _MCB.Counter.SLAVE_BUSY - return ReturnSlaveBusyCountResponse(message=count, dev_id=self.dev_id, transaction_id=self.transaction_id) + count = _MCB.Counter.DEVICE_BUSY + return ReturnDeviceBusyCountResponse(message=count, dev_id=self.dev_id, transaction_id=self.transaction_id) -class ReturnSlaveBusyCountResponse(DiagnosticBase): - """ReturnSlaveBusyCountResponse.""" +class ReturnDeviceBusyCountResponse(DiagnosticBase): + """ReturnDeviceBusyCountResponse.""" sub_function_code = 0x0011 -class ReturnSlaveBusCharacterOverrunCountRequest(DiagnosticBase): - """ReturnSlaveBusCharacterOverrunCountRequest.""" +class ReturnDeviceBusCharacterOverrunCountRequest(DiagnosticBase): + """ReturnDeviceBusCharacterOverrunCountRequest.""" sub_function_code = 0x0012 - async def update_datastore(self, _context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, _context: ModbusDeviceContext) -> ModbusPDU: """update_datastore the diagnostic request on the given device.""" count = _MCB.Counter.BusCharacterOverrun - return ReturnSlaveBusCharacterOverrunCountResponse(message=count, dev_id=self.dev_id, transaction_id=self.transaction_id) + return ReturnDeviceBusCharacterOverrunCountResponse(message=count, dev_id=self.dev_id, transaction_id=self.transaction_id) -class ReturnSlaveBusCharacterOverrunCountResponse(DiagnosticBase): - """ReturnSlaveBusCharacterOverrunCountResponse.""" +class ReturnDeviceBusCharacterOverrunCountResponse(DiagnosticBase): + """ReturnDeviceBusCharacterOverrunCountResponse.""" sub_function_code = 0x0012 @@ -317,7 +317,7 @@ class ReturnIopOverrunCountRequest(DiagnosticBase): sub_function_code = 0x0013 - async def update_datastore(self, _context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, _context: ModbusDeviceContext) -> ModbusPDU: """update_datastore the diagnostic request on the given device.""" count = _MCB.Counter.BusCharacterOverrun return ReturnIopOverrunCountResponse(message=count, dev_id=self.dev_id, transaction_id=self.transaction_id) @@ -334,7 +334,7 @@ class ClearOverrunCountRequest(DiagnosticBase): sub_function_code = 0x0014 - async def update_datastore(self, _context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, _context: ModbusDeviceContext) -> ModbusPDU: """update_datastore the diagnostic request on the given device.""" _MCB.Counter.BusCharacterOverrun = 0x0000 return ClearOverrunCountResponse(dev_id=self.dev_id, transaction_id=self.transaction_id) @@ -359,7 +359,7 @@ def get_response_pdu_size(self): data = 2 + 108 if self.message == ModbusPlusOperation.GET_STATISTICS else 0 return 1 + 2 + 2 + 2 + data - async def update_datastore(self, _context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, _context: ModbusDeviceContext) -> ModbusPDU: """update_datastore the diagnostic request on the given device.""" message: int | list | None = None # the clear operation does not return info if self.message == ModbusPlusOperation.CLEAR_STATISTICS: diff --git a/pymodbus/events.py b/pymodbus/pdu/events.py similarity index 90% rename from pymodbus/events.py rename to pymodbus/pdu/events.py index aa576a07f..19f58351b 100644 --- a/pymodbus/events.py +++ b/pymodbus/pdu/events.py @@ -87,21 +87,21 @@ class RemoteSendEvent(ModbusEvent): Bit Contents ----------------------------------------------------------- 0 Read Exception Sent (Exception Codes 1-3) - 1 Slave Abort Exception Sent (Exception Code 4) - 2 Slave Busy Exception Sent (Exception Codes 5-6) - 3 Slave Program NAK Exception Sent (Exception Code 7) + 1 Device Abort Exception Sent (Exception Code 4) + 2 Device Busy Exception Sent (Exception Codes 5-6) + 3 Device Program NAK Exception Sent (Exception Code 7) 4 Write Timeout Error Occurred 5 Currently in Listen Only Mode 6 1 7 0 """ - def __init__(self, read=False, slave_abort=False, slave_busy=False, slave_nak=False, write_timeout=False, listen=False): + def __init__(self, read=False, device_abort=False, device_busy=False, device_nak=False, write_timeout=False, listen=False): """Initialize a new event instance.""" self.read = read - self.slave_abort = slave_abort - self.slave_busy = slave_busy - self.slave_nak = slave_nak + self.device_abort = device_abort + self.device_busy = device_busy + self.device_nak = device_nak self.write_timeout = write_timeout self.listen = listen @@ -112,9 +112,9 @@ def encode(self): """ bits = [ self.read, - self.slave_abort, - self.slave_busy, - self.slave_nak, + self.device_abort, + self.device_busy, + self.device_nak, self.write_timeout, self.listen, ] @@ -130,9 +130,9 @@ def decode(self, event): # todo fix the start byte count # pylint: disable=fixme bits = unpack_bitstring(event) self.read = bits[0] - self.slave_abort = bits[1] - self.slave_busy = bits[2] - self.slave_nak = bits[3] + self.device_abort = bits[1] + self.device_busy = bits[2] + self.device_nak = bits[3] self.write_timeout = bits[4] self.listen = bits[5] diff --git a/pymodbus/pdu/file_message.py b/pymodbus/pdu/file_message.py index be939eaff..459e8baa8 100644 --- a/pymodbus/pdu/file_message.py +++ b/pymodbus/pdu/file_message.py @@ -4,7 +4,7 @@ import struct from dataclasses import dataclass -from pymodbus.datastore import ModbusSlaveContext +from pymodbus.datastore import ModbusDeviceContext from pymodbus.exceptions import ModbusException from pymodbus.pdu.pdu import ModbusPDU @@ -73,7 +73,7 @@ def get_response_pdu_size(self) -> int: """ return 1 + 7 * len(self.records) - async def update_datastore(self, _context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, _context: ModbusDeviceContext) -> ModbusPDU: """Run a read exception status request against the store.""" for record in self.records: record.record_data = b'SERVER DUMMY RECORD.' @@ -169,7 +169,7 @@ def get_response_pdu_size(self) -> int: """ return 1 + 7 * len(self.records) - async def update_datastore(self, _context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, _context: ModbusDeviceContext) -> ModbusPDU: """Run the write file record request against the context.""" return WriteFileRecordResponse(records=self.records, dev_id=self.dev_id, transaction_id=self.transaction_id) @@ -237,7 +237,7 @@ def decode(self, data: bytes) -> None: """Decode the incoming request.""" self.address = struct.unpack(">H", data)[0] - async def update_datastore(self, _context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, _context: ModbusDeviceContext) -> ModbusPDU: """Run a read exception status request against the store.""" values = [0, 1, 2, 3] # server dummy response (should be in datastore) return ReadFifoQueueResponse(values=values, dev_id=self.dev_id, transaction_id=self.transaction_id) diff --git a/pymodbus/pdu/mei_message.py b/pymodbus/pdu/mei_message.py index b3b81418f..6c8b6a49e 100644 --- a/pymodbus/pdu/mei_message.py +++ b/pymodbus/pdu/mei_message.py @@ -4,8 +4,8 @@ import struct from pymodbus.constants import DeviceInformation, MoreData -from pymodbus.datastore import ModbusSlaveContext -from pymodbus.device import DeviceInformationFactory, ModbusControlBlock +from pymodbus.datastore import ModbusDeviceContext +from pymodbus.pdu.device import DeviceInformationFactory, ModbusControlBlock from pymodbus.pdu.pdu import ExceptionResponse, ModbusPDU @@ -51,7 +51,7 @@ def decode(self, data: bytes) -> None: """Decode data part of the message.""" self.sub_function_code, self.read_code, self.object_id = struct.unpack(">BBB", data) - async def update_datastore(self, _context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, _context: ModbusDeviceContext) -> ModbusPDU: """Run a read exception status request against the store.""" if not 0x00 <= self.object_id <= 0xFF: return ExceptionResponse(self.function_code, ExceptionResponse.ILLEGAL_VALUE) diff --git a/pymodbus/pdu/other_message.py b/pymodbus/pdu/other_message.py index fac49d41d..ae973c9f6 100644 --- a/pymodbus/pdu/other_message.py +++ b/pymodbus/pdu/other_message.py @@ -4,8 +4,8 @@ import struct from pymodbus.constants import ModbusStatus -from pymodbus.datastore import ModbusSlaveContext -from pymodbus.device import DeviceInformationFactory, ModbusControlBlock +from pymodbus.datastore import ModbusDeviceContext +from pymodbus.pdu.device import DeviceInformationFactory, ModbusControlBlock from pymodbus.pdu.pdu import ModbusPDU @@ -25,7 +25,7 @@ def encode(self) -> bytes: def decode(self, _data: bytes) -> None: """Decode data part of the message.""" - async def update_datastore(self, _context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, _context: ModbusDeviceContext) -> ModbusPDU: """Run a read exception status request against the store.""" status = _MCB.Counter.summary() return ReadExceptionStatusResponse(status=status, dev_id=self.dev_id, transaction_id=self.transaction_id) @@ -98,7 +98,7 @@ def encode(self) -> bytes: def decode(self, _data: bytes) -> None: """Decode data part of the message.""" - async def update_datastore(self, _context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, _context: ModbusDeviceContext) -> ModbusPDU: """Run a read exception status request against the store.""" return GetCommEventLogResponse( status=True, @@ -146,8 +146,8 @@ def decode(self, data: bytes) -> None: self.events.append(int(data[i])) -class ReportSlaveIdRequest(ModbusPDU): - """ReportSlaveIdRequest.""" +class ReportDeviceIdRequest(ModbusPDU): + """ReportDeviceIdRequest.""" function_code = 0x11 rtu_frame_size = 4 @@ -159,8 +159,8 @@ def encode(self) -> bytes: def decode(self, _data: bytes) -> None: """Decode data part of the message.""" - async def update_datastore(self, _context: ModbusSlaveContext) -> ModbusPDU: - """Run a report slave id request against the store.""" + async def update_datastore(self, _context: ModbusDeviceContext) -> ModbusPDU: + """Run a report device id request against the store.""" information = DeviceInformationFactory.get(_MCB) id_data = [] for v_item in information.values(): @@ -171,11 +171,13 @@ async def update_datastore(self, _context: ModbusSlaveContext) -> ModbusPDU: identifier = b"-".join(id_data) identifier = identifier or b"Pymodbus" - return ReportSlaveIdResponse(identifier=identifier, dev_id=self.dev_id, transaction_id=self.transaction_id) + return ReportDeviceIdResponse(identifier=identifier, dev_id=self.dev_id, transaction_id=self.transaction_id) +ID_ON = 0xFF +ID_OFF = 0x00 -class ReportSlaveIdResponse(ModbusPDU): - """ReportSlaveIdRequeste.""" +class ReportDeviceIdResponse(ModbusPDU): + """ReportDeviceIdRequeste.""" function_code = 0x11 rtu_byte_count_pos = 2 @@ -188,7 +190,7 @@ def __init__(self, identifier: bytes = b"\x00", status: bool = True, dev_id: int def encode(self) -> bytes: """Encode the response.""" - status = ModbusStatus.SLAVE_ON if self.status else ModbusStatus.SLAVE_OFF + status = ID_ON if self.status else ID_OFF length = len(self.identifier) + 1 packet = struct.pack(">B", length) packet += self.identifier # we assume it is already encoded @@ -204,4 +206,4 @@ def decode(self, data: bytes) -> None: self.byte_count = int(data[0]) self.identifier = data[1 : self.byte_count + 1] status = int(data[-1]) - self.status = status == ModbusStatus.SLAVE_ON + self.status = status == ID_ON diff --git a/pymodbus/pdu/pdu.py b/pymodbus/pdu/pdu.py index 3b6508172..431059f8c 100644 --- a/pymodbus/pdu/pdu.py +++ b/pymodbus/pdu/pdu.py @@ -5,8 +5,8 @@ import struct from abc import abstractmethod -from pymodbus.datastore import ModbusSlaveContext -from pymodbus.exceptions import NotImplementedException +from pymodbus.datastore import ModbusDeviceContext +from pymodbus.exceptions import ModbusIOException, NotImplementedException from pymodbus.logging import Log @@ -29,6 +29,8 @@ def __init__(self, ) -> None: """Initialize the base data for a modbus request.""" self.dev_id: int = dev_id + if dev_id > 255: + raise ModbusIOException(f"Invalid ID {dev_id}") self.transaction_id: int = transaction_id self.address: int = address self.bits: list[bool] = bits or [] @@ -80,7 +82,7 @@ def encode(self) -> bytes: def decode(self, data: bytes) -> None: """Decode data part of the message.""" - async def update_datastore(self, context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, context: ModbusDeviceContext) -> ModbusPDU: """Run request against a datastore.""" _ = context return ExceptionResponse(0, 0) @@ -107,9 +109,9 @@ class ExceptionResponse(ModbusPDU): ILLEGAL_FUNCTION = 0x01 ILLEGAL_ADDRESS = 0x02 ILLEGAL_VALUE = 0x03 - SLAVE_FAILURE = 0x04 + DEVICE_FAILURE = 0x04 ACKNOWLEDGE = 0x05 - SLAVE_BUSY = 0x06 + DEVICE_BUSY = 0x06 NEGATIVE_ACKNOWLEDGE = 0x07 MEMORY_PARITY_ERROR = 0x08 GATEWAY_PATH_UNAVIABLE = 0x0A @@ -119,10 +121,10 @@ def __init__( self, function_code: int, exception_code: int = 0, - slave: int = 1, + device_id: int = 1, transaction: int = 0) -> None: """Initialize the modbus exception response.""" - super().__init__(transaction_id=transaction, dev_id=slave) + super().__init__(transaction_id=transaction, dev_id=device_id) self.function_code = function_code | 0x80 self.exception_code = exception_code Log.error(f"Exception response {self.function_code} / {self.exception_code}") diff --git a/pymodbus/pdu/register_message.py b/pymodbus/pdu/register_message.py index 656e3c571..67b7105bf 100644 --- a/pymodbus/pdu/register_message.py +++ b/pymodbus/pdu/register_message.py @@ -4,7 +4,7 @@ import struct from typing import cast -from pymodbus.datastore import ModbusSlaveContext +from pymodbus.datastore import ModbusDeviceContext from pymodbus.exceptions import ModbusIOException from pymodbus.pdu.pdu import ExceptionResponse, ModbusPDU @@ -32,7 +32,7 @@ def get_response_pdu_size(self) -> int: """ return 1 + 1 + 2 * self.count - async def update_datastore(self, context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, context: ModbusDeviceContext) -> ModbusPDU: """Run a read holding request against a datastore.""" values = cast(list[int], await context.async_getValues( self.function_code, self.address, self.count @@ -131,7 +131,7 @@ def decode(self, data: bytes) -> None: register = struct.unpack(">H", data[i : i + 2])[0] self.write_registers.append(register) - async def update_datastore(self, context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, context: ModbusDeviceContext) -> ModbusPDU: """Run a write single register request against a datastore.""" if not (1 <= self.read_count <= 0x07D): return ExceptionResponse(self.function_code, ExceptionResponse.ILLEGAL_VALUE) @@ -178,7 +178,7 @@ def decode(self, data: bytes) -> None: class WriteSingleRegisterRequest(WriteSingleRegisterResponse): """WriteSingleRegisterRequest.""" - async def update_datastore(self, context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, context: ModbusDeviceContext) -> ModbusPDU: """Run a write single register request against a datastore.""" if not 0 <= self.registers[0] <= 0xFFFF: return ExceptionResponse(self.function_code, ExceptionResponse.ILLEGAL_VALUE) @@ -217,7 +217,7 @@ def decode(self, data: bytes) -> None: for idx in range(5, (self.count * 2) + 5, 2): self.registers.append(struct.unpack(">H", data[idx : idx + 2])[0]) - async def update_datastore(self, context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, context: ModbusDeviceContext) -> ModbusPDU: """Run a write single register request against a datastore.""" if not 1 <= self.count <= 0x07B: return ExceptionResponse(self.function_code, ExceptionResponse.ILLEGAL_VALUE) @@ -269,7 +269,7 @@ def decode(self, data: bytes) -> None: """Decode the incoming request.""" self.address, self.and_mask, self.or_mask = struct.unpack(">HHH", data) - async def update_datastore(self, context: ModbusSlaveContext) -> ModbusPDU: + async def update_datastore(self, context: ModbusDeviceContext) -> ModbusPDU: """Run a mask write register request against the store.""" if not 0x0000 <= self.and_mask <= 0xFFFF: return ExceptionResponse(self.function_code, ExceptionResponse.ILLEGAL_VALUE) diff --git a/pymodbus/server/base.py b/pymodbus/server/base.py index ae46c5068..e7d73ec1c 100644 --- a/pymodbus/server/base.py +++ b/pymodbus/server/base.py @@ -6,10 +6,10 @@ from contextlib import suppress from pymodbus.datastore import ModbusServerContext -from pymodbus.device import ModbusControlBlock, ModbusDeviceIdentification from pymodbus.framer import FRAMER_NAME_TO_CLASS, FramerType from pymodbus.logging import Log from pymodbus.pdu import DecodePDU, ModbusPDU +from pymodbus.pdu.device import ModbusControlBlock, ModbusDeviceIdentification from pymodbus.transport import CommParams, ModbusProtocol from .requesthandler import ServerRequestHandler @@ -24,7 +24,7 @@ def __init__( # pylint: disable=too-many-arguments self, params: CommParams, context: ModbusServerContext | None, - ignore_missing_slaves: bool, + ignore_missing_devices: bool, broadcast_enable: bool, identity: ModbusDeviceIdentification | None, framer: FramerType, @@ -45,7 +45,7 @@ def __init__( # pylint: disable=too-many-arguments self.decoder.register(func) self.context = context or ModbusServerContext() self.control = ModbusControlBlock() - self.ignore_missing_slaves = ignore_missing_slaves + self.ignore_missing_devices = ignore_missing_devices self.broadcast_enable = broadcast_enable self.trace_packet = trace_packet self.trace_pdu = trace_pdu diff --git a/pymodbus/server/requesthandler.py b/pymodbus/server/requesthandler.py index 0ddf90931..dff111ede 100644 --- a/pymodbus/server/requesthandler.py +++ b/pymodbus/server/requesthandler.py @@ -4,7 +4,7 @@ import asyncio import traceback -from pymodbus.exceptions import ModbusIOException, NoSuchSlaveException +from pymodbus.exceptions import ModbusIOException, NoSuchIdException from pymodbus.logging import Log from pymodbus.pdu.pdu import ExceptionResponse from pymodbus.transaction import TransactionManager @@ -43,14 +43,6 @@ def callback_new_connection(self) -> ModbusProtocol: """Call when listener receive new connection request.""" raise RuntimeError("callback_new_connection should never be called") - def callback_connected(self) -> None: - """Call when connection is succcesfull.""" - super().callback_connected() - slaves = self.server.context.slaves() - if self.server.broadcast_enable: - if 0 not in slaves: - slaves.append(0) - def callback_disconnected(self, call_exc: Exception | None) -> None: """Call when connection is lost.""" super().callback_disconnected(call_exc) @@ -100,17 +92,17 @@ async def handle_request(self): try: if self.server.broadcast_enable and not self.last_pdu.dev_id: broadcast = True - # if broadcasting then execute on all slave contexts, + # if broadcasting then execute on all device contexts, # note response will be ignored - for dev_id in self.server.context.slaves(): + for dev_id in self.server.context.device_id(): response = await self.last_pdu.update_datastore(self.server.context[dev_id]) else: context = self.server.context[self.last_pdu.dev_id] response = await self.last_pdu.update_datastore(context) - except NoSuchSlaveException: - Log.error("requested slave does not exist: {}", self.last_pdu.dev_id) - if self.server.ignore_missing_slaves: + except NoSuchIdException: + Log.error("requested device id does not exist: {}", self.last_pdu.dev_id) + if self.server.ignore_missing_devices: return # the client will simply timeout waiting for a response response = ExceptionResponse(0x00, ExceptionResponse.GATEWAY_NO_RESPONSE) except Exception as exc: # pylint: disable=broad-except @@ -119,7 +111,7 @@ async def handle_request(self): exc, traceback.format_exc(), ) - response = ExceptionResponse(0x00, ExceptionResponse.SLAVE_FAILURE) + response = ExceptionResponse(0x00, ExceptionResponse.DEVICE_FAILURE) # no response when broadcasting if not broadcast: response.transaction_id = self.last_pdu.transaction_id diff --git a/pymodbus/server/server.py b/pymodbus/server/server.py index 4c5549b13..8fbd16738 100644 --- a/pymodbus/server/server.py +++ b/pymodbus/server/server.py @@ -4,9 +4,9 @@ from collections.abc import Callable from pymodbus.datastore import ModbusServerContext -from pymodbus.device import ModbusDeviceIdentification from pymodbus.framer import FramerType from pymodbus.pdu import ModbusPDU +from pymodbus.pdu.device import ModbusDeviceIdentification from pymodbus.transport import CommParams, CommType from .base import ModbusBaseServer @@ -26,7 +26,7 @@ def __init__( # pylint: disable=too-many-arguments framer=FramerType.SOCKET, identity: ModbusDeviceIdentification | None = None, address: tuple[str, int] = ("", 502), - ignore_missing_slaves: bool = False, + ignore_missing_devices: bool = False, broadcast_enable: bool = False, trace_packet: Callable[[bool, bytes], bytes] | None = None, trace_pdu: Callable[[bool, ModbusPDU], ModbusPDU] | None = None, @@ -42,8 +42,7 @@ def __init__( # pylint: disable=too-many-arguments :param framer: The framer strategy to use :param identity: An optional identify structure :param address: An optional (interface, port) to bind to. - :param ignore_missing_slaves: True to not send errors on a request - to a missing slave + :param ignore_missing_devices: True to not send errors on a missing device :param broadcast_enable: True to treat dev_id 0 as broadcast address, False to treat 0 as any other dev_id :param trace_packet: Called with bytestream received/to be sent @@ -66,7 +65,7 @@ def __init__( # pylint: disable=too-many-arguments super().__init__( params, context, - ignore_missing_slaves, + ignore_missing_devices, broadcast_enable, identity, framer, @@ -95,7 +94,7 @@ def __init__( # pylint: disable=too-many-arguments certfile=None, keyfile=None, password=None, - ignore_missing_slaves=False, + ignore_missing_devices=False, broadcast_enable=False, trace_packet: Callable[[bool, bytes], bytes] | None = None, trace_pdu: Callable[[bool, ModbusPDU], ModbusPDU] | None = None, @@ -116,8 +115,7 @@ def __init__( # pylint: disable=too-many-arguments :param certfile: The cert file path for TLS (used if sslctx is None) :param keyfile: The key file path for TLS (used if sslctx is None) :param password: The password for for decrypting the private key file - :param ignore_missing_slaves: True to not send errors on a request - to a missing slave + :param ignore_missing_devices: True to not send errors on a missing device :param broadcast_enable: True to treat dev_id 0 as broadcast address, False to treat 0 as any other dev_id :param trace_packet: Called with bytestream received/to be sent @@ -140,7 +138,7 @@ def __init__( # pylint: disable=too-many-arguments framer=framer, identity=identity, address=address, - ignore_missing_slaves=ignore_missing_slaves, + ignore_missing_devices=ignore_missing_devices, broadcast_enable=broadcast_enable, trace_packet=trace_packet, trace_pdu=trace_pdu, @@ -163,7 +161,7 @@ def __init__( # pylint: disable=too-many-arguments framer=FramerType.SOCKET, identity: ModbusDeviceIdentification | None = None, address: tuple[str, int] = ("", 502), - ignore_missing_slaves: bool = False, + ignore_missing_devices: bool = False, broadcast_enable: bool = False, trace_packet: Callable[[bool, bytes], bytes] | None = None, trace_pdu: Callable[[bool, ModbusPDU], ModbusPDU] | None = None, @@ -179,8 +177,7 @@ def __init__( # pylint: disable=too-many-arguments :param framer: The framer strategy to use :param identity: An optional identify structure :param address: An optional (interface, port) to bind to. - :param ignore_missing_slaves: True to not send errors on a request - to a missing slave + :param ignore_missing_devices: True to not send errors on a missing device :param broadcast_enable: True to treat dev_id 0 as broadcast address, False to treat 0 as any other dev_id :param trace_packet: Called with bytestream received/to be sent @@ -200,7 +197,7 @@ def __init__( # pylint: disable=too-many-arguments super().__init__( params, context, - ignore_missing_slaves, + ignore_missing_devices, broadcast_enable, identity, framer, @@ -223,7 +220,7 @@ def __init__( context: ModbusServerContext, *, framer: FramerType = FramerType.RTU, - ignore_missing_slaves: bool = False, + ignore_missing_devices: bool = False, identity: ModbusDeviceIdentification | None = None, broadcast_enable: bool = False, trace_packet: Callable[[bool, bytes], bytes] | None = None, @@ -246,8 +243,7 @@ def __init__( :param baudrate: The baud rate to use for the serial device :param timeout: The timeout to use for the serial device :param handle_local_echo: (optional) Discard local echo from dongle. - :param ignore_missing_slaves: True to not send errors on a request - to a missing slave + :param ignore_missing_devices: True to not send errors on a missing device :param broadcast_enable: True to treat dev_id 0 as broadcast address, False to treat 0 as any other dev_id :param reconnect_delay: reconnect delay in seconds @@ -272,7 +268,7 @@ def __init__( super().__init__( params, context, - ignore_missing_slaves, + ignore_missing_devices, broadcast_enable, identity, framer, diff --git a/pymodbus/server/simulator/http_server.py b/pymodbus/server/simulator/http_server.py index 424234264..a15ca84ec 100644 --- a/pymodbus/server/simulator/http_server.py +++ b/pymodbus/server/simulator/http_server.py @@ -22,9 +22,9 @@ from pymodbus.datastore import ModbusServerContext, ModbusSimulatorContext from pymodbus.datastore.simulator import Label -from pymodbus.device import ModbusDeviceIdentification from pymodbus.logging import Log from pymodbus.pdu import DecodePDU +from pymodbus.pdu.device import ModbusDeviceIdentification from pymodbus.server.server import ( ModbusSerialServer, ModbusTcpServer, @@ -155,11 +155,11 @@ def __init__( datastore = None if "device_id" in server: # Designated ModBus unit address. Will only serve data if the address matches - datastore = ModbusServerContext(slaves={int(server["device_id"]): self.datastore_context}, single=False) + datastore = ModbusServerContext(devices={int(server["device_id"]): self.datastore_context}, single=False) del server["device_id"] else: # Will server any request regardless of addressing - datastore = ModbusServerContext(slaves=self.datastore_context, single=True) + datastore = ModbusServerContext(devices=self.datastore_context, single=True) comm = comm_class[server.pop("comm")] framer = server.pop("framer") @@ -367,9 +367,9 @@ def build_html_calls(self, params: dict, html: str) -> str: (1, "ILLEGAL_FUNCTION"), (2, "ILLEGAL_ADDRESS"), (3, "ILLEGAL_VALUE"), - (4, "SLAVE_FAILURE"), + (4, "DEVICE_FAILURE"), (5, "ACKNOWLEDGE"), - (6, "SLAVE_BUSY"), + (6, "DEVICE_BUSY"), (7, "MEMORY_PARITY_ERROR"), (10, "GATEWAY_PATH_UNAVIABLE"), (11, "GATEWAY_NO_RESPONSE"), @@ -529,9 +529,9 @@ def build_json_calls(self, params: dict) -> dict: (1, "ILLEGAL_FUNCTION"), (2, "ILLEGAL_ADDRESS"), (3, "ILLEGAL_VALUE"), - (4, "SLAVE_FAILURE"), + (4, "DEVICE_FAILURE"), (5, "ACKNOWLEDGE"), - (6, "SLAVE_BUSY"), + (6, "DEVICE_BUSY"), (7, "MEMORY_PARITY_ERROR"), (10, "GATEWAY_PATH_UNAVIABLE"), (11, "GATEWAY_NO_RESPONSE"), diff --git a/pymodbus/server/simulator/setup.json b/pymodbus/server/simulator/setup.json index 94c63f4fb..ef41ff6f7 100644 --- a/pymodbus/server/simulator/setup.json +++ b/pymodbus/server/simulator/setup.json @@ -4,7 +4,7 @@ "comm": "tcp", "host": "0.0.0.0", "port": 5020, - "ignore_missing_slaves": false, + "ignore_missing_devices": false, "framer": "socket", "identity": { "VendorName": "pymodbus", @@ -40,7 +40,7 @@ "port": 5020, "certfile": "certificates/pymodbus.crt", "keyfile": "certificates/pymodbus.key", - "ignore_missing_slaves": false, + "ignore_missing_devices": false, "framer": "tls", "identity": { "VendorName": "pymodbus", @@ -55,7 +55,7 @@ "comm": "udp", "host": "0.0.0.0", "port": 5020, - "ignore_missing_slaves": false, + "ignore_missing_devices": false, "framer": "socket", "identity": { "VendorName": "pymodbus", diff --git a/test/client/test_client.py b/test/client/test_client.py index 2ddfbeb28..603b41227 100755 --- a/test/client/test_client.py +++ b/test/client/test_client.py @@ -60,11 +60,11 @@ class TestMixin: ("diag_read_bus_message_count", 0, pdu_diag.ReturnBusMessageCountRequest), ("diag_read_bus_comm_error_count",0, pdu_diag.ReturnBusCommunicationErrorCountRequest), ("diag_read_bus_exception_error_count", 0, pdu_diag.ReturnBusExceptionErrorCountRequest), - ("diag_read_slave_message_count", 0, pdu_diag.ReturnSlaveMessageCountRequest), - ("diag_read_slave_no_response_count", 0, pdu_diag.ReturnSlaveNoResponseCountRequest), - ("diag_read_slave_nak_count", 0, pdu_diag.ReturnSlaveNAKCountRequest), - ("diag_read_slave_busy_count", 0, pdu_diag.ReturnSlaveBusyCountRequest), - ("diag_read_bus_char_overrun_count", 0, pdu_diag.ReturnSlaveBusCharacterOverrunCountRequest), + ("diag_read_device_message_count", 0, pdu_diag.ReturnDeviceMessageCountRequest), + ("diag_read_device_no_response_count", 0, pdu_diag.ReturnDeviceNoResponseCountRequest), + ("diag_read_device_nak_count", 0, pdu_diag.ReturnDeviceNAKCountRequest), + ("diag_read_device_busy_count", 0, pdu_diag.ReturnDeviceBusyCountRequest), + ("diag_read_bus_char_overrun_count", 0, pdu_diag.ReturnDeviceBusCharacterOverrunCountRequest), ("diag_read_iop_overrun_count", 0, pdu_diag.ReturnIopOverrunCountRequest), ("diag_clear_overrun_counter", 0, pdu_diag.ClearOverrunCountRequest), ("diag_getclear_modbus_response", 0, pdu_diag.GetClearModbusPlusRequest), @@ -75,7 +75,7 @@ class TestMixin: ("readwrite_registers", 0, pdu_reg.ReadWriteMultipleRegistersRequest), ("readwrite_registers", 6, pdu_reg.ReadWriteMultipleRegistersRequest), ("mask_write_register", 1, pdu_reg.MaskWriteRegisterRequest), - ("report_slave_id", 0, pdu_other_msg.ReportSlaveIdRequest), + ("report_device_id", 0, pdu_other_msg.ReportDeviceIdRequest), ("read_file_record", 7, pdu_file_msg.ReadFileRecordRequest), ("write_file_record", 7, pdu_file_msg.WriteFileRecordRequest), ("read_fifo_queue", 1, pdu_file_msg.ReadFifoQueueRequest), diff --git a/test/client/test_client_faulty_response.py b/test/client/test_client_faulty_response.py index 2974f7773..dec879baf 100644 --- a/test/client/test_client_faulty_response.py +++ b/test/client/test_client_faulty_response.py @@ -1,4 +1,4 @@ -"""Test server working as slave on a multidrop RS485 line.""" +"""Test server working as a device on a multidrop RS485 line.""" import pytest diff --git a/test/client/test_client_sync.py b/test/client/test_client_sync.py index 07e8c8cf3..0f88d29af 100755 --- a/test/client/test_client_sync.py +++ b/test/client/test_client_sync.py @@ -80,9 +80,9 @@ def test_udp_client_recv_duplicate(self): client.socket = mockSocket(copy_send=False) client.socket.mock_prepare_receive(test_msg) client.socket.mock_prepare_receive(test_msg) - reply_ok = client.read_input_registers(0x820, count=1, slave=1) + reply_ok = client.read_input_registers(0x820, count=1, device_id=1) assert not reply_ok.isError() - reply_ok = client.read_input_registers(0x40, count=10, slave=1) + reply_ok = client.read_input_registers(0x40, count=10, device_id=1) assert not reply_ok.isError() client.close() @@ -396,7 +396,7 @@ def test_serial_client_recv_split(self): client.socket.mock_prepare_receive(b'\x11\x03\x06\xAE') client.socket.mock_prepare_receive(b'\x41\x56\x52\x43\x40\x49') client.socket.mock_prepare_receive(b'\xAD') - reply_ok = client.read_input_registers(0x820, count=3, slave=17) + reply_ok = client.read_input_registers(0x820, count=3, device_id=17) assert not reply_ok.isError() client.close() diff --git a/test/conftest.py b/test/conftest.py index c8a7a2322..3dfdab5a1 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -8,7 +8,7 @@ import pytest import pytest_asyncio -from pymodbus.datastore import ModbusBaseSlaveContext +from pymodbus.datastore import ModbusBaseDeviceContext from pymodbus.server import ServerAsyncStop from pymodbus.transport import NULLMODEM_HOST, CommParams, CommType from pymodbus.transport.transport import NullModem @@ -208,7 +208,7 @@ async def _check_system_health(): @pytest.fixture(name="mock_context") def define_mock_context(): """Define context class.""" - class MockContext(ModbusBaseSlaveContext): + class MockContext(ModbusBaseDeviceContext): """Mock context.""" def __init__(self, valid=False, default=True): @@ -226,7 +226,7 @@ def setValues(self, _fc, _address, _values): return MockContext -class MockLastValuesContext(ModbusBaseSlaveContext): +class MockLastValuesContext(ModbusBaseDeviceContext): """Mock context.""" def __init__(self, valid=False, default=True): diff --git a/test/examples/test_helper.py b/test/examples/test_helper.py index 8ce22239d..7573d87e6 100644 --- a/test/examples/test_helper.py +++ b/test/examples/test_helper.py @@ -18,7 +18,7 @@ def test_commandline_server_defaults(self): assert args.framer assert args.port assert args.store - assert not args.slaves + assert not args.device_ids assert not args.context def test_commandline_client_defaults(self): diff --git a/test/framer/test_multidrop.py b/test/framer/test_multidrop.py index 736572935..0bf11a995 100644 --- a/test/framer/test_multidrop.py +++ b/test/framer/test_multidrop.py @@ -1,4 +1,4 @@ -"""Test server working as slave on a multidrop RS485 line.""" +"""Test server working as device on a multidrop RS485 line.""" import pytest diff --git a/test/not_updated/test_device.py b/test/not_updated/test_device.py index 66c1fd09b..eea528374 100644 --- a/test/not_updated/test_device.py +++ b/test/not_updated/test_device.py @@ -1,12 +1,12 @@ """Test device.""" from pymodbus.constants import DeviceInformation -from pymodbus.device import ( +from pymodbus.pdu.device import ( DeviceInformationFactory, ModbusControlBlock, ModbusDeviceIdentification, ModbusPlusStatistics, ) -from pymodbus.events import RemoteReceiveEvent +from pymodbus.pdu.events import RemoteReceiveEvent # ---------------------------------------------------------------------------# @@ -202,21 +202,21 @@ def test_modbus_control_block_counters(self): assert not self.control.Counter.BusMessage for _ in range(10): self.control.Counter.BusMessage += 1 - self.control.Counter.SlaveMessage += 1 + self.control.Counter.DeviceMessage += 1 assert self.control.Counter.BusMessage == 10 self.control.Counter.BusMessage = 0x00 assert not self.control.Counter.BusMessage - assert self.control.Counter.SlaveMessage == 10 + assert self.control.Counter.DeviceMessage == 10 self.control.Counter.reset() - assert not self.control.Counter.SlaveMessage + assert not self.control.Counter.DeviceMessage def test_modbus_control_block_update(self): """Tests the MCB counters update methods.""" - values = {"SlaveMessage": 5, "BusMessage": 5} + values = {"DeviceMessage": 5, "BusMessage": 5} self.control.Counter.BusMessage += 1 - self.control.Counter.SlaveMessage += 1 + self.control.Counter.DeviceMessage += 1 self.control.Counter.update(values) - assert self.control.Counter.SlaveMessage == 6 + assert self.control.Counter.DeviceMessage == 6 assert self.control.Counter.BusMessage == 6 def test_modbus_control_block_iterator(self): @@ -236,8 +236,8 @@ def test_modbus_control_block_counter_summary(self): assert not self.control.Counter.summary() for _ in range(10): self.control.Counter.BusMessage += 1 - self.control.Counter.SlaveMessage += 1 - self.control.Counter.SlaveNAK += 1 + self.control.Counter.DeviceMessage += 1 + self.control.Counter.DeviceNAK += 1 self.control.Counter.BusCharacterOverrun += 1 assert self.control.Counter.summary() == 0xA9 self.control.Counter.reset() diff --git a/test/not_updated/test_events.py b/test/not_updated/test_events.py index 3cec6672d..f52b920b8 100644 --- a/test/not_updated/test_events.py +++ b/test/not_updated/test_events.py @@ -1,13 +1,13 @@ """Test events.""" import pytest -from pymodbus.events import ( +from pymodbus.exceptions import ParameterException +from pymodbus.pdu.events import ( CommunicationRestartEvent, EnteredListenModeEvent, RemoteReceiveEvent, RemoteSendEvent, ) -from pymodbus.exceptions import ParameterException class TestEvents: @@ -28,9 +28,9 @@ def test_remote_sent_event(self): assert result == b"\x40" event.decode(b"\x7f") assert event.read - assert event.slave_abort - assert event.slave_busy - assert event.slave_nak + assert event.device_abort + assert event.device_busy + assert event.device_nak assert event.write_timeout assert event.listen @@ -38,9 +38,9 @@ def test_remote_sent_event_encode(self): """Test remote sent event encode.""" arguments = { "read": True, - "slave_abort": True, - "slave_busy": True, - "slave_nak": True, + "device_abort": True, + "device_busy": True, + "device_nak": True, "write_timeout": True, "listen": True, } diff --git a/test/not_updated/test_remote_datastore.py b/test/not_updated/test_remote_datastore.py index bf27144d6..b81265de9 100644 --- a/test/not_updated/test_remote_datastore.py +++ b/test/not_updated/test_remote_datastore.py @@ -4,7 +4,7 @@ import pytest -from pymodbus.datastore.remote import RemoteSlaveContext +from pymodbus.datastore.remote import RemoteDeviceContext from pymodbus.exceptions import NotImplementedException from pymodbus.pdu import ExceptionResponse from pymodbus.pdu.bit_message import ReadCoilsResponse, WriteMultipleCoilsResponse @@ -14,40 +14,40 @@ class TestRemoteDataStore: """Unittest for the pymodbus.datastore.remote module.""" - def test_remote_slave_context(self): - """Test a modbus remote slave context.""" - context = RemoteSlaveContext(None) + def test_remote_device_context(self): + """Test a modbus remote device context.""" + context = RemoteDeviceContext(None) assert str(context) with pytest.raises(NotImplementedException): context.reset() - def test_remote_slave_set_values(self): - """Test setting values against a remote slave context.""" + def test_remote_device_set_values(self): + """Test setting values against a remote device context.""" client = mock.MagicMock() client.write_coils = lambda a, b: WriteMultipleCoilsResponse() client.write_registers = lambda a, b: ExceptionResponse(0x10, 0x02) - context = RemoteSlaveContext(client) + context = RemoteDeviceContext(client) context.setValues(0x0F, 0, [1]) # result = context.setValues(0x10, 1, [1]) context.setValues(0x10, 1, [1]) # assert result.exception_code == 0x02 # assert result.function_code == 0x90 - async def test_remote_slave_async_set_values(self): - """Test setting values against a remote slave context.""" + async def test_remote_device_async_set_values(self): + """Test setting values against a remote device context.""" client = mock.MagicMock() client.write_coils = mock.MagicMock(return_value=WriteMultipleCoilsResponse()) client.write_registers = mock.MagicMock( return_value=ExceptionResponse(0x10, 0x02) ) - context = RemoteSlaveContext(client) + context = RemoteDeviceContext(client) await context.async_setValues(0x0F, 0, [1]) await context.async_setValues(0x10, 1, [1]) - def test_remote_slave_get_values(self): - """Test getting values from a remote slave context.""" + def test_remote_device_get_values(self): + """Test getting values from a remote device context.""" client = mock.MagicMock() pdu = ReadCoilsResponse(bits=[True] * 10) read_input_reg_res = ReadInputRegistersResponse(registers=[10] * 10) @@ -56,7 +56,7 @@ def test_remote_slave_get_values(self): client.read_input_registers = lambda a, count=1: read_input_reg_res client.read_holding_registers = lambda a, count=1: exception_response - context = RemoteSlaveContext(client) + context = RemoteDeviceContext(client) result = context.getValues(1, 0, 10) assert result == [1] * 10 @@ -66,8 +66,8 @@ def test_remote_slave_get_values(self): result = context.getValues(3, 0, 10) assert result != [10] * 10 - async def test_remote_slave_async_get_values(self): - """Test getting values from a remote slave context.""" + async def test_remote_device_async_get_values(self): + """Test getting values from a remote device context.""" client = mock.MagicMock() pdu = ReadCoilsResponse(bits=[True] * 10) client.read_coils = mock.MagicMock(return_value=pdu) @@ -78,7 +78,7 @@ async def test_remote_slave_async_get_values(self): return_value=ExceptionResponse(0x15) ) - context = RemoteSlaveContext(client) + context = RemoteDeviceContext(client) result = await context.async_getValues(1, 0, 10) assert result == [1] * 10 diff --git a/test/pdu/test_decoders.py b/test/pdu/test_decoders.py index b7ab899b3..3bf1664ac 100644 --- a/test/pdu/test_decoders.py +++ b/test/pdu/test_decoders.py @@ -24,7 +24,7 @@ class TestModbusPDU: (0x0C, b"\x0c"), # get comm event log (0x0F, b"\x0f\x00\x01\x00\x08\x01\x00\xff"), # write multiple coils (0x10, b"\x10\x00\x01\x00\x02\x04\0xff\xff"), # write multiple registers - (0x11, b"\x11"), # report slave id + (0x11, b"\x11"), # report device id ( 0x14, b"\x14\x0e\x06\x00\x04\x00\x01\x00\x02\x06\x00\x03\x00\x09\x00\x02", @@ -55,7 +55,7 @@ class TestModbusPDU: (0x0C, b"\x0c\x08\x00\x00\x01\x08\x01\x21\x20\x00"), # get comm event log (0x0F, b"\x0f\x00\x01\x00\x08"), # write multiple coils (0x10, b"\x10\x00\x01\x00\x02"), # write multiple registers - (0x11, b"\x11\x03\x05\x01\x54"), # report slave id (device specific) + (0x11, b"\x11\x03\x05\x01\x54"), # report device id (device specific) ( 0x14, b"\x14\x0c\x05\x06\x0d\xfe\x00\x20\x05\x06\x33\xcd\x00\x40", @@ -79,7 +79,7 @@ class TestModbusPDU: (0x83, b"\x83\x03\x50\xf1"), # illegal data value exception (0x84, b"\x84\x04\x13\x03"), # skave device failure exception (0x85, b"\x85\x05\xd3\x53"), # acknowledge exception - (0x86, b"\x86\x06\x93\xa2"), # slave device busy exception + (0x86, b"\x86\x06\x93\xa2"), # device busy exception (0x87, b"\x87\x08\x53\xf2"), # memory parity exception (0x88, b"\x88\x0a\x16\x06"), # gateway path unavailable exception (0x89, b"\x89\x0b\xd6\x56"), # gateway target failed exception diff --git a/test/pdu/test_diag_messages.py b/test/pdu/test_diag_messages.py index fed1bac1e..edfbea890 100644 --- a/test/pdu/test_diag_messages.py +++ b/test/pdu/test_diag_messages.py @@ -22,22 +22,22 @@ ReturnBusExceptionErrorCountResponse, ReturnBusMessageCountRequest, ReturnBusMessageCountResponse, + ReturnDeviceBusCharacterOverrunCountRequest, + ReturnDeviceBusCharacterOverrunCountResponse, + ReturnDeviceBusyCountRequest, + ReturnDeviceBusyCountResponse, + ReturnDeviceMessageCountRequest, + ReturnDeviceMessageCountResponse, + ReturnDeviceNAKCountRequest, + ReturnDeviceNAKCountResponse, + ReturnDeviceNoResponseCountRequest, + ReturnDeviceNoResponseCountResponse, ReturnDiagnosticRegisterRequest, ReturnDiagnosticRegisterResponse, ReturnIopOverrunCountRequest, ReturnIopOverrunCountResponse, ReturnQueryDataRequest, ReturnQueryDataResponse, - ReturnSlaveBusCharacterOverrunCountRequest, - ReturnSlaveBusCharacterOverrunCountResponse, - ReturnSlaveBusyCountRequest, - ReturnSlaveBusyCountResponse, - ReturnSlaveMessageCountRequest, - ReturnSlaveMessageCountResponse, - ReturnSlaveNAKCountRequest, - ReturnSlaveNAKCountResponse, - ReturnSlaveNoResponseCountRequest, - ReturnSlaveNoResponseCountResponse, ) @@ -70,16 +70,16 @@ class TestDataStore: b"\x00\x0d\x00\x00", b"\x00\x0d\x00\x00", ), - (ReturnSlaveMessageCountRequest, b"\x00\x0e\x00\x00", b"\x00\x0e\x00\x00"), + (ReturnDeviceMessageCountRequest, b"\x00\x0e\x00\x00", b"\x00\x0e\x00\x00"), ( - ReturnSlaveNoResponseCountRequest, + ReturnDeviceNoResponseCountRequest, b"\x00\x0f\x00\x00", b"\x00\x0f\x00\x00", ), - (ReturnSlaveNAKCountRequest, b"\x00\x10\x00\x00", b"\x00\x10\x00\x00"), - (ReturnSlaveBusyCountRequest, b"\x00\x11\x00\x00", b"\x00\x11\x00\x00"), + (ReturnDeviceNAKCountRequest, b"\x00\x10\x00\x00", b"\x00\x10\x00\x00"), + (ReturnDeviceBusyCountRequest, b"\x00\x11\x00\x00", b"\x00\x11\x00\x00"), ( - ReturnSlaveBusCharacterOverrunCountRequest, + ReturnDeviceBusCharacterOverrunCountRequest, b"\x00\x12\x00\x00", b"\x00\x12\x00\x00", ), @@ -105,11 +105,11 @@ class TestDataStore: (ReturnBusMessageCountResponse, b"\x00\x0b\x00\x00"), (ReturnBusCommunicationErrorCountResponse, b"\x00\x0c\x00\x00"), (ReturnBusExceptionErrorCountResponse, b"\x00\x0d\x00\x00"), - (ReturnSlaveMessageCountResponse, b"\x00\x0e\x00\x00"), - (ReturnSlaveNoResponseCountResponse, b"\x00\x0f\x00\x00"), - (ReturnSlaveNAKCountResponse, b"\x00\x10\x00\x00"), - (ReturnSlaveBusyCountResponse, b"\x00\x11\x00\x00"), - (ReturnSlaveBusCharacterOverrunCountResponse, b"\x00\x12\x00\x00"), + (ReturnDeviceMessageCountResponse, b"\x00\x0e\x00\x00"), + (ReturnDeviceNoResponseCountResponse, b"\x00\x0f\x00\x00"), + (ReturnDeviceNAKCountResponse, b"\x00\x10\x00\x00"), + (ReturnDeviceBusyCountResponse, b"\x00\x11\x00\x00"), + (ReturnDeviceBusCharacterOverrunCountResponse, b"\x00\x12\x00\x00"), (ReturnIopOverrunCountResponse, b"\x00\x13\x00\x00"), (ClearOverrunCountResponse, b"\x00\x14\x00\x00"), (GetClearModbusPlusResponse, b"\x00\x15\x00\x04" + b"\x00\x00" * 55), diff --git a/test/pdu/test_mei_messages.py b/test/pdu/test_mei_messages.py index 40153f3a3..a16b1e5f7 100644 --- a/test/pdu/test_mei_messages.py +++ b/test/pdu/test_mei_messages.py @@ -6,7 +6,7 @@ import pytest from pymodbus.constants import DeviceInformation -from pymodbus.device import ModbusControlBlock +from pymodbus.pdu.device import ModbusControlBlock from pymodbus.pdu.mei_message import ( ReadDeviceInformationRequest, ReadDeviceInformationResponse, diff --git a/test/pdu/test_other_messages.py b/test/pdu/test_other_messages.py index 725a648a0..e2bf7dbbd 100644 --- a/test/pdu/test_other_messages.py +++ b/test/pdu/test_other_messages.py @@ -11,14 +11,14 @@ class TestOtherMessage: pymodbus_message.ReadExceptionStatusRequest, pymodbus_message.GetCommEventCounterRequest, pymodbus_message.GetCommEventLogRequest, - pymodbus_message.ReportSlaveIdRequest, + pymodbus_message.ReportDeviceIdRequest, ] responses = [ pymodbus_message.ReadExceptionStatusResponse(0x12), pymodbus_message.GetCommEventCounterResponse(0x12), pymodbus_message.GetCommEventLogResponse, - pymodbus_message.ReportSlaveIdResponse(0x12), + pymodbus_message.ReportDeviceIdResponse(0x12), ] def test_other_messages_to_string(self): @@ -85,8 +85,8 @@ def test_get_comm_event_log_with_events(self): assert response.event_count == 0x12 assert response.events == [0x12, 0x34, 0x56] - async def test_report_slave_id_request(self): - """Test report slave id request.""" + async def test_report_device_id_request(self): + """Test report device_id request.""" with mock.patch("pymodbus.pdu.other_message.DeviceInformationFactory") as dif: # First test regular identity strings identity = { @@ -103,7 +103,7 @@ async def test_report_slave_id_request(self): dif.get.return_value = identity expected_identity = "-".join(identity.values()).encode() - request = pymodbus_message.ReportSlaveIdRequest() + request = pymodbus_message.ReportDeviceIdRequest() response = await request.update_datastore(None) assert response.identifier == expected_identity @@ -121,20 +121,20 @@ async def test_report_slave_id_request(self): } dif.get.return_value = identity - request = pymodbus_message.ReportSlaveIdRequest() + request = pymodbus_message.ReportDeviceIdRequest() response = await request.update_datastore(None) assert response.identifier == expected_identity - async def test_report_slave_id(self): - """Test report slave id.""" + async def test_report_device_id(self): + """Test report device_id.""" with mock.patch("pymodbus.pdu.other_message.DeviceInformationFactory") as dif: dif.get.return_value = {} - request = pymodbus_message.ReportSlaveIdRequest() + request = pymodbus_message.ReportDeviceIdRequest() request.decode(b"\x12") assert not request.encode() assert (await request.update_datastore(None)).function_code == 0x11 - response = pymodbus_message.ReportSlaveIdResponse( + response = pymodbus_message.ReportDeviceIdResponse( (await request.update_datastore(None)).identifier, True ) diff --git a/test/pdu/test_pdu.py b/test/pdu/test_pdu.py index 111bdd974..86c699e2e 100644 --- a/test/pdu/test_pdu.py +++ b/test/pdu/test_pdu.py @@ -8,7 +8,7 @@ import pymodbus.pdu.other_message as o_msg import pymodbus.pdu.register_message as reg_msg from pymodbus.constants import ModbusStatus -from pymodbus.exceptions import NotImplementedException +from pymodbus.exceptions import ModbusIOException, NotImplementedException from pymodbus.pdu import ( ExceptionResponse, ModbusPDU, @@ -31,6 +31,11 @@ async def test_get_pdu_size(self): """Test get pdu size.""" assert not self.exception.get_response_pdu_size() + async def test_pdu_id(self): + """Test set illegal pdu id.""" + with pytest.raises(ModbusIOException): + ModbusPDU(256) + async def test_is_error(self): """Test is_error.""" assert self.exception.isError() @@ -85,11 +90,11 @@ def test_calculate_frame_size(self): (diag_msg.ReturnBusMessageCountRequest, (), {"message": 0x1010}, b'\x08\x00\x0b\x10\x10'), (diag_msg.ReturnBusCommunicationErrorCountRequest, (), {"message": 0x1010}, b'\x08\x00\x0c\x10\x10'), (diag_msg.ReturnBusExceptionErrorCountRequest, (), {"message": 0x1010}, b'\x08\x00\x0d\x10\x10'), - (diag_msg.ReturnSlaveMessageCountRequest, (), {"message": 0x1010}, b'\x08\x00\x0e\x10\x10'), - (diag_msg.ReturnSlaveNoResponseCountRequest, (), {"message": 0x1010}, b'\x08\x00\x0f\x10\x10'), - (diag_msg.ReturnSlaveNAKCountRequest, (), {"message": 0x1010}, b'\x08\x00\x10\x10\x10'), - (diag_msg.ReturnSlaveBusyCountRequest, (), {"message": 0x1010}, b'\x08\x00\x11\x10\x10'), - (diag_msg.ReturnSlaveBusCharacterOverrunCountRequest, (), {"message": 0x1010}, b'\x08\x00\x12\x10\x10'), + (diag_msg.ReturnDeviceMessageCountRequest, (), {"message": 0x1010}, b'\x08\x00\x0e\x10\x10'), + (diag_msg.ReturnDeviceNoResponseCountRequest, (), {"message": 0x1010}, b'\x08\x00\x0f\x10\x10'), + (diag_msg.ReturnDeviceNAKCountRequest, (), {"message": 0x1010}, b'\x08\x00\x10\x10\x10'), + (diag_msg.ReturnDeviceBusyCountRequest, (), {"message": 0x1010}, b'\x08\x00\x11\x10\x10'), + (diag_msg.ReturnDeviceBusCharacterOverrunCountRequest, (), {"message": 0x1010}, b'\x08\x00\x12\x10\x10'), (diag_msg.ReturnIopOverrunCountRequest, (), {"message": 0x1010}, b'\x08\x00\x13\x10\x10'), (diag_msg.ClearOverrunCountRequest, (), {"message": 0x1010}, b'\x08\x00\x14\x10\x10'), (diag_msg.GetClearModbusPlusRequest, (), {"message": 0x1010}, b'\x08\x00\x15\x10\x10'), @@ -100,7 +105,7 @@ def test_calculate_frame_size(self): (o_msg.ReadExceptionStatusRequest, (), {}, b'\x07'), (o_msg.GetCommEventCounterRequest, (), {}, b'\x0b'), (o_msg.GetCommEventLogRequest, (), {}, b'\x0c'), - (o_msg.ReportSlaveIdRequest, (), {}, b'\x11'), + (o_msg.ReportDeviceIdRequest, (), {}, b'\x11'), (reg_msg.ReadHoldingRegistersRequest, (), {"address": 117, "count": 3}, b'\x03\x00\x75\x00\x03'), (reg_msg.ReadInputRegistersRequest, (), {"address": 117, "count": 3}, b'\x04\x00\x75\x00\x03'), (reg_msg.ReadWriteMultipleRegistersRequest, (), {"read_address": 17, "read_count": 2, "write_address": 25, "write_registers": [111, 112]}, b'\x17\x00\x11\x00\x02\x00\x19\x00\x02\x04\x00\x6f\x00\x70'), @@ -125,11 +130,11 @@ def test_calculate_frame_size(self): (diag_msg.ReturnBusMessageCountResponse, (), {"message": 0x1010}, b'\x08\x00\x0b\x10\x10'), (diag_msg.ReturnBusCommunicationErrorCountResponse, (), {"message": 0x1010}, b'\x08\x00\x0c\x10\x10'), (diag_msg.ReturnBusExceptionErrorCountResponse, (), {"message": 0x1010}, b'\x08\x00\x0d\x10\x10'), - (diag_msg.ReturnSlaveMessageCountResponse, (), {"message": 0x1010}, b'\x08\x00\x0e\x10\x10'), - (diag_msg.ReturnSlaveNoResponseCountResponse, (), {"message": 0x1010}, b'\x08\x00\x0f\x10\x10'), - (diag_msg.ReturnSlaveNAKCountResponse, (), {"message": 0x1010}, b'\x08\x00\x10\x10\x10'), - (diag_msg.ReturnSlaveBusyCountResponse, (), {"message": 0x1010}, b'\x08\x00\x11\x10\x10'), - (diag_msg.ReturnSlaveBusCharacterOverrunCountResponse, (), {"message": 0x1010}, b'\x08\x00\x12\x10\x10'), + (diag_msg.ReturnDeviceMessageCountResponse, (), {"message": 0x1010}, b'\x08\x00\x0e\x10\x10'), + (diag_msg.ReturnDeviceNoResponseCountResponse, (), {"message": 0x1010}, b'\x08\x00\x0f\x10\x10'), + (diag_msg.ReturnDeviceNAKCountResponse, (), {"message": 0x1010}, b'\x08\x00\x10\x10\x10'), + (diag_msg.ReturnDeviceBusyCountResponse, (), {"message": 0x1010}, b'\x08\x00\x11\x10\x10'), + (diag_msg.ReturnDeviceBusCharacterOverrunCountResponse, (), {"message": 0x1010}, b'\x08\x00\x12\x10\x10'), (diag_msg.ReturnIopOverrunCountResponse, (), {"message": 0x1010}, b'\x08\x00\x13\x10\x10'), (diag_msg.ClearOverrunCountResponse, (), {"message": 0x1010}, b'\x08\x00\x14\x10\x10'), (diag_msg.GetClearModbusPlusResponse, (), {"message": 0x1010}, b'\x08\x00\x15\x10\x10'), @@ -140,7 +145,7 @@ def test_calculate_frame_size(self): (o_msg.ReadExceptionStatusResponse, (), {"status": 0x23}, b'\x07\x23'), (o_msg.GetCommEventCounterResponse, (), {"count": 123}, b'\x0b\x00\x00\x00\x7b'), (o_msg.GetCommEventLogResponse, (), {"status": True, "message_count": 12, "event_count": 7, "events": [12, 14]}, b'\x0c\x08\x00\x00\x00\x07\x00\x0c\x0c\x0e'), - (o_msg.ReportSlaveIdResponse, (), {"identifier": b'\x12', "status": True}, b'\x11\x02\x12\xff'), + (o_msg.ReportDeviceIdResponse, (), {"identifier": b'\x12', "status": True}, b'\x11\x02\x12\xff'), (reg_msg.ReadHoldingRegistersResponse, (), {"registers": [3, 17]}, b'\x03\x04\x00\x03\x00\x11'), (reg_msg.ReadInputRegistersResponse, (), {"registers": [3, 17]}, b'\x04\x04\x00\x03\x00\x11'), (reg_msg.ReadWriteMultipleRegistersResponse, (), {"registers": [1, 2]}, b'\x17\x04\x00\x01\x00\x02'), diff --git a/test/server/test_server_asyncio.py b/test/server/test_server_asyncio.py index eab736f0f..bbc83d454 100755 --- a/test/server/test_server_asyncio.py +++ b/test/server/test_server_asyncio.py @@ -8,15 +8,14 @@ import pytest -from pymodbus import FramerType +from pymodbus import FramerType, ModbusDeviceIdentification from pymodbus.client import AsyncModbusTcpClient from pymodbus.datastore import ( + ModbusDeviceContext, ModbusSequentialDataBlock, ModbusServerContext, - ModbusSlaveContext, ) -from pymodbus.device import ModbusDeviceIdentification -from pymodbus.exceptions import NoSuchSlaveException +from pymodbus.exceptions import NoSuchIdException from pymodbus.server import ModbusTcpServer, ModbusTlsServer, ModbusUdpServer @@ -112,13 +111,13 @@ class TestAsyncioServer: async def _setup_teardown(self): """Initialize the test environment by setting up a dummy store and context.""" self.loop = asyncio.get_running_loop() - self.store = ModbusSlaveContext( + self.store = ModbusDeviceContext( di=ModbusSequentialDataBlock(0, [17] * 100), co=ModbusSequentialDataBlock(0, [17] * 100), hr=ModbusSequentialDataBlock(0, [17] * 100), ir=ModbusSequentialDataBlock(0, [17] * 100), ) - self.context = ModbusServerContext(slaves=self.store, single=True) + self.context = ModbusServerContext(devices=self.store, single=True) self.identity = ModbusDeviceIdentification( info_name={"VendorName": "VendorName"} ) @@ -235,7 +234,7 @@ async def test_async_tcp_server_receive_data(self): async def test_async_tcp_server_roundtrip(self): """Test sending and receiving data on tcp socket.""" expected_response = b"\x01\x00\x00\x00\x00\x05\x01\x03\x02\x00\x11" - BasicClient.data = TEST_DATA # slave 1, read register + BasicClient.data = TEST_DATA # device 1, read register await self.start_server() await self.connect_server() await asyncio.wait_for(BasicClient.done, timeout=0.1) @@ -252,7 +251,7 @@ async def test_async_server_file_descriptors(self): for _ in range(2048): client = AsyncModbusTcpClient(addr[0], framer=FramerType.SOCKET, port=addr[1]) await client.connect() - response = await client.read_coils(31, count=1, slave=1) + response = await client.read_coils(31, count=1, device_id=1) assert not response.isError() client.close() @@ -274,10 +273,10 @@ async def test_async_tcp_server_shutdown_connection(self): await asyncio.sleep(0.5) await self.server.shutdown() - async def test_async_tcp_server_no_slave(self): - """Test unknown slave exception.""" + async def test_async_tcp_server_no_device(self): + """Test unknown device exception.""" self.context = ModbusServerContext( - slaves={0x01: self.store, 0x02: self.store}, single=False + devices={0x01: self.store, 0x02: self.store}, single=False ) BasicClient.data = b"\x01\x00\x00\x00\x00\x06\x05\x03\x00\x00\x00\x01" await self.start_server() @@ -292,7 +291,7 @@ async def test_async_tcp_server_modbus_error(self): await self.start_server() with mock.patch( "pymodbus.pdu.register_message.ReadHoldingRegistersRequest.update_datastore", - side_effect=NoSuchSlaveException, + side_effect=NoSuchIdException, ): await self.connect_server() await asyncio.wait_for(BasicClient.done, timeout=0.1) @@ -352,7 +351,7 @@ async def test_async_udp_server_roundtrip(self): expected_response = ( b"\x01\x00\x00\x00\x00\x05\x01\x03\x02\x00\x11" ) # value of 17 as per context - BasicClient.dataTo = TEST_DATA # slave 1, read register + BasicClient.dataTo = TEST_DATA # device 1, read register BasicClient.done = asyncio.Future() await self.start_server(do_udp=True) random_port = self.server.transport._sock.getsockname()[1] # pylint: disable=protected-access diff --git a/test/server/test_server_context.py b/test/server/test_server_context.py index 73e3b6247..802c991d1 100644 --- a/test/server/test_server_context.py +++ b/test/server/test_server_context.py @@ -1,24 +1,24 @@ """Test server context.""" import pytest -from pymodbus.datastore import ModbusServerContext, ModbusSlaveContext -from pymodbus.exceptions import NoSuchSlaveException +from pymodbus.datastore import ModbusDeviceContext, ModbusServerContext +from pymodbus.exceptions import NoSuchIdException class TestServerSingleContext: - """This is the test for the pymodbus.datastore.ModbusServerContext using a single slave context.""" + """This is the test for the pymodbus.datastore.ModbusServerContext using a single device context.""" - slave = ModbusSlaveContext() + device = ModbusDeviceContext() context = None def setup_method(self): """Set up the test environment.""" - self.context = ModbusServerContext(slaves=self.slave, single=True) + self.context = ModbusServerContext(devices=self.device, single=True) def test_single_context_gets(self): """Test getting on a single context.""" for dev_id in range(0, 0xFF): - assert self.slave == self.context[dev_id] + assert self.device == self.context[dev_id] def test_single_context_deletes(self): """Test removing on multiple context.""" @@ -26,76 +26,76 @@ def test_single_context_deletes(self): def _test(): del self.context[0x00] - with pytest.raises(NoSuchSlaveException): + with pytest.raises(NoSuchIdException): _test() def test_single_context_iter(self): """Test iterating over a single context.""" - expected = (0, self.slave) - for slave in self.context: - assert slave == expected + expected = (0, self.device) + for device in self.context: + assert device == expected def test_single_context_default(self): """Test that the single context default values work.""" self.context = ModbusServerContext() - slave = self.context[0x00] - assert not slave + device = self.context[0x00] + assert not device def test_single_context_set(self): - """Test a setting a single slave context.""" - slave = ModbusSlaveContext() - self.context[0x00] = slave + """Test a setting a single device context.""" + device = ModbusDeviceContext() + self.context[0x00] = device actual = self.context[0x00] - assert slave == actual + assert device == actual def test_single_context_register(self): """Test single context register.""" request_db = [1, 2, 3] - slave = ModbusSlaveContext() - slave.register(0xFF, "custom_request", request_db) - assert slave.store["custom_request"] == request_db - assert slave.decode(0xFF) == "custom_request" + device = ModbusDeviceContext() + device.register(0xFF, "custom_request", request_db) + assert device.store["custom_request"] == request_db + assert device.decode(0xFF) == "custom_request" class TestServerMultipleContext: - """This is the test for the pymodbus.datastore.ModbusServerContext using multiple slave contexts.""" + """This is the test for the pymodbus.datastore.ModbusServerContext using multiple device contexts.""" - slaves = None + devices = None context = None def setup_method(self): """Set up the test environment.""" - self.slaves = {id: ModbusSlaveContext() for id in range(10)} - self.context = ModbusServerContext(slaves=self.slaves, single=False) + self.devices = {id: ModbusDeviceContext() for id in range(10)} + self.context = ModbusServerContext(devices=self.devices, single=False) def test_multiple_context_gets(self): """Test getting on multiple context.""" for dev_id in range(0, 10): - assert self.slaves[dev_id] == self.context[dev_id] + assert self.devices[dev_id] == self.context[dev_id] def test_multiple_context_deletes(self): """Test removing on multiple context.""" del self.context[0x00] - with pytest.raises(NoSuchSlaveException): + with pytest.raises(NoSuchIdException): self.context[0x00]() def test_multiple_context_iter(self): """Test iterating over multiple context.""" - for dev_id, slave in self.context: - assert slave == self.slaves[dev_id] + for dev_id, device in self.context: + assert device == self.devices[dev_id] assert dev_id in self.context def test_multiple_context_default(self): """Test that the multiple context default values work.""" self.context = ModbusServerContext(single=False) - with pytest.raises(NoSuchSlaveException): + with pytest.raises(NoSuchIdException): self.context[0x00]() def test_multiple_context_set(self): - """Test a setting multiple slave contexts.""" - slaves = {id: ModbusSlaveContext() for id in range(10)} - for dev_id, slave in iter(slaves.items()): - self.context[dev_id] = slave - for dev_id, slave in iter(slaves.items()): + """Test a setting multiple device contexts.""" + devices = {id: ModbusDeviceContext() for id in range(10)} + for dev_id, device in iter(devices.items()): + self.context[dev_id] = device + for dev_id, device in iter(devices.items()): actual = self.context[dev_id] - assert slave == actual + assert device == actual diff --git a/test/server/test_simulator.py b/test/server/test_simulator.py index d0b758ce7..569ebbd36 100644 --- a/test/server/test_simulator.py +++ b/test/server/test_simulator.py @@ -105,7 +105,7 @@ class TestSimulator: "comm": "tcp", "host": NULLMODEM_HOST, "port": 5020, - "ignore_missing_slaves": False, + "ignore_missing_devices": False, "framer": "socket", "identity": { "VendorName": "pymodbus", @@ -567,7 +567,7 @@ async def test_simulator_server_end_to_end(self, simulator_server, use_port): """Test simulator server end to end.""" client = AsyncModbusTcpClient(NULLMODEM_HOST, port=use_port) assert await client.connect() - result = await client.read_holding_registers(16, count=1, slave=1) + result = await client.read_holding_registers(16, count=1, device_id=1) assert result.registers[0] == 3124 client.close() @@ -575,16 +575,16 @@ async def test_simulator_server_string(self, simulator_server, use_port): """Test simulator server end to end.""" client = AsyncModbusTcpClient(NULLMODEM_HOST, port=use_port) assert await client.connect() - result = await client.read_holding_registers(43, count=2, slave=1) + result = await client.read_holding_registers(43, count=2, device_id=1) assert result.registers[0] == int.from_bytes(bytes("St", "utf-8"), "big") assert result.registers[1] == int.from_bytes(bytes("r ", "utf-8"), "big") - result = await client.read_holding_registers(43, count=6, slave=1) + result = await client.read_holding_registers(43, count=6, device_id=1) assert result.registers[0] == int.from_bytes(bytes("St", "utf-8"), "big") assert result.registers[1] == int.from_bytes(bytes("r ", "utf-8"), "big") assert result.registers[2] == int.from_bytes(bytes("St", "utf-8"), "big") assert result.registers[3] == int.from_bytes(bytes("rx", "utf-8"), "big") assert result.registers[4] == int.from_bytes(bytes("yz", "utf-8"), "big") assert result.registers[5] == int.from_bytes(bytes("12", "utf-8"), "big") - result = await client.read_holding_registers(21, count=23, slave=1) + result = await client.read_holding_registers(21, count=23, device_id=1) assert len(result.registers) == 23 client.close()