Hi, i was switching my system from Google Cast Multiroom over to Alexa for various reasons. However, one thing that consistently annoyed me, was the lack of fine tuned volume control for Alexa in different rooms.
Logging in to the website to select each Echo and choose the volume was super annoying. On top, the spotify volume control turned all the echos to the same volume level. This is super impractical since the echo 2nd gen much louder than the rest.
So, i set out to build my own (google home) inspired volume control for Alexa.
It all works thanks to the genious Alexander Noack and his Shell Script for logging into your Alexa account and getting the data. More infos: Lötzimmer: Amazon Alexa per Shell fernsteuern (Echo remote control)
In order to make this work with shell_command i had to use the plain version (without JQ Parser) as this is not supported by the shell_command. Furthermore, shell_command does not support multiple commands ala:
"do this" | "then that" | "then that"
In order to get it working i had to write extra shell scripts and simply run 1 dynamic command from a home assistant automation that triggers the shell script.
This is how it currently looks:
I created 5 input_number sliders. (1 for each echo playing in the group, and 1 for the group)
Scale 1 - 100 for the volume levels you can set for the echos.
If you turn up the volume level of the original echos, the group volume level is turned up by a 1/4 of it respectively Meaning:
Volume 1: 0%
Volume 2: 0%
Voume 3: 0%
Volume 4: 100%
Results in 25% Volumelevel for the Group.
Reflecting the groupvolume level to the individual echos was a much harder task and i used some formulas to calculate the required percentage change.
If you turn down the groupvolume, the biggest indiviual volume levels will turn down fast than the lower volumelevels until it levels out at 0. However, keeping the approximated overall distribution of the volume levels
Vice Verca for the turning up the groupvolume. The lowest individual volume levels will rise faster until every volume meets again at 100%.
On top, i cut the volume level i can set for my echo 2nd gen (remember, i said its much louder than the rest) by 50%. So 50% overall volume level will be the maximum the echo will reach.
In order to also get individual volumelevels you manually set (voice or direct input) reflected into the home assistant I have an extra script that scrapes the volume levels periodicly and posts them via the home assistant API. (I only run this script if something is playing, and I am at home)
Please note: I’m not at all a programmer… This took me way too much time and nervers and my code most probably is ugly and can be optimized heavily. Please do so and share how to do this Would love to learn from you! - Maybe somebody could use parts of this to make a component for Alexa speakers, that would be a dream… anyway here is what you need to make it happen:
automation:
- alias: setslidergroup
condition:
- condition: state
entity_id: 'input_boolean.gruppe2'
state: 'off'
trigger:
- platform: state
entity_id: input_number.alexa_wohnzimmer
- platform: state
entity_id: input_number.alexa_schlafzimmer
- platform: state
entity_id: input_number.alexa_kuche
- platform: state
entity_id: input_number.alexa_bad
action:
- service: input_boolean.turn_on
data:
entity_id: input_boolean.gruppe
- service: input_number.set_value
data_template:
entity_id: input_number.alexa_gruppe
value: >
{% if ((states.input_number.alexa_gruppe.state | int) + (((trigger.to_state.state | int - trigger.from_state.state | int) / 4) | round)) < 0 %}
{% set value = (0) %}
{% else %}
{% set value = states.input_number.alexa_gruppe.state | int + ((trigger.to_state.state | int - trigger.from_state.state | int) / 4) | round %}
{% endif %}
{{value}}
- service: input_boolean.turn_off
data:
entity_id: input_boolean.gruppe
- alias: setsliderindividual
condition:
- condition: state
entity_id: 'input_boolean.gruppe'
state: 'off'
trigger:
- platform: state
entity_id: input_number.alexa_gruppe
action:
- service: input_boolean.turn_on
data:
entity_id: input_boolean.gruppe2
- service: input_number.set_value
data_template:
entity_id: input_number.alexa_wohnzimmer
value: >
{% if (((trigger.to_state.state | int - trigger.from_state.state | int)) | round) <= 0 %}
{% set value = ((states.input_number.alexa_wohnzimmer.state | int) * ((trigger.to_state.state | int / trigger.from_state.state | int)) ) %}
{%-elif (((trigger.to_state.state | int - trigger.from_state.state | int)) | round) > 0 %}
{% set value = (((trigger.to_state.state | int - trigger.from_state.state | int) / ( 100 - trigger.from_state.state | int) * (( 100 - states.input_number.alexa_wohnzimmer.state | int))) + (states.input_number.alexa_wohnzimmer.state | int)) %}
{% endif %}
{{value}}
- service: input_number.set_value
data_template:
entity_id: input_number.alexa_bad
value: >
{% if (((trigger.to_state.state | int - trigger.from_state.state | int)) | round) <= 0 %}
{% set value = ((states.input_number.alexa_bad.state | int) * ((trigger.to_state.state | int / trigger.from_state.state | int)) ) %}
{%-elif (((trigger.to_state.state | int - trigger.from_state.state | int)) | round) > 0 %}
{% set value = (((trigger.to_state.state | int - trigger.from_state.state | int) / ( 100 - trigger.from_state.state | int) * (( 100 - states.input_number.alexa_bad.state | int))) + (states.input_number.alexa_bad.state | int)) %}
{% endif %}
{{value}}
- service: input_number.set_value
data_template:
entity_id: input_number.alexa_schlafzimmer
value: >
{% if (((trigger.to_state.state | int - trigger.from_state.state | int)) | round) <= 0 %}
{% set value = ((states.input_number.alexa_schlafzimmer.state | int) * ((trigger.to_state.state | int / trigger.from_state.state | int)) ) %}
{%-elif (((trigger.to_state.state | int - trigger.from_state.state | int)) | round) > 0 %}
{% set value = (((trigger.to_state.state | int - trigger.from_state.state | int) / ( 100 - trigger.from_state.state | int) * (( 100 - states.input_number.alexa_schlafzimmer.state | int))) + (states.input_number.alexa_schlafzimmer.state | int)) %}
{% endif %}
{{value}}
- service: input_number.set_value
data_template:
entity_id: input_number.alexa_kuche
value: >
{% if (((trigger.to_state.state | int - trigger.from_state.state | int)) | round) <= 0 %}
{% set value = ((states.input_number.alexa_kuche.state | int) * ((trigger.to_state.state | int / trigger.from_state.state | int)) ) %}
{%-elif (((trigger.to_state.state | int - trigger.from_state.state | int)) | round) > 0 %}
{% set value = (((trigger.to_state.state | int - trigger.from_state.state | int) / ( 100 - trigger.from_state.state | int) * (( 100 - states.input_number.alexa_kuche.state | int))) + (states.input_number.alexa_kuche.state | int)) %}
{% endif %}
{{value}}
- service: input_boolean.turn_off
data:
entity_id: input_boolean.gruppe2
#########################################################################################################################################################
- alias: VolumecontrolWohnzimmer
trigger:
- platform: state
entity_id: input_number.alexa_wohnzimmer
action:
- service: shell_command.volume
data_template:
level: -d Wohnzimmer -e vol:{{states.input_number.alexa_wohnzimmer.state | int}}
- alias: VolumecontrolSchlafzimmer
trigger:
- platform: state
entity_id: input_number.alexa_schlafzimmer
action:
- service: shell_command.volume
data_template:
level: -d Schlafzimmer -e vol:{{states.input_number.alexa_schlafzimmer.state | int}}
- alias: VolumecontrolKuche
trigger:
- platform: state
entity_id: input_number.alexa_kuche
action:
- service: shell_command.volume
data_template:
level: -d KĂĽche -e vol:{{(states.input_number.alexa_kuche.state | int / 2) | int }}
- alias: VolumecontrolBad
trigger:
- platform: state
entity_id: input_number.alexa_bad
action:
- service: shell_command.volume
data_template:
level: -d Bad -e vol:{{states.input_number.alexa_bad.state | int}}
################################################# VOLUME CONTROL UPDATE ###################
- alias: UpdateVolumeSystemstart
trigger:
- platform: homeassistant
event: start
action:
- service: shell_command.volumeupdate
############################################### periodicly update if home, tag/nacht & spotify is playing
- alias: UpdateVolumeperiodicly
trigger:
- platform: time
minutes: '/10'
seconds: 0
condition:
condition: and
conditions:
- condition: template
value_template: "{% if is_state('media_player.spotify', 'playing') %}true{% endif %}"
- condition: state
entity_id: device_tracker.marcus_marcus
state: 'home'
- condition: template
value_template: "{% if not is_state('input_select.mode', 'Away') %}true{% endif %}"
action:
- service: shell_command.volumeupdate
bash:
#!/bin/sh
# This is a comment!
volumewohnzimmer=$(/share/alexa_remote_control_plain_volume.sh -q -d Wohnzimmer | grep -E '"volume":([0-9])*' -o | grep -E -o '([0-9])*')
volumeschlafzimmer=$(/share/alexa_remote_control_plain_volume.sh -q -d Schlafzimmer | grep -E '"volume":([0-9])*' -o | grep -E -o '([0-9])*')
volumebad=$(/share/alexa_remote_control_plain_volume.sh -q -d Bad | grep -E '"volume":([0-9])*' -o | grep -E -o '([0-9])*')
volumekuche=$(/share/alexa_remote_control_plain_volume.sh -q -d KĂĽche | grep -E '"volume":([0-9])*' -o | grep -E -o '([0-9])*')
answer="$((($volumekuche +1) * 2 -2))"
#echo $answer
curl -X POST -H "x-ha-access: <YOURPASSWORD>" -H "Content-Type: application/json" -d '{"entity_id": "input_number.alexa_wohnzimmer", "value":"'"$volumewohnzimmer"'"}' http:///HOMEASSISTANT_IP:8123/api/services/input_number/set_value
curl -X POST -H "x-ha-access: <YOURPASSWORD>" -H "Content-Type: application/json" -d '{"entity_id": "input_number.alexa_schlafzimmer", "value":"'"$volumeschlafzimmer"'"}' http:///HOMEASSISTANT_IP:8123/api/services/input_number/set_value
curl -X POST -H "x-ha-access: <YOURPASSWORD>" -H "Content-Type: application/json" -d '{"entity_id": "input_number.alexa_kuche", "value":"'"$answer"'"}' http://HOMEASSISTANT_IP:8123/api/services/input_number/set_value
curl -X POST -H "x-ha-access: <YOURPASSWORD>" -H "Content-Type: application/json" -d '{"entity_id": "input_number.alexa_bad", "value":"'"$volumebad"'"}' http://HOMEASSISTANT_IP:8123/api/services/input_number/set_value
shell_command:
volume: /share/alexa_remote_control_plain_volume.sh {{level}}
volumeupdate: /share/alexavolume_plain.sh