diff --git a/doc/source/examples.rst b/doc/source/examples.rst index 2be001006..d7f249aa9 100644 --- a/doc/source/examples.rst +++ b/doc/source/examples.rst @@ -79,11 +79,11 @@ Source: :github:`examples/client_calls.py` :noindex: -Client custom message -^^^^^^^^^^^^^^^^^^^^^ -Source: :github:`examples/client_custom_msg.py` +Custom message +^^^^^^^^^^^^^^ +Source: :github:`examples/custom_msg.py` -.. automodule:: examples.client_custom_msg +.. automodule:: examples.custom_msg :undoc-members: :noindex: diff --git a/examples/client_custom_msg.py b/examples/custom_msg.py similarity index 79% rename from examples/client_custom_msg.py rename to examples/custom_msg.py index a3dbf97a9..df64a3474 100755 --- a/examples/client_custom_msg.py +++ b/examples/custom_msg.py @@ -15,9 +15,15 @@ from pymodbus import FramerType from pymodbus.client import AsyncModbusTcpClient as ModbusClient +from pymodbus.datastore import ( + ModbusSequentialDataBlock, + ModbusServerContext, + ModbusSlaveContext, +) from pymodbus.exceptions import ModbusIOException -from pymodbus.pdu import ExceptionResponse, ModbusPDU +from pymodbus.pdu import ModbusPDU from pymodbus.pdu.bit_message import ReadCoilsRequest +from pymodbus.server import ServerAsyncStop, StartAsyncTcpServer # --------------------------------------------------------------------------- # @@ -31,7 +37,7 @@ # --------------------------------------------------------------------------- # -class CustomModbusPDU(ModbusPDU): +class CustomModbusResponse(ModbusPDU): """Custom modbus response.""" function_code = 55 @@ -73,7 +79,7 @@ def __init__(self, address=None, slave=1, transaction=0): """Initialize.""" super().__init__(dev_id=slave, transaction_id=transaction) self.address = address - self.count = 16 + self.count = 2 def encode(self): """Encode.""" @@ -83,14 +89,10 @@ def decode(self, data): """Decode.""" self.address, self.count = struct.unpack(">HH", data) - def execute(self, context): + async def update_datastore(self, context: ModbusSlaveContext) -> ModbusPDU: """Execute.""" - if not 1 <= self.count <= 0x7D0: - return ExceptionResponse(self.function_code, ExceptionResponse.ILLEGAL_VALUE) - if not context.validate(self.function_code, self.address, self.count): - return ExceptionResponse(self.function_code, ExceptionResponse.ILLEGAL_ADDRESS) - values = context.getValues(self.function_code, self.address, self.count) - return CustomModbusPDU(values) + _ = context + return CustomModbusResponse() # --------------------------------------------------------------------------- # @@ -119,14 +121,25 @@ def __init__(self, address, slave=1, transaction=0): async def main(host="localhost", port=5020): """Run versions of read coil.""" + store = ModbusServerContext(slaves=ModbusSlaveContext( + di=ModbusSequentialDataBlock(0, [17] * 100), + co=ModbusSequentialDataBlock(0, [17] * 100), + hr=ModbusSequentialDataBlock(0, [17] * 100), + ir=ModbusSequentialDataBlock(0, [17] * 100), + ), + single=True + ) + task = asyncio.create_task(StartAsyncTcpServer( + context=store, + address=(host, port), + custom_functions=[CustomRequest]) + ) + await asyncio.sleep(0.1) async with ModbusClient(host=host, port=port, framer=FramerType.SOCKET) as client: await client.connect() - # create a response object to control it works - CustomModbusPDU() - - # new modbus function code. - client.register(CustomModbusPDU) + # add new modbus function code. + client.register(CustomModbusResponse) slave=1 request1 = CustomRequest(32, slave=slave) try: @@ -140,6 +153,9 @@ async def main(host="localhost", port=5020): request2 = Read16CoilsRequest(32, slave) result = await client.execute(False, request2) print(result) + await ServerAsyncStop() + task.cancel() + await task if __name__ == "__main__": diff --git a/test/examples/test_examples.py b/test/examples/test_examples.py index 446190a75..f78dfd7c2 100755 --- a/test/examples/test_examples.py +++ b/test/examples/test_examples.py @@ -15,8 +15,8 @@ from examples.client_async_calls import main as main_client_async_calls from examples.client_calls import main as main_client_calls from examples.client_calls import template_call -from examples.client_custom_msg import main as main_custom_client from examples.client_payload import main as main_payload_calls +from examples.custom_msg import main as main_custom_client from examples.datastore_simulator_share import main as main_datastore_simulator_share from examples.message_parser import main as main_parse_messages from examples.server_async import setup_server @@ -149,13 +149,11 @@ async def test_client_calls_errors(self, mock_server): await run_async_client(client, modbus_calls=template_call) client.close() - async def test_custom_msg( - self, mock_server, use_comm, use_framer, use_port, use_host - ): + async def test_custom_msg(self, use_comm, use_port, use_framer, use_host): """Test client with custom message.""" - if use_comm != "tcp" or use_framer != "socket": + _ = use_framer + if use_comm != "tcp": return - assert mock_server await main_custom_client(port=use_port, host=use_host) async def test_payload(self, mock_clc, mock_cls):