Split monorepo into separate units for future independent repositories: - media-server/: Standalone FastAPI server with own README, requirements, config example, and CLAUDE.md - haos-integration/: HACS-ready Home Assistant integration with hacs.json, own README, and CLAUDE.md Both components now have their own .gitignore files and can be easily extracted into separate repositories. Also adds custom icon support for scripts configuration. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
135 lines
4.3 KiB
Python
135 lines
4.3 KiB
Python
"""Button platform for Remote Media Player integration."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from typing import Any
|
|
|
|
from homeassistant.components.button import ButtonEntity
|
|
from homeassistant.config_entries import ConfigEntry
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.helpers.entity import DeviceInfo
|
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|
|
|
from .api_client import MediaServerClient, MediaServerError
|
|
from .const import DOMAIN
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistant,
|
|
entry: ConfigEntry,
|
|
async_add_entities: AddEntitiesCallback,
|
|
) -> None:
|
|
"""Set up script buttons from a config entry."""
|
|
client: MediaServerClient = hass.data[DOMAIN][entry.entry_id]["client"]
|
|
|
|
try:
|
|
scripts = await client.list_scripts()
|
|
except MediaServerError as err:
|
|
_LOGGER.error("Failed to fetch scripts list: %s", err)
|
|
return
|
|
|
|
entities = [
|
|
ScriptButtonEntity(
|
|
client=client,
|
|
entry=entry,
|
|
script_name=script["name"],
|
|
script_label=script["label"],
|
|
script_description=script.get("description", ""),
|
|
script_icon=script.get("icon"),
|
|
)
|
|
for script in scripts
|
|
]
|
|
|
|
if entities:
|
|
async_add_entities(entities)
|
|
_LOGGER.info("Added %d script button entities", len(entities))
|
|
|
|
|
|
class ScriptButtonEntity(ButtonEntity):
|
|
"""Button entity for executing a script on the media server."""
|
|
|
|
_attr_has_entity_name = True
|
|
|
|
def __init__(
|
|
self,
|
|
client: MediaServerClient,
|
|
entry: ConfigEntry,
|
|
script_name: str,
|
|
script_label: str,
|
|
script_description: str,
|
|
script_icon: str | None = None,
|
|
) -> None:
|
|
"""Initialize the script button."""
|
|
self._client = client
|
|
self._entry = entry
|
|
self._script_name = script_name
|
|
self._script_label = script_label
|
|
self._script_description = script_description
|
|
|
|
# Entity attributes
|
|
self._attr_unique_id = f"{entry.entry_id}_script_{script_name}"
|
|
self._attr_name = script_label
|
|
# Use custom icon if provided, otherwise auto-resolve from script name
|
|
self._attr_icon = script_icon or self._get_icon_for_script(script_name)
|
|
|
|
def _get_icon_for_script(self, script_name: str) -> str:
|
|
"""Get an appropriate icon based on script name."""
|
|
icon_map = {
|
|
"lock": "mdi:lock",
|
|
"unlock": "mdi:lock-open",
|
|
"shutdown": "mdi:power",
|
|
"restart": "mdi:restart",
|
|
"sleep": "mdi:sleep",
|
|
"hibernate": "mdi:power-sleep",
|
|
"cancel": "mdi:cancel",
|
|
}
|
|
|
|
script_lower = script_name.lower()
|
|
for keyword, icon in icon_map.items():
|
|
if keyword in script_lower:
|
|
return icon
|
|
|
|
return "mdi:script-text"
|
|
|
|
@property
|
|
def device_info(self) -> DeviceInfo:
|
|
"""Return device info."""
|
|
return DeviceInfo(
|
|
identifiers={(DOMAIN, self._entry.entry_id)},
|
|
name=self._entry.title,
|
|
manufacturer="Remote Media Player",
|
|
model="Media Server",
|
|
)
|
|
|
|
@property
|
|
def extra_state_attributes(self) -> dict[str, Any]:
|
|
"""Return extra state attributes."""
|
|
return {
|
|
"script_name": self._script_name,
|
|
"description": self._script_description,
|
|
}
|
|
|
|
async def async_press(self) -> None:
|
|
"""Handle button press - execute the script."""
|
|
_LOGGER.info("Executing script: %s", self._script_name)
|
|
try:
|
|
result = await self._client.execute_script(self._script_name)
|
|
if result.get("success"):
|
|
_LOGGER.info(
|
|
"Script '%s' executed successfully (exit_code=%s)",
|
|
self._script_name,
|
|
result.get("exit_code"),
|
|
)
|
|
else:
|
|
_LOGGER.warning(
|
|
"Script '%s' failed: %s",
|
|
self._script_name,
|
|
result.get("stderr") or result.get("error"),
|
|
)
|
|
except MediaServerError as err:
|
|
_LOGGER.error("Failed to execute script '%s': %s", self._script_name, err)
|
|
raise
|