Min power/brightness for LED light in ESPHome

I have flashed a Tuya LED light bulb with ESPHome. Using original Tuya FW I can dim down to 1% without any problem but with ESPHome and the light/output/sm2135 components I can only dim to 20% until it turns of.

With gamma_correct at 1 it works like the original FW but 2.8 is default so I guess there’s a good reason for that

Any suggestions what I need to do to be able to dim the whole span from 0 to 1.

I guess it’s something silly I have missed

external_components:
  - source: github://pr#3850
    components:
      - sm2135
    refresh: 10 min

sm2135:
  clock_pin: P7
  data_pin: P6
  rgb_current: 15mA
  cw_current: 40mA

output:
  - platform: sm2135
    id: output_red
    channel: 2
  - platform: sm2135
    id: output_green
    channel: 0
  - platform: sm2135
    id: output_blue
    channel: 1
  - platform: sm2135
    id: output_cold
    channel: 3
  - platform: sm2135
    id: output_warm
    channel: 4

light:
  - platform: rgbww
    id: light_rgbww
    name: Light
    color_interlock: true
    cold_white_color_temperature: 6500 K
    warm_white_color_temperature: 2700 K
    red: output_red
    green: output_green
    blue: output_blue
    cold_white: output_cold
    warm_white: output_warm
    #gamma_correct: 1

Well then isn’t that the answer then?

I don’t think the colors are like as sharp with gamma=1 as with the default value and compared with the unpatched FW.

My thinking was that it would be possible to apply a formula like this but I don’t know how to implement that

E.G. if it turns off at 20% and lower:
0.2+x*0.8
And maybe some special treatment to make sure that it totally turns off if x=0

Found it, use min_power. Output Component — ESPHome

I have tried it but it doesn’t work as I expected (or more precise as I would like to work). If I set min_power to e.g. 0.2 it will never go beyond 20%, i.e. not even turn of.

Yes I can also add the zero_means_zero: true so that it will turn of when I decrease to 0%.

But having this configuration, dimming works as expected between 20 and 100% but between 1% and 20% the dimming effect will be stuck at it’s min value, i.e. a none linear behavior.

So what I’m looking for is a config that keeps the adjustment linear from the light component (0-100%) from the min level I define and the formula 0.2+x*0.8 will do that but I can’t see how I would be able to implement that

I think that I’m in a similar boat: LED strips, controlled via MOSFETs, that go completely dark at 5% or lower. Setting min_power to 0.05 got me… something much brighter than I wanted.

On a hunch, I divided min_power by 10. Hmm. Better, maybe, but still way too bright.

OK. Divide by 100? Bingo. Setting min_power to 0.0005 leads to a value of 1% in the UI producing an eminently reasonable minimum brightness. (100% still gets me maximum brightness. Yay!)

Searching the ESPHome source code on GitHub for min_power sheds, uh, some light on things. In particular, note how both max_power and min_power are multiplied by 100.0. The behavior looks to be deliberate, even though it’s not immediately obvious to me why the two extra orders of magnitude are used. But hey, I’m now getting the behavior I want, so I’m happy.

I’d be curious to know if this works for you, too.

Actually, on closer (read: slightly more awake) inspection, the code I pointed to seems to be specific to logging. In any case, expressing min_power as a percentage of a percentage solves, for me at least, the problem we were both having.

What I finally did was this. I putted a calibration method between the light component and the output component

output:
  - platform: libretiny_pwm
    id: output_cold
    pin: P7

  - platform: template
    id: calibrated
    type: float
    write_action:
      - if:
          condition:
            lambda: return state > 0;
          then: 
            - output.set_level:
                id: output_cold
                level: !lambda |-
                  const int min_percentage=10;
                  float min=static_cast<float>(min_percentage)/100.0f;
                  float k=(1.0f-min)/0.99f;
                  float m=(0.99f-1.0f+min)/0.99f;
                  return k*state+m;
          else: 
            - output.set_level:
                id: output_cold
                level: 0

light:
  - platform: monochromatic
    id: light_monochromatic
    name: Light
    output: calibrated
    restore_mode: RESTORE_DEFAULT_ON
    default_transition_length: 
      seconds: 1   

This way I get a linear adjustment the whole range as below with a minimum of 10%.
Yes… It’s the 1% value (not 0%) that shall match the min value of 10% since the dimmer only goes from 1% to 100%
image

But it would be better if the light component could have this built-in as I guess this is something that everyone would like to do.

And… The light component generates a none linear value so doing this with y=kx+m is probably not the best way but… I’t works quite good for now until some smart person implements min and max in the light component

2 Likes

Yes… Since some smart person have done the calibration between pwm value and lumens (or whatever), I could also see that 1% represents 0.0004 (0.04%), and 50% represents 0.14 (14%).
So it’s not as easy as checking at what value the led starts to light and then taking that value as the min value for the output component. Bin there, done that…

Wow, thx a lot for this!
I have searched for such a solution a long time ago but up until now, the light component doesnt support it.

This is the solution until a proper implementation in the component is available.

Oh cool! But how does this work for for example RGB lights, with multiple PWM signals?