Hi, I’m a happy new user of openhab (coming from FHEM and iobroker) and I’m struggling a bit with my latest rule.
Basically I’m dynamically changing the color of a LED strip based on the current power consumption of my server
and restoring the previous color after a few seconds.
The rule is working, but if it runs concurrently it does not restore the current color of the LED strip correctly.
The second instance of the rule will pick up the wrong current value (set by the first instance).
I tried to use a lock, but it didn’t change anything.
Any help would be much appreciated.
Alex
import java.util.concurrent.locks.ReentrantLock
val ReentrantLock lock = new ReentrantLock()
rule "Power"
when
Item Power changed
then
lock.lock()
try {
logInfo("LED state: ", LED01_Color.state.toString)
var curhsb1 = new HSBType(LED01_Color.state.toString)
var curhsb2 = new HSBType(LED02_Color.state.toString)
var colorvalue = Math::round((120 -((Float::parseFloat(Power.state.toString)-12) *120/24)))
if (colorvalue > 360 ) { colorvalue = 360}
if (colorvalue < 0 ) { colorvalue = 0}
var dyncolor = new HSBType(colorvalue + ",100,100")
sendCommand(LED01_Color, dyncolor)
sendCommand(LED02_Color, dyncolor)
logInfo("LED dyncolor: ", dyncolor.toString)
val double roundedpower = Math::round(100 * (Float::parseFloat(Power.state.toString))) / 100.0
sendCommand(KodiIronsky_NachrichtAnzeigen,"Current power: " + roundedpower)
Thread::sleep(3000)
sendCommand(LED01_Color, curhsb1)
sendCommand(LED02_Color, curhsb2)
} finally{
lock.unlock()
}
end
The power measurements come in every few seconds (sometimes every second, sometimes every 60 seconds or in between), because it’s a cheap energy meter with a 433MHz transmitter and the receiver doesn’t pick up all messages.
But that’s not the issue. There must be a way to have the same rule run concurrently without the instances interfering with each other OR keeping the second instance from running until the first instance finishes.
I think I found an easy way. I’m using a dummy openHAB switch as a semaphore now.
I’m checking at the beginning if it’s ON and do nothing, if it’s OFF I let the rest of the rule execute while setting the switch to ON during run time. Seems to work.
rule "Power"
when
Item Power changed
then
if (PowerRuleRunning.state == ON) {
} else {
postUpdate(PowerRuleRunning, ON)
logInfo("power.rules", "current color: " + LED01_Color.state.toString)
var curhsb1 = new HSBType(LED01_Color.state.toString)
var curhsb2 = new HSBType(LED02_Color.state.toString)
var colorvalue = Math::round((120 - ((Float::parseFloat(Power.state.toString) - 12) * 120 / 24)))
if (colorvalue > 360) {
colorvalue = 360
}
if (colorvalue < 0) {
colorvalue = 0
}
var dyncolor = new HSBType(colorvalue + ",100,100")
sendCommand(LED01_Color, dyncolor)
sendCommand(LED02_Color, dyncolor)
logInfo("power.rules", "dyncolor: " + dyncolor.toString)
val double roundedpower = Math::round(100 * (Float::parseFloat(Power.state.toString))) / 100.0
sendCommand(KodiIronsky_NachrichtAnzeigen, "Current power: " + roundedpower)
Thread::sleep(3000)
sendCommand(LED01_Color, curhsb1)
sendCommand(LED02_Color, curhsb2)
postUpdate(PowerRuleRunning, OFF)
}
end
you would have a rule that doesn’t generated side effects (i.e. doesn’t use global variables, doesn’t send commands it pay updates.
since such rules are of limited use, then you need to decide what behavior you want and use a ReentrantLock to implement it in the way you want.
your two choices of behavior are to ignore events that trigger a rule while it is still running or wait until the rule finished running before processing subsequent events.
in your attention to use the ReentrantLock above you implement the second approach. your second rule does the first, i.e. ignore.
since you are happy with your second version I’m going to guess that the problem with the lock was you really wanted to ignore the subsequent events.
to implement that using the ReentrantLock use
if(lock.isLocked) return;
lock.lock()
try {
...
I’m going from memory on the is locked call. search “ReentrantLock javadoc” to verify.
Many thanks for taking the time to give more insight. Since I’m still interested in a proper, elegant solution, I’ll try it again with the ReentrantLock sooner or later :).