Discover new devices at runtime in onewire (#135199)

This commit is contained in:
epenet 2025-01-10 11:53:31 +01:00 committed by GitHub
parent 24c70caf33
commit 475a2fb828
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 299 additions and 45 deletions

View File

@ -37,6 +37,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: OneWireConfigEntry) -> b
await hass.config_entries.async_forward_entry_setups(entry, _PLATFORMS) await hass.config_entries.async_forward_entry_setups(entry, _PLATFORMS)
onewire_hub.schedule_scan_for_new_devices()
entry.async_on_unload(entry.add_update_listener(options_update_listener)) entry.async_on_unload(entry.add_update_listener(options_update_listener))
return True return True

View File

@ -13,11 +13,17 @@ from homeassistant.components.binary_sensor import (
) )
from homeassistant.const import EntityCategory from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DEVICE_KEYS_0_3, DEVICE_KEYS_0_7, DEVICE_KEYS_A_B, READ_MODE_BOOL from .const import DEVICE_KEYS_0_3, DEVICE_KEYS_0_7, DEVICE_KEYS_A_B, READ_MODE_BOOL
from .entity import OneWireEntity, OneWireEntityDescription from .entity import OneWireEntity, OneWireEntityDescription
from .onewirehub import OneWireConfigEntry, OneWireHub from .onewirehub import (
SIGNAL_NEW_DEVICE_CONNECTED,
OneWireConfigEntry,
OneWireHub,
OWDeviceDescription,
)
# the library uses non-persistent connections # the library uses non-persistent connections
# and concurrent access to the bus is managed by the server # and concurrent access to the bus is managed by the server
@ -98,16 +104,28 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up 1-Wire platform.""" """Set up 1-Wire platform."""
async_add_entities(get_entities(config_entry.runtime_data), True)
async def _add_entities(
hub: OneWireHub, devices: list[OWDeviceDescription]
) -> None:
"""Add 1-Wire entities for all devices."""
if not devices:
return
async_add_entities(get_entities(hub, devices), True)
hub = config_entry.runtime_data
await _add_entities(hub, hub.devices)
config_entry.async_on_unload(
async_dispatcher_connect(hass, SIGNAL_NEW_DEVICE_CONNECTED, _add_entities)
)
def get_entities(onewire_hub: OneWireHub) -> list[OneWireBinarySensor]: def get_entities(
onewire_hub: OneWireHub, devices: list[OWDeviceDescription]
) -> list[OneWireBinarySensor]:
"""Get a list of entities.""" """Get a list of entities."""
if not onewire_hub.devices:
return []
entities: list[OneWireBinarySensor] = [] entities: list[OneWireBinarySensor] = []
for device in onewire_hub.devices: for device in devices:
family = device.family family = device.family
device_id = device.id device_id = device.id
device_type = device.type device_type = device.type

View File

@ -2,6 +2,7 @@
from __future__ import annotations from __future__ import annotations
from datetime import datetime, timedelta
import logging import logging
import os import os
@ -9,9 +10,12 @@ from pyownet import protocol
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_VIA_DEVICE, CONF_HOST, CONF_PORT from homeassistant.const import ATTR_VIA_DEVICE, CONF_HOST, CONF_PORT
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import device_registry as dr from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.event import async_track_time_interval
from homeassistant.util.signal_type import SignalType
from .const import ( from .const import (
DEVICE_SUPPORT, DEVICE_SUPPORT,
@ -32,10 +36,15 @@ DEVICE_MANUFACTURER = {
"EF": MANUFACTURER_HOBBYBOARDS, "EF": MANUFACTURER_HOBBYBOARDS,
} }
_DEVICE_SCAN_INTERVAL = timedelta(minutes=5)
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
type OneWireConfigEntry = ConfigEntry[OneWireHub] type OneWireConfigEntry = ConfigEntry[OneWireHub]
SIGNAL_NEW_DEVICE_CONNECTED = SignalType["OneWireHub", list[OWDeviceDescription]](
f"{DOMAIN}_new_device_connected"
)
def _is_known_device(device_family: str, device_type: str | None) -> bool: def _is_known_device(device_family: str, device_type: str | None) -> bool:
"""Check if device family/type is known to the library.""" """Check if device family/type is known to the library."""
@ -69,14 +78,42 @@ class OneWireHub:
async def initialize(self) -> None: async def initialize(self) -> None:
"""Initialize a config entry.""" """Initialize a config entry."""
await self._hass.async_add_executor_job(self._initialize) await self._hass.async_add_executor_job(self._initialize)
# Populate the device registry self._populate_device_registry(self.devices)
@callback
def _populate_device_registry(self, devices: list[OWDeviceDescription]) -> None:
"""Populate the device registry."""
device_registry = dr.async_get(self._hass) device_registry = dr.async_get(self._hass)
for device in self.devices: for device in devices:
device_registry.async_get_or_create( device_registry.async_get_or_create(
config_entry_id=self._config_entry.entry_id, config_entry_id=self._config_entry.entry_id,
**device.device_info, **device.device_info,
) )
def schedule_scan_for_new_devices(self) -> None:
"""Schedule a regular scan of the bus for new devices."""
self._config_entry.async_on_unload(
async_track_time_interval(
self._hass, self._scan_for_new_devices, _DEVICE_SCAN_INTERVAL
)
)
async def _scan_for_new_devices(self, _: datetime) -> None:
"""Scan the bus for new devices."""
devices = await self._hass.async_add_executor_job(
_discover_devices, self.owproxy
)
existing_device_ids = [device.id for device in self.devices]
new_devices = [
device for device in devices if device.id not in existing_device_ids
]
if new_devices:
self.devices.extend(new_devices)
self._populate_device_registry(new_devices)
async_dispatcher_send(
self._hass, SIGNAL_NEW_DEVICE_CONNECTED, self, new_devices
)
def _discover_devices( def _discover_devices(
owproxy: protocol._Proxy, path: str = "/", parent_id: str | None = None owproxy: protocol._Proxy, path: str = "/", parent_id: str | None = None

View File

@ -84,8 +84,8 @@ rules:
comment: It doesn't make sense to override defaults comment: It doesn't make sense to override defaults
reconfiguration-flow: done reconfiguration-flow: done
dynamic-devices: dynamic-devices:
status: todo status: done
comment: Not yet implemented comment: The bus is scanned for new devices at regular interval
discovery-update-info: discovery-update-info:
status: todo status: todo
comment: Under review comment: Under review

View File

@ -9,11 +9,17 @@ import os
from homeassistant.components.select import SelectEntity, SelectEntityDescription from homeassistant.components.select import SelectEntity, SelectEntityDescription
from homeassistant.const import EntityCategory from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import READ_MODE_INT from .const import READ_MODE_INT
from .entity import OneWireEntity, OneWireEntityDescription from .entity import OneWireEntity, OneWireEntityDescription
from .onewirehub import OneWireConfigEntry, OneWireHub from .onewirehub import (
SIGNAL_NEW_DEVICE_CONNECTED,
OneWireConfigEntry,
OneWireHub,
OWDeviceDescription,
)
# the library uses non-persistent connections # the library uses non-persistent connections
# and concurrent access to the bus is managed by the server # and concurrent access to the bus is managed by the server
@ -45,17 +51,29 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up 1-Wire platform.""" """Set up 1-Wire platform."""
async_add_entities(get_entities(config_entry.runtime_data), True)
async def _add_entities(
hub: OneWireHub, devices: list[OWDeviceDescription]
) -> None:
"""Add 1-Wire entities for all devices."""
if not devices:
return
async_add_entities(get_entities(hub, devices), True)
hub = config_entry.runtime_data
await _add_entities(hub, hub.devices)
config_entry.async_on_unload(
async_dispatcher_connect(hass, SIGNAL_NEW_DEVICE_CONNECTED, _add_entities)
)
def get_entities(onewire_hub: OneWireHub) -> list[OneWireSelectEntity]: def get_entities(
onewire_hub: OneWireHub, devices: list[OWDeviceDescription]
) -> list[OneWireSelectEntity]:
"""Get a list of entities.""" """Get a list of entities."""
if not onewire_hub.devices:
return []
entities: list[OneWireSelectEntity] = [] entities: list[OneWireSelectEntity] = []
for device in onewire_hub.devices: for device in devices:
family = device.family family = device.family
device_id = device.id device_id = device.id
device_info = device.device_info device_info = device.device_info

View File

@ -26,6 +26,7 @@ from homeassistant.const import (
UnitOfTemperature, UnitOfTemperature,
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType from homeassistant.helpers.typing import StateType
@ -39,7 +40,12 @@ from .const import (
READ_MODE_INT, READ_MODE_INT,
) )
from .entity import OneWireEntity, OneWireEntityDescription from .entity import OneWireEntity, OneWireEntityDescription
from .onewirehub import OneWireConfigEntry, OneWireHub from .onewirehub import (
SIGNAL_NEW_DEVICE_CONNECTED,
OneWireConfigEntry,
OneWireHub,
OWDeviceDescription,
)
# the library uses non-persistent connections # the library uses non-persistent connections
# and concurrent access to the bus is managed by the server # and concurrent access to the bus is managed by the server
@ -357,23 +363,35 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up 1-Wire platform.""" """Set up 1-Wire platform."""
async def _add_entities(
hub: OneWireHub, devices: list[OWDeviceDescription]
) -> None:
"""Add 1-Wire entities for all devices."""
if not devices:
return
# note: we have to go through the executor as SENSOR platform # note: we have to go through the executor as SENSOR platform
# makes extra calls to the hub during device listing # makes extra calls to the hub during device listing
entities = await hass.async_add_executor_job( entities = await hass.async_add_executor_job(
get_entities, config_entry.runtime_data, config_entry.options get_entities, hub, devices, config_entry.options
) )
async_add_entities(entities, True) async_add_entities(entities, True)
hub = config_entry.runtime_data
await _add_entities(hub, hub.devices)
config_entry.async_on_unload(
async_dispatcher_connect(hass, SIGNAL_NEW_DEVICE_CONNECTED, _add_entities)
)
def get_entities( def get_entities(
onewire_hub: OneWireHub, options: MappingProxyType[str, Any] onewire_hub: OneWireHub,
devices: list[OWDeviceDescription],
options: MappingProxyType[str, Any],
) -> list[OneWireSensor]: ) -> list[OneWireSensor]:
"""Get a list of entities.""" """Get a list of entities."""
if not onewire_hub.devices:
return []
entities: list[OneWireSensor] = [] entities: list[OneWireSensor] = []
for device in onewire_hub.devices: for device in devices:
family = device.family family = device.family
device_type = device.type device_type = device.type
device_id = device.id device_id = device.id

View File

@ -10,11 +10,17 @@ from typing import Any
from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
from homeassistant.const import EntityCategory from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DEVICE_KEYS_0_3, DEVICE_KEYS_0_7, DEVICE_KEYS_A_B, READ_MODE_BOOL from .const import DEVICE_KEYS_0_3, DEVICE_KEYS_0_7, DEVICE_KEYS_A_B, READ_MODE_BOOL
from .entity import OneWireEntity, OneWireEntityDescription from .entity import OneWireEntity, OneWireEntityDescription
from .onewirehub import OneWireConfigEntry, OneWireHub from .onewirehub import (
SIGNAL_NEW_DEVICE_CONNECTED,
OneWireConfigEntry,
OneWireHub,
OWDeviceDescription,
)
# the library uses non-persistent connections # the library uses non-persistent connections
# and concurrent access to the bus is managed by the server # and concurrent access to the bus is managed by the server
@ -158,17 +164,29 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up 1-Wire platform.""" """Set up 1-Wire platform."""
async_add_entities(get_entities(config_entry.runtime_data), True)
async def _add_entities(
hub: OneWireHub, devices: list[OWDeviceDescription]
) -> None:
"""Add 1-Wire entities for all devices."""
if not devices:
return
async_add_entities(get_entities(hub, devices), True)
hub = config_entry.runtime_data
await _add_entities(hub, hub.devices)
config_entry.async_on_unload(
async_dispatcher_connect(hass, SIGNAL_NEW_DEVICE_CONNECTED, _add_entities)
)
def get_entities(onewire_hub: OneWireHub) -> list[OneWireSwitch]: def get_entities(
onewire_hub: OneWireHub, devices: list[OWDeviceDescription]
) -> list[OneWireSwitch]:
"""Get a list of entities.""" """Get a list of entities."""
if not onewire_hub.devices:
return []
entities: list[OneWireSwitch] = [] entities: list[OneWireSwitch] = []
for device in onewire_hub.devices: for device in devices:
family = device.family family = device.family
device_type = device.type device_type = device.type
device_id = device.id device_id = device.id

View File

@ -3,9 +3,11 @@
from collections.abc import Generator from collections.abc import Generator
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
from freezegun.api import FrozenDateTimeFactory
import pytest import pytest
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
from homeassistant.components.onewire.onewirehub import _DEVICE_SCAN_INTERVAL
from homeassistant.const import Platform from homeassistant.const import Platform
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er from homeassistant.helpers import entity_registry as er
@ -13,7 +15,7 @@ from homeassistant.helpers import entity_registry as er
from . import setup_owproxy_mock_devices from . import setup_owproxy_mock_devices
from .const import MOCK_OWPROXY_DEVICES from .const import MOCK_OWPROXY_DEVICES
from tests.common import MockConfigEntry, snapshot_platform from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
@ -31,8 +33,35 @@ async def test_binary_sensors(
entity_registry: er.EntityRegistry, entity_registry: er.EntityRegistry,
snapshot: SnapshotAssertion, snapshot: SnapshotAssertion,
) -> None: ) -> None:
"""Test for 1-Wire binary sensors.""" """Test for 1-Wire binary sensor entities."""
setup_owproxy_mock_devices(owproxy, MOCK_OWPROXY_DEVICES.keys()) setup_owproxy_mock_devices(owproxy, MOCK_OWPROXY_DEVICES.keys())
await hass.config_entries.async_setup(config_entry.entry_id) await hass.config_entries.async_setup(config_entry.entry_id)
await snapshot_platform(hass, entity_registry, snapshot, config_entry.entry_id) await snapshot_platform(hass, entity_registry, snapshot, config_entry.entry_id)
@pytest.mark.parametrize("device_id", ["29.111111111111"])
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_binary_sensors_delayed(
hass: HomeAssistant,
config_entry: MockConfigEntry,
owproxy: MagicMock,
device_id: str,
entity_registry: er.EntityRegistry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test for delayed 1-Wire binary sensor entities."""
setup_owproxy_mock_devices(owproxy, [])
await hass.config_entries.async_setup(config_entry.entry_id)
assert not er.async_entries_for_config_entry(entity_registry, config_entry.entry_id)
setup_owproxy_mock_devices(owproxy, [device_id])
freezer.tick(_DEVICE_SCAN_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done(wait_background_tasks=True)
assert (
len(er.async_entries_for_config_entry(entity_registry, config_entry.entry_id))
== 8
)

View File

@ -3,11 +3,13 @@
from copy import deepcopy from copy import deepcopy
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
from freezegun.api import FrozenDateTimeFactory
from pyownet import protocol from pyownet import protocol
import pytest import pytest
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
from homeassistant.components.onewire.const import DOMAIN from homeassistant.components.onewire.const import DOMAIN
from homeassistant.components.onewire.onewirehub import _DEVICE_SCAN_INTERVAL
from homeassistant.config_entries import ConfigEntryState from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import Platform from homeassistant.const import Platform
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -17,7 +19,7 @@ from homeassistant.setup import async_setup_component
from . import setup_owproxy_mock_devices from . import setup_owproxy_mock_devices
from .const import MOCK_OWPROXY_DEVICES from .const import MOCK_OWPROXY_DEVICES
from tests.common import MockConfigEntry from tests.common import MockConfigEntry, async_fire_time_changed
from tests.typing import WebSocketGenerator from tests.typing import WebSocketGenerator
@ -102,6 +104,31 @@ async def test_registry(
assert device_entry == snapshot(name=f"{device_entry.name}-entry") assert device_entry == snapshot(name=f"{device_entry.name}-entry")
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_registry_delayed(
hass: HomeAssistant,
config_entry: MockConfigEntry,
owproxy: MagicMock,
device_registry: dr.DeviceRegistry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test device are correctly registered."""
setup_owproxy_mock_devices(owproxy, [])
await hass.config_entries.async_setup(config_entry.entry_id)
assert not dr.async_entries_for_config_entry(device_registry, config_entry.entry_id)
setup_owproxy_mock_devices(owproxy, ["1F.111111111111"])
freezer.tick(_DEVICE_SCAN_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done(wait_background_tasks=True)
assert (
len(dr.async_entries_for_config_entry(device_registry, config_entry.entry_id))
== 2
)
@patch("homeassistant.components.onewire._PLATFORMS", [Platform.SENSOR]) @patch("homeassistant.components.onewire._PLATFORMS", [Platform.SENSOR])
async def test_registry_cleanup( async def test_registry_cleanup(
hass: HomeAssistant, hass: HomeAssistant,

View File

@ -3,9 +3,11 @@
from collections.abc import Generator from collections.abc import Generator
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
from freezegun.api import FrozenDateTimeFactory
import pytest import pytest
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
from homeassistant.components.onewire.onewirehub import _DEVICE_SCAN_INTERVAL
from homeassistant.components.select import ( from homeassistant.components.select import (
DOMAIN as SELECT_DOMAIN, DOMAIN as SELECT_DOMAIN,
SERVICE_SELECT_OPTION, SERVICE_SELECT_OPTION,
@ -17,7 +19,7 @@ from homeassistant.helpers import entity_registry as er
from . import setup_owproxy_mock_devices from . import setup_owproxy_mock_devices
from .const import MOCK_OWPROXY_DEVICES from .const import MOCK_OWPROXY_DEVICES
from tests.common import MockConfigEntry, snapshot_platform from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
@ -42,6 +44,33 @@ async def test_selects(
await snapshot_platform(hass, entity_registry, snapshot, config_entry.entry_id) await snapshot_platform(hass, entity_registry, snapshot, config_entry.entry_id)
@pytest.mark.parametrize("device_id", ["28.111111111111"])
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_selects_delayed(
hass: HomeAssistant,
config_entry: MockConfigEntry,
owproxy: MagicMock,
device_id: str,
entity_registry: er.EntityRegistry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test for delayed 1-Wire select entities."""
setup_owproxy_mock_devices(owproxy, [])
await hass.config_entries.async_setup(config_entry.entry_id)
assert not er.async_entries_for_config_entry(entity_registry, config_entry.entry_id)
setup_owproxy_mock_devices(owproxy, [device_id])
freezer.tick(_DEVICE_SCAN_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done(wait_background_tasks=True)
assert (
len(er.async_entries_for_config_entry(entity_registry, config_entry.entry_id))
== 1
)
@pytest.mark.parametrize("device_id", ["28.111111111111"]) @pytest.mark.parametrize("device_id", ["28.111111111111"])
async def test_selection_option_service( async def test_selection_option_service(
hass: HomeAssistant, hass: HomeAssistant,

View File

@ -5,10 +5,12 @@ from copy import deepcopy
import logging import logging
from unittest.mock import MagicMock, _patch_dict, patch from unittest.mock import MagicMock, _patch_dict, patch
from freezegun.api import FrozenDateTimeFactory
from pyownet.protocol import OwnetError from pyownet.protocol import OwnetError
import pytest import pytest
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
from homeassistant.components.onewire.onewirehub import _DEVICE_SCAN_INTERVAL
from homeassistant.const import Platform from homeassistant.const import Platform
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er from homeassistant.helpers import entity_registry as er
@ -16,7 +18,7 @@ from homeassistant.helpers import entity_registry as er
from . import setup_owproxy_mock_devices from . import setup_owproxy_mock_devices
from .const import ATTR_INJECT_READS, MOCK_OWPROXY_DEVICES from .const import ATTR_INJECT_READS, MOCK_OWPROXY_DEVICES
from tests.common import MockConfigEntry, snapshot_platform from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
@ -34,13 +36,40 @@ async def test_sensors(
entity_registry: er.EntityRegistry, entity_registry: er.EntityRegistry,
snapshot: SnapshotAssertion, snapshot: SnapshotAssertion,
) -> None: ) -> None:
"""Test for 1-Wire sensors.""" """Test for 1-Wire sensor entities."""
setup_owproxy_mock_devices(owproxy, MOCK_OWPROXY_DEVICES.keys()) setup_owproxy_mock_devices(owproxy, MOCK_OWPROXY_DEVICES.keys())
await hass.config_entries.async_setup(config_entry.entry_id) await hass.config_entries.async_setup(config_entry.entry_id)
await snapshot_platform(hass, entity_registry, snapshot, config_entry.entry_id) await snapshot_platform(hass, entity_registry, snapshot, config_entry.entry_id)
@pytest.mark.parametrize("device_id", ["12.111111111111"])
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_sensors_delayed(
hass: HomeAssistant,
config_entry: MockConfigEntry,
owproxy: MagicMock,
device_id: str,
entity_registry: er.EntityRegistry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test for delayed 1-Wire sensor entities."""
setup_owproxy_mock_devices(owproxy, [])
await hass.config_entries.async_setup(config_entry.entry_id)
assert not er.async_entries_for_config_entry(entity_registry, config_entry.entry_id)
setup_owproxy_mock_devices(owproxy, [device_id])
freezer.tick(_DEVICE_SCAN_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done(wait_background_tasks=True)
assert (
len(er.async_entries_for_config_entry(entity_registry, config_entry.entry_id))
== 2
)
@pytest.mark.parametrize("device_id", ["12.111111111111"]) @pytest.mark.parametrize("device_id", ["12.111111111111"])
async def test_tai8570_sensors( async def test_tai8570_sensors(
hass: HomeAssistant, hass: HomeAssistant,

View File

@ -3,9 +3,11 @@
from collections.abc import Generator from collections.abc import Generator
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
from freezegun.api import FrozenDateTimeFactory
import pytest import pytest
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
from homeassistant.components.onewire.onewirehub import _DEVICE_SCAN_INTERVAL
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_ENTITY_ID,
@ -20,7 +22,7 @@ from homeassistant.helpers import entity_registry as er
from . import setup_owproxy_mock_devices from . import setup_owproxy_mock_devices
from .const import MOCK_OWPROXY_DEVICES from .const import MOCK_OWPROXY_DEVICES
from tests.common import MockConfigEntry, snapshot_platform from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
@ -38,13 +40,40 @@ async def test_switches(
entity_registry: er.EntityRegistry, entity_registry: er.EntityRegistry,
snapshot: SnapshotAssertion, snapshot: SnapshotAssertion,
) -> None: ) -> None:
"""Test for 1-Wire switches.""" """Test for 1-Wire switch entities."""
setup_owproxy_mock_devices(owproxy, MOCK_OWPROXY_DEVICES.keys()) setup_owproxy_mock_devices(owproxy, MOCK_OWPROXY_DEVICES.keys())
await hass.config_entries.async_setup(config_entry.entry_id) await hass.config_entries.async_setup(config_entry.entry_id)
await snapshot_platform(hass, entity_registry, snapshot, config_entry.entry_id) await snapshot_platform(hass, entity_registry, snapshot, config_entry.entry_id)
@pytest.mark.parametrize("device_id", ["05.111111111111"])
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_switches_delayed(
hass: HomeAssistant,
config_entry: MockConfigEntry,
owproxy: MagicMock,
device_id: str,
entity_registry: er.EntityRegistry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test for delayed 1-Wire switch entities."""
setup_owproxy_mock_devices(owproxy, [])
await hass.config_entries.async_setup(config_entry.entry_id)
assert not er.async_entries_for_config_entry(entity_registry, config_entry.entry_id)
setup_owproxy_mock_devices(owproxy, [device_id])
freezer.tick(_DEVICE_SCAN_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done(wait_background_tasks=True)
assert (
len(er.async_entries_for_config_entry(entity_registry, config_entry.entry_id))
== 1
)
@pytest.mark.parametrize("device_id", ["05.111111111111"]) @pytest.mark.parametrize("device_id", ["05.111111111111"])
@pytest.mark.usefixtures("entity_registry_enabled_by_default") @pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_switch_toggle( async def test_switch_toggle(