Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions homeassistant/components/ring/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

PLATFORMS = [
Platform.BINARY_SENSOR,
Platform.BUTTON,
Platform.LIGHT,
Platform.SENSOR,
Platform.SWITCH,
Expand Down
65 changes: 65 additions & 0 deletions homeassistant/components/ring/button.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"""This component provides HA button support for Ring Chimes."""
import logging

from homeassistant.components.button import ButtonEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from . import DOMAIN
from .entity import RingEntityMixin

_LOGGER = logging.getLogger(__name__)

BELL_ICON = "mdi:bell-ring"


async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Create the buttons for the Ring devices."""
devices = hass.data[DOMAIN][config_entry.entry_id]["devices"]
buttons = []

# add one button for each test chime type (ding, motion)
for device in devices["chimes"]:
buttons.append(ChimeButton(config_entry.entry_id, device, "ding"))
buttons.append(ChimeButton(config_entry.entry_id, device, "motion"))

async_add_entities(buttons)


class BaseRingButton(RingEntityMixin, ButtonEntity):
"""Represents a Button for controlling an aspect of a ring device."""

def __init__(self, config_entry_id, device, button_identifier, button_name):
"""Initialize the switch."""
super().__init__(config_entry_id, device)
self._button_identifier = button_identifier
self._button_name = button_name
self._attr_unique_id = f"{self._device.id}-{self._button_identifier}"

@property
def name(self):
"""Name of the device."""
return f"{self._device.name} {self._button_name}"


class ChimeButton(BaseRingButton):
"""Creates a button to play the test chime of a Chime device."""

_attr_icon = BELL_ICON

def __init__(self, config_entry_id, device, kind):
"""Initialize the button for a device with a chime."""
super().__init__(
config_entry_id, device, f"play-chime-{kind}", f"Play chime: {kind}"
)
self.kind = kind

def press(self) -> None:
"""Send the test chime request."""
if not self._device.test_sound(kind=self.kind):
_LOGGER.error("Failed to ring chime sound on %s", self.name)
55 changes: 55 additions & 0 deletions tests/components/ring/test_button.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"""The tests for the Ring button platform."""

from homeassistant.const import Platform
from homeassistant.helpers import entity_registry as er

from .common import setup_platform


async def test_entity_registry(hass, requests_mock):
"""Tests that the devices are registered in the entity registry."""
await setup_platform(hass, Platform.BUTTON)
entity_registry = er.async_get(hass)

entry = entity_registry.async_get("button.downstairs_play_chime_ding")
assert entry.unique_id == "123456-play-chime-ding"

entry = entity_registry.async_get("button.downstairs_play_chime_motion")
assert entry.unique_id == "123456-play-chime-motion"


async def test_play_chime_buttons_report_correctly(hass, requests_mock):
"""Tests that the initial state of a device that should be on is correct."""
await setup_platform(hass, Platform.BUTTON)

state = hass.states.get("button.downstairs_play_chime_ding")
assert state.attributes.get("friendly_name") == "Downstairs Play chime: ding"
assert state.attributes.get("icon") == "mdi:bell-ring"

state = hass.states.get("button.downstairs_play_chime_motion")
assert state.attributes.get("friendly_name") == "Downstairs Play chime: motion"
assert state.attributes.get("icon") == "mdi:bell-ring"


async def test_chime_can_be_played(hass, requests_mock):
"""Tests the play chime request is sent correctly."""
await setup_platform(hass, Platform.BUTTON)

# Mocks the response for playing a test sound
requests_mock.post(
"https://api.ring.com/clients_api/chimes/123456/play_sound",
text="SUCCESS",
)
await hass.services.async_call(
"button",
"press",
{"entity_id": "button.downstairs_play_chime_ding"},
blocking=True,
)

await hass.async_block_till_done()

assert requests_mock.request_history[-1].url.startswith(
"https://api.ring.com/clients_api/chimes/123456/play_sound?"
)
assert "kind=ding" in requests_mock.request_history[-1].url