Hey folks!
I’ve been looking for good ways to smoothly dim Zigbee lights with remotes, and I’ve found several viable solutions on the forum. But, all of the ones I’ve tried, have either ended up being a bit bothersome to setup, or resulted in jerky dimming.
So, I’ve worked on these two scripts and a trigger template to make it all super simple.
What it does
Two scripts issue real Zigbee Level Control “move”/“stop” commands via ZHA, so lights dim smoothly in hardware instead of stepping through light.turn_on brightness increments:
Zigbee: Start Light Level Change— starts a smooth dim (up or down) on a single light entity or a Zigbee groupZigbee: Stop Light Level Change— stops it (call on button release)
They’re posted together here since they’re a matched pair — starting a dim without a way to stop it isn’t much use.
There’s also an optional Last Dim Directions sensor (plain YAML, not a blueprint — see below for why) that remembers which way each light was last dimmed, so a single-button remote can toggle between up/down on alternating presses.
The big thing: it doesn’t care what triggers it
These are plain scripts with entity_id/group_id/direction/rate fields — so anything that can call a script action can drive them. That means:
- Any ZHA remote, via a plain Device trigger in the automation editor — no
zha_eventYAML needed (one-button, two-button, multi-button — direction is just a parameter) - Z-Wave scene controllers, same way — a Device trigger on the scene action
- The Switch Manager HACS integration (my favourite!), mapping hold/release straight to these scripts with no automation at all
- Basically any automation trigger you already have
Prerequisites
Requires the ZHA integration — this won’t work with zigbee2mqtt or deCONZ, since it uses zha.issue_zigbee_cluster_command / zha.issue_zigbee_group_command directly.
Blueprint: Zigbee: Start Light Level Change
blueprint:
name: "Zigbee: Start Light Level Change"
description: >
Start a smooth Zigbee (ZHA) light level change (dimming) for a single
light entity or a Zigbee group. Designed to be called from *any*
automation trigger — a zha_event from a Zigbee remote, a Z-Wave
scene-controller event via a Switch Manager mapping, a Z-Wave
zwave_js_value_notification, or anything else that can call a script
action. Works equally well with one-button, two-button, or multi-button
remotes since direction is just a call parameter.
Part of [Easy Zigbee Dimming](https://github.com/willmakenoise/ha_zigbee_easy_dim).
Requires the ZHA integration (not zigbee2mqtt or deCONZ).
domain: script
source_url: https://github.com/willmakenoise/ha_zigbee_easy_dim/blob/main/blueprints/script/zigbee_start_light_level_change.yaml
input: {}
fields:
entity_id:
name: Entity
description: The Zigbee entity you want to control.
selector:
entity:
filter:
domain: light
integration: zha
multiple: false
group_id:
name: Group ID
description: Group ID of the Zigbee Group you want to control. You can find the group ID in the ZHA integration under "Groups".
selector:
number:
min: 1
max: 255
mode: box
direction:
name: Direction
description: Direction to dim the light. Read the description for the "Direction Sensor" field to understand how to use the "Based on sensor" option.
selector:
select:
options:
- label: Up
value: Up
- label: Down
value: Down
- label: Based on sensor
value: template
default: Up
required: true
direction_sensor:
name: Direction Sensor
description: Sensor entity (trigger template) that tracks last dim direction. Pair this with the "Last Dim Direction" sensor from this project to let a one-button remote toggle between dimming up and down.
selector:
entity:
multiple: false
filter:
domain: sensor
rate:
name: Rate
description: Rate of dimming, in units of 1/10ths of a second.
selector:
number:
min: 1
max: 255
default: 50
required: true
endpoint:
name: Endpoint
description: Endpoint of the Zigbee device to send the command to. Usually 1 for most devices, but some devices have multiple endpoints.
selector:
number:
min: 1
max: 240
default: 1
required: true
variables:
move_direction: >
{% if direction == 'template' and direction_sensor is defined %}
{{ 'Up' if state_attr(direction_sensor, 'directions').get(entity_id, '') == 'Down'
or state_attr(entity_id, 'Brightness') == 0
else 'Down' }}
{% else %}
{{ direction }}
{% endif %}
sequence:
- alias: Choose entity or group
choose:
- conditions:
- condition: template
value_template: "{{ true if entity_id is defined }}"
alias: If entity_id is set
sequence:
- alias: Issue Start Level Change
action: zha.issue_zigbee_cluster_command
data:
cluster_id: 8
cluster_type: in
# Send with on/off command (5) to ensure light turns on if off
command: "{{ 5 if move_direction == 'Up' else 1 }}"
command_type: server
endpoint_id: "{{ endpoint }}"
params:
move_mode: "{{ move_direction }}"
rate: "{{ rate }}"
ieee: "{{ device_attr(entity_id, 'identifiers') | selectattr('0', 'eq', 'zha') | first | last }}"
alias: Entity is set
- conditions:
- condition: template
value_template: "{{ group_id is defined }}"
alias: If group_id is set
sequence:
- action: zha.issue_zigbee_group_command
data:
cluster_type: in
group: "{{ group_id }}"
cluster_id: 8
command: 1
args:
- "{{ move_direction }}"
- "{{ rate }}"
alias: Issue Start Level Change to Group
alias: Group is set
Blueprint: Zigbee: Stop Light Level Change
blueprint:
name: "Zigbee: Stop Light Level Change"
description: >
Stop an in-progress Zigbee (ZHA) light level change (dimming) for a
single light entity or a Zigbee group. Call this on button-release (or
any other stop-triggering event) to pair with "Zigbee: Start Light
Level Change".
Part of [Easy Zigbee Dimming](https://github.com/willmakenoise/ha_zigbee_easy_dim).
Requires the ZHA integration (not zigbee2mqtt or deCONZ).
domain: script
source_url: https://github.com/willmakenoise/ha_zigbee_easy_dim/blob/main/blueprints/script/zigbee_stop_light_level_change.yaml
input: {}
fields:
entity_id:
name: Entity
description: Zigbee light entity you want to control.
selector:
entity:
filter:
domain: light
integration: zha
multiple: false
group_id:
name: Group ID
description: Zigbee group_id you want to control.
selector:
number:
min: 1
max: 9999
mode: box
endpoint:
name: Endpoint
description: Endpoint of the Zigbee device to send the command to. Usually 1 for most devices, but some devices have multiple endpoints.
selector:
number:
min: 1
max: 240
default: 1
required: true
sequence:
- alias: Choose entity or group
choose:
- conditions:
- condition: template
value_template: "{{ true if entity_id is defined }}"
alias: If entity is set
sequence:
- alias: Send Level Change Stop
action: zha.issue_zigbee_cluster_command
data:
ieee: "{{ device_attr(entity_id, 'identifiers') | selectattr('0', 'eq', 'zha') | first | last }}"
cluster_type: in
cluster_id: 8
command: 3
command_type: server
params: {}
endpoint_id: "{{ endpoint }}"
- conditions:
- condition: template
value_template: "{{ true if group_id is defined }}"
alias: If group_id is set
sequence:
- action: zha.issue_zigbee_group_command
data:
group: "{{ group_id }}"
cluster_id: 8
command: 3
cluster_type: in
alias: Send Level Change Stop
alias: If group is set
Optional: Last Dim Directions sensor (plain YAML)
Home Assistant doesn’t have an import UI for template blueprints yet (only automations/scripts get that treatment), so rather than ship a blueprint file that still requires hand-written use_blueprint: YAML to use, here’s the sensor directly — paste it under template: in configuration.yaml (or in a package), swapping in your own light entities:
template:
- trigger:
- trigger: state
entity_id:
- light.your_light_entity
attribute: brightness
sensor:
- name: "Last Dim Directions"
unique_id: last_dim_directions
state: "{{ trigger.entity_id if trigger is defined }}"
attributes:
directions: >
{% set eid = trigger.entity_id %}
{% set old_b = trigger.from_state.attributes.get('brightness') | default(0, true) if trigger.from_state else 0 %}
{% set new_b = trigger.to_state.attributes.get('brightness') | default(0, true) if trigger.to_state else 0 %}
{% set dir = 'Up' if new_b > old_b else 'Down' if new_b < old_b
else this.attributes.get('directions', {}).get(eid, 'Down') %}
{{ this.attributes.get('directions', {}) | combine({eid: dir}) }}
Want it all in one file, or the full step-by-step for wiring up a ZHA/Z-Wave Device trigger or Switch Manager?
Everything above (plus the full drop-in package bundling both scripts and the sensor together) is also on GitHub, kept in sync with this post:
Happy to help if anyone gets stuck setting it up, and open to PRs if you extend it (e.g. non-ZHA support). Let me know what you think!