A victorious day, long in the making!

Hey everyone - Today was a great day in a way that nearly no one in my real life (certainly not my wife) can appreciate. Today months (really??) of tinkering came together to yeild a little nicety I’ve wanted for a long time.

TL;DR: I now have a Zigbee rotary knob (Tuya TS004F) that smoothly and reliably controls a group of bathroom lights, all dimming in sync, even though the underlying bulbs/drivers behave very differently. The path to get there ended up producing a few reusable things that others might find useful.

(Detailed project writeup if you’re interested.)


What I was trying to solve

My bathroom has multiple lights from different vendors. Out of the box:

  • They all have different minimum brightness levels
  • They ramp up/down at different perceived speeds
  • Some flicker at low values, others don’t

The end result: if you put them in a standard light group and dim them together, it never feels right. Some are too bright, some too dim, and the low end is especially ugly.

What I really wanted was:

  • One physical rotary knob on the wall
  • All lights in the room dimming together and smoothly
  • A setup I could reuse in other rooms later

What came out of the project

To get that experience, I ended up creating three pieces:

  1. A custom integration to normalize dimming behavior
    This integration introduces “normalized” light proxies in front of real lights. Each proxy:

    • Maps 0–255 to a custom curve between a Low Light Value (LLV) and High Light Dimming (HLD) for that specific light
    • Lets me tune the low/high ends per bulb so that perceived brightness is aligned across fixtures
    • Keeps the underlying lights in sync when adjusting brightness on the proxy

    The end result: when the proxy is at, say, 40%, all physical lights look like they’re at roughly the same brightness, even though they’re using different raw levels behind the scenes.

    Repo: GitHub - gunnjr/normalize_lights_integration: Normalizes lighting attributes (currently brightness) so a single scalar control yields consistent visible results across mixed devices.

  2. A HACS-published custom integration for log level management (logger_manager)
    While building and tuning the proxies, I needed to crank logging up and down frequently to watch:

    • Zigbee events
    • Light state changes
    • Service calls going through Home Assistant

    The logger_manager integration lets you manage logger levels from the UI instead of editing YAML or restarting just to tweak logging.

Open in Home Assistant

Repo: GitHub - gunnjr/ha-logger-manager: A Home Assistant custom integration that makes it easier/faster to manager logger levels. It provide a user interface (Dashboard Card) that makes it easy to discover, select, and configure loggers. With it, users can quickly dial in logging specific to their task or challenge.

  1. A blueprint that maps Tuya TS004F knob events to a light entity
    The TS004F is a quirky little device, so I built a blueprint that:

    • Handles rotate left/right for dimming
    • Handles short/long presses for actions like on/off or “jump to preset”
    • Debounces events so it feels smooth with a dimmable light or light group

    You can point the blueprint at any light or light group, which in my case is the normalized bathroom group.

    Blueprint: ha-resources/ha-assets/blueprints/tuya-ts004f at main · gunnjr/ha-resources · GitHub


How it all works together

The flow now looks like this:

  1. Each physical bathroom light is wrapped in a normalized proxy (via the custom integration)
  2. Those normalized proxies are combined into a Home Assistant light group
  3. The TS004F blueprint targets that light group
  4. Rotating the knob sends dimming events → the group adjusts → the integration maps that to per-light normalized levels

From my perspective as a user:

  • I walk into the bathroom
  • Turn the knob
  • All lights rise and fall together in a way that finally feels natural and consistent

No more mismatched brightness levels, no more “one light is blinding while another is barely on.”


Why I’m sharing this

I’m not trying to present this as the “right” way to do it — I’m just a guy who went down a rabbit hole and ended up with:

  • A normalized dimming layer for mixed hardware
  • A logging helper to make debugging less painful
  • A reusable knob blueprint that ties everything together

If you:

  • Have mixed dimmers/lights that don’t play nicely together, or
  • Use the Tuya TS004F and want it to behave more like a traditional dimmer

…then pieces of this might be helpful.


Feedback, ideas, and next steps

I’d love any feedback on:

  • Better ways to model the dimming curve (right now it’s LLV/HLD-based)
  • Improvements to the TS004F blueprint behavior
  • Ideas for extending this to room-level controllers or more complex scenes

If there’s interest, I can also add more detailed docs, config examples, or diagrams of how the entities are wired together.

Thanks for reading — and huge shoutout to the HA community in general; this project only exists because of all the examples, quirks, and discussions people have shared over the years.

3 Likes

Using 2 other blueprints that sees my Moes knob fine but your does not. The BP title says as “ZHA”, if it only works on ZHA please put that in the TL;DR :wink:

Which LLM did you use to help you write this?
It’s very well done.
ta,dr

1 Like

Please put more info in the TLDR.
The rest isn’t really human readable. :sweat:

Thanks again for sharing this with me in response to a similar (but thankfully less complex) problem I was having. Now that I’ve read your post (but before I dive in to your repo), I see just how complicated your problem was and how detailed your documentation of your fix is. Super impressive and interesting. Thanks again!

1 Like