mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Axis - Code improvements (#35592)
* Adapt library improvements Clean up integration and tests and make them more like latest changes in UniFi integration * Bump dependency to v26
This commit is contained in:
parent
cf50ccb919
commit
e6c58c9795
@ -2,19 +2,10 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import CONF_DEVICE, EVENT_HOMEASSISTANT_STOP
|
||||||
CONF_DEVICE,
|
|
||||||
CONF_HOST,
|
|
||||||
CONF_MAC,
|
|
||||||
CONF_PASSWORD,
|
|
||||||
CONF_PORT,
|
|
||||||
CONF_TRIGGER_TIME,
|
|
||||||
CONF_USERNAME,
|
|
||||||
EVENT_HOMEASSISTANT_STOP,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .const import CONF_CAMERA, CONF_EVENTS, DEFAULT_TRIGGER_TIME, DOMAIN
|
from .const import DOMAIN as AXIS_DOMAIN
|
||||||
from .device import AxisNetworkDevice, get_device
|
from .device import AxisNetworkDevice
|
||||||
|
|
||||||
LOGGER = logging.getLogger(__name__)
|
LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -26,11 +17,7 @@ async def async_setup(hass, config):
|
|||||||
|
|
||||||
async def async_setup_entry(hass, config_entry):
|
async def async_setup_entry(hass, config_entry):
|
||||||
"""Set up the Axis component."""
|
"""Set up the Axis component."""
|
||||||
if DOMAIN not in hass.data:
|
hass.data.setdefault(AXIS_DOMAIN, {})
|
||||||
hass.data[DOMAIN] = {}
|
|
||||||
|
|
||||||
if not config_entry.options:
|
|
||||||
await async_populate_options(hass, config_entry)
|
|
||||||
|
|
||||||
device = AxisNetworkDevice(hass, config_entry)
|
device = AxisNetworkDevice(hass, config_entry)
|
||||||
|
|
||||||
@ -43,7 +30,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][config_entry.unique_id] = device
|
hass.data[AXIS_DOMAIN][config_entry.unique_id] = device
|
||||||
|
|
||||||
await device.async_update_device_registry()
|
await device.async_update_device_registry()
|
||||||
|
|
||||||
@ -54,32 +41,10 @@ async def async_setup_entry(hass, config_entry):
|
|||||||
|
|
||||||
async def async_unload_entry(hass, config_entry):
|
async def async_unload_entry(hass, config_entry):
|
||||||
"""Unload Axis device config entry."""
|
"""Unload Axis device config entry."""
|
||||||
device = hass.data[DOMAIN].pop(config_entry.data[CONF_MAC])
|
device = hass.data[AXIS_DOMAIN].pop(config_entry.unique_id)
|
||||||
return await device.async_reset()
|
return await device.async_reset()
|
||||||
|
|
||||||
|
|
||||||
async def async_populate_options(hass, config_entry):
|
|
||||||
"""Populate default options for 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
|
|
||||||
camera = bool(supported_formats)
|
|
||||||
|
|
||||||
options = {
|
|
||||||
CONF_CAMERA: camera,
|
|
||||||
CONF_EVENTS: True,
|
|
||||||
CONF_TRIGGER_TIME: DEFAULT_TRIGGER_TIME,
|
|
||||||
}
|
|
||||||
|
|
||||||
hass.config_entries.async_update_entry(config_entry, options=options)
|
|
||||||
|
|
||||||
|
|
||||||
async def async_migrate_entry(hass, config_entry):
|
async def async_migrate_entry(hass, config_entry):
|
||||||
"""Migrate old entry."""
|
"""Migrate old entry."""
|
||||||
LOGGER.debug("Migrating from version %s", config_entry.version)
|
LOGGER.debug("Migrating from version %s", config_entry.version)
|
||||||
|
@ -18,7 +18,7 @@ class AxisEntityBase(Entity):
|
|||||||
"""Subscribe device events."""
|
"""Subscribe device events."""
|
||||||
self.async_on_remove(
|
self.async_on_remove(
|
||||||
async_dispatcher_connect(
|
async_dispatcher_connect(
|
||||||
self.hass, self.device.event_reachable, self.update_callback
|
self.hass, self.device.signal_reachable, self.update_callback
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -49,15 +49,12 @@ class AxisEventBase(AxisEntityBase):
|
|||||||
async def async_added_to_hass(self) -> None:
|
async def async_added_to_hass(self) -> None:
|
||||||
"""Subscribe sensors events."""
|
"""Subscribe sensors events."""
|
||||||
self.event.register_callback(self.update_callback)
|
self.event.register_callback(self.update_callback)
|
||||||
|
|
||||||
await super().async_added_to_hass()
|
await super().async_added_to_hass()
|
||||||
|
|
||||||
async def async_will_remove_from_hass(self) -> None:
|
async def async_will_remove_from_hass(self) -> None:
|
||||||
"""Disconnect device object when removed."""
|
"""Disconnect device object when removed."""
|
||||||
self.event.remove_callback(self.update_callback)
|
self.event.remove_callback(self.update_callback)
|
||||||
|
|
||||||
await super().async_will_remove_from_hass()
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_class(self):
|
def device_class(self):
|
||||||
"""Return the class of the event."""
|
"""Return the class of the event."""
|
||||||
|
@ -5,7 +5,6 @@ from datetime import timedelta
|
|||||||
from axis.event_stream import CLASS_INPUT, CLASS_OUTPUT
|
from axis.event_stream import CLASS_INPUT, CLASS_OUTPUT
|
||||||
|
|
||||||
from homeassistant.components.binary_sensor import BinarySensorEntity
|
from homeassistant.components.binary_sensor import BinarySensorEntity
|
||||||
from homeassistant.const import CONF_TRIGGER_TIME
|
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
from homeassistant.helpers.event import async_track_point_in_utc_time
|
from homeassistant.helpers.event import async_track_point_in_utc_time
|
||||||
@ -22,13 +21,13 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||||||
@callback
|
@callback
|
||||||
def async_add_sensor(event_id):
|
def async_add_sensor(event_id):
|
||||||
"""Add binary sensor from Axis device."""
|
"""Add binary sensor from Axis device."""
|
||||||
event = device.api.event.events[event_id]
|
event = device.api.event[event_id]
|
||||||
|
|
||||||
if event.CLASS != CLASS_OUTPUT:
|
if event.CLASS != CLASS_OUTPUT:
|
||||||
async_add_entities([AxisBinarySensor(event, device)], True)
|
async_add_entities([AxisBinarySensor(event, device)], True)
|
||||||
|
|
||||||
device.listeners.append(
|
device.listeners.append(
|
||||||
async_dispatcher_connect(hass, device.event_new_sensor, async_add_sensor)
|
async_dispatcher_connect(hass, device.signal_new_event, async_add_sensor)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -38,7 +37,7 @@ class AxisBinarySensor(AxisEventBase, BinarySensorEntity):
|
|||||||
def __init__(self, event, device):
|
def __init__(self, event, device):
|
||||||
"""Initialize the Axis binary sensor."""
|
"""Initialize the Axis binary sensor."""
|
||||||
super().__init__(event, device)
|
super().__init__(event, device)
|
||||||
self.remove_timer = None
|
self.cancel_scheduled_update = None
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def update_callback(self, no_delay=False):
|
def update_callback(self, no_delay=False):
|
||||||
@ -46,24 +45,25 @@ class AxisBinarySensor(AxisEventBase, BinarySensorEntity):
|
|||||||
|
|
||||||
Parameter no_delay is True when device_event_reachable is sent.
|
Parameter no_delay is True when device_event_reachable is sent.
|
||||||
"""
|
"""
|
||||||
delay = self.device.config_entry.options[CONF_TRIGGER_TIME]
|
|
||||||
|
|
||||||
if self.remove_timer is not None:
|
@callback
|
||||||
self.remove_timer()
|
def scheduled_update(now):
|
||||||
self.remove_timer = None
|
"""Timer callback for sensor update."""
|
||||||
|
self.cancel_scheduled_update = None
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
||||||
if self.is_on or delay == 0 or no_delay:
|
if self.cancel_scheduled_update is not None:
|
||||||
|
self.cancel_scheduled_update()
|
||||||
|
self.cancel_scheduled_update = None
|
||||||
|
|
||||||
|
if self.is_on or self.device.option_trigger_time == 0 or no_delay:
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
return
|
return
|
||||||
|
|
||||||
@callback
|
self.cancel_scheduled_update = async_track_point_in_utc_time(
|
||||||
def _delay_update(now):
|
self.hass,
|
||||||
"""Timer callback for sensor update."""
|
scheduled_update,
|
||||||
self.async_write_ha_state()
|
utcnow() + timedelta(seconds=self.device.option_trigger_time),
|
||||||
self.remove_timer = None
|
|
||||||
|
|
||||||
self.remove_timer = async_track_point_in_utc_time(
|
|
||||||
self.hass, _delay_update, utcnow() + timedelta(seconds=delay)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -59,7 +59,7 @@ class AxisCamera(AxisEntityBase, MjpegCamera):
|
|||||||
"""Subscribe camera events."""
|
"""Subscribe camera events."""
|
||||||
self.async_on_remove(
|
self.async_on_remove(
|
||||||
async_dispatcher_connect(
|
async_dispatcher_connect(
|
||||||
self.hass, self.device.event_new_address, self._new_address
|
self.hass, self.device.signal_new_address, self._new_address
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -5,8 +5,11 @@ LOGGER = logging.getLogger(__package__)
|
|||||||
|
|
||||||
DOMAIN = "axis"
|
DOMAIN = "axis"
|
||||||
|
|
||||||
|
ATTR_MANUFACTURER = "Axis Communications AB"
|
||||||
|
|
||||||
CONF_CAMERA = "camera"
|
CONF_CAMERA = "camera"
|
||||||
CONF_EVENTS = "events"
|
CONF_EVENTS = "events"
|
||||||
CONF_MODEL = "model"
|
CONF_MODEL = "model"
|
||||||
|
|
||||||
|
DEFAULT_EVENTS = True
|
||||||
DEFAULT_TRIGGER_TIME = 0
|
DEFAULT_TRIGGER_TIME = 0
|
||||||
|
@ -4,13 +4,18 @@ import asyncio
|
|||||||
|
|
||||||
import async_timeout
|
import async_timeout
|
||||||
import axis
|
import axis
|
||||||
|
from axis.event_stream import OPERATION_INITIALIZED
|
||||||
from axis.streammanager import SIGNAL_PLAYING
|
from axis.streammanager import SIGNAL_PLAYING
|
||||||
|
|
||||||
|
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
|
||||||
|
from homeassistant.components.camera import DOMAIN as CAMERA_DOMAIN
|
||||||
|
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_HOST,
|
CONF_HOST,
|
||||||
CONF_NAME,
|
CONF_NAME,
|
||||||
CONF_PASSWORD,
|
CONF_PASSWORD,
|
||||||
CONF_PORT,
|
CONF_PORT,
|
||||||
|
CONF_TRIGGER_TIME,
|
||||||
CONF_USERNAME,
|
CONF_USERNAME,
|
||||||
)
|
)
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
@ -18,7 +23,16 @@ from homeassistant.exceptions import ConfigEntryNotReady
|
|||||||
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
|
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||||
|
|
||||||
from .const import CONF_CAMERA, CONF_EVENTS, CONF_MODEL, DOMAIN, LOGGER
|
from .const import (
|
||||||
|
ATTR_MANUFACTURER,
|
||||||
|
CONF_CAMERA,
|
||||||
|
CONF_EVENTS,
|
||||||
|
CONF_MODEL,
|
||||||
|
DEFAULT_EVENTS,
|
||||||
|
DEFAULT_TRIGGER_TIME,
|
||||||
|
DOMAIN as AXIS_DOMAIN,
|
||||||
|
LOGGER,
|
||||||
|
)
|
||||||
from .errors import AuthenticationRequired, CannotConnect
|
from .errors import AuthenticationRequired, CannotConnect
|
||||||
|
|
||||||
|
|
||||||
@ -57,14 +71,74 @@ class AxisNetworkDevice:
|
|||||||
"""Return the serial number of this device."""
|
"""Return the serial number of this device."""
|
||||||
return self.config_entry.unique_id
|
return self.config_entry.unique_id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def option_camera(self):
|
||||||
|
"""Config entry option defining if camera should be used."""
|
||||||
|
supported_formats = self.api.vapix.params.image_format
|
||||||
|
return self.config_entry.options.get(CONF_CAMERA, bool(supported_formats))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def option_events(self):
|
||||||
|
"""Config entry option defining if platforms based on events should be created."""
|
||||||
|
return self.config_entry.options.get(CONF_EVENTS, DEFAULT_EVENTS)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def option_trigger_time(self):
|
||||||
|
"""Config entry option defining minimum number of seconds to keep trigger high."""
|
||||||
|
return self.config_entry.options.get(CONF_TRIGGER_TIME, DEFAULT_TRIGGER_TIME)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def signal_reachable(self):
|
||||||
|
"""Device specific event to signal a change in connection status."""
|
||||||
|
return f"axis_reachable_{self.serial}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def signal_new_event(self):
|
||||||
|
"""Device specific event to signal new device event available."""
|
||||||
|
return f"axis_new_event_{self.serial}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def signal_new_address(self):
|
||||||
|
"""Device specific event to signal a change in device address."""
|
||||||
|
return f"axis_new_address_{self.serial}"
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def async_connection_status_callback(self, status):
|
||||||
|
"""Handle signals of device connection status.
|
||||||
|
|
||||||
|
This is called on every RTSP keep-alive message.
|
||||||
|
Only signal state change if state change is true.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if self.available != (status == SIGNAL_PLAYING):
|
||||||
|
self.available = not self.available
|
||||||
|
async_dispatcher_send(self.hass, self.signal_reachable, True)
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def async_event_callback(self, action, event_id):
|
||||||
|
"""Call to configure events when initialized on event stream."""
|
||||||
|
if action == OPERATION_INITIALIZED:
|
||||||
|
async_dispatcher_send(self.hass, self.signal_new_event, event_id)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
async def async_new_address_callback(hass, entry):
|
||||||
|
"""Handle signals of device getting new address.
|
||||||
|
|
||||||
|
This is a static method because a class method (bound method),
|
||||||
|
can not be used with weak references.
|
||||||
|
"""
|
||||||
|
device = hass.data[AXIS_DOMAIN][entry.unique_id]
|
||||||
|
device.api.config.host = device.host
|
||||||
|
async_dispatcher_send(hass, device.signal_new_address)
|
||||||
|
|
||||||
async def async_update_device_registry(self):
|
async def async_update_device_registry(self):
|
||||||
"""Update device registry."""
|
"""Update device registry."""
|
||||||
device_registry = await self.hass.helpers.device_registry.async_get_registry()
|
device_registry = await self.hass.helpers.device_registry.async_get_registry()
|
||||||
device_registry.async_get_or_create(
|
device_registry.async_get_or_create(
|
||||||
config_entry_id=self.config_entry.entry_id,
|
config_entry_id=self.config_entry.entry_id,
|
||||||
connections={(CONNECTION_NETWORK_MAC, self.serial)},
|
connections={(CONNECTION_NETWORK_MAC, self.serial)},
|
||||||
identifiers={(DOMAIN, self.serial)},
|
identifiers={(AXIS_DOMAIN, self.serial)},
|
||||||
manufacturer="Axis Communications AB",
|
manufacturer=ATTR_MANUFACTURER,
|
||||||
model=f"{self.model} {self.product_type}",
|
model=f"{self.model} {self.product_type}",
|
||||||
name=self.name,
|
name=self.name,
|
||||||
sw_version=self.fw_version,
|
sw_version=self.fw_version,
|
||||||
@ -91,15 +165,15 @@ class AxisNetworkDevice:
|
|||||||
self.fw_version = self.api.vapix.params.firmware_version
|
self.fw_version = self.api.vapix.params.firmware_version
|
||||||
self.product_type = self.api.vapix.params.prodtype
|
self.product_type = self.api.vapix.params.prodtype
|
||||||
|
|
||||||
if self.config_entry.options[CONF_CAMERA]:
|
if self.option_camera:
|
||||||
|
|
||||||
self.hass.async_create_task(
|
self.hass.async_create_task(
|
||||||
self.hass.config_entries.async_forward_entry_setup(
|
self.hass.config_entries.async_forward_entry_setup(
|
||||||
self.config_entry, "camera"
|
self.config_entry, CAMERA_DOMAIN
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.config_entry.options[CONF_EVENTS]:
|
if self.option_events:
|
||||||
|
|
||||||
self.api.stream.connection_status_callback = (
|
self.api.stream.connection_status_callback = (
|
||||||
self.async_connection_status_callback
|
self.async_connection_status_callback
|
||||||
@ -110,7 +184,7 @@ class AxisNetworkDevice:
|
|||||||
self.hass.config_entries.async_forward_entry_setup(
|
self.hass.config_entries.async_forward_entry_setup(
|
||||||
self.config_entry, platform
|
self.config_entry, platform
|
||||||
)
|
)
|
||||||
for platform in ["binary_sensor", "switch"]
|
for platform in [BINARY_SENSOR_DOMAIN, SWITCH_DOMAIN]
|
||||||
]
|
]
|
||||||
self.hass.async_create_task(self.start(platform_tasks))
|
self.hass.async_create_task(self.start(platform_tasks))
|
||||||
|
|
||||||
@ -118,50 +192,6 @@ class AxisNetworkDevice:
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@property
|
|
||||||
def event_new_address(self):
|
|
||||||
"""Device specific event to signal new device address."""
|
|
||||||
return f"axis_new_address_{self.serial}"
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
async def async_new_address_callback(hass, entry):
|
|
||||||
"""Handle signals of device getting new address.
|
|
||||||
|
|
||||||
This is a static method because a class method (bound method),
|
|
||||||
can not be used with weak references.
|
|
||||||
"""
|
|
||||||
device = hass.data[DOMAIN][entry.unique_id]
|
|
||||||
device.api.config.host = device.host
|
|
||||||
async_dispatcher_send(hass, device.event_new_address)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def event_reachable(self):
|
|
||||||
"""Device specific event to signal a change in connection status."""
|
|
||||||
return f"axis_reachable_{self.serial}"
|
|
||||||
|
|
||||||
@callback
|
|
||||||
def async_connection_status_callback(self, status):
|
|
||||||
"""Handle signals of device connection status.
|
|
||||||
|
|
||||||
This is called on every RTSP keep-alive message.
|
|
||||||
Only signal state change if state change is true.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if self.available != (status == SIGNAL_PLAYING):
|
|
||||||
self.available = not self.available
|
|
||||||
async_dispatcher_send(self.hass, self.event_reachable, True)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def event_new_sensor(self):
|
|
||||||
"""Device specific event to signal new sensor available."""
|
|
||||||
return f"axis_add_sensor_{self.serial}"
|
|
||||||
|
|
||||||
@callback
|
|
||||||
def async_event_callback(self, action, event_id):
|
|
||||||
"""Call to configure events when initialized on event stream."""
|
|
||||||
if action == "add":
|
|
||||||
async_dispatcher_send(self.hass, self.event_new_sensor, event_id)
|
|
||||||
|
|
||||||
async def start(self, platform_tasks):
|
async def start(self, platform_tasks):
|
||||||
"""Start the event stream when all platforms are loaded."""
|
"""Start the event stream when all platforms are loaded."""
|
||||||
await asyncio.gather(*platform_tasks)
|
await asyncio.gather(*platform_tasks)
|
||||||
@ -179,7 +209,7 @@ class AxisNetworkDevice:
|
|||||||
if self.config_entry.options[CONF_CAMERA]:
|
if self.config_entry.options[CONF_CAMERA]:
|
||||||
platform_tasks.append(
|
platform_tasks.append(
|
||||||
self.hass.config_entries.async_forward_entry_unload(
|
self.hass.config_entries.async_forward_entry_unload(
|
||||||
self.config_entry, "camera"
|
self.config_entry, CAMERA_DOMAIN
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -189,7 +219,7 @@ class AxisNetworkDevice:
|
|||||||
self.hass.config_entries.async_forward_entry_unload(
|
self.hass.config_entries.async_forward_entry_unload(
|
||||||
self.config_entry, platform
|
self.config_entry, platform
|
||||||
)
|
)
|
||||||
for platform in ["binary_sensor", "switch"]
|
for platform in [BINARY_SENSOR_DOMAIN, SWITCH_DOMAIN]
|
||||||
]
|
]
|
||||||
|
|
||||||
await asyncio.gather(*platform_tasks)
|
await asyncio.gather(*platform_tasks)
|
||||||
@ -205,12 +235,7 @@ 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,
|
host=host, port=port, username=username, password=password, web_proto="http",
|
||||||
host=host,
|
|
||||||
port=port,
|
|
||||||
username=username,
|
|
||||||
password=password,
|
|
||||||
web_proto="http",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
device.vapix.initialize_params(preload_data=False)
|
device.vapix.initialize_params(preload_data=False)
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"name": "Axis",
|
"name": "Axis",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/axis",
|
"documentation": "https://www.home-assistant.io/integrations/axis",
|
||||||
"requirements": ["axis==25"],
|
"requirements": ["axis==26"],
|
||||||
"zeroconf": ["_axis-video._tcp.local."],
|
"zeroconf": ["_axis-video._tcp.local."],
|
||||||
"codeowners": ["@Kane610"]
|
"codeowners": ["@Kane610"]
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
"""Support for Axis switches."""
|
"""Support for Axis switches."""
|
||||||
|
|
||||||
from axis.event_stream import CLASS_OUTPUT
|
from axis.event_stream import CLASS_OUTPUT
|
||||||
|
from axis.port_cgi import ACTION_HIGH, ACTION_LOW
|
||||||
|
|
||||||
from homeassistant.components.switch import SwitchEntity
|
from homeassistant.components.switch import SwitchEntity
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
@ -17,13 +18,13 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||||||
@callback
|
@callback
|
||||||
def async_add_switch(event_id):
|
def async_add_switch(event_id):
|
||||||
"""Add switch from Axis device."""
|
"""Add switch from Axis device."""
|
||||||
event = device.api.event.events[event_id]
|
event = device.api.event[event_id]
|
||||||
|
|
||||||
if event.CLASS == CLASS_OUTPUT:
|
if event.CLASS == CLASS_OUTPUT:
|
||||||
async_add_entities([AxisSwitch(event, device)], True)
|
async_add_entities([AxisSwitch(event, device)], True)
|
||||||
|
|
||||||
device.listeners.append(
|
device.listeners.append(
|
||||||
async_dispatcher_connect(hass, device.event_new_sensor, async_add_switch)
|
async_dispatcher_connect(hass, device.signal_new_event, async_add_switch)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -37,16 +38,14 @@ class AxisSwitch(AxisEventBase, SwitchEntity):
|
|||||||
|
|
||||||
async def async_turn_on(self, **kwargs):
|
async def async_turn_on(self, **kwargs):
|
||||||
"""Turn on switch."""
|
"""Turn on switch."""
|
||||||
action = "/"
|
|
||||||
await self.hass.async_add_executor_job(
|
await self.hass.async_add_executor_job(
|
||||||
self.device.api.vapix.ports[self.event.id].action, action
|
self.device.api.vapix.ports[self.event.id].action, ACTION_HIGH
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_turn_off(self, **kwargs):
|
async def async_turn_off(self, **kwargs):
|
||||||
"""Turn off switch."""
|
"""Turn off switch."""
|
||||||
action = "\\"
|
|
||||||
await self.hass.async_add_executor_job(
|
await self.hass.async_add_executor_job(
|
||||||
self.device.api.vapix.ports[self.event.id].action, action
|
self.device.api.vapix.ports[self.event.id].action, ACTION_LOW
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -303,7 +303,7 @@ avea==1.4
|
|||||||
avri-api==0.1.7
|
avri-api==0.1.7
|
||||||
|
|
||||||
# homeassistant.components.axis
|
# homeassistant.components.axis
|
||||||
axis==25
|
axis==26
|
||||||
|
|
||||||
# homeassistant.components.azure_event_hub
|
# homeassistant.components.azure_event_hub
|
||||||
azure-eventhub==1.3.1
|
azure-eventhub==1.3.1
|
||||||
|
@ -141,7 +141,7 @@ async-upnp-client==0.14.13
|
|||||||
av==7.0.1
|
av==7.0.1
|
||||||
|
|
||||||
# homeassistant.components.axis
|
# homeassistant.components.axis
|
||||||
axis==25
|
axis==26
|
||||||
|
|
||||||
# homeassistant.components.homekit
|
# homeassistant.components.homekit
|
||||||
base36==0.1.1
|
base36==0.1.1
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
"""Axis binary sensor platform tests."""
|
"""Axis binary sensor platform tests."""
|
||||||
|
|
||||||
from homeassistant.components import axis
|
from homeassistant.components.axis.const import DOMAIN as AXIS_DOMAIN
|
||||||
import homeassistant.components.binary_sensor as binary_sensor
|
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
from .test_device import NAME, setup_axis_integration
|
from .test_device import NAME, setup_axis_integration
|
||||||
@ -28,19 +28,21 @@ async def test_platform_manually_configured(hass):
|
|||||||
"""Test that nothing happens when platform is manually configured."""
|
"""Test that nothing happens when platform is manually configured."""
|
||||||
assert (
|
assert (
|
||||||
await async_setup_component(
|
await async_setup_component(
|
||||||
hass, binary_sensor.DOMAIN, {"binary_sensor": {"platform": axis.DOMAIN}}
|
hass,
|
||||||
|
BINARY_SENSOR_DOMAIN,
|
||||||
|
{BINARY_SENSOR_DOMAIN: {"platform": AXIS_DOMAIN}},
|
||||||
)
|
)
|
||||||
is True
|
is True
|
||||||
)
|
)
|
||||||
|
|
||||||
assert axis.DOMAIN not in hass.data
|
assert AXIS_DOMAIN not in hass.data
|
||||||
|
|
||||||
|
|
||||||
async def test_no_binary_sensors(hass):
|
async def test_no_binary_sensors(hass):
|
||||||
"""Test that no sensors in Axis results in no sensor entities."""
|
"""Test that no sensors in Axis results in no sensor entities."""
|
||||||
await setup_axis_integration(hass)
|
await setup_axis_integration(hass)
|
||||||
|
|
||||||
assert not hass.states.async_entity_ids("binary_sensor")
|
assert not hass.states.async_entity_ids(BINARY_SENSOR_DOMAIN)
|
||||||
|
|
||||||
|
|
||||||
async def test_binary_sensors(hass):
|
async def test_binary_sensors(hass):
|
||||||
@ -48,10 +50,10 @@ async def test_binary_sensors(hass):
|
|||||||
device = await setup_axis_integration(hass)
|
device = await setup_axis_integration(hass)
|
||||||
|
|
||||||
for event in EVENTS:
|
for event in EVENTS:
|
||||||
device.api.stream.event.manage_event(event)
|
device.api.event.process_event(event)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert len(hass.states.async_entity_ids("binary_sensor")) == 2
|
assert len(hass.states.async_entity_ids(BINARY_SENSOR_DOMAIN)) == 2
|
||||||
|
|
||||||
pir = hass.states.get(f"binary_sensor.{NAME}_pir_0")
|
pir = hass.states.get(f"binary_sensor.{NAME}_pir_0")
|
||||||
assert pir.state == "off"
|
assert pir.state == "off"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
"""Axis camera platform tests."""
|
"""Axis camera platform tests."""
|
||||||
|
|
||||||
from homeassistant.components import axis
|
from homeassistant.components.axis.const import DOMAIN as AXIS_DOMAIN
|
||||||
import homeassistant.components.camera as camera
|
from homeassistant.components.camera import DOMAIN as CAMERA_DOMAIN
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
from .test_device import NAME, setup_axis_integration
|
from .test_device import NAME, setup_axis_integration
|
||||||
@ -11,19 +11,19 @@ async def test_platform_manually_configured(hass):
|
|||||||
"""Test that nothing happens when platform is manually configured."""
|
"""Test that nothing happens when platform is manually configured."""
|
||||||
assert (
|
assert (
|
||||||
await async_setup_component(
|
await async_setup_component(
|
||||||
hass, camera.DOMAIN, {"camera": {"platform": axis.DOMAIN}}
|
hass, CAMERA_DOMAIN, {"camera": {"platform": AXIS_DOMAIN}}
|
||||||
)
|
)
|
||||||
is True
|
is True
|
||||||
)
|
)
|
||||||
|
|
||||||
assert axis.DOMAIN not in hass.data
|
assert AXIS_DOMAIN not in hass.data
|
||||||
|
|
||||||
|
|
||||||
async def test_camera(hass):
|
async def test_camera(hass):
|
||||||
"""Test that Axis camera platform is loaded properly."""
|
"""Test that Axis camera platform is loaded properly."""
|
||||||
await setup_axis_integration(hass)
|
await setup_axis_integration(hass)
|
||||||
|
|
||||||
assert len(hass.states.async_entity_ids("camera")) == 1
|
assert len(hass.states.async_entity_ids(CAMERA_DOMAIN)) == 1
|
||||||
|
|
||||||
cam = hass.states.get(f"camera.{NAME}")
|
cam = hass.states.get(f"camera.{NAME}")
|
||||||
assert cam.state == "idle"
|
assert cam.state == "idle"
|
||||||
|
@ -1,6 +1,15 @@
|
|||||||
"""Test Axis config flow."""
|
"""Test Axis config flow."""
|
||||||
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 homeassistant.components.axis.const import CONF_MODEL, DOMAIN as AXIS_DOMAIN
|
||||||
|
from homeassistant.const import (
|
||||||
|
CONF_HOST,
|
||||||
|
CONF_MAC,
|
||||||
|
CONF_NAME,
|
||||||
|
CONF_PASSWORD,
|
||||||
|
CONF_PORT,
|
||||||
|
CONF_USERNAME,
|
||||||
|
)
|
||||||
|
|
||||||
from .test_device import MAC, MODEL, NAME, setup_axis_integration
|
from .test_device import MAC, MODEL, NAME, setup_axis_integration
|
||||||
|
|
||||||
@ -11,9 +20,8 @@ from tests.common import MockConfigEntry
|
|||||||
def setup_mock_axis_device(mock_device):
|
def setup_mock_axis_device(mock_device):
|
||||||
"""Prepare mock axis device."""
|
"""Prepare mock axis device."""
|
||||||
|
|
||||||
def mock_constructor(loop, host, username, password, port, web_proto):
|
def mock_constructor(host, username, password, port, web_proto):
|
||||||
"""Fake the controller constructor."""
|
"""Fake the controller constructor."""
|
||||||
mock_device.loop = loop
|
|
||||||
mock_device.host = host
|
mock_device.host = host
|
||||||
mock_device.username = username
|
mock_device.username = username
|
||||||
mock_device.password = password
|
mock_device.password = password
|
||||||
@ -30,7 +38,7 @@ def setup_mock_axis_device(mock_device):
|
|||||||
async def test_flow_manual_configuration(hass):
|
async def test_flow_manual_configuration(hass):
|
||||||
"""Test that config flow works."""
|
"""Test that config flow works."""
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
config_flow.DOMAIN, context={"source": "user"}
|
AXIS_DOMAIN, context={"source": "user"}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
@ -43,23 +51,23 @@ async def test_flow_manual_configuration(hass):
|
|||||||
result = await hass.config_entries.flow.async_configure(
|
result = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
user_input={
|
user_input={
|
||||||
config_flow.CONF_HOST: "1.2.3.4",
|
CONF_HOST: "1.2.3.4",
|
||||||
config_flow.CONF_USERNAME: "user",
|
CONF_USERNAME: "user",
|
||||||
config_flow.CONF_PASSWORD: "pass",
|
CONF_PASSWORD: "pass",
|
||||||
config_flow.CONF_PORT: 80,
|
CONF_PORT: 80,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
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"] == {
|
||||||
config_flow.CONF_HOST: "1.2.3.4",
|
CONF_HOST: "1.2.3.4",
|
||||||
config_flow.CONF_USERNAME: "user",
|
CONF_USERNAME: "user",
|
||||||
config_flow.CONF_PASSWORD: "pass",
|
CONF_PASSWORD: "pass",
|
||||||
config_flow.CONF_PORT: 80,
|
CONF_PORT: 80,
|
||||||
config_flow.CONF_MAC: MAC,
|
CONF_MAC: MAC,
|
||||||
config_flow.CONF_MODEL: "prodnbr",
|
CONF_MODEL: "prodnbr",
|
||||||
config_flow.CONF_NAME: "prodnbr 0",
|
CONF_NAME: "prodnbr 0",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -68,7 +76,7 @@ async def test_manual_configuration_update_configuration(hass):
|
|||||||
device = await setup_axis_integration(hass)
|
device = await setup_axis_integration(hass)
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
config_flow.DOMAIN, context={"source": "user"}
|
AXIS_DOMAIN, context={"source": "user"}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
@ -84,16 +92,16 @@ async def test_manual_configuration_update_configuration(hass):
|
|||||||
result = await hass.config_entries.flow.async_configure(
|
result = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
user_input={
|
user_input={
|
||||||
config_flow.CONF_HOST: "2.3.4.5",
|
CONF_HOST: "2.3.4.5",
|
||||||
config_flow.CONF_USERNAME: "user",
|
CONF_USERNAME: "user",
|
||||||
config_flow.CONF_PASSWORD: "pass",
|
CONF_PASSWORD: "pass",
|
||||||
config_flow.CONF_PORT: 80,
|
CONF_PORT: 80,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "abort"
|
assert result["type"] == "abort"
|
||||||
assert result["reason"] == "already_configured"
|
assert result["reason"] == "already_configured"
|
||||||
assert device.config_entry.data[config_flow.CONF_HOST] == "2.3.4.5"
|
assert device.host == "2.3.4.5"
|
||||||
|
|
||||||
|
|
||||||
async def test_flow_fails_already_configured(hass):
|
async def test_flow_fails_already_configured(hass):
|
||||||
@ -101,7 +109,7 @@ async def test_flow_fails_already_configured(hass):
|
|||||||
await setup_axis_integration(hass)
|
await setup_axis_integration(hass)
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
config_flow.DOMAIN, context={"source": "user"}
|
AXIS_DOMAIN, context={"source": "user"}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
@ -117,10 +125,10 @@ async def test_flow_fails_already_configured(hass):
|
|||||||
result = await hass.config_entries.flow.async_configure(
|
result = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
user_input={
|
user_input={
|
||||||
config_flow.CONF_HOST: "1.2.3.4",
|
CONF_HOST: "1.2.3.4",
|
||||||
config_flow.CONF_USERNAME: "user",
|
CONF_USERNAME: "user",
|
||||||
config_flow.CONF_PASSWORD: "pass",
|
CONF_PASSWORD: "pass",
|
||||||
config_flow.CONF_PORT: 80,
|
CONF_PORT: 80,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -131,7 +139,7 @@ async def test_flow_fails_already_configured(hass):
|
|||||||
async def test_flow_fails_faulty_credentials(hass):
|
async def test_flow_fails_faulty_credentials(hass):
|
||||||
"""Test that config flow fails on faulty credentials."""
|
"""Test that config flow fails on faulty credentials."""
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
config_flow.DOMAIN, context={"source": "user"}
|
AXIS_DOMAIN, context={"source": "user"}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
@ -144,10 +152,10 @@ async def test_flow_fails_faulty_credentials(hass):
|
|||||||
result = await hass.config_entries.flow.async_configure(
|
result = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
user_input={
|
user_input={
|
||||||
config_flow.CONF_HOST: "1.2.3.4",
|
CONF_HOST: "1.2.3.4",
|
||||||
config_flow.CONF_USERNAME: "user",
|
CONF_USERNAME: "user",
|
||||||
config_flow.CONF_PASSWORD: "pass",
|
CONF_PASSWORD: "pass",
|
||||||
config_flow.CONF_PORT: 80,
|
CONF_PORT: 80,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -157,7 +165,7 @@ async def test_flow_fails_faulty_credentials(hass):
|
|||||||
async def test_flow_fails_device_unavailable(hass):
|
async def test_flow_fails_device_unavailable(hass):
|
||||||
"""Test that config flow fails on device unavailable."""
|
"""Test that config flow fails on device unavailable."""
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
config_flow.DOMAIN, context={"source": "user"}
|
AXIS_DOMAIN, context={"source": "user"}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
@ -170,10 +178,10 @@ async def test_flow_fails_device_unavailable(hass):
|
|||||||
result = await hass.config_entries.flow.async_configure(
|
result = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
user_input={
|
user_input={
|
||||||
config_flow.CONF_HOST: "1.2.3.4",
|
CONF_HOST: "1.2.3.4",
|
||||||
config_flow.CONF_USERNAME: "user",
|
CONF_USERNAME: "user",
|
||||||
config_flow.CONF_PASSWORD: "pass",
|
CONF_PASSWORD: "pass",
|
||||||
config_flow.CONF_PORT: 80,
|
CONF_PORT: 80,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -183,18 +191,16 @@ async def test_flow_fails_device_unavailable(hass):
|
|||||||
async def test_flow_create_entry_multiple_existing_entries_of_same_model(hass):
|
async def test_flow_create_entry_multiple_existing_entries_of_same_model(hass):
|
||||||
"""Test that create entry can generate a name with other entries."""
|
"""Test that create entry can generate a name with other entries."""
|
||||||
entry = MockConfigEntry(
|
entry = MockConfigEntry(
|
||||||
domain=axis.DOMAIN,
|
domain=AXIS_DOMAIN, data={CONF_NAME: "prodnbr 0", CONF_MODEL: "prodnbr"},
|
||||||
data={config_flow.CONF_NAME: "prodnbr 0", config_flow.CONF_MODEL: "prodnbr"},
|
|
||||||
)
|
)
|
||||||
entry.add_to_hass(hass)
|
entry.add_to_hass(hass)
|
||||||
entry2 = MockConfigEntry(
|
entry2 = MockConfigEntry(
|
||||||
domain=axis.DOMAIN,
|
domain=AXIS_DOMAIN, data={CONF_NAME: "prodnbr 1", CONF_MODEL: "prodnbr"},
|
||||||
data={config_flow.CONF_NAME: "prodnbr 1", config_flow.CONF_MODEL: "prodnbr"},
|
|
||||||
)
|
)
|
||||||
entry2.add_to_hass(hass)
|
entry2.add_to_hass(hass)
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
config_flow.DOMAIN, context={"source": "user"}
|
AXIS_DOMAIN, context={"source": "user"}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
@ -207,36 +213,36 @@ async def test_flow_create_entry_multiple_existing_entries_of_same_model(hass):
|
|||||||
result = await hass.config_entries.flow.async_configure(
|
result = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
user_input={
|
user_input={
|
||||||
config_flow.CONF_HOST: "1.2.3.4",
|
CONF_HOST: "1.2.3.4",
|
||||||
config_flow.CONF_USERNAME: "user",
|
CONF_USERNAME: "user",
|
||||||
config_flow.CONF_PASSWORD: "pass",
|
CONF_PASSWORD: "pass",
|
||||||
config_flow.CONF_PORT: 80,
|
CONF_PORT: 80,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
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"] == {
|
||||||
config_flow.CONF_HOST: "1.2.3.4",
|
CONF_HOST: "1.2.3.4",
|
||||||
config_flow.CONF_USERNAME: "user",
|
CONF_USERNAME: "user",
|
||||||
config_flow.CONF_PASSWORD: "pass",
|
CONF_PASSWORD: "pass",
|
||||||
config_flow.CONF_PORT: 80,
|
CONF_PORT: 80,
|
||||||
config_flow.CONF_MAC: MAC,
|
CONF_MAC: MAC,
|
||||||
config_flow.CONF_MODEL: "prodnbr",
|
CONF_MODEL: "prodnbr",
|
||||||
config_flow.CONF_NAME: "prodnbr 2",
|
CONF_NAME: "prodnbr 2",
|
||||||
}
|
}
|
||||||
|
|
||||||
assert result["data"][config_flow.CONF_NAME] == "prodnbr 2"
|
assert result["data"][CONF_NAME] == "prodnbr 2"
|
||||||
|
|
||||||
|
|
||||||
async def test_zeroconf_flow(hass):
|
async def test_zeroconf_flow(hass):
|
||||||
"""Test that zeroconf discovery for new devices work."""
|
"""Test that zeroconf discovery for new devices work."""
|
||||||
with patch.object(axis, "get_device", return_value=Mock()):
|
with patch.object(axis.device, "get_device", return_value=Mock()):
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
config_flow.DOMAIN,
|
AXIS_DOMAIN,
|
||||||
data={
|
data={
|
||||||
config_flow.CONF_HOST: "1.2.3.4",
|
CONF_HOST: "1.2.3.4",
|
||||||
config_flow.CONF_PORT: 80,
|
CONF_PORT: 80,
|
||||||
"hostname": "name",
|
"hostname": "name",
|
||||||
"properties": {"macaddress": MAC},
|
"properties": {"macaddress": MAC},
|
||||||
},
|
},
|
||||||
@ -253,26 +259,26 @@ async def test_zeroconf_flow(hass):
|
|||||||
result = await hass.config_entries.flow.async_configure(
|
result = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
user_input={
|
user_input={
|
||||||
config_flow.CONF_HOST: "1.2.3.4",
|
CONF_HOST: "1.2.3.4",
|
||||||
config_flow.CONF_USERNAME: "user",
|
CONF_USERNAME: "user",
|
||||||
config_flow.CONF_PASSWORD: "pass",
|
CONF_PASSWORD: "pass",
|
||||||
config_flow.CONF_PORT: 80,
|
CONF_PORT: 80,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
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"] == {
|
||||||
config_flow.CONF_HOST: "1.2.3.4",
|
CONF_HOST: "1.2.3.4",
|
||||||
config_flow.CONF_USERNAME: "user",
|
CONF_USERNAME: "user",
|
||||||
config_flow.CONF_PASSWORD: "pass",
|
CONF_PASSWORD: "pass",
|
||||||
config_flow.CONF_PORT: 80,
|
CONF_PORT: 80,
|
||||||
config_flow.CONF_MAC: MAC,
|
CONF_MAC: MAC,
|
||||||
config_flow.CONF_MODEL: "prodnbr",
|
CONF_MODEL: "prodnbr",
|
||||||
config_flow.CONF_NAME: "prodnbr 0",
|
CONF_NAME: "prodnbr 0",
|
||||||
}
|
}
|
||||||
|
|
||||||
assert result["data"][config_flow.CONF_NAME] == "prodnbr 0"
|
assert result["data"][CONF_NAME] == "prodnbr 0"
|
||||||
|
|
||||||
|
|
||||||
async def test_zeroconf_flow_already_configured(hass):
|
async def test_zeroconf_flow_already_configured(hass):
|
||||||
@ -281,10 +287,10 @@ async def test_zeroconf_flow_already_configured(hass):
|
|||||||
assert device.host == "1.2.3.4"
|
assert device.host == "1.2.3.4"
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
config_flow.DOMAIN,
|
AXIS_DOMAIN,
|
||||||
data={
|
data={
|
||||||
config_flow.CONF_HOST: "1.2.3.4",
|
CONF_HOST: "1.2.3.4",
|
||||||
config_flow.CONF_PORT: 80,
|
CONF_PORT: 80,
|
||||||
"hostname": "name",
|
"hostname": "name",
|
||||||
"properties": {"macaddress": MAC},
|
"properties": {"macaddress": MAC},
|
||||||
},
|
},
|
||||||
@ -301,20 +307,20 @@ async def test_zeroconf_flow_updated_configuration(hass):
|
|||||||
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 == {
|
assert device.config_entry.data == {
|
||||||
config_flow.CONF_HOST: "1.2.3.4",
|
CONF_HOST: "1.2.3.4",
|
||||||
config_flow.CONF_PORT: 80,
|
CONF_PORT: 80,
|
||||||
config_flow.CONF_USERNAME: "username",
|
CONF_USERNAME: "username",
|
||||||
config_flow.CONF_PASSWORD: "password",
|
CONF_PASSWORD: "password",
|
||||||
config_flow.CONF_MAC: MAC,
|
CONF_MAC: MAC,
|
||||||
config_flow.CONF_MODEL: MODEL,
|
CONF_MODEL: MODEL,
|
||||||
config_flow.CONF_NAME: NAME,
|
CONF_NAME: NAME,
|
||||||
}
|
}
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
config_flow.DOMAIN,
|
AXIS_DOMAIN,
|
||||||
data={
|
data={
|
||||||
config_flow.CONF_HOST: "2.3.4.5",
|
CONF_HOST: "2.3.4.5",
|
||||||
config_flow.CONF_PORT: 8080,
|
CONF_PORT: 8080,
|
||||||
"hostname": "name",
|
"hostname": "name",
|
||||||
"properties": {"macaddress": MAC},
|
"properties": {"macaddress": MAC},
|
||||||
},
|
},
|
||||||
@ -324,24 +330,21 @@ async def test_zeroconf_flow_updated_configuration(hass):
|
|||||||
assert result["type"] == "abort"
|
assert result["type"] == "abort"
|
||||||
assert result["reason"] == "already_configured"
|
assert result["reason"] == "already_configured"
|
||||||
assert device.config_entry.data == {
|
assert device.config_entry.data == {
|
||||||
config_flow.CONF_HOST: "2.3.4.5",
|
CONF_HOST: "2.3.4.5",
|
||||||
config_flow.CONF_PORT: 8080,
|
CONF_PORT: 8080,
|
||||||
config_flow.CONF_USERNAME: "username",
|
CONF_USERNAME: "username",
|
||||||
config_flow.CONF_PASSWORD: "password",
|
CONF_PASSWORD: "password",
|
||||||
config_flow.CONF_MAC: MAC,
|
CONF_MAC: MAC,
|
||||||
config_flow.CONF_MODEL: MODEL,
|
CONF_MODEL: MODEL,
|
||||||
config_flow.CONF_NAME: NAME,
|
CONF_NAME: NAME,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async def test_zeroconf_flow_ignore_non_axis_device(hass):
|
async def test_zeroconf_flow_ignore_non_axis_device(hass):
|
||||||
"""Test that zeroconf doesn't setup devices with link local addresses."""
|
"""Test that zeroconf doesn't setup devices with link local addresses."""
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
config_flow.DOMAIN,
|
AXIS_DOMAIN,
|
||||||
data={
|
data={CONF_HOST: "169.254.3.4", "properties": {"macaddress": "01234567890"}},
|
||||||
config_flow.CONF_HOST: "169.254.3.4",
|
|
||||||
"properties": {"macaddress": "01234567890"},
|
|
||||||
},
|
|
||||||
context={"source": "zeroconf"},
|
context={"source": "zeroconf"},
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -352,8 +355,8 @@ async def test_zeroconf_flow_ignore_non_axis_device(hass):
|
|||||||
async def test_zeroconf_flow_ignore_link_local_address(hass):
|
async def test_zeroconf_flow_ignore_link_local_address(hass):
|
||||||
"""Test that zeroconf doesn't setup devices with link local addresses."""
|
"""Test that zeroconf doesn't setup devices with link local addresses."""
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
config_flow.DOMAIN,
|
AXIS_DOMAIN,
|
||||||
data={config_flow.CONF_HOST: "169.254.3.4", "properties": {"macaddress": MAC}},
|
data={CONF_HOST: "169.254.3.4", "properties": {"macaddress": MAC}},
|
||||||
context={"source": "zeroconf"},
|
context={"source": "zeroconf"},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -2,10 +2,25 @@
|
|||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
import axis as axislib
|
import axis as axislib
|
||||||
|
from axis.event_stream import OPERATION_INITIALIZED
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.components import axis
|
from homeassistant.components import axis
|
||||||
|
from homeassistant.components.axis.const import (
|
||||||
|
CONF_CAMERA,
|
||||||
|
CONF_EVENTS,
|
||||||
|
CONF_MODEL,
|
||||||
|
DOMAIN as AXIS_DOMAIN,
|
||||||
|
)
|
||||||
|
from homeassistant.const import (
|
||||||
|
CONF_HOST,
|
||||||
|
CONF_MAC,
|
||||||
|
CONF_NAME,
|
||||||
|
CONF_PASSWORD,
|
||||||
|
CONF_PORT,
|
||||||
|
CONF_USERNAME,
|
||||||
|
)
|
||||||
|
|
||||||
from tests.async_mock import Mock, patch
|
from tests.async_mock import Mock, patch
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
@ -14,16 +29,16 @@ MAC = "00408C12345"
|
|||||||
MODEL = "model"
|
MODEL = "model"
|
||||||
NAME = "name"
|
NAME = "name"
|
||||||
|
|
||||||
ENTRY_OPTIONS = {axis.CONF_CAMERA: True, axis.CONF_EVENTS: True}
|
ENTRY_OPTIONS = {CONF_CAMERA: True, CONF_EVENTS: True}
|
||||||
|
|
||||||
ENTRY_CONFIG = {
|
ENTRY_CONFIG = {
|
||||||
axis.CONF_HOST: "1.2.3.4",
|
CONF_HOST: "1.2.3.4",
|
||||||
axis.CONF_USERNAME: "username",
|
CONF_USERNAME: "username",
|
||||||
axis.CONF_PASSWORD: "password",
|
CONF_PASSWORD: "password",
|
||||||
axis.CONF_PORT: 80,
|
CONF_PORT: 80,
|
||||||
axis.CONF_MAC: MAC,
|
CONF_MAC: MAC,
|
||||||
axis.device.CONF_MODEL: MODEL,
|
CONF_MODEL: MODEL,
|
||||||
axis.device.CONF_NAME: NAME,
|
CONF_NAME: NAME,
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFAULT_BRAND = """root.Brand.Brand=AXIS
|
DEFAULT_BRAND = """root.Brand.Brand=AXIS
|
||||||
@ -67,7 +82,7 @@ async def setup_axis_integration(
|
|||||||
):
|
):
|
||||||
"""Create the Axis device."""
|
"""Create the Axis device."""
|
||||||
config_entry = MockConfigEntry(
|
config_entry = MockConfigEntry(
|
||||||
domain=axis.DOMAIN,
|
domain=AXIS_DOMAIN,
|
||||||
data=deepcopy(config),
|
data=deepcopy(config),
|
||||||
connection_class=config_entries.CONN_CLASS_LOCAL_PUSH,
|
connection_class=config_entries.CONN_CLASS_LOCAL_PUSH,
|
||||||
options=deepcopy(options),
|
options=deepcopy(options),
|
||||||
@ -95,7 +110,7 @@ async def setup_axis_integration(
|
|||||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
return hass.data[axis.DOMAIN].get(config[axis.CONF_MAC])
|
return hass.data[AXIS_DOMAIN].get(config[CONF_MAC])
|
||||||
|
|
||||||
|
|
||||||
async def test_device_setup(hass):
|
async def test_device_setup(hass):
|
||||||
@ -113,10 +128,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 == ENTRY_CONFIG[axis.CONF_HOST]
|
assert device.host == ENTRY_CONFIG[CONF_HOST]
|
||||||
assert device.model == ENTRY_CONFIG[axis.device.CONF_MODEL]
|
assert device.model == ENTRY_CONFIG[CONF_MODEL]
|
||||||
assert device.name == ENTRY_CONFIG[axis.device.CONF_NAME]
|
assert device.name == ENTRY_CONFIG[CONF_NAME]
|
||||||
assert device.serial == ENTRY_CONFIG[axis.CONF_MAC]
|
assert device.serial == ENTRY_CONFIG[CONF_MAC]
|
||||||
|
|
||||||
|
|
||||||
async def test_update_address(hass):
|
async def test_update_address(hass):
|
||||||
@ -125,7 +140,7 @@ async def test_update_address(hass):
|
|||||||
assert device.api.config.host == "1.2.3.4"
|
assert device.api.config.host == "1.2.3.4"
|
||||||
|
|
||||||
await hass.config_entries.flow.async_init(
|
await hass.config_entries.flow.async_init(
|
||||||
axis.DOMAIN,
|
AXIS_DOMAIN,
|
||||||
data={
|
data={
|
||||||
"host": "2.3.4.5",
|
"host": "2.3.4.5",
|
||||||
"port": 80,
|
"port": 80,
|
||||||
@ -157,14 +172,14 @@ async def test_device_not_accessible(hass):
|
|||||||
"""Failed setup schedules a retry of setup."""
|
"""Failed setup schedules a retry of setup."""
|
||||||
with patch.object(axis.device, "get_device", side_effect=axis.errors.CannotConnect):
|
with patch.object(axis.device, "get_device", side_effect=axis.errors.CannotConnect):
|
||||||
await setup_axis_integration(hass)
|
await setup_axis_integration(hass)
|
||||||
assert hass.data[axis.DOMAIN] == {}
|
assert hass.data[AXIS_DOMAIN] == {}
|
||||||
|
|
||||||
|
|
||||||
async def test_device_unknown_error(hass):
|
async def test_device_unknown_error(hass):
|
||||||
"""Unknown errors are handled."""
|
"""Unknown errors are handled."""
|
||||||
with patch.object(axis.device, "get_device", side_effect=Exception):
|
with patch.object(axis.device, "get_device", side_effect=Exception):
|
||||||
await setup_axis_integration(hass)
|
await setup_axis_integration(hass)
|
||||||
assert hass.data[axis.DOMAIN] == {}
|
assert hass.data[AXIS_DOMAIN] == {}
|
||||||
|
|
||||||
|
|
||||||
async def test_new_event_sends_signal(hass):
|
async def test_new_event_sends_signal(hass):
|
||||||
@ -175,7 +190,7 @@ async def test_new_event_sends_signal(hass):
|
|||||||
axis_device = axis.device.AxisNetworkDevice(hass, entry)
|
axis_device = axis.device.AxisNetworkDevice(hass, entry)
|
||||||
|
|
||||||
with patch.object(axis.device, "async_dispatcher_send") as mock_dispatch_send:
|
with patch.object(axis.device, "async_dispatcher_send") as mock_dispatch_send:
|
||||||
axis_device.async_event_callback(action="add", event_id="event")
|
axis_device.async_event_callback(action=OPERATION_INITIALIZED, event_id="event")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert len(mock_dispatch_send.mock_calls) == 1
|
assert len(mock_dispatch_send.mock_calls) == 1
|
||||||
|
@ -1,5 +1,15 @@
|
|||||||
"""Test Axis component setup process."""
|
"""Test Axis component setup process."""
|
||||||
from homeassistant.components import axis
|
from homeassistant.components import axis
|
||||||
|
from homeassistant.components.axis.const import CONF_MODEL, DOMAIN as AXIS_DOMAIN
|
||||||
|
from homeassistant.const import (
|
||||||
|
CONF_DEVICE,
|
||||||
|
CONF_HOST,
|
||||||
|
CONF_MAC,
|
||||||
|
CONF_NAME,
|
||||||
|
CONF_PASSWORD,
|
||||||
|
CONF_PORT,
|
||||||
|
CONF_USERNAME,
|
||||||
|
)
|
||||||
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 MAC, setup_axis_integration
|
||||||
@ -10,21 +20,21 @@ from tests.common import MockConfigEntry
|
|||||||
|
|
||||||
async def test_setup_no_config(hass):
|
async def test_setup_no_config(hass):
|
||||||
"""Test setup without configuration."""
|
"""Test setup without configuration."""
|
||||||
assert await async_setup_component(hass, axis.DOMAIN, {})
|
assert await async_setup_component(hass, AXIS_DOMAIN, {})
|
||||||
assert axis.DOMAIN not in hass.data
|
assert AXIS_DOMAIN not in hass.data
|
||||||
|
|
||||||
|
|
||||||
async def test_setup_entry(hass):
|
async def test_setup_entry(hass):
|
||||||
"""Test successful setup of entry."""
|
"""Test successful setup of entry."""
|
||||||
await setup_axis_integration(hass)
|
await setup_axis_integration(hass)
|
||||||
assert len(hass.data[axis.DOMAIN]) == 1
|
assert len(hass.data[AXIS_DOMAIN]) == 1
|
||||||
assert MAC in hass.data[axis.DOMAIN]
|
assert MAC in hass.data[AXIS_DOMAIN]
|
||||||
|
|
||||||
|
|
||||||
async def test_setup_entry_fails(hass):
|
async def test_setup_entry_fails(hass):
|
||||||
"""Test successful setup of entry."""
|
"""Test successful setup of entry."""
|
||||||
config_entry = MockConfigEntry(
|
config_entry = MockConfigEntry(
|
||||||
domain=axis.DOMAIN, data={axis.CONF_MAC: "0123"}, version=2
|
domain=AXIS_DOMAIN, data={CONF_MAC: "0123"}, version=2
|
||||||
)
|
)
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
|
|
||||||
@ -36,43 +46,32 @@ async def test_setup_entry_fails(hass):
|
|||||||
|
|
||||||
assert not await hass.config_entries.async_setup(config_entry.entry_id)
|
assert not await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
|
||||||
assert not hass.data[axis.DOMAIN]
|
assert not hass.data[AXIS_DOMAIN]
|
||||||
|
|
||||||
|
|
||||||
async def test_unload_entry(hass):
|
async def test_unload_entry(hass):
|
||||||
"""Test successful unload of entry."""
|
"""Test successful unload of entry."""
|
||||||
device = await setup_axis_integration(hass)
|
device = await setup_axis_integration(hass)
|
||||||
assert hass.data[axis.DOMAIN]
|
assert hass.data[AXIS_DOMAIN]
|
||||||
|
|
||||||
assert await hass.config_entries.async_unload(device.config_entry.entry_id)
|
assert await hass.config_entries.async_unload(device.config_entry.entry_id)
|
||||||
assert not hass.data[axis.DOMAIN]
|
assert not hass.data[AXIS_DOMAIN]
|
||||||
|
|
||||||
|
|
||||||
async def test_populate_options(hass):
|
|
||||||
"""Test successful populate options."""
|
|
||||||
device = await setup_axis_integration(hass, options=None)
|
|
||||||
|
|
||||||
assert device.config_entry.options == {
|
|
||||||
axis.CONF_CAMERA: True,
|
|
||||||
axis.CONF_EVENTS: True,
|
|
||||||
axis.CONF_TRIGGER_TIME: axis.DEFAULT_TRIGGER_TIME,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async def test_migrate_entry(hass):
|
async def test_migrate_entry(hass):
|
||||||
"""Test successful migration of entry data."""
|
"""Test successful migration of entry data."""
|
||||||
legacy_config = {
|
legacy_config = {
|
||||||
axis.CONF_DEVICE: {
|
CONF_DEVICE: {
|
||||||
axis.CONF_HOST: "1.2.3.4",
|
CONF_HOST: "1.2.3.4",
|
||||||
axis.CONF_USERNAME: "username",
|
CONF_USERNAME: "username",
|
||||||
axis.CONF_PASSWORD: "password",
|
CONF_PASSWORD: "password",
|
||||||
axis.CONF_PORT: 80,
|
CONF_PORT: 80,
|
||||||
},
|
},
|
||||||
axis.CONF_MAC: "mac",
|
CONF_MAC: "mac",
|
||||||
axis.device.CONF_MODEL: "model",
|
CONF_MODEL: "model",
|
||||||
axis.device.CONF_NAME: "name",
|
CONF_NAME: "name",
|
||||||
}
|
}
|
||||||
entry = MockConfigEntry(domain=axis.DOMAIN, data=legacy_config)
|
entry = MockConfigEntry(domain=AXIS_DOMAIN, data=legacy_config)
|
||||||
|
|
||||||
assert entry.data == legacy_config
|
assert entry.data == legacy_config
|
||||||
assert entry.version == 1
|
assert entry.version == 1
|
||||||
@ -80,18 +79,18 @@ async def test_migrate_entry(hass):
|
|||||||
await entry.async_migrate(hass)
|
await entry.async_migrate(hass)
|
||||||
|
|
||||||
assert entry.data == {
|
assert entry.data == {
|
||||||
axis.CONF_DEVICE: {
|
CONF_DEVICE: {
|
||||||
axis.CONF_HOST: "1.2.3.4",
|
CONF_HOST: "1.2.3.4",
|
||||||
axis.CONF_USERNAME: "username",
|
CONF_USERNAME: "username",
|
||||||
axis.CONF_PASSWORD: "password",
|
CONF_PASSWORD: "password",
|
||||||
axis.CONF_PORT: 80,
|
CONF_PORT: 80,
|
||||||
},
|
},
|
||||||
axis.CONF_HOST: "1.2.3.4",
|
CONF_HOST: "1.2.3.4",
|
||||||
axis.CONF_USERNAME: "username",
|
CONF_USERNAME: "username",
|
||||||
axis.CONF_PASSWORD: "password",
|
CONF_PASSWORD: "password",
|
||||||
axis.CONF_PORT: 80,
|
CONF_PORT: 80,
|
||||||
axis.CONF_MAC: "mac",
|
CONF_MAC: "mac",
|
||||||
axis.device.CONF_MODEL: "model",
|
CONF_MODEL: "model",
|
||||||
axis.device.CONF_NAME: "name",
|
CONF_NAME: "name",
|
||||||
}
|
}
|
||||||
assert entry.version == 2
|
assert entry.version == 2
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
"""Axis switch platform tests."""
|
"""Axis switch platform tests."""
|
||||||
|
|
||||||
from homeassistant.components import axis
|
from axis.port_cgi import ACTION_HIGH, ACTION_LOW
|
||||||
import homeassistant.components.switch as switch
|
|
||||||
|
from homeassistant.components.axis.const import DOMAIN as AXIS_DOMAIN
|
||||||
|
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
from .test_device import NAME, setup_axis_integration
|
from .test_device import NAME, setup_axis_integration
|
||||||
@ -31,17 +33,17 @@ EVENTS = [
|
|||||||
async def test_platform_manually_configured(hass):
|
async def test_platform_manually_configured(hass):
|
||||||
"""Test that nothing happens when platform is manually configured."""
|
"""Test that nothing happens when platform is manually configured."""
|
||||||
assert await async_setup_component(
|
assert await async_setup_component(
|
||||||
hass, switch.DOMAIN, {"switch": {"platform": axis.DOMAIN}}
|
hass, SWITCH_DOMAIN, {SWITCH_DOMAIN: {"platform": AXIS_DOMAIN}}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert axis.DOMAIN not in hass.data
|
assert AXIS_DOMAIN not in hass.data
|
||||||
|
|
||||||
|
|
||||||
async def test_no_switches(hass):
|
async def test_no_switches(hass):
|
||||||
"""Test that no output events in Axis results in no switch entities."""
|
"""Test that no output events in Axis results in no switch entities."""
|
||||||
await setup_axis_integration(hass)
|
await setup_axis_integration(hass)
|
||||||
|
|
||||||
assert not hass.states.async_entity_ids("switch")
|
assert not hass.states.async_entity_ids(SWITCH_DOMAIN)
|
||||||
|
|
||||||
|
|
||||||
async def test_switches(hass):
|
async def test_switches(hass):
|
||||||
@ -53,10 +55,10 @@ async def test_switches(hass):
|
|||||||
device.api.vapix.ports["1"].name = ""
|
device.api.vapix.ports["1"].name = ""
|
||||||
|
|
||||||
for event in EVENTS:
|
for event in EVENTS:
|
||||||
device.api.stream.event.manage_event(event)
|
device.api.event.process_event(event)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert len(hass.states.async_entity_ids("switch")) == 2
|
assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 2
|
||||||
|
|
||||||
relay_0 = hass.states.get(f"switch.{NAME}_doorbell")
|
relay_0 = hass.states.get(f"switch.{NAME}_doorbell")
|
||||||
assert relay_0.state == "off"
|
assert relay_0.state == "off"
|
||||||
@ -69,14 +71,20 @@ async def test_switches(hass):
|
|||||||
device.api.vapix.ports["0"].action = Mock()
|
device.api.vapix.ports["0"].action = Mock()
|
||||||
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
"switch", "turn_on", {"entity_id": f"switch.{NAME}_doorbell"}, blocking=True
|
SWITCH_DOMAIN,
|
||||||
|
"turn_on",
|
||||||
|
{"entity_id": f"switch.{NAME}_doorbell"},
|
||||||
|
blocking=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
"switch", "turn_off", {"entity_id": f"switch.{NAME}_doorbell"}, blocking=True
|
SWITCH_DOMAIN,
|
||||||
|
"turn_off",
|
||||||
|
{"entity_id": f"switch.{NAME}_doorbell"},
|
||||||
|
blocking=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert device.api.vapix.ports["0"].action.call_args_list == [
|
assert device.api.vapix.ports["0"].action.call_args_list == [
|
||||||
mock_call("/"),
|
mock_call(ACTION_HIGH),
|
||||||
mock_call("\\"),
|
mock_call(ACTION_LOW),
|
||||||
]
|
]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user