Post scriptum:
I also tried to simply fade the strip off, as the button in the app does. But I want to stretch the fade duration to 10 instead of 1 seconds. How could one achieve this? My first approach was to define each of the 16 color zones as an individual item, and to fade them out separated, based on this Universaldimmer implementation.
Items:
// TODO: Deduplicate using reflection?
Color Strip_C_CouchBackgroundZone0 "Couchbeleuchtung (Zone 0)" <lightbulb> { channel="lifx:colormzlight:D073D52FE9DB:colorzone0" }
Color Strip_C_CouchBackgroundZone1 "Couchbeleuchtung (Zone 1)" <lightbulb> { channel="lifx:colormzlight:D073D52FE9DB:colorzone1" }
//...
Color Strip_C_CouchBackgroundZone15 "Couchbeleuchtung (Zone 15)" <lightbulb> { channel="lifx:colormzlight:D073D52FE9DB:colorzone15" }
String universaldimmer "Trigges a rule to fade in/out a light"
Rules:
rule "Button_C_FadeBackground"
when
Item Button_C_FadeBackground changed
then
val zones = (0..15).map [int i |
ScriptServiceUtil.getItemRegistry.getItem('Strip_C_CouchBackgroundZone' + i)]
zones.forEach [zone |
universaldimmer.sendCommand('Color,0,10000,50,' + zone.name)]
end
Dimmer rules (widely copied from PeterK’s linked version; but use a mapping to allow for multiple timers):
import java.util.HashMap
import org.eclipse.smarthome.model.script.ScriptServiceUtil
val HashMap<GenericItem, Timer> timers = newHashMap()
// will dimm the item and report back the new brightness
var dimm = [ GenericItem myitem, String mytype, Number mytarget, Number mystep |
var int mybrightness = 0
mybrightness = (if (mytype == "Color")
(myitem.state as HSBType).getBrightness()
else
(myitem.state as DecimalType)).intValue
if (mytarget.intValue > mybrightness) {
mybrightness = mybrightness + mystep.intValue
if (mybrightness > mytarget.intValue) mybrightness = mytarget.intValue
} else {
mybrightness = mybrightness - mystep.intValue
if (mybrightness < mytarget.intValue) mybrightness = mytarget.intValue
}
myitem.sendCommand(mybrightness)
mybrightness
]
rule "Universaldimmer"
when
Item universaldimmer received command // expect e.g. Color,100,120000,12,col_E1_ES_Hue_Go_Farbe
then
val buffer = receivedCommand.toString.split(",")
val mytype = receivedCommand.toString.split(',').get(0) // Color or Dimmer
var int mytarget = Integer::parseInt(buffer.get(1)) // where to go to
val int myfadetime = Integer::parseInt(buffer.get(2)) // time for fading
val int mystep = Integer::parseInt(buffer.get(3)) // step for fading
val myitem_name = receivedCommand.toString.split(',').get(4) // Item to handle
val myitem = ScriptServiceUtil.getItemRegistry.getItem(myitem_name)
var int mytime = 0
logInfo("Universaldimmer", "Going to dim item " + myitem + "to target " + mytarget)
if (timers.containsKey(myitem)) {
logInfo("trying to cancel timer for " + myitem)
timers.get(myitem).cancel()
logInfo("canceled timer for " + myitem)
}
if (mytarget > 100) mytarget = 100
else if (mytarget < 0) mytarget = 0
// fade
var int mybrightness = dimm.apply(myitem, mytype, mytarget, mystep)
mytime = Math::round(myfadetime * mystep /
if (mybrightness > mytarget)
mybrightness + mystep - mytarget
else
mytarget - (mybrightness + mystep))
timers.put(myitem, createTimer(now.plusMillis(mytime)) [|
// Check if finishes
if (mybrightness != mytarget ) {
// if not finished dim again
mybrightness = dimm.apply(myitem, mytype, mytarget, mystep)
// rescheduling
timers.get(myitem).reschedule(now.plusMillis(mytime))
logInfo("dimmed " + myitem + " to " + myitem.state.toString)
} else {
timers.remove(myitem)
myswitch.sendCommand(OFF)
logInfo("Universaldimmer", "Completed dimming of " + myitem + "to target " + mytarget)
}
])
end
Unfortunately, this works very unreliably. I get tons of BasicIndexOutOfBoundsException
s raised in XbaseInterpreter.evaluateArgumentExpressions
and only few color zones are dimmed completely:
Any ideas what could I could have done wrong? What does this error mean? Anyway, I wonder whether the strip indeed does not provide a more specific interface …