Discover onewire devices at startup (#42410)

This commit is contained in:
epenet 2020-10-27 05:36:51 +01:00 committed by GitHub
parent 5f3384fc8a
commit f3a15eab6e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 50 additions and 26 deletions

View File

@ -1,6 +1,7 @@
"""Hub for communication with 1-Wire server or mount_dir.""" """Hub for communication with 1-Wire server or mount_dir."""
import os import os
from pi1wire import Pi1Wire
from pyownet import protocol from pyownet import protocol
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
@ -17,7 +18,10 @@ class OneWireHub:
def __init__(self, hass: HomeAssistantType): def __init__(self, hass: HomeAssistantType):
"""Initialize.""" """Initialize."""
self.hass = hass self.hass = hass
self.type: str = None
self.pi1proxy: Pi1Wire = None
self.owproxy: protocol._Proxy = None self.owproxy: protocol._Proxy = None
self.devices = None
async def connect(self, host: str, port: int) -> None: async def connect(self, host: str, port: int) -> None:
"""Connect to the owserver host.""" """Connect to the owserver host."""
@ -32,15 +36,44 @@ class OneWireHub:
"""Test that the mount_dir is a valid path.""" """Test that the mount_dir is a valid path."""
if not await self.hass.async_add_executor_job(os.path.isdir, mount_dir): if not await self.hass.async_add_executor_job(os.path.isdir, mount_dir):
raise InvalidPath raise InvalidPath
self.pi1proxy = Pi1Wire(mount_dir)
async def initialize(self, config_entry: ConfigEntry) -> None: async def initialize(self, config_entry: ConfigEntry) -> None:
"""Initialize a config entry.""" """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]) 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] host = config_entry.data[CONF_HOST]
port = config_entry.data[CONF_PORT] port = config_entry.data[CONF_PORT]
await self.connect(host, 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): class CannotConnect(HomeAssistantError):

View File

@ -4,7 +4,7 @@ import logging
import os import os
from typing import Any, Dict, Optional from typing import Any, Dict, Optional
from pi1wire import InvalidCRCException, Pi1Wire, UnsupportResponseException from pi1wire import InvalidCRCException, UnsupportResponseException
from pyownet import protocol from pyownet import protocol
import voluptuous as vol import voluptuous as vol
@ -175,21 +175,10 @@ def get_entities(onewirehub: OneWireHub, config):
conf_type = config[CONF_TYPE] conf_type = config[CONF_TYPE]
# We have an owserver on a remote(or local) host/port # We have an owserver on a remote(or local) host/port
if conf_type == CONF_TYPE_OWSERVER: if conf_type == CONF_TYPE_OWSERVER:
owhost = config[CONF_HOST] for device in onewirehub.devices:
owport = config[CONF_PORT] family = device["family"]
device_type = device["type"]
try: sensor_id = os.path.split(os.path.split(device["path"])[0])[1]
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]
dev_type = "std" dev_type = "std"
if "EF" in family: if "EF" in family:
dev_type = "HobbyBoard" dev_type = "HobbyBoard"
@ -199,7 +188,7 @@ def get_entities(onewirehub: OneWireHub, config):
_LOGGER.warning( _LOGGER.warning(
"Ignoring unknown family (%s) of sensor found for device: %s", "Ignoring unknown family (%s) of sensor found for device: %s",
family, family,
device, sensor_id,
) )
continue continue
device_info = { device_info = {
@ -213,12 +202,14 @@ def get_entities(onewirehub: OneWireHub, config):
s_id = sensor_key.split("_")[1] s_id = sensor_key.split("_")[1]
is_leaf = int( is_leaf = int(
onewirehub.owproxy.read( onewirehub.owproxy.read(
f"{device}moisture/is_leaf.{s_id}" f"{device['path']}moisture/is_leaf.{s_id}"
).decode() ).decode()
) )
if is_leaf: if is_leaf:
sensor_key = f"wetness_{s_id}" 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( entities.append(
OneWireProxy( OneWireProxy(
device_names.get(sensor_id, sensor_id), device_names.get(sensor_id, sensor_id),
@ -233,7 +224,7 @@ def get_entities(onewirehub: OneWireHub, config):
elif conf_type == CONF_TYPE_SYSBUS: elif conf_type == CONF_TYPE_SYSBUS:
base_dir = config[CONF_MOUNT_DIR] base_dir = config[CONF_MOUNT_DIR]
_LOGGER.debug("Initializing using SysBus %s", base_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] family = p1sensor.mac_address[:2]
sensor_id = f"{family}-{p1sensor.mac_address[2:]}" sensor_id = f"{family}-{p1sensor.mac_address[2:]}"
if family not in DEVICE_SUPPORT_SYSBUS: if family not in DEVICE_SUPPORT_SYSBUS:

View File

@ -418,7 +418,7 @@ async def test_owserver_setup_valid_device(hass, device_id):
# Ensure enough read side effect # Ensure enough read side effect
read_side_effect.extend([ProtocolError("Missing injected value")] * 10) 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.dir.return_value = dir_return_value
owproxy.return_value.read.side_effect = read_side_effect owproxy.return_value.read.side_effect = read_side_effect

View File

@ -142,7 +142,7 @@ async def test_onewiredirect_setup_valid_device(hass, device_id):
read_side_effect.extend([FileNotFoundError("Missing injected value")] * 20) read_side_effect.extend([FileNotFoundError("Missing injected value")] * 20)
with patch( 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( ), patch("pi1wire._finder.glob.glob", return_value=glob_result,), patch(
"pi1wire.OneWire.get_temperature", "pi1wire.OneWire.get_temperature",
side_effect=read_side_effect, side_effect=read_side_effect,

View File

@ -16,8 +16,8 @@ from . import setup_onewire_owserver_integration, setup_onewire_sysbus_integrati
from tests.common import MockConfigEntry from tests.common import MockConfigEntry
async def test_owserver_platform_not_ready(hass): async def test_owserver_connect_failure(hass):
"""Create the 1-Wire integration.""" """Test connection failure raises ConfigEntryNotReady."""
config_entry_owserver = MockConfigEntry( config_entry_owserver = MockConfigEntry(
domain=DOMAIN, domain=DOMAIN,
source="user", source="user",