diff --git a/homeassistant/components/elgato/__init__.py b/homeassistant/components/elgato/__init__.py index 0c42e359d07..c074b3303e7 100644 --- a/homeassistant/components/elgato/__init__.py +++ b/homeassistant/components/elgato/__init__.py @@ -3,6 +3,7 @@ import logging from elgato import Elgato, ElgatoConnectionError +from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_HOST, CONF_PORT @@ -12,7 +13,7 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession from .const import DOMAIN -PLATFORMS = [LIGHT_DOMAIN] +PLATFORMS = [BUTTON_DOMAIN, LIGHT_DOMAIN] async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: diff --git a/homeassistant/components/elgato/button.py b/homeassistant/components/elgato/button.py new file mode 100644 index 00000000000..4e77f05e415 --- /dev/null +++ b/homeassistant/components/elgato/button.py @@ -0,0 +1,62 @@ +"""Support for Elgato button.""" +from __future__ import annotations + +import logging + +from elgato import Elgato, ElgatoError, Info + +from homeassistant.components.button import ButtonEntity, ButtonEntityDescription +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import ENTITY_CATEGORY_CONFIG +from homeassistant.core import HomeAssistant +from homeassistant.helpers.entity import DeviceInfo +from homeassistant.helpers.entity_platform import AddEntitiesCallback + +from .const import DOMAIN + +_LOGGER = logging.getLogger(__name__) + + +async def async_setup_entry( + hass: HomeAssistant, + entry: ConfigEntry, + async_add_entities: AddEntitiesCallback, +) -> None: + """Set up Elgato button based on a config entry.""" + elgato: Elgato = hass.data[DOMAIN][entry.entry_id] + info = await elgato.info() + async_add_entities([ElgatoIdentifyButton(elgato, info)]) + + +class ElgatoIdentifyButton(ButtonEntity): + """Defines an Elgato identify button.""" + + def __init__(self, elgato: Elgato, info: Info) -> None: + """Initialize the button entity.""" + self.elgato = elgato + self._info = info + self.entity_description = ButtonEntityDescription( + key="identify", + name="Identify", + icon="mdi:help", + entity_category=ENTITY_CATEGORY_CONFIG, + ) + self._attr_unique_id = f"{info.serial_number}_{self.entity_description.key}" + + @property + def device_info(self) -> DeviceInfo: + """Return device information about this Elgato Light.""" + return DeviceInfo( + identifiers={(DOMAIN, self._info.serial_number)}, + manufacturer="Elgato", + model=self._info.product_name, + name=self._info.product_name, + sw_version=f"{self._info.firmware_version} ({self._info.firmware_build_number})", + ) + + async def async_press(self) -> None: + """Identify the light, will make it blink.""" + try: + await self.elgato.identify() + except ElgatoError: + _LOGGER.exception("An error occurred while identifying the Elgato Light") diff --git a/tests/components/elgato/test_button.py b/tests/components/elgato/test_button.py new file mode 100644 index 00000000000..21211596d0c --- /dev/null +++ b/tests/components/elgato/test_button.py @@ -0,0 +1,77 @@ +"""Tests for the Elgato Light button platform.""" +from unittest.mock import patch + +from elgato import ElgatoError +import pytest + +from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN, SERVICE_PRESS +from homeassistant.const import ( + ATTR_ENTITY_ID, + ATTR_ICON, + ENTITY_CATEGORY_CONFIG, + STATE_UNKNOWN, +) +from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry as er + +from tests.components.elgato import init_integration +from tests.test_util.aiohttp import AiohttpClientMocker + + +@pytest.mark.freeze_time("2021-11-13 11:48:00") +async def test_button_identify( + hass: HomeAssistant, aioclient_mock: AiohttpClientMocker +) -> None: + """Test the Elgato identify button.""" + await init_integration(hass, aioclient_mock) + + entity_registry = er.async_get(hass) + + state = hass.states.get("button.identify") + assert state + assert state.attributes.get(ATTR_ICON) == "mdi:help" + assert state.state == STATE_UNKNOWN + + entry = entity_registry.async_get("button.identify") + assert entry + assert entry.unique_id == "CN11A1A00001_identify" + assert entry.entity_category == ENTITY_CATEGORY_CONFIG + + with patch( + "homeassistant.components.elgato.light.Elgato.identify" + ) as mock_identify: + await hass.services.async_call( + BUTTON_DOMAIN, + SERVICE_PRESS, + {ATTR_ENTITY_ID: "button.identify"}, + blocking=True, + ) + + assert len(mock_identify.mock_calls) == 1 + mock_identify.assert_called_with() + + state = hass.states.get("button.identify") + assert state + assert state.state == "2021-11-13T11:48:00+00:00" + + +async def test_button_identify_error( + hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, caplog +) -> None: + """Test an error occurs with the Elgato identify button.""" + await init_integration(hass, aioclient_mock) + + with patch( + "homeassistant.components.elgato.light.Elgato.identify", + side_effect=ElgatoError, + ) as mock_identify: + await hass.services.async_call( + BUTTON_DOMAIN, + SERVICE_PRESS, + {ATTR_ENTITY_ID: "button.identify"}, + blocking=True, + ) + + await hass.async_block_till_done() + assert len(mock_identify.mock_calls) == 1 + assert "An error occurred while identifying the Elgato Light" in caplog.text