Hi everyone,
I created a script today to ask assist things like:
“Search a few albums from Daft Punk to select from.”
“Show me some playlists with breakfast in the name.”
“Is there a song called She Moves from Graham Candy available?”
And as you’re talking to an LLM, that can process the result before replying, my kids tested:
“Search for Minions albums, but we want funny music and not movie soundtracks or audiobooks.”
Which only replied with a few albums that aren’t the OST or audiobook of one of the movies (they were in the result of the script, but filtered out by the LLM).
Together with the Full LLM Music Assistant Blueprint from @TheFes collection ( GitHub - TheFes/ha-blueprints: Home Assistant Blueprints for (voice) commands ), you can then tell assist to play the result e.g. in the living room.
This is already way cooler than Alexas music control, and this was one of the points where she was better than custom voice assistants for a looong time. ![]()
Another example:
“List me 10 songs from Lilly Wood and the Prick”
And then tell assist to play number 1,3,8 from the list in the kitchen (which again calls the exisiting Music Assistant script linked above, with the correct parameters to start the playback with the first song and enqueue the rest).
It’s more or less a thin wrapper around the music assistant “search” action, that filters out unneeded field:
(This is a simple script, shared with the LLM assistant. Not a intent_script.)
alias: Music Library Search
icon: mdi:search-web
description: >
Use this tool to search for Radio Stations or available music in the streaming
services we subscribed. Attention: if you search for songs of an artist, the
media_return_type is track, as you search for tracks. media_return_type artist
is only for searching artists, not songs of artists.
fields:
media_return_type:
name: Media Return Type
description: >-
Choose the right category that you want to be returned (Not the type you
provide as search_query). If you search for multiple artists, choose
artist. If you search for tracks from an artist, choose track.
required: true
selector:
select:
options:
- track
- artist
- album
- playlist
- radio
search_query:
name: Search String
description: >-
Could be the artist name, a specific track name, both combined with a dash
between, a radio station name, a playlist name
required: true
selector:
text: {}
limit:
name: Limit
description: >-
Set the maximum results you want to get back. If you only need a single
match set limit to 5, which is the minimum value when calling this tool.
If the user requested a longer list, set the limit to something larger
than 5 as needed.
required: true
selector:
number:
min: 0
max: 50
mode: slider
sequence:
- data:
name: "MUSIC LIBRARY SEARCH: "
message: "{{ media_return_type, search_query,limit }}"
entity_id: "{{ this.entity_id }}"
action: logbook.log
- data:
config_entry_id: 01JH0XS4ZEMCFN1DTCH87B3G50
media_type:
- "{{ media_return_type }}"
name: "{{ search_query }}"
limit: "{{ limit }}"
artist: ""
album: ""
library_only: false
response_variable: raw_result
action: music_assistant.search
- variables:
simplified_result: >
{%- set ns = namespace(
tracks = [],
albums = [],
artists = [],
radio = [],
playlists= []
) %}
{# -------- TRACKS -------- #} {%- for t in raw_result.tracks |
default([]) %}
{%- set track_artist = (t.artists | default([]))[0].name
if (t.artists | default([]))|length > 0
else none %}
{%- set album_name = t.album.name
if t.album is defined and t.album.name is defined
else none %}
{%- set album_artist = (t.album.artists | default([]))[0].name
if t.album is defined
and (t.album.artists | default([]))|length > 0
else none %}
{%- set ns.tracks = ns.tracks + [{
'name': t.name,
'artist': track_artist,
'album': {
'name': album_name,
'artist': album_artist
}
}] %}
{%- endfor %}
{# -------- ALBUMS -------- #} {%- for a in raw_result.albums |
default([]) %}
{%- set album_artist = (a.artists | default([]))[0].name
if (a.artists | default([]))|length > 0
else none %}
{%- set ns.albums = ns.albums + [{
'name': a.name,
'artist': album_artist
}] %}
{%- endfor %}
{# -------- ARTISTS -------- #} {%- for ar in raw_result.artists |
default([]) %}
{%- set ns.artists = ns.artists + [{'name': ar.name}] %}
{%- endfor %}
{# -------- RADIO -------- #} {%- for r in raw_result.radio |
default([]) %}
{%- set ns.radio = ns.radio + [{'name': r.name}] %}
{%- endfor %}
{# -------- PLAYLISTS -------- #} {%- for p in raw_result.playlists |
default([]) %}
{%- set ns.playlists = ns.playlists + [{'name': p.name}] %}
{%- endfor %}
{{ {
'tracks': ns.tracks,
'albums': ns.albums,
'artists': ns.artists,
'radio': ns.radio,
'playlists': ns.playlists
} }}
- stop: ""
response_variable: simplified_result
You might have to set the config_entry_id to the one of your Music Assistant instance. ![]()
In the script is the current stable Music Assistant version identifier.
If you use the beta, try this one: 01JH0XS4ZEMCFN1DTCH87B3G50
In case it changed over the time look it up here:
Developer Tools → Actions → Music Assistant Search → Select the Music Assistant instance in the dropdown → Switch to YAML view and copy the needed id.
Some notes on the description and my prompt:
I changed the description of the existing Music Assistant Play Script / Blueprint linked from TheFes repo above, that it is to PLAY music (I removed the part where it stated “search and play”)
And I added that there is another script (this new one here) to search music.
Then in my prompt I have this section:
There are 2 tools to start media playback.
Always prefer “<NameOfTheOtherScriptOfTheFesRepo>” over HassMediaSearchAndPlay, as the latter one isn’t working currently.
If you only search for music, but won’t play it, use “<NameOfThisScript>”
This also solves the problem, that HA has it’s own “Play” tool now, which seems to be preferred by Assist.
That’s why I told it, that it wouldn’t work atm, so it doesn’t touch it anymore. ![]()
One last note:
I do all my automations in Node-RED.
So also my LLM Scripts use normally Nored.Trigger to call a flow and an event to hand the response back to the script.
But as this worked so wonderful, I thought it should be shared.
As I never touched Jinja beside some VERY simple templates, I asked ChatGPT O3 to convert the logic.
It works, but I don’t know if it’s best practise.
Fell free to post improvements if needed. ![]()

