mirror of
https://github.com/home-assistant/core.git
synced 2025-09-03 03:41:40 +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._scan_interval = int(entry[CONF_SCAN_INTERVAL])
|
||||||
self._cancel_timer: Callable[[], None] | None = None
|
self._cancel_timer: Callable[[], None] | None = None
|
||||||
self._cancel_call: Callable[[], None] | None = None
|
self._cancel_call: Callable[[], None] | None = None
|
||||||
|
|
||||||
self._attr_unique_id = entry.get(CONF_UNIQUE_ID)
|
self._attr_unique_id = entry.get(CONF_UNIQUE_ID)
|
||||||
self._attr_name = entry[CONF_NAME]
|
self._attr_name = entry[CONF_NAME]
|
||||||
self._attr_device_class = entry.get(CONF_DEVICE_CLASS)
|
self._attr_device_class = entry.get(CONF_DEVICE_CLASS)
|
||||||
@@ -177,9 +176,20 @@ class BasePlatform(Entity):
|
|||||||
self._attr_available = False
|
self._attr_available = False
|
||||||
self.async_write_ha_state()
|
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:
|
async def async_base_added_to_hass(self) -> None:
|
||||||
"""Handle entity which will be added."""
|
"""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(
|
self.async_on_remove(
|
||||||
async_dispatcher_connect(self.hass, SIGNAL_STOP_ENTITY, self.async_hold)
|
async_dispatcher_connect(self.hass, SIGNAL_STOP_ENTITY, self.async_hold)
|
||||||
)
|
)
|
||||||
|
@@ -4,7 +4,6 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from collections.abc import Callable
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from pymodbus.client import (
|
from pymodbus.client import (
|
||||||
@@ -28,11 +27,10 @@ from homeassistant.const import (
|
|||||||
CONF_TYPE,
|
CONF_TYPE,
|
||||||
EVENT_HOMEASSISTANT_STOP,
|
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 import config_validation as cv
|
||||||
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.typing import ConfigType
|
from homeassistant.helpers.typing import ConfigType
|
||||||
from homeassistant.util.hass_dict import HassKey
|
from homeassistant.util.hass_dict import HassKey
|
||||||
|
|
||||||
@@ -254,13 +252,13 @@ class ModbusHub:
|
|||||||
self._client: (
|
self._client: (
|
||||||
AsyncModbusSerialClient | AsyncModbusTcpClient | AsyncModbusUdpClient | None
|
AsyncModbusSerialClient | AsyncModbusTcpClient | AsyncModbusUdpClient | None
|
||||||
) = None
|
) = 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.event_connected = asyncio.Event()
|
||||||
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_request: dict[str, RunEntry] = {}
|
self._pb_request: dict[str, RunEntry] = {}
|
||||||
self._connect_task: asyncio.Task
|
self._connect_task: asyncio.Task
|
||||||
self._last_log_error: str = ""
|
self._last_log_error: str = ""
|
||||||
@@ -325,10 +323,10 @@ class ModbusHub:
|
|||||||
_LOGGER.info(message)
|
_LOGGER.info(message)
|
||||||
|
|
||||||
# Start counting down to allow modbus requests.
|
# Start counting down to allow modbus requests.
|
||||||
if self._config_delay:
|
if self.config_delay:
|
||||||
self._async_cancel_listener = async_call_later(
|
await asyncio.sleep(self.config_delay)
|
||||||
self.hass, self._config_delay, self.async_end_delay
|
self.config_delay = 0
|
||||||
)
|
self.event_connected.set()
|
||||||
|
|
||||||
async def async_setup(self) -> bool:
|
async def async_setup(self) -> bool:
|
||||||
"""Set up pymodbus client."""
|
"""Set up pymodbus client."""
|
||||||
@@ -349,12 +347,6 @@ class ModbusHub:
|
|||||||
)
|
)
|
||||||
return True
|
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:
|
async def async_restart(self) -> None:
|
||||||
"""Reconnect client."""
|
"""Reconnect client."""
|
||||||
if self._client:
|
if self._client:
|
||||||
@@ -364,9 +356,6 @@ class ModbusHub:
|
|||||||
|
|
||||||
async def async_close(self) -> None:
|
async def async_close(self) -> None:
|
||||||
"""Disconnect client."""
|
"""Disconnect client."""
|
||||||
if self._async_cancel_listener:
|
|
||||||
self._async_cancel_listener()
|
|
||||||
self._async_cancel_listener = None
|
|
||||||
if not self._connect_task.done():
|
if not self._connect_task.done():
|
||||||
self._connect_task.cancel()
|
self._connect_task.cancel()
|
||||||
|
|
||||||
@@ -426,8 +415,6 @@ class ModbusHub:
|
|||||||
use_call: str,
|
use_call: str,
|
||||||
) -> ModbusPDU | None:
|
) -> ModbusPDU | None:
|
||||||
"""Convert async to sync pymodbus call."""
|
"""Convert async to sync pymodbus call."""
|
||||||
if self._config_delay:
|
|
||||||
return None
|
|
||||||
async with self._lock:
|
async with self._lock:
|
||||||
if not self._client:
|
if not self._client:
|
||||||
return None
|
return None
|
||||||
|
@@ -23,6 +23,7 @@ from homeassistant.const import (
|
|||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
from homeassistant.util import dt as dt_util
|
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
|
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(
|
async def mock_modbus_fixture(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
caplog: pytest.LogCaptureFixture,
|
caplog: pytest.LogCaptureFixture,
|
||||||
|
freezer: FrozenDateTimeFactory,
|
||||||
check_config_loaded,
|
check_config_loaded,
|
||||||
config_addon,
|
config_addon,
|
||||||
do_config,
|
do_config,
|
||||||
@@ -158,6 +160,15 @@ async def mock_modbus_fixture(
|
|||||||
result = await async_setup_component(hass, DOMAIN, config)
|
result = await async_setup_component(hass, DOMAIN, config)
|
||||||
assert result or not check_config_loaded
|
assert result or not check_config_loaded
|
||||||
await hass.async_block_till_done()
|
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
|
return mock_pymodbus
|
||||||
|
|
||||||
|
|
||||||
|
@@ -920,6 +920,9 @@ async def mock_modbus_read_pymodbus_fixture(
|
|||||||
freezer.tick(timedelta(seconds=DEFAULT_SCAN_INTERVAL + 60))
|
freezer.tick(timedelta(seconds=DEFAULT_SCAN_INTERVAL + 60))
|
||||||
async_fire_time_changed(hass)
|
async_fire_time_changed(hass)
|
||||||
await hass.async_block_till_done()
|
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
|
return mock_pymodbus
|
||||||
|
|
||||||
|
|
||||||
@@ -1088,11 +1091,11 @@ async def test_delay(
|
|||||||
start_time = dt_util.utcnow()
|
start_time = dt_util.utcnow()
|
||||||
assert await async_setup_component(hass, DOMAIN, config) is True
|
assert await async_setup_component(hass, DOMAIN, config) is True
|
||||||
await hass.async_block_till_done()
|
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_sensor_active = start_time + timedelta(seconds=2)
|
||||||
time_after_delay = start_time + timedelta(seconds=(set_delay))
|
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)
|
time_stop = time_after_scan + timedelta(seconds=10)
|
||||||
now = start_time
|
now = start_time
|
||||||
while now < time_stop:
|
while now < time_stop:
|
||||||
@@ -1105,8 +1108,13 @@ async def test_delay(
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
if now > time_sensor_active:
|
if now > time_sensor_active:
|
||||||
if now <= time_after_delay:
|
if now <= time_after_delay:
|
||||||
assert hass.states.get(entity_id).state == STATE_UNAVAILABLE
|
assert hass.states.get(entity_id).state in (
|
||||||
elif now > time_after_scan:
|
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
|
assert hass.states.get(entity_id).state == STATE_ON
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user