mirror of
https://github.com/home-assistant/core.git
synced 2025-08-31 18:31:35 +02:00
Do not start modbus update process until connection+delay. (#150796)
This commit is contained in:
@@ -92,7 +92,6 @@ class BasePlatform(Entity):
|
||||
self._scan_interval = int(entry[CONF_SCAN_INTERVAL])
|
||||
self._cancel_timer: Callable[[], None] | None = None
|
||||
self._cancel_call: Callable[[], None] | None = None
|
||||
|
||||
self._attr_unique_id = entry.get(CONF_UNIQUE_ID)
|
||||
self._attr_name = entry[CONF_NAME]
|
||||
self._attr_device_class = entry.get(CONF_DEVICE_CLASS)
|
||||
@@ -177,9 +176,20 @@ class BasePlatform(Entity):
|
||||
self._attr_available = False
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_await_connection(self, _now: Any) -> None:
|
||||
"""Wait for first connect."""
|
||||
await self._hub.event_connected.wait()
|
||||
self.async_run()
|
||||
|
||||
async def async_base_added_to_hass(self) -> None:
|
||||
"""Handle entity which will be added."""
|
||||
self.async_run()
|
||||
self.async_on_remove(
|
||||
async_call_later(
|
||||
self.hass,
|
||||
self._hub.config_delay + 0.1,
|
||||
self.async_await_connection,
|
||||
)
|
||||
)
|
||||
self.async_on_remove(
|
||||
async_dispatcher_connect(self.hass, SIGNAL_STOP_ENTITY, self.async_hold)
|
||||
)
|
||||
|
@@ -4,7 +4,6 @@ from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from collections import namedtuple
|
||||
from collections.abc import Callable
|
||||
from typing import Any
|
||||
|
||||
from pymodbus.client import (
|
||||
@@ -28,11 +27,10 @@ from homeassistant.const import (
|
||||
CONF_TYPE,
|
||||
EVENT_HOMEASSISTANT_STOP,
|
||||
)
|
||||
from homeassistant.core import Event, HomeAssistant, ServiceCall, callback
|
||||
from homeassistant.core import Event, HomeAssistant, ServiceCall
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.discovery import async_load_platform
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||
from homeassistant.helpers.event import async_call_later
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
from homeassistant.util.hass_dict import HassKey
|
||||
|
||||
@@ -254,13 +252,13 @@ class ModbusHub:
|
||||
self._client: (
|
||||
AsyncModbusSerialClient | AsyncModbusTcpClient | AsyncModbusUdpClient | None
|
||||
) = None
|
||||
self._async_cancel_listener: Callable[[], None] | None = None
|
||||
self._in_error = False
|
||||
self._lock = asyncio.Lock()
|
||||
self.event_connected = asyncio.Event()
|
||||
self.hass = hass
|
||||
self.name = client_config[CONF_NAME]
|
||||
self._config_type = client_config[CONF_TYPE]
|
||||
self._config_delay = client_config[CONF_DELAY]
|
||||
self.config_delay = client_config[CONF_DELAY]
|
||||
self._pb_request: dict[str, RunEntry] = {}
|
||||
self._connect_task: asyncio.Task
|
||||
self._last_log_error: str = ""
|
||||
@@ -325,10 +323,10 @@ class ModbusHub:
|
||||
_LOGGER.info(message)
|
||||
|
||||
# Start counting down to allow modbus requests.
|
||||
if self._config_delay:
|
||||
self._async_cancel_listener = async_call_later(
|
||||
self.hass, self._config_delay, self.async_end_delay
|
||||
)
|
||||
if self.config_delay:
|
||||
await asyncio.sleep(self.config_delay)
|
||||
self.config_delay = 0
|
||||
self.event_connected.set()
|
||||
|
||||
async def async_setup(self) -> bool:
|
||||
"""Set up pymodbus client."""
|
||||
@@ -349,12 +347,6 @@ class ModbusHub:
|
||||
)
|
||||
return True
|
||||
|
||||
@callback
|
||||
def async_end_delay(self, args: Any) -> None:
|
||||
"""End startup delay."""
|
||||
self._async_cancel_listener = None
|
||||
self._config_delay = 0
|
||||
|
||||
async def async_restart(self) -> None:
|
||||
"""Reconnect client."""
|
||||
if self._client:
|
||||
@@ -364,9 +356,6 @@ class ModbusHub:
|
||||
|
||||
async def async_close(self) -> None:
|
||||
"""Disconnect client."""
|
||||
if self._async_cancel_listener:
|
||||
self._async_cancel_listener()
|
||||
self._async_cancel_listener = None
|
||||
if not self._connect_task.done():
|
||||
self._connect_task.cancel()
|
||||
|
||||
@@ -426,8 +415,6 @@ class ModbusHub:
|
||||
use_call: str,
|
||||
) -> ModbusPDU | None:
|
||||
"""Convert async to sync pymodbus call."""
|
||||
if self._config_delay:
|
||||
return None
|
||||
async with self._lock:
|
||||
if not self._client:
|
||||
return None
|
||||
|
@@ -23,6 +23,7 @@ from homeassistant.const import (
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.util import dt as dt_util
|
||||
from homeassistant.util.hass_dict import HassKey
|
||||
|
||||
from tests.common import async_fire_time_changed, mock_restore_cache
|
||||
|
||||
@@ -121,6 +122,7 @@ def mock_pymodbus_fixture(do_exception, register_words):
|
||||
async def mock_modbus_fixture(
|
||||
hass: HomeAssistant,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
check_config_loaded,
|
||||
config_addon,
|
||||
do_config,
|
||||
@@ -158,6 +160,15 @@ async def mock_modbus_fixture(
|
||||
result = await async_setup_component(hass, DOMAIN, config)
|
||||
assert result or not check_config_loaded
|
||||
await hass.async_block_till_done()
|
||||
key = HassKey(DOMAIN)
|
||||
if key not in hass.data:
|
||||
return None
|
||||
hub = hass.data[HassKey(DOMAIN)][TEST_MODBUS_NAME]
|
||||
await hub.event_connected.wait()
|
||||
assert hub.event_connected.is_set()
|
||||
freezer.tick(timedelta(seconds=1))
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
return mock_pymodbus
|
||||
|
||||
|
||||
|
@@ -920,6 +920,9 @@ async def mock_modbus_read_pymodbus_fixture(
|
||||
freezer.tick(timedelta(seconds=DEFAULT_SCAN_INTERVAL + 60))
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
freezer.tick(timedelta(seconds=DEFAULT_SCAN_INTERVAL + 60))
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
return mock_pymodbus
|
||||
|
||||
|
||||
@@ -1088,11 +1091,11 @@ async def test_delay(
|
||||
start_time = dt_util.utcnow()
|
||||
assert await async_setup_component(hass, DOMAIN, config) is True
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get(entity_id).state == STATE_UNKNOWN
|
||||
assert hass.states.get(entity_id).state in (STATE_UNKNOWN, STATE_UNAVAILABLE)
|
||||
|
||||
time_sensor_active = start_time + timedelta(seconds=2)
|
||||
time_after_delay = start_time + timedelta(seconds=(set_delay))
|
||||
time_after_scan = start_time + timedelta(seconds=(set_delay + set_scan_interval))
|
||||
time_after_scan = time_after_delay + timedelta(seconds=(set_scan_interval))
|
||||
time_stop = time_after_scan + timedelta(seconds=10)
|
||||
now = start_time
|
||||
while now < time_stop:
|
||||
@@ -1105,8 +1108,13 @@ async def test_delay(
|
||||
await hass.async_block_till_done()
|
||||
if now > time_sensor_active:
|
||||
if now <= time_after_delay:
|
||||
assert hass.states.get(entity_id).state == STATE_UNAVAILABLE
|
||||
elif now > time_after_scan:
|
||||
assert hass.states.get(entity_id).state in (
|
||||
STATE_UNKNOWN,
|
||||
STATE_UNAVAILABLE,
|
||||
)
|
||||
if now <= time_after_delay + timedelta(seconds=2):
|
||||
continue
|
||||
if now > time_after_scan + timedelta(seconds=2):
|
||||
assert hass.states.get(entity_id).state == STATE_ON
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user