Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save cpw/f167ce8a5d2464f7ee9a51f3b17f337c to your computer and use it in GitHub Desktop.
Save cpw/f167ce8a5d2464f7ee9a51f3b17f337c to your computer and use it in GitHub Desktop.
• UP/DOWN (short): ON / OFF • UP/DOWN (hold): fast and smooth brightness stepping that stops immediately on release (implemented with `mode: restart` for zero run-on) • LEFT/RIGHT (short): cycle through 6 preset RGB colors (wrap-around; uses an input_number helper to track index) • LEFT/RIGHT (long press): optional custom actions (empty by defa…
blueprint:
name: ZHA – IKEA STYRBAR all controls & 6-color palette (modern syntax)
description: >
Smooth, responsive control for the IKEA STYRBAR (square) remote on ZHA.
• UP/DOWN (short): ON / OFF
• UP/DOWN (hold): fast and smooth brightness stepping that stops immediately on release
(implemented with `mode: restart` for zero run-on)
• LEFT/RIGHT (short): cycle through 3 preset colour temperatures (wrap-around; uses an input_number helper to track index)
• LEFT/RIGHT (long press): optional custom actions (empty by default)
Setup notes:
1) If you want LEFT/RIGHT color cycling, create an *input_number* helper with min=1, max=3, step=1.
Example entity id: input_number.styrbar_color_index (you can choose another; select it below).
2) Choose your 3 colour temperatures.
3) Adjust hold speed with “Tick interval (ms)” and “Step size (%)”.
domain: automation
input:
remote:
name: Remote (ZHA device)
selector:
device:
integration: zha
manufacturer: IKEA of Sweden
model: Remote Control N2
multiple: false
light:
name: Light(s)
selector:
target:
entity:
domain: light
# Stores the current palette index (1..6) for LEFT/RIGHT cycling
color_index_helper:
name: Color index helper (1–3)
description: Create/select an input_number with min=1, max=3, step=1 to remember the active palette color.
default: input_number.styrbar_color_index
selector:
entity:
domain: input_number
# 6-color palette (RGB)
palette_temp1: { name: Temp 1 K, default: 2700, selector: { color_temp: { unit: kelvin } } }
palette_temp2: { name: Temp 2 K, default: 3000, selector: { color_temp: { unit: kelvin } } }
palette_temp3: { name: Temp 3 K, default: 4000, selector: { color_temp: { unit: kelvin } } }
# Hold behavior (tuning)
tick_ms:
name: Tick interval (ms)
description: Time between brightness steps while holding. Smaller = faster/smoother.
default: 10
selector:
number:
min: 5
max: 200
step: 5
unit_of_measurement: ms
mode: slider
step_pct:
name: Step size (% per tick)
description: Amount of brightness changed per tick while holding.
default: 5
selector:
number:
min: 1
max: 20
step: 1
unit_of_measurement: '%'
mode: slider
# Optional custom actions on long-press LEFT/RIGHT
button_left_long:
name: Left button – long press (custom action)
default: []
selector: { action: {} }
button_right_long:
name: Right button – long press (custom action)
default: []
selector: { action: {} }
# Restart mode ensures release events cancel the running hold loop immediately (no run-on)
mode: restart
max_exceeded: silent
trigger:
- platform: event
event_type: zha_event
event_data:
device_id: !input remote
action:
# -------- Modern-syntax variables (scoped to this run) --------
- variables:
color_index_entity: !input color_index_helper
tick_ms_input: !input tick_ms
step_pct_input: !input step_pct
tick_s: "{{ (tick_ms_input | float(10)) / 1000 }}"
step_up: "{{ step_pct_input | int(5) }}"
step_down: "{{ (step_pct_input | int(5)) * -1 }}"
cap_ticks: 1200 # ~12s watchdog at 10ms ticks (failsafe)
cmd: "{{ trigger.event.data.command }}"
cluster: "{{ trigger.event.data.cluster_id }}"
args: "{{ trigger.event.data.args | default([]) }}"
- choose:
# --- UP short → ON ---
- conditions: "{{ cluster == 6 and cmd == 'on' }}"
sequence:
- service: light.turn_on
target: !input light
data: { transition: 0.1 }
# --- DOWN short → OFF ---
- conditions: "{{ cluster == 6 and cmd == 'off' }}"
sequence:
- service: light.turn_off
target: !input light
# --- HOLD UP (brightness +) — step on timeout, stop on release/opposite ---
- conditions: "{{ cluster == 8 and cmd == 'move_with_on_off' }}"
sequence:
- variables: { _i: 0 }
- repeat:
sequence:
# Wait first; step only if still holding
- wait_for_trigger:
# Release / stop
- platform: event
event_type: zha_event
event_data: { device_id: !input remote, cluster_id: 8, command: "stop" }
- platform: event
event_type: zha_event
event_data: { device_id: !input remote, cluster_id: 8, command: "stop_with_on_off" }
# Opposite hold also cancels
- platform: event
event_type: zha_event
event_data: { device_id: !input remote, cluster_id: 8, command: "move" }
timeout: "{{ tick_s }}"
continue_on_timeout: true
- choose:
- conditions: "{{ not wait.completed }}"
sequence:
- service: light.turn_on
target: !input light
data: { brightness_step_pct: "{{ step_up }}", transition: 0 }
- variables: { _i: "{{ _i + 1 }}" }
until:
- condition: template
value_template: "{{ wait.completed or (_i | int) >= (cap_ticks | int) }}"
# --- HOLD DOWN (brightness −) — step on timeout, stop on release/opposite ---
- conditions: "{{ cluster == 8 and cmd == 'move' }}"
sequence:
- variables: { _i: 0 }
- repeat:
sequence:
- wait_for_trigger:
# Release / stop
- platform: event
event_type: zha_event
event_data: { device_id: !input remote, cluster_id: 8, command: "stop" }
- platform: event
event_type: zha_event
event_data: { device_id: !input remote, cluster_id: 8, command: "stop_with_on_off" }
# Opposite hold also cancels
- platform: event
event_type: zha_event
event_data: { device_id: !input remote, cluster_id: 8, command: "move_with_on_off" }
timeout: "{{ tick_s }}"
continue_on_timeout: true
- choose:
- conditions: "{{ not wait.completed }}"
sequence:
- service: light.turn_on
target: !input light
data: { brightness_step_pct: "{{ step_down }}", transition: 0 }
- variables: { _i: "{{ _i + 1 }}" }
until:
- condition: template
value_template: "{{ wait.completed or (_i | int) >= (cap_ticks | int) }}"
# --- LEFT/RIGHT short → palette cycle (wrap) ---
- conditions: "{{ cluster == 5 and cmd == 'press' and args in [[256,13,0],[257,13,0]] }}"
sequence:
- variables:
curr_idx: "{{ states(color_index_entity) | int(1) }}"
next_idx: >
{% if args == [256,13,0] %}
{{ 1 if curr_idx >= 3 else curr_idx + 1 }}
{% else %}
{{ 3 if curr_idx <= 1 else curr_idx - 1 }}
{% endif %}
- service: input_number.set_value
target: { entity_id: !input color_index_helper }
data: { value: "{{ next_idx }}" }
- choose:
- conditions: "{{ next_idx == 1 }}"
sequence:
- service: light.turn_on
target: !input light
data: { color_temp_kelvin: !input palette_temp1, transition: 0 }
- conditions: "{{ next_idx == 2 }}"
sequence:
- service: light.turn_on
target: !input light
data: { color_temp_kelvin: !input palette_temp2, transition: 0 }
- conditions: "{{ next_idx == 3 }}"
sequence:
- service: light.turn_on
target: !input light
data: { color_temp_kelvin: !input palette_temp3, transition: 0 }
# --- LEFT/RIGHT long press (optional custom) ---
- conditions: "{{ cluster == 5 and cmd == 'hold' }}"
sequence:
- choose:
- conditions: "{{ args == [3329, 0] }}"
sequence: !input button_left_long
- conditions: "{{ args == [3328, 0] }}"
sequence: !input button_right_long
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment