Use runtime_data in Axis integration (#116729)
Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com>
This commit is contained in:
parent
ce8cea86a2
commit
81a269f4f5
9 changed files with 47 additions and 56 deletions
|
@ -13,8 +13,10 @@ from .hub import AxisHub, get_axis_api
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
AxisConfigEntry = ConfigEntry[AxisHub]
|
||||||
|
|
||||||
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
|
|
||||||
|
async def async_setup_entry(hass: HomeAssistant, config_entry: AxisConfigEntry) -> bool:
|
||||||
"""Set up the Axis integration."""
|
"""Set up the Axis integration."""
|
||||||
hass.data.setdefault(AXIS_DOMAIN, {})
|
hass.data.setdefault(AXIS_DOMAIN, {})
|
||||||
|
|
||||||
|
@ -25,8 +27,7 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
|
||||||
except AuthenticationRequired as err:
|
except AuthenticationRequired as err:
|
||||||
raise ConfigEntryAuthFailed from err
|
raise ConfigEntryAuthFailed from err
|
||||||
|
|
||||||
hub = AxisHub(hass, config_entry, api)
|
hub = config_entry.runtime_data = AxisHub(hass, config_entry, api)
|
||||||
hass.data[AXIS_DOMAIN][config_entry.entry_id] = hub
|
|
||||||
await hub.async_update_device_registry()
|
await hub.async_update_device_registry()
|
||||||
await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS)
|
await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS)
|
||||||
hub.setup()
|
hub.setup()
|
||||||
|
@ -42,7 +43,6 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
|
||||||
|
|
||||||
async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
|
async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
|
||||||
"""Unload Axis device config entry."""
|
"""Unload Axis device config entry."""
|
||||||
hass.data[AXIS_DOMAIN].pop(config_entry.entry_id)
|
|
||||||
return await hass.config_entries.async_unload_platforms(config_entry, PLATFORMS)
|
return await hass.config_entries.async_unload_platforms(config_entry, PLATFORMS)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -17,11 +17,11 @@ from homeassistant.components.binary_sensor import (
|
||||||
BinarySensorEntity,
|
BinarySensorEntity,
|
||||||
BinarySensorEntityDescription,
|
BinarySensorEntityDescription,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.event import async_call_later
|
from homeassistant.helpers.event import async_call_later
|
||||||
|
|
||||||
|
from . import AxisConfigEntry
|
||||||
from .entity import AxisEventDescription, AxisEventEntity
|
from .entity import AxisEventDescription, AxisEventEntity
|
||||||
from .hub import AxisHub
|
from .hub import AxisHub
|
||||||
|
|
||||||
|
@ -177,11 +177,11 @@ ENTITY_DESCRIPTIONS = (
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config_entry: ConfigEntry,
|
config_entry: AxisConfigEntry,
|
||||||
async_add_entities: AddEntitiesCallback,
|
async_add_entities: AddEntitiesCallback,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up a Axis binary sensor."""
|
"""Set up a Axis binary sensor."""
|
||||||
AxisHub.get_hub(hass, config_entry).entity_loader.register_platform(
|
config_entry.runtime_data.entity_loader.register_platform(
|
||||||
async_add_entities, AxisBinarySensor, ENTITY_DESCRIPTIONS
|
async_add_entities, AxisBinarySensor, ENTITY_DESCRIPTIONS
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,12 @@ from urllib.parse import urlencode
|
||||||
|
|
||||||
from homeassistant.components.camera import CameraEntityFeature
|
from homeassistant.components.camera import CameraEntityFeature
|
||||||
from homeassistant.components.mjpeg import MjpegCamera, filter_urllib3_logging
|
from homeassistant.components.mjpeg import MjpegCamera, filter_urllib3_logging
|
||||||
from homeassistant.config_entries import ConfigEntry
|
|
||||||
from homeassistant.const import HTTP_DIGEST_AUTHENTICATION
|
from homeassistant.const import HTTP_DIGEST_AUTHENTICATION
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
|
from . import AxisConfigEntry
|
||||||
from .const import DEFAULT_STREAM_PROFILE, DEFAULT_VIDEO_SOURCE
|
from .const import DEFAULT_STREAM_PROFILE, DEFAULT_VIDEO_SOURCE
|
||||||
from .entity import AxisEntity
|
from .entity import AxisEntity
|
||||||
from .hub import AxisHub
|
from .hub import AxisHub
|
||||||
|
@ -17,13 +17,13 @@ from .hub import AxisHub
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config_entry: ConfigEntry,
|
config_entry: AxisConfigEntry,
|
||||||
async_add_entities: AddEntitiesCallback,
|
async_add_entities: AddEntitiesCallback,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up the Axis camera video stream."""
|
"""Set up the Axis camera video stream."""
|
||||||
filter_urllib3_logging()
|
filter_urllib3_logging()
|
||||||
|
|
||||||
hub = AxisHub.get_hub(hass, config_entry)
|
hub = config_entry.runtime_data
|
||||||
|
|
||||||
if (
|
if (
|
||||||
not (prop := hub.api.vapix.params.property_handler.get("0"))
|
not (prop := hub.api.vapix.params.property_handler.get("0"))
|
||||||
|
|
|
@ -32,6 +32,7 @@ from homeassistant.core import callback
|
||||||
from homeassistant.helpers.device_registry import format_mac
|
from homeassistant.helpers.device_registry import format_mac
|
||||||
from homeassistant.util.network import is_link_local
|
from homeassistant.util.network import is_link_local
|
||||||
|
|
||||||
|
from . import AxisConfigEntry
|
||||||
from .const import (
|
from .const import (
|
||||||
CONF_STREAM_PROFILE,
|
CONF_STREAM_PROFILE,
|
||||||
CONF_VIDEO_SOURCE,
|
CONF_VIDEO_SOURCE,
|
||||||
|
@ -260,13 +261,14 @@ class AxisFlowHandler(ConfigFlow, domain=AXIS_DOMAIN):
|
||||||
class AxisOptionsFlowHandler(OptionsFlowWithConfigEntry):
|
class AxisOptionsFlowHandler(OptionsFlowWithConfigEntry):
|
||||||
"""Handle Axis device options."""
|
"""Handle Axis device options."""
|
||||||
|
|
||||||
|
config_entry: AxisConfigEntry
|
||||||
hub: AxisHub
|
hub: AxisHub
|
||||||
|
|
||||||
async def async_step_init(
|
async def async_step_init(
|
||||||
self, user_input: dict[str, Any] | None = None
|
self, user_input: dict[str, Any] | None = None
|
||||||
) -> ConfigFlowResult:
|
) -> ConfigFlowResult:
|
||||||
"""Manage the Axis device options."""
|
"""Manage the Axis device options."""
|
||||||
self.hub = AxisHub.get_hub(self.hass, self.config_entry)
|
self.hub = self.config_entry.runtime_data
|
||||||
return await self.async_step_configure_stream()
|
return await self.async_step_configure_stream()
|
||||||
|
|
||||||
async def async_step_configure_stream(
|
async def async_step_configure_stream(
|
||||||
|
|
|
@ -5,11 +5,10 @@ from __future__ import annotations
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from homeassistant.components.diagnostics import async_redact_data
|
from homeassistant.components.diagnostics import async_redact_data
|
||||||
from homeassistant.config_entries import ConfigEntry
|
|
||||||
from homeassistant.const import CONF_MAC, CONF_PASSWORD, CONF_UNIQUE_ID, CONF_USERNAME
|
from homeassistant.const import CONF_MAC, CONF_PASSWORD, CONF_UNIQUE_ID, CONF_USERNAME
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
from .hub import AxisHub
|
from . import AxisConfigEntry
|
||||||
|
|
||||||
REDACT_CONFIG = {CONF_MAC, CONF_PASSWORD, CONF_UNIQUE_ID, CONF_USERNAME}
|
REDACT_CONFIG = {CONF_MAC, CONF_PASSWORD, CONF_UNIQUE_ID, CONF_USERNAME}
|
||||||
REDACT_BASIC_DEVICE_INFO = {"SerialNumber", "SocSerialNumber"}
|
REDACT_BASIC_DEVICE_INFO = {"SerialNumber", "SocSerialNumber"}
|
||||||
|
@ -17,10 +16,10 @@ REDACT_VAPIX_PARAMS = {"root.Network", "System.SerialNumber"}
|
||||||
|
|
||||||
|
|
||||||
async def async_get_config_entry_diagnostics(
|
async def async_get_config_entry_diagnostics(
|
||||||
hass: HomeAssistant, config_entry: ConfigEntry
|
hass: HomeAssistant, config_entry: AxisConfigEntry
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
"""Return diagnostics for a config entry."""
|
"""Return diagnostics for a config entry."""
|
||||||
hub = AxisHub.get_hub(hass, config_entry)
|
hub = config_entry.runtime_data
|
||||||
diag: dict[str, Any] = hub.additional_diagnostics.copy()
|
diag: dict[str, Any] = hub.additional_diagnostics.copy()
|
||||||
|
|
||||||
diag["config"] = async_redact_data(config_entry.as_dict(), REDACT_CONFIG)
|
diag["config"] = async_redact_data(config_entry.as_dict(), REDACT_CONFIG)
|
||||||
|
|
|
@ -2,11 +2,10 @@
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import TYPE_CHECKING, Any
|
||||||
|
|
||||||
import axis
|
import axis
|
||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry
|
|
||||||
from homeassistant.core import Event, HomeAssistant, callback
|
from homeassistant.core import Event, HomeAssistant, callback
|
||||||
from homeassistant.helpers import device_registry as dr
|
from homeassistant.helpers import device_registry as dr
|
||||||
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, format_mac
|
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, format_mac
|
||||||
|
@ -17,12 +16,15 @@ from .config import AxisConfig
|
||||||
from .entity_loader import AxisEntityLoader
|
from .entity_loader import AxisEntityLoader
|
||||||
from .event_source import AxisEventSource
|
from .event_source import AxisEventSource
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from .. import AxisConfigEntry
|
||||||
|
|
||||||
|
|
||||||
class AxisHub:
|
class AxisHub:
|
||||||
"""Manages a Axis device."""
|
"""Manages a Axis device."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, hass: HomeAssistant, config_entry: ConfigEntry, api: axis.AxisDevice
|
self, hass: HomeAssistant, config_entry: AxisConfigEntry, api: axis.AxisDevice
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the device."""
|
"""Initialize the device."""
|
||||||
self.hass = hass
|
self.hass = hass
|
||||||
|
@ -37,13 +39,6 @@ class AxisHub:
|
||||||
|
|
||||||
self.additional_diagnostics: dict[str, Any] = {}
|
self.additional_diagnostics: dict[str, Any] = {}
|
||||||
|
|
||||||
@callback
|
|
||||||
@staticmethod
|
|
||||||
def get_hub(hass: HomeAssistant, config_entry: ConfigEntry) -> AxisHub:
|
|
||||||
"""Get Axis hub from config entry."""
|
|
||||||
hub: AxisHub = hass.data[AXIS_DOMAIN][config_entry.entry_id]
|
|
||||||
return hub
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def available(self) -> bool:
|
def available(self) -> bool:
|
||||||
"""Connection state to the device."""
|
"""Connection state to the device."""
|
||||||
|
@ -63,7 +58,7 @@ class AxisHub:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def async_new_address_callback(
|
async def async_new_address_callback(
|
||||||
hass: HomeAssistant, config_entry: ConfigEntry
|
hass: HomeAssistant, config_entry: AxisConfigEntry
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Handle signals of device getting new address.
|
"""Handle signals of device getting new address.
|
||||||
|
|
||||||
|
@ -71,7 +66,7 @@ class AxisHub:
|
||||||
This is a static method because a class method (bound method),
|
This is a static method because a class method (bound method),
|
||||||
cannot be used with weak references.
|
cannot be used with weak references.
|
||||||
"""
|
"""
|
||||||
hub = AxisHub.get_hub(hass, config_entry)
|
hub = config_entry.runtime_data
|
||||||
hub.config = AxisConfig.from_config_entry(config_entry)
|
hub.config = AxisConfig.from_config_entry(config_entry)
|
||||||
hub.event_source.config_entry = config_entry
|
hub.event_source.config_entry = config_entry
|
||||||
hub.api.config.host = hub.config.host
|
hub.api.config.host = hub.config.host
|
||||||
|
|
|
@ -11,10 +11,10 @@ from homeassistant.components.light import (
|
||||||
LightEntity,
|
LightEntity,
|
||||||
LightEntityDescription,
|
LightEntityDescription,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
|
from . import AxisConfigEntry
|
||||||
from .entity import TOPIC_TO_EVENT_TYPE, AxisEventDescription, AxisEventEntity
|
from .entity import TOPIC_TO_EVENT_TYPE, AxisEventDescription, AxisEventEntity
|
||||||
from .hub import AxisHub
|
from .hub import AxisHub
|
||||||
|
|
||||||
|
@ -45,11 +45,11 @@ ENTITY_DESCRIPTIONS = (
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config_entry: ConfigEntry,
|
config_entry: AxisConfigEntry,
|
||||||
async_add_entities: AddEntitiesCallback,
|
async_add_entities: AddEntitiesCallback,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up the Axis light platform."""
|
"""Set up the Axis light platform."""
|
||||||
AxisHub.get_hub(hass, config_entry).entity_loader.register_platform(
|
config_entry.runtime_data.entity_loader.register_platform(
|
||||||
async_add_entities, AxisLight, ENTITY_DESCRIPTIONS
|
async_add_entities, AxisLight, ENTITY_DESCRIPTIONS
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -10,11 +10,11 @@ from homeassistant.components.switch import (
|
||||||
SwitchEntity,
|
SwitchEntity,
|
||||||
SwitchEntityDescription,
|
SwitchEntityDescription,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
|
||||||
from homeassistant.const import EntityCategory
|
from homeassistant.const import EntityCategory
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
|
from . import AxisConfigEntry
|
||||||
from .entity import AxisEventDescription, AxisEventEntity
|
from .entity import AxisEventDescription, AxisEventEntity
|
||||||
from .hub import AxisHub
|
from .hub import AxisHub
|
||||||
|
|
||||||
|
@ -38,11 +38,11 @@ ENTITY_DESCRIPTIONS = (
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config_entry: ConfigEntry,
|
config_entry: AxisConfigEntry,
|
||||||
async_add_entities: AddEntitiesCallback,
|
async_add_entities: AddEntitiesCallback,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up the Axis switch platform."""
|
"""Set up the Axis switch platform."""
|
||||||
AxisHub.get_hub(hass, config_entry).entity_loader.register_platform(
|
config_entry.runtime_data.entity_loader.register_platform(
|
||||||
async_add_entities, AxisSwitch, ENTITY_DESCRIPTIONS
|
async_add_entities, AxisSwitch, ENTITY_DESCRIPTIONS
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ import pytest
|
||||||
|
|
||||||
from homeassistant.components import axis, zeroconf
|
from homeassistant.components import axis, zeroconf
|
||||||
from homeassistant.components.axis.const import DOMAIN as AXIS_DOMAIN
|
from homeassistant.components.axis.const import DOMAIN as AXIS_DOMAIN
|
||||||
from homeassistant.components.axis.hub import AxisHub
|
|
||||||
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
|
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
|
||||||
from homeassistant.config_entries import SOURCE_ZEROCONF
|
from homeassistant.config_entries import SOURCE_ZEROCONF
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
|
@ -52,7 +51,7 @@ async def test_device_setup(
|
||||||
device_registry: dr.DeviceRegistry,
|
device_registry: dr.DeviceRegistry,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Successful setup."""
|
"""Successful setup."""
|
||||||
hub = AxisHub.get_hub(hass, setup_config_entry)
|
hub = setup_config_entry.runtime_data
|
||||||
|
|
||||||
assert hub.api.vapix.firmware_version == "9.10.1"
|
assert hub.api.vapix.firmware_version == "9.10.1"
|
||||||
assert hub.api.vapix.product_number == "M1065-LW"
|
assert hub.api.vapix.product_number == "M1065-LW"
|
||||||
|
@ -78,7 +77,7 @@ async def test_device_setup(
|
||||||
@pytest.mark.parametrize("api_discovery_items", [API_DISCOVERY_BASIC_DEVICE_INFO])
|
@pytest.mark.parametrize("api_discovery_items", [API_DISCOVERY_BASIC_DEVICE_INFO])
|
||||||
async def test_device_info(hass: HomeAssistant, setup_config_entry) -> None:
|
async def test_device_info(hass: HomeAssistant, setup_config_entry) -> None:
|
||||||
"""Verify other path of device information works."""
|
"""Verify other path of device information works."""
|
||||||
hub = AxisHub.get_hub(hass, setup_config_entry)
|
hub = setup_config_entry.runtime_data
|
||||||
|
|
||||||
assert hub.api.vapix.firmware_version == "9.80.1"
|
assert hub.api.vapix.firmware_version == "9.80.1"
|
||||||
assert hub.api.vapix.product_number == "M1065-LW"
|
assert hub.api.vapix.product_number == "M1065-LW"
|
||||||
|
@ -124,30 +123,26 @@ async def test_update_address(
|
||||||
hass: HomeAssistant, setup_config_entry, mock_vapix_requests
|
hass: HomeAssistant, setup_config_entry, mock_vapix_requests
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test update address works."""
|
"""Test update address works."""
|
||||||
hub = AxisHub.get_hub(hass, setup_config_entry)
|
hub = setup_config_entry.runtime_data
|
||||||
assert hub.api.config.host == "1.2.3.4"
|
assert hub.api.config.host == "1.2.3.4"
|
||||||
|
|
||||||
with patch(
|
mock_vapix_requests("2.3.4.5")
|
||||||
"homeassistant.components.axis.async_setup_entry", return_value=True
|
await hass.config_entries.flow.async_init(
|
||||||
) as mock_setup_entry:
|
AXIS_DOMAIN,
|
||||||
mock_vapix_requests("2.3.4.5")
|
data=zeroconf.ZeroconfServiceInfo(
|
||||||
await hass.config_entries.flow.async_init(
|
ip_address=ip_address("2.3.4.5"),
|
||||||
AXIS_DOMAIN,
|
ip_addresses=[ip_address("2.3.4.5")],
|
||||||
data=zeroconf.ZeroconfServiceInfo(
|
hostname="mock_hostname",
|
||||||
ip_address=ip_address("2.3.4.5"),
|
name="name",
|
||||||
ip_addresses=[ip_address("2.3.4.5")],
|
port=80,
|
||||||
hostname="mock_hostname",
|
properties={"macaddress": MAC},
|
||||||
name="name",
|
type="mock_type",
|
||||||
port=80,
|
),
|
||||||
properties={"macaddress": MAC},
|
context={"source": SOURCE_ZEROCONF},
|
||||||
type="mock_type",
|
)
|
||||||
),
|
await hass.async_block_till_done()
|
||||||
context={"source": SOURCE_ZEROCONF},
|
|
||||||
)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert hub.api.config.host == "2.3.4.5"
|
assert hub.api.config.host == "2.3.4.5"
|
||||||
assert len(mock_setup_entry.mock_calls) == 1
|
|
||||||
|
|
||||||
|
|
||||||
async def test_device_unavailable(
|
async def test_device_unavailable(
|
||||||
|
|
Loading…
Add table
Reference in a new issue