-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
16 changed files
with
908 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
name: Release | ||
|
||
on: | ||
push: | ||
tags: | ||
- '*' | ||
|
||
jobs: | ||
release_zip_file: | ||
name: Publish HACS zip file asset | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Check out repository | ||
uses: actions/checkout@v4 | ||
|
||
- name: Compress Custom Component | ||
run: | | ||
cd ${{ github.workspace }}/custom_components/pterodactyl-panel | ||
zip pterodactyl-panel.zip -r ./ | ||
- uses: ncipollo/[email protected] | ||
with: | ||
allowUpdates: true | ||
generateReleaseNotes: true | ||
artifacts: ${{ github.workspace }}/custom_components/pterodactyl-panel/pterodactyl-panel.zip |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
name: Validate | ||
|
||
on: | ||
push: | ||
branches: | ||
- main | ||
pull_request: | ||
schedule: | ||
- cron: "0 0 * * *" | ||
workflow_dispatch: | ||
|
||
jobs: | ||
validate-hacs: | ||
runs-on: "ubuntu-latest" | ||
steps: | ||
- uses: "actions/checkout@v4" | ||
- name: HACS validation | ||
uses: "hacs/action@main" | ||
with: | ||
category: "integration" | ||
|
||
validate-ha: | ||
runs-on: "ubuntu-latest" | ||
steps: | ||
- uses: "actions/checkout@v4" | ||
- uses: "home-assistant/actions/hassfest@master" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
.env | ||
.venv | ||
env/ | ||
venv/ | ||
ENV/ | ||
env.bak/ | ||
venv.bak/ | ||
virt-env | ||
|
||
__pycache__/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
[![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/tjleach98/homeassistant-pterodactyl-panel/.github%2Fworkflows%2Fvalidate.yml?style=flat-square&label=validate)](https://github.com/tjleach98/homeassistant-pterodactyl-panel/actions/workflows/validate.yml) | ||
[![GitHub Release](https://img.shields.io/github/release/tjleach98/homeassistant-pterodactyl-panel.svg?style=flat-square)](https://github.com/tjleach98/homeassistant-pterodactyl-panel/releases) | ||
[![GitHub](https://img.shields.io/github/license/tjleach98/homeassistant-pterodactyl-panel.svg?style=flat-square)](LICENSE) | ||
[![Downloads](https://img.shields.io/github/downloads/tjleach98/homeassistant-pterodactyl-panel/total?style=flat-square)](https://github.com/tjleach98/homeassistant-pterodactyl-panel/releases) | ||
|
||
# Pterodactyl Panel Home Assistant Integration | ||
This is a basic Home Assistant integration for the [Pterodactyl Panel](https://pterodactyl.io/). It uses the `py-dactyl` library available [here](https://github.com/iamkubi/pydactyl) | ||
|
||
## Influence | ||
The source code for this project is influenced by the [Proxmox VE](https://github.com/dougiteixeira/proxmoxve) integration. | ||
|
||
## Installation | ||
### Manual | ||
Place the entire `custom_components/pterodactyl-panel` folder in this repo inside the `config/custom_components/` folder of your Home Assistant instance. | ||
|
||
If `custom_components` doesn't exist, create it. Click [here](https://developers.home-assistant.io/docs/creating_integration_file_structure/#where-home-assistant-looks-for-integrations) for more details. | ||
|
||
Once the files are in place, restart Home Assistant and the integration should be available. | ||
|
||
### HACS | ||
Add this repository to HACS as a custom repository. Details for this can be found [here](https://hacs.xyz/docs/faq/custom_repositories). | ||
|
||
## Setup | ||
Go to Account Settings -> API Credentials -> Create API Key. | ||
|
||
## Currently Available Sensors | ||
### Button | ||
#### Server | ||
- Start | ||
- Stop | ||
- Restart | ||
|
||
### Binary Sensor | ||
#### Server | ||
- Is Running | ||
- Is Under Maintenance | ||
|
||
### Sensor | ||
#### Server | ||
- Absolute CPU Usage | ||
- Current State | ||
- Disk Usage | ||
- Memory Usage | ||
- Network Upload/Download | ||
- Current Node | ||
- Uptime |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
"""Custom integration to integrate the Pterodactyl Panel with Home Assistant.""" | ||
|
||
from __future__ import annotations | ||
|
||
import logging | ||
from typing import Final | ||
|
||
from pydactyl import PterodactylClient | ||
from pydactyl.exceptions import ClientConfigError | ||
from pydactyl.responses import PaginatedResponse | ||
from requests.exceptions import HTTPError | ||
|
||
from homeassistant.config_entries import ConfigEntry | ||
from homeassistant.const import CONF_API_KEY, CONF_HOST, Platform | ||
from homeassistant.core import HomeAssistant | ||
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady | ||
|
||
from .const import DOMAIN, PTERODACTYL_ATTRIBUTES | ||
from .coordinator import PterodactylServerCoordinator | ||
|
||
_LOGGER: logging.Logger = logging.getLogger(__package__) | ||
|
||
PLATFORMS: Final[list[str]] = [Platform.BINARY_SENSOR, Platform.BUTTON, Platform.SENSOR] | ||
|
||
STARTUP_MESSAGE: Final = f"Starting setup for {DOMAIN}" | ||
|
||
|
||
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool: | ||
"""Set up Pterodactyl Panel from a config entry.""" | ||
if hass.data.get(DOMAIN) is None: | ||
hass.data.setdefault(DOMAIN, {}) | ||
_LOGGER.info(STARTUP_MESSAGE) | ||
|
||
url = config_entry.data.get(CONF_HOST) | ||
api_key = config_entry.data.get(CONF_API_KEY) | ||
|
||
try: | ||
pterodactyl_api = PterodactylClient(url, api_key) | ||
await hass.async_add_executor_job(pterodactyl_api.client.account.get_account) | ||
except ClientConfigError as exception: | ||
raise ConfigEntryAuthFailed from exception | ||
except HTTPError as exception: | ||
if exception.response.status_code == 401: | ||
raise ConfigEntryAuthFailed from exception | ||
|
||
raise ConfigEntryNotReady from exception | ||
|
||
coordinators: list[PterodactylServerCoordinator] = [] | ||
|
||
server_list_pages: PaginatedResponse = await hass.async_add_executor_job( | ||
pterodactyl_api.client.servers.list_servers | ||
) | ||
server_list_data = server_list_pages.data | ||
|
||
# Get all servers if more than one page. | ||
if server_list_pages.meta['pagination']['total_pages'] > 1: | ||
server_list_data = await hass.async_add_executor_job(server_list_pages.collect) | ||
|
||
servers = [server_data[PTERODACTYL_ATTRIBUTES] for server_data in server_list_data] | ||
|
||
for server in servers: | ||
coordinator_server = PterodactylServerCoordinator( | ||
hass=hass, entry=config_entry, client=pterodactyl_api, server=server | ||
) | ||
await coordinator_server.async_refresh() | ||
coordinators.append(coordinator_server) | ||
|
||
config_entry.runtime_data = coordinators | ||
|
||
await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS) | ||
|
||
return True | ||
|
||
|
||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: | ||
"""Unload a config entry.""" | ||
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS) | ||
|
||
|
||
async def async_reload_entry(hass: HomeAssistant, entry: ConfigEntry) -> None: | ||
"""Reload config entry.""" | ||
await async_unload_entry(hass, entry) | ||
await async_setup_entry(hass, entry) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
"""Binary Sensor for the Pterodactyl Panel.""" | ||
|
||
from collections.abc import Callable | ||
from dataclasses import dataclass | ||
from typing import Final | ||
|
||
from homeassistant.components.binary_sensor import ( | ||
BinarySensorDeviceClass, | ||
BinarySensorEntity, | ||
BinarySensorEntityDescription, | ||
) | ||
from homeassistant.config_entries import ConfigEntry | ||
from homeassistant.core import HomeAssistant | ||
from homeassistant.helpers.entity_platform import AddEntitiesCallback | ||
|
||
from .entity import PterodactylEntity, PterodactylEntityDescription | ||
|
||
|
||
@dataclass(frozen=True, kw_only=True) | ||
class PterodactylBinarySensorEntityDescription( | ||
PterodactylEntityDescription, BinarySensorEntityDescription | ||
): | ||
"""Class describing Pterodactyl Panel Binary Sensors.""" | ||
|
||
value_fn: Callable[[str | int | float], str | int | float] = lambda value: value | ||
|
||
|
||
BINARY_SENSORS: Final[list[PterodactylBinarySensorEntityDescription]] = [ | ||
PterodactylBinarySensorEntityDescription( | ||
key="is_node_under_maintenance", | ||
translation_key="pterodactyl_is_node_under_maintenance", | ||
), | ||
PterodactylBinarySensorEntityDescription( | ||
key="is_running", | ||
device_class=BinarySensorDeviceClass.RUNNING, | ||
translation_key="pterodactyl_is_running", | ||
), | ||
] | ||
|
||
|
||
async def async_setup_entry( | ||
hass: HomeAssistant, | ||
config_entry: ConfigEntry, | ||
async_add_entities: AddEntitiesCallback, | ||
) -> None: | ||
"""Set up the Pterodactyl Panel binary sensors.""" | ||
for coordinator in config_entry.runtime_data: | ||
async_add_entities( | ||
[ | ||
PterodactylBinarySensorEntity(coordinator, config_entry, sensor) | ||
for sensor in BINARY_SENSORS | ||
if sensor.key in coordinator.data | ||
] | ||
) | ||
|
||
|
||
class PterodactylBinarySensorEntity(PterodactylEntity, BinarySensorEntity): | ||
"""Represents a Pterodactyl Panel binary sensor.""" | ||
|
||
@property | ||
def is_on(self) -> bool: | ||
"""Return true if the binary sensor is on.""" | ||
val = self.coordinator.data.get(self.entity_description.key) | ||
return self.entity_description.value_fn(val) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
"""Button for the Pterodactyl Panel.""" | ||
|
||
from dataclasses import dataclass | ||
import logging | ||
from typing import Final | ||
|
||
from homeassistant.components.button import ButtonEntity, ButtonEntityDescription | ||
from homeassistant.config_entries import ConfigEntry | ||
from homeassistant.core import HomeAssistant | ||
from homeassistant.exceptions import ServiceValidationError | ||
from homeassistant.helpers.entity_platform import AddEntitiesCallback | ||
|
||
from .entity import PterodactylEntity, PterodactylEntityDescription | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
|
||
|
||
@dataclass | ||
class PterodactylButtonEntityDescription( | ||
PterodactylEntityDescription, ButtonEntityDescription | ||
): | ||
"""Describes Pterodactyl Panel button entity.""" | ||
|
||
|
||
BUTTONS: Final[list[PterodactylButtonEntityDescription]] = [ | ||
PterodactylButtonEntityDescription( | ||
key="server_restart", | ||
translation_key="pterodactyl_server_restart", | ||
), | ||
PterodactylButtonEntityDescription( | ||
key="server_start", | ||
translation_key="pterodactyl_server_start", | ||
), | ||
PterodactylButtonEntityDescription( | ||
key="server_stop", | ||
translation_key="pterodactyl_server_stop", | ||
), | ||
] | ||
|
||
|
||
async def async_setup_entry( | ||
hass: HomeAssistant, | ||
config_entry: ConfigEntry, | ||
async_add_entities: AddEntitiesCallback, | ||
) -> None: | ||
"""Set up the Pterodactyl Panel buttons.""" | ||
for coordinator in config_entry.runtime_data: | ||
async_add_entities( | ||
[ | ||
PterodactylButtonEntity(coordinator, config_entry, button) | ||
for button in BUTTONS | ||
] | ||
) | ||
|
||
|
||
class PterodactylButtonEntity(PterodactylEntity, ButtonEntity): | ||
"""Represents a Pterodactyl Panel button.""" | ||
|
||
async def async_press(self) -> None: | ||
"""Handle the button press.""" | ||
power_action = "" | ||
match self.entity_description.key: | ||
case "server_start": | ||
power_action = "start" | ||
case "server_stop": | ||
power_action = "stop" | ||
case "server_restart": | ||
power_action = "restart" | ||
case _: | ||
raise ServiceValidationError("Button must be start, stop, or restart") | ||
|
||
await self.coordinator.send_power_action(power_action) |
Oops, something went wrong.