Avoid creating onvif switches on unsupported devices (#91907)

* Avoid creating onvif switches on unsupported devices

fixes #89064

* cover
This commit is contained in:
J. Nick Koston 2023-04-23 19:56:43 -05:00 committed by GitHub
parent 0b0c94ee52
commit 14d2645de2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 45 additions and 6 deletions

View File

@ -28,6 +28,7 @@ class ONVIFSwitchEntityDescriptionMixin:
] ]
turn_on_data: Any turn_on_data: Any
turn_off_data: Any turn_off_data: Any
supported_fn: Callable[[ONVIFDevice], bool]
@dataclass @dataclass
@ -46,6 +47,7 @@ SWITCHES: tuple[ONVIFSwitchEntityDescription, ...] = (
turn_off_data={"Focus": {"AutoFocusMode": "MANUAL"}}, turn_off_data={"Focus": {"AutoFocusMode": "MANUAL"}},
turn_on_fn=lambda device: device.async_set_imaging_settings, turn_on_fn=lambda device: device.async_set_imaging_settings,
turn_off_fn=lambda device: device.async_set_imaging_settings, turn_off_fn=lambda device: device.async_set_imaging_settings,
supported_fn=lambda device: device.capabilities.imaging,
), ),
ONVIFSwitchEntityDescription( ONVIFSwitchEntityDescription(
key="ir_lamp", key="ir_lamp",
@ -55,6 +57,7 @@ SWITCHES: tuple[ONVIFSwitchEntityDescription, ...] = (
turn_off_data={"IrCutFilter": "ON"}, turn_off_data={"IrCutFilter": "ON"},
turn_on_fn=lambda device: device.async_set_imaging_settings, turn_on_fn=lambda device: device.async_set_imaging_settings,
turn_off_fn=lambda device: device.async_set_imaging_settings, turn_off_fn=lambda device: device.async_set_imaging_settings,
supported_fn=lambda device: device.capabilities.imaging,
), ),
ONVIFSwitchEntityDescription( ONVIFSwitchEntityDescription(
key="wiper", key="wiper",
@ -64,6 +67,7 @@ SWITCHES: tuple[ONVIFSwitchEntityDescription, ...] = (
turn_off_data="tt:Wiper|Off", turn_off_data="tt:Wiper|Off",
turn_on_fn=lambda device: device.async_run_aux_command, turn_on_fn=lambda device: device.async_run_aux_command,
turn_off_fn=lambda device: device.async_run_aux_command, turn_off_fn=lambda device: device.async_run_aux_command,
supported_fn=lambda device: device.capabilities.ptz,
), ),
) )
@ -76,7 +80,11 @@ async def async_setup_entry(
"""Set up a ONVIF switch platform.""" """Set up a ONVIF switch platform."""
device = hass.data[DOMAIN][config_entry.unique_id] device = hass.data[DOMAIN][config_entry.unique_id]
async_add_entities(ONVIFSwitch(device, description) for description in SWITCHES) async_add_entities(
ONVIFSwitch(device, description)
for description in SWITCHES
if description.supported_fn(device)
)
class ONVIFSwitch(ONVIFBaseEntity, SwitchEntity): class ONVIFSwitch(ONVIFBaseEntity, SwitchEntity):

View File

@ -91,7 +91,7 @@ def setup_mock_onvif_camera(
mock_onvif_camera.side_effect = mock_constructor mock_onvif_camera.side_effect = mock_constructor
def setup_mock_device(mock_device): def setup_mock_device(mock_device, capabilities=None):
"""Prepare mock ONVIFDevice.""" """Prepare mock ONVIFDevice."""
mock_device.async_setup = AsyncMock(return_value=True) mock_device.async_setup = AsyncMock(return_value=True)
mock_device.available = True mock_device.available = True
@ -103,7 +103,7 @@ def setup_mock_device(mock_device):
SERIAL_NUMBER, SERIAL_NUMBER,
MAC, MAC,
) )
mock_device.capabilities = Capabilities(imaging=True) mock_device.capabilities = capabilities or Capabilities(imaging=True, ptz=True)
profile1 = Profile( profile1 = Profile(
index=0, index=0,
token="dummy", token="dummy",
@ -132,6 +132,7 @@ async def setup_onvif_integration(
unique_id=MAC, unique_id=MAC,
entry_id="1", entry_id="1",
source=config_entries.SOURCE_USER, source=config_entries.SOURCE_USER,
capabilities=None,
) -> tuple[MockConfigEntry, MagicMock, MagicMock]: ) -> tuple[MockConfigEntry, MagicMock, MagicMock]:
"""Create an ONVIF config entry.""" """Create an ONVIF config entry."""
if not config: if not config:
@ -164,7 +165,7 @@ async def setup_onvif_integration(
setup_mock_onvif_camera(mock_onvif_camera, two_profiles=True) setup_mock_onvif_camera(mock_onvif_camera, two_profiles=True)
# no discovery # no discovery
mock_discovery.return_value = [] mock_discovery.return_value = []
setup_mock_device(mock_device) setup_mock_device(mock_device, capabilities=capabilities)
mock_device.device = mock_onvif_camera mock_device.device = mock_onvif_camera
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()

View File

@ -55,7 +55,7 @@ async def test_diagnostics(
"capabilities": { "capabilities": {
"snapshot": False, "snapshot": False,
"events": False, "events": False,
"ptz": False, "ptz": True,
"imaging": True, "imaging": True,
}, },
"profiles": [ "profiles": [

View File

@ -6,7 +6,7 @@ from homeassistant.const import ATTR_ENTITY_ID, STATE_OFF, STATE_ON, STATE_UNKNO
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er from homeassistant.helpers import entity_registry as er
from . import MAC, setup_onvif_integration from . import MAC, Capabilities, setup_onvif_integration
async def test_wiper_switch(hass: HomeAssistant) -> None: async def test_wiper_switch(hass: HomeAssistant) -> None:
@ -24,6 +24,16 @@ async def test_wiper_switch(hass: HomeAssistant) -> None:
assert entry.unique_id == f"{MAC}_wiper" assert entry.unique_id == f"{MAC}_wiper"
async def test_wiper_switch_no_ptz(hass: HomeAssistant) -> None:
"""Test the wiper switch does not get created if the camera does not support ptz."""
_config, _camera, device = await setup_onvif_integration(
hass, capabilities=Capabilities(imaging=True, ptz=False)
)
device.profiles = device.async_get_profiles()
assert hass.states.get("switch.testcamera_wiper") is None
async def test_turn_wiper_switch_on(hass: HomeAssistant) -> None: async def test_turn_wiper_switch_on(hass: HomeAssistant) -> None:
"""Test Wiper switch turn on.""" """Test Wiper switch turn on."""
_, _camera, device = await setup_onvif_integration(hass) _, _camera, device = await setup_onvif_integration(hass)
@ -75,6 +85,16 @@ async def test_autofocus_switch(hass: HomeAssistant) -> None:
assert entry.unique_id == f"{MAC}_autofocus" assert entry.unique_id == f"{MAC}_autofocus"
async def test_auto_focus_switch_no_imaging(hass: HomeAssistant) -> None:
"""Test the autofocus switch does not get created if the camera does not support imaging."""
_config, _camera, device = await setup_onvif_integration(
hass, capabilities=Capabilities(imaging=False, ptz=True)
)
device.profiles = device.async_get_profiles()
assert hass.states.get("switch.testcamera_autofocus") is None
async def test_turn_autofocus_switch_on(hass: HomeAssistant) -> None: async def test_turn_autofocus_switch_on(hass: HomeAssistant) -> None:
"""Test autofocus switch turn on.""" """Test autofocus switch turn on."""
_, _camera, device = await setup_onvif_integration(hass) _, _camera, device = await setup_onvif_integration(hass)
@ -126,6 +146,16 @@ async def test_infrared_switch(hass: HomeAssistant) -> None:
assert entry.unique_id == f"{MAC}_ir_lamp" assert entry.unique_id == f"{MAC}_ir_lamp"
async def test_infrared_switch_no_imaging(hass: HomeAssistant) -> None:
"""Test the infrared switch does not get created if the camera does not support imaging."""
_config, _camera, device = await setup_onvif_integration(
hass, capabilities=Capabilities(imaging=False, ptz=False)
)
device.profiles = device.async_get_profiles()
assert hass.states.get("switch.testcamera_ir_lamp") is None
async def test_turn_infrared_switch_on(hass: HomeAssistant) -> None: async def test_turn_infrared_switch_on(hass: HomeAssistant) -> None:
"""Test infrared switch turn on.""" """Test infrared switch turn on."""
_, _camera, device = await setup_onvif_integration(hass) _, _camera, device = await setup_onvif_integration(hass)