updated apps
This commit is contained in:
@@ -0,0 +1,500 @@
|
||||
blueprint:
|
||||
name: IKEA E2490 BILRESA Scroll Wheel (Zigbee2MQTT + ZHA)
|
||||
description: 'Unified controller blueprint for IKEA E2490 BILRESA scroll wheel working
|
||||
with Zigbee2MQTT and ZHA.
|
||||
|
||||
- Buttons: on, off, on_double, off_double
|
||||
|
||||
- Scroll: brightness_move_to_level with action_level from Zigbee2MQTT main topic,
|
||||
or ZHA move_to_level args
|
||||
|
||||
Supports light brightness, media_player volume, light color_temp, light hue.
|
||||
|
||||
Version: 2026-01-18
|
||||
|
||||
'
|
||||
domain: automation
|
||||
input:
|
||||
controller_device:
|
||||
name: Controller Device (Zigbee2MQTT or ZHA)
|
||||
description: Select the E2490 device integrated via Zigbee2MQTT or ZHA.
|
||||
selector:
|
||||
device:
|
||||
filter:
|
||||
- integration: mqtt
|
||||
- integration: zha
|
||||
multiple: false
|
||||
scroll_target:
|
||||
name: Scroll wheel target entity (light)
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
- domain:
|
||||
- light
|
||||
multiple: false
|
||||
reorder: false
|
||||
scroll_mode:
|
||||
name: Default scroll mode
|
||||
description: Default mode when automation starts or after auto-reset timeout
|
||||
default: brightness
|
||||
selector:
|
||||
select:
|
||||
mode: dropdown
|
||||
options:
|
||||
- label: Brightness (light)
|
||||
value: brightness
|
||||
- label: Volume (media_player)
|
||||
value: volume
|
||||
- label: Color temperature (light)
|
||||
value: color_temp
|
||||
- label: Hue (light)
|
||||
value: hue
|
||||
sort: false
|
||||
custom_value: false
|
||||
multiple: false
|
||||
volume_target:
|
||||
name: Volume target (media_player)
|
||||
default:
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
- domain:
|
||||
- media_player
|
||||
multiple: false
|
||||
reorder: false
|
||||
color_temp_target:
|
||||
name: Color temperature target (light)
|
||||
default:
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
- domain:
|
||||
- light
|
||||
multiple: false
|
||||
reorder: false
|
||||
hue_target:
|
||||
name: Hue target (light)
|
||||
default:
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
- domain:
|
||||
- light
|
||||
multiple: false
|
||||
reorder: false
|
||||
scroll_mode_helper:
|
||||
name: (Optional) Scroll mode helper (input_select)
|
||||
description: 'Provide an input_select to allow cycling scroll modes at runtime
|
||||
with double ON. Must have options: brightness, volume, color_temp, hue (in
|
||||
that order)'
|
||||
default:
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
- domain:
|
||||
- input_select
|
||||
multiple: false
|
||||
reorder: false
|
||||
last_activity_helper:
|
||||
name: (Optional) Last activity helper (input_datetime)
|
||||
description: Provide an input_datetime to enable auto-reset after inactivity.
|
||||
Works with scroll mode helper and reset timeout.
|
||||
default:
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
- domain:
|
||||
- input_datetime
|
||||
multiple: false
|
||||
reorder: false
|
||||
reset_timeout:
|
||||
name: (Optional) Auto-reset timeout (seconds)
|
||||
description: Time in seconds of inactivity before resetting to default scroll
|
||||
mode. Set to 0 to disable auto-reset. Requires both scroll mode helper and
|
||||
last activity helper.
|
||||
default: 60
|
||||
selector:
|
||||
number:
|
||||
min: 0.0
|
||||
max: 3600.0
|
||||
step: 1.0
|
||||
unit_of_measurement: seconds
|
||||
mode: box
|
||||
volume_max:
|
||||
name: (Optional) Max volume
|
||||
description: Upper limit for volume mode (0.0 - 1.0). Values from the wheel
|
||||
will be clamped to this maximum.
|
||||
default: 1.0
|
||||
selector:
|
||||
number:
|
||||
min: 0.0
|
||||
max: 1.0
|
||||
step: 0.01
|
||||
mode: slider
|
||||
button_on_short:
|
||||
name: Button ON - short press (optional)
|
||||
default: []
|
||||
selector:
|
||||
action: {}
|
||||
button_off_short:
|
||||
name: Button OFF - short press (optional)
|
||||
default: []
|
||||
selector:
|
||||
action: {}
|
||||
button_on_double:
|
||||
name: Button ON - double press (optional)
|
||||
default: []
|
||||
selector:
|
||||
action: {}
|
||||
button_off_double:
|
||||
name: Button OFF - double press (optional)
|
||||
default: []
|
||||
selector:
|
||||
action: {}
|
||||
source_url: https://gist.github.com/mcinnes01/399132520034291b89a82659653b2893
|
||||
alias: IKEA E2490 BILRESA Scroll Wheel (Zigbee2MQTT + ZHA)
|
||||
variables:
|
||||
controller_device: !input controller_device
|
||||
friendly_name: '{{ device_attr(controller_device, ''name'') | default('''') }}'
|
||||
z2m_topic: zigbee2mqtt/{{ friendly_name }}
|
||||
scroll_mode: !input scroll_mode
|
||||
scroll_mode_helper: !input scroll_mode_helper
|
||||
last_activity_helper: !input last_activity_helper
|
||||
reset_timeout: !input reset_timeout
|
||||
effective_mode: '{{ states(scroll_mode_helper) if scroll_mode_helper is not none
|
||||
and states(scroll_mode_helper) != '''' else scroll_mode }}'
|
||||
brightness_target: !input scroll_target
|
||||
volume_target: !input volume_target
|
||||
color_temp_target: !input color_temp_target
|
||||
hue_target: !input hue_target
|
||||
volume_max: !input volume_max
|
||||
available_modes: '{% set modes = [] %} {% if brightness_target is not none %}{%
|
||||
set modes = modes + [''brightness''] %}{% endif %} {% if volume_target is not
|
||||
none %}{% set modes = modes + [''volume''] %}{% endif %} {% if color_temp_target
|
||||
is not none %}{% set modes = modes + [''color_temp''] %}{% endif %} {% if hue_target
|
||||
is not none %}{% set modes = modes + [''hue''] %}{% endif %} {{ modes }}
|
||||
|
||||
'
|
||||
button_on_short_seq: !input button_on_short
|
||||
button_off_short_seq: !input button_off_short
|
||||
button_on_double_seq: !input button_on_double
|
||||
button_off_double_seq: !input button_off_double
|
||||
trigger:
|
||||
- platform: device
|
||||
id: z2m-on
|
||||
domain: mqtt
|
||||
device_id: !input controller_device
|
||||
type: action
|
||||
subtype: 'on'
|
||||
- platform: device
|
||||
id: z2m-off
|
||||
domain: mqtt
|
||||
device_id: !input controller_device
|
||||
type: action
|
||||
subtype: 'off'
|
||||
- platform: device
|
||||
id: z2m-on-double
|
||||
domain: mqtt
|
||||
device_id: !input controller_device
|
||||
type: action
|
||||
subtype: on_double
|
||||
- platform: device
|
||||
id: z2m-off-double
|
||||
domain: mqtt
|
||||
device_id: !input controller_device
|
||||
type: action
|
||||
subtype: off_double
|
||||
- platform: mqtt
|
||||
id: z2m-payload
|
||||
topic: zigbee2mqtt/#
|
||||
- platform: event
|
||||
id: zha-on
|
||||
event_type: zha_event
|
||||
event_data:
|
||||
device_id: !input controller_device
|
||||
command: 'on'
|
||||
- platform: event
|
||||
id: zha-off
|
||||
event_type: zha_event
|
||||
event_data:
|
||||
device_id: !input controller_device
|
||||
command: 'off'
|
||||
- platform: event
|
||||
id: zha-level
|
||||
event_type: zha_event
|
||||
event_data:
|
||||
device_id: !input controller_device
|
||||
command: move_to_level
|
||||
condition: []
|
||||
action:
|
||||
- if:
|
||||
- condition: template
|
||||
value_template: "{{ scroll_mode_helper is not none \n and last_activity_helper
|
||||
is not none \n and reset_timeout > 0\n and states(last_activity_helper)
|
||||
not in ['unknown', 'unavailable', ''] \n and (now() - (states(last_activity_helper)
|
||||
| as_datetime)).total_seconds() > reset_timeout }}\n"
|
||||
then:
|
||||
- service: input_select.select_option
|
||||
target:
|
||||
entity_id: '{{ scroll_mode_helper }}'
|
||||
data:
|
||||
option: '{{ scroll_mode }}'
|
||||
- choose:
|
||||
- conditions:
|
||||
- condition: template
|
||||
value_template: "{{ trigger.id == 'z2m-payload' \n and trigger.topic == z2m_topic
|
||||
\n and trigger.payload_json is defined \n and trigger.payload_json.action
|
||||
== 'brightness_move_to_level' }}\n"
|
||||
sequence:
|
||||
- variables:
|
||||
lvl: '{{ trigger.payload_json.action_level | default(none) }}'
|
||||
trans: '{{ trigger.payload_json.action_transition_time | default(0) }}'
|
||||
- choose:
|
||||
- conditions:
|
||||
- condition: template
|
||||
value_template: '{{ effective_mode == ''brightness'' and brightness_target
|
||||
is not none }}'
|
||||
sequence:
|
||||
- service: light.turn_on
|
||||
target:
|
||||
entity_id: '{{ brightness_target }}'
|
||||
data:
|
||||
brightness: '{% if lvl is none %}255{% else %}{{ ((lvl|float/241.0)*255.0)|round(0)|int
|
||||
}}{% endif %}
|
||||
|
||||
'
|
||||
transition: '{{ trans }}'
|
||||
- if:
|
||||
- condition: template
|
||||
value_template: '{{ last_activity_helper is not none }}'
|
||||
then:
|
||||
- service: input_datetime.set_datetime
|
||||
target:
|
||||
entity_id: '{{ last_activity_helper }}'
|
||||
data:
|
||||
timestamp: '{{ now().timestamp() }}'
|
||||
- conditions:
|
||||
- condition: template
|
||||
value_template: '{{ effective_mode == ''volume'' and volume_target is not
|
||||
none }}'
|
||||
sequence:
|
||||
- service: media_player.volume_set
|
||||
target:
|
||||
entity_id: '{{ volume_target }}'
|
||||
data:
|
||||
volume_level: "{% if lvl is none %}\n {{ volume_max }}\n{% else %}\n
|
||||
\ {{ ((lvl|float/241.0) * volume_max)|round(3) }}\n{% endif %}\n"
|
||||
- if:
|
||||
- condition: template
|
||||
value_template: '{{ last_activity_helper is not none }}'
|
||||
then:
|
||||
- service: input_datetime.set_datetime
|
||||
target:
|
||||
entity_id: '{{ last_activity_helper }}'
|
||||
data:
|
||||
timestamp: '{{ now().timestamp() }}'
|
||||
- conditions:
|
||||
- condition: template
|
||||
value_template: '{{ effective_mode == ''color_temp'' and color_temp_target
|
||||
is not none }}'
|
||||
sequence:
|
||||
- variables:
|
||||
min_mireds: '{{ state_attr(color_temp_target, ''min_mireds'') | default(153)
|
||||
}}'
|
||||
max_mireds: '{{ state_attr(color_temp_target, ''max_mireds'') | default(500)
|
||||
}}'
|
||||
- service: light.turn_on
|
||||
target:
|
||||
entity_id: '{{ color_temp_target }}'
|
||||
data:
|
||||
color_temp: "{% set minm = min_mireds|int %} {% set maxm = max_mireds|int
|
||||
%} {% if lvl is none %}\n {{ maxm }}\n{% else %}\n {% set ratio =
|
||||
((lvl|float - 1.0)/240.0) %}\n {{ (minm + ratio*(maxm-minm))|round(0)|int
|
||||
}}\n{% endif %}\n"
|
||||
- if:
|
||||
- condition: template
|
||||
value_template: '{{ last_activity_helper is not none }}'
|
||||
then:
|
||||
- service: input_datetime.set_datetime
|
||||
target:
|
||||
entity_id: '{{ last_activity_helper }}'
|
||||
data:
|
||||
timestamp: '{{ now().timestamp() }}'
|
||||
- conditions:
|
||||
- condition: template
|
||||
value_template: '{{ effective_mode == ''hue'' and hue_target is not none
|
||||
}}'
|
||||
sequence:
|
||||
- variables:
|
||||
current_hs: '{{ state_attr(hue_target, ''hs_color'') | default([0, 100])
|
||||
}}'
|
||||
current_sat: '{{ current_hs[1] if current_hs is sequence and current_hs|length
|
||||
> 1 else 100 }}'
|
||||
hue_val: '{% if lvl is none %}360{% else %}{{ ((lvl|float/241.0)*360.0)|round(0)|int
|
||||
}}{% endif %}
|
||||
|
||||
'
|
||||
- service: light.turn_on
|
||||
target:
|
||||
entity_id: '{{ hue_target }}'
|
||||
data:
|
||||
hs_color: '[ {{ hue_val }}, {{ current_sat }} ]'
|
||||
- if:
|
||||
- condition: template
|
||||
value_template: '{{ last_activity_helper is not none }}'
|
||||
then:
|
||||
- service: input_datetime.set_datetime
|
||||
target:
|
||||
entity_id: '{{ last_activity_helper }}'
|
||||
data:
|
||||
timestamp: '{{ now().timestamp() }}'
|
||||
- conditions:
|
||||
- condition: template
|
||||
value_template: '{{ trigger.id == ''zha-level'' }}'
|
||||
sequence:
|
||||
- variables:
|
||||
lvl: '{% set a = trigger.event.data.args | default([]) %} {% if a is sequence
|
||||
and a|length > 0 %}{{ a[0] }}{% else %}{{ none }}{% endif %}
|
||||
|
||||
'
|
||||
trans: '{% set a = trigger.event.data.args | default([]) %} {% if a is sequence
|
||||
and a|length > 1 %}{{ a[1] }}{% else %}0{% endif %}
|
||||
|
||||
'
|
||||
- choose:
|
||||
- conditions:
|
||||
- condition: template
|
||||
value_template: '{{ effective_mode == ''brightness'' and brightness_target
|
||||
is not none }}'
|
||||
sequence:
|
||||
- service: light.turn_on
|
||||
target:
|
||||
entity_id: '{{ brightness_target }}'
|
||||
data:
|
||||
brightness: '{% if lvl is none %}255{% else %}{{ (lvl|int)|min(255)|max(1)
|
||||
}}{% endif %}
|
||||
|
||||
'
|
||||
transition: '{{ trans }}'
|
||||
- if:
|
||||
- condition: template
|
||||
value_template: '{{ last_activity_helper is not none }}'
|
||||
then:
|
||||
- service: input_datetime.set_datetime
|
||||
target:
|
||||
entity_id: '{{ last_activity_helper }}'
|
||||
data:
|
||||
timestamp: '{{ now().timestamp() }}'
|
||||
- conditions:
|
||||
- condition: template
|
||||
value_template: '{{ trigger.id in [''z2m-on'',''zha-on''] }}'
|
||||
sequence:
|
||||
- choose:
|
||||
- conditions:
|
||||
- condition: template
|
||||
value_template: '{{ button_on_short_seq | length > 0 }}'
|
||||
sequence: !input button_on_short
|
||||
default:
|
||||
- choose:
|
||||
- conditions:
|
||||
- condition: template
|
||||
value_template: '{{ effective_mode == ''volume'' and volume_target is
|
||||
not none }}'
|
||||
sequence:
|
||||
- service: media_player.turn_on
|
||||
target:
|
||||
entity_id: '{{ volume_target }}'
|
||||
- conditions: []
|
||||
sequence:
|
||||
- service: light.turn_on
|
||||
target:
|
||||
entity_id: !input scroll_target
|
||||
- conditions:
|
||||
- condition: template
|
||||
value_template: '{{ trigger.id in [''z2m-off'',''zha-off''] }}'
|
||||
sequence:
|
||||
- choose:
|
||||
- conditions:
|
||||
- condition: template
|
||||
value_template: '{{ button_off_short_seq | length > 0 }}'
|
||||
sequence: !input button_off_short
|
||||
default:
|
||||
- choose:
|
||||
- conditions:
|
||||
- condition: template
|
||||
value_template: '{{ effective_mode == ''volume'' and volume_target is
|
||||
not none }}'
|
||||
sequence:
|
||||
- service: media_player.turn_off
|
||||
target:
|
||||
entity_id: '{{ volume_target }}'
|
||||
- conditions: []
|
||||
sequence:
|
||||
- service: light.turn_off
|
||||
target:
|
||||
entity_id: !input scroll_target
|
||||
- conditions:
|
||||
- condition: template
|
||||
value_template: '{{ trigger.id == ''z2m-on-double'' }}'
|
||||
sequence:
|
||||
- choose:
|
||||
- conditions:
|
||||
- condition: template
|
||||
value_template: '{{ scroll_mode_helper is not none }}'
|
||||
sequence:
|
||||
- variables:
|
||||
current_mode: '{{ states(scroll_mode_helper) }}'
|
||||
modes_list: '{{ available_modes }}'
|
||||
current_index: '{{ modes_list.index(current_mode) if current_mode in modes_list
|
||||
else 0 }}'
|
||||
next_index: '{{ (current_index + 1) % (modes_list | length) }}'
|
||||
next_mode: '{{ modes_list[next_index] if modes_list | length > 0 else
|
||||
''brightness'' }}'
|
||||
- service: input_select.select_option
|
||||
target:
|
||||
entity_id: '{{ scroll_mode_helper }}'
|
||||
data:
|
||||
option: '{{ next_mode }}'
|
||||
- if:
|
||||
- condition: template
|
||||
value_template: '{{ last_activity_helper is not none }}'
|
||||
then:
|
||||
- service: input_datetime.set_datetime
|
||||
target:
|
||||
entity_id: '{{ last_activity_helper }}'
|
||||
data:
|
||||
timestamp: '{{ now().timestamp() }}'
|
||||
- choose:
|
||||
- conditions:
|
||||
- condition: template
|
||||
value_template: '{{ button_on_double_seq | length > 0 }}'
|
||||
sequence: !input button_on_double
|
||||
- conditions: []
|
||||
sequence:
|
||||
- choose:
|
||||
- conditions:
|
||||
- condition: template
|
||||
value_template: '{{ button_on_double_seq | length > 0 }}'
|
||||
sequence: !input button_on_double
|
||||
- conditions: []
|
||||
sequence:
|
||||
- service: light.turn_on
|
||||
target:
|
||||
entity_id: !input scroll_target
|
||||
data:
|
||||
brightness: 255
|
||||
- conditions:
|
||||
- condition: template
|
||||
value_template: '{{ trigger.id == ''z2m-off-double'' }}'
|
||||
sequence:
|
||||
- choose:
|
||||
- conditions:
|
||||
- condition: template
|
||||
value_template: '{{ button_off_double_seq | length > 0 }}'
|
||||
sequence: !input button_off_double
|
||||
default:
|
||||
- service: light.turn_off
|
||||
target:
|
||||
entity_id: !input scroll_target
|
||||
mode: restart
|
||||
max_exceeded: silent
|
||||
Reference in New Issue
Block a user