Chromecast Radio with station and player selection

Makes sense! Thanks

Works great thanks,

just one question, I would like to display the artwork cover is that possible with this option?

Kr,

André

1 Like

you need to create a camera that points to a jpg file.
I retrieve artwork, artist and track via a separate python script (scrape using BS4 and send to HA via MQTT)
Then I use a template sensor to figure out which station I’m playing and a picture-glance lovelace card to display the template sensors (artist, track, artwork camera):

Lovelace config extract for that:

  - type: custom:stack-in-card
    mode: vertical
    cards:
    - type: picture-glance
      camera_image: camera.chromecast_radio_pic
      entities:
        - entity: input_select.chromecast_radio_station
        - entity: input_text.custom_station
        - entity: input_select.chromecast_radio_speakers
        - entity: switch.chromecast_radio_vol_down
        - entity: switch.chromecast_radio_mute
        - entity: switch.chromecast_radio_vol_up
        - entity: switch.chromecast_radio_stop
        - entity: switch.chromecast_radio_play
    - type: conditional
      conditions:
        - entity: binary_sensor.radio_is_streaming
          state: "on"
      card:
        type: entities
        show_header_toggle: false
        entities:
          - entity: sensor.stream_artist
            name: Artist
            secondary_info: last-changed
            icon: mdi:account-music
          - entity: sensor.stream_track
            name: Track
            secondary_info: last-changed
            icon: mdi:music-circle
1 Like

Great howto, I will try it tonight.

Can you please share this script? I’m not familiar with BS4, can you explain?

BS4 is Beautiful Soup. It’s the engine that’s used by the Scrape Sensor
But the scrape sensor only refreshes once every min and I find it a bit more complicated than using BS4 directly. In addition I want a single call per radio, as opposed to 1 call per attribute, which might end up black listing me as spam/DDOS
Here is the python script I’ve written to extract artist, track and album art from the various radios I listen to:

Show Code
#!/usr/bin/python
# -*- coding: utf-8 -*-

from bs4 import BeautifulSoup
from urllib.request import urlopen, Request
import paho.mqtt.client as mqtt
import time
from threading import Thread
from datetime import datetime
import json

import secrets

MQTT_Host = secrets.MQTT_Host
MQTT_Port = secrets.MQTT_Port
MQTT_User = secrets.MQTT_User
MQTT_Password = secrets.MQTT_Password

client = mqtt.Client("HA_Scraper") # must be unique on MQTT network
client.username_pw_set(str(MQTT_User),str(MQTT_Password))
client.connect(MQTT_Host, port=MQTT_Port, keepalive=60)
client.loop_start()
headers = {'User-Agent': 'Mozilla/5.0'}



class Radio:

	# Initializer / Instance Attributes
	def __init__(self, name, url, pic, pic_sel, pic_att, artist, artist_sel, artist_att, track, track_sel, track_att):
		self.name = name
		self.url = url
		self.pic = pic
		self.pic_sel = pic_sel
		self.pic_att = pic_att
		self.artist = artist
		self.artist_sel = artist_sel
		self.artist_att = artist_att
		self.track = track
		self.track_sel = track_sel
		self.track_att = track_att



class Podcast:

	# Initializer / Instance Attributes
	def __init__(self, name, url, track, track_sel, track_att, mp3_url, mp3_sel, mp3_att):
		self.name = name
		self.url = url
		self.track = track
		self.track_sel = track_sel
		self.track_att = track_att
		self.mp3_url = mp3_url
		self.mp3_sel = mp3_sel
		self.mp3_att = mp3_att


RTL2 = Radio("RTL2", "https://www.6play.fr/rtl2/quel-est-ce-titre", "", ".ecfper-2", "src", "", ".ecfper-6", "", "", ".ecfper-5", "") #https://timeline.rtl.fr/RTL2/songs
Absolute_Radio_CR = Radio("Absolute_Radio_CR", "https://planetradio.co.uk/absolute-radio-60s/player/", "", ".station-cards.cf > div:nth-child(3) > a .main-img", "style", "", ".station-cards.cf > div:nth-child(3) > a > .text-wrapper > div > .artist", "", "", ".station-cards.cf > div:nth-child(3) > a > .text-wrapper > div > .track", "")
Absolute_Radio_CR2 = Radio("Absolute_Radio_CR2", # Name
                "https://planetradio.co.uk/absolute-classic-rock/player/", # URL
                "", #Leave Blank
                ".now-playing-wrapper > .now-playing.cf > .now-playing-block.cf.right.extended-info > .image", # Picture Select
                "style", # Picture Select Attribute
                "", #Leave Blank
                ".now-playing-wrapper > .now-playing.cf > .now-playing-block.cf.right.extended-info > .info-wrapper.fr > div > .title.extended-info", # Artist Select
                "", # Artist Select Attribute
                "", #Leave Blank
                ".now-playing-wrapper > .now-playing.cf > .now-playing-block.cf.right.extended-info > .info-wrapper.fr > div > .track.extended-info", # Track Select
                "" # Track Select Attribute
            )
Absolute_Radio = Radio("Absolute_Radio", "https://planetradio.co.uk/absolute-radio-60s/player/", "", ".station-cards.cf > div:nth-child(1) > a .main-img", "style", "", ".station-cards.cf > div:nth-child(1) > a > .text-wrapper > div > .artist", "", "", ".station-cards.cf > div:nth-child(1) > a > .text-wrapper > div > .track", "")
Absolute_Radio2 = Radio("Absolute_Radio2", # Name
                "https://planetradio.co.uk/absolute-radio/player/", # URL
                "", #Leave Blank
                ".now-playing-wrapper > .now-playing.cf > .now-playing-block.cf.right.extended-info > .image", # Picture Select
                "style", # Picture Select Attribute
                "", #Leave Blank
                ".now-playing-wrapper > .now-playing.cf > .now-playing-block.cf.right.extended-info > .info-wrapper.fr > div > .title.extended-info", # Artist Select
                "", # Artist Select Attribute
                "", #Leave Blank
                ".now-playing-wrapper > .now-playing.cf > .now-playing-block.cf.right.extended-info > .info-wrapper.fr > div > .track.extended-info", # Track Select
                "" # Track Select Attribute
            )
IoT_Podcast = Podcast("IoT Podcast", "https://iotpodcast.com/feed/", "", "item:nth-of-type(1) title", "", "","enclosure:nth-of-type(1)", "url")
Hass_Podcast = Podcast("Hass Podcast", "https://hasspodcast.io/feed/podcast", "", "item:nth-of-type(1) title", "", "","enclosure:nth-of-type(1)", "url")
Chill = Radio("Chill", "https://www.smoothradio.com/chill/radio/playlist/", "", ".js-lazy", "data-src", "", ".now-playing__text-content__details__artist", "", "", ".now-playing__text-content__details__track", "")
Scala = Radio("Scala", "https://planetradio.co.uk/jazz-fm/player/", "", ".station-cards.cf > div:nth-child(1) > a .main-img", "style", "", ".station-cards.cf > div:nth-child(1) > a > .text-wrapper > div > .artist", "", "", ".station-cards.cf > div:nth-child(1) > a > .text-wrapper > div > .track", "")
Scala2 = Radio("Scala2", # Name
                "https://planetradio.co.uk/scala-radio/player/", # URL
                "", #Leave Blank
                ".now-playing-wrapper > .now-playing.cf > .now-playing-block.cf.right.extended-info > .image", # Picture Select
                "style", # Picture Select Attribute
                "", #Leave Blank
                ".now-playing-wrapper > .now-playing.cf > .now-playing-block.cf.right.extended-info > .info-wrapper.fr > div > .title.extended-info", # Artist Select
                "", # Artist Select Attribute
                "", #Leave Blank
                ".now-playing-wrapper > .now-playing.cf > .now-playing-block.cf.right.extended-info > .info-wrapper.fr > div > .track.extended-info", # Track Select
                "" # Track Select Attribute
            )



def bs_get_value_radio(radio):
	req = Request(radio.url, headers=headers)
	content = urlopen(req).read()

	try:
		raw_data = BeautifulSoup(content,"html.parser")
	except Exception as e:
		print("%s Unable to get BS from URL" % e)
	try:
		if(radio.pic != raw_data.select(radio.pic_sel)[0][radio.pic_att]):
			radio.pic = raw_data.select(radio.pic_sel)[0][radio.pic_att].replace("background-image:url(", "").replace(")", "")
			client.publish("RadioStream/"+radio.name+"/pic_url",radio.pic.encode('ascii'), qos=0, retain=True)

	except Exception as e:
		print ("Can't get "+radio.name+" Image")
	try:
		if (radio.artist_att):
			if(radio.artist != raw_data.select(radio.artist_sel)[0][radio.artist_att]):
				radio.artist = raw_data.select(radio.artist_sel)[0][radio.artist_att]
				client.publish("RadioStream/"+radio.name+"/artist",radio.artist, qos=0, retain=True)
		else:
			if(radio.artist != raw_data.select(radio.artist_sel)[0].text.title()):
				radio.artist = raw_data.select(radio.artist_sel)[0].text.title().strip()
				client.publish("RadioStream/"+radio.name+"/artist",radio.artist, qos=0, retain=True)
	except Exception as e:
		print ("Can't get "+radio.name+" Artist")

	try:
		if (radio.track_att):
			if(radio.track != raw_data.select(radio.track_sel)[0][radio.track_att]):
				radio.track = raw_data.select(radio.track_sel)[0][radio.track_att]
				client.publish("RadioStream/"+radio.name+"/track",radio.track, qos=0, retain=True)
		else:
			if(radio.track != raw_data.select(radio.track_sel)[0].text.title()):
				radio.track = raw_data.select(radio.track_sel)[0].text.title().strip()
				client.publish("RadioStream/"+radio.name+"/track",radio.track, qos=0, retain=True)
	except Exception as e:
		print ("Can't get "+radio.name+" Track")

def bs_get_value_podcast(podcast):
	req = Request(podcast.url, headers=headers)
	content = urlopen(req).read()

	try:
		raw_data = BeautifulSoup(content,"html.parser")
	except Exception as e:
		print("%s Unable to get BS from URL" % e)

	try:
		if (podcast.mp3_att):
			if(podcast.mp3_url != raw_data.select(podcast.mp3_sel)[0][podcast.mp3_att]):
				podcast.mp3_url = raw_data.select(podcast.mp3_sel)[0][podcast.mp3_att]
				client.publish("RadioStream/"+podcast.name+"/mp3_url",podcast.mp3_url, qos=0, retain=True)
		else:
			if(podcast.mp3_url != raw_data.select(podcast.mp3_sel)[0].text.title()):
				podcast.mp3_url = raw_data.select(podcast.mp3_sel)[0].text.title().strip()
				client.publish("RadioStream/"+podcast.name+"/mp3_url",podcast.mp3_url, qos=0, retain=True)
	except Exception as e:
		print ("Can't get "+podcast.name+" MP3 URL")

	try:
		if (podcast.track_att):
			if(podcast.track != raw_data.select(podcast.track_sel)[0][podcast.track_att]):
				podcast.track = raw_data.select(podcast.track_sel)[0][podcast.track_att]
				client.publish("RadioStream/"+podcast.name+"/track",podcast.track, qos=0, retain=True)
		else:
			if(podcast.track != raw_data.select(podcast.track_sel)[0].text.title()):
				podcast.track = raw_data.select(podcast.track_sel)[0].text.title().strip()
				client.publish("RadioStream/"+podcast.name+"/track",podcast.track, qos=0, retain=True)
	except Exception as e:
		print ("Can't get "+podcast.name+" Track")

def planetradio(name, url):
    url = url + str(datetime.now().strftime('%Y-%m-%d')) + "/" + str(datetime.now().strftime('%H:%M')) +"/1"
    req = Request(url, headers=headers)
    content = str(urlopen(req).read()).replace("b'","").replace("'","")
    json_content = json.loads(content)
    client.publish("RadioStream/"+name+"/pic_url",json_content[0]["nowPlayingImage"], qos=0, retain=True)
    client.publish("RadioStream/"+name+"/artist",json_content[0]["nowPlayingArtist"], qos=0, retain=True)
    client.publish("RadioStream/"+name+"/track",json_content[0]["nowPlayingTrack"], qos=0, retain=True)


def streamguys(url):
    # url = "https://jeta.streamguys.com:8444/8944a2fe68caa986fdee0f2a3c03675d624bab9a/scraper/9cebb028-9f73-4062-830b-478535e516a1/metadata"
    req = Request(url, headers=headers)
    content = str(urlopen(req).read()).replace("b'","").replace("'","")
    json_content = json.loads(content)
    metadata = json_content["StreamTitle"].split(" - ")
    try:
        client.publish("RadioStream/Radio_Fiji_Two/artist",metadata[-1], qos=0, retain=True)
    except:
        client.publish("RadioStream/Radio_Fiji_Two/artist","N/A", qos=0, retain=True)
        pass
    try:
        client.publish("RadioStream/Radio_Fiji_Two/track",metadata[-2], qos=0, retain=True)
    except:
        client.publish("RadioStream/Radio_Fiji_Two/track","N/A", qos=0, retain=True)
        pass

Refresh_Timer = 0
while(True):

	Thread(target=bs_get_value_radio, args=[RTL2]).start()
	Thread(target=planetradio, args=["Absolute_Radio_CR","https://listenapi.bauerradio.com/api9/eventsdadi/absolute-classic-rock/"]).start()
	Thread(target=planetradio, args=["Absolute_Radio","https://listenapi.bauerradio.com/api9/eventsdadi/absolute-radio/"]).start()
	Thread(target=planetradio, args=["Scala","https://listenapi.bauerradio.com/api9/eventsdadi/scala-radio/"]).start()
	Thread(target=streamguys, args=["https://jeta.streamguys.com:8444/8944a2fe68caa986fdee0f2a3c03675d624bab9a/scraper/9cebb028-9f73-4062-830b-478535e516a1/metadata"]).start()
	Thread(target=bs_get_value_podcast, args=[IoT_Podcast]).start()
	if(Refresh_Timer == 240):
		Thread(target=bs_get_value_podcast, args=[Hass_Podcast]).start()
		Refresh_Timer = 0
	Thread(target=bs_get_value_radio, args=[Chill]).start()
	time.sleep(15)
	Refresh_Timer = Refresh_Timer + 1

it probably needs a bit of cleaning… I originally scraped content of the html player page, but that would fail every now and again. I then found out that some radios offered a json page with the details I needed (e.g. planet radio stations) so I adjusted.
I then call the script at HA startup and it keeps running…
Hope it makes sense / is helpful to others

2 Likes

Hi @ASNNetworks

So I’m getting there now.


But I’m going crazy over the gap between the buttons in the top. I tried with padding 0px, margins: 0px, etc…
Here’s my config: https://pastebin.com/6f0D1Erk

Are you able to see my mistake?

Thanks in advance!

Use stack-in-card instead of vertical-stack. That allows you create vertical and horizontal stacks where the button cards have no gaps and look like one single card. This is what I use for most of my UI to give it a more clean look.

For example:


These are all stack within stacks, but they appear as single cards.

Make sure you use 0.1.1, 0.2.0 has a bug with nested cards.

1 Like

Nice!

I’ll give a go

Thanks man! :slight_smile: :ok_hand:t3:

1 Like

Guys,

Streaming to Sonos will not work by me. Streaming to googlehome mini or Chromecast is no problem. What should be the problem?

Hello dear people…i have been reading the original post and scrolling till 2021. I am quite confuse to which is the working iteration now on the current HA version.

I got a google home mini and interested in streaming tunein or other radio to the mini. I don’t have a Spotify account. If anyone can point me to the right direction please?
Thanks

If you haven’t already, setup the package folder / file

Place this in the yaml file:

input_select:
  radio_station:
    name: 'Select Radio Station:'
    options:
      - Hit 92-9
      - Nova 93-7
      - Mix 94-5
      - 96FM
      - 80's 1
      - 80's 2
      - OldSkool Hits
      - Old Skool Anthems
      - Raw FM (dance)
      - 181FM Power (Todays Hits)
      - 181FM 90's Dance
      - 181FM Star 90's
      - 181FM The Breeze
      - Heat Radio (RnB)
      - Fresh 92-7
      - DI Chill & Tropical House
      - DI Disco House
      - DI Funky House
      - DI Liquid D&B
      - Aloha Joe's Relaxation Island
      - Spectrum Fit
      - Energy FM Australia
      - Jazz Relax
      - Australian Country
      - Rebel FM
    initial: Raw FM (dance)
    icon: mdi:radio

    

  chromecast_radio:
    name: 'Select Speakers:'
    options:
      - Lounge
      - Bedroom
      - Office
      - Lounge and Office
      - House
      - House except office
      - Everywhere
      - Everywhere except office
      - Back yard
    initial: House
    icon: mdi:speaker-wireless

input_number: 
  volume_radio:
    name: Volume
    icon: mdi:volume-high
    min: 0
    max: 1
    step: 0.05

automation:
  - alias: 'Listen Radio'
    trigger:
      - platform: state
        entity_id: input_select.radio_station
    action: 
      - service: script.radio

  - alias: 'Set Chromecast Radio Volume'
    trigger:
      platform: state
      entity_id: input_number.volume_radio
    action:
      service: media_player.volume_set
      data_template:
        entity_id: >
          {% if is_state("input_select.chromecast_radio", "Lounge") %} media_player.lounge_speakers
          {% elif is_state("input_select.chromecast_radio", "Bedroom") %} media_player.bedroom
          {% elif is_state("input_select.chromecast_radio", "Office") %} media_player.chromecastaudio3249
          {% elif is_state("input_select.chromecast_radio", "Lounge and Office") %} media_player.lounge_and_office
          {% elif is_state("input_select.chromecast_radio", "House") %} media_player.house
          {% elif is_state("input_select.chromecast_radio", "House except office") %} media_player.house_except_office
          {% elif is_state("input_select.chromecast_radio", "Everywhere") %} media_player.everywhere
          {% elif is_state("input_select.chromecast_radio", "Everywhere except office") %} media_player.all_except_office
          {% elif is_state("input_select.chromecast_radio", "Back yard") %} media_player.back_yard
          {% endif %}
        volume_level: '{{  states.input_number.volume_radio.state  }}'

script:

  radio:
    alias: Play Radio on Chromecast Audio
    sequence:
    - service: media_player.volume_set
      data_template:
        entity_id: >
          {% if is_state("input_select.chromecast_radio", "Lounge") %} media_player.lounge_speakers
          {% elif is_state("input_select.chromecast_radio", "Bedroom") %} media_player.bedroom
          {% elif is_state("input_select.chromecast_radio", "Office") %} media_player.chromecastaudio3249
          {% elif is_state("input_select.chromecast_radio", "Lounge and Office") %} media_player.lounge_and_office
          {% elif is_state("input_select.chromecast_radio", "House") %} media_player.house
          {% elif is_state("input_select.chromecast_radio", "House except office") %} media_player.house_except_office
          {% elif is_state("input_select.chromecast_radio", "Everywhere") %} media_player.everywhere
          {% elif is_state("input_select.chromecast_radio", "Everywhere except office") %} media_player.all_except_office
          {% elif is_state("input_select.chromecast_radio", "Back yard") %} media_player.back_yard
          {% endif %}
        volume_level: '{{  states.input_number.volume_radio.state  }}' 
    - service: media_player.play_media
      data_template:
        entity_id: >
          {% if is_state("input_select.chromecast_radio", "Lounge") %} media_player.lounge_speakers
          {% elif is_state("input_select.chromecast_radio", "Bedroom") %} media_player.bedroom
          {% elif is_state("input_select.chromecast_radio", "Office") %} media_player.chromecastaudio3249
          {% elif is_state("input_select.chromecast_radio", "Lounge and Office") %} media_player.lounge_and_office
          {% elif is_state("input_select.chromecast_radio", "House") %} media_player.house
          {% elif is_state("input_select.chromecast_radio", "House except office") %} media_player.house_except_office
          {% elif is_state("input_select.chromecast_radio", "Everywhere") %} media_player.everywhere
          {% elif is_state("input_select.chromecast_radio", "Everywhere except office") %} media_player.all_except_office
          {% elif is_state("input_select.chromecast_radio", "Back yard") %} media_player.back_yard
          {% endif %}
        media_content_id: >
          {% if is_state("input_select.radio_station", "Hit 92-9") %} http://ic6ti.scahw.com.au/6ppm_128
          {% elif is_state("input_select.radio_station", "Nova 93-7") %} http://streaming.novaentertainment.com.au/nova937
          {% elif is_state("input_select.radio_station", "Mix 94-5") %} http://sc01.scahw.com.au/6mix_32
          {% elif is_state("input_select.radio_station", "96FM") %} https://icy.ihrcast.arn.com.au/au_012_icy
          {% elif is_state("input_select.radio_station", "80's 1") %} http://ic2ti.scahw.com.au/2easy_128
          {% elif is_state("input_select.radio_station", "80's 2") %} http://18243.live.streamtheworld.com/T_RAD_80S_S01_SC?
          {% elif is_state("input_select.radio_station", "OldSkool Hits") %} http://sc01.scahw.com.au/loveland_32
          {% elif is_state("input_select.radio_station", "Old Skool Anthems") %} http://nebula.shoutca.st:8075/stream
          {% elif is_state("input_select.radio_station", "Raw FM (dance)") %} https://frontend.stream.rawfm.net.au/i/syd-stream-192k.mp3 
          {% elif is_state("input_select.radio_station", "181FM Power (Todays Hits)") %} http://listen.181fm.com/181-power_128k.mp3?
          {% elif is_state("input_select.radio_station", "181FM 90's Dance") %} http://listen.181fm.com/181-90sdance_128k.mp3
          {% elif is_state("input_select.radio_station", "181FM Star 90's") %} http://listen.181fm.com/181-star90s_128k.mp3
          {% elif is_state("input_select.radio_station", "181FM The Breeze") %} http://listen.181fm.com/181-breeze_128k.mp3
          {% elif is_state("input_select.radio_station", "Heat Radio (RnB)") %} http://174.37.159.206:8106/stream
          {% elif is_state("input_select.radio_station", "Fresh 92-7") %} http://live.fresh927.com.au:80/freshaac
          {% elif is_state("input_select.radio_station", "DI Chill & Tropical House") %} http://pub1.diforfree.org:8000/di_chillntropicalhouse_hi
          {% elif is_state("input_select.radio_station", "DI Disco House") %} http://pub1.diforfree.org:8000/di_discohouse_hi
          {% elif is_state("input_select.radio_station", "DI Funky House") %} http://pub1.diforfree.org:8000/di_funkyhouse_hi
          {% elif is_state("input_select.radio_station", "DI Liquid D&B") %} http://pub1.diforfree.org:8000/di_liquiddnb_hi
          {% elif is_state("input_select.radio_station", "Aloha Joe's Relaxation Island") %} http://s2.voscast.com:7932/
          {% elif is_state("input_select.radio_station", "Spectrum Fit") %} http://51.255.235.165:5292/
          {% elif is_state("input_select.radio_station", "Energy FM Australia") %} http://s3.viastreaming.net:8502/
          {% elif is_state("input_select.radio_station", "Jazz Relax") %} http://199.195.194.94:8036/stream
          {% elif is_state("input_select.radio_station", "Australian Country") %} https://streaming.radio.co/s5ea3fdd1c/listen
          {% elif is_state("input_select.radio_station", "Rebel FM") %} https://au1.fastcast4u.com/proxy/rblgc?mp=/stream
          {% endif %}
        media_content_type: 'audio/mp4'

Adjust the entity id’s for your media players accordingly, change the radio station URL’s to whatever you want etc.

In Lovelace add a card:

entities:
  - input_select.radio_station
  - input_select.chromecast_radio
  - script.radio
  - input_number.volume_radio
header:
  image: /local/images/internet_radio.jpg
  type: picture
show_header_toggle: false
type: entities

Save this file under: www\images\internet_radio.jpg

internet_radio

…and you should end up with this:
image

6 Likes

thanks a lot. It works :slight_smile:

Not sure if this is the right forum, but would it be possible to use the same setup for TV-stations? I want to see live TV on my chromecast with a list of tv stations, like SVT1, TV4 etc (Swedish).

Hello, I have added Sonos support for my script.

  1. In the device select, all sonos devices have to have “Sonos” in the name eg.:
chromecast_radio:
    name: 'Device:'
    options:
      - Citation AMP
      - TV
      - Sonos Keittiö
    initial: Citation AMP
    icon: mdi:speaker-wireless

And here is an example how the media_content_id needs to be set:
(PS. Did not check if people have set the extra.title, but here is an example for that aswell. it will show the title in non-audio chrome cast devices and so on…)
(PPS media_content_type is music, as documentation suggests. Don’t know why OP had string there)

media_content_id: >
          {% if is_state("input_select.radio_station", "City") %}{% set url = "https://stream.bauermedia.fi/radiocity/radiocity_64.aac" %}
          {% elif is_state("input_select.radio_station", "Nostalgia") %}{% set url = "https://stream.bauermedia.fi/nostalgia/nostalgia_64.aac" %}
          {% elif is_state("input_select.radio_station", "Radio Rock") %}{% set url = "https://supla.digitacdn.net/live/_definst_/supla/radiorock/playlist.m3u8" %}
          {% endif %}
          {% if "Sonos" in states("input_select.chromecast_radio") %}x-rincon-mp3radio://{{url.split("://")[1]}}
          {% else %}{{url}}
          {% endif %}
        media_content_type: music
        extra:
          title: "{{ states('input_select.radio_station') }}"

Sonos uses the scheme x-rincon-mp3radio instead of http/https. All my streams work with https and http, so I’m not sure if sonos actually plays https streams.

:beer: Cheers, Ville

Thanks for sharing your code with specific reference to how to tackle different URL for Sonos and chromecast which works perfectly fine. I’m using the script to serve multiple rooms. For that purpose I wish to store the currently selected station for each room such that once I return to the specific room selection menu, it defaults to the currently selected/played music station. In principle it’s the reverse of the selection procedure:

 - platform: template
  sensors:
    radio_select_sonos:
      value_template: >-
          {% if is_state_attr('media_player.office', 'media_content_id', "x-rincon-mp3radio://https://21223.live.streamtheworld.com:443/SKYRADIO.mp3") %} 
            Sky Radio
           ........
          {% endif %}

This all works fine for my google chromecast devices which return the stream URL as specified. For SONOS, the situation is different. The above station returns a URL which is totally different from what was entered and moreover not consistent in what it returns. In case of the above URL, SONOS returns on the command:

 {{state_attr('media_player.office', 'media_content_id')}} the following URL which differs every time:
x-rincon-mp3radio://https://21283.live.streamtheworld.com:443/SRGSTR01.mp3

As stated, this URL is not consistent and changes very time the station is selected such that it would be impossible to store the currently selected station for the specific room.
Have you ever come across this phenomena and know how to overcome.

For chromecasts the urls should look like https://example.com and for sonos x-rincon-mp3radio://example.com. I see you are checking the state for x-rincon-mp3radio://https://example.com.
That shouldn’t work for either of the devices. Maybe try to figure out what the media_content_id for the devices are in the developer tools. Select the entity there and see what the url is. For me the Sonos has what I have set it. Anyways, I think you should read the state to a variable first and then just check if it contains the some part that is after the scheme for example:

{% set mediaIdOffice = state_attr('media_player.office', 'media_content_id') %}
{% if "SKYRADIO.mp3" in mediaIdOffice %} 
  Sky Radio
  ........
{% endif %}

Thanks a lot for putting me on a progressive trail. My URL’s specific to chromecast and sonos respectively are consistent with what you quoted in your response. Your proposed solution based on identifying string with {% if "SKYRADIO.mp3" in mediaIdOffice %} based on ‘media_content_id’ works fine for SONOS.
For chromecast using the Beosound Core, the content of ‘media_content_id’ is not always consistent and sometimes results in { {url}} response instead of the stream URL. However, I figured out that consistently and in all cases, the selected station name is being stored in ‘media_content_id’ and subsequently used instead using your if “contains-string” concept. Thanks a lot.
What I noticed though is that once changing room selection, though it defaults properly to the selected (currently running) radio station, it’s not a bumpless transfer. In other words, it reloads the currently played radio station URL. This looks obvious since one trigger is ‘input_select.radio_station’. I have tried to implement a value_template condition which, once true, will only continue with the action which contains the media_content_id’s.
To avoid a reload of the stream URL, the condition checks whether the result of the ‘mediaIdOffice’ is un-equal to ‘input_select.radio_station’ in which case fire ‘action’, otherwise stop.
If the above makes sense and you have a suggestion, I would appreciate yr feedback.

Folks, I now have everything working, sort of ;

image

But I have several ways to initiate playback on my devices. And if I use any other method than this Lovelace card, I’d like to make an automation that automatically populates this card, so that it shows the chosen settings independently of how it was initiated.
I know that it is possible to set the input.select value in a script. My problem is that if I do, it automatically also triggers the automation behind the card - just as if I had made a manual selection. This in turn again triggers the script, and I’m in a never ending loop.

So, I’m looking for a clever way to populate the on-screen display, without actually triggering the automation.
Any ideas, anyone?

Turn the automaton off before you update the input select, update it, then turn the automation back on?