diff --git a/homeassistant/components/unifiprotect/__init__.py b/homeassistant/components/unifiprotect/__init__.py index 1e9f168820c..4e659d39cc5 100644 --- a/homeassistant/components/unifiprotect/__init__.py +++ b/homeassistant/components/unifiprotect/__init__.py @@ -27,7 +27,6 @@ from .const import ( from .data import ProtectData, async_ufp_instance_for_config_entry_ids from .discovery import async_start_discovery from .migrate import async_migrate_data -from .repairs import async_create_repairs from .services import async_cleanup_services, async_setup_services from .utils import ( _async_unifi_mac_from_hass, @@ -122,7 +121,6 @@ async def _async_setup_entry( hass: HomeAssistant, entry: ConfigEntry, data_service: ProtectData ) -> None: await async_migrate_data(hass, entry, data_service.api) - await async_create_repairs(hass, entry, data_service.api) await data_service.async_setup() if not data_service.last_update_success: diff --git a/homeassistant/components/unifiprotect/repairs.py b/homeassistant/components/unifiprotect/repairs.py index 72f297c8c25..49473744d06 100644 --- a/homeassistant/components/unifiprotect/repairs.py +++ b/homeassistant/components/unifiprotect/repairs.py @@ -2,94 +2,24 @@ from __future__ import annotations -from functools import partial -from itertools import chain import logging -from typing import Any, cast +from typing import cast from pyunifiprotect import ProtectApiClient import voluptuous as vol from homeassistant import data_entry_flow -from homeassistant.components.automation import ( - EVENT_AUTOMATION_RELOADED, - automations_with_entity, -) from homeassistant.components.repairs import ConfirmRepairFlow, RepairsFlow -from homeassistant.components.script import scripts_with_entity from homeassistant.config_entries import ConfigEntry -from homeassistant.const import Platform from homeassistant.core import HomeAssistant, callback -from homeassistant.helpers import entity_registry as er, issue_registry as ir -from homeassistant.helpers.issue_registry import ( - IssueSeverity, - async_get as async_get_issue_registry, -) +from homeassistant.helpers.issue_registry import async_get as async_get_issue_registry -from .const import CONF_ALLOW_EA, DOMAIN +from .const import CONF_ALLOW_EA from .utils import async_create_api_client _LOGGER = logging.getLogger(__name__) -async def async_create_repairs( - hass: HomeAssistant, entry: ConfigEntry, protect: ProtectApiClient -) -> None: - """Create any additional repairs for deprecations.""" - - await _deprecate_smart_sensor(hass, entry, protect) - entry.async_on_unload( - hass.bus.async_listen( - EVENT_AUTOMATION_RELOADED, - partial(_deprecate_smart_sensor, hass, entry, protect), - ) - ) - - -async def _deprecate_smart_sensor( - hass: HomeAssistant, - entry: ConfigEntry, - protect: ProtectApiClient, - *args: Any, - **kwargs: Any, -) -> None: - entity_registry = er.async_get(hass) - automations: dict[str, list[str]] = {} - scripts: dict[str, list[str]] = {} - for entity in er.async_entries_for_config_entry(entity_registry, entry.entry_id): - if ( - entity.domain == Platform.SENSOR - and entity.disabled_by is None - and "detected_object" in entity.unique_id - ): - entity_automations = automations_with_entity(hass, entity.entity_id) - entity_scripts = scripts_with_entity(hass, entity.entity_id) - if entity_automations: - automations[entity.entity_id] = entity_automations - if entity_scripts: - scripts[entity.entity_id] = entity_scripts - - if automations or scripts: - items = sorted( - set( - chain.from_iterable(list(automations.values()) + list(scripts.values())) - ) - ) - ir.async_create_issue( - hass, - DOMAIN, - "deprecate_smart_sensor", - is_fixable=False, - breaks_in_ha_version="2023.3.0", - severity=IssueSeverity.WARNING, - translation_key="deprecate_smart_sensor", - translation_placeholders={"items": "* `" + "`\n* `".join(items) + "`\n"}, - ) - else: - _LOGGER.debug("No found usages of Detected Object sensor") - ir.async_delete_issue(hass, DOMAIN, "deprecate_smart_sensor") - - class EAConfirm(RepairsFlow): """Handler for an issue fixing flow.""" diff --git a/homeassistant/components/unifiprotect/sensor.py b/homeassistant/components/unifiprotect/sensor.py index 7a31fffee49..5b17ed0020c 100644 --- a/homeassistant/components/unifiprotect/sensor.py +++ b/homeassistant/components/unifiprotect/sensor.py @@ -53,7 +53,6 @@ from .utils import async_dispatch_id as _ufpd, async_get_light_motion_current _LOGGER = logging.getLogger(__name__) OBJECT_TYPE_NONE = "none" -DEVICE_CLASS_DETECTION = "unifiprotect__detection" @dataclass @@ -524,14 +523,6 @@ NVR_DISABLED_SENSORS: tuple[ProtectSensorEntityDescription, ...] = ( ) EVENT_SENSORS: tuple[ProtectSensorEventEntityDescription, ...] = ( - ProtectSensorEventEntityDescription( - key="detected_object", - name="Detected Object", - device_class=DEVICE_CLASS_DETECTION, - entity_registry_enabled_default=False, - ufp_value="is_smart_detected", - ufp_event_obj="last_smart_detect_event", - ), ProtectSensorEventEntityDescription( key="smart_obj_licenseplate", name="License Plate Detected", diff --git a/tests/components/unifiprotect/__init__.py b/tests/components/unifiprotect/__init__.py index 1bbe9fb435d..cc59bca3506 100644 --- a/tests/components/unifiprotect/__init__.py +++ b/tests/components/unifiprotect/__init__.py @@ -3,6 +3,7 @@ from contextlib import contextmanager from unittest.mock import AsyncMock, MagicMock, patch +import pytest from unifi_discovery import AIOUnifiScanner, UnifiDevice, UnifiService DEVICE_HOSTNAME = "unvr" @@ -27,6 +28,8 @@ UNIFI_DISCOVERY_PARTIAL = UnifiDevice( services={UnifiService.Protect: True}, ) +pytest.register_assert_rewrite("tests.components.unifiprotect.utils") + def _patch_discovery(device=None, no_device=False): mock_aio_discovery = MagicMock(auto_spec=AIOUnifiScanner) diff --git a/tests/components/unifiprotect/test_repairs.py b/tests/components/unifiprotect/test_repairs.py index 829e695ea2e..b9fa9bc57b8 100644 --- a/tests/components/unifiprotect/test_repairs.py +++ b/tests/components/unifiprotect/test_repairs.py @@ -3,11 +3,10 @@ from __future__ import annotations from copy import copy from http import HTTPStatus -from unittest.mock import Mock, patch +from unittest.mock import Mock from pyunifiprotect.data import Camera, Version -from homeassistant.components.automation import DOMAIN as AUTOMATION_DOMAIN from homeassistant.components.repairs.issue_handler import ( async_process_repairs_platforms, ) @@ -15,12 +14,10 @@ from homeassistant.components.repairs.websocket_api import ( RepairsFlowIndexView, RepairsFlowResourceView, ) -from homeassistant.components.script import DOMAIN as SCRIPT_DOMAIN from homeassistant.components.unifiprotect.const import DOMAIN -from homeassistant.const import SERVICE_RELOAD, Platform +from homeassistant.const import Platform from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er -from homeassistant.setup import async_setup_component from .utils import MockUFPFixture, init_entry @@ -186,154 +183,3 @@ async def test_deprecate_smart_no_automations( if i["issue_id"] == "deprecate_smart_sensor": issue = i assert issue is None - - -async def _load_automation(hass: HomeAssistant, entity_id: str): - assert await async_setup_component( - hass, - AUTOMATION_DOMAIN, - { - AUTOMATION_DOMAIN: [ - { - "alias": "test1", - "trigger": [ - {"platform": "state", "entity_id": entity_id}, - { - "platform": "event", - "event_type": "state_changed", - "event_data": {"entity_id": entity_id}, - }, - ], - "condition": { - "condition": "state", - "entity_id": entity_id, - "state": "on", - }, - "action": [ - { - "service": "test.script", - "data": {"entity_id": entity_id}, - }, - ], - }, - ] - }, - ) - - -async def test_deprecate_smart_automation( - hass: HomeAssistant, - ufp: MockUFPFixture, - hass_ws_client: WebSocketGenerator, - doorbell: Camera, -) -> None: - """Test Deprecate Sensor repair exists for existing installs.""" - - registry = er.async_get(hass) - entry = registry.async_get_or_create( - Platform.SENSOR, - DOMAIN, - f"{doorbell.mac}_detected_object", - config_entry=ufp.entry, - ) - await _load_automation(hass, entry.entity_id) - await init_entry(hass, ufp, [doorbell]) - - await async_process_repairs_platforms(hass) - ws_client = await hass_ws_client(hass) - - await ws_client.send_json({"id": 1, "type": "repairs/list_issues"}) - msg = await ws_client.receive_json() - - assert msg["success"] - issue = None - for i in msg["result"]["issues"]: - if i["issue_id"] == "deprecate_smart_sensor": - issue = i - assert issue is not None - - with patch( - "homeassistant.config.load_yaml_config_file", - autospec=True, - return_value={AUTOMATION_DOMAIN: []}, - ): - await hass.services.async_call(AUTOMATION_DOMAIN, SERVICE_RELOAD, blocking=True) - await hass.async_block_till_done() - - await ws_client.send_json({"id": 2, "type": "repairs/list_issues"}) - msg = await ws_client.receive_json() - - assert msg["success"] - issue = None - for i in msg["result"]["issues"]: - if i["issue_id"] == "deprecate_smart_sensor": - issue = i - assert issue is None - - -async def _load_script(hass: HomeAssistant, entity_id: str): - assert await async_setup_component( - hass, - SCRIPT_DOMAIN, - { - SCRIPT_DOMAIN: { - "test": { - "sequence": { - "service": "test.script", - "data": {"entity_id": entity_id}, - } - } - }, - }, - ) - - -async def test_deprecate_smart_script( - hass: HomeAssistant, - ufp: MockUFPFixture, - hass_ws_client: WebSocketGenerator, - doorbell: Camera, -) -> None: - """Test Deprecate Sensor repair exists for existing installs.""" - - registry = er.async_get(hass) - entry = registry.async_get_or_create( - Platform.SENSOR, - DOMAIN, - f"{doorbell.mac}_detected_object", - config_entry=ufp.entry, - ) - await _load_script(hass, entry.entity_id) - await init_entry(hass, ufp, [doorbell]) - - await async_process_repairs_platforms(hass) - ws_client = await hass_ws_client(hass) - - await ws_client.send_json({"id": 1, "type": "repairs/list_issues"}) - msg = await ws_client.receive_json() - - assert msg["success"] - issue = None - for i in msg["result"]["issues"]: - if i["issue_id"] == "deprecate_smart_sensor": - issue = i - assert issue is not None - - with patch( - "homeassistant.config.load_yaml_config_file", - autospec=True, - return_value={SCRIPT_DOMAIN: {}}, - ): - await hass.services.async_call(SCRIPT_DOMAIN, SERVICE_RELOAD, blocking=True) - await hass.config_entries.async_reload(ufp.entry.entry_id) - await hass.async_block_till_done() - - await ws_client.send_json({"id": 2, "type": "repairs/list_issues"}) - msg = await ws_client.receive_json() - - assert msg["success"] - issue = None - for i in msg["result"]["issues"]: - if i["issue_id"] == "deprecate_smart_sensor": - issue = i - assert issue is None diff --git a/tests/components/unifiprotect/test_sensor.py b/tests/components/unifiprotect/test_sensor.py index 2daa44699b4..0d763e6f906 100644 --- a/tests/components/unifiprotect/test_sensor.py +++ b/tests/components/unifiprotect/test_sensor.py @@ -15,10 +15,7 @@ from pyunifiprotect.data import ( ) from pyunifiprotect.data.nvr import EventMetadata, LicensePlateMetadata -from homeassistant.components.unifiprotect.const import ( - ATTR_EVENT_SCORE, - DEFAULT_ATTRIBUTION, -) +from homeassistant.components.unifiprotect.const import DEFAULT_ATTRIBUTION from homeassistant.components.unifiprotect.sensor import ( ALL_DEVICES_SENSORS, CAMERA_DISABLED_SENSORS, @@ -27,7 +24,6 @@ from homeassistant.components.unifiprotect.sensor import ( MOTION_TRIP_SENSORS, NVR_DISABLED_SENSORS, NVR_SENSORS, - OBJECT_TYPE_NONE, SENSE_SENSORS, ) from homeassistant.const import ( @@ -62,11 +58,11 @@ async def test_sensor_camera_remove( ufp.api.bootstrap.nvr.system_info.ustorage = None await init_entry(hass, ufp, [doorbell, unadopted_camera]) - assert_entity_counts(hass, Platform.SENSOR, 25, 12) + assert_entity_counts(hass, Platform.SENSOR, 24, 12) await remove_entities(hass, ufp, [doorbell, unadopted_camera]) assert_entity_counts(hass, Platform.SENSOR, 12, 9) await adopt_devices(hass, ufp, [doorbell, unadopted_camera]) - assert_entity_counts(hass, Platform.SENSOR, 25, 12) + assert_entity_counts(hass, Platform.SENSOR, 24, 12) async def test_sensor_sensor_remove( @@ -320,7 +316,7 @@ async def test_sensor_setup_camera( """Test sensor entity setup for camera devices.""" await init_entry(hass, ufp, [doorbell]) - assert_entity_counts(hass, Platform.SENSOR, 25, 12) + assert_entity_counts(hass, Platform.SENSOR, 24, 12) entity_registry = er.async_get(hass) @@ -399,22 +395,6 @@ async def test_sensor_setup_camera( assert state.state == "-50" assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION - # Detected Object - unique_id, entity_id = ids_from_device_description( - Platform.SENSOR, doorbell, EVENT_SENSORS[0] - ) - - entity = entity_registry.async_get(entity_id) - assert entity - assert entity.unique_id == unique_id - - await enable_entity(hass, ufp.entry.entry_id, entity_id) - - state = hass.states.get(entity_id) - assert state - assert state.state == OBJECT_TYPE_NONE - assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION - async def test_sensor_setup_camera_with_last_trip_time( hass: HomeAssistant, @@ -426,7 +406,7 @@ async def test_sensor_setup_camera_with_last_trip_time( """Test sensor entity setup for camera devices with last trip time.""" await init_entry(hass, ufp, [doorbell]) - assert_entity_counts(hass, Platform.SENSOR, 25, 25) + assert_entity_counts(hass, Platform.SENSOR, 24, 24) entity_registry = er.async_get(hass) @@ -448,52 +428,6 @@ async def test_sensor_setup_camera_with_last_trip_time( assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION -async def test_sensor_update_motion( - hass: HomeAssistant, ufp: MockUFPFixture, doorbell: Camera, fixed_now: datetime -) -> None: - """Test sensor motion entity.""" - - await init_entry(hass, ufp, [doorbell]) - assert_entity_counts(hass, Platform.SENSOR, 25, 12) - - _, entity_id = ids_from_device_description( - Platform.SENSOR, doorbell, EVENT_SENSORS[0] - ) - - await enable_entity(hass, ufp.entry.entry_id, entity_id) - - event = Event( - id="test_event_id", - type=EventType.SMART_DETECT, - start=fixed_now - timedelta(seconds=1), - end=None, - score=100, - smart_detect_types=[SmartDetectObjectType.PERSON], - smart_detect_event_ids=[], - camera_id=doorbell.id, - api=ufp.api, - ) - - new_camera = doorbell.copy() - new_camera.is_smart_detected = True - new_camera.last_smart_detect_event_id = event.id - - mock_msg = Mock() - mock_msg.changed_data = {} - mock_msg.new_obj = event - - ufp.api.bootstrap.cameras = {new_camera.id: new_camera} - ufp.api.bootstrap.events = {event.id: event} - ufp.ws_msg(mock_msg) - await hass.async_block_till_done() - - state = hass.states.get(entity_id) - assert state - assert state.state == SmartDetectObjectType.PERSON.value - assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION - assert state.attributes[ATTR_EVENT_SCORE] == 100 - - async def test_sensor_update_alarm( hass: HomeAssistant, ufp: MockUFPFixture, sensor_all: Sensor, fixed_now: datetime ) -> None: @@ -581,10 +515,10 @@ async def test_camera_update_licenseplate( ) await init_entry(hass, ufp, [camera]) - assert_entity_counts(hass, Platform.SENSOR, 24, 13) + assert_entity_counts(hass, Platform.SENSOR, 23, 13) _, entity_id = ids_from_device_description( - Platform.SENSOR, camera, EVENT_SENSORS[1] + Platform.SENSOR, camera, EVENT_SENSORS[0] ) event_metadata = EventMetadata(