Help with RESTful Sensor to create buttons for a set of radio presets

Hi there, trying to get my head around the usage of a RESTful Sensor and how to combine various methods and pieces of HA to achieve my goal.

First of all, I’d say my biggest problem right now is that I just don’t know how to “debug” the RESTful Sensor I’m trying to create. I created it in configuration.yaml (well in fact in a sensors.yaml since I’m spreading the config a bit but that doesn’t change) and each time I try to figure out if my small change worked, I need to save, and restart HA then check the sensor just to see it’s still showing “Unknown”. Maybe the “developer” module would help but I really didn’t find how to do that. Ideally I’d like to be able to type the configuration and similarly to when creating some widget component, have some kind of live update of the sensor so that I can see if I’m heading the correct direction, how the result payload is being parsed and so on. If you know something to that regards, please tell me so that I can better debug and figure out stuff on my own.

Context

I have a NAD amplifier with a BluOS component and that lets me preset (in that context) internet radio broadcasts as preset 1, preset 2, …

My goal is to present a dynamic list of those presets in HA so that I can tap an image and get the amplifier tune in to that preset.

What I achieved so far

I manually created some shell commands to integrate:

shell_command:
  blueos_launch_rts: 'bash /config/shell/blueos_launch_preset.sh "RTS La Première"'
  blueos_launch_radioswisspop: 'bash /config/shell/blueos_launch_preset.sh "Radio Swiss Pop"'
  blueos_launch_radioswissclassic: 'bash /config/shell/blueos_launch_preset.sh "Radio Swiss Classic"'
  blueos_launch_radioswissjazz: 'bash /config/shell/blueos_launch_preset.sh "Radio Swiss Jazz"'
  blueos_launch_nrj: 'bash /config/shell/blueos_launch_preset.sh "NRJ"'
  blueos_launch_europe1: 'bash /config/shell/blueos_launch_preset.sh "Europe 1"'

My script will then do a few curl requests to the API to basically:

  1. Set the volume to 50 (GET to http://10.20.30.41:11000/Volume?level=50)
  2. Wait “a little bit” (right now 2 sec is fine and way too much but anyway)
  3. Tune in using GET on http://10.20.30.41:11000/Play?url=<some-url>

Those 6 shell commands are manually configured as the tap_action of 6 custom:button-card:

Goal is to get those buttons dynamically

Instead of calling a shell script I imagine it should be possible to fire one or more GET calls to the API. But if that’s too complex, I can still rely on a shell script, with some dynamic parameter passed for instance.

API endpoint http://10.20.30.41:11000/Presets returns a XML:

<?xml version="1.0" encoding="UTF-8"?>
<presets prid="0">
  <preset id="1" name="91.0 | RTS La Première (Culture)" url="TuneIn:s6809/http://opml.radiotime.com/Tune.ashx?id=s6809&amp;formats=wma,mp3,aac,ogg,hls&amp;partnerId=8OeGua6y&amp;serial=5C:DC:96:DD:16:E2" image="http://cdn-radiotime-logos.tunein.com/s6809q.png" volume="49"></preset>
  <preset id="2" name="Radio Swiss Pop" url="TuneIn:s25243" image="http://cdn-radiotime-logos.tunein.com/s25243g.png"></preset>
  <preset id="3" name="Radio Swiss Classic" url="TuneIn:s25582" image="http://cdn-profiles.tunein.com/s25582/images/logog.jpg?t=638797534050000000"></preset>
  <preset id="4" name="Radio Swiss Jazz" url="TuneIn:s6814" image="http://cdn-profiles.tunein.com/s6814/images/logog.jpg?t=638811105710000000"></preset>
  <preset id="5" name="NRJ" url="TuneIn:s170914" image="http://cdn-profiles.tunein.com/s2339/images/logog.png?t=500"></preset>
  <preset id="6" name="Europe 1" url="TuneIn:s74923" image="http://cdn-profiles.tunein.com/s6566/images/logog.png?t=2"></preset>
</presets>

I need to retrieve url and image to prepare my buttons. url being the URL to pass to the /Play=url=... endpoint.

Reading the doc of RESTful Sensor:

But since I don’t know how to debug, I’m lost trying to combine pieces together. I’m not even sure how I can somehow “create a list of [radio] presets” as some sensor or whatever and then somehow iterate to dynamically generate my buttons:

type: grid
square: false
columns: 3
cards:
  - type: custom:button-card
    name: RTS
    show_name: false
    show_entity_picture: true
    entity_picture: http://cdn-radiotime-logos.tunein.com/s6809q.png
    tap_action:
      action: call-service
      service: shell_command.blueos_launch_rts
    styles:
      card:
        - aspect-ratio: 1/1
        - width: 100px
        - border-radius: 5px
        - border-width: 2px
      icon:
        - width: 100%
        - height: 100%
  - type: custom:button-card
    name: NRJ
	...

So any help, ideally from the debugging steps up to, hints, direction, ideas, … for the rest would be extremely helpful.

Many thanks.

Found in another post that I could add this to my configuration.yaml:

logger:
  default: info
  logs:
    homeassistant.components.rest: debug

I now have a file /homeassistant/home-assistant.log which shows something useful for debugging:

2025-10-17 16:33:06.109 DEBUG (MainThread) [homeassistant.components.rest.data] REST response from http://10.20.30.41:11000/Presets: status=200, content-type=application/xml, length=1047
2025-10-17 16:33:06.110 DEBUG (MainThread) [homeassistant.components.rest.data] Data fetched from resource: <?xml version="1.0" encoding="UTF-8"?>
<presets prid="0">
  <preset id="1" name="91.0 | RTS La Première (Culture)" url="TuneIn:s6809/http://opml.radiotime.com/Tune.ashx?id=s6809&amp;formats=wma,mp3,aac,ogg,hls&amp;partnerId=8OeGua6y&amp;serial=5C:DC:96:DD:16:E2" image="http://cdn-radiotime-logos.tunein.com/s6809q.png" volume="49"></preset>
  <preset id="2" name="Radio Swiss Pop" url="TuneIn:s25243" image="http://cdn-radiotime-logos.tunein.com/s25243g.png"></preset>
  <preset id="3" name="Radio Swiss Classic" url="TuneIn:s25582" image="http://cdn-profiles.tunein.com/s25582/images/logog.jpg?t=638797534050000000"></preset>
  <preset id="4" name="Radio Swiss Jazz" url="TuneIn:s6814" image="http://cdn-profiles.tunein.com/s6814/images/logog.jpg?t=638811105710000000"></preset>
  <preset id="5" name="NRJ" url="TuneIn:s170914" image="http://cdn-profiles.tunein.com/s2339/images/logog.png?t=500"></preset>
  <preset id="6" name="Europe 1" url="TuneIn:s74923" image="http://cdn-profiles.tunein.com/s6566/images/logog.png?t=2"></preset>
</presets>
2025-10-17 16:33:06.110 DEBUG (MainThread) [homeassistant.components.rest.data] JSON converted from XML: {"presets":{"@prid":"0","preset":[{"@id":"1","@name":"91.0 | RTS La Première (Culture)","@url":"TuneIn:s6809/http://opml.radiotime.com/Tune.ashx?id=s6809&formats=wma,mp3,aac,ogg,hls&partnerId=8OeGua6y&serial=5C:DC:96:DD:16:E2","@image":"http://cdn-radiotime-logos.tunein.com/s6809q.png","@volume":"49"},{"@id":"2","@name":"Radio Swiss Pop","@url":"TuneIn:s25243","@image":"http://cdn-radiotime-logos.tunein.com/s25243g.png"},{"@id":"3","@name":"Radio Swiss Classic","@url":"TuneIn:s25582","@image":"http://cdn-profiles.tunein.com/s25582/images/logog.jpg?t=638797534050000000"},{"@id":"4","@name":"Radio Swiss Jazz","@url":"TuneIn:s6814","@image":"http://cdn-profiles.tunein.com/s6814/images/logog.jpg?t=638811105710000000"},{"@id":"5","@name":"NRJ","@url":"TuneIn:s170914","@image":"http://cdn-profiles.tunein.com/s2339/images/logog.png?t=500"},{"@id":"6","@name":"Europe 1","@url":"TuneIn:s74923","@image":"http://cdn-profiles.tunein.com/s6566/images/logog.png?t=2"}]}}
2025-10-17 16:33:06.110 ERROR (MainThread) [homeassistant.core] State {"presets":{"@prid":"0","preset":[{"@id":"1","@name":"91.0 | RTS La Première (Culture)","@url":"TuneIn:s6809/http://opml.radiotime.com/Tune.ashx?id=s6809&formats=wma,mp3,aac,ogg,hls&partnerId=8OeGua6y&serial=5C:DC:96:DD:16:E2","@image":"http://cdn-radiotime-logos.tunein.com/s6809q.png","@volume":"49"},{"@id":"2","@name":"Radio Swiss Pop","@url":"TuneIn:s25243","@image":"http://cdn-radiotime-logos.tunein.com/s25243g.png"},{"@id":"3","@name":"Radio Swiss Classic","@url":"TuneIn:s25582","@image":"http://cdn-profiles.tunein.com/s25582/images/logog.jpg?t=638797534050000000"},{"@id":"4","@name":"Radio Swiss Jazz","@url":"TuneIn:s6814","@image":"http://cdn-profiles.tunein.com/s6814/images/logog.jpg?t=638811105710000000"},{"@id":"5","@name":"NRJ","@url":"TuneIn:s170914","@image":"http://cdn-profiles.tunein.com/s2339/images/logog.png?t=500"},{"@id":"6","@name":"Europe 1","@url":"TuneIn:s74923","@image":"http://cdn-profiles.tunein.com/s6566/images/logog.png?t=2"}]}} for sensor.bluos_presets is longer than 255, falling back to unknown

The end is interesting, it explains why I get the Unknown in my sensor:

...ages/logog.png?t=2"}]}} for sensor.bluos_presets is longer than 255, falling back to unknown

That’s not quick to debug but at least I can debug a bit.

I’m there:

- platform: rest
  name: bluos_presets
  resource: http://10.20.30.41:11000/Presets
  value_template: "{{ value_json.presets.preset | count() }}"

gives me a sensor with “6” [presets].

But still lost about the very concept of getting a list of presets with some attributes. Unsure this can be achieved the way I imagine it, sensor has some state, possibly attributes but that’s a single entity, I guess I’m looking for some kind of “collection” instead.