Media Player
Control media players with playback, volume, source selection, and media information.
Quick Example
// Component approach
<MediaPlayer entityId="media_player.living_room_speaker">
{({ isPlaying, toggle, mediaTitle, volumeLevel }) => (
<div>
<p>{mediaTitle || 'No media playing'}</p>
<button onClick={toggle}>
{isPlaying ? 'PAUSE' : 'PLAY'}
</button>
<p>Volume: {Math.round(volumeLevel * 100)}%</p>
</div>
)}
</MediaPlayer>
// Hook approach
const speaker = useMediaPlayer('media_player.living_room_speaker')
<div>
<p>{speaker.mediaTitle || 'No media playing'}</p>
<button onClick={speaker.toggle}>
{speaker.isPlaying ? 'PAUSE' : 'PLAY'}
</button>
<p>Volume: {Math.round(speaker.volumeLevel * 100)}%</p>
</div>
Component API
Basic Usage
import { MediaPlayer } from 'hass-react'
<MediaPlayer entityId="media_player.living_room_speaker">
{(playerProps) => (
// Your UI here
)}
</MediaPlayer>
Render Props
The MediaPlayer component provides these props to your render function:
State Properties
isPlaying(boolean) - Whether media is currently playingisPaused(boolean) - Whether media is pausedisIdle(boolean) - Whether player is idle (no media loaded)isOff(boolean) - Whether player is turned offisOn(boolean) - Whether player is turned on
Media Information
mediaTitle(string | null) - Current media titlemediaArtist(string | null) - Current media artistmediaAlbum(string | null) - Current media albummediaContentType(string | null) - Type of media contentmediaDuration(number | null) - Total duration in secondsmediaPosition(number | null) - Current position in seconds
Audio Control
volumeLevel(number) - Current volume level (0-1)isMuted(boolean) - Whether audio is mutedcurrentSource(string | null) - Current input sourcesourceList(string[]) - Available input sourcescurrentSoundMode(string | null) - Current sound modesoundModeList(string[]) - Available sound modes
Advanced Features
shuffle(boolean | null) - Shuffle mode statusrepeat(string | null) - Repeat mode (off, one, all)appName(string | null) - Current app name
Support Properties
supportsPlay(boolean) - Player supports playsupportsPause(boolean) - Player supports pausesupportsStop(boolean) - Player supports stopsupportsNextTrack(boolean) - Player supports next tracksupportsPreviousTrack(boolean) - Player supports previous tracksupportsVolumeSet(boolean) - Player supports volume controlsupportsVolumeMute(boolean) - Player supports mute/unmutesupportsSeek(boolean) - Player supports seekingsupportsTurnOn(boolean) - Player supports power onsupportsTurnOff(boolean) - Player supports power offsupportsSelectSource(boolean) - Player supports source selectionsupportsSelectSoundMode(boolean) - Player supports sound mode selectionsupportsShuffle(boolean) - Player supports shufflesupportsRepeat(boolean) - Player supports repeat modes
Control Methods
play()- Start playbackpause()- Pause playbackstop()- Stop playbacktoggle()- Toggle play/pausenextTrack()- Skip to next trackpreviousTrack()- Skip to previous trackturnOn()- Turn player onturnOff()- Turn player offsetVolume(volume: number)- Set volume (0-1)toggleMute()- Toggle mutemute()- Mute audiounmute()- Unmute audioselectSource(source: string)- Select input sourceselectSoundMode(soundMode: string)- Select sound modesetShuffle(shuffle: boolean)- Enable/disable shufflesetRepeat(repeat: string)- Set repeat modeseek(position: number)- Seek to position in secondsplayMedia(mediaType: string, mediaId: string)- Play specific media
Entity Properties
entityId(string) - The entity IDstate(string) - Raw state value from Home Assistantattributes(object) - All entity attributeslastChanged(Date) - When the entity last changedlastUpdated(Date) - When the entity was last updated
Hook API
Basic Usage
import { useMediaPlayer } from 'hass-react'
function MyComponent() {
const player = useMediaPlayer('media_player.living_room_speaker')
// All the same properties as component render props
return <div>{player.isPlaying ? 'PLAYING' : 'PAUSED'}</div>
}
The useMediaPlayer hook returns an object with all the same properties and methods as the component's render props.
List All Media Players
Use the useMediaPlayers hook to retrieve all available media player entities:
import { useMediaPlayers } from 'hass-react'
function MediaPlayerList() {
const mediaPlayers = useMediaPlayers()
return (
<div>
<h2>Available Media Players ({mediaPlayers.length})</h2>
{mediaPlayers.map(player => (
<div key={player.entity_id}>
{player.attributes.friendly_name || player.entity_id}
</div>
))}
</div>
)
}
The useMediaPlayers hook fetches all media player entities from Home Assistant and returns an array of media player objects.
Examples
Simple Media Control
<MediaPlayer entityId="media_player.bedroom_speaker">
{({ isPlaying, isPaused, isOff, play, pause, stop, turnOn, mediaTitle, mediaArtist, attributes }) => (
<div>
<h3>{attributes.friendly_name}</h3>
<div>
<strong>{mediaTitle || 'No media'}</strong>
{mediaArtist && <p>by {mediaArtist}</p>}
</div>
<div>
{isOff ? (
<button onClick={turnOn}>Turn On</button>
) : (
<>
<button onClick={play} disabled={isPlaying}>
Play
</button>
<button onClick={pause} disabled={!isPlaying}>
Pause
</button>
<button onClick={stop}>
Stop
</button>
</>
)}
</div>
</div>
)}
</MediaPlayer>
Volume Control
<MediaPlayer entityId="media_player.kitchen_speaker">
{({ volumeLevel, isMuted, setVolume, toggleMute, supportsVolumeSet, supportsVolumeMute, attributes }) => (
<div>
<h3>{attributes.friendly_name}</h3>
{supportsVolumeSet && (
<div>
<label>Volume: {Math.round(volumeLevel * 100)}%</label>
<input
type="range"
min="0"
max="100"
value={volumeLevel * 100}
onChange={(e) => setVolume(parseInt(e.target.value) / 100)}
/>
</div>
)}
{supportsVolumeMute && (
<button onClick={toggleMute}>
{isMuted ? 'Unmute' : 'Mute'}
</button>
)}
</div>
)}
</MediaPlayer>
Track Navigation
<MediaPlayer entityId="media_player.spotify">
{({
isPlaying, toggle, nextTrack, previousTrack,
supportsNextTrack, supportsPreviousTrack,
mediaTitle, mediaArtist, mediaAlbum, attributes
}) => (
<div>
<h3>{attributes.friendly_name}</h3>
<div>
<strong>{mediaTitle || 'No track'}</strong>
{mediaArtist && <p>{mediaArtist}</p>}
{mediaAlbum && <p>Album: {mediaAlbum}</p>}
</div>
<div>
{supportsPreviousTrack && (
<button onClick={previousTrack}>Previous</button>
)}
<button onClick={toggle}>
{isPlaying ? 'Pause' : 'Play'}
</button>
{supportsNextTrack && (
<button onClick={nextTrack}>Next</button>
)}
</div>
</div>
)}
</MediaPlayer>
Progress Bar with Seeking
<MediaPlayer entityId="media_player.music_player">
{({ mediaPosition, mediaDuration, seek, supportsSeek, mediaTitle, attributes }) => (
<div>
<h3>{attributes.friendly_name}</h3>
<p>{mediaTitle || 'No media'}</p>
{supportsSeek && mediaDuration && (
<div>
<input
type="range"
min="0"
max={mediaDuration}
value={mediaPosition || 0}
onChange={(e) => seek(parseInt(e.target.value))}
/>
<div>
{Math.floor((mediaPosition || 0) / 60)}:
{String(Math.floor((mediaPosition || 0) % 60)).padStart(2, '0')} /
{Math.floor(mediaDuration / 60)}:
{String(Math.floor(mediaDuration % 60)).padStart(2, '0')}
</div>
</div>
)}
</div>
)}
</MediaPlayer>
Source Selection
<MediaPlayer entityId="media_player.av_receiver">
{({ currentSource, sourceList, selectSource, supportsSelectSource, attributes }) => (
<div>
<h3>{attributes.friendly_name}</h3>
<p>Current Source: {currentSource}</p>
{supportsSelectSource && sourceList.length > 0 && (
<div>
<label>Select Source:</label>
<select value={currentSource || ''} onChange={(e) => selectSource(e.target.value)}>
{sourceList.map(source => (
<option key={source} value={source}>
{source}
</option>
))}
</select>
</div>
)}
</div>
)}
</MediaPlayer>
Shuffle and Repeat
<MediaPlayer entityId="media_player.music_service">
{({
shuffle, repeat, setShuffle, setRepeat,
supportsShuffle, supportsRepeat, attributes
}) => (
<div>
<h3>{attributes.friendly_name}</h3>
{supportsShuffle && (
<label>
<input
type="checkbox"
checked={shuffle || false}
onChange={(e) => setShuffle(e.target.checked)}
/>
Shuffle
</label>
)}
{supportsRepeat && (
<div>
<label>Repeat:</label>
<select value={repeat || 'off'} onChange={(e) => setRepeat(e.target.value)}>
<option value="off">Off</option>
<option value="one">One</option>
<option value="all">All</option>
</select>
</div>
)}
</div>
)}
</MediaPlayer>
Multiple Players
function MediaPlayerPanel() {
const players = [
'media_player.living_room',
'media_player.kitchen',
'media_player.bedroom'
]
return (
<div>
<h2>Media Players</h2>
{players.map(entityId => (
<MediaPlayer key={entityId} entityId={entityId}>
{({ isPlaying, toggle, mediaTitle, volumeLevel, attributes }) => (
<div>
<strong>{attributes.friendly_name}</strong>
<br />
Playing: {mediaTitle || 'Nothing'}
<br />
Volume: {Math.round(volumeLevel * 100)}%
<br />
<button onClick={toggle}>
{isPlaying ? 'Pause' : 'Play'}
</button>
</div>
)}
</MediaPlayer>
))}
</div>
)
}
Using Hooks
import { useMediaPlayer } from 'hass-react'
function MediaPlayerCard({ entityId }) {
const player = useMediaPlayer(entityId)
const getStatusText = () => {
if (player.isOff) return 'OFF'
if (player.isPlaying) return 'PLAYING'
if (player.isPaused) return 'PAUSED'
if (player.isIdle) return 'IDLE'
return 'UNKNOWN'
}
const formatTime = (seconds: number) => {
const mins = Math.floor(seconds / 60)
const secs = Math.floor(seconds % 60)
return `${mins}:${String(secs).padStart(2, '0')}`
}
return (
<div>
<h3>{player.attributes.friendly_name}</h3>
<div>Status: {getStatusText()}</div>
{player.mediaTitle && (
<div>
<strong>{player.mediaTitle}</strong>
{player.mediaArtist && <div>{player.mediaArtist}</div>}
</div>
)}
{player.mediaPosition !== null && player.mediaDuration !== null && (
<div>
{formatTime(player.mediaPosition)} / {formatTime(player.mediaDuration)}
</div>
)}
<div>
<button onClick={player.toggle} disabled={player.isOff}>
{player.isPlaying ? 'Pause' : 'Play'}
</button>
{player.supportsNextTrack && (
<button onClick={player.nextTrack}>Next</button>
)}
</div>
{player.supportsVolumeSet && (
<div>
Volume: {Math.round(player.volumeLevel * 100)}%
<input
type="range"
min="0"
max="100"
value={player.volumeLevel * 100}
onChange={(e) => player.setVolume(parseInt(e.target.value) / 100)}
/>
</div>
)}
<p>Last updated: {player.lastUpdated.toLocaleTimeString()}</p>
</div>
)
}