Easy Zigbee Dimming — smooth ZHA dimming scripts, usable from any remote/trigger

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 group
  • Zigbee: 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_event YAML 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

Open your Home Assistant instance and show the blueprint import dialog with the Zigbee: Start Light Level Change script pre-filled.

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

Open your Home Assistant instance and show the blueprint import dialog with the Zigbee: Stop Light Level Change script pre-filled.

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:

GitHub - willmakenoise/ha_zigbee_easy_dim: Smooth Zigbee (ZHA) light dimming scripts + optional direction-memory sensor, triggerable from any remote/trigger source · GitHub

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!