Compare commits

...

1 Commits

Author SHA1 Message Date
e4eeb2a97b Add automatic script reload support
Features:
- Listen for scripts_changed WebSocket messages
- Automatically reload integration when scripts change
- New on_scripts_changed callback in WebSocket client
- Seamless button entity updates without manual reload

Technical changes:
- Enhanced MediaServerWebSocket with scripts_changed handler
- Updated MediaPlayerCoordinator to trigger integration reload
- Pass config entry to coordinator for reload capability

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-06 03:53:35 +03:00
2 changed files with 23 additions and 0 deletions

View File

@@ -307,6 +307,7 @@ class MediaServerWebSocket:
token: str,
on_status_update: Callable[[dict[str, Any]], None],
on_disconnect: Callable[[], None] | None = None,
on_scripts_changed: Callable[[], None] | None = None,
) -> None:
"""Initialize the WebSocket client.
@@ -316,12 +317,14 @@ class MediaServerWebSocket:
token: API authentication token
on_status_update: Callback when status update received
on_disconnect: Callback when connection lost
on_scripts_changed: Callback when scripts have changed
"""
self._host = host
self._port = int(port)
self._token = token
self._on_status_update = on_status_update
self._on_disconnect = on_disconnect
self._on_scripts_changed = on_scripts_changed
self._ws_url = f"ws://{host}:{self._port}/api/media/ws?token={token}"
self._session: aiohttp.ClientSession | None = None
self._ws: aiohttp.ClientWebSocketResponse | None = None
@@ -401,6 +404,10 @@ class MediaServerWebSocket:
f"{status_data['album_art_url']}?token={self._token}&t={track_hash}"
)
self._on_status_update(status_data)
elif msg_type == "scripts_changed":
_LOGGER.info("Scripts changed notification received")
if self._on_scripts_changed:
self._on_scripts_changed()
elif msg_type == "pong":
_LOGGER.debug("Received pong")

View File

@@ -82,6 +82,7 @@ async def async_setup_entry(
port=entry.data[CONF_PORT],
token=entry.data[CONF_TOKEN],
use_websocket=use_websocket,
entry=entry,
)
# Set up WebSocket connection if enabled
@@ -118,6 +119,7 @@ class MediaPlayerCoordinator(DataUpdateCoordinator[dict[str, Any]]):
port: int,
token: str,
use_websocket: bool = True,
entry: ConfigEntry | None = None,
) -> None:
"""Initialize the coordinator.
@@ -129,6 +131,7 @@ class MediaPlayerCoordinator(DataUpdateCoordinator[dict[str, Any]]):
port: Server port
token: API token
use_websocket: Whether to use WebSocket for updates
entry: Config entry (for integration reload on scripts change)
"""
super().__init__(
hass,
@@ -141,6 +144,7 @@ class MediaPlayerCoordinator(DataUpdateCoordinator[dict[str, Any]]):
self._port = port
self._token = token
self._use_websocket = use_websocket
self._entry = entry
self._ws_client: MediaServerWebSocket | None = None
self._ws_connected = False
self._reconnect_task: asyncio.Task | None = None
@@ -162,6 +166,7 @@ class MediaPlayerCoordinator(DataUpdateCoordinator[dict[str, Any]]):
token=self._token,
on_status_update=self._handle_ws_status_update,
on_disconnect=self._handle_ws_disconnect,
on_scripts_changed=self._handle_ws_scripts_changed,
)
if await self._ws_client.connect():
@@ -192,6 +197,17 @@ class MediaPlayerCoordinator(DataUpdateCoordinator[dict[str, Any]]):
# Schedule reconnect attempt
self._schedule_reconnect()
@callback
def _handle_ws_scripts_changed(self) -> None:
"""Handle scripts changed notification from WebSocket."""
if self._entry:
_LOGGER.info("Scripts changed, reloading integration")
self.hass.async_create_task(
self.hass.config_entries.async_reload(self._entry.entry_id)
)
else:
_LOGGER.warning("Cannot reload integration: entry not available")
def _schedule_reconnect(self) -> None:
"""Schedule a WebSocket reconnection attempt."""
if self._reconnect_task and not self._reconnect_task.done():