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
13 changes: 6 additions & 7 deletions pymodbus/client/async_serial.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@

from serial_asyncio import create_serial_connection

from pymodbus.client.base import ModbusClientProtocol
from pymodbus.framer import ModbusFramer
from pymodbus.transaction import ModbusRtuFramer
from pymodbus.client.base import ModbusBaseClient
from pymodbus.framer.rtu_framer import ModbusRtuFramer
from pymodbus.client.base import ModbusBaseClient, ModbusClientProtocol
from pymodbus.constants import Defaults

_logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -67,7 +66,7 @@ def __init__(

async def close(self): # pylint: disable=invalid-overridden-method
"""Stop connection."""
if self._connected and self.protocol and self.protocol.transport:
if self.connected and self.protocol and self.protocol.transport:
self.protocol.transport.close()

def _create_protocol(self):
Expand All @@ -77,7 +76,7 @@ def _create_protocol(self):
return protocol

@property
def _connected(self):
def connected(self):
"""Connect internal."""
return self._connected_event.is_set()

Expand Down Expand Up @@ -108,15 +107,15 @@ async def connect(self): # pylint: disable=invalid-overridden-method
def protocol_made_connection(self, protocol):
"""Notify successful connection."""
_logger.info("Serial connected.")
if not self._connected:
if not self.connected:
self._connected_event.set()
self.protocol = protocol
else:
_logger.error("Factory protocol connect callback called while connected.")

def protocol_lost_connection(self, protocol):
"""Notify lost connection."""
if self._connected:
if self.connected:
_logger.info("Serial lost connection.")
if protocol is not self.protocol:
_logger.error(
Expand Down
30 changes: 13 additions & 17 deletions pymodbus/client/async_tcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@
import typing

from pymodbus.framer import ModbusFramer
from pymodbus.transaction import ModbusSocketFramer
from pymodbus.client.base import ModbusBaseClient
from pymodbus.client.base import ModbusClientProtocol
from pymodbus.framer.socket_framer import ModbusSocketFramer
from pymodbus.client.base import ModbusBaseClient, ModbusClientProtocol
from pymodbus.constants import Defaults

_logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -102,20 +101,17 @@ def protocol_made_connection(self, protocol):

def protocol_lost_connection(self, protocol):
"""Notify lost connection."""
if self.connected:
_logger.info("Protocol lost connection.")
if protocol is not self.protocol:
_logger.error(
"Factory protocol callback called "
"from unexpected protocol instance."
)

self.connected = False
self.protocol = None
if self.params.host:
asyncio.ensure_future(self._reconnect())
else:
_logger.error("Factory protocol connect callback called while connected.")
_logger.info("Protocol lost connection.")
if protocol is not self.protocol:
_logger.error(
"Factory protocol callback called "
"from unexpected protocol instance."
)

self.connected = False
self.protocol = None
if self.params.host:
asyncio.ensure_future(self._reconnect())

async def _reconnect(self):
"""Reconnect."""
Expand Down
31 changes: 29 additions & 2 deletions pymodbus/client/async_tls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,42 @@
import ssl

from pymodbus.client.async_tcp import AsyncModbusTcpClient
from pymodbus.transaction import ModbusTlsFramer, FifoTransactionManager
from pymodbus.client.helper_tls import sslctx_provider
from pymodbus.transaction import FifoTransactionManager
from pymodbus.client.base import ModbusClientProtocol
from pymodbus.framer import ModbusFramer
from pymodbus.framer.tls_framer import ModbusTlsFramer
from pymodbus.constants import Defaults

_logger = logging.getLogger(__name__)


def sslctx_provider(sslctx=None, certfile=None, keyfile=None, password=None): # pylint: disable=missing-type-doc
"""Provide the SSLContext for ModbusTlsClient.

If the user defined SSLContext is not passed in, sslctx_provider will
produce a default one.

:param sslctx: The user defined SSLContext to use for TLS (default None and
auto create)
:param certfile: The optional client"s cert file path for TLS server request
:param keyfile: The optional client"s key file path for TLS server request
:param password: The password for for decrypting client"s private key file
"""
if sslctx is None:
# According to MODBUS/TCP Security Protocol Specification, it is
# TLSv2 at least
sslctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
sslctx.verify_mode = ssl.CERT_REQUIRED
sslctx.check_hostname = True

if certfile and keyfile:
sslctx.load_cert_chain(
certfile=certfile, keyfile=keyfile, password=password
)

return sslctx


class AsyncModbusTlsClient(AsyncModbusTcpClient):
"""**AsyncModbusTlsClient**.

Expand Down
5 changes: 2 additions & 3 deletions pymodbus/client/async_udp.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
import socket
import typing

from pymodbus.client.base import ModbusBaseClient
from pymodbus.transaction import ModbusSocketFramer
from pymodbus.client.base import ModbusClientProtocol
from pymodbus.framer.socket_framer import ModbusSocketFramer
from pymodbus.client.base import ModbusBaseClient, ModbusClientProtocol
from pymodbus.framer import ModbusFramer
from pymodbus.constants import Defaults

Expand Down
14 changes: 13 additions & 1 deletion pymodbus/client/base.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Base for all clients."""
from __future__ import annotations
from dataclasses import dataclass
import socket
import asyncio
import logging

Expand Down Expand Up @@ -186,6 +187,15 @@ def recv(self, size):
"""
return size

@classmethod
def _get_address_family(cls, address):
"""Get the correct address family."""
try:
_ = socket.inet_pton(socket.AF_INET6, address)
except socket.error: # not a valid ipv6 address
return socket.AF_INET
return socket.AF_INET6

# ----------------------------------------------------------------------- #
# The magic methods
# ----------------------------------------------------------------------- #
Expand All @@ -195,6 +205,7 @@ def __enter__(self):
:returns: The current instance of the client
:raises ConnectionException:
"""

if not self.connect():
raise ConnectionException(f"Failed to connect[{self.__str__()}]")
return self
Expand Down Expand Up @@ -279,7 +290,8 @@ def connection_made(self, transport):

async def close(self): # pylint: disable=invalid-overridden-method
"""Close connection."""
self.transport.close()
if self.transport:
self.transport.close()
self._connected = False

def connection_lost(self, reason):
Expand Down
30 changes: 0 additions & 30 deletions pymodbus/client/helper_tls.py

This file was deleted.

3 changes: 1 addition & 2 deletions pymodbus/client/mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import pymodbus.diag_message as pdu_diag
from pymodbus.utilities import ModbusTransactionState
from pymodbus.pdu import ModbusResponse, ModbusRequest
from pymodbus.exceptions import ModbusException


_logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -50,7 +49,7 @@ def execute(self, request: ModbusRequest) -> ModbusResponse:
:param request: Request to send
:raises ModbusException:
"""
raise ModbusException(f"Execute({request}) not implemented.")
return request

def read_coils(
self,
Expand Down
2 changes: 1 addition & 1 deletion pymodbus/client/sync_diag.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from pymodbus.client.sync_tcp import ModbusTcpClient
from pymodbus.constants import Defaults
from pymodbus.exceptions import ConnectionException
from pymodbus.transaction import ModbusSocketFramer
from pymodbus.framer.socket_framer import ModbusSocketFramer

_logger = logging.getLogger(__name__)

Expand Down
7 changes: 6 additions & 1 deletion pymodbus/client/sync_serial.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from pymodbus.client.base import ModbusBaseClient
from pymodbus.exceptions import ConnectionException
from pymodbus.framer import ModbusFramer
from pymodbus.transaction import ModbusRtuFramer
from pymodbus.framer.rtu_framer import ModbusRtuFramer
from pymodbus.utilities import ModbusTransactionState, hexlify_packets
from pymodbus.constants import Defaults

Expand Down Expand Up @@ -76,6 +76,11 @@ def __init__(
self.silent_interval = 3.5 * self._t0
self.silent_interval = round(self.silent_interval, 6)

@property
def connected(self):
"""Connect internal."""
return self.connect()

def connect(self):
"""Connect to the modbus serial server."""
if self.socket:
Expand Down
7 changes: 6 additions & 1 deletion pymodbus/client/sync_tcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from pymodbus.exceptions import ConnectionException
from pymodbus.utilities import ModbusTransactionState
from pymodbus.client.base import ModbusBaseClient
from pymodbus.transaction import ModbusSocketFramer
from pymodbus.framer.socket_framer import ModbusSocketFramer
from pymodbus.framer import ModbusFramer
from pymodbus.constants import Defaults

Expand Down Expand Up @@ -51,6 +51,11 @@ def __init__(
self.source_address = source_address
self.socket = None

@property
def connected(self):
"""Connect internal."""
return self.connect()

def connect(self):
"""Connect to the modbus tcp server."""
if self.socket:
Expand Down
9 changes: 7 additions & 2 deletions pymodbus/client/sync_tls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
import logging
import socket

from pymodbus.client.helper_tls import sslctx_provider
from pymodbus.client.async_tls import sslctx_provider
from pymodbus.client.sync_tcp import ModbusTcpClient
from pymodbus.transaction import ModbusTlsFramer
from pymodbus.framer.tls_framer import ModbusTlsFramer
from pymodbus.framer import ModbusFramer
from pymodbus.constants import Defaults

Expand Down Expand Up @@ -57,6 +57,11 @@ def __init__(
self.password = password
self.server_hostname = server_hostname

@property
def connected(self):
"""Connect internal."""
return self.connect()

def connect(self):
"""Connect to the modbus tls server."""
if self.socket:
Expand Down
14 changes: 5 additions & 9 deletions pymodbus/client/sync_udp.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from pymodbus.exceptions import ConnectionException
from pymodbus.client.base import ModbusBaseClient
from pymodbus.transaction import ModbusSocketFramer
from pymodbus.framer.socket_framer import ModbusSocketFramer
from pymodbus.framer import ModbusFramer
from pymodbus.constants import Defaults

Expand Down Expand Up @@ -56,14 +56,10 @@ def __init__(

self.socket = None

@classmethod
def _get_address_family(cls, address):
"""Get the correct address family."""
try:
_ = socket.inet_pton(socket.AF_INET6, address)
except socket.error: # not a valid ipv6 address
return socket.AF_INET
return socket.AF_INET6
@property
def connected(self):
"""Connect internal."""
return self.connect()

def connect(self):
"""Connect to the modbus tcp server.
Expand Down
49 changes: 0 additions & 49 deletions test/asyncio_test_helper.py

This file was deleted.

Loading