A custom Home Assistant integration for controlling Blu-Ray players via their TCP/IP control protocol. Supported models: BDP-83, BDP-93/95, BDP-103/105 and UDP-203/205. Magnetar players are also supported (see Magnetar players).
- Power control: Turn on/off
- Playback control: Play, pause, stop, next/previous track
- Volume control: Volume up/down, set level, mute
- Input source selection: Switch between model-specific inputs (see Supported Input Sources)
- Repeat and shuffle: Set repeat mode (off/one/all) and toggle shuffle
- Media info: Track name, album, artist, playback position/duration
- Extended state attributes: Disc type, audio type, subtitle type, aspect ratio, 3D status, HDR status, video resolution
- Real-time updates: Oppo/pre-20X players stream detailed status via verbose mode 3; Magnetar players stream real state via a separate push channel (see Magnetar players)
- Auto-discovery: Every supported model can be found automatically on your network (see Auto-discovery)
- Custom services: Dimmer, Pure Audio toggle, on-screen info toggle, audio language cycle, subtitle cycle, zoom cycle (see Services)
- Automatic reconnection: Reconnects automatically if the connection is lost
- Install HACS if you don't already have it.
- Home Assistant → HACS → Integrations.
- Search “Oppo/Magnetar Blu-ray Players” → Install.
- Restart Home Assistant.
- Clone or download this repository.
- Copy
custom_components/oppo_udpinto your HAcustom_components/directory. - Restart HA.
Manual installs won’t auto-notify updates-watch the repo if you go this route.
- Go to Settings → Devices & Services → Add Integration
- Search for "Oppo/Magnetar Blu-ray Players"
- Enter the IP address of your player
- Enter the TCP port (default is 23)
- Enter a name for the entity (default is "Oppo UDP-203")
- Select your model (BDP-83, BDP-93/95, BDP-103/105, UDP-203, UDP-205 or Magnetar)
- Leave the port at the default and the correct port for the selected model is applied automatically (BDP-83: 19999; BDP-93/95/103/105: 48360; UDP-203/205: 23; Magnetar: 8102), or set it explicitly to override.
- For Magnetar players, enter the player's MAC address (required, used to wake it on power on).
Every supported model can also be found automatically and will show up under Settings → Devices & Services for you to confirm and add:
- UDP-203/205 and BDP-103/105 are found via UPnP/SSDP (the same mechanism used for DLNA).
- All models (BDP-83/93/95/103/105 and UDP-203/205) are also found via a legacy UDP discovery probe - undocumented by Oppo, reverse-engineered from their now-discontinued mobile app.
- Magnetar players are found via an SSDP-style UDP probe, reverse-engineered from the Magnetar mobile app (Magnetar's own manual doesn't document discovery at all).
None of the non-SSDP mechanisms are officially documented, so if a player doesn't show up, add it manually with the steps above and check that your network allows UDP broadcast/multicast traffic to and from your Home Assistant host.
Magnetar players mostly speak a fire-and-forget network-control protocol on TCP port 8102: most commands are acknowledged with ack and carry no state. Right after connecting, the integration also sends an identify command - undocumented by the official manual, that makes the player start pushing its real power/playback/volume/now-playing state on the same connection. As a result:
- State is real, not assumed, once that push connection is up - it reflects what the player is actually doing, including changes made outside Home Assistant (IR remote, front panel). Until the push channel connects (e.g. right after a Home Assistant restart, or while the player is unreachable), state falls back to optimistic (assumed) - derived from the last command the integration sent - and the entity is flagged
assumed_statefor that window; the last assumed state is restored across Home Assistant restarts. - Once the push channel is up, media info (track/artist/album, position/duration) and extended state attributes (HDR, 4K, color space, deep color, frame rate, channel, frequency, media type, repeat mode) are available, read-only.
- Supported features: power on/off, play, pause, stop, next/previous, volume up/down, mute, plus the custom services below.
- Not available (no protocol support for setting them): input source selection, set-volume-to-level, repeat/shuffle.
- A MAC address is required. Power on sends a Wake-on-LAN magic packet before the power command as the players go into sleep mode after being powered off for some time.
These players share the Oppo command codes but use the IP REMOTE <CODE> framing on model-specific ports (BDP-83: 19999; BDP-93/95/103/105: 48360). Power, playback, volume (up/down/set/mute), repeat/shuffle and real-time streaming updates all work the same as on the UDP-20X. Some newer capabilities are not present in the older protocol:
- BDP-83 / BDP-93/95: no input-source selection.
- BDP-103/105: input-source selection is supported (see below).
- All pre-20X: no aspect-ratio, 3D or HDR (the players don't expose those queries). Track name/album/artist is available for these players too, but via a separate HTTP JSON API on port 436 rather than the telnet protocol (see Protocol) - confirmed on BDP-103/105; BDP-83/93/95 support is untested but expected to work the same way, and fails silently (metadata just stays empty) if it doesn't.
- Oppo BDP-83 / BDP-93/95 / BDP-103/105 / UDP-203 / UDP-205, or Magnetar player
- Player must be connected to your network
- The player communicates on TCP port 23 (UDP-20X), 19999 (BDP-83), 48360 (BDP-93/95/103/105) or 8102 (Magnetar); pre-20X players additionally use port 436 for track metadata
- If you want to power the player on via the integration, enable network in standby in the player's settings
- Home Assistant
2024.6.0or newer - Python
3.14.2or newer (matches Home Assistant's bundled Python)
This integration communicates with the player using the Oppo RS-232 and IP Control Protocol. UDP-20X players use #CMD\r framing on port 23; pre-20X players (BDP-83/93/95/103/105) use the IP REMOTE CMD framing on their model-specific ports. In both cases responses are received as @OK value\r or @ER error\r.
The integration enables verbose mode 3 (detailed unsolicited status updates) so the player pushes state changes - including playback progress - in real-time without polling.
Pre-20X players additionally expose track name/album/artist via a separate, proprietary HTTP JSON API on port 436 (undocumented by Oppo, reverse-engineered from their BDP-10x MediaControl mobile app). The integration queries it whenever the telnet status updates indicate track/disc info may have changed, rather than polling on a fixed interval.
Magnetar players use a different, undocumented protocol on port 8102 instead (see Magnetar players).
- Blu-Ray Player
- HDMI Front
- HDMI Back
- ARC HDMI Out 1
- ARC HDMI Out 2
- Optical
- Coaxial
- USB Audio
- Blu-Ray Player
- HDMI In
- ARC HDMI Out
- Blu-Ray Player
- HDMI In
- Optical
- Coaxial
- USB Audio
BDP-83 and BDP-93/95 have no input-source control.
The integration exposes the following services. All take an entity target.
| Service | Description |
|---|---|
oppo_udp.dimmer |
Cycle the front-panel display brightness (On / Dim / Off) |
oppo_udp.pure_audio_toggle |
Toggle Pure Audio mode (disables video output) |
oppo_udp.info_toggle |
Show or hide the on-screen display |
oppo_udp.audio_language_toggle |
Cycle to the next audio language or channel |
oppo_udp.subtitle_toggle |
Cycle to the next subtitle language |
oppo_udp.zoom |
Cycle zoom / aspect-ratio mode |
oppo_udp.eject |
Toggle the disc tray open or closed |
oppo_udp.fast_forward |
Fast forward (cycles through the fast-forward speeds) |
oppo_udp.fast_reverse |
Fast reverse (cycles through the rewind speeds) |
oppo_udp.power_toggle |
Toggle the player between on and standby |
Example:
service: oppo_udp.pure_audio_toggle
target:
entity_id: media_player.oppo_udp_203- Player becomes unresponsive to IP commands: The Oppo UDP-20X players have a known issue where they can become completely unresponsive to IP control commands. IR and front panel controls still work in this state. To restore IP control, you need to physically disconnect the power cable, then power the player back on (the network stack only starts when the player is powered on).
- Single connection limit: The player only supports one TCP connection at a time. If you need multiple systems to control the player simultaneously, use oppo-multiplexer to broker the connections.
- Input source switching after power on: The player may accept a power on command and report success while still transitioning between states. If you want to switch input source immediately after powering on, add a delay of a few seconds to allow the player to fully start.
- Track metadata accuracy: The artist, album, and track name information may not always be available or accurate. This is a limitation of what the player provides.
- Cannot connect: Ensure the player is powered on and on the same network. Check that no other application is connected to port 23 (only one TCP connection is allowed at a time).
- Slow responses: The integration rate-limits commands to 100ms intervals to avoid overwhelming the player.
- State not updating: If the player loses connection, it will automatically attempt to reconnect every 30 seconds.
- Magnetar playback status stuck on one value: The player's
<state>field (play/pause/stop) isn't documented anywhere and was inferred rather than confirmed against real hardware. If your firmware reports something else, playback status won't update (power, volume and media info still will) - check the Home Assistant log for "Unrecognized Magnetar playback state" and open an issue with the logged value. - Player not found by auto-discovery: Several of the discovery mechanisms rely on UDP broadcast/multicast reaching your Home Assistant host - check your router/firewall allows that traffic, then add the player manually (see Configuration).
- No track/album/artist on a pre-20X player: This is fetched over HTTP from port 436, confirmed only on BDP-103/105. If your player doesn't expose that API, this will silently stay empty - check the Home Assistant log for "Failed to query http://.../getmusicplayinfo".