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 <joostlek@outlook.com>

* Update homeassistant/components/reolink/switch.py

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>

* fixes and simplify

---------

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
This commit is contained in:
starkillerOG 2024-07-23 13:28:33 +02:00 committed by GitHub
parent 0d765a27c9
commit 1fd3c9d6dd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 147 additions and 11 deletions

View File

@ -203,6 +203,9 @@
},
"status_led": {
"default": "mdi:lightning-bolt-circle"
},
"hdr": {
"default": "mdi:hdr"
}
},
"sensor": {

View File

@ -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),
),
)

View File

@ -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"

View File

@ -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)

View File

@ -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