1
0
mirror of https://github.com/natekspencer/hacs-oasis_mini.git synced 2025-11-08 05:03:52 -05:00

Add button to play a random track

This commit is contained in:
Nathan Spencer
2024-07-11 11:00:01 -06:00
parent c14e882dc8
commit 21105e497a
4 changed files with 89 additions and 17 deletions

View File

@@ -2,7 +2,9 @@
from __future__ import annotations from __future__ import annotations
from typing import Any, Coroutine from dataclasses import dataclass
import random
from typing import Awaitable, Callable
from homeassistant.components.button import ( from homeassistant.components.button import (
ButtonDeviceClass, ButtonDeviceClass,
@@ -11,31 +13,68 @@ from homeassistant.components.button import (
) )
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import EntityDescription
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN from .const import DOMAIN
from .coordinator import OasisMiniCoordinator from .coordinator import OasisMiniCoordinator
from .entity import OasisMiniEntity from .entity import OasisMiniEntity
from .pyoasismini import OasisMini
from .pyoasismini.const import TRACKS from .pyoasismini.const import TRACKS
class OasisMiniButtonEntity(OasisMiniEntity, ButtonEntity):
"""Oasis Mini button entity."""
async def async_press(self) -> None:
"""Press the button."""
await self.device.async_reboot()
DESCRIPTOR = ButtonEntityDescription(
key="reboot", device_class=ButtonDeviceClass.RESTART
)
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None: ) -> None:
"""Set up Oasis Mini button using config entry.""" """Set up Oasis Mini button using config entry."""
coordinator: OasisMiniCoordinator = hass.data[DOMAIN][entry.entry_id] coordinator: OasisMiniCoordinator = hass.data[DOMAIN][entry.entry_id]
async_add_entities([OasisMiniButtonEntity(coordinator, entry, DESCRIPTOR)]) async_add_entities(
[
OasisMiniButtonEntity(coordinator, entry, descriptor)
for descriptor in DESCRIPTORS
]
)
async def play_random_track(device: OasisMini) -> None:
"""Play random track."""
track = int(random.choice(list(TRACKS)))
if track not in device.playlist:
await device.async_add_track_to_playlist(track)
# Move track to next item in the playlist and then select it
if (idx := device.playlist.index(track)) != (next_idx := device.playlist_index + 1):
await device.async_move_track(idx, next_idx)
await device.async_change_track(next_idx)
await device.async_play()
@dataclass(frozen=True, kw_only=True)
class OasisMiniButtonEntityDescription(ButtonEntityDescription):
"""Oasis Mini button entity description."""
press_fn: Callable[[OasisMini], Awaitable[None]]
DESCRIPTORS = (
OasisMiniButtonEntityDescription(
key="reboot",
device_class=ButtonDeviceClass.RESTART,
press_fn=lambda device: device.async_reboot(),
),
OasisMiniButtonEntityDescription(
key="random_track",
name="Play random track",
press_fn=play_random_track,
),
)
class OasisMiniButtonEntity(OasisMiniEntity, ButtonEntity):
"""Oasis Mini button entity."""
entity_description: OasisMiniButtonEntityDescription
async def async_press(self) -> None:
"""Press the button."""
await self.entity_description.press_fn(self.device)
await self.coordinator.async_request_refresh()

View File

@@ -127,6 +127,11 @@ class OasisMini:
"""Return the url.""" """Return the url."""
return f"http://{self._host}/" return f"http://{self._host}/"
async def async_add_track_to_playlist(self, track: int) -> None:
"""Add track to playlist."""
await self._async_command(params={"ADDJOBLIST": track})
self.playlist.append(track)
async def async_change_track(self, index: int) -> None: async def async_change_track(self, index: int) -> None:
"""Change the track.""" """Change the track."""
if index >= len(self.playlist): if index >= len(self.playlist):
@@ -156,6 +161,10 @@ class OasisMini:
setattr(self, attr, value) setattr(self, attr, value)
return status return status
async def async_move_track(self, _from: int, _to: int) -> None:
"""Move a track in the playlist."""
await self._async_command(params={"MOVEJOB": f"{_from};{_to}"})
async def async_pause(self) -> None: async def async_pause(self) -> None:
"""Send pause command.""" """Send pause command."""
await self._async_command(params={"CMDPAUSE": ""}) await self._async_command(params={"CMDPAUSE": ""})
@@ -264,6 +273,19 @@ class OasisMini:
) )
return response return response
async def async_cloud_get_tracks(self, tracks: list[int]) -> None:
"""Get cloud tracks."""
if not self.access_token:
return
response = await self._async_request(
"GET",
urljoin(CLOUD_BASE_URL, "api/track"),
headers={"Authorization": f"Bearer {self.access_token}"},
params={"ids[]": tracks},
)
return response
async def _async_request(self, method: str, url: str, **kwargs) -> Any: async def _async_request(self, method: str, url: str, **kwargs) -> Any:
"""Login via the cloud.""" """Login via the cloud."""
response = await self._session.request(method, url, **kwargs) response = await self._session.request(method, url, **kwargs)
@@ -283,3 +305,7 @@ class OasisMini:
self._current_track_details = await self.async_cloud_get_track_info( self._current_track_details = await self.async_cloud_get_track_info(
self.current_track_id self.current_track_id
) )
async def async_get_playlist_details(self) -> dict:
"""Get playlist info."""
return await self.async_cloud_get_tracks(self.playlist)

View File

@@ -8,4 +8,4 @@ from typing import Final
__TRACKS_FILE = os.path.join(os.path.dirname(__file__), "tracks.json") __TRACKS_FILE = os.path.join(os.path.dirname(__file__), "tracks.json")
with open(__TRACKS_FILE, "r", encoding="utf8") as file: with open(__TRACKS_FILE, "r", encoding="utf8") as file:
TRACKS: Final[dict[int, dict[str, str]]] = json.load(file) TRACKS: Final[dict[str, dict[str, str]]] = json.load(file)

View File

@@ -4,3 +4,10 @@ known-first-party = ["homeassistant", "tests"]
forced-separate = ["tests"] forced-separate = ["tests"]
combine-as-imports = true combine-as-imports = true
split-on-trailing-comma = false split-on-trailing-comma = false
[tool.pylint."MESSAGES CONTROL"]
# abstract-method - with intro of async there are always methods missing
disable = [
"abstract-method",
"unexpected-keyword-arg",
]