mirror of
https://github.com/home-assistant/core.git
synced 2025-07-24 21:57:51 +00:00
Discover onewire devices at startup (#42410)
This commit is contained in:
parent
5f3384fc8a
commit
f3a15eab6e
@ -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):
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user