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
1 change: 1 addition & 0 deletions API_changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Versions (X.Y.Z) where Z > 0 e.g. 3.0.1 do NOT have API changes!

API changes 3.6.0 (future)
--------------------------
- framer= is an enum: pymodbus.Framer, but still accept a framer class


API changes 3.5.0
Expand Down
8 changes: 2 additions & 6 deletions examples/client_custom_msg.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,10 @@
import logging
import struct

from pymodbus import Framer
from pymodbus.bit_read_message import ReadCoilsRequest
from pymodbus.client import AsyncModbusTcpClient as ModbusClient

# --------------------------------------------------------------------------- #
# import the various server implementations
# --------------------------------------------------------------------------- #
from pymodbus.pdu import ModbusExceptions, ModbusRequest, ModbusResponse
from pymodbus.transaction import ModbusSocketFramer


# --------------------------------------------------------------------------- #
Expand Down Expand Up @@ -130,7 +126,7 @@ def __init__(self, address, **kwargs):

async def main(host="localhost", port=5020):
"""Run versions of read coil."""
with ModbusClient(host=host, port=port, framer=ModbusSocketFramer) as client:
with ModbusClient(host=host, port=port, framer_name=Framer.SOCKET) as client:
await client.connect()

# new modbus function code.
Expand Down
6 changes: 3 additions & 3 deletions examples/client_performance.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
import asyncio
import time

from pymodbus import Framer
from pymodbus.client import AsyncModbusSerialClient, ModbusSerialClient
from pymodbus.transaction import ModbusRtuFramer


LOOP_COUNT = 1000
Expand All @@ -29,7 +29,7 @@ def run_sync_client_test():
print("--- Testing sync client v3.4.1")
client = ModbusSerialClient(
"/dev/ttys007",
framer=ModbusRtuFramer,
framer_name=Framer.RTU,
baudrate=9600,
)
client.connect()
Expand All @@ -56,7 +56,7 @@ async def run_async_client_test():
print("--- Testing async client v3.4.1")
client = AsyncModbusSerialClient(
"/dev/ttys007",
framer=ModbusRtuFramer,
framer_name=Framer.RTU,
baudrate=9600,
)
await client.connect()
Expand Down
5 changes: 2 additions & 3 deletions examples/datastore_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,10 @@
import asyncio
import logging

from pymodbus import pymodbus_apply_logging_config
from pymodbus import Framer, pymodbus_apply_logging_config
from pymodbus.datastore import ModbusServerContext, ModbusSimulatorContext
from pymodbus.device import ModbusDeviceIdentification
from pymodbus.server import StartAsyncTcpServer
from pymodbus.transaction import ModbusSocketFramer


logging.basicConfig()
Expand Down Expand Up @@ -141,7 +140,7 @@ def setup_simulator(setup=None, actions=None, cmdline=None):
args = get_commandline(cmdline=cmdline)
pymodbus_apply_logging_config(args.log.upper())
_logger.setLevel(args.log.upper())
args.framer = ModbusSocketFramer
args.framer = Framer.SOCKET
args.port = int(args.port)

_logger.info("### Create datastore")
Expand Down
22 changes: 2 additions & 20 deletions examples/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,11 @@
import os

from pymodbus import pymodbus_apply_logging_config
from pymodbus.transaction import (
ModbusAsciiFramer,
ModbusBinaryFramer,
ModbusRtuFramer,
ModbusSocketFramer,
ModbusTlsFramer,
)


_logger = logging.getLogger(__file__)


def get_framer(framer):
"""Convert framer name to framer class"""
framers = {
"ascii": ModbusAsciiFramer,
"binary": ModbusBinaryFramer,
"rtu": ModbusRtuFramer,
"socket": ModbusSocketFramer,
"tls": ModbusTlsFramer,
}
return framers[framer]


def get_commandline(server=False, description=None, extras=None, cmdline=None):
"""Read and validate command line arguments"""
parser = argparse.ArgumentParser(description=description)
Expand Down Expand Up @@ -123,7 +104,8 @@ def get_commandline(server=False, description=None, extras=None, cmdline=None):
}
pymodbus_apply_logging_config(args.log.upper())
_logger.setLevel(args.log.upper())
args.framer = get_framer(args.framer or comm_defaults[args.comm][0])
if not args.framer:
args.framer = comm_defaults[args.comm][0]
args.port = args.port or comm_defaults[args.comm][1]
if args.comm != "serial" and args.port:
args.port = int(args.port)
Expand Down
5 changes: 2 additions & 3 deletions examples/server_hook.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,13 @@
import asyncio
import logging

from pymodbus import pymodbus_apply_logging_config
from pymodbus import Framer, pymodbus_apply_logging_config
from pymodbus.datastore import (
ModbusSequentialDataBlock,
ModbusServerContext,
ModbusSlaveContext,
)
from pymodbus.server import ModbusTcpServer
from pymodbus.transaction import ModbusSocketFramer


class Manipulator:
Expand Down Expand Up @@ -64,7 +63,7 @@ async def setup(self):
)
self.server = ModbusTcpServer(
context,
ModbusSocketFramer,
Framer.SOCKET,
None,
("127.0.0.1", 5020),
request_tracer=self.server_request_tracer,
Expand Down
21 changes: 5 additions & 16 deletions examples/simple_async_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,7 @@
"""
import asyncio

from pymodbus import pymodbus_apply_logging_config

# --------------------------------------------------------------------------- #
# import the various client implementations
# --------------------------------------------------------------------------- #
from pymodbus import Framer, pymodbus_apply_logging_config
from pymodbus.client import (
AsyncModbusSerialClient,
AsyncModbusTcpClient,
Expand All @@ -24,16 +20,9 @@
)
from pymodbus.exceptions import ModbusException
from pymodbus.pdu import ExceptionResponse
from pymodbus.transaction import (
# ModbusAsciiFramer,
# ModbusBinaryFramer,
ModbusRtuFramer,
ModbusSocketFramer,
ModbusTlsFramer,
)


async def run_async_simple_client(comm, host, port, framer=ModbusSocketFramer):
async def run_async_simple_client(comm, host, port, framer=Framer.SOCKET):
"""Run async client."""

# activate debugging
Expand All @@ -56,7 +45,7 @@ async def run_async_simple_client(comm, host, port, framer=ModbusSocketFramer):
client = AsyncModbusUdpClient(
host,
port=port,
framer=ModbusSocketFramer,
framer=framer,
# timeout=10,
# retries=3,
# retry_on_empty=False,
Expand All @@ -67,7 +56,7 @@ async def run_async_simple_client(comm, host, port, framer=ModbusSocketFramer):
elif comm == "serial":
client = AsyncModbusSerialClient(
port,
framer=ModbusRtuFramer,
framer=framer,
# timeout=10,
# retries=3,
# retry_on_empty=False,
Expand All @@ -83,7 +72,7 @@ async def run_async_simple_client(comm, host, port, framer=ModbusSocketFramer):
client = AsyncModbusTlsClient(
host,
port=port,
framer=ModbusTlsFramer,
framer=Framer.TLS,
# timeout=10,
# retries=3,
# retry_on_empty=False,
Expand Down
17 changes: 5 additions & 12 deletions examples/simple_sync_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# --------------------------------------------------------------------------- #
# import the various client implementations
# --------------------------------------------------------------------------- #
from pymodbus import pymodbus_apply_logging_config
from pymodbus import Framer, pymodbus_apply_logging_config
from pymodbus.client import (
ModbusSerialClient,
ModbusTcpClient,
Expand All @@ -22,16 +22,9 @@
)
from pymodbus.exceptions import ModbusException
from pymodbus.pdu import ExceptionResponse
from pymodbus.transaction import (
# ModbusAsciiFramer,
# ModbusBinaryFramer,
ModbusRtuFramer,
ModbusSocketFramer,
ModbusTlsFramer,
)


def run_sync_simple_client(comm, host, port, framer=ModbusSocketFramer):
def run_sync_simple_client(comm, host, port, framer=Framer.SOCKET):
"""Run sync client."""

# activate debugging
Expand All @@ -54,7 +47,7 @@ def run_sync_simple_client(comm, host, port, framer=ModbusSocketFramer):
client = ModbusUdpClient(
host,
port=port,
framer=ModbusSocketFramer,
framer=framer,
# timeout=10,
# retries=3,
# retry_on_empty=False,
Expand All @@ -65,7 +58,7 @@ def run_sync_simple_client(comm, host, port, framer=ModbusSocketFramer):
elif comm == "serial":
client = ModbusSerialClient(
port,
framer=ModbusRtuFramer,
framer=framer,
# timeout=10,
# retries=3,
# retry_on_empty=False,
Expand All @@ -81,7 +74,7 @@ def run_sync_simple_client(comm, host, port, framer=ModbusSocketFramer):
client = ModbusTlsClient(
host,
port=port,
framer=ModbusTlsFramer,
framer=Framer.TLS,
# timeout=10,
# retries=3,
# retry_on_empty=False,
Expand Down
4 changes: 2 additions & 2 deletions examples/simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
import asyncio
import logging

from pymodbus import Framer
from pymodbus.client import AsyncModbusTcpClient
from pymodbus.datastore import ModbusSimulatorContext
from pymodbus.server import ModbusSimulatorServer, get_simulator_commandline
from pymodbus.transaction import ModbusSocketFramer


logging.basicConfig()
Expand Down Expand Up @@ -75,7 +75,7 @@ async def run_simulator():
client = AsyncModbusTcpClient(
"127.0.0.1",
port=5020,
framer=ModbusSocketFramer,
framer=Framer.SOCKET,
)
await client.connect()
assert client.connected
Expand Down
2 changes: 2 additions & 0 deletions pymodbus/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
"""

__all__ = [
"Framer",
"pymodbus_apply_logging_config",
"__version__",
"__version_full__",
]

from pymodbus.framer import Framer
from pymodbus.logging import pymodbus_apply_logging_config


Expand Down
41 changes: 23 additions & 18 deletions pymodbus/client/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
import asyncio
import socket
from dataclasses import dataclass
from typing import Any, Callable
from typing import Any, Callable, Type, cast

from pymodbus.client.mixin import ModbusClientMixin
from pymodbus.exceptions import ConnectionException, ModbusIOException
from pymodbus.factory import ClientDecoder
from pymodbus.framer import ModbusFramer
from pymodbus.framer import FRAMER_NAME_TO_CLASS, Framer, ModbusFramer
from pymodbus.logging import Log
from pymodbus.pdu import ModbusRequest, ModbusResponse
from pymodbus.transaction import DictTransactionManager
Expand All @@ -20,20 +20,23 @@
class ModbusBaseClient(ModbusClientMixin, ModbusProtocol):
"""**ModbusBaseClient**

**Parameters common to all clients**:

:param framer: (optional) Modbus Framer class.
:param timeout: (optional) Timeout for a request, in seconds.
:param retries: (optional) Max number of retries per request.
:param retry_on_empty: (optional) Retry on empty response.
:param close_comm_on_error: (optional) Close connection on error.
:param strict: (optional) Strict timing, 1.5 character between requests.
:param broadcast_enable: (optional) True to treat id 0 as broadcast address.
:param reconnect_delay: (optional) Minimum delay in milliseconds before reconnecting.
:param reconnect_delay_max: (optional) Maximum delay in milliseconds before reconnecting.
:param on_reconnect_callback: (optional) Function that will be called just before a reconnection attempt.
:param no_resend_on_retry: (optional) Do not resend request when retrying due to missing response.
:param kwargs: (optional) Experimental parameters.
Fixed parameters:

:param framer: Framer enum name

Optional parameters:

:param timeout: Timeout for a request, in seconds.
:param retries: Max number of retries per request.
:param retry_on_empty: Retry on empty response.
:param close_comm_on_error: Close connection on error.
:param strict: Strict timing, 1.5 character between requests.
:param broadcast_enable: True to treat id 0 as broadcast address.
:param reconnect_delay: Minimum delay in milliseconds before reconnecting.
:param reconnect_delay_max: Maximum delay in milliseconds before reconnecting.
:param on_reconnect_callback: Function that will be called just before a reconnection attempt.
:param no_resend_on_retry: Do not resend request when retrying due to missing response.
:param kwargs: Experimental parameters.

.. tip::
**reconnect_delay** doubles automatically with each unsuccessful connect, from
Expand Down Expand Up @@ -62,7 +65,7 @@ class _params:

def __init__( # pylint: disable=too-many-arguments
self,
framer: type[ModbusFramer] = None,
framer: Framer,
timeout: float = 3,
retries: int = 3,
retry_on_empty: bool = False,
Expand Down Expand Up @@ -114,7 +117,9 @@ def __init__( # pylint: disable=too-many-arguments
self.slaves: list[int] = []

# Common variables.
self.framer = framer(ClientDecoder(), self)
self.framer = FRAMER_NAME_TO_CLASS.get(
framer, cast(Type[ModbusFramer], framer)
)(ClientDecoder(), self)
self.transaction = DictTransactionManager(
self, retries=retries, retry_on_empty=retry_on_empty, **kwargs
)
Expand Down
Loading