Files
tac2100_solar_mbus2mqtt/env/lib/python3.11/site-packages/pymodbus/client/udp.py
2025-01-03 15:06:21 +01:00

191 lines
5.3 KiB
Python

"""Modbus client async UDP communication."""
import asyncio
import socket
from typing import Any, Tuple, Type
from pymodbus.client.base import ModbusBaseClient
from pymodbus.exceptions import ConnectionException
from pymodbus.framer import ModbusFramer
from pymodbus.framer.socket_framer import ModbusSocketFramer
from pymodbus.logging import Log
from pymodbus.transport import CommType
DGRAM_TYPE = socket.SOCK_DGRAM
class AsyncModbusUdpClient(
ModbusBaseClient, asyncio.Protocol, asyncio.DatagramProtocol
):
"""**AsyncModbusUdpClient**.
:param host: Host IP address or host name
:param port: (optional) Port used for communication.
:param framer: (optional) Framer class.
:param source_address: (optional) source address of client,
:param kwargs: (optional) Experimental parameters
..tip::
See ModbusBaseClient for common parameters.
Example::
from pymodbus.client import AsyncModbusUdpClient
async def run():
client = AsyncModbusUdpClient("localhost")
await client.connect()
...
client.close()
"""
def __init__(
self,
host: str,
port: int = 502,
framer: Type[ModbusFramer] = ModbusSocketFramer,
source_address: Tuple[str, int] = None,
**kwargs: Any,
) -> None:
"""Initialize Asyncio Modbus UDP Client."""
asyncio.DatagramProtocol.__init__(self)
asyncio.Protocol.__init__(self)
ModbusBaseClient.__init__(
self, framer=framer, CommType=CommType.UDP, host=host, port=port, **kwargs
)
self.params.source_address = source_address
@property
def connected(self):
"""Return true if connected."""
return self.is_active()
async def connect(self) -> bool:
"""Start reconnecting asynchronous udp client.
:meta private:
"""
self.reset_delay()
Log.debug(
"Connecting to {}:{}.",
self.comm_params.host,
self.comm_params.port,
)
return await self.transport_connect()
class ModbusUdpClient(ModbusBaseClient):
"""**ModbusUdpClient**.
:param host: Host IP address or host name
:param port: (optional) Port used for communication.
:param framer: (optional) Framer class.
:param source_address: (optional) source address of client,
:param kwargs: (optional) Experimental parameters
..tip::
See ModbusBaseClient for common parameters.
Example::
from pymodbus.client import ModbusUdpClient
async def run():
client = ModbusUdpClient("localhost")
client.connect()
...
client.close()
Remark: There are no automatic reconnect as with AsyncModbusUdpClient
"""
def __init__(
self,
host: str,
port: int = 502,
framer: Type[ModbusFramer] = ModbusSocketFramer,
source_address: Tuple[str, int] = None,
**kwargs: Any,
) -> None:
"""Initialize Modbus UDP Client."""
kwargs["use_sync"] = True
self.transport = None
super().__init__(
framer=framer, port=port, host=host, CommType=CommType.UDP, **kwargs
)
self.params.source_address = source_address
self.socket = None
@property
def connected(self):
"""Connect internal."""
return self.socket is not None
def connect(self): # pylint: disable=invalid-overridden-method
"""Connect to the modbus tcp server.
:meta private:
"""
if self.socket:
return True
try:
family = ModbusUdpClient._get_address_family(self.comm_params.host)
self.socket = socket.socket(family, socket.SOCK_DGRAM)
self.socket.settimeout(self.comm_params.timeout_connect)
except OSError as exc:
Log.error("Unable to create udp socket {}", exc)
self.close()
return self.socket is not None
def close(self): # pylint: disable=arguments-differ
"""Close the underlying socket connection.
:meta private:
"""
self.socket = None
def send(self, request):
"""Send data on the underlying socket.
:meta private:
"""
super().send(request)
if not self.socket:
raise ConnectionException(str(self))
if request:
return self.socket.sendto(
request, (self.comm_params.host, self.comm_params.port)
)
return 0
def recv(self, size):
"""Read data from the underlying descriptor.
:meta private:
"""
super().recv(size)
if not self.socket:
raise ConnectionException(str(self))
return self.socket.recvfrom(size)[0]
def is_socket_open(self):
"""Check if socket is open.
:meta private:
"""
return True
def __str__(self):
"""Build a string representation of the connection."""
return f"ModbusUdpClient({self.comm_params.host}:{self.comm_params.port})"
def __repr__(self):
"""Return string representation."""
return (
f"<{self.__class__.__name__} at {hex(id(self))} socket={self.socket}, "
f"ipaddr={self.comm_params.host}, port={self.comm_params.port}, timeout={self.comm_params.timeout_connect}>"
)