Last active
April 27, 2025 19:23
-
-
Save f0ff886f/58642a648e2e50a32c7d028f40e9cd6e to your computer and use it in GitHub Desktop.
This file contains hidden or 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: | |
# Media control via Philips Hue Tap Dial by gTunes | |
# | |
# Works only with Home Assistant and Zigbee2MQTT | |
# | |
# Version History: | |
# - v 0.1 Dec 2023 : Initial version | |
# | |
# Based on earlier work by: | |
# - https://community.home-assistant.io/t/z2m-ikea-symfonisk-gen2-e2123-media-control-v1-53/559523 Shawsky | |
# - https://gist.github.com/erkr/a437ebcb98a2b5ba2deebabd02f5ffae Eric Kreuwels | |
# - https://gist.github.com/alexwmaustin/2c25cfa1a0ade1ab9fc1ef0940289672 Alex Austin | |
name: Z2M - Philips Hue Tap Dial Media Control | |
description: | |
'Control the selected media player (and any joined to it) with a Philips Hue Tap Dial controller via Zigbee2MQTT (Z2M) | |
Supports volume control by rotating the dial | |
A single press of Button 1 is Toggle Play / Pause | |
Single presses of Buttons 3 and 4 are Previous Track and Next Track | |
Single press of button 2 is configurable as are long presses of all buttons' | |
domain: automation | |
input: | |
remote: | |
name: Remote | |
description: The Philips Hue Tap Dial to use | |
selector: | |
device: | |
filter: | |
integration: mqtt | |
manufacturer: Philips | |
model: Hue Tap dial switch | |
multiple: false | |
base_topic: | |
name: Zigbee2MQTT Base mqtt topic | |
description: The base topic configured in Zigbee2MQTT. If you haven't changed this, leave the default here ("zigbee2mqtt") | |
default: zigbee2mqtt | |
media_player: | |
name: Media Player | |
description: The media player to control with this automation | |
selector: | |
entity: | |
domain: media_player | |
multiple: false | |
volume_steps: | |
name: Volume number of steps | |
description: Controls the volume scale. Set this to the number of steps supported by your playback device | |
default: 100 | |
selector: | |
number: | |
min: 5 | |
max: 100 | |
step: 1 | |
unit_of_measurement: "Num" | |
mode: slider | |
step_rotation_increments: | |
name: "\"Step\" rotation volume increments" | |
description: Number of volume increments for a "step" rotation event | |
default: 1.0 | |
selector: | |
number: | |
min: 0.1 | |
max: 5.0 | |
step: 0.1 | |
unit_of_measurement: "Num" | |
mode: slider | |
slow_rotation_increments: | |
name: "\"Slow\" rotation volume increments" | |
description: Number of volume increments for a "slow" rotation event | |
default: 2 | |
selector: | |
number: | |
min: 0.1 | |
max: 5.0 | |
step: 0.1 | |
unit_of_measurement: "Num" | |
mode: slider | |
fast_rotation_increments: | |
name: "\"Fast\" rotation volume increments" | |
description: Number of volume increments for a "fast" rotation event | |
default: 3 | |
selector: | |
number: | |
min: 0.1 | |
max: 5.0 | |
step: 0.1 | |
unit_of_measurement: "Num" | |
mode: slider | |
button_1_hold: | |
name: Button 1 (Long) | |
description: Action to run on a long press of Button 1 | |
default: [] | |
selector: | |
action: {} | |
button_2_short: | |
name: Button 2 (Short) | |
description: Action to run on a short press of Button 2 | |
default: [] | |
selector: | |
action: {} | |
button_2_hold: | |
name: Button 2 (Long) | |
description: Action to run on a long press of Button 2 | |
default: [] | |
selector: | |
action: {} | |
button_3_hold: | |
name: Button 3 (Long) | |
description: Action to run on a long press of Button 3 | |
default: [] | |
selector: | |
action: {} | |
button_4_hold: | |
name: Button 4 (Long) | |
description: Action to run on a long press of Button 4 | |
default: [] | |
selector: | |
action: {} | |
mode: restart | |
max_exceeded: silent | |
trigger_variables: | |
base_topic: !input base_topic | |
controller: !input remote | |
trigger: | |
- platform: mqtt | |
topic: "{{ base_topic }}/+/action" | |
action: | |
- variables: | |
controllertopic: "{{ base_topic }}/{{ device_attr(controller, 'name') }}/action" | |
player: !input 'media_player' | |
steps: !input volume_steps | |
stepsize: '{{ 1.0 / steps }}' | |
stepmultiplier: { | |
'dial_rotate_right_step' : !input step_rotation_increments, | |
'dial_rotate_left_step' : !input step_rotation_increments, | |
'dial_rotate_right_slow' : !input slow_rotation_increments, | |
'dial_rotate_left_slow' : !input slow_rotation_increments, | |
'dial_rotate_right_fast' : !input fast_rotation_increments, | |
'dial_rotate_left_fast' : !input fast_rotation_increments | |
} | |
- choose: | |
- conditions: | |
- "{{ trigger.payload != ''}}" | |
- "{{ trigger.topic == controllertopic }}" | |
sequence: | |
- choose: | |
## Commands | |
# Play / Pause | |
- conditions: "{{ trigger.payload == 'button_1_press_release' }}" | |
sequence: | |
- service: media_player.media_play_pause | |
entity_id: !input 'media_player' | |
# Next Track | |
- conditions: "{{ trigger.payload == 'button_4_press_release' }}" | |
sequence: | |
- service: media_player.media_next_track | |
entity_id: !input 'media_player' | |
# Previous Track | |
- conditions: "{{ trigger.payload == 'button_3_press_release' }}" | |
sequence: | |
- service: media_player.media_previous_track | |
entity_id: !input 'media_player' | |
# Rotate Right (Volume Up) | |
- conditions: "{{ trigger.payload in ['dial_rotate_right_step', 'dial_rotate_right_slow', 'dial_rotate_right_fast'] }}" | |
sequence: | |
- service: media_player.volume_set | |
target: | |
entity_id: "{{ player }}" | |
data: | |
volume_level: >- | |
{% set volume = state_attr(player, "volume_level") + (stepsize * stepmultiplier[trigger.payload]) %} | |
{{ 1.0 if volume > 1.0 else volume }} | |
# Rotate Left (Volume Down) | |
- conditions: "{{ trigger.payload in ['dial_rotate_left_step', 'dial_rotate_left_slow', 'dial_rotate_left_fast'] }}" | |
sequence: | |
- service: media_player.volume_set | |
target: | |
entity_id: "{{ player }}" | |
data: | |
volume_level: >- | |
{% set volume = state_attr(player, "volume_level") - (stepsize * stepmultiplier[trigger.payload]) %} | |
{{ 0.0 if volume < 0.0 else volume }} | |
## Actions | |
# Button 1 Long Press | |
- conditions: "{{ trigger.payload == 'button_1_hold' }}" | |
sequence: !input button_1_hold | |
# Button 2 Short Press | |
- conditions: "{{ trigger.payload == 'button_2_press_release' }}" | |
sequence: !input button_2_short | |
# Button 2 Long Press | |
- conditions: "{{ trigger.payload == 'button_2_hold' }}" | |
sequence: !input button_2_hold | |
# Button 3 Long Press | |
- conditions: "{{ trigger.payload == 'button_3_hold' }}" | |
sequence: !input button_3_hold | |
# Button 4 Long Press | |
- conditions: "{{ trigger.payload == 'button_4_hold' }}" | |
sequence: !input button_4_hold |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment