-
-
Notifications
You must be signed in to change notification settings - Fork 37.7k
Reolink add switch platform #87943
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Reolink add switch platform #87943
Changes from 15 commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
d8f4046
Add switch entities
starkillerOG 9196506
fix import
starkillerOG 46c23d9
fix isort
starkillerOG 1895581
No need to call update
starkillerOG fdfafd1
do not await async_write_ha_state
starkillerOG cc59f18
Merge remote-tracking branch 'upstream/dev' into reolink_switch2
starkillerOG cc68ad5
Add record audio and Siren on event switches
starkillerOG b65ca08
Merge branch 'dev' into reolink_switch2
starkillerOG ca388a0
Merge branch 'dev' into reolink_switch2
starkillerOG 505d7fe
Remove floodlight and IR lights switches
starkillerOG 86045e3
Merge branch 'dev' into reolink_switch2
starkillerOG 1088a43
Add aditional switches
starkillerOG 2c82278
remove duplicate const
starkillerOG 803103b
Add NVR switches
starkillerOG dd3d48d
require channel
starkillerOG 7446ee9
Adjust docstring
starkillerOG 72da13e
Add typing
starkillerOG 1784165
Add EntityCategory
starkillerOG 994ef76
Merge branch 'dev' into reolink_switch2
frenck File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,229 @@ | ||
| """This component provides support for Reolink switch entities.""" | ||
| from __future__ import annotations | ||
|
|
||
| from collections.abc import Callable | ||
| from dataclasses import dataclass | ||
| from typing import Any | ||
|
|
||
| from reolink_aio.api import Host | ||
|
|
||
| from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription | ||
| from homeassistant.config_entries import ConfigEntry | ||
| from homeassistant.core import HomeAssistant | ||
| from homeassistant.helpers.entity_platform import AddEntitiesCallback | ||
|
|
||
| from . import ReolinkData | ||
| from .const import DOMAIN | ||
| from .entity import ReolinkBaseCoordinatorEntity, ReolinkCoordinatorEntity | ||
|
|
||
|
|
||
| @dataclass | ||
| class ReolinkSwitchEntityDescriptionMixin: | ||
| """Mixin values for Reolink switch entities.""" | ||
|
|
||
| value: Callable[[Host, int], bool] | ||
| method: Callable[[Host, int, bool], Any] | ||
|
|
||
|
|
||
| @dataclass | ||
| class ReolinkSwitchEntityDescription( | ||
| SwitchEntityDescription, ReolinkSwitchEntityDescriptionMixin | ||
| ): | ||
| """A class that describes switch entities.""" | ||
|
|
||
| supported: Callable[[Host, int], bool] = lambda api, ch: True | ||
|
|
||
|
|
||
| @dataclass | ||
| class ReolinkNVRSwitchEntityDescriptionMixin: | ||
| """Mixin values for Reolink NVR switch entities.""" | ||
|
|
||
| value: Callable[[Host], bool] | ||
| method: Callable[[Host, bool], Any] | ||
|
|
||
|
|
||
| @dataclass | ||
| class ReolinkNVRSwitchEntityDescription( | ||
| SwitchEntityDescription, ReolinkNVRSwitchEntityDescriptionMixin | ||
| ): | ||
| """A class that describes NVR switch entities.""" | ||
|
|
||
| supported: Callable[[Host], bool] = lambda api: True | ||
|
|
||
|
|
||
| SWITCH_ENTITIES = ( | ||
| ReolinkSwitchEntityDescription( | ||
| key="record_audio", | ||
| name="Record audio", | ||
| icon="mdi:microphone", | ||
| supported=lambda api, ch: api.supported(ch, "audio"), | ||
| value=lambda api, ch: api.audio_record(ch), | ||
| method=lambda api, ch, value: api.set_audio(ch, value), | ||
| ), | ||
| ReolinkSwitchEntityDescription( | ||
| key="siren_on_event", | ||
| name="Siren on event", | ||
| icon="mdi:alarm-light", | ||
| supported=lambda api, ch: api.supported(ch, "siren"), | ||
| value=lambda api, ch: api.audio_alarm_enabled(ch), | ||
| method=lambda api, ch, value: api.set_audio_alarm(ch, value), | ||
| ), | ||
| ReolinkSwitchEntityDescription( | ||
| key="auto_tracking", | ||
| name="Auto tracking", | ||
| icon="mdi:target-account", | ||
| supported=lambda api, ch: api.supported(ch, "auto_track"), | ||
| value=lambda api, ch: api.auto_track_enabled(ch), | ||
| method=lambda api, ch, value: api.set_auto_tracking(ch, value), | ||
| ), | ||
| ReolinkSwitchEntityDescription( | ||
| key="auto_focus", | ||
| name="Auto focus", | ||
| icon="mdi:focus-field", | ||
| supported=lambda api, ch: api.supported(ch, "auto_focus"), | ||
| value=lambda api, ch: api.autofocus_enabled(ch), | ||
| method=lambda api, ch, value: api.set_autofocus(ch, value), | ||
| ), | ||
| ReolinkSwitchEntityDescription( | ||
| key="gaurd_return", | ||
| name="Guard return", | ||
| icon="mdi:crosshairs-gps", | ||
| supported=lambda api, ch: api.supported(ch, "ptz_guard"), | ||
| value=lambda api, ch: api.ptz_guard_enabled(ch), | ||
| method=lambda api, ch, value: api.set_ptz_guard(ch, enable=value), | ||
| ), | ||
| ) | ||
|
|
||
| NVR_SWITCH_ENTITIES = ( | ||
| ReolinkNVRSwitchEntityDescription( | ||
| key="email", | ||
| name="Email on event", | ||
| icon="mdi:email", | ||
| supported=lambda api: api.supported(None, "email"), | ||
| value=lambda api: api.email_enabled(), | ||
| method=lambda api, value: api.set_email(None, value), | ||
| ), | ||
| ReolinkNVRSwitchEntityDescription( | ||
| key="ftp_upload", | ||
| name="FTP upload", | ||
| icon="mdi:swap-horizontal", | ||
| supported=lambda api: api.supported(None, "ftp"), | ||
| value=lambda api: api.ftp_enabled(), | ||
| method=lambda api, value: api.set_ftp(None, value), | ||
| ), | ||
| ReolinkNVRSwitchEntityDescription( | ||
| key="push_notifications", | ||
| name="Push notifications", | ||
| icon="mdi:message-badge", | ||
| supported=lambda api: api.supported(None, "push"), | ||
| value=lambda api: api.push_enabled(), | ||
| method=lambda api, value: api.set_push(None, value), | ||
| ), | ||
| ReolinkNVRSwitchEntityDescription( | ||
| key="record", | ||
| name="Record", | ||
| icon="mdi:record-rec", | ||
| supported=lambda api: api.supported(None, "recording"), | ||
| value=lambda api: api.recording_enabled(), | ||
| method=lambda api, value: api.set_recording(None, value), | ||
| ), | ||
| ReolinkNVRSwitchEntityDescription( | ||
| key="buzzer", | ||
| name="Buzzer on event", | ||
| icon="mdi:room-service", | ||
| supported=lambda api: api.supported(None, "buzzer"), | ||
| value=lambda api: api.buzzer_enabled(), | ||
| method=lambda api, value: api.set_buzzer(None, value), | ||
| ), | ||
|
starkillerOG marked this conversation as resolved.
|
||
| ) | ||
|
|
||
|
|
||
| async def async_setup_entry( | ||
| hass: HomeAssistant, | ||
| config_entry: ConfigEntry, | ||
| async_add_entities: AddEntitiesCallback, | ||
| ) -> None: | ||
| """Set up a Reolink switch entities.""" | ||
| reolink_data: ReolinkData = hass.data[DOMAIN][config_entry.entry_id] | ||
|
|
||
| entities: list[ReolinkSwitchEntity | ReolinkNVRSwitchEntity] = [ | ||
| ReolinkSwitchEntity(reolink_data, channel, entity_description) | ||
| for entity_description in SWITCH_ENTITIES | ||
| for channel in reolink_data.host.api.channels | ||
| if entity_description.supported(reolink_data.host.api, channel) | ||
| ] | ||
| entities.extend( | ||
| [ | ||
| ReolinkNVRSwitchEntity(reolink_data, entity_description) | ||
| for entity_description in NVR_SWITCH_ENTITIES | ||
| if entity_description.supported(reolink_data.host.api) | ||
| ] | ||
| ) | ||
| async_add_entities(entities) | ||
|
|
||
|
|
||
| class ReolinkSwitchEntity(ReolinkCoordinatorEntity, SwitchEntity): | ||
| """Base switch entity class for Reolink IP cameras.""" | ||
|
|
||
| entity_description: ReolinkSwitchEntityDescription | ||
|
|
||
| def __init__( | ||
| self, | ||
| reolink_data: ReolinkData, | ||
| channel: int, | ||
| entity_description: ReolinkSwitchEntityDescription, | ||
| ) -> None: | ||
| """Initialize Reolink switch entity.""" | ||
| super().__init__(reolink_data, channel) | ||
| self.entity_description = entity_description | ||
|
|
||
| self._attr_unique_id = ( | ||
| f"{self._host.unique_id}_{self._channel}_{entity_description.key}" | ||
| ) | ||
|
|
||
| @property | ||
| def is_on(self): | ||
| """Return true if switch is on.""" | ||
| return self.entity_description.value(self._host.api, self._channel) | ||
|
|
||
| async def async_turn_on(self, **kwargs): | ||
| """Turn the entity on.""" | ||
| await self.entity_description.method(self._host.api, self._channel, True) | ||
| self.async_write_ha_state() | ||
|
|
||
| async def async_turn_off(self, **kwargs): | ||
| """Turn the entity off.""" | ||
| await self.entity_description.method(self._host.api, self._channel, False) | ||
| self.async_write_ha_state() | ||
|
|
||
|
|
||
| class ReolinkNVRSwitchEntity(ReolinkBaseCoordinatorEntity, SwitchEntity): | ||
| """Switch entity class for Reolink NVR features.""" | ||
|
|
||
| entity_description: ReolinkNVRSwitchEntityDescription | ||
|
|
||
| def __init__( | ||
| self, | ||
| reolink_data: ReolinkData, | ||
| entity_description: ReolinkNVRSwitchEntityDescription, | ||
| ) -> None: | ||
| """Initialize Reolink switch entity.""" | ||
| super().__init__(reolink_data) | ||
| self.entity_description = entity_description | ||
|
|
||
| self._attr_unique_id = f"{self._host.unique_id}_{entity_description.key}" | ||
|
|
||
| @property | ||
| def is_on(self): | ||
| """Return true if switch is on.""" | ||
| return self.entity_description.value(self._host.api) | ||
|
|
||
| async def async_turn_on(self, **kwargs): | ||
| """Turn the entity on.""" | ||
| await self.entity_description.method(self._host.api, True) | ||
| self.async_write_ha_state() | ||
|
|
||
| async def async_turn_off(self, **kwargs): | ||
| """Turn the entity off.""" | ||
| await self.entity_description.method(self._host.api, False) | ||
| self.async_write_ha_state() | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.