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
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pymodbus\.client\.asynchronous\.asyncio package
pymodbus\.client\.asynchronous\.async_io package
===============================================

.. automodule:: pymodbus.client.asynchronous.async_io
Expand Down
7 changes: 3 additions & 4 deletions doc/source/library/pymodbus.client.rst
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
pymodbus\.client package
========================

.. automodule:: pymodbus.client
:members:
:undoc-members:
:show-inheritance:
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>`.

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

Subpackages
-----------
Expand Down
20 changes: 15 additions & 5 deletions pymodbus/bit_read_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,10 @@ def __str__(self):


class ReadBitsResponseBase(ModbusResponse):
"""Base class for Messages responding to bit-reading values."""
"""Base class for Messages responding to bit-reading values.

The requested bits can be found in the .bits list.
"""

_rtu_byte_count_pos = 2

Expand All @@ -67,6 +70,8 @@ def __init__(self, values, **kwargs):
:param values: The requested values to be returned
"""
ModbusResponse.__init__(self, **kwargs)

#: A list of booleans representing bit values
self.bits = values or []

def encode(self):
Expand Down Expand Up @@ -144,9 +149,9 @@ def execute(self, context):
request is valid against the current datastore.

:param context: The datastore to request from
:returns: The initializes response message, exception message otherwise
:returns: An initialized :py:class:`~pymodbus.register_read_message.ReadCoilsResponse`, or an :py:class:`~pymodbus.pdu.ExceptionResponse` if an error occurred
"""
if not 1 <= self.count <= 0x7D0:
if not (1 <= self.count <= 0x7d0):
return self.doException(merror.IllegalValue)
if not context.validate(self.function_code, self.address, self.count):
return self.doException(merror.IllegalAddress)
Expand All @@ -166,6 +171,8 @@ class ReadCoilsResponse(ReadBitsResponseBase):
remaining bits in the final data byte will be padded with zeros
(toward the high order end of the byte). The Byte Count field specifies
the quantity of complete bytes of data.

The requested coils can be found in boolean form in the .bits list.
"""

function_code = 1
Expand Down Expand Up @@ -205,9 +212,9 @@ def execute(self, context):
request is valid against the current datastore.

:param context: The datastore to request from
:returns: The initializes response message, exception message otherwise
:returns: An initialized :py:class:`~pymodbus.register_read_message.ReadDiscreteInputsResponse`, or an :py:class:`~pymodbus.pdu.ExceptionResponse` if an error occurred
"""
if not 1 <= self.count <= 0x7D0:
if not (1 <= self.count <= 0x7d0):
return self.doException(merror.IllegalValue)
if not context.validate(self.function_code, self.address, self.count):
return self.doException(merror.IllegalAddress)
Expand All @@ -227,6 +234,8 @@ class ReadDiscreteInputsResponse(ReadBitsResponseBase):
remaining bits in the final data byte will be padded with zeros
(toward the high order end of the byte). The Byte Count field specifies
the quantity of complete bytes of data.

The requested coils can be found in boolean form in the .bits list.
"""

function_code = 2
Expand All @@ -243,6 +252,7 @@ def __init__(self, values=None, **kwargs):
# Exported symbols
# ---------------------------------------------------------------------------#
__all__ = [
"ReadBitsResponseBase",
"ReadCoilsRequest",
"ReadCoilsResponse",
"ReadDiscreteInputsRequest",
Expand Down
39 changes: 30 additions & 9 deletions pymodbus/client/asynchronous/async_io/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def connection_made(self, transport):
"""Call when a connection is made.

The transport argument is the transport representing the connection.

:param transport:
:return:
"""
Expand All @@ -56,6 +57,7 @@ def connection_lost(self, reason):
"""Call when the connection is lost or closed.

The argument is either an exception object or None

:param reason:
:return:
"""
Expand All @@ -69,24 +71,33 @@ def data_received(self, data):
"""Call when some data is received.

data is a non-empty bytes object containing the incoming data.

:param data:
:return:
"""
self._data_received(data)

def create_future(self): # pylint: disable=no-self-use
"""Create asyncio Future object."""
"""Help function to create asyncio Future object.

:return:
"""
return asyncio.Future()

def resolve_future(self, my_future, result): # pylint: disable=no-self-use
"""Resolve future."""
"""Resolve the completed future and sets the result.

:param my_future:
:param result:
:return:
"""
if not my_future.done():
my_future.set_result(result)

def raise_future(self, my_future, exc): # pylint: disable=no-self-use
"""Set exception of a future if not done
"""Set exception of a future if not done.

:param f:
:param my_future:
:param exc:
:return:
"""
Expand Down Expand Up @@ -183,6 +194,7 @@ def data_received(self, data):
"""Call when some data is received.

data is a non-empty bytes object containing the incoming data.

:param data:
:return:
"""
Expand Down Expand Up @@ -219,7 +231,7 @@ class ReconnectingAsyncioModbusTcpClient:
DELAY_MAX_MS = 1000 * 60 * 5

def __init__(self, protocol_class=None, loop=None, **kwargs):
"""Initialize ReconnectingAsyncioModbusTcpClient
"""Initialize ReconnectingAsyncioModbusTcpClient.

:param protocol_class: Protocol used to talk to modbus device.
:param loop: Event loop to use
Expand Down Expand Up @@ -258,7 +270,10 @@ async def start(self, host, port=502):
return await self._connect()

def stop(self):
"""Stop client."""
"""Stop client.

:return:
"""
# prevent reconnect:
self.host = None

Expand Down Expand Up @@ -606,7 +621,7 @@ class AsyncioModbusUdpClient:
"""Client to connect to modbus device over UDP."""

def __init__(self, host=None, port=502, protocol_class=None, loop=None, **kwargs):
"""Initialize Asyncio Modbus UDP Client
"""Initialize Asyncio Modbus UDP Client.

:param host: Host IP address
:param port: Port to connect
Expand All @@ -627,7 +642,10 @@ def __init__(self, host=None, port=502, protocol_class=None, loop=None, **kwargs
self._proto_args = kwargs

def stop(self):
"""Stop connection."""
"""Stop connection.

:return:
"""
# prevent reconnect:
# self.host = None

Expand Down Expand Up @@ -753,7 +771,10 @@ def _connected(self):
return self._connected_event.is_set()

async def connect(self):
"""Connect Async client."""
"""Connect Async client.

:return:
"""
_logger.debug(TEXT_CONNECTING)
try:
await create_serial_connection(
Expand Down
9 changes: 5 additions & 4 deletions pymodbus/client/sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@
class BaseModbusClient(ModbusClientMixin):
"""Interface for a modbus synchronous client.

Defined here are all the methods for performing the related request
methods. Derived classes simply need to implement the transport
methods and set the correct framer.
Defined here are all the methods for performing the related
request methods.
Derived classes simply need to implement the transport methods and set the correct
framer.
"""

def __init__(self, framer, **kwargs):
Expand Down Expand Up @@ -128,7 +129,7 @@ def __exit__(self, klass, value, traceback):
self.close()

def idle_time(self):
"""Return bus Idle Time to initiate next transaction.
"""Bus Idle Time to initiate next transaction

:return: time stamp
"""
Expand Down
26 changes: 19 additions & 7 deletions pymodbus/register_read_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ def __str__(self):


class ReadRegistersResponseBase(ModbusResponse):
"""Base class for responding to a modbus register read."""
"""Base class for responding to a modbus register read.

The requested registers can be found in the .registers list.
"""

_rtu_byte_count_pos = 2

Expand All @@ -60,6 +63,8 @@ def __init__(self, values, **kwargs):
:param values: The values to write to
"""
ModbusResponse.__init__(self, **kwargs)

#: A list of register values
self.registers = values or []

def encode(self):
Expand Down Expand Up @@ -122,9 +127,9 @@ def execute(self, context):
"""Run a read holding request against a datastore.

:param context: The datastore to request from
:returns: An initialized response, exception message otherwise
:returns: An initialized :py:class:`~pymodbus.register_read_message.ReadHoldingRegistersResponse`, or an :py:class:`~pymodbus.pdu.ExceptionResponse` if an error occurred
"""
if not 1 <= self.count <= 0x7D:
if not (1 <= self.count <= 0x7d):
return self.doException(merror.IllegalValue)
if not context.validate(self.function_code, self.address, self.count):
return self.doException(merror.IllegalAddress)
Expand All @@ -140,6 +145,8 @@ class ReadHoldingRegistersResponse(ReadRegistersResponseBase):
starting register address and the number of registers. In the PDU
Registers are addressed starting at zero. Therefore registers numbered
1-16 are addressed as 0-15.

The requested registers can be found in the .registers list.
"""

function_code = 3
Expand Down Expand Up @@ -176,9 +183,9 @@ def execute(self, context):
"""Run a read input request against a datastore.

:param context: The datastore to request from
:returns: An initialized response, exception message otherwise
:returns: An initialized :py:class:`~pymodbus.register_read_message.ReadInputRegistersResponse`, or an :py:class:`~pymodbus.pdu.ExceptionResponse` if an error occurred
"""
if not 1 <= self.count <= 0x7D:
if not (1 <= self.count <= 0x7d):
return self.doException(merror.IllegalValue)
if not context.validate(self.function_code, self.address, self.count):
return self.doException(merror.IllegalAddress)
Expand All @@ -194,6 +201,8 @@ class ReadInputRegistersResponse(ReadRegistersResponseBase):
starting register address and the number of registers. In the PDU
Registers are addressed starting at zero. Therefore input registers
numbered 1-16 are addressed as 0-15.

The requested registers can be found in the .registers list.
"""

function_code = 4
Expand Down Expand Up @@ -281,9 +290,9 @@ def execute(self, context):
"""Run a write single register request against a datastore.

:param context: The datastore to request from
:returns: An initialized response, exception message otherwise
:returns: An initialized :py:class:`~pymodbus.register_read_message.ReadWriteMultipleRegistersResponse`, or an :py:class:`~pymodbus.pdu.ExceptionResponse` if an error occurred
"""
if not 1 <= self.read_count <= 0x07D:
if not (1 <= self.read_count <= 0x07d):
return self.doException(merror.IllegalValue)
if not 1 <= self.write_count <= 0x079:
return self.doException(merror.IllegalValue)
Expand Down Expand Up @@ -331,6 +340,8 @@ class ReadWriteMultipleRegistersResponse(ModbusResponse):
The normal response contains the data from the group of registers that
were read. The byte count field specifies the quantity of bytes to
follow in the read data field.

The requested registers can be found in the .registers list.
"""

function_code = 23
Expand Down Expand Up @@ -379,6 +390,7 @@ def __str__(self):
"ReadHoldingRegistersResponse",
"ReadInputRegistersRequest",
"ReadInputRegistersResponse",
"ReadRegistersResponseBase",
"ReadWriteMultipleRegistersRequest",
"ReadWriteMultipleRegistersResponse",
]