From 1fd3c9d6dd705a9097900cb2277fac73dcb49c27 Mon Sep 17 00:00:00 2001 From: starkillerOG Date: Tue, 23 Jul 2024 13:28:33 +0200 Subject: [PATCH] Replace Reolink HDR switch by HDR select entity (#122373) * Add HDR select * Update strings.json * Update strings.json * add icon * remove HDR switch * cleanup old HDR switch * add tests * Keep HDR switch entity around untill HA 2025.2.0 * Add repair issue * Update strings.json * fixes and review comments * Add tests * Update homeassistant/components/reolink/strings.json Co-authored-by: Joost Lekkerkerker * Update homeassistant/components/reolink/switch.py Co-authored-by: Joost Lekkerkerker * fixes and simplify --------- Co-authored-by: Joost Lekkerkerker --- homeassistant/components/reolink/icons.json | 3 + homeassistant/components/reolink/select.py | 12 +++ homeassistant/components/reolink/strings.json | 14 +++- homeassistant/components/reolink/switch.py | 48 ++++++++--- tests/components/reolink/test_switch.py | 81 +++++++++++++++++++ 5 files changed, 147 insertions(+), 11 deletions(-) create mode 100644 tests/components/reolink/test_switch.py diff --git a/homeassistant/components/reolink/icons.json b/homeassistant/components/reolink/icons.json index a4620bd95d5..539c2461204 100644 --- a/homeassistant/components/reolink/icons.json +++ b/homeassistant/components/reolink/icons.json @@ -203,6 +203,9 @@ }, "status_led": { "default": "mdi:lightning-bolt-circle" + }, + "hdr": { + "default": "mdi:hdr" } }, "sensor": { diff --git a/homeassistant/components/reolink/select.py b/homeassistant/components/reolink/select.py index 907cc90b8af..cf32d7b45f9 100644 --- a/homeassistant/components/reolink/select.py +++ b/homeassistant/components/reolink/select.py @@ -9,6 +9,7 @@ from typing import Any from reolink_aio.api import ( DayNightEnum, + HDREnum, Host, SpotlightModeEnum, StatusLedEnum, @@ -118,6 +119,17 @@ SELECT_ENTITIES = ( api.set_status_led(ch, StatusLedEnum[name].value, doorbell=True) ), ), + ReolinkSelectEntityDescription( + key="hdr", + cmd_key="GetIsp", + translation_key="hdr", + entity_category=EntityCategory.CONFIG, + entity_registry_enabled_default=False, + get_options=[method.name for method in HDREnum], + supported=lambda api, ch: api.supported(ch, "HDR"), + value=lambda api, ch: HDREnum(api.HDR_state(ch)).name, + method=lambda api, ch, name: api.set_HDR(ch, HDREnum[name].value), + ), ) diff --git a/homeassistant/components/reolink/strings.json b/homeassistant/components/reolink/strings.json index aa141818ec6..3b9aba84634 100644 --- a/homeassistant/components/reolink/strings.json +++ b/homeassistant/components/reolink/strings.json @@ -69,6 +69,10 @@ "firmware_update": { "title": "Reolink firmware update required", "description": "\"{name}\" with model \"{model}\" and hardware version \"{hw_version}\" is running a old firmware version \"{current_firmware}\", while at least firmware version \"{required_firmware}\" is required for proper operation of the Reolink integration. The latest firmware can be downloaded from the [Reolink download center]({download_link})." + }, + "hdr_switch_deprecated": { + "title": "Reolink HDR switch deprecated", + "description": "The Reolink HDR switch entity is deprecated and will be removed in HA 2025.2.0. It has been replaced by a HDR select entity offering options `on`, `off` and `auto`. To remove this issue, please adjust automations accordingly and disable the HDR switch entity." } }, "services": { @@ -478,6 +482,14 @@ "alwaysonatnight": "Auto & always on at night", "alwayson": "Always on" } + }, + "hdr": { + "name": "HDR", + "state": { + "off": "[%key:common::state::off%]", + "on": "[%key:common::state::on%]", + "auto": "Auto" + } } }, "sensor": { @@ -554,7 +566,7 @@ "name": "Doorbell button sound" }, "hdr": { - "name": "HDR" + "name": "[%key:component::reolink::entity::select::hdr::name%]" }, "pir_enabled": { "name": "PIR enabled" diff --git a/homeassistant/components/reolink/switch.py b/homeassistant/components/reolink/switch.py index 9dfce88f93a..cd74d774bb1 100644 --- a/homeassistant/components/reolink/switch.py +++ b/homeassistant/components/reolink/switch.py @@ -14,6 +14,7 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.const import EntityCategory from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError +from homeassistant.helpers import entity_registry as er, issue_registry as ir from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import ReolinkData @@ -173,16 +174,6 @@ SWITCH_ENTITIES = ( value=lambda api, ch: api.doorbell_button_sound(ch), method=lambda api, ch, value: api.set_volume(ch, doorbell_button_sound=value), ), - ReolinkSwitchEntityDescription( - key="hdr", - cmd_key="GetIsp", - translation_key="hdr", - entity_category=EntityCategory.CONFIG, - entity_registry_enabled_default=False, - supported=lambda api, ch: api.supported(ch, "HDR"), - value=lambda api, ch: api.HDR_on(ch) is True, - method=lambda api, ch, value: api.set_HDR(ch, value), - ), ReolinkSwitchEntityDescription( key="pir_enabled", cmd_key="GetPirInfo", @@ -254,6 +245,18 @@ NVR_SWITCH_ENTITIES = ( ), ) +# Can be removed in HA 2025.2.0 +DEPRECATED_HDR = ReolinkSwitchEntityDescription( + key="hdr", + cmd_key="GetIsp", + translation_key="hdr", + entity_category=EntityCategory.CONFIG, + entity_registry_enabled_default=False, + supported=lambda api, ch: api.supported(ch, "HDR"), + value=lambda api, ch: api.HDR_on(ch) is True, + method=lambda api, ch, value: api.set_HDR(ch, value), +) + async def async_setup_entry( hass: HomeAssistant, @@ -276,6 +279,31 @@ async def async_setup_entry( if entity_description.supported(reolink_data.host.api) ] ) + + # Can be removed in HA 2025.2.0 + entity_reg = er.async_get(hass) + reg_entities = er.async_entries_for_config_entry(entity_reg, config_entry.entry_id) + for entity in reg_entities: + if entity.domain == "switch" and entity.unique_id.endswith("_hdr"): + if entity.disabled: + entity_reg.async_remove(entity.entity_id) + continue + + ir.async_create_issue( + hass, + DOMAIN, + "hdr_switch_deprecated", + is_fixable=False, + severity=ir.IssueSeverity.WARNING, + translation_key="hdr_switch_deprecated", + ) + entities.extend( + ReolinkSwitchEntity(reolink_data, channel, DEPRECATED_HDR) + for channel in reolink_data.host.api.channels + if DEPRECATED_HDR.supported(reolink_data.host.api, channel) + ) + break + async_add_entities(entities) diff --git a/tests/components/reolink/test_switch.py b/tests/components/reolink/test_switch.py new file mode 100644 index 00000000000..ebf805b593d --- /dev/null +++ b/tests/components/reolink/test_switch.py @@ -0,0 +1,81 @@ +"""Test the Reolink switch platform.""" + +from unittest.mock import MagicMock, patch + +from homeassistant.components.reolink import const +from homeassistant.const import Platform +from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry as er, issue_registry as ir + +from .conftest import TEST_UID + +from tests.common import MockConfigEntry + + +async def test_cleanup_hdr_switch_( + hass: HomeAssistant, + config_entry: MockConfigEntry, + reolink_connect: MagicMock, + entity_registry: er.EntityRegistry, +) -> None: + """Test cleanup of the HDR switch entity.""" + original_id = f"{TEST_UID}_hdr" + domain = Platform.SWITCH + + reolink_connect.channels = [0] + reolink_connect.supported.return_value = True + + entity_registry.async_get_or_create( + domain=domain, + platform=const.DOMAIN, + unique_id=original_id, + config_entry=config_entry, + suggested_object_id=original_id, + disabled_by=er.RegistryEntryDisabler.USER, + ) + + assert entity_registry.async_get_entity_id(domain, const.DOMAIN, original_id) + + # setup CH 0 and host entities/device + with patch("homeassistant.components.reolink.PLATFORMS", [domain]): + assert await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + assert ( + entity_registry.async_get_entity_id(domain, const.DOMAIN, original_id) is None + ) + + +async def test_hdr_switch_deprecated_repair_issue( + hass: HomeAssistant, + config_entry: MockConfigEntry, + reolink_connect: MagicMock, + entity_registry: er.EntityRegistry, + issue_registry: ir.IssueRegistry, +) -> None: + """Test repairs issue is raised when hdr switch entity used.""" + original_id = f"{TEST_UID}_hdr" + domain = Platform.SWITCH + + reolink_connect.channels = [0] + reolink_connect.supported.return_value = True + + entity_registry.async_get_or_create( + domain=domain, + platform=const.DOMAIN, + unique_id=original_id, + config_entry=config_entry, + suggested_object_id=original_id, + disabled_by=None, + ) + + assert entity_registry.async_get_entity_id(domain, const.DOMAIN, original_id) + + # setup CH 0 and host entities/device + with patch("homeassistant.components.reolink.PLATFORMS", [domain]): + assert await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + assert entity_registry.async_get_entity_id(domain, const.DOMAIN, original_id) + + assert (const.DOMAIN, "hdr_switch_deprecated") in issue_registry.issues