Skip to content
Open
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
12 changes: 2 additions & 10 deletions examples/client_async_calls.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,8 @@
All available modbus calls are present.

If you are performing a request that is not available in the client
mixin, you have to perform the request like this instead::

from pymodbus.pdu.diag_message import ClearCountersRequest
from pymodbus.pdu.diag_message import ClearCountersResponse

request = ClearCountersRequest()
response = client.execute(request)
if isinstance(response, ClearCountersResponse):
... do something with the response

mixin, you can use client.execute directly, but the easiest way it to add
a custom PDU class.

This example uses client_async.py and client_sync.py to handle connection,
and have the same options.
Expand Down
12 changes: 2 additions & 10 deletions examples/client_calls.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,8 @@
All available modbus calls are present.

If you are performing a request that is not available in the client
mixin, you have to perform the request like this instead::

from pymodbus.pdu.diag_message import ClearCountersRequest
from pymodbus.pdu.diag_message import ClearCountersResponse

request = ClearCountersRequest()
response = client.execute(request)
if isinstance(response, ClearCountersResponse):
... do something with the response

mixin, you can use client.execute directly, but the easiest way it to add
a custom PDU class.

This example uses client_async.py and client_sync.py to handle connection,
and have the same options.
Expand Down
109 changes: 0 additions & 109 deletions examples/custom_msg.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#!/usr/bin/env python3
# pylint: disable=missing-type-doc
"""Pymodbus Synchronous Client Examples.

The following is an example of how to use the synchronous modbus client
Expand All @@ -12,14 +11,9 @@
"""

import asyncio
import struct

from pymodbus import FramerType
from pymodbus.client import AsyncModbusTcpClient as ModbusClient
from pymodbus.datastore import ModbusServerContext
from pymodbus.exceptions import ModbusIOException
from pymodbus.pdu import ModbusPDU
from pymodbus.pdu.bit_message import ReadCoilsRequest
from pymodbus.server import ServerAsyncStop, StartAsyncTcpServer
from pymodbus.simulator import DataType, SimData, SimDevice

Expand All @@ -35,92 +29,6 @@
# --------------------------------------------------------------------------- #


class CustomModbusResponse(ModbusPDU):
"""Custom modbus response."""

function_code = 55

@classmethod
def x_calculateRtuFrameSize(cls, data: bytes) -> int:
"""Calculate the size of a PDU."""
return int(data[2]) + 2 + 3

def __init__(self, values: list[int] | None = None, device_id=1, transaction=0):
"""Initialize."""
super().__init__(dev_id=device_id, transaction_id=transaction)
self.values: list[int] = values or []

def x_encode(self):
"""Encode response pdu.

:returns: The encoded packet message
"""
res = struct.pack(">B", len(self.values) * 2)
for register in self.values: # pragma: no cover
res += struct.pack(">H", register)
return res

def x_decode(self, data): # pragma: no cover
"""Decode response pdu.

:param data: The packet data to decode
"""
byte_count = int(data[0])
self.values = []
for i in range(1, byte_count + 1, 2):
self.values.append(struct.unpack(">H", data[i : i + 2])[0])


class CustomRequest(ModbusPDU):
"""Custom modbus request."""

function_code = 55

@classmethod
def x_calculateRtuFrameSize(cls, data: bytes) -> int:
"""Calculate the size of a PDU."""
return 8

def __init__(self, address=None, device_id=1, transaction=0):
"""Initialize."""
super().__init__(dev_id=device_id, transaction_id=transaction)
self.address = address
self.count = 2

def x_encode(self):
"""Encode."""
return struct.pack(">HH", self.address, self.count)

def x_decode(self, data):
"""Decode."""
self.address, self.count = struct.unpack(">HH", data)

async def datastore_update(
self, context: ModbusServerContext, device_id: int
) -> ModbusPDU:
"""Update diagnostic request on the given device."""
_ = context, device_id
return CustomModbusResponse()


# --------------------------------------------------------------------------- #
# This could also have been defined as
# --------------------------------------------------------------------------- #


class Read16CoilsRequest(ReadCoilsRequest):
"""Read 16 coils in one request."""

def __init__(self, address, device_id=1, transaction=0):
"""Initialize a new instance.

:param address: The address to start reading from
"""
super().__init__(
address=address, count=16, dev_id=device_id, transaction_id=transaction
)


# --------------------------------------------------------------------------- #
# execute the request with your client
# --------------------------------------------------------------------------- #
Expand All @@ -137,30 +45,13 @@ async def main(host="localhost", port=5020):
0, SimData(0, datatype=DataType.REGISTERS, values=[17] * 100)
),
address=(host, port),
custom_pdu=[CustomRequest],
)
)
await asyncio.sleep(0.1)
async with ModbusClient(host=host, port=port, framer=FramerType.SOCKET) as client:
await client.connect()

# add new modbus function code.
assert CustomModbusResponse.x_calculateRtuFrameSize(b"\x00\x00\x07\x00") == 12
client.register(CustomModbusResponse)
device_id = 1
assert CustomRequest.x_calculateRtuFrameSize(b"") == 8
request1 = CustomRequest(32, device_id=device_id)
try:
result = await client.execute(False, request1)
except ModbusIOException: # pragma: no cover
print("Server do not support CustomRequest.")
else:
print(result) # pragma: no cover

# inherited request
request2 = Read16CoilsRequest(32, device_id)
result = await client.execute(False, request2)
print(result)
await ServerAsyncStop()
task.cancel()
await task
Expand Down
4 changes: 2 additions & 2 deletions examples/server_hook.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import sys

from pymodbus import FramerType, pymodbus_apply_logging_config
from pymodbus.pdu import ModbusPDU
from pymodbus.pdu import ModbusPdu
from pymodbus.server import ModbusTcpServer
from pymodbus.simulator import DataType, SimData, SimDevice

Expand Down Expand Up @@ -41,7 +41,7 @@ def trace_packet(self, sending: bool, data: bytes) -> bytes:

return data

def trace_pdu(self, sending: bool, pdu: ModbusPDU) -> ModbusPDU:
def trace_pdu(self, sending: bool, pdu: ModbusPdu) -> ModbusPdu:
"""Do dummy trace."""
txt = "REQUEST pdu" if sending else "RESPONSE pdu"
print(f"---> {txt}: {pdu}")
Expand Down
5 changes: 2 additions & 3 deletions pymodbus/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
"""

__all__ = [
"ExceptionResponse",
"FramerType",
"Log",
"ModbusDeviceIdentification",
"ModbusException",
"ModbusPdu",
"__version__",
"__version_full__",
"pymodbus_apply_logging_config",
Expand All @@ -17,8 +17,7 @@
from .exceptions import ModbusException
from .framer import FramerType
from .logging import Log, pymodbus_apply_logging_config
from .pdu import ExceptionResponse
from .pdu.device import ModbusDeviceIdentification
from .pdu import ModbusDeviceIdentification, ModbusPdu


__version__ = "4.0.0dev16"
Expand Down
18 changes: 9 additions & 9 deletions pymodbus/client/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
from ..exceptions import ConnectionException
from ..framer import FRAMER_NAME_TO_CLASS, FramerBase, FramerType
from ..logging import Log
from ..pdu import DecodePDU, ModbusPDU
from ..pdu import DecodePDU, ModbusPdu
from ..transaction import TransactionManager
from ..transport import CommParams
from .mixin import ModbusClientMixin


class ModbusBaseClient(ModbusClientMixin[Awaitable[ModbusPDU]]):
class ModbusBaseClient(ModbusClientMixin[Awaitable[ModbusPdu]]):
"""**ModbusBaseClient**.

:mod:`ModbusBaseClient` is normally not referenced outside :mod:`pymodbus`.
Expand All @@ -26,7 +26,7 @@ def __init__(
retries: int,
comm_params: CommParams,
trace_packet: Callable[[bool, bytes], bytes] | None,
trace_pdu: Callable[[bool, ModbusPDU], ModbusPDU] | None,
trace_pdu: Callable[[bool, ModbusPdu], ModbusPdu] | None,
trace_connect: Callable[[bool], None] | None,
) -> None:
"""Initialize a client instance.
Expand Down Expand Up @@ -61,7 +61,7 @@ async def connect(self) -> bool:
rc = await self.ctx.connect()
return rc

def register(self, custom_response_class: type[ModbusPDU]) -> None:
def register(self, custom_response_class: type[ModbusPdu]) -> None:
"""Register a custom response class with the decoder (call **sync**).

:param custom_response_class: (optional) Modbus response class.
Expand All @@ -76,7 +76,7 @@ def close(self) -> None:
"""Close connection."""
self.ctx.close()

def execute(self, no_response_expected: bool, request: ModbusPDU):
def execute(self, no_response_expected: bool, request: ModbusPdu):
"""Execute request and get response (call **sync/async**).

:meta private:
Expand Down Expand Up @@ -120,7 +120,7 @@ def __str__(self):
return f"{self.__class__.__name__} {self.ctx.comm_params.host}:{self.ctx.comm_params.port}"


class ModbusBaseSyncClient(ModbusClientMixin[ModbusPDU]):
class ModbusBaseSyncClient(ModbusClientMixin[ModbusPdu]):
"""**ModbusBaseClient**.

:mod:`ModbusBaseClient` is normally not referenced outside :mod:`pymodbus`.
Expand All @@ -132,7 +132,7 @@ def __init__(
retries: int,
comm_params: CommParams,
trace_packet: Callable[[bool, bytes], bytes] | None,
trace_pdu: Callable[[bool, ModbusPDU], ModbusPDU] | None,
trace_pdu: Callable[[bool, ModbusPdu], ModbusPdu] | None,
trace_connect: Callable[[bool], None] | None,
) -> None:
"""Initialize a client instance.
Expand Down Expand Up @@ -161,7 +161,7 @@ def __init__(
# ----------------------------------------------------------------------- #
# Client external interface
# ----------------------------------------------------------------------- #
def register(self, custom_response_class: type[ModbusPDU]) -> None:
def register(self, custom_response_class: type[ModbusPdu]) -> None:
"""Register a custom response class with the decoder.

:param custom_response_class: (optional) Modbus response class.
Expand All @@ -172,7 +172,7 @@ def register(self, custom_response_class: type[ModbusPDU]) -> None:
"""
self.framer.decoder.register(custom_response_class)

def execute(self, no_response_expected: bool, request: ModbusPDU) -> ModbusPDU:
def execute(self, no_response_expected: bool, request: ModbusPdu) -> ModbusPdu:
"""Execute request and get response (call **sync/async**).

:param no_response_expected: The client will not expect a response to the request
Expand Down
Loading
Loading