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
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
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.
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
OK - I’m trying to understand it
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
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
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
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.