Strictly type modbus.py. (#56375)
This commit is contained in:
parent
4c4bd740f3
commit
f3ad4ca0cc
1 changed files with 41 additions and 29 deletions
|
@ -4,12 +4,19 @@ from __future__ import annotations
|
||||||
import asyncio
|
import asyncio
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Any, Callable
|
||||||
|
|
||||||
from pymodbus.client.sync import ModbusSerialClient, ModbusTcpClient, ModbusUdpClient
|
from pymodbus.client.sync import (
|
||||||
|
BaseModbusClient,
|
||||||
|
ModbusSerialClient,
|
||||||
|
ModbusTcpClient,
|
||||||
|
ModbusUdpClient,
|
||||||
|
)
|
||||||
from pymodbus.constants import Defaults
|
from pymodbus.constants import Defaults
|
||||||
from pymodbus.exceptions import ModbusException
|
from pymodbus.exceptions import ModbusException
|
||||||
from pymodbus.pdu import ModbusResponse
|
from pymodbus.pdu import ModbusResponse
|
||||||
from pymodbus.transaction import ModbusRtuFramer
|
from pymodbus.transaction import ModbusRtuFramer
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_DELAY,
|
CONF_DELAY,
|
||||||
|
@ -21,10 +28,11 @@ from homeassistant.const import (
|
||||||
CONF_TYPE,
|
CONF_TYPE,
|
||||||
EVENT_HOMEASSISTANT_STOP,
|
EVENT_HOMEASSISTANT_STOP,
|
||||||
)
|
)
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import HomeAssistant, ServiceCall, callback
|
||||||
from homeassistant.helpers.discovery import async_load_platform
|
from homeassistant.helpers.discovery import async_load_platform
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||||
from homeassistant.helpers.event import async_call_later
|
from homeassistant.helpers.event import Event, async_call_later
|
||||||
|
from homeassistant.helpers.typing import ConfigType
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
ATTR_ADDRESS,
|
ATTR_ADDRESS,
|
||||||
|
@ -113,12 +121,12 @@ PYMODBUS_CALL = [
|
||||||
|
|
||||||
|
|
||||||
async def async_modbus_setup(
|
async def async_modbus_setup(
|
||||||
hass,
|
hass: HomeAssistant,
|
||||||
config,
|
config: ConfigType,
|
||||||
service_write_register_schema,
|
service_write_register_schema: vol.Schema,
|
||||||
service_write_coil_schema,
|
service_write_coil_schema: vol.Schema,
|
||||||
service_stop_start_schema,
|
service_stop_start_schema: vol.Schema,
|
||||||
):
|
) -> bool:
|
||||||
"""Set up Modbus component."""
|
"""Set up Modbus component."""
|
||||||
|
|
||||||
hass.data[DOMAIN] = hub_collect = {}
|
hass.data[DOMAIN] = hub_collect = {}
|
||||||
|
@ -138,7 +146,7 @@ async def async_modbus_setup(
|
||||||
async_load_platform(hass, component, DOMAIN, conf_hub, config)
|
async_load_platform(hass, component, DOMAIN, conf_hub, config)
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_stop_modbus(event):
|
async def async_stop_modbus(event: Event) -> None:
|
||||||
"""Stop Modbus service."""
|
"""Stop Modbus service."""
|
||||||
|
|
||||||
async_dispatcher_send(hass, SIGNAL_STOP_ENTITY)
|
async_dispatcher_send(hass, SIGNAL_STOP_ENTITY)
|
||||||
|
@ -147,7 +155,7 @@ async def async_modbus_setup(
|
||||||
|
|
||||||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, async_stop_modbus)
|
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, async_stop_modbus)
|
||||||
|
|
||||||
async def async_write_register(service):
|
async def async_write_register(service: ServiceCall) -> None:
|
||||||
"""Write Modbus registers."""
|
"""Write Modbus registers."""
|
||||||
unit = int(float(service.data[ATTR_UNIT]))
|
unit = int(float(service.data[ATTR_UNIT]))
|
||||||
address = int(float(service.data[ATTR_ADDRESS]))
|
address = int(float(service.data[ATTR_ADDRESS]))
|
||||||
|
@ -171,7 +179,7 @@ async def async_modbus_setup(
|
||||||
schema=service_write_register_schema,
|
schema=service_write_register_schema,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_write_coil(service):
|
async def async_write_coil(service: ServiceCall) -> None:
|
||||||
"""Write Modbus coil."""
|
"""Write Modbus coil."""
|
||||||
unit = service.data[ATTR_UNIT]
|
unit = service.data[ATTR_UNIT]
|
||||||
address = service.data[ATTR_ADDRESS]
|
address = service.data[ATTR_ADDRESS]
|
||||||
|
@ -188,7 +196,7 @@ async def async_modbus_setup(
|
||||||
DOMAIN, SERVICE_WRITE_COIL, async_write_coil, schema=service_write_coil_schema
|
DOMAIN, SERVICE_WRITE_COIL, async_write_coil, schema=service_write_coil_schema
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_stop_hub(service):
|
async def async_stop_hub(service: ServiceCall) -> None:
|
||||||
"""Stop Modbus hub."""
|
"""Stop Modbus hub."""
|
||||||
async_dispatcher_send(hass, SIGNAL_STOP_ENTITY)
|
async_dispatcher_send(hass, SIGNAL_STOP_ENTITY)
|
||||||
hub = hub_collect[service.data[ATTR_HUB]]
|
hub = hub_collect[service.data[ATTR_HUB]]
|
||||||
|
@ -198,7 +206,7 @@ async def async_modbus_setup(
|
||||||
DOMAIN, SERVICE_STOP, async_stop_hub, schema=service_stop_start_schema
|
DOMAIN, SERVICE_STOP, async_stop_hub, schema=service_stop_start_schema
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_restart_hub(service):
|
async def async_restart_hub(service: ServiceCall) -> None:
|
||||||
"""Restart Modbus hub."""
|
"""Restart Modbus hub."""
|
||||||
async_dispatcher_send(hass, SIGNAL_START_ENTITY)
|
async_dispatcher_send(hass, SIGNAL_START_ENTITY)
|
||||||
hub = hub_collect[service.data[ATTR_HUB]]
|
hub = hub_collect[service.data[ATTR_HUB]]
|
||||||
|
@ -213,19 +221,19 @@ async def async_modbus_setup(
|
||||||
class ModbusHub:
|
class ModbusHub:
|
||||||
"""Thread safe wrapper class for pymodbus."""
|
"""Thread safe wrapper class for pymodbus."""
|
||||||
|
|
||||||
def __init__(self, hass, client_config):
|
def __init__(self, hass: HomeAssistant, client_config: dict[str, Any]) -> None:
|
||||||
"""Initialize the Modbus hub."""
|
"""Initialize the Modbus hub."""
|
||||||
|
|
||||||
# generic configuration
|
# generic configuration
|
||||||
self._client = None
|
self._client: BaseModbusClient | None = None
|
||||||
self._async_cancel_listener = None
|
self._async_cancel_listener: Callable[[], None] | None = None
|
||||||
self._in_error = False
|
self._in_error = False
|
||||||
self._lock = asyncio.Lock()
|
self._lock = asyncio.Lock()
|
||||||
self.hass = hass
|
self.hass = hass
|
||||||
self.name = client_config[CONF_NAME]
|
self.name = client_config[CONF_NAME]
|
||||||
self._config_type = client_config[CONF_TYPE]
|
self._config_type = client_config[CONF_TYPE]
|
||||||
self._config_delay = client_config[CONF_DELAY]
|
self._config_delay = client_config[CONF_DELAY]
|
||||||
self._pb_call = {}
|
self._pb_call: dict[str, RunEntry] = {}
|
||||||
self._pb_class = {
|
self._pb_class = {
|
||||||
SERIAL: ModbusSerialClient,
|
SERIAL: ModbusSerialClient,
|
||||||
TCP: ModbusTcpClient,
|
TCP: ModbusTcpClient,
|
||||||
|
@ -264,7 +272,7 @@ class ModbusHub:
|
||||||
else:
|
else:
|
||||||
self._msg_wait = 0
|
self._msg_wait = 0
|
||||||
|
|
||||||
def _log_error(self, text: str, error_state=True):
|
def _log_error(self, text: str, error_state: bool = True) -> None:
|
||||||
log_text = f"Pymodbus: {self.name}: {text}"
|
log_text = f"Pymodbus: {self.name}: {text}"
|
||||||
if self._in_error:
|
if self._in_error:
|
||||||
_LOGGER.debug(log_text)
|
_LOGGER.debug(log_text)
|
||||||
|
@ -272,7 +280,7 @@ class ModbusHub:
|
||||||
_LOGGER.error(log_text)
|
_LOGGER.error(log_text)
|
||||||
self._in_error = error_state
|
self._in_error = error_state
|
||||||
|
|
||||||
async def async_setup(self):
|
async def async_setup(self) -> bool:
|
||||||
"""Set up pymodbus client."""
|
"""Set up pymodbus client."""
|
||||||
try:
|
try:
|
||||||
self._client = self._pb_class[self._config_type](**self._pb_params)
|
self._client = self._pb_class[self._config_type](**self._pb_params)
|
||||||
|
@ -287,7 +295,7 @@ class ModbusHub:
|
||||||
await self.async_connect_task()
|
await self.async_connect_task()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
async def async_connect_task(self):
|
async def async_connect_task(self) -> None:
|
||||||
"""Try to connect, and retry if needed."""
|
"""Try to connect, and retry if needed."""
|
||||||
async with self._lock:
|
async with self._lock:
|
||||||
if not await self.hass.async_add_executor_job(self._pymodbus_connect):
|
if not await self.hass.async_add_executor_job(self._pymodbus_connect):
|
||||||
|
@ -302,19 +310,19 @@ class ModbusHub:
|
||||||
)
|
)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_end_delay(self, args):
|
def async_end_delay(self, args: Any) -> None:
|
||||||
"""End startup delay."""
|
"""End startup delay."""
|
||||||
self._async_cancel_listener = None
|
self._async_cancel_listener = None
|
||||||
self._config_delay = 0
|
self._config_delay = 0
|
||||||
|
|
||||||
async def async_restart(self):
|
async def async_restart(self) -> None:
|
||||||
"""Reconnect client."""
|
"""Reconnect client."""
|
||||||
if self._client:
|
if self._client:
|
||||||
await self.async_close()
|
await self.async_close()
|
||||||
|
|
||||||
await self.async_setup()
|
await self.async_setup()
|
||||||
|
|
||||||
async def async_close(self):
|
async def async_close(self) -> None:
|
||||||
"""Disconnect client."""
|
"""Disconnect client."""
|
||||||
if self._async_cancel_listener:
|
if self._async_cancel_listener:
|
||||||
self._async_cancel_listener()
|
self._async_cancel_listener()
|
||||||
|
@ -330,8 +338,10 @@ class ModbusHub:
|
||||||
message = f"modbus {self.name} communication closed"
|
message = f"modbus {self.name} communication closed"
|
||||||
_LOGGER.warning(message)
|
_LOGGER.warning(message)
|
||||||
|
|
||||||
def _pymodbus_connect(self):
|
def _pymodbus_connect(self) -> bool:
|
||||||
"""Connect client."""
|
"""Connect client."""
|
||||||
|
if not self._client:
|
||||||
|
return False
|
||||||
try:
|
try:
|
||||||
self._client.connect()
|
self._client.connect()
|
||||||
except ModbusException as exception_error:
|
except ModbusException as exception_error:
|
||||||
|
@ -342,7 +352,9 @@ class ModbusHub:
|
||||||
_LOGGER.warning(message)
|
_LOGGER.warning(message)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _pymodbus_call(self, unit, address, value, use_call):
|
def _pymodbus_call(
|
||||||
|
self, unit: int, address: int, value: int | list[int], use_call: str
|
||||||
|
) -> ModbusResponse:
|
||||||
"""Call sync. pymodbus."""
|
"""Call sync. pymodbus."""
|
||||||
kwargs = {"unit": unit} if unit else {}
|
kwargs = {"unit": unit} if unit else {}
|
||||||
entry = self._pb_call[use_call]
|
entry = self._pb_call[use_call]
|
||||||
|
@ -359,10 +371,10 @@ class ModbusHub:
|
||||||
|
|
||||||
async def async_pymodbus_call(
|
async def async_pymodbus_call(
|
||||||
self,
|
self,
|
||||||
unit: str | int | None,
|
unit: int | None,
|
||||||
address: int,
|
address: int,
|
||||||
value: str | int,
|
value: int | list[int],
|
||||||
use_call: str | None,
|
use_call: str,
|
||||||
) -> ModbusResponse | None:
|
) -> ModbusResponse | None:
|
||||||
"""Convert async to sync pymodbus call."""
|
"""Convert async to sync pymodbus call."""
|
||||||
if self._config_delay:
|
if self._config_delay:
|
||||||
|
|
Loading…
Add table
Reference in a new issue