Combination of Media Players

I’m in need of some starting help for targeting multiple media players with one button.

I have three media players in HASS (Sonos, IKEA Sonos, Denon). I want to play a radio station stream to all of them. How to best and most elegantly achieve this? Ideally this should be available from HomeKit as well.

I started off with a Lovelace button and created a lightweight service in there. But this seems to be too limiting. Right now, I have a more-or-less working script which can stream music to the Sonos devices.

script:
  play_1live:
    alias: "Play 1LIVE"
    icon: mdi:radio
    description: "Plays 1LIVE"
    sequence:
      - alias: "Play Radio"
        service: media_player.play_media
        data:
          entity_id:
            - media_player.schlafzimmer
            - media_player.wohnzimmer
            - media_player.kuche
          media_content_id: "https://wdr-1live-live.icecastssl.wdr.de/wdr/1live/live/mp3/128/stream.mp3"
          media_content_type: music

Right now, I call this still from the Developer Tools, Services section and haven’t created a button for this. I would need to create another script for stopping everything. And how to, potentially, change volume, I don’t know either. And having a dedicated stop and a dedicated start button is stupid for a two-state entity; one button to should be able to start and stop things! So I would need to template this?!

I found the Universal Media Player, which might be the right integration. But it seems quite complicated and need lots of manual programming (and what are attributes?!). Will it provide a media player which I can use from HomeKit?
Before I get started with digging too deep into things: I am on the right track? Does anyone have some pointers for me?

All of the devices are AirPlay-capable (that’s how I play radio to them right now), but using AirPlay as a protocol from HASS is not there yet, as far as I understand. If I’m wrong, this could be an alternative…

(In a recent post, @elupus presented https://github.com/elupus/hass_media_stack, how does this factor into things?)

Help! :slight_smile:

Mine does not help here.

The solution I came up with follows. I’ve just finished it, so I can’t say anything towards long-term viability. But, in theory, it should be alright.

What not worked: Using the native media_player.play_media support with media_content_id is easy. But has a big caveat: The devices are not in-sync. The two Sonos devices are pretty much synchronized, but the Denon devices is somewhat quicker. Sketch: A script with a sequence and two media_player.play_medias; one for the Sonos devices (entity_id: [media_player.a, media_player_b] and one for the Denon device. (It took me quite some time – and a lucky find – that Sonos wants media_content_type: music, but Denon wants media_content_type: url…).

So, back to a working strategy: Use Airplay – because that’s in sync.

I compiled forked-daapd (with websockets), enabled MPD support in the forked-daapd config and included it as a new media player to Home Assistant.

media_player:
  - platform: mpd
    host: 127.0.0.1
    port: 6600
    name: Raspi Forked DAAPD

Inset: This forked-daapd/MPD media player has great support in Home Assistant by @kalkih forked-daapd-card (see also his forum entry)!

With this new MPD-Airplay device media_player.raspi_forked_daapd, we can easily exploit native Home Assistant support for playing media:

service: media_player.play_media
data:
  entity_id: media_player.raspi_forked_daapd
  media_content_id: "https://wdr-1live-live.icecastssl.wdr.de/wdr/1live/live/mp3/128/stream.mp3"
  media_content_type: music

But there are two things, which – to my knowledge – are not supported:

  1. Enabling Airplay devices (/speakers) on the forked-daapd backend (because they might have been disabled previously)
  2. Set volume of each Airplay device individually to some default (especially the Denon music player needs to lower volume significantly for anything music compared to TV and movie)

@kalkih’s Lovelace card supports both features, but AFAIK they are not scriptable from Home Assistant directly. But exploiting forked-daapd’s well-documented API is easy with Home Assistant’s rest_commands. The following two commands will enable an Airplay device (activate_speaker) and set volume (set_volume). The port, in this case, is not the MPD-feature port of forked-daapd but the actual forked-daap port.

rest_command:
  activate_speaker:
    url: "http://localhost:3689/api/outputs/{{ id }}"
    method: PUT
    payload: '{"selected": true}'
  set_volume:
    url: "http://localhost:3689/api/outputs/{{ id }}"
    method: PUT
    payload: '{"volume": {{ volume }} }'

We are nearly there. We basically have everything to create a Universal Media Player, except a state. The Universal Media Player is dedicated for this one radio station stream. When the radio stream is played, the Universal Media Player should be on, when not, it should be off – we can reuse this for the Homekit integration. So we create a input_boolean to hold the state whether or not the radio station is currently playing in the setup.

input_boolean:
  playing_1live:
    name: "Currently Playing 1LIVE Airplay Broadcast"
    icon: mdi:speaker

Let’s put everything together.

  • Create a script which starts everything up: Enable the Airplay devices, set their volume to our default, and play the stream MP3; also, change the state of our boolean.
  • Create a script which stops everything. We just need to stop the raspi_forked_daapd media player – and change the state of our boolean.

Here are the scripts:

script:
  1live_broadcast_start:
    alias: "1LIVE Radio: Prepare and Play"
    icon: mdi:radio
    sequence:
      - alias: "Enable speaker Schlafzimmer"
        service: rest_command.activate_speaker
        data: { 'id': '57717330314888' }
      - alias: "Enable speaker Wohnzimmer"
        service: rest_command.activate_speaker
        data: { 'id': '24924472818' }
      - alias: "Enable speaker Kueche"
        service: rest_command.activate_speaker
        data: { 'id': '132116598949134' }
      - alias: "Play to All"
        service: media_player.play_media
        data:
          entity_id: media_player.raspi_forked_daapd
          media_content_id: "https://wdr-1live-live.icecastssl.wdr.de/wdr/1live/live/mp3/128/stream.mp3"
          media_content_type: music
      - alias: "Set volume Schlafzimmer"
        service: rest_command.set_volume
        data: { 'id': '57717888', 'volume': '20' }
      - alias: "Set volume Wohnzimmer"
        service: rest_command.set_volume
        data: { 'id': '249472818', 'volume': '22' }
      - alias: "Set volume Kueche"
        service: rest_command.set_volume
        data: { 'id': '1321168949134', 'volume': '20' }
      - alias: "Set 1LIVE Airplay Broadcast state to ON"
        service: input_boolean.turn_on
        data:
          entity_id: input_boolean.playing_1live
  1live_broadcast_stop:
    alias: "1LIVE Radio: Stop Broadcasting"
    icon: mdi:radio
    sequence:
      - service: media_player.media_pause
        data:
          entity_id: media_player.raspi_forked_daapd
      - alias: "Set 1LIVE Airplay Broadcast state to ON"
        service: input_boolean.turn_off
        data:
          entity_id: input_boolean.playing_1live

(The IDs can be retrieved from the forked-daapd API.)

Both scripts should be called from the Universal Media Player. The state of the player should be extracted from the input_boolean (not raspi_forked_daapd directly, because that could play something else).

media_player:
  - platform: universal
    name: "1LIVE Player"
    children:
      - media_player.raspi_forked_daapd
    commands:
      turn_on:
        service: script.1live_broadcast_start
      turn_off: 
        service: script.1live_broadcast_stop
    attributes:
      state: input_boolean.playing_1live
      volume_level: media_player.raspi_forked_daapd|volume_level   # probably not needed

Done! Well, nearly. We want to integrate this to iOS:

homekit:
  filter:
    include_entities:
      - media_player.1live_player
  entity_config:
    media_player.1live_player:
      name: "1LIVE"
      feature_list:
        - feature: on_off

Tadaa. Let me know if there’s stuff to improve.

4 Likes