Skip to content

Commit

Permalink
Add button platform to opentherm_gw (home-assistant#125185)
Browse files Browse the repository at this point in the history
* Add button platform to opentherm_gw

* Add tests for button.py

* Update tests/components/opentherm_gw/test_button.py

---------

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
  • Loading branch information
mvn23 and joostlek authored Sep 4, 2024
1 parent bad305d commit 892c32c
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 1 deletion.
2 changes: 1 addition & 1 deletion homeassistant/components/opentherm_gw/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
extra=vol.ALLOW_EXTRA,
)

PLATFORMS = [Platform.BINARY_SENSOR, Platform.CLIMATE, Platform.SENSOR]
PLATFORMS = [Platform.BINARY_SENSOR, Platform.BUTTON, Platform.CLIMATE, Platform.SENSOR]


async def options_updated(hass: HomeAssistant, entry: ConfigEntry) -> None:
Expand Down
73 changes: 73 additions & 0 deletions homeassistant/components/opentherm_gw/button.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"""Support for OpenTherm Gateway buttons."""

from collections.abc import Awaitable, Callable
from dataclasses import dataclass

import pyotgw.vars as gw_vars

from homeassistant.components.button import (
ButtonDeviceClass,
ButtonEntity,
ButtonEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_ID, EntityCategory
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from . import OpenThermGatewayHub
from .const import (
DATA_GATEWAYS,
DATA_OPENTHERM_GW,
GATEWAY_DEVICE_DESCRIPTION,
OpenThermDataSource,
)
from .entity import OpenThermEntity, OpenThermEntityDescription


@dataclass(frozen=True, kw_only=True)
class OpenThermButtonEntityDescription(
ButtonEntityDescription, OpenThermEntityDescription
):
"""Describes an opentherm_gw button entity."""

action: Callable[[OpenThermGatewayHub], Awaitable]


BUTTON_DESCRIPTIONS: tuple[OpenThermButtonEntityDescription, ...] = (
OpenThermButtonEntityDescription(
key="restart_button",
device_class=ButtonDeviceClass.RESTART,
device_description=GATEWAY_DEVICE_DESCRIPTION,
action=lambda hub: hub.gateway.set_mode(gw_vars.OTGW_MODE_RESET),
),
)


async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the OpenTherm Gateway buttons."""
gw_hub = hass.data[DATA_OPENTHERM_GW][DATA_GATEWAYS][config_entry.data[CONF_ID]]

async_add_entities(
OpenThermButton(gw_hub, description) for description in BUTTON_DESCRIPTIONS
)


class OpenThermButton(OpenThermEntity, ButtonEntity):
"""Representation of an OpenTherm button."""

_attr_entity_category = EntityCategory.CONFIG
entity_description: OpenThermButtonEntityDescription

@callback
def receive_report(self, status: dict[OpenThermDataSource, dict]) -> None:
"""Handle status updates from the component."""
# We don't need any information from the reports here

async def async_press(self) -> None:
"""Perform button action."""
await self.entity_description.action(self._gateway)
50 changes: 50 additions & 0 deletions tests/components/opentherm_gw/test_button.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""Test opentherm_gw buttons."""

from unittest.mock import AsyncMock, MagicMock

from pyotgw.vars import OTGW_MODE_RESET

from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN, SERVICE_PRESS
from homeassistant.components.opentherm_gw import DOMAIN as OPENTHERM_DOMAIN
from homeassistant.components.opentherm_gw.const import OpenThermDeviceIdentifier
from homeassistant.const import ATTR_ENTITY_ID, CONF_ID
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er

from .conftest import MINIMAL_STATUS

from tests.common import MockConfigEntry


async def test_restart_button(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
mock_config_entry: MockConfigEntry,
mock_pyotgw: MagicMock,
) -> None:
"""Test restart button."""

mock_pyotgw.return_value.set_mode = AsyncMock(return_value=MINIMAL_STATUS)
mock_config_entry.add_to_hass(hass)

await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()

assert (
button_entity_id := entity_registry.async_get_entity_id(
BUTTON_DOMAIN,
OPENTHERM_DOMAIN,
f"{mock_config_entry.data[CONF_ID]}-{OpenThermDeviceIdentifier.GATEWAY}-restart_button",
)
) is not None

await hass.services.async_call(
BUTTON_DOMAIN,
SERVICE_PRESS,
{
ATTR_ENTITY_ID: button_entity_id,
},
blocking=True,
)

mock_pyotgw.return_value.set_mode.assert_awaited_once_with(OTGW_MODE_RESET)

0 comments on commit 892c32c

Please sign in to comment.