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
7 changes: 2 additions & 5 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Remark: "Supports" means that we only test with those versions, lower versions (
Summary
------------------------------------------------------------

Pymodbus is a full Modbus protocol implementation using a synchronous or asynchronous core. The preferred mode for asynchronous communication is asyncio, however for the moment twisted and tornado are also supported (due to be removed or converted to a plugin in a later version).
Pymodbus is a full Modbus protocol implementation using a synchronous or asynchronous core. The preferred mode for asynchronous communication is asyncio, however for the moment twisted are also supported (due to be removed or converted to a plugin in a later version).

Supported modbus communication modes: tcp, rtu-over-tcp, udp, serial, tls

Expand All @@ -53,7 +53,7 @@ Client Features
* Full read/write protocol on discrete and register
* Most of the extended protocol (diagnostic/file/pipe/setting/information)
* TCP, RTU-OVER-TCP, UDP, TLS, Serial ASCII, Serial RTU, and Serial Binary
* asynchronous(powered by asyncio/twisted/tornado) and synchronous versions
* asynchronous(powered by asyncio/twisted) and synchronous versions
* Payload builder/decoder utilities
* Pymodbus REPL for quick tests
* Customable framer to allow for custom implementations
Expand Down Expand Up @@ -129,7 +129,6 @@ If you think, that something in the code is broken/not running well, please `ope

.. important::
**Note For async clients, it is recommended to use `asyncio` as the async facilitator.**
**If using tornado make sure the tornado version is `4.5.3` other versions of tornado can break the implementation**


------------------------------------------------------------
Expand Down Expand Up @@ -171,8 +170,6 @@ Available options are:

- **twisted**, installs twisted as alternative to asyncio (will be removed in a future version).

- **tornado**, installs tornado as alternative to asyncio (will be removed in a future version).

- **documentation**, installs tools to generate documentation.

- **development**, installs development tools needed to enable test/check of pymodbus changes.
Expand Down
2 changes: 1 addition & 1 deletion doc/source/library/pymodbus.client.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
pymodbus\.client package
========================

Pymodbus offers a :mod:`synchronous client <pymodbus.client.sync>`, and async clients based on :mod:`asyncio <pymodbus.client.asynchronous.async_io>`, :mod:`Tornado <pymodbus.client.asynchronous.tornado>`, and :mod:`Twisted <pymodbus.client.asynchronous.Twisted>`.
Pymodbus offers a :mod:`synchronous client <pymodbus.client.sync>`, and async clients based on :mod:`asyncio <pymodbus.client.asynchronous.async_io>` and :mod:`Twisted <pymodbus.client.asynchronous.Twisted>`.

Each client shares a :mod:`common client mixin <pymodbus.client.common>` which offers simple methods for reading and writing.

Expand Down
8 changes: 1 addition & 7 deletions pymodbus/client/asynchronous/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Async Modbus Client implementation based on Twisted, tornado and asyncio
"""Async Modbus Client implementation based on Twisted and asyncio

Example run::

Expand All @@ -10,9 +10,6 @@
from pymodbus.client.asynchronous.serial import AsyncModbusSerialClient as Client
from pymodbus.client.asynchronous.udp import AsyncModbusUDPClient as Client

# For tornado based asynchronous client use
event_loop, future = Client(schedulers.IO_LOOP, port=5020)

# For twisted based asynchronous client use
event_loop, future = Client(schedulers.REACTOR, port=5020)

Expand All @@ -23,9 +20,6 @@
# a Future/deferred object which would be used to
# add call backs to run asynchronously.

# The Actual client could be accessed with future.result() with Tornado
# and future.result when using twisted

# For asyncio the actual client is returned and event loop is asyncio loop
"""
import logging
Expand Down
11 changes: 2 additions & 9 deletions pymodbus/client/asynchronous/deprecated/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
warnings.simplefilter("always", DeprecationWarning)

WARNING = """
Usage of "{}" is deprecated from 2.0.0 and will be removed in future releases.
Use the new Async Modbus Client implementation based on Twisted, tornado
Usage of "{}" is deprecated from 3.0.0 and will be removed in future releases.
Use the new Async Modbus Client implementation based on Twisted
and asyncio
------------------------------------------------------------------------

Expand All @@ -19,9 +19,6 @@
from pymodbus.client.asynchronous.serial import AsyncModbusSerialClient as Client
from pymodbus.client.asynchronous.udp import AsyncModbusUDPClient as Client

# For tornado based asynchronous client use
event_loop, future = Client(schedulers.IO_LOOP, port=5020)

# For twisted based asynchronous client use
event_loop, deferred = Client(schedulers.REACTOR, port=5020)

Expand All @@ -32,14 +29,10 @@
# a Future/deferred object which would be used to
# add call backs to run asynchronously.

# The Actual client could be accessed with future.result() with Tornado
# and future.result when using twisted

# For asyncio the actual client is returned and event loop is asyncio loop

Refer:
https://pymodbus.readthedocs.io/en/dev/source/example/async_twisted_client.html
https://pymodbus.readthedocs.io/en/dev/source/example/async_tornado_client.html
https://pymodbus.readthedocs.io/en/dev/source/example/async_asyncio_client.html

"""
Expand Down
31 changes: 3 additions & 28 deletions pymodbus/client/asynchronous/factory/serial.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Factory to create asynchronous serial clients based on twisted/tornado/asyncio."""
"""Factory to create asynchronous serial clients based on twisted/asyncio."""
# pylint: disable=missing-type-doc
import logging
import asyncio
Expand Down Expand Up @@ -69,29 +69,6 @@ def __init__(self, framer, *args, **kwargs):
return proto, ser_client


def io_loop_factory(port=None, framer=None, **kwargs):
"""Create Tornado based asynchronous serial clients.

:param port: Serial port
:param framer: Modbus Framer
:param kwargs:
:return: event_loop_thread and tornado future
"""
from tornado.ioloop import IOLoop # pylint: disable=import-outside-toplevel
from pymodbus.client.asynchronous.tornado import ( # pylint: disable=import-outside-toplevel
AsyncModbusSerialClient as Client,
)

ioloop = IOLoop()
protocol = EventLoopThread("ioloop", ioloop.start, ioloop.stop)
protocol.start()
client = Client(port=port, framer=framer, ioloop=ioloop, **kwargs)

future = client.connect()

return protocol, future


def async_io_factory(port=None, framer=None, **kwargs):
"""Create asyncio based asynchronous serial clients.

Expand Down Expand Up @@ -121,18 +98,16 @@ def async_io_factory(port=None, framer=None, **kwargs):
def get_factory(scheduler):
"""Get protocol factory based on the backend scheduler being used.

:param scheduler: REACTOR/IO_LOOP/ASYNC_IO
:param scheduler: REACTOR/ASYNC_IO
:return:
:raises Exception: Failure
"""
if scheduler == schedulers.REACTOR:
return reactor_factory
if scheduler == schedulers.IO_LOOP:
return io_loop_factory
if scheduler == schedulers.ASYNC_IO:
return async_io_factory

txt = f"Allowed Schedulers: {schedulers.REACTOR}, {schedulers.IO_LOOP}, {schedulers.ASYNC_IO}"
txt = f"Allowed Schedulers: {schedulers.REACTOR}, {schedulers.ASYNC_IO}"
_logger.warning(txt)
txt = f'Invalid Scheduler "{scheduler}"'
raise Exception(txt)
50 changes: 3 additions & 47 deletions pymodbus/client/asynchronous/factory/tcp.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Factory to create asynchronous tcp clients based on twisted/tornado/asyncio."""
"""Factory to create asynchronous tcp clients based on twisted/asyncio."""
# pylint: disable=missing-type-doc
import logging
import asyncio
Expand Down Expand Up @@ -61,48 +61,6 @@ def reactor_factory(
return protocol, deferred


def io_loop_factory(
host="127.0.0.1",
port=Defaults.Port,
framer=None,
source_address=None,
timeout=None,
**kwargs,
):
"""Create Tornado based asynchronous tcp clients.

:param host: Host IP address
:param port: Port
:param framer: Modbus Framer
:param source_address: Bind address
:param timeout: Timeout in seconds
:param kwargs:
:return: event_loop_thread and tornado future
"""
from tornado.ioloop import IOLoop # pylint: disable=import-outside-toplevel
from pymodbus.client.asynchronous.tornado import ( # pylint: disable=import-outside-toplevel
AsyncModbusTCPClient as Client,
)

ioloop = IOLoop()
protocol = EventLoopThread("ioloop", ioloop.start, ioloop.stop)
protocol.start()

client = Client(
host=host,
port=port,
framer=framer,
source_address=source_address,
timeout=timeout,
ioloop=ioloop,
**kwargs,
)

future = client.connect()

return protocol, future


def async_io_factory(host="127.0.0.1", port=Defaults.Port, **kwargs):
"""Create asyncio based asynchronous tcp clients.

Expand Down Expand Up @@ -137,18 +95,16 @@ def async_io_factory(host="127.0.0.1", port=Defaults.Port, **kwargs):
def get_factory(scheduler):
"""Get protocol factory based on the backend scheduler being used.

:param scheduler: REACTOR/IO_LOOP/ASYNC_IO
:param scheduler: REACTOR/ASYNC_IO
:return: new factory
:raises Exception: Failure
"""
if scheduler == schedulers.REACTOR:
return reactor_factory
if scheduler == schedulers.IO_LOOP:
return io_loop_factory
if scheduler == schedulers.ASYNC_IO:
return async_io_factory

txt = f"Allowed Schedulers: {schedulers.REACTOR}, {schedulers.IO_LOOP}, {schedulers.ASYNC_IO}"
txt = f"Allowed Schedulers: {schedulers.REACTOR}, {schedulers.ASYNC_IO}"
_logger.warning(txt)
txt = f'Invalid Scheduler "{scheduler}"'
raise Exception(txt)
45 changes: 2 additions & 43 deletions pymodbus/client/asynchronous/factory/udp.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

from pymodbus.client.asynchronous.async_io import init_udp_client
from pymodbus.client.asynchronous import schedulers
from pymodbus.client.asynchronous.thread import EventLoopThread
from pymodbus.constants import Defaults

_logger = logging.getLogger(__name__)
Expand All @@ -32,44 +31,6 @@ def reactor_factory(
raise NotImplementedError()


def io_loop_factory(
host="127.0.0.1",
port=Defaults.Port,
framer=None,
source_address=None,
timeout=None,
**kwargs,
):
"""Create Tornado based asynchronous udp clients.

:param host: Host IP address
:param port: Port
:param framer: Modbus Framer
:param source_address: Bind address
:param timeout: Timeout in seconds
:param kwargs:
:return: event_loop_thread and tornado future
"""
from tornado.ioloop import IOLoop # pylint: disable=import-outside-toplevel
from pymodbus.client.asynchronous.tornado import ( # pylint: disable=import-outside-toplevel
AsyncModbusUDPClient as Client,
)

client = Client(
host=host,
port=port,
framer=framer,
source_address=source_address,
timeout=timeout,
**kwargs,
)
protocol = EventLoopThread("ioloop", IOLoop.current().start, IOLoop.current().stop)
protocol.start()
future = client.connect()

return protocol, future


def async_io_factory(host="127.0.0.1", port=Defaults.Port, **kwargs):
"""Create asyncio based asynchronous udp clients.

Expand Down Expand Up @@ -101,18 +62,16 @@ def async_io_factory(host="127.0.0.1", port=Defaults.Port, **kwargs):
def get_factory(scheduler):
"""Get protocol factory based on the backend scheduler being used.

:param scheduler: REACTOR/IO_LOOP/ASYNC_IO
:param scheduler: REACTOR/ASYNC_IO
:return: new factory
:raises Exception: Failure
"""
if scheduler == schedulers.REACTOR:
return reactor_factory
if scheduler == schedulers.IO_LOOP:
return io_loop_factory
if scheduler == schedulers.ASYNC_IO:
return async_io_factory

txt = f"Allowed Schedulers: {schedulers.REACTOR}, {schedulers.IO_LOOP}, {schedulers.ASYNC_IO}"
txt = f"Allowed Schedulers: {schedulers.REACTOR}, {schedulers.ASYNC_IO}"
_logger.warning(txt)
txt = f'Invalid Scheduler "{scheduler}"'
raise Exception(txt)
1 change: 0 additions & 1 deletion pymodbus/client/asynchronous/schedulers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
"""Backend schedulers to use with generic Async clients."""

REACTOR = "reactor"
IO_LOOP = "io_loop"
ASYNC_IO = "async_io"
1 change: 0 additions & 1 deletion pymodbus/client/asynchronous/thread.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
class EventLoopThread:
"""Event loop controlling the backend event loops.

io_loop for tornado,
reactor for twisted,
event_loop for Asyncio
"""
Expand Down
Loading