Add config flow for One wire (#39321)

* Add support for config_flow
Add support for switches
Add support for binary sensors

* Add config flow strings

* Update .coveragerc

* black-formatting

* fixes for isort and flake

* fixes for pylint

* fixes for isort

* fixes for isort

* fixes for config_flow

* Add devices to Device Registry

* Updated comments

* fixes for flake8

* Updated comments

* Updated comments

* Implement async_unload_entry

* remove binary_sensor and switch implementation (will move to new PR)

* Update .coveragerc

Co-authored-by: Chris Talkington <chris@talkingtontech.com>

* Update .coveragerc

* Review config flow to store the configuration type

* Add config_flow tests

* Move CONF_NAMES to constants

* Fix isort

* Tweak to onewire logger

* Tweak to onewire logger for sensor

* Reset _LOGGER variable

* Normalise header

* Normalise header

* Update to use references in config flow translations

* Improve test coverage

* fixes for isort

* Update async_unload_entry

* Update common strings

* Update imports

* Move connect attempt to executor

* Update common strings

* Remove OWFS from config_flow

* Prevent duplicate config entries

* Fix isort

* Fix flake8

* Fix tests following removal of OWFS implementation

* Fix flake8

* Adjust config from yaml to config-flow, and add ability to specify sysbus directory

* Ajust unique_id for config entries

* Fix test_config_flow

* Fix invalid merge

* Convert yaml to config_entry

* Update sysbus tests

* Tweaks to yaml import process, and add OWFS warning

* Enable migration of OWFS platform config to config_entry

* update the existing corresponding config entry on OWFS conversion

* Remove CONFIG_SCHEMA

* Move data_schema to constants

* Remove log message

* Remove duplicate warning

* Update already_configured to use already_configured_device constant

* Schedule get_entities on the executor

* Update duplicate entry check for OWServer

* Review TryCatch

* Schedule os.path.isdir on the executor

* rename owhost/owport

* Update checks for empty

* Fix incorrect patch

* Move config_flow validation methods to new OneWireHub

* Fix typo and pre-commit

* Cleanup try/else

* patch async_setup/async_setup_entry

* cleanup implicit exit point

* Fix invalid patch

* cleanup implicit exit point

* cleanup implicit exit point

Co-authored-by: Chris Talkington <chris@talkingtontech.com>
This commit is contained in:
epenet 2020-10-24 03:57:16 +02:00 committed by GitHub
parent ed232ac733
commit 6ef53a2c5d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 774 additions and 32 deletions

View file

@ -1 +1,31 @@
"""The 1-Wire component."""
import asyncio
from .const import SUPPORTED_PLATFORMS
async def async_setup(hass, config):
"""Set up 1-Wire integrations."""
return True
async def async_setup_entry(hass, config_entry):
"""Set up a 1-Wire proxy for a config entry."""
for component in SUPPORTED_PLATFORMS:
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(config_entry, component)
)
return True
async def async_unload_entry(hass, config_entry):
"""Unload a config entry."""
unload_ok = all(
await asyncio.gather(
*[
hass.config_entries.async_forward_entry_unload(config_entry, component)
for component in SUPPORTED_PLATFORMS
]
)
)
return unload_ok

View file

@ -0,0 +1,195 @@
"""Config flow for 1-Wire component."""
import voluptuous as vol
from homeassistant import exceptions
from homeassistant.config_entries import CONN_CLASS_LOCAL_POLL, ConfigFlow
from homeassistant.const import CONF_HOST, CONF_PORT, CONF_TYPE
from homeassistant.helpers.typing import HomeAssistantType
from .const import ( # pylint: disable=unused-import
CONF_MOUNT_DIR,
CONF_TYPE_OWFS,
CONF_TYPE_OWSERVER,
CONF_TYPE_SYSBUS,
DEFAULT_OWSERVER_HOST,
DEFAULT_OWSERVER_PORT,
DEFAULT_SYSBUS_MOUNT_DIR,
DOMAIN,
)
from .onewirehub import OneWireHub
DATA_SCHEMA_USER = vol.Schema(
{vol.Required(CONF_TYPE): vol.In([CONF_TYPE_OWSERVER, CONF_TYPE_SYSBUS])}
)
DATA_SCHEMA_OWSERVER = vol.Schema(
{
vol.Required(CONF_HOST, default=DEFAULT_OWSERVER_HOST): str,
vol.Required(CONF_PORT, default=DEFAULT_OWSERVER_PORT): int,
}
)
DATA_SCHEMA_MOUNTDIR = vol.Schema(
{
vol.Required(CONF_MOUNT_DIR, default=DEFAULT_SYSBUS_MOUNT_DIR): str,
}
)
async def validate_input_owserver(hass: HomeAssistantType, data):
"""Validate the user input allows us to connect.
Data has the keys from DATA_SCHEMA_OWSERVER with values provided by the user.
"""
hub = OneWireHub(hass)
host = data[CONF_HOST]
port = data[CONF_PORT]
if not await hub.can_connect(host, port):
raise CannotConnect
# Return info that you want to store in the config entry.
return {"title": host}
def is_duplicate_owserver_entry(hass: HomeAssistantType, user_input):
"""Check existing entries for matching host and port."""
for config_entry in hass.config_entries.async_entries(DOMAIN):
if (
config_entry.data[CONF_TYPE] == CONF_TYPE_OWSERVER
and config_entry.data[CONF_HOST] == user_input[CONF_HOST]
and config_entry.data[CONF_PORT] == str(user_input[CONF_PORT])
):
return True
return False
async def validate_input_mount_dir(hass: HomeAssistantType, data):
"""Validate the user input allows us to connect.
Data has the keys from DATA_SCHEMA_MOUNTDIR with values provided by the user.
"""
hub = OneWireHub(hass)
mount_dir = data[CONF_MOUNT_DIR]
if not await hub.is_valid_mount_dir(mount_dir):
raise InvalidPath
# Return info that you want to store in the config entry.
return {"title": mount_dir}
class OneWireFlowHandler(ConfigFlow, domain=DOMAIN):
"""Handle 1-Wire config flow."""
VERSION = 1
CONNECTION_CLASS = CONN_CLASS_LOCAL_POLL
def __init__(self):
"""Initialize 1-Wire config flow."""
self.onewire_config = {}
async def async_step_user(self, user_input=None):
"""Handle 1-Wire config flow start.
Let user manually input configuration.
"""
errors = {}
if user_input is not None:
self.onewire_config.update(user_input)
if CONF_TYPE_OWSERVER == user_input[CONF_TYPE]:
return await self.async_step_owserver()
if CONF_TYPE_SYSBUS == user_input[CONF_TYPE]:
return await self.async_step_mount_dir()
return self.async_show_form(
step_id="user",
data_schema=DATA_SCHEMA_USER,
errors=errors,
)
async def async_step_owserver(self, user_input=None):
"""Handle OWServer configuration."""
errors = {}
if user_input:
# Prevent duplicate entries
if is_duplicate_owserver_entry(self.hass, user_input):
return self.async_abort(reason="already_configured")
self.onewire_config.update(user_input)
try:
info = await validate_input_owserver(self.hass, user_input)
except CannotConnect:
errors["base"] = "cannot_connect"
else:
return self.async_create_entry(
title=info["title"], data=self.onewire_config
)
return self.async_show_form(
step_id="owserver",
data_schema=DATA_SCHEMA_OWSERVER,
errors=errors,
)
async def async_step_mount_dir(self, user_input=None):
"""Handle SysBus configuration."""
errors = {}
if user_input:
# Prevent duplicate entries
await self.async_set_unique_id(
f"{CONF_TYPE_SYSBUS}:{user_input[CONF_MOUNT_DIR]}"
)
self._abort_if_unique_id_configured()
self.onewire_config.update(user_input)
try:
info = await validate_input_mount_dir(self.hass, user_input)
except InvalidPath:
errors["base"] = "invalid_path"
else:
return self.async_create_entry(
title=info["title"], data=self.onewire_config
)
return self.async_show_form(
step_id="mount_dir",
data_schema=DATA_SCHEMA_MOUNTDIR,
errors=errors,
)
async def async_step_import(self, platform_config):
"""Handle import configuration from YAML."""
# OWServer
if platform_config[CONF_TYPE] == CONF_TYPE_OWSERVER:
if CONF_PORT not in platform_config:
platform_config[CONF_PORT] = DEFAULT_OWSERVER_PORT
return await self.async_step_owserver(platform_config)
# OWFS
if platform_config[CONF_TYPE] == CONF_TYPE_OWFS: # pragma: no cover
# This part of the implementation does not conform to policy regarding 3rd-party libraries, and will not longer be updated.
# https://developers.home-assistant.io/docs/creating_platform_code_review/#5-communication-with-devicesservices
await self.async_set_unique_id(
f"{CONF_TYPE_OWFS}:{platform_config[CONF_MOUNT_DIR]}"
)
self._abort_if_unique_id_configured(
updates=platform_config, reload_on_update=True
)
return self.async_create_entry(
title=platform_config[CONF_MOUNT_DIR], data=platform_config
)
# SysBus
if CONF_MOUNT_DIR not in platform_config:
platform_config[CONF_MOUNT_DIR] = DEFAULT_SYSBUS_MOUNT_DIR
return await self.async_step_mount_dir(platform_config)
class CannotConnect(exceptions.HomeAssistantError):
"""Error to indicate we cannot connect."""
class InvalidPath(exceptions.HomeAssistantError):
"""Error to indicate the path is invalid."""

View file

@ -8,6 +8,7 @@ CONF_TYPE_OWFS = "OWFS"
CONF_TYPE_OWSERVER = "OWServer"
CONF_TYPE_SYSBUS = "SysBus"
DEFAULT_OWSERVER_HOST = "localhost"
DEFAULT_OWSERVER_PORT = 4304
DEFAULT_SYSBUS_MOUNT_DIR = "/sys/bus/w1/devices/"

View file

@ -2,6 +2,7 @@
"domain": "onewire",
"name": "1-Wire",
"documentation": "https://www.home-assistant.io/integrations/onewire",
"config_flow": true,
"requirements": ["pyownet==0.10.0.post1", "pi1wire==0.1.0"],
"codeowners": ["@garbled1", "@epenet"]
}

View file

@ -0,0 +1,35 @@
"""Hub for communication with 1-Wire server or mount_dir."""
import logging
import os
from pyownet import protocol
from homeassistant.helpers.typing import HomeAssistantType
_LOGGER = logging.getLogger(__name__)
class OneWireHub:
"""Hub to communicate with SysBus or OWServer."""
def __init__(self, hass: HomeAssistantType):
"""Initialize."""
self.hass = hass
async def can_connect(self, host, port) -> bool:
"""Test if we can authenticate with the host."""
try:
await self.hass.async_add_executor_job(protocol.proxy, host, port)
except (protocol.Error, protocol.ConnError) as exc:
_LOGGER.error(
"Cannot connect to owserver on %s:%d, got: %s", host, port, exc
)
return False
return True
async def is_valid_mount_dir(self, mount_dir) -> bool:
"""Test that the mount_dir is a valid path."""
if not await self.hass.async_add_executor_job(os.path.isdir, mount_dir):
_LOGGER.error("Cannot find directory %s", mount_dir)
return False
return True

View file

@ -8,9 +8,11 @@ from pyownet import protocol
import voluptuous as vol
from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.config_entries import SOURCE_IMPORT
from homeassistant.const import (
CONF_HOST,
CONF_PORT,
CONF_TYPE,
ELECTRICAL_CURRENT_AMPERE,
LIGHT_LUX,
PERCENTAGE,
@ -29,6 +31,7 @@ from .const import (
CONF_TYPE_SYSBUS,
DEFAULT_OWSERVER_PORT,
DEFAULT_SYSBUS_MOUNT_DIR,
DOMAIN,
PRESSURE_CBAR,
)
@ -125,36 +128,44 @@ def hb_info_from_type(dev_type="std"):
return HOBBYBOARD_EF
def setup_platform(hass, config, add_entities, discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""Old way of setting up 1-Wire platform."""
if config.get(CONF_HOST):
config[CONF_TYPE] = CONF_TYPE_OWSERVER
elif config[CONF_MOUNT_DIR] == DEFAULT_SYSBUS_MOUNT_DIR:
config[CONF_TYPE] = CONF_TYPE_SYSBUS
else: # pragma: no cover
# This part of the implementation does not conform to policy regarding 3rd-party libraries, and will not longer be updated.
# https://developers.home-assistant.io/docs/creating_platform_code_review/#5-communication-with-devicesservices
config[CONF_TYPE] = CONF_TYPE_OWFS
hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_IMPORT}, data=config
)
)
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up 1-Wire platform."""
entities = get_entities(config)
add_entities(entities, True)
entities = await hass.async_add_executor_job(get_entities, config_entry.data)
async_add_entities(entities, True)
def get_entities(config):
"""Get a list of entities."""
base_dir = config[CONF_MOUNT_DIR]
owhost = config.get(CONF_HOST)
owport = config[CONF_PORT]
# Ensure type is configured
if owhost:
conf_type = CONF_TYPE_OWSERVER
elif base_dir == DEFAULT_SYSBUS_MOUNT_DIR:
conf_type = CONF_TYPE_SYSBUS
else: # pragma: no cover
# This part of the implementation does not conform to policy regarding 3rd-party libraries, and will not longer be updated.
# https://developers.home-assistant.io/docs/creating_platform_code_review/#5-communication-with-devicesservices
conf_type = CONF_TYPE_OWFS
entities = []
device_names = {}
if CONF_NAMES in config:
if isinstance(config[CONF_NAMES], dict):
device_names = config[CONF_NAMES]
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]
_LOGGER.debug("Initializing using %s:%s", owhost, owport)
try:
owproxy = protocol.proxy(host=owhost, port=owport)
@ -163,7 +174,7 @@ def get_entities(config):
_LOGGER.error(
"Cannot connect to owserver on %s:%d, got: %s", owhost, owport, exc
)
devices = []
return entities
for device in devices:
_LOGGER.debug("Found device: %s", device)
family = owproxy.read(f"{device}family").decode()
@ -200,8 +211,9 @@ def get_entities(config):
# We have a raw GPIO ow sensor on a Pi
elif conf_type == CONF_TYPE_SYSBUS:
_LOGGER.debug("Initializing using SysBus")
for p1sensor in Pi1Wire().find_all_sensors():
base_dir = config[CONF_MOUNT_DIR]
_LOGGER.debug("Initializing using SysBus %s", base_dir)
for p1sensor in Pi1Wire(base_dir).find_all_sensors():
family = p1sensor.mac_address[:2]
sensor_id = f"{family}-{p1sensor.mac_address[2:]}"
if family not in DEVICE_SUPPORT_SYSBUS:
@ -232,6 +244,7 @@ def get_entities(config):
else: # pragma: no cover
# This part of the implementation does not conform to policy regarding 3rd-party libraries, and will not longer be updated.
# https://developers.home-assistant.io/docs/creating_platform_code_review/#5-communication-with-devicesservices
base_dir = config[CONF_MOUNT_DIR]
_LOGGER.debug("Initializing using OWFS %s", base_dir)
_LOGGER.warning(
"The OWFS implementation of 1-Wire sensors is deprecated, "

View file

@ -0,0 +1,26 @@
{
"config": {
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
},
"error": {
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
"invalid_path": "Directory not found."
},
"step": {
"owserver": {
"data": {
"host": "[%key:common::config_flow::data::host%]",
"port": "[%key:common::config_flow::data::port%]"
},
"title": "Set owserver details"
},
"user": {
"data": {
"type": "Connection type"
},
"title": "Set up 1-Wire"
}
}
}
}

View file

@ -0,0 +1,26 @@
{
"config": {
"abort": {
"already_configured": "Service is already configured"
},
"error": {
"cannot_connect": "Unable to connect.",
"invalid_path": "Directory not found."
},
"step": {
"owserver": {
"data": {
"host": "Host",
"port": "Port"
},
"title": "Set owserver details"
},
"user": {
"data": {
"type": "Connection type"
},
"title": "Set up 1-Wire"
}
}
}
}

View file

@ -132,6 +132,7 @@ FLOWS = [
"nws",
"nzbget",
"omnilogic",
"onewire",
"onvif",
"opentherm_gw",
"openuv",

View file

@ -1 +1,60 @@
"""Tests for 1-Wire integration."""
from asynctest.mock import patch
from homeassistant.components.onewire.const import (
CONF_TYPE_OWSERVER,
CONF_TYPE_SYSBUS,
DEFAULT_SYSBUS_MOUNT_DIR,
DOMAIN,
)
from homeassistant.config_entries import CONN_CLASS_LOCAL_POLL
from homeassistant.const import CONF_HOST, CONF_PORT, CONF_TYPE
from tests.common import MockConfigEntry
async def setup_onewire_sysbus_integration(hass):
"""Create the 1-Wire integration."""
config_entry = MockConfigEntry(
domain=DOMAIN,
source="user",
data={
CONF_TYPE: CONF_TYPE_SYSBUS,
},
unique_id=f"{CONF_TYPE_SYSBUS}:{DEFAULT_SYSBUS_MOUNT_DIR}",
connection_class=CONN_CLASS_LOCAL_POLL,
options={},
entry_id="1",
)
config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
return config_entry
async def setup_onewire_owserver_integration(hass):
"""Create the 1-Wire integration."""
config_entry = MockConfigEntry(
domain=DOMAIN,
source="user",
data={
CONF_TYPE: CONF_TYPE_OWSERVER,
CONF_HOST: "1.2.3.4",
CONF_PORT: "1234",
},
unique_id=f"{CONF_TYPE_OWSERVER}:1.2.3.4:1234",
connection_class=CONN_CLASS_LOCAL_POLL,
options={},
entry_id="2",
)
config_entry.add_to_hass(hass)
with patch(
"homeassistant.components.onewire.sensor.protocol.proxy",
):
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
return config_entry

View file

@ -0,0 +1,333 @@
"""Tests for 1-Wire config flow."""
from pyownet import protocol
from homeassistant.components.onewire.const import (
CONF_MOUNT_DIR,
CONF_TYPE_OWSERVER,
CONF_TYPE_SYSBUS,
DEFAULT_OWSERVER_PORT,
DEFAULT_SYSBUS_MOUNT_DIR,
DOMAIN,
)
from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER
from homeassistant.const import CONF_HOST, CONF_PORT, CONF_TYPE
from homeassistant.data_entry_flow import (
RESULT_TYPE_ABORT,
RESULT_TYPE_CREATE_ENTRY,
RESULT_TYPE_FORM,
)
from . import setup_onewire_owserver_integration, setup_onewire_sysbus_integration
from tests.async_mock import patch
async def test_user_owserver(hass):
"""Test OWServer user flow."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
assert result["type"] == RESULT_TYPE_FORM
assert not result["errors"]
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={CONF_TYPE: CONF_TYPE_OWSERVER},
)
assert result["type"] == RESULT_TYPE_FORM
assert result["step_id"] == "owserver"
assert not result["errors"]
# Invalid server
with patch(
"homeassistant.components.onewire.onewirehub.protocol.proxy",
side_effect=protocol.ConnError,
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={CONF_HOST: "1.2.3.4", CONF_PORT: 1234},
)
assert result["type"] == RESULT_TYPE_FORM
assert result["step_id"] == "owserver"
assert result["errors"] == {"base": "cannot_connect"}
# Valid server
with patch("homeassistant.components.onewire.onewirehub.protocol.proxy",), patch(
"homeassistant.components.onewire.async_setup", return_value=True
) as mock_setup, patch(
"homeassistant.components.onewire.async_setup_entry",
return_value=True,
) as mock_setup_entry:
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={CONF_HOST: "1.2.3.4", CONF_PORT: 1234},
)
assert result["type"] == RESULT_TYPE_CREATE_ENTRY
assert result["title"] == "1.2.3.4"
assert result["data"] == {
CONF_TYPE: CONF_TYPE_OWSERVER,
CONF_HOST: "1.2.3.4",
CONF_PORT: 1234,
}
await hass.async_block_till_done()
assert len(mock_setup.mock_calls) == 1
assert len(mock_setup_entry.mock_calls) == 1
async def test_user_owserver_duplicate(hass):
"""Test OWServer flow."""
with patch(
"homeassistant.components.onewire.async_setup", return_value=True
) as mock_setup, patch(
"homeassistant.components.onewire.async_setup_entry",
return_value=True,
) as mock_setup_entry:
await setup_onewire_owserver_integration(hass)
assert len(hass.config_entries.async_entries(DOMAIN)) == 1
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
assert result["type"] == RESULT_TYPE_FORM
assert not result["errors"]
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={CONF_TYPE: CONF_TYPE_OWSERVER},
)
assert result["type"] == RESULT_TYPE_FORM
assert result["step_id"] == "owserver"
assert not result["errors"]
# Duplicate server
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={CONF_HOST: "1.2.3.4", CONF_PORT: 1234},
)
assert result["type"] == RESULT_TYPE_ABORT
assert result["reason"] == "already_configured"
await hass.async_block_till_done()
assert len(mock_setup.mock_calls) == 1
assert len(mock_setup_entry.mock_calls) == 1
async def test_user_sysbus(hass):
"""Test SysBus flow."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
assert result["type"] == RESULT_TYPE_FORM
assert not result["errors"]
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={CONF_TYPE: CONF_TYPE_SYSBUS},
)
assert result["type"] == RESULT_TYPE_FORM
assert result["step_id"] == "mount_dir"
assert not result["errors"]
# Invalid path
with patch(
"homeassistant.components.onewire.onewirehub.os.path.isdir",
return_value=False,
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={CONF_MOUNT_DIR: "/sys/bus/invalid_directory"},
)
assert result["type"] == RESULT_TYPE_FORM
assert result["step_id"] == "mount_dir"
assert result["errors"] == {"base": "invalid_path"}
# Valid path
with patch(
"homeassistant.components.onewire.onewirehub.os.path.isdir",
return_value=True,
), patch(
"homeassistant.components.onewire.async_setup", return_value=True
) as mock_setup, patch(
"homeassistant.components.onewire.async_setup_entry",
return_value=True,
) as mock_setup_entry:
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={CONF_MOUNT_DIR: "/sys/bus/directory"},
)
assert result["type"] == RESULT_TYPE_CREATE_ENTRY
assert result["title"] == "/sys/bus/directory"
assert result["data"] == {
CONF_TYPE: CONF_TYPE_SYSBUS,
CONF_MOUNT_DIR: "/sys/bus/directory",
}
await hass.async_block_till_done()
assert len(mock_setup.mock_calls) == 1
assert len(mock_setup_entry.mock_calls) == 1
async def test_user_sysbus_duplicate(hass):
"""Test SysBus duplicate flow."""
with patch(
"homeassistant.components.onewire.async_setup", return_value=True
) as mock_setup, patch(
"homeassistant.components.onewire.async_setup_entry",
return_value=True,
) as mock_setup_entry:
await setup_onewire_sysbus_integration(hass)
assert len(hass.config_entries.async_entries(DOMAIN)) == 1
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
assert result["type"] == RESULT_TYPE_FORM
assert not result["errors"]
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={CONF_TYPE: CONF_TYPE_SYSBUS},
)
assert result["type"] == RESULT_TYPE_FORM
assert result["step_id"] == "mount_dir"
assert not result["errors"]
# Valid path
with patch(
"homeassistant.components.onewire.onewirehub.os.path.isdir",
return_value=True,
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={CONF_MOUNT_DIR: DEFAULT_SYSBUS_MOUNT_DIR},
)
assert result["type"] == RESULT_TYPE_ABORT
assert result["reason"] == "already_configured"
await hass.async_block_till_done()
assert len(mock_setup.mock_calls) == 1
assert len(mock_setup_entry.mock_calls) == 1
async def test_import_sysbus(hass):
"""Test import step."""
with patch(
"homeassistant.components.onewire.onewirehub.os.path.isdir",
return_value=True,
), patch(
"homeassistant.components.onewire.async_setup", return_value=True
) as mock_setup, patch(
"homeassistant.components.onewire.async_setup_entry",
return_value=True,
) as mock_setup_entry:
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data={CONF_TYPE: CONF_TYPE_SYSBUS},
)
assert result["type"] == RESULT_TYPE_CREATE_ENTRY
assert result["title"] == DEFAULT_SYSBUS_MOUNT_DIR
assert result["data"] == {
CONF_TYPE: CONF_TYPE_SYSBUS,
CONF_MOUNT_DIR: DEFAULT_SYSBUS_MOUNT_DIR,
}
await hass.async_block_till_done()
assert len(mock_setup.mock_calls) == 1
assert len(mock_setup_entry.mock_calls) == 1
async def test_import_sysbus_with_mount_dir(hass):
"""Test import step."""
with patch(
"homeassistant.components.onewire.onewirehub.os.path.isdir",
return_value=True,
), patch(
"homeassistant.components.onewire.async_setup", return_value=True
) as mock_setup, patch(
"homeassistant.components.onewire.async_setup_entry",
return_value=True,
) as mock_setup_entry:
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data={
CONF_TYPE: CONF_TYPE_SYSBUS,
CONF_MOUNT_DIR: DEFAULT_SYSBUS_MOUNT_DIR,
},
)
assert result["type"] == RESULT_TYPE_CREATE_ENTRY
assert result["title"] == DEFAULT_SYSBUS_MOUNT_DIR
assert result["data"] == {
CONF_TYPE: CONF_TYPE_SYSBUS,
CONF_MOUNT_DIR: DEFAULT_SYSBUS_MOUNT_DIR,
}
await hass.async_block_till_done()
assert len(mock_setup.mock_calls) == 1
assert len(mock_setup_entry.mock_calls) == 1
async def test_import_owserver(hass):
"""Test import step."""
with patch("homeassistant.components.onewire.onewirehub.protocol.proxy",), patch(
"homeassistant.components.onewire.async_setup", return_value=True
) as mock_setup, patch(
"homeassistant.components.onewire.async_setup_entry",
return_value=True,
) as mock_setup_entry:
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data={
CONF_TYPE: CONF_TYPE_OWSERVER,
CONF_HOST: "1.2.3.4",
},
)
assert result["type"] == RESULT_TYPE_CREATE_ENTRY
assert result["title"] == "1.2.3.4"
assert result["data"] == {
CONF_TYPE: CONF_TYPE_OWSERVER,
CONF_HOST: "1.2.3.4",
CONF_PORT: DEFAULT_OWSERVER_PORT,
}
await hass.async_block_till_done()
assert len(mock_setup.mock_calls) == 1
assert len(mock_setup_entry.mock_calls) == 1
async def test_import_owserver_with_port(hass):
"""Test import step."""
with patch("homeassistant.components.onewire.onewirehub.protocol.proxy",), patch(
"homeassistant.components.onewire.async_setup", return_value=True
) as mock_setup, patch(
"homeassistant.components.onewire.async_setup_entry",
return_value=True,
) as mock_setup_entry:
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data={
CONF_TYPE: CONF_TYPE_OWSERVER,
CONF_HOST: "1.2.3.4",
CONF_PORT: "1234",
},
)
assert result["type"] == RESULT_TYPE_CREATE_ENTRY
assert result["title"] == "1.2.3.4"
assert result["data"] == {
CONF_TYPE: CONF_TYPE_OWSERVER,
CONF_HOST: "1.2.3.4",
CONF_PORT: "1234",
}
await hass.async_block_till_done()
assert len(mock_setup.mock_calls) == 1
assert len(mock_setup_entry.mock_calls) == 1

View file

@ -1,5 +1,5 @@
"""Tests for 1-Wire devices connected on SysBus."""
from unittest.mock import PropertyMock, patch
from unittest.mock import patch
from pi1wire import InvalidCRCException, UnsupportResponseException
import pytest
@ -93,19 +93,18 @@ async def test_onewiredirect_setup_valid_device(hass, device_id):
"""Test that sysbus config entry works correctly."""
entity_registry = mock_registry(hass)
glob_result = [f"/{DEFAULT_SYSBUS_MOUNT_DIR}/{device_id}"]
read_side_effect = []
expected_sensors = MOCK_DEVICE_SENSORS[device_id]["sensors"]
for expected_sensor in expected_sensors:
read_side_effect.append(expected_sensor["injected_value"])
with patch(
"homeassistant.components.onewire.sensor.Pi1Wire"
) as mock_pi1wire, patch("pi1wire.OneWire") as mock_owsensor:
type(mock_owsensor).mac_address = PropertyMock(
return_value=device_id.replace("-", "")
)
mock_owsensor.get_temperature.side_effect = read_side_effect
mock_pi1wire.return_value.find_all_sensors.return_value = [mock_owsensor]
"homeassistant.components.onewire.sensor.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,
):
assert await async_setup_component(hass, SENSOR_DOMAIN, MOCK_CONFIG)
await hass.async_block_till_done()

View file

@ -0,0 +1,23 @@
"""Tests for 1-Wire config flow."""
from homeassistant.components.onewire.const import DOMAIN
from homeassistant.config_entries import ENTRY_STATE_LOADED, ENTRY_STATE_NOT_LOADED
from . import setup_onewire_owserver_integration, setup_onewire_sysbus_integration
async def test_unload_entry(hass):
"""Test being able to unload an entry."""
config_entry_owserver = await setup_onewire_owserver_integration(hass)
config_entry_sysbus = await setup_onewire_sysbus_integration(hass)
assert len(hass.config_entries.async_entries(DOMAIN)) == 2
assert config_entry_owserver.state == ENTRY_STATE_LOADED
assert config_entry_sysbus.state == ENTRY_STATE_LOADED
assert await hass.config_entries.async_unload(config_entry_owserver.entry_id)
assert await hass.config_entries.async_unload(config_entry_sysbus.entry_id)
await hass.async_block_till_done()
assert config_entry_owserver.state == ENTRY_STATE_NOT_LOADED
assert config_entry_sysbus.state == ENTRY_STATE_NOT_LOADED
assert not hass.data.get(DOMAIN)

View file

@ -7,7 +7,7 @@ from tests.common import assert_setup_component
async def test_setup_minimum(hass):
"""Test setup with minimum configuration."""
"""Test old platform setup with minimum configuration."""
config = {"sensor": {"platform": "onewire"}}
with assert_setup_component(1, "sensor"):
assert await async_setup_component(hass, sensor.DOMAIN, config)
@ -15,7 +15,7 @@ async def test_setup_minimum(hass):
async def test_setup_sysbus(hass):
"""Test setup with SysBus configuration."""
"""Test old platform setup with SysBus configuration."""
config = {
"sensor": {
"platform": "onewire",
@ -28,7 +28,7 @@ async def test_setup_sysbus(hass):
async def test_setup_owserver(hass):
"""Test setup with OWServer configuration."""
"""Test old platform setup with OWServer configuration."""
config = {"sensor": {"platform": "onewire", "host": "localhost"}}
with assert_setup_component(1, "sensor"):
assert await async_setup_component(hass, sensor.DOMAIN, config)
@ -36,7 +36,7 @@ async def test_setup_owserver(hass):
async def test_setup_owserver_with_port(hass):
"""Test setup with OWServer configuration."""
"""Test old platform setup with OWServer configuration."""
config = {"sensor": {"platform": "onewire", "host": "localhost", "port": "1234"}}
with assert_setup_component(1, "sensor"):
assert await async_setup_component(hass, sensor.DOMAIN, config)