[SOLVED] Issue with "decreasing" a value in Rule

Tags: #<Tag:0x00007f74601cf760> #<Tag:0x00007f74601cf4e0>

Hi,

I’m setting up a rule for my dimmer which controls the lights in my shed.
The rule will be triggered by ASTRO info, but for testing purpose I created a switch item and using ON and OFF in the rule. This will be replaced by sunset etc, later.

I have a rule for increasing the dimmer value (state). This one works:

if(receivedCommand == ON){
                timer = null
                logDebug("rules.dimmer","Received command ON, dimmer increase started...")
                OU_shed_dimmer.sendCommand(dimLevel)
                logDebug("rules.dimmer","DimmerLevel = "+dimLevel)

                timer = createTimer(now.plusSeconds(1),[|
                        if(OU_shed_dimmer.state<100){
                                dimLevel=dimLevel+1
                                OU_shed_dimmer.sendCommand(dimLevel)
                                logDebug("rules.dimmer","In timerloop, DimLevel: "+dimLevel+" state: "+OU_shed_dimmer.state)
                                timer.reschedule(now.plusSeconds(1))
                        }else {
                                timer = null
                        }


                ])
        }

This rule, for now, increments the dimmer with 1 % at the time until 100 is reached.

Problem/ Issue
When I want to do the reverse, decreasing the dimmer, a problem occurs.
the code I use is:

        if(receivedCommand == OFF){

                timer = null
                logDebug("rules.dimmer","Received command OFF, dimmer decrease started...")
                dimLevel = OU_shed_dimmer.state
                logDebug("rules.dimmer","Dimmerlevel = "+dimLevel)
                logDebug("rules.dimmer","Timer: "+timer)
                timer = createTimer(now.plusSeconds(3),[|
                        logDebug("rules.dimmer","DECREASE in first timer line...the state of the dimmer is: "+OU_shed_dimmer.state)
                        if(OU_shed_dimmer.state>0){
                                logDebug("rules.dimmer","Dimmer state > 0 (current: "+OU_shed_dimmer.state+")...executing decrease")
                                dimLevel = dimLevel-1
                                OU_shed_dimmer.sendCommand(dimLevel)
                                logDebug("rules.dimmer","new state after decrease: "+OU_shed_dimmer.state)
                                timer.reschedule(now.plusSeconds(3))
                        }
                ])
        }

The rule seems to hang at the line

dimLevel = dimLevel -1

because nothing happens anymore. No logs are added, but no error on the scripting rule either.
The log on the dimmer rule looks as:

2019-09-29 13:27:15.865 [DEBUG] [.smarthome.model.script.rules.dimmer] - Received command OFF, dimmer decrease started...
2019-09-29 13:27:15.866 [DEBUG] [.smarthome.model.script.rules.dimmer] - Dimmerlevel = 10
2019-09-29 13:27:15.866 [DEBUG] [.smarthome.model.script.rules.dimmer] - Timer: null
2019-09-29 13:27:18.869 [DEBUG] [.smarthome.model.script.rules.dimmer] - DECREASE in first timer line...the state of the dimmer is: 10
2019-09-29 13:27:18.870 [DEBUG] [.smarthome.model.script.rules.dimmer] - Dimmer state > 0 (current: 10)...executing decrease

When I remove the line of the dimLevel = dimLevel -1, the timer keeps running and lines are added in the log…but of course, the state does not change since there is no new value…

Thank you in advance for the support!
/Jasper

Add a log line in the timer, what is the value of dimLevel?

                        logDebug("rules.dimmer","DECREASE in first timer line...the state of the dimmer is: "+OU_shed_dimmer.state)
                        if(OU_shed_dimmer.state>0){
                                logDebug("rules.dimmer","Dimmer state > 0 (current: "+OU_shed_dimmer.state+")...executing decrease")
                                logDebug("rules.dimmer", "dimLevel:" + dimLevel")

if(OU_shed_dimmer.state>0){
                                logDebug("rules.dimmer","Dimmer state > 0 (current: "+OU_shed_dimmer.state+")...executing decrease")
                                logDebug("rules.dimmer", "dimLevel:" + dimLevel)
                                dimLevel = dimLevel-1
                                OU_shed_dimmer.sendCommand(dimLevel)
                                logDebug("rules.dimmer","new state after decrease: "+OU_shed_dimmer.state)
                                timer.reschedule(now.plusSeconds(3))
                        }

Outputs in log:

2019-09-29 13:58:10.216 [DEBUG] [.smarthome.model.script.rules.dimmer] - Received command OFF, dimmer decrease started...
2019-09-29 13:58:10.217 [DEBUG] [.smarthome.model.script.rules.dimmer] - Dimmerlevel = 6
2019-09-29 13:58:10.217 [DEBUG] [.smarthome.model.script.rules.dimmer] - Timer: null
2019-09-29 13:58:13.219 [DEBUG] [.smarthome.model.script.rules.dimmer] - DECREASE in first timer line...the state of the dimmer is: 6
2019-09-29 13:58:13.220 [DEBUG] [.smarthome.model.script.rules.dimmer] - Dimmer state > 0 (current: 6)...executing decrease
2019-09-29 13:58:13.220 [DEBUG] [.smarthome.model.script.rules.dimmer] - dimLevel:6

Found the solution

At the top of my script I declared the variable “dimLevel”
I used the following declaration:

var int dimLevel = 1
var Timer timer = null

I changed the type to “Number”:

var Number dimLevel = 1
var Timer timer = null

and now it works!
However, I still don’t understand why the rule in the INCREASE part worked with the “Int” variable type and the DECREASE “hangs”.

For completion, the output in the logfile now is:

2019-09-29 14:22:14.743 [DEBUG] [.smarthome.model.script.rules.dimmer] - DECREASE in first timer line...the state of the dimmer is: 9
2019-09-29 14:22:14.744 [DEBUG] [.smarthome.model.script.rules.dimmer] - Dimmer state > 0 (current: 9)...executing decrease
2019-09-29 14:22:14.745 [DEBUG] [.smarthome.model.script.rules.dimmer] - dimLevel:9
2019-09-29 14:22:14.746 [DEBUG] [.smarthome.model.script.rules.dimmer] - new state after decrease: 9
2019-09-29 14:22:17.747 [DEBUG] [.smarthome.model.script.rules.dimmer] - DECREASE in first timer line...the state of the dimmer is: 8
2019-09-29 14:22:17.748 [DEBUG] [.smarthome.model.script.rules.dimmer] - Dimmer state > 0 (current: 8)...executing decrease
2019-09-29 14:22:17.749 [DEBUG] [.smarthome.model.script.rules.dimmer] - dimLevel:8
2019-09-29 14:22:17.750 [DEBUG] [.smarthome.model.script.rules.dimmer] - new state after decrease: 8
2019-09-29 14:22:20.752 [DEBUG] [.smarthome.model.script.rules.dimmer] - DECREASE in first timer line...the state of the dimmer is: 7
2019-09-29 14:22:20.753 [DEBUG] [.smarthome.model.script.rules.dimmer] - Dimmer state > 0 (current: 7)...executing decrease
2019-09-29 14:22:20.754 [DEBUG] [.smarthome.model.script.rules.dimmer] - dimLevel:7
2019-09-29 14:22:20.763 [DEBUG] [.smarthome.model.script.rules.dimmer] - new state after decrease: 6
2019-09-29 14:22:23.764 [DEBUG] [.smarthome.model.script.rules.dimmer] - DECREASE in first timer line...the state of the dimmer is: 6
2019-09-29 14:22:23.766 [DEBUG] [.smarthome.model.script.rules.dimmer] - Dimmer state > 0 (current: 6)...executing decrease
2019-09-29 14:22:23.766 [DEBUG] [.smarthome.model.script.rules.dimmer] - dimLevel:6
2019-09-29 14:22:23.767 [DEBUG] [.smarthome.model.script.rules.dimmer] - new state after decrease: 6
2019-09-29 14:22:26.769 [DEBUG] [.smarthome.model.script.rules.dimmer] - DECREASE in first timer line...the state of the dimmer is: 5
2019-09-29 14:22:26.770 [DEBUG] [.smarthome.model.script.rules.dimmer] - Dimmer state > 0 (current: 5)...executing decrease
2019-09-29 14:22:26.770 [DEBUG] [.smarthome.model.script.rules.dimmer] - dimLevel:5
2019-09-29 14:22:26.772 [DEBUG] [.smarthome.model.script.rules.dimmer] - new state after decrease: 5
2019-09-29 14:22:29.773 [DEBUG] [.smarthome.model.script.rules.dimmer] - DECREASE in first timer line...the state of the dimmer is: 4
2019-09-29 14:22:29.774 [DEBUG] [.smarthome.model.script.rules.dimmer] - Dimmer state > 0 (current: 4)...executing decrease
2019-09-29 14:22:29.775 [DEBUG] [.smarthome.model.script.rules.dimmer] - dimLevel:4
2019-09-29 14:22:29.776 [DEBUG] [.smarthome.model.script.rules.dimmer] - new state after decrease: 4
2019-09-29 14:22:32.778 [DEBUG] [.smarthome.model.script.rules.dimmer] - DECREASE in first timer line...the state of the dimmer is: 3
2019-09-29 14:22:32.779 [DEBUG] [.smarthome.model.script.rules.dimmer] - Dimmer state > 0 (current: 3)...executing decrease
2019-09-29 14:22:32.780 [DEBUG] [.smarthome.model.script.rules.dimmer] - dimLevel:3
2019-09-29 14:22:32.781 [DEBUG] [.smarthome.model.script.rules.dimmer] - new state after decrease: 3
2019-09-29 14:22:35.783 [DEBUG] [.smarthome.model.script.rules.dimmer] - DECREASE in first timer line...the state of the dimmer is: 2
2019-09-29 14:22:35.784 [DEBUG] [.smarthome.model.script.rules.dimmer] - Dimmer state > 0 (current: 2)...executing decrease
2019-09-29 14:22:35.784 [DEBUG] [.smarthome.model.script.rules.dimmer] - dimLevel:2
2019-09-29 14:22:35.785 [DEBUG] [.smarthome.model.script.rules.dimmer] - new state after decrease: 2
2019-09-29 14:22:38.788 [DEBUG] [.smarthome.model.script.rules.dimmer] - DECREASE in first timer line...the state of the dimmer is: 1
2019-09-29 14:22:38.789 [DEBUG] [.smarthome.model.script.rules.dimmer] - Dimmer state > 0 (current: 1)...executing decrease
2019-09-29 14:22:38.789 [DEBUG] [.smarthome.model.script.rules.dimmer] - dimLevel:1
2019-09-29 14:22:38.796 [DEBUG] [.smarthome.model.script.rules.dimmer] - new state after decrease: 1
2019-09-29 14:22:41.797 [DEBUG] [.smarthome.model.script.rules.dimmer] - DECREASE in first timer line...the state of the dimmer is: 0

@vzorglub thank you for looking into this with me!
/Jasper

Cool,
Try to avoid the use of primitives in DSL
The type Number is flexible enough for most purposes.
I only use int for timers

Thanks @vzorglub
But it seems inconsistent that the + operator works and the - operator causes a “hang” in the rule…

I modified the rule now to use the sunset START trigger to start the rule. I’ll let you know tomorrow how that went.

All seem to work, there is a hickup in the script, but that should be solved easily.

Thanks everyone!

How about this?

var Timer tDim = null                                                                    // timer for sunset/sunrise

rule "sunset sunrise"
when
    Channel 'astro:sun:home:set#event'  triggered START or                               // sunset
    Channel 'astro:sun:home:rise#event' triggered START                                  // sunrise
then
    logDebug("dimmer","Rule sunset sunrise triggered")
    if(tDim === null)                                                                    // only when there is no running timer
        logDebug("dimmer","timer was null")
        tDim = createTimer(now.plusMillis(100) [|                                        // start timer fast
            logDebug("dimmer","dimmer timer executed")
            var Number nDim = 0                                                          // helper var
            if(now.getHourOfDay > 11 && (OU_shed_dimmer.state as Number) < 100) {        // it's after noon (so sunset triggered the rule) and dimmer is not 100% 
                logDebug("dimmer","dimm up from {}%",OU_shed_dimmer.state)
                OU_shed_dimmer.sendCommand((OU_shed_dimmer.state as Number) + 1)         // dim up
                nDim = 1                                                                 // set dim time to 1 Second
            } else if(now.getHourOfDay < 12 && (OU_shed_dimmer.state as Number) > 0) {   // it's before noon (so sunrise triggered the rule) and dimmer is not 0% 
                logDebug("dimmer","dimm down from {}%",OU_shed_dimmer.state)
                OU_shed_dimmer.sendCommand((OU_shed_dimmer.state as Number) - 1)         // dim down
                nDim = 3                                                                 // set dim time to 3 Seconds
            }
            if(nDim > 0)                                                                 // check of nDim was set
                logDebug("dimmer","reschedule timer with {} Second(s)",nDim)
                tDim.reschedule(now.plusSeconds(nDim))                                   // nDim was set, so reschedule timer
            else                                                                         // nDim wasn't set
                logDebug("dimmer","delete timer.")
                tDim = null                                                              // so delete timer
        ])
end

Thank you Udo!
Ill have a look at it tomorrow.
I need to get use to the language/ syntax of openhab. Learning every day!

Hi @Udo_Hartmann

The now.gethour does not exist (anymore). The correct code now is:

now.getHourOfDay()

For the rest, it’s a smart script and running here :wink:

Thanks!

Yes, you’re perfectly right. I wonder why I wrote the wrong method, because I never used getHour but only getHourOfDay…

Anyway, I changed the code above for reference…

1 Like

@Udo_Hartmann can you also elaborate a bit more on the “timer” in general?

I’m writing a rule for several scenes…like TV, MOVIE, GOOD NIGHT.
so I’m basically switching a button with mappings.

What I want is that e.g. if TV is clicked, the table light is dimmed, the main light to OFF, tv lights on etc etc.
But, I’m really struggling with the timer. Cause I want “pause” between the switching and dimming and so on.
To test how the timer behaves, I wrote a little test script, with ON / OFF of a light with some seconds in between. However, I don’t get how this is executed:

rule "scene selector"
when
    Item SceneSelect received command 
then
    logDebug("rules.scenes","DEBUG: Item SceneSelect Received command: {}",receivedCommand)
    
    if(receivedCommand == 0){
        logDebug("rules.scenes","Executing Command '0' lines")
        var Timer timer = null
        timer = createTimer(now.plusSeconds(1),[| 
            GF_Living_mainLight_Switch.sendCommand(ON)
            logDebug("rules.scenes","Command ON send to main light, now waiting 10 seconds")
            timer.reschedule(now.plusSeconds(10))
            GF_Living_mainLight_Switch.sendCommand(OFF)
            logDebug("rules.scenes","Command OFF sent, now waiting 5 seconds")
            timer.reschedule(now.plusSeconds(5))
            logDebug("rules.scenes","waited two seconds, now destroy the timer")
            timer = null
            logDebug("rules.scenes","Timer set back to NULL")
        ])
    }
logDebug("rules.scenes","DEBUG END")
end

which gives me the log file:

2019-10-05 21:59:57.788 [DEBUG] [.smarthome.model.script.rules.scenes] - DEBUG: Item SceneSelect Received command: 0
2019-10-05 21:59:57.790 [DEBUG] [.smarthome.model.script.rules.scenes] - Executing Command '0' lines
2019-10-05 21:59:57.799 [DEBUG] [.smarthome.model.script.rules.scenes] - DEBUG END
2019-10-05 21:59:58.793 [DEBUG] [.smarthome.model.script.rules.scenes] - Command ON send to main light, now waiting 10 seconds
2019-10-05 21:59:58.796 [DEBUG] [.smarthome.model.script.rules.scenes] - Command OFF sent, now waiting 5 seconds
2019-10-05 21:59:58.798 [DEBUG] [.smarthome.model.script.rules.scenes] - waited two seconds, now destroy the timer
2019-10-05 21:59:58.803 [DEBUG] [.smarthome.model.script.rules.scenes] - Timer set back to NULL
2019-10-05 22:00:03.799 [DEBUG] [.smarthome.model.script.rules.scenes] - Command ON send to main light, now waiting 10 seconds

I would expect that after the “sendCommand(ON)” the timer will reset with 2 seconds…and continues with the next statement, until all statements in the IF statement are done. However, the behavior is totally different. It looks like it goes all the way to the “end” statement and then suddenly goes back to some of the commands…

I’m a bit clueless about the behavior of timers in scripts…

You want to do several steps and pausing between…

// Always setup global vars at top of the file
var Timer tScene = null                                                                                  // Scene Timer
var Number nScene = null                                                                                 // Selected Scene
var Number nSceneStep = 0                                                                                // Current Scene step

rule "scene selector"
when
    Item SceneSelect received command                                                                    // maybe better use changed as trigger
then
    if(tScene !== null) {                                                                                // stop rule if there is a running timer
        logDebug("sceneSelect","Scene selection Timer already running!")
        return; 
    }
    logDebug("sceneSelect","SceneSelect Received command: {}",receivedCommand)
    nScene = receivedCommmand                                                                            // save scene
    nSceneStep = 0                                                                                       // reset counter
    tScene = createTimer(now.plusMillis(100), [|                                                         // start scene almost immediately
        nSceneStep = nSceneStep + 1                                                                      // count up
        switch (nScene.intValue) {                                                                       // which scene?
            case 0: {                                                                                    // scene 0
                switch (nSceneStep.intValue) {                                                           // which step?
                    case 1: {                                                                            // first step
                        GF_Living_mainLight_Switch.sendCommand(ON)
                        logDebug("sceneSelect","Command ON sent to main light, now waiting 10 seconds")
                        tScene.reschedule(now.plusSeconds(10))
                    }
                    case 2: {                                                                            // second step
                        GF_Living_mainLight_Switch.sendCommand(OFF)
                        logDebug("sceneSelect","Command OFF sent, now waiting 5 seconds")
                        tScene.reschedule(now.plusSeconds(5))
                    }
                    case 3: {                                                                            // third step
                        logDebug("sceneSelect","waited five seconds, now destroy the timer")
                        tScene = null
                        logDebug("sceneSelect","Timer set back to NULL")
                    }
                    default: {                                                                           // none of the above...
                        tScene = null
                    }
                }
            }
            case 1: {                                                                                    // scene 1
                // same as in scene 0...
            }
        }
    ])
    logDebug("sceneSelect","DEBUG END")
end

Of course you don’t need the third step, as you do nothing at all (you could delete the timer instantly)

Instead of stopping the rule when there is a running timer, you could also cancel the timer and restart with a new one by changing the block

    if(tScene !== null) {                                                                                // stop rule if there is a running timer
        logDebug("sceneSelect","Scene selection Timer already running!")
		return; 
    }

to

    tScene?.cancel
1 Like

Super @Udo_Hartmann,

I’ll dive into it now and let you know!
Thanks a lot for your support!!

/Jasper

Hi @Udo_Hartmann,

It’s getting better, however, the script (adjusted) now seems to hang at certain points in a scene.

First of all, I had to adjust the condition to:

if(tScene!== null && nSceneStep==0){

Otherwise I always received that the timer already existed and the rule was exited…not sure if I did correct?

Now that the rule is running, it ‘hangs’ again at certain stage.
The rule looks as follow:

var Timer tScene = null
var Number nScene = null
var Number nSceneStep = 0

rule "Scene Selector"

when 
    Item SceneSelect received command 

then 
    if(tScene!== null && nSceneStep==0){                                    //testing if it's the first time..if so cancel the previous timer to run the script
        logDebug ("rules.scenes", "Scene selection Timer already running")
        tScene.cancel
        return;
    }
    logDebug("rules.scenes", "Scene selection received command: {}",receivedCommand)
    nScene = receivedCommand
    nSceneStep = 0
    tScene = createTimer(now.plusMillis(100), [|
        nSceneStep = nSceneStep + 1
        logDebug("rules.scenes","nScene set to: {}",nScene.intValue)
        switch(nScene.intValue){
            case 0: {
                logDebug("rules.scenes", "the nSceneStep counter has: {} as value",nSceneStep.intValue)
                switch(nSceneStep.intValue){
                    case 1:{
                        if(GF_Light_TV!=ON){
                            logDebug("rules.scenes","TV light was off, now switching it on")
                            GF_Light_TV.sendCommand(ON)
                        }
                        else{
                            logDebug("rules.scenes","TV light was already on, we proceed directly")
                        }
                    }
                    case 2:{
                        if(GF_Living_mainLight_Switch.state == ON){
                            logDebug("rules.scenes", "Main light was on, now turning it off")
                            GF_Living_mainLight_Switch.sendCommand(OFF)
                            logDebug("rules.scenes","Main light switched off, wait 2 seconds")
                            tScene.reschedule(now.plusSeconds(2))
                        }
                        else{
                            logDebug("rules.scenes","Main light was off, directly to next command")
                        }
                    }
                    case 3: {
                            logDebug("rules.scenes","Main light done, next step, turn on living table or bright it up..")
                            GF_LivingDining_Light.sendCommand(30)
                            tScene.reschedule(now.plusSeconds(2))
                        
                    }
                }
            }
            case 1:{
                logDebug("rules.scenes","Movie scene selected")
            } // scene number 1 selected...do stuff    
            case 2:{
                logDebug("rules.scenes","Good night in progress")
                switch(nSceneStep.intValue){
                    case 1:{
                        GF_Living_mainLight_Switch.sendCommand(ON)
                        logDebug("rules.scenes","Command ON sent to main light living room, 10 seconds waiting now...")
                        tScene.reschedule(now.plusSeconds(2))
                    }
                    case 2:{
                        GF_LivingDining_Light.sendCommand(100)
                        logDebug("rules.scenes","Dining light living room to 100%, 2 seconds before hall light will turn on...")
                        tScene.reschedule(now.plusSeconds(2))
                    }
                    case 3:{
                        GF_Hall_Light.sendCommand(ON)
                        logDebug("rules.scenes","Command ON sent to Hall light, 2 seconds The TV light will shut down...")
                        //tScene.reschedule(now.plusSeconds(2))
                    }
                    case 4:{
                        if(GF_Light_TV.state==ON){
                            logDebug("rules.scenes","TV light was on, now turning it off")
                            GF_Light_TV.sendCommand(OFF)
                        }
                        logDebug("rules.scenes","TV light handled, now waiting 30 seconds for next command")
                        tScene.reschedule(now.plusSeconds(30))
                    }
                    case 5:{
                        GF_Living_mainLight_Switch.sendCommand(OFF) //No need to check for state, since we have put it ON in the first step
                        logDebug("rules.scenes", "Main light turned off")
                        tScene.reschedule(now.plusSeconds(10))
                    }
                    case 6:{
                        logDebug("rules.scenes","Dimming the living diner light to 50%, almost time to leave the room")
                        GF_LivingDining_Light.sendCommand(50)
                        logDebug("rules.scenes", "Setting timer to one minute before turning off the dining light")
                    }
                    case 7:{
                        logDebug("rules.scenes", "Dining light off, we are done in the living room. ")
                        GF_LivingDining_Light.sendCommand(OFF)
                        logDebug("rules.scenes", "Living room should be dark, 1 minute left for locking front door before we switch off hall light")
                        tScene.reschedule(now.plusSeconds(60))
                    }
                    case 8:{
                        logDebug("rules.scenes", "Shutting off halway light...time to go upstairs")
                        GF_Hall_Light.sendCommand(Off)
                        if(GF_Entrace_Light.state == ON){
                            GF_Entrace_Light.sendCommand(OFF)
                        }
                        tScene = null
                    }
                    default:{
                        tScene = null
                    }
                }
            }
            default: {
                tScene = null
                tScene.cancel
            }
        }
    ])
    logDebug("rules.scenes", "LOG DEBUG Scene Select has ended")
// use in the last command=> tScene = null !!
                                
end

When I select the “Good Night” button, which is the value of 2 of sceneSelect, the script stops , no more log lines are produces and it seems to be stuck?

The loglines producesd by the script:

2019-10-06 18:55:03.915 [DEBUG] [.smarthome.model.script.rules.scenes] - nScene set to: 2
2019-10-06 18:55:03.917 [DEBUG] [.smarthome.model.script.rules.scenes] - Good night in progress
2019-10-06 18:55:03.918 [DEBUG] [.smarthome.model.script.rules.scenes] - Command ON sent to main light living room, 10 seconds waiting now...
2019-10-06 18:55:05.921 [DEBUG] [.smarthome.model.script.rules.scenes] - nScene set to: 2
2019-10-06 18:55:05.922 [DEBUG] [.smarthome.model.script.rules.scenes] - Good night in progress
2019-10-06 18:55:05.923 [DEBUG] [.smarthome.model.script.rules.scenes] - Dining light living room to 100%, 2 seconds before hall light will turn on...
2019-10-06 18:55:07.926 [DEBUG] [.smarthome.model.script.rules.scenes] - nScene set to: 2
2019-10-06 18:55:07.928 [DEBUG] [.smarthome.model.script.rules.scenes] - Good night in progress
2019-10-06 18:55:07.929 [DEBUG] [.smarthome.model.script.rules.scenes] - Command ON sent to Hall light, 2 seconds The TV light will shut down...

that’s it…nothing happens anymore…

I’m pretty sure I’m again doing something wrong with the timer object, but can’t figure it out yet…

/Jasper

No, it’s not ok to change the line.

If this:

   if(tScene !== null) {                                                                                // stop rule if there is a running timer
        logDebug("sceneSelect","Scene selection Timer already running!")
        return; 
    }

is “always” executed, then the timer is already started. Do not mix up the lines. Either

   if(tScene !== null) {                                                                                // stop rule if there is a running timer
        logDebug("sceneSelect","Scene selection Timer already running!")
        return; 
    }

OR

tScene?.cancel

not the latter within the former!

Please restart openHAB to ensure tScene is null.

Please also don’t do this:

logDebug ("rules.scenes", "Scene selection Timer already running")

but only

logDebug ("scenes", "Scene selection Timer already running")

The first String is the Logger Name. As all log lines come from rules, it does not make any sense to add “rules.” to the name. Please be aware that all the logger names are completed with org.openhab.core.model.script. (or org.eclipse.smarthome.model.script. for versions between ~OH2.1 and OH2.5-M1) anyway.

if(GF_Light_TV!=ON){

If GF_Light_TV is an Item, this is wrong. Instead you have to use

if(GF_Light_TV.state != ON){

After this, there is notScene.reschedule(), this command is not optional, as it restarts the timer (and therefor jumps to the next step). If you want to proceed directly, just use a short reschedule (e.g. 50 mSec)

Same is for the final command

tScene = null

which is also not optional (so always add a default: tScene = null) if using the switch command.

Maybe a more straight forward solution (especially in question of rescheduling):

var Timer tScene = null
var Number nScene = null
var Number nSceneStep = 0

rule "Scene Selector"
when 
    Item SceneSelect received command 
then 
    if(tScene!== null){                                    
        logDebug ("scenes", "Scene selection Timer already running, abort rule!")
        return;
    }
    logDebug("scenes", "Scene selection received command: {}",receivedCommand)
    nScene = receivedCommand
    nSceneStep = 0
    tScene = createTimer(now.plusMillis(100), [|
        var Number nMillis = 0
        var String strMessage
        nSceneStep = nSceneStep + 1
        switch(nScene.intValue){
            case 0: {
                switch(nSceneStep.intValue){
                    case 1:{
                        if(GF_Light_TV.state != ON){
                            GF_Light_TV.sendCommand(ON)
                            strMessage = "TV light was off, now switching it on"
                            nMillis=2000
                        }
                        else{
                            strMessage = "TV light already on, we proceed directly"
                            nMillis=50000
                        }
                    }
                    case 2:{
                        if(GF_Living_mainLight_Switch.state != OFF){
                            GF_Living_mainLight_Switch.sendCommand(OFF)
                            strMessage = "Main light was on, now turning it off"
                            nMillis=2000
                        }
                        else{
                            strMessage = "Main light was off, directly to next command"
                            nMillis=50
                        }
                    }
                    case 3: {
                        strMessage = "turn on living table or bright it up"
                        GF_LivingDining_Light.sendCommand(30)
                    }
                }
            }
            case 1:{
                strMessage = "Movie scene selected")
            } 
            case 2:{
                switch(nSceneStep.intValue){
                    case 1:{
                        GF_Living_mainLight_Switch.sendCommand(ON)
                        strMessage = "Command ON sent to main light living room"
                        nMillis=2000
                    }
                    case 2:{
                        GF_LivingDining_Light.sendCommand(100)
                        strMessage = "Dining light living room to 100%"
                        nMillis=2000
                    }
                    case 3:{
                        GF_Hall_Light.sendCommand(ON)
                        strMessage = "Command ON sent to Hall light"
                        nMillis=2000
                    }
                    case 4:{
                        if(GF_Light_TV.state==ON){
                            GF_Light_TV.sendCommand(OFF)
                        }
                        strMessage = "TV light handled"
                        nMillis=30000
                    }
                    case 5:{
                        GF_Living_mainLight_Switch.sendCommand(OFF) 
                        strMessage = "Main light turned off"
                        nMillis=10000
                    }
                    case 6:{
                        GF_LivingDining_Light.sendCommand(50)
                        strMessage = "Dimming the living diner light to 50%"
                        nMillis=60000
                        }
                    case 7:{
                        GF_LivingDining_Light.sendCommand(OFF)
                        strMessage = "Dining light off"
                        nMillis=60000
                    }
                    case 8:{
                        GF_Hall_Light.sendCommand(Off)
                        if(GF_Entrace_Light.state == ON){
                            GF_Entrace_Light.sendCommand(OFF)
                        }
                        strMessage = "Shutting off halway light"
                    }
                }
            }
        }
        logDebug("scenes","nScene: {} nSceneStep: {} - {}", nScene, nSceneStep, strMessage)
        if(nMillis > 0)
            tScene.reschedule(now.plusMillis(nMillis))
        else
            tScene = null
    ])
end

The last few lines:

        logDebug("scenes","nScene: {} nSceneStep: {} - {}", nScene, nSceneStep, strMessage)
        if(nMillis < 10)
            tScene = null
        else
            tScene.reschedule(now.plusMillis(nMillis))

will be executed at each timer run. The way it’s ensured that tScene is either running or null, it’s not possible to forget setting the reschedule (or null)

1 Like

I will look into it as per your directions! Great!
Is there any source where to find more info on the different objects one can use in rules?

I dont want to ‘bother’ people too much if I can study myself

Well, there is some documentation. The rules DSL is based on XTEND.
xtend is based on JAVA.

By using VisualStudio Code (NOT Visual Studio) with the openHAB plugin, you get autocompletion. You can get almost every possible method in the context.

But there is no source as good as the community… :slight_smile:

1 Like