Axis - Remove manual configuration and legacy config file import (#30365)

* Remove manual configuration and legacy config file import

* Remove unused imports in tests after rebase
This commit is contained in:
Robert Svensson 2020-01-03 21:25:31 +01:00 committed by Andrew Sayre
parent 6387a50697
commit bb55606d29
4 changed files with 24 additions and 233 deletions

View file

@ -1,43 +1,18 @@
"""Support for Axis devices.""" """Support for Axis devices."""
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.const import ( from homeassistant.const import (
CONF_DEVICE, CONF_DEVICE,
CONF_MAC, CONF_MAC,
CONF_NAME,
CONF_TRIGGER_TIME, CONF_TRIGGER_TIME,
EVENT_HOMEASSISTANT_STOP, EVENT_HOMEASSISTANT_STOP,
) )
from homeassistant.helpers import config_validation as cv
from .config_flow import DEVICE_SCHEMA
from .const import CONF_CAMERA, CONF_EVENTS, DEFAULT_TRIGGER_TIME, DOMAIN from .const import CONF_CAMERA, CONF_EVENTS, DEFAULT_TRIGGER_TIME, DOMAIN
from .device import AxisNetworkDevice, get_device from .device import AxisNetworkDevice, get_device
CONFIG_SCHEMA = vol.Schema(
{DOMAIN: cv.schema_with_slug_keys(DEVICE_SCHEMA)}, extra=vol.ALLOW_EXTRA
)
async def async_setup(hass, config): async def async_setup(hass, config):
"""Set up for Axis devices.""" """Old way to set up Axis devices."""
if not hass.config_entries.async_entries(DOMAIN) and DOMAIN in config:
for device_name, device_config in config[DOMAIN].items():
if CONF_NAME not in device_config:
device_config[CONF_NAME] = device_name
hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_IMPORT},
data=device_config,
)
)
return True return True

View file

@ -14,7 +14,6 @@ from homeassistant.const import (
) )
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from homeassistant.util.json import load_json
from .const import CONF_MODEL, DOMAIN from .const import CONF_MODEL, DOMAIN
from .device import get_device from .device import get_device
@ -107,16 +106,12 @@ class AxisFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
except CannotConnect: except CannotConnect:
errors["base"] = "device_unavailable" errors["base"] = "device_unavailable"
data = ( data = self.discovery_schema or {
self.import_schema vol.Required(CONF_HOST): str,
or self.discovery_schema vol.Required(CONF_USERNAME): str,
or { vol.Required(CONF_PASSWORD): str,
vol.Required(CONF_HOST): str, vol.Required(CONF_PORT, default=DEFAULT_PORT): int,
vol.Required(CONF_USERNAME): str, }
vol.Required(CONF_PASSWORD): str,
vol.Required(CONF_PORT, default=DEFAULT_PORT): int,
}
)
return self.async_show_form( return self.async_show_form(
step_id="user", step_id="user",
@ -130,18 +125,17 @@ class AxisFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
Generate a name to be used as a prefix for device entities. Generate a name to be used as a prefix for device entities.
""" """
if self.name is None: same_model = [
same_model = [ entry.data[CONF_NAME]
entry.data[CONF_NAME] for entry in self.hass.config_entries.async_entries(DOMAIN)
for entry in self.hass.config_entries.async_entries(DOMAIN) if entry.data[CONF_MODEL] == self.model
if entry.data[CONF_MODEL] == self.model ]
]
self.name = f"{self.model}" self.name = f"{self.model}"
for idx in range(len(same_model) + 1): for idx in range(len(same_model) + 1):
self.name = f"{self.model} {idx}" self.name = f"{self.model} {idx}"
if self.name not in same_model: if self.name not in same_model:
break break
data = { data = {
CONF_DEVICE: self.device_config, CONF_DEVICE: self.device_config,
@ -187,53 +181,17 @@ class AxisFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
await self._update_entry(entry, discovery_info[CONF_HOST]) await self._update_entry(entry, discovery_info[CONF_HOST])
return self.async_abort(reason="already_configured") return self.async_abort(reason="already_configured")
config_file = await self.hass.async_add_executor_job(
load_json, self.hass.config.path(CONFIG_FILE)
)
# pylint: disable=no-member # https://github.com/PyCQA/pylint/issues/3167 # pylint: disable=no-member # https://github.com/PyCQA/pylint/issues/3167
self.context["title_placeholders"] = { self.context["title_placeholders"] = {
"name": discovery_info["hostname"][:-7], "name": discovery_info["hostname"][:-7],
"host": discovery_info[CONF_HOST], "host": discovery_info[CONF_HOST],
} }
if serialnumber not in config_file: self.discovery_schema = {
self.discovery_schema = { vol.Required(CONF_HOST, default=discovery_info[CONF_HOST]): str,
vol.Required(CONF_HOST, default=discovery_info[CONF_HOST]): str, vol.Required(CONF_USERNAME): str,
vol.Required(CONF_USERNAME): str, vol.Required(CONF_PASSWORD): str,
vol.Required(CONF_PASSWORD): str, vol.Required(CONF_PORT, default=discovery_info[CONF_PORT]): int,
vol.Required(CONF_PORT, default=discovery_info[CONF_PORT]): int,
}
return await self.async_step_user()
try:
device_config = DEVICE_SCHEMA(config_file[serialnumber])
device_config[CONF_HOST] = discovery_info[CONF_HOST]
if CONF_NAME not in device_config:
device_config[CONF_NAME] = discovery_info["hostname"]
except vol.Invalid:
return self.async_abort(reason="bad_config_file")
return await self.async_step_import(device_config)
async def async_step_import(self, import_config):
"""Import a Axis device as a config entry.
This flow is triggered by `async_setup` for configured devices.
This flow is also triggered by `async_step_discovery`.
This will execute for any Axis device that contains a complete
configuration.
"""
self.name = import_config[CONF_NAME]
self.import_schema = {
vol.Required(CONF_HOST, default=import_config[CONF_HOST]): str,
vol.Required(CONF_USERNAME, default=import_config[CONF_USERNAME]): str,
vol.Required(CONF_PASSWORD, default=import_config[CONF_PASSWORD]): str,
vol.Required(CONF_PORT, default=import_config[CONF_PORT]): int,
} }
return await self.async_step_user(user_input=import_config)
return await self.async_step_user()

View file

@ -196,52 +196,6 @@ async def test_zeroconf_flow(hass):
assert result["step_id"] == "user" assert result["step_id"] == "user"
async def test_zeroconf_flow_known_device(hass):
"""Test that zeroconf discovery for known devices work.
This is legacy support from devices registered with configurator.
"""
with patch(
"homeassistant.components.axis.config_flow.load_json",
return_value={
"00408C12345": {
config_flow.CONF_HOST: "2.3.4.5",
config_flow.CONF_USERNAME: "user",
config_flow.CONF_PASSWORD: "pass",
config_flow.CONF_PORT: 80,
}
},
), patch("axis.AxisDevice") as mock_device:
def mock_constructor(loop, host, username, password, port, web_proto):
"""Fake the controller constructor."""
mock_device.loop = loop
mock_device.host = host
mock_device.username = username
mock_device.password = password
mock_device.port = port
return mock_device
mock_device.side_effect = mock_constructor
mock_device.vapix.params.system_serialnumber = "serialnumber"
mock_device.vapix.params.prodnbr = "prodnbr"
mock_device.vapix.params.prodtype = "prodtype"
mock_device.vapix.params.firmware_version = "firmware_version"
result = await hass.config_entries.flow.async_init(
config_flow.DOMAIN,
data={
config_flow.CONF_HOST: "1.2.3.4",
config_flow.CONF_PORT: 80,
"hostname": "name",
"properties": {"macaddress": "00408C12345"},
},
context={"source": "zeroconf"},
)
assert result["type"] == "create_entry"
async def test_zeroconf_flow_already_configured(hass): async def test_zeroconf_flow_already_configured(hass):
"""Test that zeroconf doesn't setup already configured devices.""" """Test that zeroconf doesn't setup already configured devices."""
entry = MockConfigEntry( entry = MockConfigEntry(
@ -298,79 +252,3 @@ async def test_zeroconf_flow_ignore_link_local_address(hass):
assert result["type"] == "abort" assert result["type"] == "abort"
assert result["reason"] == "link_local_address" assert result["reason"] == "link_local_address"
async def test_zeroconf_flow_bad_config_file(hass):
"""Test that zeroconf discovery with bad config files abort."""
with patch(
"homeassistant.components.axis.config_flow.load_json",
return_value={
"00408C12345": {
config_flow.CONF_HOST: "2.3.4.5",
config_flow.CONF_USERNAME: "user",
config_flow.CONF_PASSWORD: "pass",
config_flow.CONF_PORT: 80,
}
},
), patch(
"homeassistant.components.axis.config_flow.DEVICE_SCHEMA",
side_effect=config_flow.vol.Invalid(""),
):
result = await hass.config_entries.flow.async_init(
config_flow.DOMAIN,
data={
config_flow.CONF_HOST: "1.2.3.4",
"hostname": "name",
"properties": {"macaddress": "00408C12345"},
},
context={"source": "zeroconf"},
)
assert result["type"] == "abort"
assert result["reason"] == "bad_config_file"
async def test_import_flow_works(hass):
"""Test that import flow works."""
with patch("axis.AxisDevice") as mock_device:
def mock_constructor(loop, host, username, password, port, web_proto):
"""Fake the controller constructor."""
mock_device.loop = loop
mock_device.host = host
mock_device.username = username
mock_device.password = password
mock_device.port = port
return mock_device
mock_device.side_effect = mock_constructor
mock_device.vapix.params.system_serialnumber = "serialnumber"
mock_device.vapix.params.prodnbr = "prodnbr"
mock_device.vapix.params.prodtype = "prodtype"
mock_device.vapix.params.firmware_version = "firmware_version"
result = await hass.config_entries.flow.async_init(
config_flow.DOMAIN,
data={
config_flow.CONF_HOST: "1.2.3.4",
config_flow.CONF_USERNAME: "user",
config_flow.CONF_PASSWORD: "pass",
config_flow.CONF_PORT: 80,
config_flow.CONF_NAME: "name",
},
context={"source": "import"},
)
assert result["type"] == "create_entry"
assert result["title"] == "{} - {}".format("prodnbr", "serialnumber")
assert result["data"] == {
axis.CONF_DEVICE: {
config_flow.CONF_HOST: "1.2.3.4",
config_flow.CONF_USERNAME: "user",
config_flow.CONF_PASSWORD: "pass",
config_flow.CONF_PORT: 80,
},
config_flow.CONF_MAC: "serialnumber",
config_flow.CONF_MODEL: "prodnbr",
config_flow.CONF_NAME: "name",
}

View file

@ -7,26 +7,6 @@ from homeassistant.setup import async_setup_component
from tests.common import MockConfigEntry, mock_coro from tests.common import MockConfigEntry, mock_coro
async def test_setup(hass):
"""Test configured options for a device are loaded via config entry."""
with patch.object(hass.config_entries, "flow") as mock_config_flow:
assert await async_setup_component(
hass,
axis.DOMAIN,
{
axis.DOMAIN: {
"device_name": {
axis.config_flow.CONF_HOST: "1.2.3.4",
axis.config_flow.CONF_PORT: 80,
}
}
},
)
assert len(mock_config_flow.mock_calls) == 1
async def test_setup_device_already_configured(hass): async def test_setup_device_already_configured(hass):
"""Test already configured device does not configure a second.""" """Test already configured device does not configure a second."""
with patch.object(hass, "config_entries") as mock_config_entries: with patch.object(hass, "config_entries") as mock_config_entries: