Home Assistant & Light

Fixing Matter RGBW Bulb Flicker in Home Assistant (Without Giving Up Brightness)

I recently ran into an annoying but surprisingly common problem with Matter RGB bulbs in Home Assistant:

White light flickers or becomes unstable above ~75–80% brightness,
while colored light works perfectly fine at 100%.

At first, this feels like it must be a software issue. Matter is new, Thread can be finicky, and Home Assistant’s lighting stack is complex. My initial instinct was to look for firmware updates, network issues, or integration bugs.

None of that helped — because the issue wasn’t software at all.


Understanding what’s actually going on

Most RGB bulbs don’t treat “white” as just another color. Electrically, white is the most demanding mode the bulb has.

White light usually:

  • Drives multiple LED channels simultaneously
  • Draws significantly more current than single-color output
  • Pushes the internal driver hardest near maximum brightness

This becomes especially noticeable at the cool end of the white spectrum. In my case, the bulb’s native white range is:

  • 2702 K → 6535 K

At around 6500 K, high brightness consistently triggered flicker. Warm whites were slightly more forgiving, and saturated colors were perfectly stable even at full output.

That was the first hint that brightness needed to be handled differently depending on how the bulb was being used.


What Home Assistant actually reports

One of the trickier parts of diagnosing this was understanding what Home Assistant exposes at the entity level.

When the bulb is set to cool white, Home Assistant reports something like:





color_mode: color_temp
brightness: 192
color_temp_kelvin: 6535
hs_color: [54.768, 1.6]
rgb_color: [255, 255, 251]

Even though HS and RGB values are present, the critical attribute is:





color_mode: color_temp

When the bulb is truly in a colored state, Home Assistant reports:





color_mode: hs

That distinction turned out to be reliable across warm white, cool white, and fully colored scenes — and it became the foundation of the solution.


The design goal

I didn’t want to “fix” flicker by giving up functionality. The goal was:

  • Cap brightness only when the bulb is in white mode
  • Leave RGB colors completely unrestricted
  • Avoid visible snap-back or reactive corrections
  • Keep the solution group-safe and Matter-friendly
  • Make it adjustable without rewriting configuration

In other words, I wanted the system to understand intent, not just react to raw brightness values.


The approach

The solution has three main components.

A UI-controlled brightness cap

Instead of hard-coding a brightness limit, I created a Number Helper in Home Assistant:





input_number.maxlightflicker
  • Range: 0–100
  • Meaning: Maximum safe brightness for white light, as a percentage

This lets me tune the threshold dynamically as firmware, fixtures, or power conditions change.


A Template Light as a control layer

Rather than controlling the real bulb (or group) directly, I wrapped it in a Template Light.

This template:

  • Mirrors the real entity’s state and attributes so the UI behaves correctly
  • Intercepts turn_on calls
  • Applies conditional logic:
    • If color_mode == hs, allow full brightness
    • If color_mode == color_temp, clamp brightness to the helper-defined limit

Because this happens before the service call reaches the bulb, the driver never enters the unstable region — there’s no flicker and no correction afterward.


Respecting the bulb’s real white range

To keep the UI accurate, the template entity is explicitly configured with the bulb’s native white range:





2702 K → 6535 K

That ensures the color temperature slider behaves exactly like the physical bulb, just with smarter brightness handling layered on top.


How it behaves day to day

From a user perspective, nothing feels “special” — and that’s the point.

  • White light ramps smoothly up to its safe maximum
  • Cool whites stay usable without instability
  • Colored scenes hit 100% brightness with no limitation
  • The brightness cap can be adjusted live from the UI
  • Groups behave consistently

Most importantly, the system never needs to correct itself after the fact. The unsafe command is never sent.


A broader lesson

This ended up being a good reminder that Home Assistant isn’t just an automation engine — it’s a control plane.

By understanding:

  • how devices actually behave electrically, and
  • how Home Assistant represents state,

you can build solutions that respect hardware limits without sacrificing capability.

If you’re running Matter RGB bulbs and seeing flicker in white mode, this isn’t something you have to live with — it’s just a problem that needs to be constrained thoughtfully.

You can find the example below:

template:
  - light:
      - name: "Living Room Ficture (SmartCap)"
        unique_id: living_room_ficture_smartcap

        turn_on:
          - variables:
              cap_pct: "{{ states('input_number.maxlightflicker') | int(76) }}"
              cap: "{{ (cap_pct * 255 / 100) | round(0) | int }}"
              current_mode: "{{ state_attr('light.living_room_ficture', 'color_mode') }}"
              requested_hs: "{{ hs_color is defined }}"
              # With your bulbs: white => color_temp, color => hs
              rgb_mode: "{{ requested_hs or (current_mode == 'hs') }}"
              out_brightness: >-
                {% if brightness is not defined %}
                  {% if rgb_mode %}255{% else %}{{ cap }}{% endif %}
                {% else %}
                  {% if rgb_mode %}{{ brightness }}{% else %}{{ [brightness, cap] | min }}{% endif %}
                {% endif %}

          - choose:
              - conditions: "{{ hs_color is defined }}"
                sequence:
                  - service: light.turn_on
                    target: { entity_id: light.living_room_ficture }
                    data:
                      hs_color: "{{ hs_color }}"
                      brightness: "{{ out_brightness }}"

              - conditions: "{{ color_temp_kelvin is defined }}"
                sequence:
                  - service: light.turn_on
                    target: { entity_id: light.living_room_ficture }
                    data:
                      color_temp_kelvin: "{{ color_temp_kelvin }}"
                      brightness: "{{ out_brightness }}"

              - conditions: "{{ color_temp is defined }}"
                sequence:
                  - service: light.turn_on
                    target: { entity_id: light.living_room_ficture }
                    data:
                      color_temp: "{{ color_temp }}"
                      brightness: "{{ out_brightness }}"

              - conditions: "{{ kelvin is defined }}"
                sequence:
                  - service: light.turn_on
                    target: { entity_id: light.living_room_ficture }
                    data:
                      kelvin: "{{ kelvin }}"
                      brightness: "{{ out_brightness }}"

            default:
              - service: light.turn_on
                target: { entity_id: light.living_room_ficture }
                data:
                  brightness: "{{ out_brightness }}"

        turn_off:
          - service: light.turn_off
            target: { entity_id: light.living_room_ficture }

        set_level:
          - variables:
              cap_pct: "{{ states('input_number.maxlightflicker') | int(76) }}"
              cap: "{{ (cap_pct * 255 / 100) | round(0) | int }}"
              current_mode: "{{ state_attr('light.living_room_ficture', 'color_mode') }}"
          - service: light.turn_on
            target: { entity_id: light.living_room_ficture }
            data:
              brightness: >-
                {% if current_mode == 'hs' %}
                  {{ brightness }}
                {% else %}
                  {{ [brightness, cap] | min }}
                {% endif %}

        set_hs:
          - service: light.turn_on
            target: { entity_id: light.living_room_ficture }
            data:
              hs_color: "{{ hs }}"
              brightness: "{{ brightness | default(255) }}"

        set_temperature:
          - variables:
              cap_pct: "{{ states('input_number.maxlightflicker') | int(76) }}"
              cap: "{{ (cap_pct * 255 / 100) | round(0) | int }}"
              out_brightness: "{{ [brightness | default(cap), cap] | min }}"
          - choose:
              - conditions: "{{ color_temp_kelvin is defined }}"
                sequence:
                  - service: light.turn_on
                    target: { entity_id: light.living_room_ficture }
                    data:
                      color_temp_kelvin: "{{ color_temp_kelvin }}"
                      brightness: "{{ out_brightness }}"
            default:
              - service: light.turn_on
                target: { entity_id: light.living_room_ficture }
                data:
                  color_temp: "{{ color_temp }}"
                  brightness: "{{ out_brightness }}"

Leave a Reply

Your email address will not be published. Required fields are marked *