Exploring Smart Lighting Integration with IKEA STYRBAR and Zigbee2MQTT

As a long-time user of smart lighting solutions, I’ve been experimenting with integrating my IKEA STYRBAR (E2001/E2002) with a CCT LED strip through Zigbee2MQTT. The goal was to mimic the behavior of IKEA lights and controllers, creating a seamless experience with three scenes: warm, normal, and cold. While the setup seemed straightforward, there were a few hurdles to overcome.

Initially, I connected the CCT LED strip to a Shelly RGBW2, assigning each channel to warm and cold white separately. The challenge was to combine these into a single light entity controlled by the STYRBAR. After some research, I discovered that manually creating a scene helper of type input number with a range from 0 to 1 was the key to achieving the desired functionality.

Here’s a simplified version of the automation I implemented:

yaml
alias: Downstair bathroom mirror light controller
description: “”
trigger:

  • platform: state
    entity_id:
    • sensor.potatozeta_action
      attribute: action
      to:
    • “on”
    • “off”
    • arrow_left_click
    • arrow_right_click
    • brightness_move_down
    • brightness_move_up
    • brightness_stop
      condition:
      action:
  • variables:
    command: “{{ trigger.to_state.state }}”
    low_brightness: 1
    default_brightness: 20
    high_brightness: 100
    step_pct: 5
    speed: 300
    warm_channel: light.downstairs_bathroom_channel_4
    cold_channel: light.downstairs_bathroom_channel_3
    scene: “{{ states(‘input_number.mirror_scene’) | int }}”
    current_visible_brightness: >-
    {{ (state_attr(‘light.downstair_bathroom_mirror’, ‘brightness’) or 0) / 2.55 }}
  • choose:
    • conditions:
      • condition: template
        value_template: “{{ command == ‘on’ }}”
        sequence:
      • service: light.turn_on
        target:
        entity_id: |{% if scene == 0 %} {{ warm_channel }}{% elif scene == 1 %} {{ warm_channel }}, {{ cold_channel }}{% elif scene == 2 %} {{ cold_channel }}{% endif %}
        data:
        brightness_pct: “{{ default_brightness }}”
    • conditions:
      • condition: template
        value_template: “{{ command == ‘off’ }}”
        sequence:
      • service: light.turn_off
        target:
        entity_id: |{% if scene == 0 %} {{ warm_channel }}{% elif scene == 1 %} {{ warm_channel }}, {{ cold_channel }}{% elif scene == 2 %} {{ cold_channel }}{% endif %}
    • conditions:
      • condition: template
        value_template: “{{ command == ‘brightness_move_up’ }}”
        sequence:
      • repeat:
        while:
        sequence:
        - service: light.turn_on
        target:
        entity_id: |{% if scene == 0 %} {{ warm_channel }}{% elif scene == 1 %} {{ warm_channel }}, {{ cold_channel }}{% elif scene == 2 %} {{ cold_channel }}{% endif %}
        data:
        brightness_step_pct: “{{ step_pct | int }}”
        transition: “{{ (speed / 1000) | float }}”
        - delay:
        milliseconds: “{{ speed }}”
    • conditions:
      • condition: template
        value_template: “{{ command == ‘brightness_move_down’ }}”
        sequence:
      • repeat:
        while:
        sequence:
        - variables:
        current_brightness_warm: “{{ (state_attr(warm_channel, ‘brightness’) or 0) | int }}”
        current_brightness_cold: “{{ (state_attr(cold_channel, ‘brightness’) or 0) | int }}”
        new_brightness_warm: >-
        {{ [current_brightness_warm - (step_pct * 2.55), low_brightness * 2.55] | max }}
        new_brightness_cold: >-
        {{ [current_brightness_cold - (step_pct * 2.55), low_brightness * 2.55] | max }}
        new_brightness: “{{ [new_brightness_cold, new_brightness_warm] | min}}”
        - service: light.turn_on
        target:
        entity_id: >{% set warm_on = is_state(warm_channel, ‘on’) %}{% set cold_on = is_state(cold_channel, ‘on’) %}{% if warm_on and cold_on %} {{ [warm_channel, cold_channel] | join(', ') }}{% elif warm_on %} {{ warm_channel }}{% elif cold_on %} {{ cold_channel }}{% else %} none{% endif %}
        data:
        brightness: “{{ new_brightness }}”
        transition: “{{ (speed / 1000) | float }}”
        - delay:
        milliseconds: “{{ speed }}”
    • conditions:
      • condition: template
        value_template: “{{ command == ‘arrow_right_click’ }}”
        sequence:
      • choose:
        • conditions:
          • condition: template
            value_template: “{{ scene < 2 }}”
            sequence:
          • service: input_number.set_value
            target:
            entity_id: input_number.mirror_scene
            data:
            value: “{{ scene + 1 }}”
        • choose:
          • conditions:
            • condition: template
              value_template: “{{ (scene == 0) }}”
              sequence:
              parallel:
              • service: light.turn_on
                target:
                entity_id:
                - “{{ cold_channel }}”
                - “{{ warm_channel }}”
                data:
                brightness_pct: “{{ current_visible_brightness }}”
          • conditions:
            • condition: template
              value_template: “{{ scene == 2 or scene == 1 }}”
              sequence:
            • service: light.turn_on
              target:
              entity_id: “{{ cold_channel }}”
              data:
              brightness_pct: “{{ current_visible_brightness }}”
            • service: light.turn_off
              target:
              entity_id: “{{ warm_channel }}”
    • conditions:
      • condition: template
        value_template: “{{ command == ‘arrow_left_click’ }}”
        sequence:
      • choose:
        • conditions:
          • condition: template
            value_template: “{{ scene > 0 }}”
            sequence:
          • service: input_number.set_value
            target:
            entity_id: input_number.mirror_scene
            data:
            value: “{{ scene - 1 }}”
        • choose:
          • conditions:
            • condition: template
              value_template: “{{ (scene == 0) or (scene == 1) }}”
              sequence:
              parallel:
              • service: light.turn_on
                target:
                entity_id: “{{ warm_channel }}”
                data:
                brightness_pct: “{{ current_visible_brightness }}”
              • service: light.turn_off
                target:
                entity_id: “{{ cold_channel }}”
          • conditions:
            • condition: template
              value_template: “{{ scene == 2 }}”
              sequence:
            • service: light.turn_on
              target:
              entity_id:
              - “{{ warm_channel }}”
              - “{{ cold_channel }}”
              data:
              brightness_pct: “{{ current_visible_brightness }}”
              default:
              mode: restart

This setup allows for smooth transitions between scenes and brightness levels, all controlled seamlessly by the STYRBAR. The key takeaway is that with a bit of configuration and automation, even basic hardware can be transformed into a sophisticated smart lighting system. If anyone has questions or suggestions for improvement, I’d love to hear them!

#SmartLighting Zigbee2MQTT ikea HomeAutomation