Add button platform to Dremel 3D printer (#94517)

Co-authored-by: Franck Nijhof <git@frenck.dev>
This commit is contained in:
Robert Hillis 2023-06-27 11:44:29 -04:00 committed by GitHub
parent 3e85a29b86
commit cd26de73b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 146 additions and 1 deletions

View File

@ -12,7 +12,7 @@ from homeassistant.exceptions import ConfigEntryNotReady
from .const import CAMERA_MODEL, DOMAIN
from .coordinator import Dremel3DPrinterDataUpdateCoordinator
PLATFORMS = [Platform.BINARY_SENSOR, Platform.CAMERA, Platform.SENSOR]
PLATFORMS = [Platform.BINARY_SENSOR, Platform.BUTTON, Platform.CAMERA, Platform.SENSOR]
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:

View File

@ -0,0 +1,78 @@
"""Support for Dremel 3D Printer buttons."""
from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from dremel3dpy import Dremel3DPrinter
from homeassistant.components.button import ButtonEntity, ButtonEntityDescription
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN
from .entity import Dremel3DPrinterEntity
@dataclass
class Dremel3DPrinterButtonEntityMixin:
"""Mixin for required keys."""
press_fn: Callable[[Dremel3DPrinter], None]
@dataclass
class Dremel3DPrinterButtonEntityDescription(
ButtonEntityDescription, Dremel3DPrinterButtonEntityMixin
):
"""Describes a Dremel 3D Printer button entity."""
BUTTON_TYPES: tuple[Dremel3DPrinterButtonEntityDescription, ...] = (
Dremel3DPrinterButtonEntityDescription(
key="cancel_job",
translation_key="cancel_job",
press_fn=lambda api: api.stop_print(),
),
Dremel3DPrinterButtonEntityDescription(
key="pause_job",
translation_key="pause_job",
press_fn=lambda api: api.pause_print(),
),
Dremel3DPrinterButtonEntityDescription(
key="resume_job",
translation_key="resume_job",
press_fn=lambda api: api.resume_print(),
),
)
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up Dremel 3D Printer control buttons."""
coordinator = hass.data[DOMAIN][config_entry.entry_id]
async_add_entities(
Dremel3DPrinterButtonEntity(coordinator, description)
for description in BUTTON_TYPES
)
class Dremel3DPrinterButtonEntity(Dremel3DPrinterEntity, ButtonEntity):
"""Represent a Dremel 3D Printer button."""
entity_description: Dremel3DPrinterButtonEntityDescription
def press(self) -> None:
"""Handle the button press."""
# api does not care about the current state
try:
self.entity_description.press_fn(self._api)
except RuntimeError as ex:
raise HomeAssistantError(
"An error occurred while submitting command"
) from ex

View File

@ -16,6 +16,17 @@
}
},
"entity": {
"button": {
"cancel_job": {
"name": "Cancel job"
},
"pause_job": {
"name": "Pause job"
},
"resume_job": {
"name": "Resume job"
}
},
"sensor": {
"job_phase": {
"name": "Job phase"

View File

@ -0,0 +1,56 @@
"""Button tests for the Dremel 3D Printer integration."""
from unittest.mock import AsyncMock, patch
import pytest
from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN, SERVICE_PRESS
from homeassistant.components.dremel_3d_printer.const import DOMAIN
from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.setup import async_setup_component
from tests.common import MockConfigEntry
@pytest.mark.parametrize(
("button", "function"),
(
("cancel", "stop"),
("pause", "pause"),
("resume", "resume"),
),
)
async def test_buttons(
hass: HomeAssistant,
connection: None,
config_entry: MockConfigEntry,
entity_registry_enabled_by_default: AsyncMock,
button: str,
function: str,
) -> None:
"""Test button entities function."""
await hass.config_entries.async_setup(config_entry.entry_id)
assert await async_setup_component(hass, DOMAIN, {})
with patch(
f"homeassistant.components.dremel_3d_printer.Dremel3DPrinter.{function}_print"
) as mock:
await hass.services.async_call(
BUTTON_DOMAIN,
SERVICE_PRESS,
{ATTR_ENTITY_ID: [f"button.dremel_3d45_{button}_job"]},
blocking=True,
)
assert mock.call_count == 1
with patch(
f"homeassistant.components.dremel_3d_printer.Dremel3DPrinter.{function}_print",
side_effect=RuntimeError,
) as mock, pytest.raises(HomeAssistantError):
await hass.services.async_call(
BUTTON_DOMAIN,
SERVICE_PRESS,
{ATTR_ENTITY_ID: [f"button.dremel_3d45_{button}_job"]},
blocking=True,
)
assert mock.call_count == 1