I know the team is working on Home Assistant integration, until they get that going I have used the REST API within Home Assistant to setup a “universal media player”.
If there’s any interest I’d be happy to share the config.
I know the team is working on Home Assistant integration, until they get that going I have used the REST API within Home Assistant to setup a “universal media player”.
If there’s any interest I’d be happy to share the config.
Was thinking of doing the exact same thing here - would love to see your HA config if you’re willing to share!
Here’s what I’ve got so far. I think this is everything.
configuration.yaml
rest: !include rest.yaml
rest_command: !include rest_command.yaml
media_player: !include media_player.yml
rest.yaml
- scan_interval: 5
resource: http://amplipi.local/api/sources
headers:
accept: "application/json"
sensor:
- name: "AmpliPi Source 1"
value_template: "{{ value_json.sources[0].info.state }}"
json_attributes_path: "$.sources[0].info"
json_attributes:
- "name"
- "artist"
- "track"
- "album"
- "img_url"
- name: "AmpliPi Source 2"
value_template: "{{ value_json.sources[1].info.state }}"
json_attributes_path: "$.sources[1].info"
json_attributes:
- "name"
- "artist"
- "track"
- "album"
- "img_url"
- name: "AmpliPi Source 3"
value_template: "{{ value_json.sources[2].info.state }}"
json_attributes_path: "$.sources[2].info"
json_attributes:
- "name"
- "artist"
- "track"
- "album"
- "img_url"
- name: "AmpliPi Source 4"
value_template: "{{ value_json.sources[3].info.state }}"
json_attributes_path: "$.sources[3].info"
json_attributes:
- "name"
- "artist"
- "track"
- "album"
- "img_url"
- scan_interval: 2
resource: http://amplipi.local/api/zones
headers:
accept: "application/json"
sensor:
- name: "AmpliPi Zone 1"
value_template: "{{ value_json.zones[0].source_id }}"
json_attributes_path: "$.zones[0]"
json_attributes:
- "id"
- "name"
- "source_id"
- "mute"
- "disabled"
- name: "AmpliPi Zone 1 Volume"
value_template: "{{ ( value_json.zones[0].vol | default(-79) | float - -79 ) / 79 }}"
- name: "AmpliPi Zone 1 Source"
value_template: "{{ 'Input ' + ( ( value_json.zones[0].source_id | default(1) | int + 1 ) | string ) }}"
- name: "AmpliPi Zone 2"
value_template: "{{ value_json.zones[1].source_id }}"
json_attributes_path: "$.zones[1]"
json_attributes:
- "id"
- "name"
- "source_id"
- "mute"
- "vol"
- "disabled"
- name: "AmpliPi Zone 2 Volume"
value_template: "{{ ( value_json.zones[1].vol | default(-79) | float - -79 ) / 79 }}"
- name: "AmpliPi Zone 2 Source"
value_template: "{{ 'Input ' + ( ( value_json.zones[1].source_id | default(1) | int + 1 ) | string ) }}"
- name: "AmpliPi Zone 3"
value_template: "{{ value_json.zones[2].source_id }}"
json_attributes_path: "$.zones[2]"
json_attributes:
- "id"
- "name"
- "source_id"
- "mute"
- "vol"
- "disabled"
- name: "AmpliPi Zone 3 Volume"
value_template: "{{ ( value_json.zones[2].vol | default(-79) | float - -79 ) / 79 }}"
- name: "AmpliPi Zone 3 Source"
value_template: "{{ 'Input ' + ( ( value_json.zones[2].source_id | default(1) | int + 1 ) | string ) }}"
- name: "AmpliPi Zone 4"
value_template: "{{ value_json.zones[3].source_id }}"
json_attributes_path: "$.zones[3]"
json_attributes:
- "id"
- "name"
- "source_id"
- "mute"
- "vol"
- "disabled"
- name: "AmpliPi Zone 4 Volume"
value_template: "{{ ( value_json.zones[3].vol | default(-79) | float - -79 ) / 79 }}"
- name: "AmpliPi Zone 4 Source"
value_template: "{{ 'Input ' + ( ( value_json.zones[3].source_id | default(1) | int + 1 ) | string ) }}"
- name: "AmpliPi Zone 5"
value_template: "{{ value_json.zones[4].source_id }}"
json_attributes_path: "$.zones[4]"
json_attributes:
- "id"
- "name"
- "source_id"
- "mute"
- "vol"
- "disabled"
- name: "AmpliPi Zone 5 Volume"
value_template: "{{ ( value_json.zones[4].vol | default(-79) | float - -79 ) / 79 }}"
- name: "AmpliPi Zone 5 Source"
value_template: "{{ 'Input ' + ( ( value_json.zones[4].source_id | default(1) | int + 1 ) | string ) }}"
- name: "AmpliPi Zone 6"
value_template: "{{ value_json.zones[5].source_id }}"
json_attributes_path: "$.zones[5]"
json_attributes:
- "id"
- "name"
- "source_id"
- "mute"
- "vol"
- "disabled"
- name: "AmpliPi Zone 6 Volume"
value_template: "{{ ( value_json.zones[5].vol | default(-79) | float - -79 ) / 79 }}"
- name: "AmpliPi Zone 6 Source"
value_template: "{{ 'Input ' + ( ( value_json.zones[5].source_id | default(1) | int + 1 ) | string ) }}"
rest_command.yml
amplipi_zone_mute:
url: http://amplipi.local/api/zones
method: PATCH
payload: '{ "zones": [ {{ zoneId | int | default(2) - 1 }} ], "update": { "mute": {{ mute | string | lower }} } }'
headers:
content-type: 'application/json'
amplipi_zone_vol:
url: http://amplipi.local/api/zones
method: PATCH
payload: '{ "zones": [ {{ zoneId | int | default(2) - 1 }} ], "update": { "vol": {{ -79 - ( volume * -79) }} } }'
headers:
content-type: 'application/json'
amplipi_zone_source:
url: http://amplipi.local/api/zones
method: PATCH
payload: '{ "zones": [ {{ zoneId | int | default(2) - 1 }} ], "update": { "source_id": {{ sourceId | regex_findall_index("\d") | int - 1 }} } }'
headers:
content-type: 'application/json'
media_player.yml
- platform: universal
name: AmpliPi Zone 1
commands:
volume_up:
service: rest_command.amplipi_zone_vol
data:
zoneId: 1
volume: "{{ states('sensor.amplipi_zone_1_volume') | default(0.00) | float + 0.01 }}"
volume_down:
service: rest_command.amplipi_zone_vol
data:
zoneId: 1
volume: "{{ states('sensor.amplipi_zone_1_volume') | default(0.00) | float - 0.01 }}"
volume_set:
service: rest_command.amplipi_zone_vol
data:
zoneId: 1
volume: "{{ volume_level }}"
volume_mute:
service: rest_command.amplipi_zone_mute
data:
zoneId: 1
mute: "{{ not ( state_attr('sensor.amplipi_zone_1','mute') | default(False) ) }}"
select_source:
service: rest_command.amplipi_zone_source
data:
zoneId: 1
sourceId: "{{ source }}"
attributes:
volume_level: sensor.amplipi_zone_1_volume
is_volume_muted: sensor.amplipi_zone_1|mute
state: sensor.amplipi_zone_1
source: sensor.amplipi_zone_1_source
source_list: input_select.amplipi_inputs|options
device_class: speaker
- platform: universal
name: AmpliPi Zone 2
commands:
volume_up:
service: rest_command.amplipi_zone_vol
data:
zoneId: 2
volume: "{{ states('sensor.amplipi_zone_2_volume') | default(0.00) | float + 0.01 }}"
volume_down:
service: rest_command.amplipi_zone_vol
data:
zoneId: 2
volume: "{{ states('sensor.amplipi_zone_2_volume') | default(0.00) | float - 0.01 }}"
volume_mute:
service: rest_command.amplipi_zone_mute
data:
zoneId: 2
mute: "{{ not ( state_attr('sensor.amplipi_zone_2','mute') | default(False) ) }}"
volume_set:
service: rest_command.amplipi_zone_vol
data:
zoneId: 2
volume: "{{ volume_level }}"
select_source:
service: rest_command.amplipi_zone_source
data:
zoneId: 2
sourceId: "{{ source }}"
attributes:
volume_level: sensor.amplipi_zone_2_volume
is_volume_muted: sensor.amplipi_zone_2|mute
state: sensor.amplipi_zone_2
source: sensor.amplipi_zone_2_source
source_list: input_select.amplipi_inputs|options
device_class: speaker
- platform: universal
name: AmpliPi Zone 3
commands:
volume_up:
service: rest_command.amplipi_zone_vol
data:
zoneId: 3
volume: "{{ states('sensor.amplipi_zone_3_volume') | default(0.00) | float + 0.01 }}"
volume_down:
service: rest_command.amplipi_zone_vol
data:
zoneId: 3
volume: "{{ states('sensor.amplipi_zone_3_volume') | default(0.00) | float - 0.01 }}"
volume_mute:
service: rest_command.amplipi_zone_mute
data:
zoneId: 3
mute: "{{ not ( state_attr('sensor.amplipi_zone_3','mute') | default(False) ) }}"
volume_set:
service: rest_command.amplipi_zone_vol
data:
zoneId: 3
volume: "{{ volume_level }}"
select_source:
service: rest_command.amplipi_zone_source
data:
zoneId: 3
sourceId: "{{ source }}"
attributes:
volume_level: sensor.amplipi_zone_3_volume
is_volume_muted: sensor.amplipi_zone_3|mute
state: sensor.amplipi_zone_3
source: sensor.amplipi_zone_3_source
source_list: input_select.amplipi_inputs|options
device_class: speaker
- platform: universal
name: AmpliPi Zone 4
commands:
volume_up:
service: rest_command.amplipi_zone_vol
data:
zoneId: 4
volume: "{{ states('sensor.amplipi_zone_4_volume') | default(0.00) | float + 0.01 }}"
volume_down:
service: rest_command.amplipi_zone_vol
data:
zoneId: 4
volume: "{{ states('sensor.amplipi_zone_4_volume') | default(0.00) | float - 0.01 }}"
volume_mute:
service: rest_command.amplipi_zone_mute
data:
zoneId: 4
mute: "{{ not ( state_attr('sensor.amplipi_zone_4','mute') | default(False) ) }}"
volume_set:
service: rest_command.amplipi_zone_vol
data:
zoneId: 4
volume: "{{ volume_level }}"
select_source:
service: rest_command.amplipi_zone_source
data:
zoneId: 4
sourceId: "{{ source }}"
attributes:
volume_level: sensor.amplipi_zone_4_volume
is_volume_muted: sensor.amplipi_zone_4|mute
state: sensor.amplipi_zone_4
source: sensor.amplipi_zone_4_source
source_list: input_select.amplipi_inputs|options
device_class: speaker
- platform: universal
name: AmpliPi Zone 5
commands:
volume_up:
service: rest_command.amplipi_zone_vol
data:
zoneId: 5
volume: "{{ states('sensor.amplipi_zone_5_volume') | default(0.00) | float + 0.01 }}"
volume_down:
service: rest_command.amplipi_zone_vol
data:
zoneId: 5
volume: "{{ states('sensor.amplipi_zone_5_volume') | default(0.00) | float - 0.01 }}"
volume_mute:
service: rest_command.amplipi_zone_mute
data:
zoneId: 5
mute: "{{ not ( state_attr('sensor.amplipi_zone_5','mute') | default(False) ) }}"
volume_set:
service: rest_command.amplipi_zone_vol
data:
zoneId: 5
volume: "{{ volume_level }}"
select_source:
service: rest_command.amplipi_zone_source
data:
zoneId: 5
sourceId: "{{ source }}"
attributes:
volume_level: sensor.amplipi_zone_5_volume
is_volume_muted: sensor.amplipi_zone_5|mute
state: sensor.amplipi_zone_5
source: sensor.amplipi_zone_5_source
source_list: input_select.amplipi_inputs|options
device_class: speaker
- platform: universal
name: AmpliPi Zone 6
commands:
volume_up:
service: rest_command.amplipi_zone_vol
data:
zoneId: 6
volume: "{{ states('sensor.amplipi_zone_6_volume') | default(0.00) | float + 0.01 }}"
volume_down:
service: rest_command.amplipi_zone_vol
data:
zoneId: 6
volume: "{{ states('sensor.amplipi_zone_6_volume') | default(0.00) | float - 0.01 }}"
volume_mute:
service: rest_command.amplipi_zone_mute
data:
zoneId: 6
mute: "{{ not ( state_attr('sensor.amplipi_zone_6','mute') | default(False) ) }}"
volume_set:
service: rest_command.amplipi_zone_vol
data:
zoneId: 6
volume: "{{ volume_level }}"
select_source:
service: rest_command.amplipi_zone_source
data:
zoneId: 6
sourceId: "{{ source }}"
attributes:
volume_level: sensor.amplipi_zone_6_volume
is_volume_muted: sensor.amplipi_zone_6|mute
state: sensor.amplipi_zone_6
source: sensor.amplipi_zone_6_source
source_list: input_select.amplipi_inputs|options
device_class: speaker
And since they want you to use the interface for input_select I created an entry in the interface named “AmpliPi Inputs” and gave it 4 values, “Input 1”, “Input 2”, “Input 3”, “Input 4”
This allows your media player’s to change input. I couldn’t find a way in Home Assistant to make that list dynamic from REST, there are some limitations in the RESTful sensors that I couldn’t figure out how to work around.
I didn’t do any REST commands for changing the stream on the inputs themselves yet.
This is a great start, thanks so much sharing -
A correction for the mute values in media_player.yml:
mute: "{{ is_volume_muted }}"
instead of
mute: "{{ not ( state_attr('sensor.amplipi_zone_1','mute') | default(False) ) }}"
I’ve been working on trying to get media playback controls to appear in the HA Lovelace front-end. In my rest_command.yaml, I added the following:
amplipi_stream_exec:
url: http://amplipi.local/api/streams/{{ sid }}/{{ cmd }}
method: POST
headers:
accept: "application/json"
This works, when I use the built-in HA Developer Tools → Service with the following yaml:
service: rest_command.amplipi_stream_exec
data:
sid: 1002 # hard-coded for testing, applies to Spotify stream
cmd: next
Then, to add the controls to the media player, I extended media_player.yaml with the following:
media_next_track:
service: rest_command.amplipi_stream_exec
data:
sid: 1002
cmd: next
This does not work. I have tried putting the data in {}, in “” and multiple other permutations & combinations. I have also tried changing the “attribute: device_class:” to tv and receiver, but am still not seeing any controls.
I have posted a question on the HA forums, but have not had any replies thus far. If anyone here has any insight, I will share my working (hopefully!) config.
That looks correct, I have had issues with things wanting quotes, I’d try:
data:
sid: 1002
cmd: "next"
See if that works?
I’m currently using the spotify and mopidy integrations in HA to control what’s playing on the AmpliPi so I’ve not had a need for the controls, sorry.
There is now a functional HA integration here GitHub - brianhealey/hacs_amplipi: Adds media player support for the AmpliPi MultiZone Audio Player in case anyone else does what I did and finds this thread first.
Just pushed an update that makes it more compatible with 0.1.8.