mirror of
https://github.com/home-assistant/core.git
synced 2025-07-24 13:47:35 +00:00
Axis - config flow use new helper functions (#31286)
* Make use of new config flow helpers Simplify Axis entry config to work with config flow helpers * Keep old device data for rollback purposes
This commit is contained in:
parent
cd1aa46404
commit
56657fa859
@ -1,15 +1,23 @@
|
|||||||
"""Support for Axis devices."""
|
"""Support for Axis devices."""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_DEVICE,
|
CONF_DEVICE,
|
||||||
|
CONF_HOST,
|
||||||
CONF_MAC,
|
CONF_MAC,
|
||||||
|
CONF_PASSWORD,
|
||||||
|
CONF_PORT,
|
||||||
CONF_TRIGGER_TIME,
|
CONF_TRIGGER_TIME,
|
||||||
|
CONF_USERNAME,
|
||||||
EVENT_HOMEASSISTANT_STOP,
|
EVENT_HOMEASSISTANT_STOP,
|
||||||
)
|
)
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup(hass, config):
|
async def async_setup(hass, config):
|
||||||
"""Old way to set up Axis devices."""
|
"""Old way to set up Axis devices."""
|
||||||
@ -35,7 +43,7 @@ async def async_setup_entry(hass, config_entry):
|
|||||||
config_entry, unique_id=device.api.vapix.params.system_serialnumber
|
config_entry, unique_id=device.api.vapix.params.system_serialnumber
|
||||||
)
|
)
|
||||||
|
|
||||||
hass.data[DOMAIN][device.serial] = device
|
hass.data[DOMAIN][config_entry.unique_id] = device
|
||||||
|
|
||||||
await device.async_update_device_registry()
|
await device.async_update_device_registry()
|
||||||
|
|
||||||
@ -52,7 +60,13 @@ async def async_unload_entry(hass, config_entry):
|
|||||||
|
|
||||||
async def async_populate_options(hass, config_entry):
|
async def async_populate_options(hass, config_entry):
|
||||||
"""Populate default options for device."""
|
"""Populate default options for device."""
|
||||||
device = await get_device(hass, config_entry.data[CONF_DEVICE])
|
device = await get_device(
|
||||||
|
hass,
|
||||||
|
host=config_entry.data[CONF_HOST],
|
||||||
|
port=config_entry.data[CONF_PORT],
|
||||||
|
username=config_entry.data[CONF_USERNAME],
|
||||||
|
password=config_entry.data[CONF_PASSWORD],
|
||||||
|
)
|
||||||
|
|
||||||
supported_formats = device.vapix.params.image_format
|
supported_formats = device.vapix.params.image_format
|
||||||
camera = bool(supported_formats)
|
camera = bool(supported_formats)
|
||||||
@ -64,3 +78,18 @@ async def async_populate_options(hass, config_entry):
|
|||||||
}
|
}
|
||||||
|
|
||||||
hass.config_entries.async_update_entry(config_entry, options=options)
|
hass.config_entries.async_update_entry(config_entry, options=options)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_migrate_entry(hass, config_entry):
|
||||||
|
"""Migrate old entry."""
|
||||||
|
LOGGER.debug("Migrating from version %s", config_entry.version)
|
||||||
|
|
||||||
|
# Flatten configuration but keep old data if user rollbacks HASS
|
||||||
|
if config_entry.version == 1:
|
||||||
|
config_entry.data = {**config_entry.data, **config_entry.data[CONF_DEVICE]}
|
||||||
|
|
||||||
|
config_entry.version = 2
|
||||||
|
|
||||||
|
LOGGER.info("Migration to version %s successful", config_entry.version)
|
||||||
|
|
||||||
|
return True
|
||||||
|
@ -9,7 +9,6 @@ from homeassistant.components.mjpeg.camera import (
|
|||||||
)
|
)
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_AUTHENTICATION,
|
CONF_AUTHENTICATION,
|
||||||
CONF_DEVICE,
|
|
||||||
CONF_HOST,
|
CONF_HOST,
|
||||||
CONF_NAME,
|
CONF_NAME,
|
||||||
CONF_PASSWORD,
|
CONF_PASSWORD,
|
||||||
@ -35,15 +34,13 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||||||
|
|
||||||
config = {
|
config = {
|
||||||
CONF_NAME: config_entry.data[CONF_NAME],
|
CONF_NAME: config_entry.data[CONF_NAME],
|
||||||
CONF_USERNAME: config_entry.data[CONF_DEVICE][CONF_USERNAME],
|
CONF_USERNAME: config_entry.data[CONF_USERNAME],
|
||||||
CONF_PASSWORD: config_entry.data[CONF_DEVICE][CONF_PASSWORD],
|
CONF_PASSWORD: config_entry.data[CONF_PASSWORD],
|
||||||
CONF_MJPEG_URL: AXIS_VIDEO.format(
|
CONF_MJPEG_URL: AXIS_VIDEO.format(
|
||||||
config_entry.data[CONF_DEVICE][CONF_HOST],
|
config_entry.data[CONF_HOST], config_entry.data[CONF_PORT],
|
||||||
config_entry.data[CONF_DEVICE][CONF_PORT],
|
|
||||||
),
|
),
|
||||||
CONF_STILL_IMAGE_URL: AXIS_IMAGE.format(
|
CONF_STILL_IMAGE_URL: AXIS_IMAGE.format(
|
||||||
config_entry.data[CONF_DEVICE][CONF_HOST],
|
config_entry.data[CONF_HOST], config_entry.data[CONF_PORT],
|
||||||
config_entry.data[CONF_DEVICE][CONF_PORT],
|
|
||||||
),
|
),
|
||||||
CONF_AUTHENTICATION: HTTP_DIGEST_AUTHENTICATION,
|
CONF_AUTHENTICATION: HTTP_DIGEST_AUTHENTICATION,
|
||||||
}
|
}
|
||||||
@ -76,14 +73,14 @@ class AxisCamera(AxisEntityBase, MjpegCamera):
|
|||||||
async def stream_source(self):
|
async def stream_source(self):
|
||||||
"""Return the stream source."""
|
"""Return the stream source."""
|
||||||
return AXIS_STREAM.format(
|
return AXIS_STREAM.format(
|
||||||
self.device.config_entry.data[CONF_DEVICE][CONF_USERNAME],
|
self.device.config_entry.data[CONF_USERNAME],
|
||||||
self.device.config_entry.data[CONF_DEVICE][CONF_PASSWORD],
|
self.device.config_entry.data[CONF_PASSWORD],
|
||||||
self.device.host,
|
self.device.host,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _new_address(self):
|
def _new_address(self):
|
||||||
"""Set new device address for video stream."""
|
"""Set new device address for video stream."""
|
||||||
port = self.device.config_entry.data[CONF_DEVICE][CONF_PORT]
|
port = self.device.config_entry.data[CONF_PORT]
|
||||||
self._mjpeg_url = AXIS_VIDEO.format(self.device.host, port)
|
self._mjpeg_url = AXIS_VIDEO.format(self.device.host, port)
|
||||||
self._still_image_url = AXIS_IMAGE.format(self.device.host, port)
|
self._still_image_url = AXIS_IMAGE.format(self.device.host, port)
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ import voluptuous as vol
|
|||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_DEVICE,
|
|
||||||
CONF_HOST,
|
CONF_HOST,
|
||||||
CONF_MAC,
|
CONF_MAC,
|
||||||
CONF_NAME,
|
CONF_NAME,
|
||||||
@ -33,16 +32,12 @@ DEFAULT_PORT = 80
|
|||||||
class AxisFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
class AxisFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
"""Handle a Axis config flow."""
|
"""Handle a Axis config flow."""
|
||||||
|
|
||||||
VERSION = 1
|
VERSION = 2
|
||||||
CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_PUSH
|
CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_PUSH
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""Initialize the Axis config flow."""
|
"""Initialize the Axis config flow."""
|
||||||
self.device_config = {}
|
self.device_config = {}
|
||||||
self.model = None
|
|
||||||
self.name = None
|
|
||||||
self.serial_number = None
|
|
||||||
|
|
||||||
self.discovery_schema = {}
|
self.discovery_schema = {}
|
||||||
self.import_schema = {}
|
self.import_schema = {}
|
||||||
|
|
||||||
@ -55,24 +50,32 @@ class AxisFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
|
|
||||||
if user_input is not None:
|
if user_input is not None:
|
||||||
try:
|
try:
|
||||||
|
device = await get_device(
|
||||||
|
self.hass,
|
||||||
|
host=user_input[CONF_HOST],
|
||||||
|
port=user_input[CONF_PORT],
|
||||||
|
username=user_input[CONF_USERNAME],
|
||||||
|
password=user_input[CONF_PASSWORD],
|
||||||
|
)
|
||||||
|
|
||||||
|
serial_number = device.vapix.params.system_serialnumber
|
||||||
|
await self.async_set_unique_id(serial_number)
|
||||||
|
|
||||||
|
self._abort_if_unique_id_configured(
|
||||||
|
updates={
|
||||||
|
CONF_HOST: user_input[CONF_HOST],
|
||||||
|
CONF_PORT: user_input[CONF_PORT],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
self.device_config = {
|
self.device_config = {
|
||||||
CONF_HOST: user_input[CONF_HOST],
|
CONF_HOST: user_input[CONF_HOST],
|
||||||
CONF_PORT: user_input[CONF_PORT],
|
CONF_PORT: user_input[CONF_PORT],
|
||||||
CONF_USERNAME: user_input[CONF_USERNAME],
|
CONF_USERNAME: user_input[CONF_USERNAME],
|
||||||
CONF_PASSWORD: user_input[CONF_PASSWORD],
|
CONF_PASSWORD: user_input[CONF_PASSWORD],
|
||||||
|
CONF_MAC: serial_number,
|
||||||
|
CONF_MODEL: device.vapix.params.prodnbr,
|
||||||
}
|
}
|
||||||
device = await get_device(self.hass, self.device_config)
|
|
||||||
|
|
||||||
self.serial_number = device.vapix.params.system_serialnumber
|
|
||||||
config_entry = await self.async_set_unique_id(self.serial_number)
|
|
||||||
if config_entry:
|
|
||||||
return self._update_entry(
|
|
||||||
config_entry,
|
|
||||||
host=user_input[CONF_HOST],
|
|
||||||
port=user_input[CONF_PORT],
|
|
||||||
)
|
|
||||||
|
|
||||||
self.model = device.vapix.params.prodnbr
|
|
||||||
|
|
||||||
return await self._create_entry()
|
return await self._create_entry()
|
||||||
|
|
||||||
@ -101,41 +104,23 @@ 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.
|
||||||
"""
|
"""
|
||||||
|
model = self.device_config[CONF_MODEL]
|
||||||
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] == model
|
||||||
]
|
]
|
||||||
|
|
||||||
self.name = f"{self.model}"
|
name = model
|
||||||
for idx in range(len(same_model) + 1):
|
for idx in range(len(same_model) + 1):
|
||||||
self.name = f"{self.model} {idx}"
|
name = f"{model} {idx}"
|
||||||
if self.name not in same_model:
|
if name not in same_model:
|
||||||
break
|
break
|
||||||
|
|
||||||
data = {
|
self.device_config[CONF_NAME] = name
|
||||||
CONF_DEVICE: self.device_config,
|
|
||||||
CONF_NAME: self.name,
|
|
||||||
CONF_MAC: self.serial_number,
|
|
||||||
CONF_MODEL: self.model,
|
|
||||||
}
|
|
||||||
|
|
||||||
title = f"{self.model} - {self.serial_number}"
|
title = f"{model} - {self.device_config[CONF_MAC]}"
|
||||||
return self.async_create_entry(title=title, data=data)
|
return self.async_create_entry(title=title, data=self.device_config)
|
||||||
|
|
||||||
def _update_entry(self, entry, host, port):
|
|
||||||
"""Update existing entry."""
|
|
||||||
if (
|
|
||||||
entry.data[CONF_DEVICE][CONF_HOST] == host
|
|
||||||
and entry.data[CONF_DEVICE][CONF_PORT] == port
|
|
||||||
):
|
|
||||||
return self.async_abort(reason="already_configured")
|
|
||||||
|
|
||||||
entry.data[CONF_DEVICE][CONF_HOST] = host
|
|
||||||
entry.data[CONF_DEVICE][CONF_PORT] = port
|
|
||||||
|
|
||||||
self.hass.config_entries.async_update_entry(entry)
|
|
||||||
return self.async_abort(reason="updated_configuration")
|
|
||||||
|
|
||||||
async def async_step_zeroconf(self, discovery_info):
|
async def async_step_zeroconf(self, discovery_info):
|
||||||
"""Prepare configuration for a discovered Axis device."""
|
"""Prepare configuration for a discovered Axis device."""
|
||||||
@ -147,18 +132,19 @@ class AxisFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
if discovery_info[CONF_HOST].startswith("169.254"):
|
if discovery_info[CONF_HOST].startswith("169.254"):
|
||||||
return self.async_abort(reason="link_local_address")
|
return self.async_abort(reason="link_local_address")
|
||||||
|
|
||||||
config_entry = await self.async_set_unique_id(serial_number)
|
await self.async_set_unique_id(serial_number)
|
||||||
if config_entry:
|
|
||||||
return self._update_entry(
|
self._abort_if_unique_id_configured(
|
||||||
config_entry,
|
updates={
|
||||||
host=discovery_info[CONF_HOST],
|
CONF_HOST: discovery_info[CONF_HOST],
|
||||||
port=discovery_info[CONF_PORT],
|
CONF_PORT: discovery_info[CONF_PORT],
|
||||||
)
|
}
|
||||||
|
)
|
||||||
|
|
||||||
# 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],
|
CONF_NAME: discovery_info["hostname"][:-7],
|
||||||
"host": discovery_info[CONF_HOST],
|
CONF_HOST: discovery_info[CONF_HOST],
|
||||||
}
|
}
|
||||||
|
|
||||||
self.discovery_schema = {
|
self.discovery_schema = {
|
||||||
|
@ -7,9 +7,7 @@ import axis
|
|||||||
from axis.streammanager import SIGNAL_PLAYING
|
from axis.streammanager import SIGNAL_PLAYING
|
||||||
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_DEVICE,
|
|
||||||
CONF_HOST,
|
CONF_HOST,
|
||||||
CONF_MAC,
|
|
||||||
CONF_NAME,
|
CONF_NAME,
|
||||||
CONF_PASSWORD,
|
CONF_PASSWORD,
|
||||||
CONF_PORT,
|
CONF_PORT,
|
||||||
@ -42,7 +40,7 @@ class AxisNetworkDevice:
|
|||||||
@property
|
@property
|
||||||
def host(self):
|
def host(self):
|
||||||
"""Return the host of this device."""
|
"""Return the host of this device."""
|
||||||
return self.config_entry.data[CONF_DEVICE][CONF_HOST]
|
return self.config_entry.data[CONF_HOST]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def model(self):
|
def model(self):
|
||||||
@ -75,7 +73,13 @@ class AxisNetworkDevice:
|
|||||||
async def async_setup(self):
|
async def async_setup(self):
|
||||||
"""Set up the device."""
|
"""Set up the device."""
|
||||||
try:
|
try:
|
||||||
self.api = await get_device(self.hass, self.config_entry.data[CONF_DEVICE])
|
self.api = await get_device(
|
||||||
|
self.hass,
|
||||||
|
host=self.config_entry.data[CONF_HOST],
|
||||||
|
port=self.config_entry.data[CONF_PORT],
|
||||||
|
username=self.config_entry.data[CONF_USERNAME],
|
||||||
|
password=self.config_entry.data[CONF_PASSWORD],
|
||||||
|
)
|
||||||
|
|
||||||
except CannotConnect:
|
except CannotConnect:
|
||||||
raise ConfigEntryNotReady
|
raise ConfigEntryNotReady
|
||||||
@ -126,7 +130,7 @@ class AxisNetworkDevice:
|
|||||||
This is a static method because a class method (bound method),
|
This is a static method because a class method (bound method),
|
||||||
can not be used with weak references.
|
can not be used with weak references.
|
||||||
"""
|
"""
|
||||||
device = hass.data[DOMAIN][entry.data[CONF_MAC]]
|
device = hass.data[DOMAIN][entry.unique_id]
|
||||||
device.api.config.host = device.host
|
device.api.config.host = device.host
|
||||||
async_dispatcher_send(hass, device.event_new_address)
|
async_dispatcher_send(hass, device.event_new_address)
|
||||||
|
|
||||||
@ -197,15 +201,15 @@ class AxisNetworkDevice:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
async def get_device(hass, config):
|
async def get_device(hass, host, port, username, password):
|
||||||
"""Create a Axis device."""
|
"""Create a Axis device."""
|
||||||
|
|
||||||
device = axis.AxisDevice(
|
device = axis.AxisDevice(
|
||||||
loop=hass.loop,
|
loop=hass.loop,
|
||||||
host=config[CONF_HOST],
|
host=host,
|
||||||
username=config[CONF_USERNAME],
|
port=port,
|
||||||
password=config[CONF_PASSWORD],
|
username=username,
|
||||||
port=config[CONF_PORT],
|
password=password,
|
||||||
web_proto="http",
|
web_proto="http",
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -224,13 +228,11 @@ async def get_device(hass, config):
|
|||||||
return device
|
return device
|
||||||
|
|
||||||
except axis.Unauthorized:
|
except axis.Unauthorized:
|
||||||
LOGGER.warning(
|
LOGGER.warning("Connected to device at %s but not registered.", host)
|
||||||
"Connected to device at %s but not registered.", config[CONF_HOST]
|
|
||||||
)
|
|
||||||
raise AuthenticationRequired
|
raise AuthenticationRequired
|
||||||
|
|
||||||
except (asyncio.TimeoutError, axis.RequestError):
|
except (asyncio.TimeoutError, axis.RequestError):
|
||||||
LOGGER.error("Error connecting to the Axis device at %s", config[CONF_HOST])
|
LOGGER.error("Error connecting to the Axis device at %s", host)
|
||||||
raise CannotConnect
|
raise CannotConnect
|
||||||
|
|
||||||
except axis.AxisException:
|
except axis.AxisException:
|
||||||
|
@ -23,8 +23,7 @@
|
|||||||
"already_configured": "Device is already configured",
|
"already_configured": "Device is already configured",
|
||||||
"bad_config_file": "Bad data from config file",
|
"bad_config_file": "Bad data from config file",
|
||||||
"link_local_address": "Link local addresses are not supported",
|
"link_local_address": "Link local addresses are not supported",
|
||||||
"not_axis_device": "Discovered device not an Axis device",
|
"not_axis_device": "Discovered device not an Axis device"
|
||||||
"updated_configuration": "Updated device configuration with new host address"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,7 +4,7 @@ from unittest.mock import Mock, patch
|
|||||||
from homeassistant.components import axis
|
from homeassistant.components import axis
|
||||||
from homeassistant.components.axis import config_flow
|
from homeassistant.components.axis import config_flow
|
||||||
|
|
||||||
from .test_device import MAC, setup_axis_integration
|
from .test_device import MAC, MODEL, NAME, setup_axis_integration
|
||||||
|
|
||||||
from tests.common import MockConfigEntry, mock_coro
|
from tests.common import MockConfigEntry, mock_coro
|
||||||
|
|
||||||
@ -54,12 +54,10 @@ async def test_flow_manual_configuration(hass):
|
|||||||
assert result["type"] == "create_entry"
|
assert result["type"] == "create_entry"
|
||||||
assert result["title"] == f"prodnbr - {MAC}"
|
assert result["title"] == f"prodnbr - {MAC}"
|
||||||
assert result["data"] == {
|
assert result["data"] == {
|
||||||
axis.CONF_DEVICE: {
|
config_flow.CONF_HOST: "1.2.3.4",
|
||||||
config_flow.CONF_HOST: "1.2.3.4",
|
config_flow.CONF_USERNAME: "user",
|
||||||
config_flow.CONF_USERNAME: "user",
|
config_flow.CONF_PASSWORD: "pass",
|
||||||
config_flow.CONF_PASSWORD: "pass",
|
config_flow.CONF_PORT: 80,
|
||||||
config_flow.CONF_PORT: 80,
|
|
||||||
},
|
|
||||||
config_flow.CONF_MAC: MAC,
|
config_flow.CONF_MAC: MAC,
|
||||||
config_flow.CONF_MODEL: "prodnbr",
|
config_flow.CONF_MODEL: "prodnbr",
|
||||||
config_flow.CONF_NAME: "prodnbr 0",
|
config_flow.CONF_NAME: "prodnbr 0",
|
||||||
@ -95,11 +93,8 @@ async def test_manual_configuration_update_configuration(hass):
|
|||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "abort"
|
assert result["type"] == "abort"
|
||||||
assert result["reason"] == "updated_configuration"
|
assert result["reason"] == "already_configured"
|
||||||
assert (
|
assert device.config_entry.data[config_flow.CONF_HOST] == "2.3.4.5"
|
||||||
device.config_entry.data[config_flow.CONF_DEVICE][config_flow.CONF_HOST]
|
|
||||||
== "2.3.4.5"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def test_flow_fails_already_configured(hass):
|
async def test_flow_fails_already_configured(hass):
|
||||||
@ -223,12 +218,10 @@ async def test_flow_create_entry_multiple_existing_entries_of_same_model(hass):
|
|||||||
assert result["type"] == "create_entry"
|
assert result["type"] == "create_entry"
|
||||||
assert result["title"] == f"prodnbr - {MAC}"
|
assert result["title"] == f"prodnbr - {MAC}"
|
||||||
assert result["data"] == {
|
assert result["data"] == {
|
||||||
axis.CONF_DEVICE: {
|
config_flow.CONF_HOST: "1.2.3.4",
|
||||||
config_flow.CONF_HOST: "1.2.3.4",
|
config_flow.CONF_USERNAME: "user",
|
||||||
config_flow.CONF_USERNAME: "user",
|
config_flow.CONF_PASSWORD: "pass",
|
||||||
config_flow.CONF_PASSWORD: "pass",
|
config_flow.CONF_PORT: 80,
|
||||||
config_flow.CONF_PORT: 80,
|
|
||||||
},
|
|
||||||
config_flow.CONF_MAC: MAC,
|
config_flow.CONF_MAC: MAC,
|
||||||
config_flow.CONF_MODEL: "prodnbr",
|
config_flow.CONF_MODEL: "prodnbr",
|
||||||
config_flow.CONF_NAME: "prodnbr 2",
|
config_flow.CONF_NAME: "prodnbr 2",
|
||||||
@ -271,12 +264,10 @@ async def test_zeroconf_flow(hass):
|
|||||||
assert result["type"] == "create_entry"
|
assert result["type"] == "create_entry"
|
||||||
assert result["title"] == f"prodnbr - {MAC}"
|
assert result["title"] == f"prodnbr - {MAC}"
|
||||||
assert result["data"] == {
|
assert result["data"] == {
|
||||||
axis.CONF_DEVICE: {
|
config_flow.CONF_HOST: "1.2.3.4",
|
||||||
config_flow.CONF_HOST: "1.2.3.4",
|
config_flow.CONF_USERNAME: "user",
|
||||||
config_flow.CONF_USERNAME: "user",
|
config_flow.CONF_PASSWORD: "pass",
|
||||||
config_flow.CONF_PASSWORD: "pass",
|
config_flow.CONF_PORT: 80,
|
||||||
config_flow.CONF_PORT: 80,
|
|
||||||
},
|
|
||||||
config_flow.CONF_MAC: MAC,
|
config_flow.CONF_MAC: MAC,
|
||||||
config_flow.CONF_MODEL: "prodnbr",
|
config_flow.CONF_MODEL: "prodnbr",
|
||||||
config_flow.CONF_NAME: "prodnbr 0",
|
config_flow.CONF_NAME: "prodnbr 0",
|
||||||
@ -310,6 +301,15 @@ async def test_zeroconf_flow_updated_configuration(hass):
|
|||||||
"""Test that zeroconf update configuration with new parameters."""
|
"""Test that zeroconf update configuration with new parameters."""
|
||||||
device = await setup_axis_integration(hass)
|
device = await setup_axis_integration(hass)
|
||||||
assert device.host == "1.2.3.4"
|
assert device.host == "1.2.3.4"
|
||||||
|
assert device.config_entry.data == {
|
||||||
|
config_flow.CONF_HOST: "1.2.3.4",
|
||||||
|
config_flow.CONF_PORT: 80,
|
||||||
|
config_flow.CONF_USERNAME: "username",
|
||||||
|
config_flow.CONF_PASSWORD: "password",
|
||||||
|
config_flow.CONF_MAC: MAC,
|
||||||
|
config_flow.CONF_MODEL: MODEL,
|
||||||
|
config_flow.CONF_NAME: NAME,
|
||||||
|
}
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
config_flow.DOMAIN,
|
config_flow.DOMAIN,
|
||||||
@ -323,11 +323,16 @@ async def test_zeroconf_flow_updated_configuration(hass):
|
|||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "abort"
|
assert result["type"] == "abort"
|
||||||
assert result["reason"] == "updated_configuration"
|
assert result["reason"] == "already_configured"
|
||||||
assert device.host == "2.3.4.5"
|
assert device.config_entry.data == {
|
||||||
assert (
|
config_flow.CONF_HOST: "2.3.4.5",
|
||||||
device.config_entry.data[config_flow.CONF_DEVICE][config_flow.CONF_PORT] == 8080
|
config_flow.CONF_PORT: 8080,
|
||||||
)
|
config_flow.CONF_USERNAME: "username",
|
||||||
|
config_flow.CONF_PASSWORD: "password",
|
||||||
|
config_flow.CONF_MAC: MAC,
|
||||||
|
config_flow.CONF_MODEL: MODEL,
|
||||||
|
config_flow.CONF_NAME: NAME,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async def test_zeroconf_flow_ignore_non_axis_device(hass):
|
async def test_zeroconf_flow_ignore_non_axis_device(hass):
|
||||||
|
@ -14,18 +14,14 @@ MAC = "00408C12345"
|
|||||||
MODEL = "model"
|
MODEL = "model"
|
||||||
NAME = "name"
|
NAME = "name"
|
||||||
|
|
||||||
DEVICE_DATA = {
|
ENTRY_OPTIONS = {axis.CONF_CAMERA: True, axis.CONF_EVENTS: True}
|
||||||
axis.device.CONF_HOST: "1.2.3.4",
|
|
||||||
axis.device.CONF_USERNAME: "username",
|
|
||||||
axis.device.CONF_PASSWORD: "password",
|
|
||||||
axis.device.CONF_PORT: 80,
|
|
||||||
}
|
|
||||||
|
|
||||||
ENTRY_OPTIONS = {axis.device.CONF_CAMERA: True, axis.device.CONF_EVENTS: True}
|
|
||||||
|
|
||||||
ENTRY_CONFIG = {
|
ENTRY_CONFIG = {
|
||||||
axis.device.CONF_DEVICE: DEVICE_DATA,
|
axis.CONF_HOST: "1.2.3.4",
|
||||||
axis.device.CONF_MAC: MAC,
|
axis.CONF_USERNAME: "username",
|
||||||
|
axis.CONF_PASSWORD: "password",
|
||||||
|
axis.CONF_PORT: 80,
|
||||||
|
axis.CONF_MAC: MAC,
|
||||||
axis.device.CONF_MODEL: MODEL,
|
axis.device.CONF_MODEL: MODEL,
|
||||||
axis.device.CONF_NAME: NAME,
|
axis.device.CONF_NAME: NAME,
|
||||||
}
|
}
|
||||||
@ -76,6 +72,7 @@ async def setup_axis_integration(
|
|||||||
connection_class=config_entries.CONN_CLASS_LOCAL_PUSH,
|
connection_class=config_entries.CONN_CLASS_LOCAL_PUSH,
|
||||||
options=deepcopy(options),
|
options=deepcopy(options),
|
||||||
entry_id="1",
|
entry_id="1",
|
||||||
|
version=2,
|
||||||
)
|
)
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
|
|
||||||
@ -116,10 +113,10 @@ async def test_device_setup(hass):
|
|||||||
assert forward_entry_setup.mock_calls[1][1] == (entry, "binary_sensor")
|
assert forward_entry_setup.mock_calls[1][1] == (entry, "binary_sensor")
|
||||||
assert forward_entry_setup.mock_calls[2][1] == (entry, "switch")
|
assert forward_entry_setup.mock_calls[2][1] == (entry, "switch")
|
||||||
|
|
||||||
assert device.host == DEVICE_DATA[axis.device.CONF_HOST]
|
assert device.host == ENTRY_CONFIG[axis.CONF_HOST]
|
||||||
assert device.model == ENTRY_CONFIG[axis.device.CONF_MODEL]
|
assert device.model == ENTRY_CONFIG[axis.device.CONF_MODEL]
|
||||||
assert device.name == ENTRY_CONFIG[axis.device.CONF_NAME]
|
assert device.name == ENTRY_CONFIG[axis.device.CONF_NAME]
|
||||||
assert device.serial == ENTRY_CONFIG[axis.device.CONF_MAC]
|
assert device.serial == ENTRY_CONFIG[axis.CONF_MAC]
|
||||||
|
|
||||||
|
|
||||||
async def test_update_address(hass):
|
async def test_update_address(hass):
|
||||||
@ -204,7 +201,7 @@ async def test_get_device_fails(hass):
|
|||||||
with patch(
|
with patch(
|
||||||
"axis.param_cgi.Params.update_brand", side_effect=axislib.Unauthorized
|
"axis.param_cgi.Params.update_brand", side_effect=axislib.Unauthorized
|
||||||
), pytest.raises(axis.errors.AuthenticationRequired):
|
), pytest.raises(axis.errors.AuthenticationRequired):
|
||||||
await axis.device.get_device(hass, DEVICE_DATA)
|
await axis.device.get_device(hass, host="", port="", username="", password="")
|
||||||
|
|
||||||
|
|
||||||
async def test_get_device_device_unavailable(hass):
|
async def test_get_device_device_unavailable(hass):
|
||||||
@ -212,7 +209,7 @@ async def test_get_device_device_unavailable(hass):
|
|||||||
with patch(
|
with patch(
|
||||||
"axis.param_cgi.Params.update_brand", side_effect=axislib.RequestError
|
"axis.param_cgi.Params.update_brand", side_effect=axislib.RequestError
|
||||||
), pytest.raises(axis.errors.CannotConnect):
|
), pytest.raises(axis.errors.CannotConnect):
|
||||||
await axis.device.get_device(hass, DEVICE_DATA)
|
await axis.device.get_device(hass, host="", port="", username="", password="")
|
||||||
|
|
||||||
|
|
||||||
async def test_get_device_unknown_error(hass):
|
async def test_get_device_unknown_error(hass):
|
||||||
@ -220,4 +217,4 @@ async def test_get_device_unknown_error(hass):
|
|||||||
with patch(
|
with patch(
|
||||||
"axis.param_cgi.Params.update_brand", side_effect=axislib.AxisException
|
"axis.param_cgi.Params.update_brand", side_effect=axislib.AxisException
|
||||||
), pytest.raises(axis.errors.AuthenticationRequired):
|
), pytest.raises(axis.errors.AuthenticationRequired):
|
||||||
await axis.device.get_device(hass, DEVICE_DATA)
|
await axis.device.get_device(hass, host="", port="", username="", password="")
|
||||||
|
@ -4,7 +4,7 @@ from unittest.mock import Mock, patch
|
|||||||
from homeassistant.components import axis
|
from homeassistant.components import axis
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
from .test_device import MAC, setup_axis_integration
|
from .test_device import ENTRY_CONFIG, MAC, setup_axis_integration
|
||||||
|
|
||||||
from tests.common import MockConfigEntry, mock_coro
|
from tests.common import MockConfigEntry, mock_coro
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ async def test_setup_device_already_configured(hass):
|
|||||||
assert await async_setup_component(
|
assert await async_setup_component(
|
||||||
hass,
|
hass,
|
||||||
axis.DOMAIN,
|
axis.DOMAIN,
|
||||||
{axis.DOMAIN: {"device_name": {axis.config_flow.CONF_HOST: "1.2.3.4"}}},
|
{axis.DOMAIN: {"device_name": {axis.CONF_HOST: "1.2.3.4"}}},
|
||||||
)
|
)
|
||||||
|
|
||||||
assert not mock_config_entries.flow.mock_calls
|
assert not mock_config_entries.flow.mock_calls
|
||||||
@ -38,7 +38,7 @@ async def test_setup_entry(hass):
|
|||||||
async def test_setup_entry_fails(hass):
|
async def test_setup_entry_fails(hass):
|
||||||
"""Test successful setup of entry."""
|
"""Test successful setup of entry."""
|
||||||
entry = MockConfigEntry(
|
entry = MockConfigEntry(
|
||||||
domain=axis.DOMAIN, data={axis.device.CONF_MAC: "0123"}, options=True
|
domain=axis.DOMAIN, data={axis.CONF_MAC: "0123"}, options=True
|
||||||
)
|
)
|
||||||
|
|
||||||
mock_device = Mock()
|
mock_device = Mock()
|
||||||
@ -63,7 +63,7 @@ async def test_unload_entry(hass):
|
|||||||
|
|
||||||
async def test_populate_options(hass):
|
async def test_populate_options(hass):
|
||||||
"""Test successful populate options."""
|
"""Test successful populate options."""
|
||||||
entry = MockConfigEntry(domain=axis.DOMAIN, data={"device": {}})
|
entry = MockConfigEntry(domain=axis.DOMAIN, data=ENTRY_CONFIG)
|
||||||
entry.add_to_hass(hass)
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
with patch.object(axis, "get_device", return_value=mock_coro(Mock())):
|
with patch.object(axis, "get_device", return_value=mock_coro(Mock())):
|
||||||
@ -75,3 +75,41 @@ async def test_populate_options(hass):
|
|||||||
axis.CONF_EVENTS: True,
|
axis.CONF_EVENTS: True,
|
||||||
axis.CONF_TRIGGER_TIME: axis.DEFAULT_TRIGGER_TIME,
|
axis.CONF_TRIGGER_TIME: axis.DEFAULT_TRIGGER_TIME,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_migrate_entry(hass):
|
||||||
|
"""Test successful migration of entry data."""
|
||||||
|
legacy_config = {
|
||||||
|
axis.CONF_DEVICE: {
|
||||||
|
axis.CONF_HOST: "1.2.3.4",
|
||||||
|
axis.CONF_USERNAME: "username",
|
||||||
|
axis.CONF_PASSWORD: "password",
|
||||||
|
axis.CONF_PORT: 80,
|
||||||
|
},
|
||||||
|
axis.CONF_MAC: "mac",
|
||||||
|
axis.device.CONF_MODEL: "model",
|
||||||
|
axis.device.CONF_NAME: "name",
|
||||||
|
}
|
||||||
|
entry = MockConfigEntry(domain=axis.DOMAIN, data=legacy_config)
|
||||||
|
|
||||||
|
assert entry.data == legacy_config
|
||||||
|
assert entry.version == 1
|
||||||
|
|
||||||
|
await axis.async_migrate_entry(hass, entry)
|
||||||
|
|
||||||
|
assert entry.data == {
|
||||||
|
axis.CONF_DEVICE: {
|
||||||
|
axis.CONF_HOST: "1.2.3.4",
|
||||||
|
axis.CONF_USERNAME: "username",
|
||||||
|
axis.CONF_PASSWORD: "password",
|
||||||
|
axis.CONF_PORT: 80,
|
||||||
|
},
|
||||||
|
axis.CONF_HOST: "1.2.3.4",
|
||||||
|
axis.CONF_USERNAME: "username",
|
||||||
|
axis.CONF_PASSWORD: "password",
|
||||||
|
axis.CONF_PORT: 80,
|
||||||
|
axis.CONF_MAC: "mac",
|
||||||
|
axis.device.CONF_MODEL: "model",
|
||||||
|
axis.device.CONF_NAME: "name",
|
||||||
|
}
|
||||||
|
assert entry.version == 2
|
||||||
|
Loading…
x
Reference in New Issue
Block a user