I'm after a device running Music Assistant and Voice Assist ... but for my 75 year old mum it needs a simple user interface, probably with a dozen radio buttons for playlists and radio stations, suitable for playing music in the background as she's cooking.
All the music players I found a few years ago seem designed for audiophiles who want all the bells and whistles as they select each track individually 
Is this even possible with MA ? Can you point me in the right direction or suggest appropriate keywords to search for ?
FYI, this is the python program I wrote a few years ago as a front end to mpd and running on a RasPi. My other option is to try adding Linux Voice Assist to this.
I'm using LMS instead of MA, so I don't know the details of MA, but basic control can be achieved using media_player services. Since you're no stranger to programming, you could create the UI yourself, for example, using custom:button-card. Basic JavaScript and CSS knowledge will be sufficient.
If you'd like to try it, to get you started, here's a dashboard/view in single-card mode that mimics part of your program:
Code
views:
- type: panel
path: music
title: Music
cards:
- type: custom:button-card
show_name: false
variables:
player: media_player.squeezeesp32
stateObj: '[[[ return states[variables.player]; ]]]'
state: '[[[ return variables.stateObj?.state; ]]]'
attrs: '[[[ return variables.stateObj?.attributes; ]]]'
volume: '[[[ return variables.attrs?.volume_level; ]]]'
title: '[[[ return variables.attrs?.media_title; ]]]'
artist: '[[[ return variables.attrs?.media_artist; ]]]'
album: '[[[ return variables.attrs?.media_album_name; ]]]'
contentId: '[[[ return variables.attrs?.media_content_id; ]]]'
name: '[[[ return variables.state ]]]'
styles:
card:
- cursor: default
- padding: 16px
grid:
- text-align: start
- font-size: 125%
- grid-template-areas: |
"title title title title ."
"album album album . ."
"up pause prev . ."
"down pause next . ."
"r1 . . . ."
"r2 . . . ."
"r3 . . . ."
- grid-template-rows: auto
- grid-template-columns: repeat(3, 150px) auto
custom_fields:
title:
- background-color: rgba(var(--rgb-card-background-color),0.5)
- padding: 4px
- margin-bottom: 8px
album:
- background-color: rgba(var(--rgb-card-background-color),0.5)
- padding: 4px
- margin-bottom: 16px
pause:
- margin: 0px 8px
up:
- margin-bottom: 8px
prev:
- margin-bottom: 8px
r1:
- margin-top: 16px
- margin-bottom: 8px
r2:
- margin-bottom: 8px
custom_fields:
title: '[[[ return `${variables.title} - ${variables.artist}`; ]]]'
album: '[[[ return variables.album ?? ''-- no album --''; ]]]'
up:
card:
type: custom:button-card
name: Vol +
styles:
card:
- background-color: var(--card-background-color)
- font-size: 1em
tap_action:
action: |
[[[
const v = variables.volume;
return isNaN(v) || v == 1 ? 'none' : 'perform-action'
]]]
perform_action: media_player.volume_set
target:
entity_id: '[[[ return variables.player; ]]]'
data:
volume_level: '[[[ return Math.min(variables.volume + 0.05, 1); ]]]'
down:
card:
type: custom:button-card
name: Vol -
styles:
card:
- background-color: var(--card-background-color)
- font-size: 1em
tap_action:
action: |
[[[
const v = variables.volume;
return isNaN(v) || v == 0 ? 'none' : 'perform-action'
]]]
perform_action: media_player.volume_set
target:
entity_id: '[[[ return variables.player; ]]]'
data:
volume_level: '[[[ return Math.max(variables.volume - 0.05, 0); ]]]'
pause:
card:
type: custom:button-card
name: Pause
styles:
card:
- background-color: var(--card-background-color)
- font-size: 1em
- min-height: 3em
tap_action:
action: perform-action
perform_action: media_player.media_pause
target:
entity_id: '[[[ return variables.player; ]]]'
prev:
card:
type: custom:button-card
name: << Prev
styles:
card:
- background-color: var(--card-background-color)
- font-size: 1em
tap_action:
action: perform-action
next:
card:
type: custom:button-card
name: Next >>
styles:
card:
- background-color: var(--card-background-color)
- font-size: 1em
tap_action:
action: perform-action
r1:
card:
type: custom:button-card
name: Radio NŚ
styles:
card:
- background-color: |
[[[
const me = 'ypqt40u0x1zuv';
const id = variables.contentId;
const title = variables.title;
return id.includes(me) || title.includes(me) ? 'brown' : 'var(--card-background-color)';
]]]
- font-size: 1em
tap_action:
action: perform-action
perform_action: media_player.play_media
target:
entity_id: '[[[ return variables.player; ]]]'
data:
media_content_id: https://n20a-eu.rcs.revma.com/ypqt40u0x1zuv
media_content_type: music
r2:
card:
type: custom:button-card
name: Radio 357
styles:
card:
- background-color: |
[[[
const me = 'an1ugyygzk8uv';
const id = variables.contentId;
const title = variables.title;
return id.includes(me) || title.includes(me) ? 'brown' : 'var(--card-background-color)';
]]]
- font-size: 1em
tap_action:
action: perform-action
perform_action: media_player.play_media
target:
entity_id: '[[[ return variables.player; ]]]'
data:
media_content_id: https://n31a-eu.rcs.revma.com/an1ugyygzk8uv
media_content_type: music
r3:
card:
type: custom:button-card
name: Other radio
styles:
card:
- background-color: |
[[[
const me = 'xyz';
const id = variables.contentId;
const title = variables.title;
return id.includes(me) || title.includes(me) ? 'brown' : 'var(--card-background-color)';
]]]
- font-size: 1em
Colors come from my theme; you have full control over colors, font sizes, etc.; you can embed helpers/selectors (e.g. through entities card); you can enhance/declutter the code with custom button templates.
Thanks slimak, I haven't used custom:button-card before, but it does look like what I'm after, and it's been quite a while since I've done much website development - so I have some work ahead
Thank you also for such a large chunk of code to get me started ... most appreciated.
So, if I understand correctly, the idea is to install Linux Voice Assist and a browser (to run full-screen in kiosk mode) on the Kitchen RasPi, with the browser configured to log into HA as a user who only sees the Music panel.
Ha! If you have experience with web development, UI should be easy. For me, the hardest part is always tackling CSS
Ask if you have any problems.
CSS obviously hasn't gotten any better in the past 20 years
Except maybe that the C now stands for "complex" instead of "cascading"