Files
alexei.dolgolyov 783771489a Initial commit: HACS-ready Home Assistant integration
Remote Media Player integration for controlling PC media playback
from Home Assistant via the Media Server API.

Features:
- Full media player controls (play, pause, stop, next, previous)
- Volume control and mute
- Seek support with smooth timeline updates
- Real-time updates via WebSocket
- Script buttons for PC control (shutdown, restart, lock, etc.)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 14:40:33 +03:00

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