TP-LINK KASA KL130 - How to Query H,S,B Values to Create Dimming Function?

  • openHAB version:2.5.0

Hi
I am trying to set up a dimming function - so that the “TP-LINK KASA KL130” lights dim to “OFF” slowly when the OFF switch is clicked.

Item file is:

Color lamp1_Color { channel=“tplinksmarthome:kl130:7FFE13:color” }
Switch substitute_switch_for_lamp1 //presumably I need to create this?

Sitemap file is:

Switch item=lamp1_Color label= “On / Off” icon=“Light” //normal fully off or fully on switch - presumably I will delete this once dimmer function is set up…

Switch substitute_switch_for_lamp1 //presumably I need to create this new switch to avoid conflicts with normal ON,OFF functionality

Rules file is:

val HSBType myColorNow = [how to query h,s,b values]
val h = [parse myColorNow]
val s = [parse myColorNow]
val b = [parse myColorNow]
val step=10

rule "dimming rule"
when
	Item substitute_switch_for_lamp1 received command OFF

then
	while (b >= 0)
	{
		lamp1_Color.sendCommand(h,s,b)
		Thread::sleep(500)
		if(b>step)
		{
			b=b-step
		}
		else
		{
		b=0
		}		
	}
	
end

I believe I need help with:

  1. the items and sitemap - have I correctly thought about the need for a user defined item to avoid conflicts with the KL130 pre-defined ON/OFF functions

  2. the Rules - I have no idea how to query the current H,S,B values of the light - even though they show up in the logs so should be readily available…

  3. I do not have eclipse smarthome installed - do I need it for what I am trying to do? Would prefer to avoid…

Many thanks!

In openHAB, every item carries a state
Your color item lamp1_Color will report it’s ‘state’ in HSB
see here for using the state of an item in rules

Appreciate it.
I now have the following code which appears to work. Hope it may be of some use to others.
Nonetheless I am puzzled by the syntax:

rule "dimming rule"

when
	Item substitute_switch_for_lamp1 received command OFF
	
then
	var HSBType myColorNow = lamp1_Color.state as HSBType
	var myColorNowAsArray=myColorNow.toString.split(",")
	var h = myColorNowAsArray.get(0)
	var s = myColorNowAsArray.get(1)
	var b = myColorNowAsArray.get(2)
	var step=1
	
	//var hD = Float::parseFloat(h)
	//var sP = Float::parseFloat(s)
	var bP = Float::parseFloat(b)
	
	while (bP >= 0)
	
	{
		var newColorType = h+","+s+","+bP
		lamp1_Color.sendCommand(new HSBType(newColorType))
		Thread::sleep(100)
		bP=bP-step			
	}
	
end

Specifically I don’t understand why I had to parse the “b” variable into a float, yet “h” and “s” seem to be just fine staying as they are (presumably Strings?).

Any guidance appreciated.
If the code could be improved, please make suggestions.

Cheers

OK, great job Mark. I’m pretty sure the color state is returned as a string. Not sure why it has to be parsed as a float.
Your rule looks good and the only thing people will bark at you for using thread sleep which is generally not a good idea but your sleep is so short I don’t believe it will hurt. 100 ms is safe

As you want to do math with it, it can’t stay a string :wink:

1 Like

Thank you.

What would be a good alternative to the thread::sleep command?

I considered calling an item such as:

"Switch lamp_timer {expire="0.5s, command=OFF"}

or similar, but I am sure there are better solutions.

Cheers

thanks. So it is the

while (bP >= 0)
and
bP=bP-step

Causing the trouble?
…Will know for next time. Appreciate it.

no Mark, that would be my first choice to replace the sleeps
I was going to suggest the expire binding. The resolution isn’t perfect (time wise) for short duration periods. some times my 3 second expire timer seems closer to 4 seconds but you can adjust it

Well, it’s no trouble at all but a necessary step for math to parse string to float (or int).
Even when doing math in good old Basic :slight_smile: you have to use val(string).

In question of Thread::sleep(): As your rule does a single Thread::sleep(100), there is absolutely no reason to change this.

But think about another rule, let’s say we have 10 lights, every light shall dim up from 0 to 100 in 200 seconds, and it shall be light by light.
If doing it with a Thread::sleep(), we will end up with something like

for each light {
    while(brightnss < 100) {
        brightness += 1
        light.sendCommand(brightness)
        Thread::sleep(2000)
    }
}

(just symbolic code, won’t work!)

Now that is: The rule is started, then iterates through the lights and does a dim up in 1% steps. But that is 10 times 100 times 2 sec runtime for this rule (plus execution time for sendCommand…). Thread::sleep() will exactly do that: let the thread sleep. The rule will block one thread completely for 2000 Seconds!

Now the timer:

var Timer tTimer = null
var brighness = 0
var light = 0

brightnes = 0
light = 0
tTimer = createTimer(now, [|
    brightness += 1
    if(brightness > 100) {
        light += 1
        brightness = 1
    }
    if(light < 10) {
        light.sendCommand(brightness)
        tTimer.reschedule(now.plusMillis(2000))
    } else {
        tTimer = null
    }
])

(this code won’t work either :wink: )
When using a timer, the rule will simply schedule the timer, the timer will step through the lights and the brightness for each lamp, but will reschedule itself. The commands will need some time for the job, the timer will also use a thread, but instead of sleeping, the timer is rescheduled and no thread is blocked, instead the timer code will be executed 2000 times. :slight_smile:

1 Like