6ae0ed1787
Release / release (push) Successful in 2s
Production-readiness pass: security hardening, performance improvements, new services (send_message, set_repeat, refresh_library), diagnostics, reauth flow, image proxy, per-instance device IDs, exponential WS reconnect backoff, ID validation, stale device cleanup, and supporting integration plumbing. Three rounds of independent code review applied. See RELEASE_NOTES.md for the full changelog.
280 lines
11 KiB
Markdown
280 lines
11 KiB
Markdown
# Emby Media Player
|
||
|
||
[](https://github.com/hacs/integration)
|
||
[](RELEASE_NOTES.md)
|
||
[](https://www.home-assistant.io/)
|
||
|
||
A Home Assistant custom integration that exposes Emby Server clients as media players with full playback control, real-time WebSocket updates, library browsing, repeat-mode control, and on-screen messaging.
|
||
|
||
## Features
|
||
|
||
### Playback & metadata
|
||
|
||
- **Full media-player control**: play, pause, stop, seek, volume, mute, next/previous track, repeat mode.
|
||
- **Real-time updates over WebSocket** with a slow REST poll as a safety net — `PlaybackStart`, `PlaybackProgress`, and `PlaybackStopped` events update the entity in place.
|
||
- **Now-playing metadata**: title, artist, album, series / season / episode, artwork, duration, position, play method (DirectPlay / DirectStream / Transcode).
|
||
- **Per-client device class** inferred from the Emby client (AndroidTV / Kodi / Roku → TV, music clients → speaker, others → generic).
|
||
- **Enqueue semantics** mapped to Emby commands: HA's `play` / `replace` → `PlayNow`, `next` → `PlayNext`, `add` → `PlayLast`.
|
||
|
||
### Library
|
||
|
||
- **Browse the Emby library** from Home Assistant's media browser — Movies, TV Shows, Music, Playlists, user views.
|
||
- **Server-side image proxy** — artwork is fetched with the API key in an HTTP header and never leaks into URLs in the browser.
|
||
|
||
### Security & reliability
|
||
|
||
- **API key never appears in URLs** (no query-string leakage to proxy logs or browser history).
|
||
- **Per-instance device IDs** derived from the Home Assistant UUID — multiple HA installs no longer collide on the same Emby server.
|
||
- **Self-signed HTTPS** support via a `verify_ssl` toggle.
|
||
- **Reauth flow** prompts for a fresh API key when the server rejects the current one.
|
||
- **Exponential backoff with jitter** for WebSocket reconnects; auth failures stop the retry loop.
|
||
- **ID validation** on all session / item / user identifiers (defense in depth against path traversal in REST paths).
|
||
- **Stale device cleanup** removes media-player devices for sessions that disappear for over 30 minutes (with a 10-minute grace period after startup).
|
||
|
||
### Integration plumbing
|
||
|
||
- **Diagnostics** — Settings → Integrations → "..." → Download diagnostics for a redacted JSON dump (API key and session IDs are hashed/redacted).
|
||
- **Hub device** linked to per-session devices via `via_device` — easier to clean up.
|
||
- **Zeroconf + SSDP discovery hints** so Emby servers can be found by HA.
|
||
- **Three services**: `send_message`, `set_repeat`, `refresh_library`.
|
||
|
||
## Installation
|
||
|
||
### HACS (Recommended)
|
||
|
||
1. Open HACS in Home Assistant.
|
||
2. Click on **Integrations**.
|
||
3. Click the three-dots menu and select **Custom repositories**.
|
||
4. Add this repository URL and select **Integration** as the category.
|
||
5. Click **Install**.
|
||
6. Restart Home Assistant.
|
||
|
||
### Manual Installation
|
||
|
||
1. Download the `custom_components/emby_player` folder.
|
||
2. Copy it to your Home Assistant `custom_components` directory.
|
||
3. Restart Home Assistant.
|
||
|
||
## Configuration
|
||
|
||
1. Go to **Settings → Devices & Services**.
|
||
2. Click **Add Integration** and search for **Emby Media Player**.
|
||
3. Enter your Emby server details:
|
||
- **Host** — Emby server hostname or IP address.
|
||
- **Port** — default `8096` (HTTP) or `8920` (HTTPS).
|
||
- **API Key** — created in Emby Dashboard → Extended → API Keys.
|
||
- **Use SSL** — enable if your server uses HTTPS.
|
||
- **Verify SSL certificate** — disable only when using a self-signed certificate that HA's CA bundle doesn't trust.
|
||
4. Select the Emby user account to use for browsing & playback.
|
||
5. Click **Submit**.
|
||
|
||
### Getting an API key
|
||
|
||
1. Open your Emby Server Dashboard.
|
||
2. Navigate to **Extended → API Keys**.
|
||
3. Click **New API Key** (+ button).
|
||
4. Give it a name (e.g., `Home Assistant`).
|
||
5. Copy the generated key.
|
||
|
||
> Admin keys list all users automatically. Non-admin keys fall back to the
|
||
> public users endpoint — the integration handles both.
|
||
|
||
### Reauthentication
|
||
|
||
If you regenerate the API key on the Emby server, Home Assistant will flag
|
||
the integration as needing attention and walk you through entering the new
|
||
key — no need to remove and re-add the integration.
|
||
|
||
## Options
|
||
|
||
After configuration, open **Configure** on the integration to adjust:
|
||
|
||
- **Scan Interval** (5–60 s, default `10`). Used as the polling cadence while
|
||
the WebSocket is unavailable. When the WebSocket is connected, the
|
||
integration drops to a 5-minute REST safety-net poll automatically.
|
||
|
||
## Supported Features
|
||
|
||
| Feature | Support |
|
||
| ------------------- | ------- |
|
||
| Play / Pause | Yes |
|
||
| Stop | Yes |
|
||
| Volume Control | Yes |
|
||
| Volume Mute | Yes |
|
||
| Seek | Yes |
|
||
| Next Track | Yes |
|
||
| Previous Track | Yes |
|
||
| Repeat Mode | Yes |
|
||
| Media Browser | Yes |
|
||
| Play Media | Yes |
|
||
| Enqueue / Play Next | Yes |
|
||
|
||
## Entity Attributes
|
||
|
||
Each media player entity exposes the following attributes:
|
||
|
||
| Attribute | Description |
|
||
| -------------- | -------------------------------------------------------------------------- |
|
||
| `session_id` | Emby session identifier |
|
||
| `device_id` | Device identifier |
|
||
| `device_name` | Name of the playback device |
|
||
| `client_name` | Emby client application name |
|
||
| `user_name` | Emby user currently signed in on the client (when available) |
|
||
| `item_id` | Currently playing item ID (only while playing) |
|
||
| `item_type` | Type of media (`Movie`, `Episode`, `Audio`, …) |
|
||
| `play_method` | `DirectPlay`, `DirectStream`, or `Transcode` (only while playing) |
|
||
|
||
## Services
|
||
|
||
### `emby_player.send_message`
|
||
|
||
Display a banner notification on an Emby client. Great for doorbells, alarms,
|
||
laundry timers, etc.
|
||
|
||
| Field | Required | Description |
|
||
| ------------ | -------- | -------------------------------------------- |
|
||
| `entity_id` | Yes | One or more Emby media-player entities. |
|
||
| `message` | Yes | Text to display. |
|
||
| `header` | No | Optional header / title. |
|
||
| `timeout_ms` | No | How long to show the message (100–60000 ms). |
|
||
|
||
```yaml
|
||
service: emby_player.send_message
|
||
target:
|
||
entity_id: media_player.emby_living_room_tv
|
||
data:
|
||
header: "Doorbell"
|
||
message: "Someone's at the front door"
|
||
timeout_ms: 5000
|
||
```
|
||
|
||
### `emby_player.set_repeat`
|
||
|
||
Set the repeat mode on the current playback.
|
||
|
||
| Field | Required | Description |
|
||
| ------------- | -------- | -------------------------------------------------------- |
|
||
| `entity_id` | Yes | One or more Emby media-player entities. |
|
||
| `repeat_mode` | Yes | One of `RepeatNone`, `RepeatOne`, or `RepeatAll`. |
|
||
|
||
```yaml
|
||
service: emby_player.set_repeat
|
||
target:
|
||
entity_id: media_player.emby_living_room_tv
|
||
data:
|
||
repeat_mode: RepeatAll
|
||
```
|
||
|
||
> The standard HA media-player repeat control is also wired up — `media_player.repeat_set` will work without using this service.
|
||
|
||
### `emby_player.refresh_library`
|
||
|
||
Trigger a server-side library scan. If `entity_id` is omitted, all configured
|
||
Emby servers are refreshed.
|
||
|
||
```yaml
|
||
service: emby_player.refresh_library
|
||
```
|
||
|
||
## Diagnostics
|
||
|
||
Open **Settings → Integrations → Emby Media Player → "..." → Download diagnostics** to get a redacted JSON dump containing the entry, the current sessions, server id, and WebSocket connection status. Useful when filing bug reports.
|
||
|
||
The dump redacts the API key and replaces real session / device / user IDs with stable hashes so it's safe to share.
|
||
|
||
## Automation Examples
|
||
|
||
### Dim lights when a movie starts
|
||
|
||
```yaml
|
||
automation:
|
||
- alias: "Dim lights for movie"
|
||
trigger:
|
||
- platform: state
|
||
entity_id: media_player.emby_living_room_tv
|
||
to: "playing"
|
||
condition:
|
||
- condition: template
|
||
value_template: "{{ state_attr('media_player.emby_living_room_tv', 'item_type') == 'Movie' }}"
|
||
action:
|
||
- service: light.turn_on
|
||
target:
|
||
entity_id: light.living_room
|
||
data:
|
||
brightness_pct: 20
|
||
```
|
||
|
||
### Pause playback when the doorbell rings, then notify the screen
|
||
|
||
```yaml
|
||
automation:
|
||
- alias: "Pause Emby on doorbell"
|
||
trigger:
|
||
- platform: state
|
||
entity_id: binary_sensor.doorbell
|
||
to: "on"
|
||
action:
|
||
- service: media_player.media_pause
|
||
target:
|
||
entity_id: media_player.emby_living_room_tv
|
||
- service: emby_player.send_message
|
||
target:
|
||
entity_id: media_player.emby_living_room_tv
|
||
data:
|
||
header: "Doorbell"
|
||
message: "Someone is at the door"
|
||
timeout_ms: 8000
|
||
```
|
||
|
||
### Toggle shuffle/repeat from a script
|
||
|
||
```yaml
|
||
script:
|
||
emby_repeat_all:
|
||
sequence:
|
||
- service: media_player.repeat_set
|
||
target:
|
||
entity_id: media_player.emby_living_room_tv
|
||
data:
|
||
repeat: all
|
||
```
|
||
|
||
## Troubleshooting
|
||
|
||
### Connection issues
|
||
|
||
- Verify the Emby server is reachable from the Home Assistant host (try `ping` / `curl http://<host>:8096/emby/System/Info` from a terminal on the HA box).
|
||
- Check that the API key is valid and not revoked in Emby Dashboard → Extended → API Keys.
|
||
- For HTTPS with a self-signed certificate, toggle **Verify SSL certificate** off in the integration config.
|
||
- If reauth keeps failing, regenerate the API key on the server and try again.
|
||
|
||
### No media players appearing
|
||
|
||
- Media-player entities are only created for **active sessions that support remote control**. Start playback on an Emby client first.
|
||
- Browser-based Emby Web sessions usually do not support remote control and won't appear as entities.
|
||
- Check **Settings → System → Logs** in Home Assistant for messages from `custom_components.emby_player`.
|
||
|
||
### WebSocket connection failed
|
||
|
||
If the WebSocket can't connect, the integration falls back to REST polling at the configured **Scan Interval**. To restore real-time updates:
|
||
|
||
- Allow WebSocket traffic to TCP `8096` / `8920` from the HA host.
|
||
- If you run Emby behind a reverse proxy, make sure `Upgrade` / `Connection` headers are forwarded for `/embywebsocket`.
|
||
- For HTTPS proxies (Caddy / Traefik / nginx), confirm the WebSocket path is included in the proxy config.
|
||
|
||
### Stale devices in the registry
|
||
|
||
Devices for sessions that haven't been seen for 30 minutes are removed automatically (after a 10-minute startup grace). You can also manually delete a device from **Settings → Devices & Services → Emby Media Player → Device → Delete**.
|
||
|
||
## Versioning
|
||
|
||
See [RELEASE_NOTES.md](RELEASE_NOTES.md) for the full changelog.
|
||
|
||
## Contributing
|
||
|
||
Contributions are welcome. Please open an issue or submit a pull request.
|
||
|
||
## License
|
||
|
||
This project is licensed under the MIT License.
|