From 4194785e95277e67b40d07b3d829b361f0846e7d Mon Sep 17 00:00:00 2001 From: jan iversen Date: Sat, 9 Sep 2023 10:50:35 +0200 Subject: [PATCH] server tracer example. --- doc/source/examples.rst | 8 ++++ examples/server_hook.py | 87 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100755 examples/server_hook.py diff --git a/doc/source/examples.rst b/doc/source/examples.rst index a5efe9b4f..2d5e14f68 100644 --- a/doc/source/examples.rst +++ b/doc/source/examples.rst @@ -64,6 +64,10 @@ Callback Server example ^^^^^^^^^^^^^^^^^^^^^^^ .. literalinclude:: ../../examples/server_callback.py +Server tracer example +^^^^^^^^^^^^^^^^^^^^^ +.. literalinclude:: ../../examples/server_hook.py + Custom Message client ^^^^^^^^^^^^^^^^^^^^^ .. literalinclude:: ../../examples/client_custom_msg.py @@ -107,6 +111,10 @@ Examples contributions These examples are supplied by users of pymodbus. The pymodbus team thanks for sharing the examples. +Solar +^^^^^ +.. literalinclude:: ../../examples/contrib/solar.py + Redis datastore ^^^^^^^^^^^^^^^ .. literalinclude:: ../../examples/contrib/redis_datastore.py diff --git a/examples/server_hook.py b/examples/server_hook.py new file mode 100755 index 000000000..199a9a5a3 --- /dev/null +++ b/examples/server_hook.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python3 +"""Pymodbus Server With request/response manipulator. + +This is an example of using the builtin request/response tracer to +manipulate the messages to/from the modbus server +""" +import asyncio +import logging + +from pymodbus import pymodbus_apply_logging_config +from pymodbus.datastore import ( + ModbusSequentialDataBlock, + ModbusServerContext, + ModbusSlaveContext, +) +from pymodbus.server import ModbusTcpServer +from pymodbus.transaction import ModbusSocketFramer + + +class Manipulator: + """A Class to run the server. + + Using a class allows the easy use of global variables, but + are not strictly needed + """ + + message_count: int = 1 + server: ModbusTcpServer = None + + def server_request_tracer(self, request, *_addr): + """Trace requests. + + All server requests passes this filter before being handled. + """ + print(f"---> REQUEST: {request}") + + def server_response_manipulator(self, response): + """Manipulate responses. + + All server responses passes this filter before being sent. + The filter returns: + + - response, either original or modified + - skip_encoding, signals whether or not to encode the response + """ + if not self.message_count: + print(f"---> RESPONSE: {response}") + self.message_count = 3 + else: + print("---> RESPONSE: NONE") + response.should_respond = False + self.message_count -= 1 + return response, False + + async def setup(self): + """Prepare server.""" + pymodbus_apply_logging_config(logging.DEBUG) + datablock = ModbusSequentialDataBlock(0x00, [17] * 100) + context = ModbusServerContext( + slaves=ModbusSlaveContext( + di=datablock, co=datablock, hr=datablock, ir=datablock + ), + single=True, + ) + self.server = ModbusTcpServer( + context, + ModbusSocketFramer, + None, + ("127.0.0.1", 5020), + request_tracer=self.server_request_tracer, + response_manipulator=self.server_response_manipulator, + ) + + async def run(self): + """Attach Run server""" + await self.server.serve_forever() + + +async def main(): + """Run example.""" + server = Manipulator() + await server.setup() + await server.run() + + +if __name__ == "__main__": + asyncio.run(main(), debug=True) # pragma: no cover