diff --git a/homeassistant/components/nam/__init__.py b/homeassistant/components/nam/__init__.py index 98152956fb5..094c286b931 100644 --- a/homeassistant/components/nam/__init__.py +++ b/homeassistant/components/nam/__init__.py @@ -42,7 +42,7 @@ from .const import ( _LOGGER = logging.getLogger(__name__) -PLATFORMS = ["sensor"] +PLATFORMS = ["button", "sensor"] async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: diff --git a/homeassistant/components/nam/button.py b/homeassistant/components/nam/button.py new file mode 100644 index 00000000000..3a205606ccc --- /dev/null +++ b/homeassistant/components/nam/button.py @@ -0,0 +1,58 @@ +"""Support for the Nettigo Air Monitor service.""" +from __future__ import annotations + +import logging + +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_platform import AddEntitiesCallback +from homeassistant.helpers.update_coordinator import CoordinatorEntity + +from . import NAMDataUpdateCoordinator +from .const import DEFAULT_NAME, DOMAIN + +PARALLEL_UPDATES = 1 + +_LOGGER = logging.getLogger(__name__) + +RESTART_BUTTON: ButtonEntityDescription = ButtonEntityDescription( + key="restart", + name=f"{DEFAULT_NAME} Restart", + icon="mdi:restart", + entity_category=ENTITY_CATEGORY_CONFIG, +) + + +async def async_setup_entry( + hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback +) -> None: + """Add a Nettigo Air Monitor entities from a config_entry.""" + coordinator: NAMDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id] + + buttons: list[NAMButton] = [] + buttons.append(NAMButton(coordinator, RESTART_BUTTON)) + + async_add_entities(buttons, False) + + +class NAMButton(CoordinatorEntity, ButtonEntity): + """Define an Nettigo Air Monitor button.""" + + coordinator: NAMDataUpdateCoordinator + + def __init__( + self, + coordinator: NAMDataUpdateCoordinator, + description: ButtonEntityDescription, + ) -> None: + """Initialize.""" + super().__init__(coordinator) + self._attr_device_info = coordinator.device_info + self._attr_unique_id = f"{coordinator.unique_id}-{description.key}" + self.entity_description = description + + async def async_press(self) -> None: + """Triggers the restart.""" + await self.coordinator.nam.async_restart() diff --git a/tests/components/nam/test_button.py b/tests/components/nam/test_button.py new file mode 100644 index 00000000000..7cd731e7584 --- /dev/null +++ b/tests/components/nam/test_button.py @@ -0,0 +1,48 @@ +"""Test button of Nettigo Air Monitor integration.""" +from unittest.mock import patch + +from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN +from homeassistant.const import ATTR_ENTITY_ID, ATTR_ICON, STATE_UNKNOWN +from homeassistant.helpers import entity_registry as er +from homeassistant.util import dt as dt_util + +from tests.components.nam import init_integration + + +async def test_button(hass): + """Test states of the button.""" + registry = er.async_get(hass) + + await init_integration(hass) + + state = hass.states.get("button.nettigo_air_monitor_restart") + assert state + assert state.state == STATE_UNKNOWN + assert state.attributes.get(ATTR_ICON) == "mdi:restart" + + entry = registry.async_get("button.nettigo_air_monitor_restart") + assert entry + assert entry.unique_id == "aa:bb:cc:dd:ee:ff-restart" + + +async def test_button_press(hass): + """Test button press.""" + await init_integration(hass) + + now = dt_util.utcnow() + with patch( + "homeassistant.components.nam.NettigoAirMonitor.async_restart" + ) as mock_restart, patch("homeassistant.core.dt_util.utcnow", return_value=now): + await hass.services.async_call( + BUTTON_DOMAIN, + "press", + {ATTR_ENTITY_ID: "button.nettigo_air_monitor_restart"}, + blocking=True, + ) + await hass.async_block_till_done() + + mock_restart.assert_called_once() + + state = hass.states.get("button.nettigo_air_monitor_restart") + assert state + assert state.state == now.isoformat()