Smoothly dimming the leds

  • Platform information:
    • Hardware: RPI 3
    • OS: openhabianPI
    • Java Runtime Environment: (Zulu Embedded 8.25.0.76-linux-aarch32hf) (build 1.8.0_152-b76)
    • openHAB version: 2.4.0
  • Issue of the topic: I have been looking into how I can smoothly dim the leds acording to the brightness level outside. I have succeed in setting the right brightness level, however the light can change quickly sometimes and the dimming of the leds looks really bad. I’m looking to make something similar. This is what I have tried, however the Dimmer bugs out and just goes back and forward at value like 30,60. Not sure why, It might have something to do with the delay, however I need this to happen relatively quickly.
rule "RGB_W1 Adaptive"
when
Item lightLevel received update or
Item adaptiveLedsW1 changed
then
var Number set = 0
var Number current = RGB_W1D.state as DecimalType
var Number lux = lightLevel.state as DecimalType
if (adaptiveLedsW1.state == ON && lightLevel.state <= 1000) {
        set = (1000-lux)/10
}
else if (adaptiveLedsW1.state == ON && lightLevel.state >= 1001) {
        set = 0
}
while((current=current+1) <= set) {
        RGB_W1D.sendCommand(current)
        Thread::Sleep(50)
}
end

My Configuration :

Dimmer RGB_W1D {mqtt=">[broker:/led2/PWM/14:command:*:JS(topwm.js)],<[broker:/led2/PWM/14:state:JS(todim.js)]"}
Switch RGB_W1SW {mqtt=">[broker:/led2/PWM/14:command:ON:1023],>[broker:/led2/PWM/14:command:OFF:0],<[broker:/led2/PWM/14:state:JS(pwmswitch.js)]" }
Switch adaptiveLedsW1
Switch item=adaptiveLedsW1 label="LED pagal apšvietimą"
Switch item=RGB_W1SW label="LED Apšvietimas"
Slider item=RGB_W1D label="LED Apšvietimo Ryškumas"
  rule "RGB_W1 Adaptive"
when
Item lightLevel received update or
Item adaptiveLedsW1 changed
then
if (adaptiveLedsW1.state == ON && lightLevel.state <= 1000) {
        var Number lux = lightLevel.state as DecimalType
        RGB_W1D.sendCommand((1000-lux)/10)
}
else if (adaptiveLedsW1.state == ON && lightLevel.state >= 1001) {
        RGB_W1D.sendCommand(0)
}
end

In other word what I want to accomplish is

• when light instensity has changed
• calculate the right led brightness (for eg. if the light instensity is 100lx my led brightness should be 90%(i can accomplish that doing (1000-lux)/10))
• every 100ms add 1+ to the current led brightness until it reaches the right led brightness
2019-02-07 17:13:37.364 [vent.ItemStateChangedEvent] - RGB_W1D changed from 29.0 to 30

2019-02-07 17:13:37.421 [vent.ItemStateChangedEvent] - RGB_W1D changed from 30 to 30.000000000000004

2019-02-07 17:13:37.460 [ome.event.ItemCommandEvent] - Item 'RGB_W1D' received command 31

2019-02-07 17:13:37.484 [vent.ItemStateChangedEvent] - RGB_W1D changed from 30.000000000000004 to 31

^^
buggy dimmer

You’ve probably got multiple copies of the rule running, each doing its own thing.

This is a bad idea, you are tying it up in a long running rule (hencethose multiple copies running)

Might get some ideas here


there are plenty other dimmer how-tos

1 Like

I have taken some inspiration from the forums and managed to get this working:

rule "Dimmer"
when
Item lightLevel received update or
Item adaptiveLedsW1 changed
then
val int timeoutMills = 60
var int dimLevel = (RGB_W1D.state as DecimalType).intValue
var Timer timer = null
var int setLevel = ((1000-(lightLevel.state as DecimalType))/10).intValue
if(adaptiveLedsW1.state == ON && lightLevel.state <= 1000) {
    if(dimLevel <= setLevel) {
        if (timer === null) {
                timer = createTimer(now.plusSeconds(0), [ |
                RGB_W1D.sendCommand(dimLevel)
                if (dimLevel == setLevel) {
                        timer = null
                } else {
                        dimLevel = dimLevel + 1
                        timer.reschedule(now.plusMillis(timeoutMills))
                }
                ])
        }
    } else {
        if (timer === null) {
                timer = createTimer(now.plusSeconds(0), [ |
                RGB_W1D.sendCommand(dimLevel)
                if (dimLevel == setLevel) {
                        timer = null
                } else {
                        dimLevel = dimLevel - 1
                        timer.reschedule(now.plusMillis(timeoutMills))
                }
                ])
        }
    }
}
end

however this happens sometimes

2019-02-07 18:24:33.060 [vent.ItemStateChangedEvent] - RGB_W1D changed from 89 to 90

2019-02-07 18:24:33.068 [ome.event.ItemCommandEvent] - Item 'RGB_W1D' received command 90

2019-02-07 18:24:33.090 [ome.event.ItemCommandEvent] - Item 'RGB_W1D' received command 91

2019-02-07 18:24:33.143 [ome.event.ItemCommandEvent] - Item 'RGB_W1D' received command 91

2019-02-07 18:24:33.175 [ome.event.ItemCommandEvent] - Item 'RGB_W1D' received command 92

2019-02-07 18:24:33.229 [vent.ItemStateChangedEvent] - RGB_W1D changed from 90 to 91

2019-02-07 18:24:33.234 [ome.event.ItemCommandEvent] - Item 'RGB_W1D' received command 93

2019-02-07 18:24:33.238 [ome.event.ItemCommandEvent] - Item 'RGB_W1D' received command 92

2019-02-07 18:24:33.279 [vent.ItemStateChangedEvent] - RGB_W1D changed from 91 to 92

it causes the dimmer to be laggy sometimes

Turn off autoupdate for your Item. Every time you send a command, autoupdate guesses what the result might be and updates the Item. It’s doing that in its own timeframe, and won’t be synchronised with your dimming steps.

1 Like

the autoupdate bugs out everything and the state always goes to a 100

Dimmer RGB_W1D {mqtt=">[broker:/led2/PWM/14:command:*:JS(topwm.js)]",autoupdate="false"}

For some unknown reason, you’ve deleted your MQTT input so the Item no longer gets state from the real dimmer. If you do mean to run it blind, you’ll need autoupdate back.

I’m suprised the rule isn’t throwing errors in your logs anyway, the local/global variables status looks all wrong.

1 Like

Worked it out. My end config.
.items

Dimmer RGB_W0D {mqtt=">[broker:/led/PWM/5:command:*:JS(topwm.js)],<[broker:/led/PWM/5:state:JS(todim.js)]"}
Switch RGB_W0SW {mqtt=">[broker:/led/PWM/5:command:ON:1023],>[broker:/led/PWM/5:command:OFF:0],<[broker:/led/PWM/5:state:JS(pwmswitch.js)]" }
Switch adaptiveLedsW0

.rules

rule "Slowly Dim Up"
when
Item lightLevel received update or
Item adaptiveLedsW1 changed
then
val int timeoutMills = 100
var int dimLevel = (RGB_W1D.state as DecimalType).intValue
var Timer timer = null
var int setLevel = ((1000-(lightLevel.state as DecimalType))/10).intValue
if(adaptiveLedsW1.state == ON && lightLevel.state <= 1000) {
    if(dimLevel <= setLevel) {
        if (timer === null) {
                timer = createTimer(now.plusSeconds(0), [ |
                RGB_W1D.postUpdate(dimLevel)
                if (dimLevel == setLevel) {
                        timer = null
                } else {
                        dimLevel = dimLevel + 1
                        timer.reschedule(now.plusMillis(timeoutMills))
                }
                ])
        }
    } else {
        if (timer === null) {
                timer = createTimer(now.plusSeconds(0), [ |
                RGB_W1D.postUpdate(dimLevel)
                if (dimLevel == setLevel) {
                        timer = null
                } else {
                        dimLevel = dimLevel - 1
                        timer.reschedule(now.plusMillis(timeoutMills))
                }
                ])
        }
    }
}
end

.sitemap

Switch item=adaptiveLedsW1 label="LED pagal apšvietimą"
Switch item=RGB_W1SW label="LED Apšvietimas"
Slider item=RGB_W1D label="LED Apšvietimo Ryškumas"

todim.js

(function(i) {
    if(i>1000) {
        return 100;
    } else if (i<=1000) {
        return parseInt(Number(i/10));
    }
})(input)

topwm.js

(function(i) {
    return i*10.23;
})(input)

pwmswitch.js

(function(i) {
    if(i==1023 || i==1023.0) {
    var state = "ON";
    } else if (i==0 || i==0.0){
    var state = "OFF";
    } else {
    var state = "UNDEF";
    }
    return state;
})(input)

didn’t mean to, it fixed my first issue with the buggy dimmer, the math was wrong.

I’m not getting any errors

Well, can’t beat that.

I suspect things might go wrong if you have more than start of the dimming rule - each will create it’s own private, independent timer. But if light levels drift slowly, that’s not likely to happen I suppose.

Yes that’s better.
50 milliseconds is a bit short for openHAB depending on what platform your run
I would recommend that you make that even longer and increase the iteration.
You will not notice the difference visually and it will run much smother:

val int timeoutMills = 500
....
                        dimLevel = dimLevel + 5

I’m currently trying to run two dimmers simultaneously ,however if they are in the same rules file one of them doesn’t work, I have created separate timers.

You’ll have to post the whole code, please

var Timer RGB_W0T = null
var Timer RGB_W1T = null
var Timer RGB_W2T = null
val int timeoutMills = 100

rule "Progressive Dimmer RGB_W0D"
when
Item lightLevel changed or
Item adaptiveLedsW0 changed
then
if(adaptiveLedsW0.state == ON) {
        var int dimLevel = (RGB_W0D.state as DecimalType).intValue
	var int setLevel = 0
        if(lightLevel.state <= 1000) { setLevel = ((1000-(lightLevel.state as DecimalType))/10).intValue }
        else { setLevel = 0 }
	if (RGB_W0T === null) {
                RGB_W0T = createTimer(now.plusSeconds(0), [ |
                if (dimLevel == setLevel) {
                        RGB_W0T = null
                } else {
                        if(dimLevel < setLevel) dimLevel = dimLevel + 1
                        else if(dimLevel > setLevel) dimLevel = dimLevel - 1
                        var int pwmValue = ((dimLevel * 1024) / 100).intValue
                        publish("broker","/led/PWM/5",pwmValue.toString)
                        RGB_W0T.reschedule(now.plusMillis(timeoutMills))
                }
                ])
        }
}
end

rule "Progressive Dimmer RGB_W1D"
when
Item lightLevel changed or
Item adaptiveLedsW1 changed
then
if(adaptiveLedsW1.state == ON) {
        var int dimLevel = (RGB_W1D.state as DecimalType).intValue
        var int setLevel = 0
        if(lightLevel.state <= 1000) { setLevel = ((1000-(lightLevel.state as DecimalType))/10).intValue }
        else { setLevel = 0 }
        if (RGB_W1T === null) {
                RGB_W1T = createTimer(now.plusSeconds(0), [ |
                if (dimLevel == setLevel) {
                        RGB_W1T = null
                } else {
                        if(dimLevel < setLevel) dimLevel = dimLevel + 1
                        else if(dimLevel > setLevel) dimLevel = dimLevel - 1
                        var int pwmValue = ((dimLevel * 1024) / 100).intValue
                        publish("broker","/led2/PWM/14",pwmValue.toString)
                        RGB_W1T.reschedule(now.plusMillis(timeoutMills))
                }
                ])
        }
}
end

rule "Progressive Dimmer RGB_W2D"
when
Item lightLevel changed or
Item adaptiveLedsW2 changed
then
if(adaptiveLedsW2.state == ON) {
        var int dimLevel = (RGB_W2D.state as DecimalType).intValue
        var int setLevel = 0
        if(lightLevel.state <= 1000) { setLevel = ((1000-(lightLevel.state as DecimalType))/10).intValue }
        else { setLevel = 0 }
        if (RGB_W2T === null) {
                RGB_W2T = createTimer(now.plusSeconds(0), [ |
                if (dimLevel == setLevel) {
                        RGB_W2T = null
                } else {
                        if(dimLevel < setLevel) dimLevel = dimLevel + 1
                        else if(dimLevel > setLevel) dimLevel = dimLevel - 1
                        var int pwmValue = ((dimLevel * 1024) / 100).intValue
                        publish("broker","/led2/PWM/4",pwmValue.toString)
                        RGB_W2T.reschedule(now.plusMillis(timeoutMills))
                }
                ])
        }
}
end

So this is what I got to work, do you see anything that can cause me any issues? Help is appreciated :slight_smile:

val int timeoutMills = 150

rule "Progressive Dimmer LED_W0D"
        when
                Item lightLevel changed or
                Item LED_W0A changed
        then
        if(LED_W0A.state == ON) {
                var Timer LED_W0T = null
                var int dimLevel = (LED_W0D.state as DecimalType).intValue
                var int setLevel = 0
                if(lightLevel.state <= 1000)
                        setLevel = ((1000-(lightLevel.state as DecimalType))/10).intValue
                else
                        setLevel = 0
                if(LED_W0T === null) {
                        LED_W0T = createTimer(now.plusSeconds(0), [ |
                                if (dimLevel == setLevel) {
                                        LED_W0T = null
                                } else if (LED_W0T !== null) {
                                        if(dimLevel < setLevel)
                                                dimLevel = dimLevel + 1
                                        else if(dimLevel > setLevel)
                                                dimLevel = dimLevel - 1
                                        LED_W0D.sendCommand(dimLevel)
                                        LED_W0T.reschedule(now.toInstant().plusMillis(timeoutMills).atZone(now.zone))
                                }
                        ])

                }
        }

end

I’m upgrading my installation to openHab 3.0, I thought I would share this rule, with you guys, for anyone that will be searching regarding this topic.

1 Like