diff --git a/homeassistant/components/onewire/onewirehub.py b/homeassistant/components/onewire/onewirehub.py index 1d2aef27b09..3b715eed0dd 100644 --- a/homeassistant/components/onewire/onewirehub.py +++ b/homeassistant/components/onewire/onewirehub.py @@ -1,6 +1,7 @@ """Hub for communication with 1-Wire server or mount_dir.""" import os +from pi1wire import Pi1Wire from pyownet import protocol from homeassistant.config_entries import ConfigEntry @@ -17,7 +18,10 @@ class OneWireHub: def __init__(self, hass: HomeAssistantType): """Initialize.""" self.hass = hass + self.type: str = None + self.pi1proxy: Pi1Wire = None self.owproxy: protocol._Proxy = None + self.devices = None async def connect(self, host: str, port: int) -> None: """Connect to the owserver host.""" @@ -32,15 +36,44 @@ class OneWireHub: """Test that the mount_dir is a valid path.""" if not await self.hass.async_add_executor_job(os.path.isdir, mount_dir): raise InvalidPath + self.pi1proxy = Pi1Wire(mount_dir) async def initialize(self, config_entry: ConfigEntry) -> None: """Initialize a config entry.""" - if config_entry.data[CONF_TYPE] == CONF_TYPE_SYSBUS: + self.type = config_entry.data[CONF_TYPE] + if self.type == CONF_TYPE_SYSBUS: await self.check_mount_dir(config_entry.data[CONF_MOUNT_DIR]) - elif config_entry.data[CONF_TYPE] == CONF_TYPE_OWSERVER: + elif self.type == CONF_TYPE_OWSERVER: host = config_entry.data[CONF_HOST] port = config_entry.data[CONF_PORT] await self.connect(host, port) + await self.discover_devices() + + async def discover_devices(self): + """Discover all devices.""" + if self.devices is None: + if self.type == CONF_TYPE_SYSBUS: + self.devices = await self.hass.async_add_executor_job( + self.pi1proxy.find_all_sensors + ) + if self.type == CONF_TYPE_OWSERVER: + self.devices = await self.hass.async_add_executor_job( + self._discover_devices_owserver + ) + return self.devices + + def _discover_devices_owserver(self): + """Discover all owserver devices.""" + devices = [] + for device_path in self.owproxy.dir(): + devices.append( + { + "path": device_path, + "family": self.owproxy.read(f"{device_path}family").decode(), + "type": self.owproxy.read(f"{device_path}type").decode(), + } + ) + return devices class CannotConnect(HomeAssistantError): diff --git a/homeassistant/components/onewire/sensor.py b/homeassistant/components/onewire/sensor.py index e1b6d736194..2b192ca6ad6 100644 --- a/homeassistant/components/onewire/sensor.py +++ b/homeassistant/components/onewire/sensor.py @@ -4,7 +4,7 @@ import logging import os from typing import Any, Dict, Optional -from pi1wire import InvalidCRCException, Pi1Wire, UnsupportResponseException +from pi1wire import InvalidCRCException, UnsupportResponseException from pyownet import protocol import voluptuous as vol @@ -175,21 +175,10 @@ def get_entities(onewirehub: OneWireHub, config): conf_type = config[CONF_TYPE] # We have an owserver on a remote(or local) host/port if conf_type == CONF_TYPE_OWSERVER: - owhost = config[CONF_HOST] - owport = config[CONF_PORT] - - try: - devices = onewirehub.owproxy.dir() - except protocol.OwnetError as exc: - _LOGGER.error( - "Failed to list devices on %s:%d, got: %s", owhost, owport, exc - ) - return entities - for device in devices: - _LOGGER.debug("Found device: %s", device) - family = onewirehub.owproxy.read(f"{device}family").decode() - device_type = onewirehub.owproxy.read(f"{device}type").decode() - sensor_id = os.path.split(os.path.split(device)[0])[1] + for device in onewirehub.devices: + family = device["family"] + device_type = device["type"] + sensor_id = os.path.split(os.path.split(device["path"])[0])[1] dev_type = "std" if "EF" in family: dev_type = "HobbyBoard" @@ -199,7 +188,7 @@ def get_entities(onewirehub: OneWireHub, config): _LOGGER.warning( "Ignoring unknown family (%s) of sensor found for device: %s", family, - device, + sensor_id, ) continue device_info = { @@ -213,12 +202,14 @@ def get_entities(onewirehub: OneWireHub, config): s_id = sensor_key.split("_")[1] is_leaf = int( onewirehub.owproxy.read( - f"{device}moisture/is_leaf.{s_id}" + f"{device['path']}moisture/is_leaf.{s_id}" ).decode() ) if is_leaf: sensor_key = f"wetness_{s_id}" - device_file = os.path.join(os.path.split(device)[0], sensor_value) + device_file = os.path.join( + os.path.split(device["path"])[0], sensor_value + ) entities.append( OneWireProxy( device_names.get(sensor_id, sensor_id), @@ -233,7 +224,7 @@ def get_entities(onewirehub: OneWireHub, config): elif conf_type == CONF_TYPE_SYSBUS: base_dir = config[CONF_MOUNT_DIR] _LOGGER.debug("Initializing using SysBus %s", base_dir) - for p1sensor in Pi1Wire(base_dir).find_all_sensors(): + for p1sensor in onewirehub.devices: family = p1sensor.mac_address[:2] sensor_id = f"{family}-{p1sensor.mac_address[2:]}" if family not in DEVICE_SUPPORT_SYSBUS: diff --git a/tests/components/onewire/test_entity_owserver.py b/tests/components/onewire/test_entity_owserver.py index 26668e105ca..ab45b382286 100644 --- a/tests/components/onewire/test_entity_owserver.py +++ b/tests/components/onewire/test_entity_owserver.py @@ -418,7 +418,7 @@ async def test_owserver_setup_valid_device(hass, device_id): # Ensure enough read side effect read_side_effect.extend([ProtocolError("Missing injected value")] * 10) - with patch("homeassistant.components.onewire.sensor.protocol.proxy") as owproxy: + with patch("homeassistant.components.onewire.onewirehub.protocol.proxy") as owproxy: owproxy.return_value.dir.return_value = dir_return_value owproxy.return_value.read.side_effect = read_side_effect diff --git a/tests/components/onewire/test_entity_sysbus.py b/tests/components/onewire/test_entity_sysbus.py index f1fcc90e96e..242939d3a37 100644 --- a/tests/components/onewire/test_entity_sysbus.py +++ b/tests/components/onewire/test_entity_sysbus.py @@ -142,7 +142,7 @@ async def test_onewiredirect_setup_valid_device(hass, device_id): read_side_effect.extend([FileNotFoundError("Missing injected value")] * 20) with patch( - "homeassistant.components.onewire.sensor.os.path.isdir", return_value=True + "homeassistant.components.onewire.onewirehub.os.path.isdir", return_value=True ), patch("pi1wire._finder.glob.glob", return_value=glob_result,), patch( "pi1wire.OneWire.get_temperature", side_effect=read_side_effect, diff --git a/tests/components/onewire/test_init.py b/tests/components/onewire/test_init.py index a371b8c6b2b..8df9b1ed2ff 100644 --- a/tests/components/onewire/test_init.py +++ b/tests/components/onewire/test_init.py @@ -16,8 +16,8 @@ from . import setup_onewire_owserver_integration, setup_onewire_sysbus_integrati from tests.common import MockConfigEntry -async def test_owserver_platform_not_ready(hass): - """Create the 1-Wire integration.""" +async def test_owserver_connect_failure(hass): + """Test connection failure raises ConfigEntryNotReady.""" config_entry_owserver = MockConfigEntry( domain=DOMAIN, source="user",