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": { "status_led": {
"default": "mdi:lightning-bolt-circle" "default": "mdi:lightning-bolt-circle"
},
"hdr": {
"default": "mdi:hdr"
} }
}, },
"sensor": { "sensor": {

View File

@ -9,6 +9,7 @@ from typing import Any
from reolink_aio.api import ( from reolink_aio.api import (
DayNightEnum, DayNightEnum,
HDREnum,
Host, Host,
SpotlightModeEnum, SpotlightModeEnum,
StatusLedEnum, StatusLedEnum,
@ -118,6 +119,17 @@ SELECT_ENTITIES = (
api.set_status_led(ch, StatusLedEnum[name].value, doorbell=True) 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": { "firmware_update": {
"title": "Reolink firmware update required", "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})." "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": { "services": {
@ -478,6 +482,14 @@
"alwaysonatnight": "Auto & always on at night", "alwaysonatnight": "Auto & always on at night",
"alwayson": "Always on" "alwayson": "Always on"
} }
},
"hdr": {
"name": "HDR",
"state": {
"off": "[%key:common::state::off%]",
"on": "[%key:common::state::on%]",
"auto": "Auto"
}
} }
}, },
"sensor": { "sensor": {
@ -554,7 +566,7 @@
"name": "Doorbell button sound" "name": "Doorbell button sound"
}, },
"hdr": { "hdr": {
"name": "HDR" "name": "[%key:component::reolink::entity::select::hdr::name%]"
}, },
"pir_enabled": { "pir_enabled": {
"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.const import EntityCategory
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError 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 homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import ReolinkData from . import ReolinkData
@ -173,16 +174,6 @@ SWITCH_ENTITIES = (
value=lambda api, ch: api.doorbell_button_sound(ch), value=lambda api, ch: api.doorbell_button_sound(ch),
method=lambda api, ch, value: api.set_volume(ch, doorbell_button_sound=value), 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( ReolinkSwitchEntityDescription(
key="pir_enabled", key="pir_enabled",
cmd_key="GetPirInfo", 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( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
@ -276,6 +279,31 @@ async def async_setup_entry(
if entity_description.supported(reolink_data.host.api) 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) 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