How to slowy dim the lights

Does anyone have an idea on how i can set my lights to dim slowly over time. I have philips hue lights. What i want to do is make a ‘goto sleep scene’ and a ‘waking up scene’.

an idea i have is to create timers, but that seems so much code. Does anyone have other ideas?

import org.openhab.model.script.actions.*
import org.joda.time.*
var Timer timer15
var Timer timer14
var Timer timer13
//etc.

rule "Goto to sleep"
when
	Item SwGotoSleep changed
then
	timer15 = createTimer(now.plusMinutes(1)) [|
            sendCommand(Dimmer, "100%")
        ]
	timer14 = createTimer(now.plusMinutes(2)) [|
            sendCommand(Dimmer, "95%")
        ]
	timer13 = createTimer(now.plusMinutes(3)) [|
            sendCommand(Dimmer, "90%")
        ]
    //etc.
end

Regards,
Pieter

1 Like

If you got really “artful”, I suppose you could put this in some sort of timer-increment/brightness-decrement loop. BUT, sometimes straightforward and wordy is MUCH MUCH more maintainable than “artful” and short.

Deciphering the “artful” can be a real time-sink.

1 Like

You could do a loop and a sleep. Something like this:

rule "Go to sleep"
when
    Item SwGotoSleep changed
then
    var percent = 100
    while(percent > 0) {
        sendCommand(Dimmer, new Integer(percent).toString + "%")
        percent = percent - 5
        Thread::sleep(60000) // one minute
    }
end

I’m not positive about my conversion of “percent” to a String above but something like it should work. I think that is a bit cleaner than creating 50 timers.

Rich

3 Likes

I wonder (haven’t tried it) if you could use the createTimerWithArgument call to pass a percent type as the argument, and when the closure runs, create a new timer with argument with a smaller percentage, until you reach zero percent. Something like:

rule "Go to sleep"
when
   Item SwGotoSleep changed to ON
then
  val dim = [ pct | 
    Dimmer.sendCommand(pct)
    if (pct.longValue > 0) {
      createTimerWithArgument(now.plusMinutes(1), new PercentType(pct.longValue-5), this)
    }
  ]
  dim.apply(new PercentType(95))
end

I use this script as “Automation is Active” affordance (ie fairly subtle environmental cue that stuff is being monitored and controller).

var Number automationActiveDimmer
automationActiveDimmer=100
while(automationActiveDimmer > 0 {
    automationActiveDimmer=automationActiveDimmer-20
    sendCommand(di_LIGHT_LivingRoom_rf,automationActiveDimmer)
    Thread::sleep(2000)
}

@rlkoshak @bob_dickenson @watou Thanks for the input. I need test and see what fits my needs best

@bob_dickenson : True, simple is sometimes better. The light in question is also a RGB light, with seperate timers i could even change colours in some timers.

@rlkoshak and @bob_dickenson : I thought that ‘Thread::sleep(60000)’ would sleep the entire rules engine for 1 minute. But i presume that is not the case?

@pieter_s_top, my assumption was that each rule operates in its own thread so the sleep should only pause the one rule. But now that you mention it I realize my assumption isn’t based on anything.

Has anyone looked at the code or run an experiment? While I’ve used Thread:: sleep in my rules, it is usually for fractions of a second so if the whole rules engine pauses I wouldn’t notice.

Rich

I just did that little experiment to test if 'Threat::sleep ’ effects the other rules.

rule “Goto sleep”
when
Item SwGotoSleep changed to ON
then
logInfo(“GoToSleep”,“Going to sleep for 1 minute”)
Thread::sleep(60000) // 1 minute
logInfo(“GoToSleep”,“Wake up from sleep”)
SwGotoSleep.sendCommand(OFF)
end

rule “Kick”
when
Item KickToTest changed
then
logInfo(“KickToTest”,“Au!”)
end

I activated the ‘SwGotoSleep’ and toggled (kicked :wink: ) the ‘KickToTest’ It resulted in the following logfile:
2015-09-08 21:10:51.675 [INFO ] [openhab.model.script.GoToSleep] - Going to sleep for 1 minute
2015-09-08 21:10:53.955 [INFO ] [penhab.model.script.KickToTest] - Au!
2015-09-08 21:10:54.871 [INFO ] [penhab.model.script.KickToTest] - Au!
2015-09-08 21:11:51.707 [INFO ] [openhab.model.script.GoToSleep] - Wake up from sleep.

So while one rule is being run the others also keep running.

I love it when my unsubstantiated assumptions turn out to be true. :slight_smile:

5 Likes

Hi,
if you are using hue lights you also have the option to use the transitiontime argument of the hue API.
Unfortunately this argument cannot be set though the hue binding, but you can directly send an HTTP PUT to the hue bridge using openHABs executeCommandLine action and the linux curl tool.

This is how I slowly dim my light until it is off in 60 seconds:

var String hueApiCall = "curl@@-X@@PUT@@-d@@{\"on\": %s, \"transitiontime\": %d}@@http://<hueIP>/api/<yourAPIPassword>/lights/%d/state"
executeCommandLine(String::format(hueApiCall, "false", 600, 2))
postUpdate(Light_CO_Main, OFF) // need to update the item manually after direct API call

The transitiontime has to be defined in 100ms steps, e.g. 1 second would be a transitiontime of 10.

Disadvantage of this approach is that you cannot use the hue configuration from your item files.

2 Likes

Hi from the API it looks like the string has to be

http:///api//groups/%d/action

it works to put off and on a group, thus the transitiontime gets ignored and i don’t know why

Maybe a bit late, but i thought i would share what i ended up using.

Scene_Slaapkamer is the item that is set to value 9 to trigger the sleep mode. During the rule i check if that value stays the same.
ColorSlaapkamer is my Phillips Hue light in my Bedroom

rule "Go to sleep"
when
    Item Scene_Slaapkamer changed to 9
then	
	//Go from from a bright orang-red to soft red (and off)
	logInfo("GoToSleep", "Starting", Scene_Slaapkamer.state.toString)
	ColorSlaapkamer.sendCommand("10,100,100")
    var percent = 100
    var color = 10
    while(percent > 0 && Scene_Slaapkamer.state == 9) {
        ColorSlaapkamer.sendCommand(color.toString + ",100," + percent.toString)
        color = percent / 10
        percent = percent - 5
		logInfo("GoToSleep", color.toString, percent.toString)
        Thread::sleep(30000) //takes 10 min to go off
    }
    if(Scene_Slaapkamer.state == 9){
    	SwSlaapkamer.sendCommand(OFF)
    	Scene_Slaapkamer.sendCommand(0)
		logInfo("GoToSleep", "Finshed ")
	}else{
		logInfo("GoToSleep", "Aborted ")
	}
end

Anyone interested in my Wake up light sequence with time selection ?

2 Likes

Do also use Philips Hue in bedroom and will try your sleep lights, however I prefer a longer time to finally switch it off.

Also very interested to see your wake-up light sequence

I use the following rule and script to fade in and fade out my aquarium lights over a certain period. A cron will start the event.

I’m sure you will be able to adapt it to your own needs.

Aquarium.rules

rule "Aquarium verlichting timer OFF"
   
	when
		Time cron "0 30 20 * * ?"
	
	then
		
		if aquariumMode.state == 1 {
			logInfo("aquariumTIMER","aquariumTIMER: licht uit")
			callScript("aquarium_fade_out")
		}
	end


rule "Aquarium verlichting timer ON"
   
	when
		Time cron "0 45 10 * * ?"
	
	then
		if aquariumMode.state == 1 {
			logInfo("aquariumTIMER","aquariumTIMER: licht aan")
			callScript("aquarium_fade_in")
		}
	end

fade_in.script

var Number FadeInDimmer
var Number FadeInDimmer2

FadeInDimmer=aquariumWarmWhite.state
FadeInDimmer2=aquariumWhite.state
    
while(FadeInDimmer<100 || FadeInDimmer2<100){
        
	FadeInDimmer=FadeInDimmer+1
	FadeInDimmer2=FadeInDimmer2+1
        
	logInfo("aquariumWarmWhite", "aquariumWarmWhite fade-in: " + FadeInDimmer)
	logInfo("aquariumWhite", "aquariumWhite fade-in: " + FadeInDimmer2)
		
	sendCommand(aquariumWarmWhite,FadeInDimmer)
	sendCommand(aquariumWhite,FadeInDimmer2)

    Thread::sleep(18000)

}

fade_out.script

var Number FadeOutDimmer
var Number FadeOutDimmer2

FadeOutDimmer=aquariumWarmWhite.state
FadeOutDimmer2=aquariumWhite.state

while(FadeOutDimmer>0 || FadeOutDimmer2>0){

	FadeOutDimmer=FadeOutDimmer-1
	FadeOutDimmer2=FadeOutDimmer2-1
		
	logInfo("aquariumWarmWhite", "aquariumWarmWhite fade-out: " + FadeOutDimmer)
	logInfo("aquariumWhite", "aquariumWhite fade-out: " + FadeOutDimmer2)
        
	sendCommand(aquariumWarmWhite,FadeOutDimmer)
	sendCommand(aquariumWhite,FadeOutDimmer2)
		
	Thread::sleep(18000)

}

I hate to reply to something so old, but it still seemed relevant and I didn’t want to just start a new thread. One thing all of these examples seemed to have in common is that once they were triggered they’re going to be sending commands every so many seconds nonstop until they get to the desired end state.

What if I want to start a slow transition, but if a subsequent command is sent to the dimmer abort it? Maybe I’m slowly dimming the lights, but then I decide to go to the bathroom and hit the light switch. With these scripts running then a few minutes later the lights will go back down.

I guess I could add a check to see on each loop if the setting is still where I think it should be.

The direct Hue API solution doesn’t help me as in my case I want to just change the setting of a dimmer that isn’t directly bound to anything.

I just posted a solution to this but can’t find it so I rewrote it as a Design Pattern.

Information is gold, in case someone finds this thread one day, here’s another way to do it. It’s a bit heavy but it works very well. I’ve been using this for months with no issues. At my house OH is 100% in charge of the lights and physical control of the lights are discouraged (in fact during the upcoming remodel i’ll be completely removing the physical switches).

So there are 3 pieces needed to adjust the lights, What I call steps, adjuster delay and level. Steps is how big of a jump the rules takes when adjusting the lights(light level), delay is how long before the next jump, level is brightness. Based on the room, house, or lighting modes, steps and delay is always defined and can change VIA logic at anytime. Level is adjusted like you would expect via a rule or UI. When a light is changed VIA the UI a default value is temporarily applied to step and delay to make the transition more immediate. When logic changes the level, i usually pass steps and delay values ahead of the level so the change is as gradual as I want it to be. Also, if the lights are transitioning from an off state the steps is temporarily defaulted to a higher value(depends on the bulb type(s) and is hard coded)(outside the scope of this thread). This is to quickly bring light into a dark room. I’ve tested it as far out as 45 minutes and it works awesomely. So the rule just sat there looping for 45 minutes until the desired levels were reached. It’s really cool when all of a sudden you look around and the lighting level is drastically different, and it tickles the shit out of visitors.

If you dig through and look at whats going on you’ll see how simple it all is. The rule below only triggers when the level value changes. At any point during the transition the steps, delays, and levels can be changed but level can not be changed via the physical switch it must be done using a UI(i had a plan for that but got lazy since i decided to rip out the physical switches at some point anyway). A concurrency guard can be used but in over 6 months I’ve only seen one instance where it was necessary. I also don’t use it because for really long transitions (45 minutes) you’re effectively locked out until the transition is complete (There’s ways around that). This way changes to the steps and delays are applied the next time the rule loops(which is no big deal usually), but a change to the level triggers the rules all over again and the change in values kills the first loop and the new loop takes the lights to the new values. Hopefully this is interesting or helpful to someone. It’s very similar to the examples above except there are no hard coded values.

then
Thread::sleep(100)
	logDebug("FamilyRoom", "Ceiling Light Adjuster - Starting")
	if(Light_FF_FamilyRoom_Ceiling.state != Light_FF_FamilyRoom_Ceiling_level.state){
		logDebug("FamilyRoom", "Ceiling Light Adjuster - Target:" +Light_FF_FamilyRoom_Ceiling_level.state + "Actual:" +Light_FF_FamilyRoom_Ceiling.state)
		if(FamilyRoom_Ceiling_LightingAutomation.state!=8 || FamilyRoom_Ceiling_LightingAutomation.state!=9){
			logDebug("FamilyRoom", "Ceiling Light Adjuster - Automation Enabled")
			if(Light_FF_FamilyRoom_Ceiling.state < Light_FF_FamilyRoom_Ceiling_level.state){
				logDebug("FamilyRoom", "Ceiling Light Adjuster - Disabling Override Detection")
				Light_FF_FamilyRoom_Ceiling_OR_Bypass.sendCommand("ON")
				logDebug("FamilyRoom", "Ceiling Light Adjuster - Target:" +Light_FF_FamilyRoom_Ceiling_level.state + " Actual:" +Light_FF_FamilyRoom_Ceiling.state)
				logDebug("FamilyRoom", "Ceiling Light Adjuster - Turning Lights UP")
				var familyRoomCeilingLightAdjusterActual = Light_FF_FamilyRoom_Ceiling.state
				var familyRoomCeilingLightAdjusterTarget = Light_FF_FamilyRoom_Ceiling_level.state
				while(familyRoomCeilingLightAdjusterActual<familyRoomCeilingLightAdjusterTarget){
					var familyRoomCeilingLightAdjusterWorker = (Light_FF_FamilyRoom_Ceiling.state as DecimalType) + FamilyRoom_Ceiling_Light_Adjuster.state as DecimalType
					if(Light_FF_FamilyRoom_Ceiling.state < Light_FF_FamilyRoom_Ceiling_level.state){
						Light_FF_FamilyRoom_Ceiling_Control.sendCommand("ON")
						Light_FF_FamilyRoom_Ceiling.sendCommand(familyRoomCeilingLightAdjusterWorker)
						logDebug("FamilyRoom", "Ceiling Light Adjuster - Ceiling lights: " + Light_FF_FamilyRoom_Ceiling.state)
						Thread::sleep((FamilyRoom_Ceiling_Light_Adjuster_Timer.state as DecimalType).intValue)			
						familyRoomCeilingLightAdjusterActual = Light_FF_FamilyRoom_Ceiling.state
						familyRoomCeilingLightAdjusterTarget = Light_FF_FamilyRoom_Ceiling_level.state
					}
				}
				logDebug("FamilyRoom", "Ceiling Light Adjuster - Enabling Override Detection")
				Light_FF_FamilyRoom_Ceiling_OR_Bypass.sendCommand("OFF")
			}
			else
			if(Light_FF_FamilyRoom_Ceiling.state > Light_FF_FamilyRoom_Ceiling_level.state){
				logDebug("FamilyRoom", "Ceiling Light Adjuster - Disabling Override Detection")
				Light_FF_FamilyRoom_Ceiling_OR_Bypass.sendCommand("ON")
				logDebug("FamilyRoom", "Ceiling Light Adjuster - Target:" +Light_FF_FamilyRoom_Ceiling_level.state + " Actual:" +Light_FF_FamilyRoom_Ceiling.state)
				logDebug("FamilyRoom", "Ceiling Light Adjuster - Turning Lights DOWN")
				var familyRoomCeilingLightAdjusterActual = Light_FF_FamilyRoom_Ceiling.state
				var familyRoomCeilingLightAdjusterTarget = Light_FF_FamilyRoom_Ceiling_level.state
				while(familyRoomCeilingLightAdjusterActual>familyRoomCeilingLightAdjusterTarget){
					var familyRoomCeilingLightAdjusterWorker = (Light_FF_FamilyRoom_Ceiling.state as DecimalType) - FamilyRoom_Ceiling_Light_Adjuster.state as DecimalType
					if(Light_FF_FamilyRoom_Ceiling.state > Light_FF_FamilyRoom_Ceiling_level.state){
						Light_FF_FamilyRoom_Ceiling_Control.sendCommand("ON")
						Light_FF_FamilyRoom_Ceiling.sendCommand(familyRoomCeilingLightAdjusterWorker)
						logDebug("FamilyRoom", "Ceiling Light Adjuster - Ceiling lights: " + Light_FF_FamilyRoom_Ceiling.state)
						Thread::sleep((FamilyRoom_Ceiling_Light_Adjuster_Timer.state as DecimalType).intValue)
						familyRoomCeilingLightAdjusterActual = Light_FF_FamilyRoom_Ceiling.state
						familyRoomCeilingLightAdjusterTarget = Light_FF_FamilyRoom_Ceiling_level.state
					}
				}
				logDebug("FamilyRoom", "Ceiling Light Adjuster - Enabling Override Detection")
				Light_FF_FamilyRoom_Ceiling_OR_Bypass.sendCommand("OFF")
			}	
		}
	}
end

This has nothing to do with your rule file…but…id be very careful removing all of the physical switches. Stuff happens! And if your only control is software, you may be left in the dark, or for that matter in the light. I say this only because I have experienced it, and it has made me never again not install a physical switch, even if hidden from view such as in a garage or closet…at least you would have an override then. Just my 2 cents. Great rule by the way.

1 Like

Here’s another one using cron. No sleeps involved.

var boolean FadeIn = true
var PercentType Leuchtwert = new PercentType(0)

rule "Weihnachtsbeleuchtung Einfahrt an"
when
        Time cron "*/12 * * ? * MON-SUN"                // alle 12 Sekunden 2% => 10 Minuten Fade-in
then
        if (Weihnachtsbeleuchtung.state == OFF || Tageslicht.state == ON)
                return;

        if (Leuchtwert <= 0)
                FadeIn = true
        if (Leuchtwert >= 100)
                FadeIn = false

        if (FadeIn)
                Leuchtwert = new PercentType (Leuchtwert + 2)
        else
                Leuchtwert = new PercentType (Leuchtwert - 2)
        mobil_Dimmer72.sendCommand(Leuchtwert)

        logInfo("rules", "Schalte Weihnachtsbeleuchtung Einfahrt auf " + Leuchtwert)
end
1 Like