Add button platform to Pterodactyl (#141910)

* Add button platform to Pterodactyl

* Fix parameter order of send_power_action, remove _attr_has_entity_name from button

* Rename PterodactylCommands to PterodactylCommand
This commit is contained in:
elmurato 2025-03-31 17:53:08 +02:00 committed by GitHub
parent 64994277b1
commit 94884d33db
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 154 additions and 1 deletions

View File

@ -7,7 +7,7 @@ from homeassistant.core import HomeAssistant
from .coordinator import PterodactylConfigEntry, PterodactylCoordinator 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: async def async_setup_entry(hass: HomeAssistant, entry: PterodactylConfigEntry) -> bool:

View File

@ -1,6 +1,7 @@
"""API module of the Pterodactyl integration.""" """API module of the Pterodactyl integration."""
from dataclasses import dataclass from dataclasses import dataclass
from enum import StrEnum
import logging import logging
from pydactyl import PterodactylClient from pydactyl import PterodactylClient
@ -43,6 +44,15 @@ class PterodactylData:
uptime: int 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: class PterodactylAPI:
"""Wrapper for Pterodactyl's API.""" """Wrapper for Pterodactyl's API."""
@ -124,3 +134,20 @@ class PterodactylAPI:
_LOGGER.debug("%s", data[identifier]) _LOGGER.debug("%s", data[identifier])
return data 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

View File

@ -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

View File

@ -1,5 +1,19 @@
{ {
"entity": { "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": { "sensor": {
"cpu_utilization": { "cpu_utilization": {
"default": "mdi:cpu-64-bit" "default": "mdi:cpu-64-bit"

View File

@ -26,6 +26,20 @@
"name": "Status" "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": { "sensor": {
"cpu_utilization": { "cpu_utilization": {
"name": "CPU utilization" "name": "CPU utilization"