Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions doc/source/example/async_asyncio_serial_client.rst

This file was deleted.

4 changes: 0 additions & 4 deletions doc/source/example/asynchronous_asyncio_serial_client.rst

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
==================================================
Asyncio Server Example
Asynchronous Client Example
==================================================
.. literalinclude:: ../../../examples/common/asyncio_server.py
.. literalinclude:: ../../../examples/client_async.py
4 changes: 4 additions & 0 deletions doc/source/example/client_async_basic_calls.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
==================================================
Asynchronous Client basic calls example
==================================================
.. literalinclude:: ../../../examples/client_async_basic_calls.py
4 changes: 4 additions & 0 deletions doc/source/example/client_async_extended_calls.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
==================================================
Asynchronous client extended calls example
==================================================
.. literalinclude:: ../../../examples/client_async_extended_calls.py
2 changes: 1 addition & 1 deletion doc/source/example/client_sync_basic_calls.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
==================================================
Synchronous Client Example
Synchronous client basic calls example
==================================================
.. literalinclude:: ../../../examples/client_sync_basic_calls.py
2 changes: 1 addition & 1 deletion doc/source/example/client_sync_extended_calls.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
==================================================
Synchronous Client Example
Synchronous client extended calls example
==================================================
.. literalinclude:: ../../../examples/client_sync_extended_calls.py
8 changes: 4 additions & 4 deletions doc/source/example/modules.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ Examples
.. toctree::
:maxdepth: 4

async_asyncio_client
async_asyncio_serial_client
asyncio_server
asynchronous_asyncio_modbus_tls_client
callback_server
client_sync
client_sync_basic_calls
client_sync_extended_calls
client_async
client_async_basic_calls
client_async_extended_calls
changing_framers
custom_datablock
custom_message
Expand All @@ -22,9 +22,9 @@ Examples
payload_server
performance
server_sync
server_async
updating_server

asynchronous_asyncio_serial_client
bcd_payload
concurrent_client
deviceinfo_showcase_client
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
==================================================
Async Asyncio Client Example
Asynchronous server example
==================================================
.. literalinclude:: ../../../examples/common/async_asyncio_client.py
.. literalinclude:: ../../../examples/server_async.py
2 changes: 1 addition & 1 deletion doc/source/example/server_sync.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
==================================================
Synchronous Server Example
Synchronous server example
==================================================
.. literalinclude:: ../../../examples/server_sync.py
207 changes: 207 additions & 0 deletions examples/client_async.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
#!/usr/bin/env python3
"""Pymodbus Aynchronous Client Example.

An example of a single threaded synchronous client.

usage: client_async.py [-h] [--comm {tcp,udp,serial,tls}]
[--framer {ascii,binary,rtu,socket,tls}]
[--log {critical,error,warning,info,debug}]
[--port PORT]
options:
-h, --help show this help message and exit
--comm {tcp,udp,serial,tls}
"serial", "tcp", "udp" or "tls"
--framer {ascii,binary,rtu,socket,tls}
"ascii", "binary", "rtu", "socket" or "tls"
--log {critical,error,warning,info,debug}
"critical", "error", "warning", "info" or "debug"
--port PORT the port to use

The corresponding server must be started before e.g. as:
python3 server_sync.py
"""
import argparse
import asyncio
from threading import Thread
import logging


# --------------------------------------------------------------------------- #
# import the various client implementations
# --------------------------------------------------------------------------- #
from pymodbus.client.asynchronous.serial import AsyncModbusSerialClient
from pymodbus.client.asynchronous.tcp import AsyncModbusTCPClient
from pymodbus.client.asynchronous.tls import AsyncModbusTLSClient
from pymodbus.client.asynchronous.udp import AsyncModbusUDPClient
from pymodbus.transaction import (
ModbusAsciiFramer,
ModbusBinaryFramer,
ModbusRtuFramer,
ModbusSocketFramer,
ModbusTlsFramer,
)


def setup_async_client(loop):
"""Run client setup."""
args = get_commandline()
_logger.info("### Create client object")

if args.comm == "tcp":
loop, client = AsyncModbusTCPClient( # pylint: disable=unpacking-non-sequence
host="127.0.0.1", # define tcp address where to connect to.
port=args.port, # on which port
framer=ModbusSocketFramer, # how to interpret the messages
timeout=1, # waiting time for request to complete
retries=3, # retries per transaction
retry_on_empty=False, # Is an empty response a retry
source_address=("localhost", 0), # bind socket to address
strict=True, # use strict timing, t1.5 for Modbus RTU
loop=loop,
)
elif args.comm == "udp":
loop, client = AsyncModbusUDPClient( # pylint: disable=unpacking-non-sequence
host="localhost", # define tcp address where to connect to.
port=args.port, # on which port
framer=args.framer, # how to interpret the messages
timeout=1, # waiting time for request to complete
retries=3, # retries per transaction
retry_on_empty=False, # Is an empty response a retry
source_address=("localhost", 0), # bind socket to address
strict=True, # use strict timing, t1.5 for Modbus RTU
loop=loop,
)
elif args.comm == "serial":
loop, client = AsyncModbusSerialClient( # pylint: disable=unpacking-non-sequence
port=args.port, # serial port
framer=args.framer, # how to interpret the messages
stopbits=1, # The number of stop bits to use
bytesize=7, # The bytesize of the serial messages
parity="even", # Which kind of parity to use
baudrate=9600, # The baud rate to use for the serial device
handle_local_echo=False, # Handle local echo of the USB-to-RS485 adaptor
timeout=1, # waiting time for request to complete
strict=True, # use strict timing, t1.5 for Modbus RTU
loop=loop,
)
elif args.comm == "tls":
loop, client = AsyncModbusTLSClient( # pylint: disable=unpacking-non-sequence
host="localhost", # define tcp address where to connect to.
port=args.port, # on which port
sslctx=None, # ssl control
certfile=None, # certificate file
keyfile=None, # key file
password=None, # pass phrase
framer=args.framer, # how to interpret the messages
timeout=1, # waiting time for request to complete
retries=3, # retries per transaction
retry_on_empty=False, # Is an empty response a retry
source_address=("localhost", 0), # bind socket to address
strict=True, # use strict timing, t1.5 for Modbus RTU
loop=loop,
)
return loop, client


async def run_async_client(modbus_calls=None):
"""Run sync client."""
_logger.info("### Client ready")

def done(future): # pylint: disable=unused-argument
"""Done."""
_logger.info("Done !!!")

def start_loop(loop):
"""Start Loop"""
asyncio.set_event_loop(loop)
loop.run_forever()

loop = asyncio.new_event_loop()
mythread = Thread(target=start_loop, args=[loop])
mythread.daemon = True
# Start the loop
mythread.start()
await asyncio.sleep(1)
assert loop.is_running() # nosec
asyncio.set_event_loop(loop)

loop, client = setup_async_client(loop)

# Run supplied modbus calls
if modbus_calls:
future = asyncio.run_coroutine_threadsafe(
modbus_calls(client.protocol), loop=loop
)
future.add_done_callback(done)
while not future.done():
await asyncio.sleep(0.1)
loop.stop()
_logger.info("### End of Program")


# --------------------------------------------------------------------------- #
# Extra code, to allow commandline parameters instead of changing the code
# --------------------------------------------------------------------------- #
FORMAT = "%(asctime)-15s %(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s"
logging.basicConfig(format=FORMAT)
_logger = logging.getLogger()


def get_commandline():
"""Read and validate command line arguments"""
parser = argparse.ArgumentParser(
description="Connect/disconnect a synchronous client."
)
parser.add_argument(
"--comm",
choices=["tcp", "udp", "serial", "tls"],
help='"serial", "tcp", "udp" or "tls"',
type=str,
)
parser.add_argument(
"--framer",
choices=["ascii", "binary", "rtu", "socket", "tls"],
help='"ascii", "binary", "rtu", "socket" or "tls"',
type=str,
)
parser.add_argument(
"--log",
choices=["critical", "error", "warning", "info", "debug"],
help='"critical", "error", "warning", "info" or "debug"',
type=str,
)
parser.add_argument(
"--port",
help="the port to use",
type=int,
)
args = parser.parse_args()

# set defaults
comm_defaults = {
"tcp": ["socket", 5020],
"udp": ["socket", 5020],
"serial": ["rtu", "/dev/ptyp0"],
"tls": ["tls", 5020],
}
framers = {
"ascii": ModbusAsciiFramer,
"binary": ModbusBinaryFramer,
"rtu": ModbusRtuFramer,
"socket": ModbusSocketFramer,
"tls": ModbusTlsFramer,
}
_logger.setLevel(args.log.upper() if args.log else logging.INFO)
if not args.comm:
args.comm = "tcp"
if not args.framer:
args.framer = comm_defaults[args.comm][0]
if not args.port:
args.port = comm_defaults[args.comm][1]
args.framer = framers[args.framer]
return args


if __name__ == "__main__":
# Connect/disconnect no calls.
asyncio.run(run_async_client())
Loading