Lutron Aurora controller for Zigbee2MQTT via pyscript

Trying to get the most I can out of these old switches. They don’t provide enough information in ZHA to do reasonable dimmer control, but Z2MQTT provides a little more info for control.

# Zigbee2MQTT - Lutron Aurora Control
# - Listens to MQTT messages on zigbee2mqtt/<device>
# - Maps switch device names to target light entities using SWITCH_TO_LIGHTS dictionary
# - Button press toggles lights on/off
# - Rotation adjusts brightness (only when lights are already on)
# - Uses action_level and action_transition_time from Z2M payloads
# - Supports button-press transition values from older and newer Zigbee2MQTT versions

# logger.set_level(**{"custom_components.pyscript.file.zigbee2mqtt_lutron_aurora_control": "debug"})

# Configuration: Map switch device names to target light entities
# Key: Switch name (from MQTT)
# Value: List of light entity IDs that this switch controls
SWITCH_TO_LIGHTS = {
    "Office Hue Switch": [
        "light.office_nano_bulb_01",
        "light.office_nano_bulb_02",
        "light.office_hue_lightstrip",
    ],
    "Living Room Hue Switch": ["light.magic_areas_light_groups_living_room_all_lights"],
}

# Brightness settings
BRIGHTNESS_MIN = 10
BRIGHTNESS_MAX = 255
DEFAULT_TRANSITION = 0.2


# Clamp brightness to valid range
def clamp_brightness(value: int) -> int:
    return max(BRIGHTNESS_MIN, min(value, BRIGHTNESS_MAX))


# Returns brightness of first lit entity, or None if no lights are on
def get_current_brightness(target_lights: list[str]) -> int | None:
    for entity in target_lights:
        if state.get(entity) == "on":
            brightness = state.get(f"{entity}.brightness")
            if brightness is not None:
                return int(brightness)
    return None


# Check if the event is a button press (vs rotation)
def is_press_event(transition_time: float, action_level: int) -> bool:
    # Older Z2M versions report 0.07; newer versions report 0.7.
    if abs(transition_time - 0.07) < 1e-3:
        return True
    if abs(transition_time - 0.7) < 1e-3:
        return True
    return False


@mqtt_trigger("zigbee2mqtt/+")
def on_z2m_event(topic=None, payload=None, payload_obj=None, **kwargs):
    if not topic or not topic.startswith("zigbee2mqtt/"):
        return

    device_name = topic.split("/", 1)[1]

    # Look up target lights from configuration mapping
    target_lights = SWITCH_TO_LIGHTS.get(device_name)
    if target_lights is None:
        log.debug(f"No mapping found for switch '{device_name}', skipping")
        return

    log.debug(f"TARGETING: {target_lights}")

    # Check if any light entity exists
    entity_exists = False
    for entity in target_lights:
        if state.get(entity):
            entity_exists = True
            break
    if not entity_exists:
        log.debug(f"No light entities found in {target_lights}, skipping")
        return

    # Parse payload
    action_level = (payload_obj or {}).get("action_level")
    transition_time = (payload_obj or {}).get("action_transition_time", 0)

    # Ignore if no action_level reported
    if action_level is None:
        return

    # Handle button press: toggle light
    if is_press_event(transition_time, action_level):
        log.debug(f"{device_name} --> TOGGLE")
        light.toggle(entity_id=target_lights)
        return

    # Handle rotation: adjust brightness (only when lights are on)
    current_brightness = get_current_brightness(target_lights)
    if current_brightness is None:
        return

    new_brightness = clamp_brightness(action_level)

    # Skip redundant write if no change
    if current_brightness == new_brightness:
        return

    log.debug(f"{device_name} --> Rotate dim -> brightness {new_brightness}")
    light.turn_on(
        entity_id=target_lights,
        brightness=new_brightness,
        transition=DEFAULT_TRANSITION,
    )

I have been trying to look for solution like this for ages.
For the uninitiated like me, how do I use the script & where do I put / setup the script?

Hi @k8gg

  1. On your computer, create a file called zigbee2mqtt_lutron_aurora_control.py
  2. Copy and paste the code from the first post into the file.
  3. In Home Assistant, install pyscript via HACS - Use Options 1 here.
  4. Follow the configuration instructions here. During configuration there’s a sentence "Add files with a suffix of .py in the folder <config>/pyscript". Copy the zigbee2mqtt_lutron_aurora_control.py to the pyscript folder during that step.

If you need more help let me know. I’m excited to see if this works well for others.

Cheers!

Does this work with the SONOFF Zigbee 3.0 USB Dongle Plus-E ?

I don’t know why it wouldn’t. It is Zigbee2MQTT specific, not hardware specific.
Although it’s possible I don’t know some limitation.

Can’t hurt to just try it and find out, yeah?

Just ordered it off amazon, going to update here! Thanks for the quick response.

Works like a freakin charm @GollyJer . You are the goat . thanks

Updated the code in OP to support newer Zigbee2MQTT versions, which report Aurora button presses with action_transition_time=0.7 instead of 0.07. Code will work in old and new versions of z2mqtt.