Add oven stop button to SmartThings (#141142)

This commit is contained in:
Joost Lekkerkerker 2025-03-22 19:51:41 +01:00 committed by GitHub
parent 99d0449cbe
commit b47d3076cc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 284 additions and 0 deletions

View File

@ -79,6 +79,7 @@ type SmartThingsConfigEntry = ConfigEntry[SmartThingsData]
PLATFORMS = [
Platform.BINARY_SENSOR,
Platform.BUTTON,
Platform.CLIMATE,
Platform.COVER,
Platform.EVENT,

View File

@ -0,0 +1,75 @@
"""Support for button entities through the SmartThings cloud API."""
from __future__ import annotations
from dataclasses import dataclass
from pysmartthings import Capability, Command, SmartThings
from homeassistant.components.button import ButtonEntity, ButtonEntityDescription
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from . import FullDevice, SmartThingsConfigEntry
from .const import MAIN
from .entity import SmartThingsEntity
@dataclass(frozen=True, kw_only=True)
class SmartThingsButtonDescription(ButtonEntityDescription):
"""Class describing SmartThings button entities."""
key: Capability
command: Command
CAPABILITIES_TO_BUTTONS: dict[Capability | str, SmartThingsButtonDescription] = {
Capability.OVEN_OPERATING_STATE: SmartThingsButtonDescription(
key=Capability.OVEN_OPERATING_STATE,
translation_key="stop",
command=Command.STOP,
),
}
async def async_setup_entry(
hass: HomeAssistant,
entry: SmartThingsConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Add button entities for a config entry."""
entry_data = entry.runtime_data
async_add_entities(
SmartThingsButtonEntity(
entry_data.client, device, CAPABILITIES_TO_BUTTONS[capability]
)
for device in entry_data.devices.values()
for capability in device.status[MAIN]
if capability in CAPABILITIES_TO_BUTTONS
)
class SmartThingsButtonEntity(SmartThingsEntity, ButtonEntity):
"""Define a SmartThings button."""
entity_description: SmartThingsButtonDescription
def __init__(
self,
client: SmartThings,
device: FullDevice,
entity_description: SmartThingsButtonDescription,
) -> None:
"""Initialize the instance."""
super().__init__(client, device, set())
self.entity_description = entity_description
self._attr_unique_id = (
f"{device.device.device_id}_{MAIN}_{entity_description.key}"
)
async def async_press(self) -> None:
"""Press the button."""
await self.execute_device_command(
self.entity_description.key,
self.entity_description.command,
)

View File

@ -14,6 +14,11 @@
}
}
},
"button": {
"stop": {
"default": "mdi:stop"
}
},
"number": {
"washer_rinse_cycles": {
"default": "mdi:waves-arrow-up"

View File

@ -46,6 +46,11 @@
"name": "Valve"
}
},
"button": {
"stop": {
"name": "Stop"
}
},
"event": {
"button": {
"state": {

View File

@ -0,0 +1,142 @@
# serializer version: 1
# name: test_all_entities[da_ks_microwave_0101x][button.microwave_stop-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'button',
'entity_category': None,
'entity_id': 'button.microwave_stop',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Stop',
'platform': 'smartthings',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'stop',
'unique_id': '2bad3237-4886-e699-1b90-4a51a3d55c8a_main_ovenOperatingState',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[da_ks_microwave_0101x][button.microwave_stop-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Microwave Stop',
}),
'context': <ANY>,
'entity_id': 'button.microwave_stop',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_all_entities[da_ks_oven_01061][button.oven_stop-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'button',
'entity_category': None,
'entity_id': 'button.oven_stop',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Stop',
'platform': 'smartthings',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'stop',
'unique_id': '9447959a-0dfa-6b27-d40d-650da525c53f_main_ovenOperatingState',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[da_ks_oven_01061][button.oven_stop-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Oven Stop',
}),
'context': <ANY>,
'entity_id': 'button.oven_stop',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_all_entities[da_ks_range_0101x][button.vulcan_stop-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'button',
'entity_category': None,
'entity_id': 'button.vulcan_stop',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Stop',
'platform': 'smartthings',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'stop',
'unique_id': '2c3cbaa0-1899-5ddc-7b58-9d657bd48f18_main_ovenOperatingState',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[da_ks_range_0101x][button.vulcan_stop-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Vulcan Stop',
}),
'context': <ANY>,
'entity_id': 'button.vulcan_stop',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---

View File

@ -0,0 +1,56 @@
"""Test for the SmartThings button platform."""
from unittest.mock import AsyncMock
from freezegun.api import FrozenDateTimeFactory
from pysmartthings import Capability, Command
import pytest
from syrupy import SnapshotAssertion
from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN, SERVICE_PRESS
from homeassistant.components.smartthings import MAIN
from homeassistant.const import ATTR_ENTITY_ID, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from . import setup_integration, snapshot_smartthings_entities
from tests.common import MockConfigEntry
async def test_all_entities(
hass: HomeAssistant,
snapshot: SnapshotAssertion,
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
entity_registry: er.EntityRegistry,
) -> None:
"""Test all entities."""
await setup_integration(hass, mock_config_entry)
snapshot_smartthings_entities(hass, entity_registry, snapshot, Platform.BUTTON)
@pytest.mark.parametrize("device_fixture", ["da_ks_microwave_0101x"])
async def test_press(
hass: HomeAssistant,
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test state update."""
await setup_integration(hass, mock_config_entry)
freezer.move_to("2023-10-21")
await hass.services.async_call(
BUTTON_DOMAIN,
SERVICE_PRESS,
{ATTR_ENTITY_ID: "button.microwave_stop"},
blocking=True,
)
devices.execute_device_command.assert_called_once_with(
"2bad3237-4886-e699-1b90-4a51a3d55c8a",
Capability.OVEN_OPERATING_STATE,
Command.STOP,
MAIN,
)