[SOLVED] Dimmer Rule with exec Binding

OK first thing I found in the logs is a wrong loop. “sun rise” is going down to 399 PWM and then it jumps down to 40 - 30 - 20 - 10 - 0 and this several time

2019-01-27 11:08:41.055 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 409'
2019-01-27 11:08:50.071 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 399
2019-01-27 11:08:50.079 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 399'
2019-01-27 11:14:06.002 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 40
2019-01-27 11:14:06.009 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 40'
2019-01-27 11:14:15.027 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 30
2019-01-27 11:14:15.035 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 30'
2019-01-27 11:14:24.051 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 20
2019-01-27 11:14:24.058 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 20'
2019-01-27 11:14:33.077 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 10
2019-01-27 11:14:33.085 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 10'
2019-01-27 11:14:42.106 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 0
2019-01-27 11:14:42.113 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 0'
2019-01-27 11:14:06.002 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 40
2019-01-27 11:14:06.009 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 40'
2019-01-27 11:14:15.027 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 30
2019-01-27 11:14:15.035 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 30'
2019-01-27 11:14:24.051 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 20
2019-01-27 11:14:24.058 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 20'
2019-01-27 11:14:33.077 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 10
2019-01-27 11:14:33.085 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 10'
2019-01-27 11:14:42.106 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 0
2019-01-27 11:14:42.113 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 0'
2019-01-27 11:14:06.002 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 40
2019-01-27 11:14:06.009 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 40'
2019-01-27 11:14:15.027 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 30
2019-01-27 11:14:15.035 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 30'
2019-01-27 11:14:24.051 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 20
2019-01-27 11:14:24.058 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 20'
2019-01-27 11:14:33.077 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 10
2019-01-27 11:14:33.085 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 10'
2019-01-27 11:14:42.106 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 0
2019-01-27 11:14:42.113 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 0'
2019-01-27 11:14:06.002 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 40
2019-01-27 11:14:06.009 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 40'
2019-01-27 11:14:15.027 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 30
2019-01-27 11:14:15.035 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 30'
2019-01-27 11:14:24.051 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 20
2019-01-27 11:14:24.058 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 20'
2019-01-27 11:14:33.077 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 10
2019-01-27 11:14:33.085 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 10'
2019-01-27 11:14:42.106 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 0
2019-01-27 11:14:42.113 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 0'
2019-01-27 11:14:06.002 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 40
2019-01-27 11:14:06.009 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 40'
2019-01-27 11:14:15.027 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 30
2019-01-27 11:14:15.035 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 30'
2019-01-27 11:14:24.051 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 20
2019-01-27 11:14:24.058 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 20'
2019-01-27 11:14:33.077 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 10
2019-01-27 11:14:33.085 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 10'
2019-01-27 11:14:42.106 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 0
2019-01-27 11:14:42.113 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 0'
2019-01-27 11:14:06.002 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 40
2019-01-27 11:14:06.009 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 40'
2019-01-27 11:14:15.027 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 30
2019-01-27 11:14:15.035 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 30'
2019-01-27 11:14:24.051 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 20
2019-01-27 11:14:24.058 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 20'
2019-01-27 11:14:33.077 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 10
2019-01-27 11:14:33.085 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 10'
2019-01-27 11:14:42.106 [INFO ] [ome.model.script.LOOP Command Line: ] - gpio pwm 1 0
2019-01-27 11:14:42.113 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'gpio pwm 1 0'

Furthermore the logs yesterday for the sunset was fine. It started at pwm 0 and increased in 10th steps to 1024.

So rule sunrise -> sunset worked
sunset -> sunrise didn’t work. Needed to restart openhab to trigger it manually and then it worked with some strange errors (log above).

Here are the two rules again (may has some changes)

sunrise:

val int timeoutSecs = 9 // 9 seconds for 15 minutes
var int dimLevel = 100 // Start from 100
var Timer timer = null // Initialise timer to null

rule "Slowly Dim Up"

when

    Item GPIO4 changed to ON

then

    if (timer === null) { // If there is no timer
        logInfo("TIMER", "Starting dimmer loop")
        timer = createTimer(now.plusSeconds(0), [ |   //Starts immediately
            if (dimLevel == 0) { //If we have reached 0
                timer = null // cancel timer
            } else {
                dimLevel = dimLevel -1 // Decrease dimLevel by 1
                val int pwmValue = ((dimLevel * 1024) / 100).intValue // Scale dimLevel from 0-100 to 0-1024
                val commandString = "gpio pwm 1 " + pwmValue // Create command String
                logInfo("LOOP Command Line: ", commandString)
                executeCommandLine(commandString) // Execute command String
                timer.reschedule(now.plusSeconds(timeoutSecs)) // reschedule timer like a loop
            }
        ])
    }
end

Sunset

val int timeoutSecs = 9 // 9 seconds for 15 minutes
var int dimLevel = 0 // Start from 0
var Timer timer = null // Initialise timer to null

rule "Slowly Dim Down"

when

    Item DUMMY changed to ON

then

    if (timer === null) { // If there is no timer
        logInfo("TIMER", "Starting dimmer loop")
        timer = createTimer(now.plusSeconds(0), [ |   //Starts immediately
            if (dimLevel == 100) { //If we have reached 100
                timer = null // cancel timer
            } else {
                dimLevel = dimLevel +1 // Increase dimLevel by 1
                val int pwmValue = ((dimLevel * 1024) / 100).intValue // Scale dimLevel from 0-100 to 0-1024
                val commandString = "gpio pwm 1 " + pwmValue // Create command String
                logInfo("LOOP Command Line: ", commandString)
                executeCommandLine(commandString) // Execute command String
                timer.reschedule(now.plusSeconds(timeoutSecs)) // reschedule timer like a loop
            }
        ])
    }
end

No one an idea?

You seem to have missed the comment about global variables.
You cannot, in the same rules file, create a global variable dimlevel which is both 100 and 0.
I would have expected this to generate errors in openhab.log actually.

You can share the timer and timeoutSecs globals, but you should create them only once.
Personally, I would give timer a more unique name to avoid confusion some other time.

So I should use “dimLevel” and maybe “dimmingLevel”?
Same with timer?

It’s up to you.

Thinking about it a bit more, you’re not going to want both rules to run at the same time. Having a shared global timer should stop that happening, so that’s probably a good thing.
I would give it a different name so that you don’t write another rule later also using ‘timer’ and get unexpected happenings.

Regarding dimlevel - if we make sure the rules only run one at a time, you could actually use the same global variable. Only define it with var once, of course.
But when you define it as a global, it only gets set to its initial vale when the rules file loads. When the rules run, they will alter it.

So before entering your timer loop in each rule, set the dimlevel to whatever is needed, 0 or 100

Quick question, are these two rules in separate files?

Yes, they are.

OK - I’m trying to understand it :wink:
So I don’t need a dimLevel in each rule because the level is set by the rules befor. If I use “Timer” for both timer, both timer will run in the background, right? So I could try this rules:

val int timeoutSecs = 9 // 9 seconds for 15 minutes
var int dimLevel = 100 // Start from 100
var Timer_Up timer = null // Initialise timer to null

rule "Slowly Dim Up"

when

    Item GPIO4 changed to ON

then

    if (timer === null) { // If there is no timer
        logInfo("TIMER", "Starting dimmer loop")
        timer = createTimer(now.plusSeconds(0), [ |   //Starts immediately
            if (dimLevel == 0) { //If we have reached 0
                timer = null // cancel timer
            } else {
                dimLevel = dimLevel -1 // Decrease dimLevel by 1
                val int pwmValue = ((dimLevel * 1024) / 100).intValue // Scale dimLevel from 0-100 to 0-1024
                val commandString = "gpio pwm 1 " + pwmValue // Create command String
                logInfo("LOOP Command Line: ", commandString)
                executeCommandLine(commandString) // Execute command String
                timer.reschedule(now.plusSeconds(timeoutSecs)) // reschedule timer like a loop
            }
        ])
    }
end

val int timeoutSecs = 9 // 9 seconds for 15 minutes
var Timer_Down timer = null // Initialise timer to null

rule "Slowly Dim Down"

when

    Item DUMMY changed to ON

then

    if (timer === null) { // If there is no timer
        logInfo("TIMER", "Starting dimmer loop")
        timer = createTimer(now.plusSeconds(0), [ |   //Starts immediately
            if (dimLevel == 100) { //If we have reached 100
                timer = null // cancel timer
            } else {
                dimLevel = dimLevel +1 // Increase dimLevel by 1
                val int pwmValue = ((dimLevel * 1024) / 100).intValue // Scale dimLevel from 0-100 to 0-1024
                val commandString = "gpio pwm 1 " + pwmValue // Create command String
                logInfo("LOOP Command Line: ", commandString)
                executeCommandLine(commandString) // Execute command String
                timer.reschedule(now.plusSeconds(timeoutSecs)) // reschedule timer like a loop
            }
        ])
    }
end

I’m on a good way? :smiley:

Maybe if I offer a briefing on so called “global variables

If you define a variable with var or val inside a rule, it only exists within that rule and is effectively created each time the rule runs and destroyed when it ends.

If instead you define it outside of any rule, we call it global because it can be shared by any rules in that rules file.
It’s a useful way for one rule to alter something that another rule can read later.
Or for all rules to share some common value, like a timeout.

Good practice is to define any globals at the top of your rules file, before any actual rules.
Pretty obviously, each global has to have a unique name.

If you assign an initial value,
var myGlobal = 22
that value will be given to the variable when the rules file loads.
But if any rules alter the value, it stays altered and dos not revert to that initial value (until next time you boot or edit the rules file).

So if var or val inside a rule only operate in this rule I dont need to change the name.
Wait - lets start again? Whats the different between global variable an the variable who operate only inside of one rule?
Is this global:

val int timeoutSecs = 9 // 9 seconds for 15 minutes
var int dimLevel = 100 // Start from 100
var Timer_Up timer = null // Initialise timer to null

rule "Slowly Dim Up"

and this not:

rule "Slowly Dim Up"

val int timeoutSecs = 9 // 9 seconds for 15 minutes
var int dimLevel = 100 // Start from 100
var Timer_Up timer = null // Initialise timer to null

?

You got it

OK…I get this error now:

Configuration model 'aufgang.rules' has errors, therefore ignoring it: [3,1]: mismatched input 'val' expecting 'when'

Post the whole rules file

rule "Slowly Dim Up"

val int timeoutSecs = 9 // 9 seconds for 15 minutes
var int dimLevel = 100 // Start from 100
var Timer_Up timer = null // Initialise timer to null

when

    Item GPIO4 changed to ON

then

    if (timer === null) { // If there is no timer
        logInfo("TIMER", "Starting dimmer loop")
        timer = createTimer(now.plusSeconds(0), [ |   //Starts immediately
            if (dimLevel == 0) { //If we have reached 0
                timer = null // cancel timer
            } else {
                dimLevel = dimLevel -1 // Decrease dimLevel by 1
                val int pwmValue = ((dimLevel * 1024) / 100).intValue // Scale dimLevel from 0-100 to 0-1024
                val commandString = "gpio pwm 1 " + pwmValue // Create command String
                logInfo("LOOP Command Line: ", commandString)
                executeCommandLine(commandString) // Execute command String
                timer.reschedule(now.plusSeconds(timeoutSecs)) // reschedule timer like a loop
            }
        ])
    }
end
val int timeoutSecs = 9 // 9 seconds for 15 minutes

var Timer_Up timer = null // Initialise timer to null

rule "Slowly Dim Up"
when
    Item GPIO4 changed to ON
then
    var int dimLevel = 100 // Start from 100
    if (timer === null) { // If there is no timer
        logInfo("TIMER", "Starting dimmer loop")
        timer = createTimer(now.plusSeconds(0), [ |   //Starts immediately
            if (dimLevel == 0) { //If we have reached 0
                timer = null // cancel timer
            } else {
                dimLevel = dimLevel -1 // Decrease dimLevel by 1
                val int pwmValue = ((dimLevel * 1024) / 100).intValue // Scale dimLevel from 0-100 to 0-1024
                val commandString = "gpio pwm 1 " + pwmValue // Create command String
                logInfo("LOOP Command Line: ", commandString)
                executeCommandLine(commandString) // Execute command String
                timer.reschedule(now.plusSeconds(timeoutSecs)) // reschedule timer like a loop
            }
        ])
    }
end

hmm Thank you. I’m going to try it.
Do I need to use unique names for the timer in both rules?

Not if they are in different files

I tried it this way and it looks like its working:

rule "Slowly Dim Up"
when
    Item GPIO4 changed to ON
then
    val int timeoutSecs = 9 // 9 seconds for 15 minutes
    var Timer_Up timer = null // Initialise timer to null
    var int dimLevel = 100 // Start from 100
    if (timer === null) { // If there is no timer
...

If you’re not using VSC editor to highlight syntax errors, you gotta keep an eye on your openhab.log to see if a rules file you just uploaded contains errors.

var Timer_Up timer = null
Syntax is var class-of-variable name-of-this-variable = whatever
In this case, timer class is actually Timer as well, case is important.
So that’s two errors, it would be
var Timer Timer_Up = null
or whatever.

Next, this part has become nonsense

rule "Slowly Dim Up"
...
    var Timer_Up timer = null // Initialise timer to null
    var int dimLevel = 100 // Start from 100
    if (timer === null) { // If there is no timer

We know it’s null, because we just set it that way…
It’s really worth reading and following along with the rule, and asking about things that are unclear if needed. You’re not going to get people posting you complete working error-free rules that do exactly what you want, you’ll need to understand enough to fix and modify them.

Having said all that, here is a suggestion. Assuming you never want to have dim-up and dim-down happening at the same time. Put BOTH your rules into one rules file as follows (and delete the spare file)

// Globals
var Timer dimTimer = null // Initialise timer to null
              // shared timer so that only one rule runs at a time 
val int timeoutSecs = 9 // 9 seconds for 15 minutes
              // convenient to control both rules with same setting
var int dimLevel = 0 // don't care what value it is
              // global so that it can be accessed inside timer

rule "Slowly Dim Up"
when
    Item GPIO4 changed to ON
then
    if (dimTimer === null) { // If there is no timer
        logInfo("TIMER", "Starting dimup loop")
        dimLevel = 100    // initial value
        dimTimer = createTimer(now.plusSeconds(0), [ |   //Starts immediately
            if (dimLevel == 0) { //If we have reached 0
                dimTimer = null // cancel timer
            } else {
                dimLevel = dimLevel -1 // Decrease dimLevel by 1
                val int pwmValue = ((dimLevel * 1024) / 100).intValue // Scale dimLevel from 0-100 to 0-1024
                val commandString = "gpio pwm 1 " + pwmValue // Create command String
                logInfo("LOOP Command Line: ", commandString)
                executeCommandLine(commandString) // Execute command String
                dimTimer.reschedule(now.plusSeconds(timeoutSecs)) // reschedule timer like a loop
            }
        ])
    }
end

rule "Slowly Dim Down"
when
    Item GPIO4 changed to OFF
then
    if (dimTimer === null) { // If there is no timer
        logInfo("TIMER", "Starting dim down loop")
        dimLevel = 0   // initialise
        dimTimer = createTimer(now.plusSeconds(0), [ |   //Starts immediately
            if (dimLevel == 100) { //If we have reached 100
                dimTimer = null // cancel timer
            } else {
                dimLevel = dimLevel +1 // Increase dimLevel by 1
                val int pwmValue = ((dimLevel * 1024) / 100).intValue // Scale dimLevel from 0-100 to 0-1024
                val commandString = "gpio pwm 1 " + pwmValue // Create command String
                logInfo("LOOP Command Line: ", commandString)
                executeCommandLine(commandString) // Execute command String
                dimTimer.reschedule(now.plusSeconds(timeoutSecs)) // reschedule timer like a loop
            }
        ])
    }
end

You need to check the rule triggers, and see if that is what you want.