Last active
July 20, 2024 06:32
-
-
Save aschamberger/ee3934d3d6fe87fae99da495c0065992 to your computer and use it in GitHub Desktop.
HA Automation Blueprint: Control Logitech Squeezebox media player entities from KNX switching and relative dimming (DPT 3.007) telegrams.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
blueprint: | |
name: KNX - Squeezebox control | |
description: Control Logitech Squeezebox media player entities from KNX switching and relative | |
dimming (DPT 3.007) telegrams. | |
homeassistant: | |
# `knx.telegram` trigger and `enabled` templates require Home Assistant 2024.6.0 | |
min_version: "2024.6.0" | |
domain: automation | |
input: | |
media_player: | |
name: Squeezebox media player | |
description: The Squeezebox instance that shall be controled. | |
selector: | |
entity: | |
domain: media_player | |
dimm_helper: | |
name: Helper for relative dimming | |
description: Relative dimming 'toggle helper' to handle stop command | |
selector: | |
entity: | |
domain: input_boolean | |
default: {} | |
switch_address: | |
name: Switch group address | |
description: > | |
Group address for switching the player on and off (DPT 1.001). | |
Example: '8/3/20' | |
default: null | |
state_address: | |
name: State group address | |
description: > | |
Group address for player state (DPT 1.001). | |
Example: '8/3/21'' | |
default: null | |
dimm_address: | |
name: Volume relative dimming address | |
description: > | |
Group address for dimming the volume (DPT 3.007). | |
Example: '8/3/22' | |
default: null | |
volume_state_address: | |
name: Volume state group address | |
description: > | |
Group address for player volume (DPT 5.001). | |
Example: '8/3/23' | |
default: null | |
favorite_address: | |
name: favorite group address | |
description: > | |
Group address for iterating the favorite list (DPT 1.007). Value: only 1. | |
Example: '8/3/24' | |
default: null | |
mute_address: | |
name: Mute group address | |
description: > | |
Group address for muting the player (DPT 1.001). | |
Example: '8/3/25' | |
default: null | |
mute_state_address: | |
name: Mute state group address | |
description: > | |
Group address for muting state of the player (DPT 1.001). | |
Example: '8/3/26' | |
default: null | |
dimm_time: | |
name: Dimm time | |
description: Time dimming from 0 to 100% shall take. | |
selector: | |
number: | |
min: 1 | |
max: 20 | |
step: 0.1 | |
unit_of_measurement: seconds | |
mode: slider | |
default: 4 | |
dimm_steps: | |
name: Dimm steps | |
description: Steps used to dimm from 0 to 100%. | |
selector: | |
number: | |
min: 1 | |
max: 100 | |
step: 1 | |
unit_of_measurement: steps | |
mode: slider | |
default: 40 | |
source_url: https://gist.github.com/aschamberger/ee3934d3d6fe87fae99da495c0065992 | |
mode: parallel | |
max_exceeded: silent | |
variables: | |
media_player_entity_id: !input media_player | |
_dimm_time: !input dimm_time | |
_dimm_steps: !input dimm_steps | |
dimm_time: '{{ _dimm_time|float }}' | |
dimm_steps: '{{ _dimm_steps|int }}' | |
dimm_step: '{{ (1 / dimm_steps) }}' | |
dimm_delay: '{{ dimm_time * 1000 / dimm_steps }}' | |
trigger_variables: | |
_dimm_helper: !input dimm_helper | |
_switch_address: !input switch_address | |
_state_address: !input state_address | |
_dimm_address: !input dimm_address | |
_volume_state_address: !input volume_state_address | |
_favorite_address: !input favorite_address | |
_mute_address: !input mute_address | |
_mute_state_address: !input mute_state_address | |
trigger: | |
- platform: homeassistant | |
event: start | |
id: initialize | |
- platform: event | |
event_type: automation_reloaded | |
id: initialize | |
# when KNX integration was reloaded | |
- platform: event | |
event_type: service_registered | |
event_data: | |
domain: knx | |
service: event_register | |
id: initialize | |
- platform: knx.telegram | |
destination: !input switch_address | |
group_value_read: false | |
group_value_response: false | |
id: switch | |
enabled: "{{ _switch_address != None }}" | |
- platform: knx.telegram | |
destination: !input dimm_address | |
group_value_read: false | |
group_value_response: false | |
id: dimm | |
enabled: "{{ not not _dimm_helper and _dimm_address != None }}" | |
- platform: knx.telegram | |
destination: !input favorite_address | |
group_value_read: false | |
group_value_response: false | |
id: favorite | |
enabled: "{{ _favorite_address != None }}" | |
- platform: knx.telegram | |
destination: !input mute_address | |
group_value_read: false | |
group_value_response: false | |
id: mute | |
enabled: "{{ _mute_address != None }}" | |
- platform: state | |
entity_id: !input media_player | |
to: | |
id: expose_state | |
enabled: "{{ _state_address != None }}" | |
- platform: knx.telegram | |
destination: !input state_address | |
group_value_write: false | |
group_value_response: false | |
id: expose_state_read | |
enabled: "{{ _state_address != None }}" | |
- platform: state | |
entity_id: !input media_player | |
attribute: volume_level | |
id: expose_volume | |
enabled: "{{ _volume_state_address != None }}" | |
- platform: knx.telegram | |
destination: !input volume_state_address | |
group_value_write: false | |
group_value_response: false | |
id: expose_volume_read | |
enabled: "{{ _volume_state_address != None }}" | |
action: | |
- choose: | |
# TURN ON | |
- conditions: | |
condition: and | |
conditions: | |
- condition: trigger | |
id: switch | |
- '{{ trigger.payload == 1 }}' | |
sequence: | |
- service: media_player.media_play | |
entity_id: !input media_player | |
# TURN OFF | |
- conditions: | |
condition: and | |
conditions: | |
- condition: trigger | |
id: switch | |
- '{{ trigger.payload == 0 }}' | |
sequence: | |
- service: media_player.turn_off | |
entity_id: !input media_player | |
# VOLUME STOP | |
- conditions: | |
condition: and | |
conditions: | |
- condition: trigger | |
id: dimm | |
- '{{ trigger.payload == 0 or trigger.payload == 8 }}' | |
sequence: | |
- service: input_boolean.turn_on | |
data: {} | |
target: | |
entity_id: !input dimm_helper | |
# VOLUME UP | |
- conditions: | |
condition: and | |
conditions: | |
- condition: trigger | |
id: dimm | |
- '{{ 9 <= trigger.payload <= 15 }}' | |
sequence: | |
- service: input_boolean.turn_off | |
data: {} | |
target: | |
entity_id: !input dimm_helper | |
- repeat: | |
while: | |
- condition: state | |
entity_id: !input dimm_helper | |
state: "off" | |
- "{{ repeat.index <= dimm_steps }}" | |
sequence: | |
- service: media_player.volume_set | |
entity_id: !input media_player | |
data: | |
volume_level: '{% if state_attr(media_player_entity_id, "volume_level") == None %}{{ dimm_step }}{% else %}{{ ([0.01, state_attr(media_player_entity_id, "volume_level") + dimm_step, 1]|sort)[1] }}{% endif %}' | |
- delay: | |
milliseconds: '{{ dimm_delay }}' | |
- service: input_boolean.turn_off | |
data: {} | |
target: | |
entity_id: !input dimm_helper | |
# VOLUME DOWN | |
- conditions: | |
condition: and | |
conditions: | |
- condition: trigger | |
id: dimm | |
- '{{ 1 <= trigger.payload <= 7 }}' | |
sequence: | |
- service: input_boolean.turn_off | |
data: {} | |
target: | |
entity_id: !input dimm_helper | |
- repeat: | |
while: | |
- condition: state | |
entity_id: !input dimm_helper | |
state: "off" | |
- "{{ repeat.index <= dimm_steps }}" | |
sequence: | |
- service: media_player.volume_set | |
entity_id: !input media_player | |
data: | |
volume_level: '{% if state_attr(media_player_entity_id, "volume_level") == None %}{{ dimm_step }}{% else %}{{ ([0.01, state_attr(media_player_entity_id, "volume_level") - dimm_step, 1]|sort)[1] }}{% endif %}' | |
- delay: | |
milliseconds: '{{ dimm_delay }}' | |
- service: input_boolean.turn_off | |
data: {} | |
target: | |
entity_id: !input dimm_helper | |
# FAVORITE | |
- conditions: | |
condition: and | |
conditions: | |
- condition: trigger | |
id: favorite | |
- '{{ trigger.payload == 1 }}' | |
sequence: | |
# 1: get currently played item | |
- service: squeezebox.call_query | |
entity_id: !input media_player | |
data: | |
command: path | |
parameters: | |
- '?' | |
# 2a: search if current item is a favorite | |
- service: squeezebox.call_query | |
entity_id: !input media_player | |
data: | |
command: favorites | |
parameters: | |
- exists | |
- "{{ state_attr(media_player_entity_id, 'query_result')['_path'] }}" | |
# 2b: store result | |
- variables: | |
current_item: "{% if state_attr(media_player_entity_id, 'query_result')['exists'] == 1 %}{{ state_attr(media_player_entity_id, 'query_result')['index'] }}{% else %}-1{% endif %}" | |
# 3: get all favorites | |
- service: squeezebox.call_query | |
entity_id: !input media_player | |
data: | |
command: favorites | |
parameters: | |
- items | |
- '0' | |
- 'item_id:' | |
# 4: play next item from favorites | |
- service: squeezebox.call_query | |
entity_id: !input media_player | |
data: | |
command: favorites | |
parameters: | |
- playlist | |
- play | |
- > | |
{%- set ns = namespace(ids=[]) -%} | |
{%- for fav in state_attr(media_player_entity_id, 'query_result')['loop_loop'] if fav.isaudio == 1 -%} | |
{%- set ns.ids = ns.ids + [fav.id.split('.')[1]] -%} | |
{%- endfor -%} | |
{%- if current_item == -1 -%} | |
item_id:{{ ns.ids[0] }} | |
{%- else -%} | |
{%- if ns.ids.index(current_item|string)+1 == ns.ids|length -%} | |
item_id:{{ ns.ids[0] }} | |
{%- else -%} | |
item_id:{{ ns.ids[ns.ids.index(current_item|string)+1] }} | |
{%- endif -%} | |
{%- endif -%} | |
# MUTE | |
- conditions: | |
condition: and | |
conditions: | |
- condition: trigger | |
id: mute | |
- '{{ trigger.payload == 1 }}' | |
sequence: | |
- service: media_player.volume_mute | |
entity_id: !input media_player | |
data: | |
is_volume_muted: true | |
# UNMUTE | |
- conditions: | |
condition: and | |
conditions: | |
- condition: trigger | |
id: mute | |
- '{{ trigger.payload == 0 }}' | |
sequence: | |
- service: media_player.volume_mute | |
entity_id: !input media_player | |
data: | |
is_volume_muted: false | |
# EXPOSE STATE | |
- conditions: | |
condition: or | |
conditions: | |
- condition: trigger | |
id: expose_state | |
- condition: trigger | |
id: expose_state_read | |
sequence: | |
- service: knx.send | |
data: | |
address: !input state_address | |
payload: "{% if states(media_player_entity_id) == 'off' %}0{% else %}1{% endif %}" | |
response: "{{ trigger.id == 'expose_state_read' }}" | |
# EXPOSE VOLUME | |
- conditions: | |
condition: or | |
conditions: | |
- condition: trigger | |
id: expose_volume | |
- condition: trigger | |
id: expose_volume_read | |
sequence: | |
- service: knx.send | |
data: | |
address: !input volume_state_address | |
payload: "{% if state_attr(media_player_entity_id, 'volume_level') == None %}0{% else %}{{ state_attr(media_player_entity_id, 'volume_level')*100 }}{% endif %}" | |
response: "{{ trigger.id == 'expose_volume_read' }}" | |
type: percent | |
# INITIALIZE | |
- conditions: | |
condition: trigger | |
id: initialize | |
sequence: | |
- sequence: | |
- condition: template | |
value_template: "{{ True }}" | |
enabled: "{{ _mute_state_address != None }}" | |
- service: knx.exposure_register | |
data: | |
address: !input mute_state_address | |
entity_id: !input media_player | |
attribute: is_volume_muted | |
type: binary | |
default: 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment