diff --git a/homeassistant/components/pterodactyl/__init__.py b/homeassistant/components/pterodactyl/__init__.py index 5712c1bdd58..c0e23b271d1 100644 --- a/homeassistant/components/pterodactyl/__init__.py +++ b/homeassistant/components/pterodactyl/__init__.py @@ -7,7 +7,7 @@ from homeassistant.core import HomeAssistant from .coordinator import PterodactylConfigEntry, PterodactylCoordinator -_PLATFORMS: list[Platform] = [Platform.BINARY_SENSOR, Platform.SENSOR] +_PLATFORMS: list[Platform] = [Platform.BINARY_SENSOR, Platform.BUTTON, Platform.SENSOR] async def async_setup_entry(hass: HomeAssistant, entry: PterodactylConfigEntry) -> bool: diff --git a/homeassistant/components/pterodactyl/api.py b/homeassistant/components/pterodactyl/api.py index aadb3261db0..a60962ecf51 100644 --- a/homeassistant/components/pterodactyl/api.py +++ b/homeassistant/components/pterodactyl/api.py @@ -1,6 +1,7 @@ """API module of the Pterodactyl integration.""" from dataclasses import dataclass +from enum import StrEnum import logging from pydactyl import PterodactylClient @@ -43,6 +44,15 @@ class PterodactylData: uptime: int +class PterodactylCommand(StrEnum): + """Command enum for the Pterodactyl server.""" + + START_SERVER = "start" + STOP_SERVER = "stop" + RESTART_SERVER = "restart" + FORCE_STOP_SERVER = "kill" + + class PterodactylAPI: """Wrapper for Pterodactyl's API.""" @@ -124,3 +134,20 @@ class PterodactylAPI: _LOGGER.debug("%s", data[identifier]) return data + + async def async_send_command( + self, identifier: str, command: PterodactylCommand + ) -> None: + """Send a command to the Pterodactyl server.""" + try: + await self.hass.async_add_executor_job( + self.pterodactyl.client.servers.send_power_action, # type: ignore[union-attr] + identifier, + command, + ) + except ( + PydactylError, + BadRequestError, + PterodactylApiError, + ) as error: + raise PterodactylConnectionError(error) from error diff --git a/homeassistant/components/pterodactyl/button.py b/homeassistant/components/pterodactyl/button.py new file mode 100644 index 00000000000..a1201f3ced5 --- /dev/null +++ b/homeassistant/components/pterodactyl/button.py @@ -0,0 +1,98 @@ +"""Button platform for the Pterodactyl integration.""" + +from __future__ import annotations + +from dataclasses import dataclass + +from homeassistant.components.button import ButtonEntity, ButtonEntityDescription +from homeassistant.core import HomeAssistant +from homeassistant.exceptions import HomeAssistantError +from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback + +from .api import PterodactylCommand, PterodactylConnectionError +from .coordinator import PterodactylConfigEntry, PterodactylCoordinator +from .entity import PterodactylEntity + +KEY_START_SERVER = "start_server" +KEY_STOP_SERVER = "stop_server" +KEY_RESTART_SERVER = "restart_server" +KEY_FORCE_STOP_SERVER = "force_stop_server" + +# Coordinator is used to centralize the data updates. +PARALLEL_UPDATES = 0 + + +@dataclass(frozen=True, kw_only=True) +class PterodactylButtonEntityDescription(ButtonEntityDescription): + """Class describing Pterodactyl button entities.""" + + command: PterodactylCommand + + +BUTTON_DESCRIPTIONS = [ + PterodactylButtonEntityDescription( + key=KEY_START_SERVER, + translation_key=KEY_START_SERVER, + command=PterodactylCommand.START_SERVER, + ), + PterodactylButtonEntityDescription( + key=KEY_STOP_SERVER, + translation_key=KEY_STOP_SERVER, + command=PterodactylCommand.STOP_SERVER, + ), + PterodactylButtonEntityDescription( + key=KEY_RESTART_SERVER, + translation_key=KEY_RESTART_SERVER, + command=PterodactylCommand.RESTART_SERVER, + ), + PterodactylButtonEntityDescription( + key=KEY_FORCE_STOP_SERVER, + translation_key=KEY_FORCE_STOP_SERVER, + command=PterodactylCommand.FORCE_STOP_SERVER, + entity_registry_enabled_default=False, + ), +] + + +async def async_setup_entry( + hass: HomeAssistant, + config_entry: PterodactylConfigEntry, + async_add_entities: AddConfigEntryEntitiesCallback, +) -> None: + """Set up the Pterodactyl button platform.""" + coordinator = config_entry.runtime_data + + async_add_entities( + PterodactylButtonEntity(coordinator, identifier, description, config_entry) + for identifier in coordinator.api.identifiers + for description in BUTTON_DESCRIPTIONS + ) + + +class PterodactylButtonEntity(PterodactylEntity, ButtonEntity): + """Representation of a Pterodactyl button entity.""" + + entity_description: PterodactylButtonEntityDescription + + def __init__( + self, + coordinator: PterodactylCoordinator, + identifier: str, + description: PterodactylButtonEntityDescription, + config_entry: PterodactylConfigEntry, + ) -> None: + """Initialize the button entity.""" + super().__init__(coordinator, identifier, config_entry) + self.entity_description = description + self._attr_unique_id = f"{self.game_server_data.uuid}_{description.key}" + + async def async_press(self) -> None: + """Handle the button press.""" + try: + await self.coordinator.api.async_send_command( + self.identifier, self.entity_description.command + ) + except PterodactylConnectionError as err: + raise HomeAssistantError( + f"Failed to send action '{self.entity_description.key}'" + ) from err diff --git a/homeassistant/components/pterodactyl/icons.json b/homeassistant/components/pterodactyl/icons.json index 245bdd7dbe5..265a8dcadda 100644 --- a/homeassistant/components/pterodactyl/icons.json +++ b/homeassistant/components/pterodactyl/icons.json @@ -1,5 +1,19 @@ { "entity": { + "button": { + "start_server": { + "default": "mdi:play" + }, + "stop_server": { + "default": "mdi:stop" + }, + "restart_server": { + "default": "mdi:refresh" + }, + "force_stop_server": { + "default": "mdi:flash-alert" + } + }, "sensor": { "cpu_utilization": { "default": "mdi:cpu-64-bit" diff --git a/homeassistant/components/pterodactyl/strings.json b/homeassistant/components/pterodactyl/strings.json index 9f1feef388c..97b33566f39 100644 --- a/homeassistant/components/pterodactyl/strings.json +++ b/homeassistant/components/pterodactyl/strings.json @@ -26,6 +26,20 @@ "name": "Status" } }, + "button": { + "start_server": { + "name": "Start server" + }, + "stop_server": { + "name": "Stop server" + }, + "restart_server": { + "name": "Restart server" + }, + "force_stop_server": { + "name": "Force stop server" + } + }, "sensor": { "cpu_utilization": { "name": "CPU utilization"