forked from home-assistant/core
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow setting volume on Ring devices (home-assistant#125773)
* Turn Ring Doorbell and Chime volumes into number entities. * turn RingOther volumes into numbers as well * fix linter issues * move other volume strings into `number` section * add back old volume sensors but deprecate them * add tests for `ring.number` * add back strings for sensors that have just become deprecated * remove deprecated volume sensors from test * Revert "remove deprecated volume sensors from test" This reverts commit fc95af6. * create entities for deprecated sensors so that tests still run * remove print * add entities immediately * move `RingNumberEntityDescription` above `RingNumber` and remove unused import * remove irrelevant comment about history * fix not using `setter_fn` * add missing icons for other volume entities * rename `entity` -> `entity_id` in number tests * fix typing in number test * use constants for `hass.services.async_call()` * use `@refresh_after` decorator instead of delaying updates manually * move descriptors above entity class * Use snapshot to test states. * add missing snapshot file for number platform * Update homeassistant/components/ring/number.py Co-authored-by: Steven B. <[email protected]> --------- Co-authored-by: Steven B. <[email protected]>
- Loading branch information
Showing
9 changed files
with
2,687 additions
and
6 deletions.
There are no files selected for viewing
This file contains 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 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 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,150 @@ | ||
"""Component providing HA number support for Ring Door Bell/Chimes.""" | ||
|
||
from collections.abc import Awaitable, Callable | ||
from dataclasses import dataclass | ||
from typing import Any, Generic, cast | ||
|
||
from ring_doorbell import RingChime, RingDoorBell, RingGeneric, RingOther | ||
import ring_doorbell.const | ||
|
||
from homeassistant.components.number import ( | ||
NumberEntity, | ||
NumberEntityDescription, | ||
NumberMode, | ||
) | ||
from homeassistant.core import HomeAssistant, callback | ||
from homeassistant.helpers.entity_platform import AddEntitiesCallback | ||
from homeassistant.helpers.typing import StateType | ||
|
||
from . import RingConfigEntry | ||
from .coordinator import RingDataCoordinator | ||
from .entity import RingDeviceT, RingEntity, refresh_after | ||
|
||
|
||
async def async_setup_entry( | ||
hass: HomeAssistant, | ||
entry: RingConfigEntry, | ||
async_add_entities: AddEntitiesCallback, | ||
) -> None: | ||
"""Set up a numbers for a Ring device.""" | ||
ring_data = entry.runtime_data | ||
devices_coordinator = ring_data.devices_coordinator | ||
|
||
async_add_entities( | ||
RingNumber(device, devices_coordinator, description) | ||
for description in NUMBER_TYPES | ||
for device in ring_data.devices.all_devices | ||
if description.exists_fn(device) | ||
) | ||
|
||
|
||
@dataclass(frozen=True, kw_only=True) | ||
class RingNumberEntityDescription(NumberEntityDescription, Generic[RingDeviceT]): | ||
"""Describes Ring number entity.""" | ||
|
||
value_fn: Callable[[RingDeviceT], StateType] | ||
setter_fn: Callable[[RingDeviceT, float], Awaitable[None]] | ||
exists_fn: Callable[[RingGeneric], bool] | ||
|
||
|
||
NUMBER_TYPES: tuple[RingNumberEntityDescription[Any], ...] = ( | ||
RingNumberEntityDescription[RingChime]( | ||
key="volume", | ||
translation_key="volume", | ||
mode=NumberMode.SLIDER, | ||
native_min_value=ring_doorbell.const.CHIME_VOL_MIN, | ||
native_max_value=ring_doorbell.const.CHIME_VOL_MAX, | ||
native_step=1, | ||
value_fn=lambda device: device.volume, | ||
setter_fn=lambda device, value: device.async_set_volume(int(value)), | ||
exists_fn=lambda device: isinstance(device, RingChime), | ||
), | ||
RingNumberEntityDescription[RingDoorBell]( | ||
key="volume", | ||
translation_key="volume", | ||
mode=NumberMode.SLIDER, | ||
native_min_value=ring_doorbell.const.DOORBELL_VOL_MIN, | ||
native_max_value=ring_doorbell.const.DOORBELL_VOL_MAX, | ||
native_step=1, | ||
value_fn=lambda device: device.volume, | ||
setter_fn=lambda device, value: device.async_set_volume(int(value)), | ||
exists_fn=lambda device: isinstance(device, RingDoorBell), | ||
), | ||
RingNumberEntityDescription[RingOther]( | ||
key="doorbell_volume", | ||
translation_key="doorbell_volume", | ||
mode=NumberMode.SLIDER, | ||
native_min_value=ring_doorbell.const.OTHER_DOORBELL_VOL_MIN, | ||
native_max_value=ring_doorbell.const.OTHER_DOORBELL_VOL_MAX, | ||
native_step=1, | ||
value_fn=lambda device: device.doorbell_volume, | ||
setter_fn=lambda device, value: device.async_set_doorbell_volume(int(value)), | ||
exists_fn=lambda device: isinstance(device, RingOther), | ||
), | ||
RingNumberEntityDescription[RingOther]( | ||
key="mic_volume", | ||
translation_key="mic_volume", | ||
mode=NumberMode.SLIDER, | ||
native_min_value=ring_doorbell.const.MIC_VOL_MIN, | ||
native_max_value=ring_doorbell.const.MIC_VOL_MAX, | ||
native_step=1, | ||
value_fn=lambda device: device.mic_volume, | ||
setter_fn=lambda device, value: device.async_set_mic_volume(int(value)), | ||
exists_fn=lambda device: isinstance(device, RingOther), | ||
), | ||
RingNumberEntityDescription[RingOther]( | ||
key="voice_volume", | ||
translation_key="voice_volume", | ||
mode=NumberMode.SLIDER, | ||
native_min_value=ring_doorbell.const.VOICE_VOL_MIN, | ||
native_max_value=ring_doorbell.const.VOICE_VOL_MAX, | ||
native_step=1, | ||
value_fn=lambda device: device.voice_volume, | ||
setter_fn=lambda device, value: device.async_set_voice_volume(int(value)), | ||
exists_fn=lambda device: isinstance(device, RingOther), | ||
), | ||
) | ||
|
||
|
||
class RingNumber(RingEntity[RingDeviceT], NumberEntity): | ||
"""A number implementation for Ring device.""" | ||
|
||
entity_description: RingNumberEntityDescription[RingDeviceT] | ||
|
||
def __init__( | ||
self, | ||
device: RingDeviceT, | ||
coordinator: RingDataCoordinator, | ||
description: RingNumberEntityDescription[RingDeviceT], | ||
) -> None: | ||
"""Initialize a number for Ring device.""" | ||
super().__init__(device, coordinator) | ||
self.entity_description = description | ||
self._attr_unique_id = f"{device.id}-{description.key}" | ||
self._update_native_value() | ||
|
||
def _update_native_value(self) -> None: | ||
native_value = self.entity_description.value_fn(self._device) | ||
if native_value is not None: | ||
self._attr_native_value = float(native_value) | ||
|
||
@callback | ||
def _handle_coordinator_update(self) -> None: | ||
"""Call update method.""" | ||
|
||
self._device = cast( | ||
RingDeviceT, | ||
self._get_coordinator_data().get_device(self._device.device_api_id), | ||
) | ||
|
||
self._update_native_value() | ||
|
||
super()._handle_coordinator_update() | ||
|
||
@refresh_after | ||
async def async_set_native_value(self, value: float) -> None: | ||
"""Call setter on Ring device.""" | ||
await self.entity_description.setter_fn(self._device, value) | ||
|
||
self._attr_native_value = value | ||
self.async_write_ha_state() |
This file contains 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 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 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
Oops, something went wrong.