Home Assistant Temporary REST Integration

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.

1 Like

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.

1 Like

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.

3 Likes

Just pushed an update that makes it more compatible with 0.1.8.

1 Like