TRADFRI binding problem dimming inside a rule

Hi everybody,

I’m trying to implement a light alarm clock with my tradfri LED-Bulbs by dimming the lights from 1% to X%. I already implement the rules for this but now get some strange behaviour for the brightness dimmer.
When I set an value by sendCommand it always update the item twice incrementing by one. Here an example from the events.log:

2018-05-02 00:05:04.962 [ome.event.ItemCommandEvent] - Item 'brightSchlafzimmer' received command 2
2018-05-02 00:05:04.971 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 0 to 2
2018-05-02 00:05:04.974 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 2 to 0
2018-05-02 00:05:05.648 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 0 to 2
2018-05-02 00:05:08.030 [ome.event.ItemCommandEvent] - Item 'brightSchlafzimmer' received command 3
2018-05-02 00:05:08.051 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 2 to 3
2018-05-02 00:05:08.075 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 3 to 4
2018-05-02 00:05:14.183 [ome.event.ItemCommandEvent] - Item 'brightSchlafzimmer' received command 5
2018-05-02 00:05:14.197 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 4 to 5
2018-05-02 00:05:14.243 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 5 to 6
2018-05-02 00:05:20.330 [ome.event.ItemCommandEvent] - Item 'brightSchlafzimmer' received command 7
2018-05-02 00:05:20.345 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 6 to 7
2018-05-02 00:05:20.370 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 7 to 8
2018-05-02 00:05:26.491 [ome.event.ItemCommandEvent] - Item 'brightSchlafzimmer' received command 9
2018-05-02 00:05:26.504 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 8 to 9
2018-05-02 00:05:26.644 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 9 to 10
2018-05-02 00:05:32.645 [ome.event.ItemCommandEvent] - Item 'brightSchlafzimmer' received command 11
2018-05-02 00:05:32.654 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 10 to 11
2018-05-02 00:05:32.684 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 11 to 12

Here is the item I’m trying to increment only by one percent every 3 Seconds at the moment:

Dimmer brightSchlafzimmer
    "Schlafzimmer Helligkeit"
    <light>
    (brightTRADFRI)
    {channel="tradfri:0220:gwb8d7af2c9c97:schlafzimmerVorne:brightness,tradfri:0220:gwb8d7af2c9c97:schlafzimmerMitte:brightness,tradfri:0220:gwb8d7af2c9c97:schlafzimmerHinten:brightness"}

Anybody a clue what maybe wrong?

Thanks in advance

DerOetzi

Can you publish the rule, please?

Hallo

sorry hatte ich noch vergessen. Ich möchte es wenn es funktioniert für verschiedene Zimmer ausweiten, weswegen ich die Regel mithilfe der Variable thingName flexibel halten möchte.

import org.eclipse.xtext.xbase.lib.Functions
import java.util.List
import java.lang.Math

val Functions$Function3<String, Number, Number, String> runWecker = [ thingName, maxHell, dauer | 
    var bright = brightTRADFRI.members.findFirst[name.equals("bright" + thingName)]
    var colorTemp = colorTempTRADFRI.members.findFirst[name.equals("colorTemp" + thingName)]

    if ( bright.state == 0) {
        var int dimmer = 2
        var sleep = new DecimalType((dauer * 60000) / (maxHell - 2))
        var sleepTime = Math::round(sleep.floatValue)
        colorTemp.sendCommand(100)
        logInfo("Wecker", "Wecker " + thingName + " aktivieren (Wartezeit: " + sleepTime + "ms)")

        bright.sendCommand(dimmer)
        while (dimmer < maxHell) {
            Thread::sleep(sleepTime)
            var dimmerStatus = (bright.state as DecimalType).intValue           
            if (dimmerStatus == dimmer) {
                dimmer = dimmer + 1
                if (dimmer <= 100) {
                    bright.sendCommand(dimmer)
                }
                logDebug("Wecker", "Wecker " + thingName + ": Dimmer plus 1 gesetzt auf " + dimmer)
            } else if (dimmerStatus == dimmer + 1) { 
                //BUG da das item immer automatisch um 1 erhöht wird gebe Fehlermeldung aus!
                dimmer = dimmerStatus
                logDebug("Wecker", "Wecker " + thingName + ": Dimmer war schon auf " + dimmer)
            } else {
                dimmer = 100
                logInfo("Wecker", "Wecker " + thingName + ": Abbruch durch Tastendruck")
            }
        }

        colorTemp.sendCommand(50)
        logInfo("Wecker", "Wecker " + thingName + ": Beendet")
    } else {
        logInfo("Wecker", "Wecker " + thingName + ": Nicht gestartet da Licht bereits an")
    }

    "Wecker finished"
]

val List<String> tage = newArrayList("Dummy", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag")

rule "GUI Weckzeit"
when
    Item weckerSchlafzimmerZeitStunde received update or
    Item weckerSchlafzimmerZeitMinute received update or
    Item weckerSchlafzimmerZeitDauer received update
then
    var String thingName = triggeringItem.name.substring(6, triggeringItem.name.indexOf("Zeit"))    
    var int stunde = (CONFIG.members.findFirst[name.equals("wecker" + thingName + "ZeitStunde")].state as DecimalType).intValue
    var int minute = (CONFIG.members.findFirst[name.equals("wecker" + thingName + "ZeitMinute")].state as DecimalType).intValue
    var int dauer = (CONFIG.members.findFirst[name.equals("wecker" + thingName + "ZeitDauer")].state as DecimalType).intValue

    var message = String::format("%02d:%02d Uhr (-%02d min)", stunde, minute, dauer)

    postUpdate("wecker" + thingName + "ZeitMessage", message)
end

rule "Wecker"
when
    Time cron "0 0/1 * * * ?" 
then
    var String thingName = "Schlafzimmer"

    if (CONFIG.members.findFirst[name.equals("wecker" + thingName + "Hauptschalter")].state != ON || ANWESENHEITEN.state == 0) {
        return
    }

    var weckerStunde = (CONFIG.members.findFirst[name.equals("wecker" + thingName + "ZeitStunde")].state as DecimalType).intValue
    var weckerMinute = (CONFIG.members.findFirst[name.equals("wecker" + thingName + "ZeitMinute")].state as DecimalType).intValue
    var weckerDauer = (CONFIG.members.findFirst[name.equals("wecker" + thingName + "ZeitDauer")].state as DecimalType).intValue

    weckerMinute = weckerMinute - weckerDauer
    if (weckerMinute < 0) {
        weckerStunde = weckerStunde - 1
        weckerMinute = 60 + weckerMinute
        if (weckerStunde < 0) {
            weckerStunde = 23
        }
    }

    var wochentag = (CONFIG.members.findFirst[name.equals("wecker" + thingName + tage.get(now.getDayOfWeek()))])

    if (wochentag.state == ON && weckerStunde == now.getHourOfDay() && weckerMinute == now.getMinuteOfHour()) {
        var maxHell = (CONFIG.members.findFirst[name.equals("wecker" + thingName + "MaxHelligkeit")].state as DecimalType).intValue
        runWecker.apply(thingName, maxHell, weckerDauer)
    }

end

Hello, could you translate the beginning to English please

Hi,

sorry again here in englisch. These are the two rule I use. The first rule is just to update the gui and the second is the one for the alarmclock-function. Because I want to reuse the rules for different rooms later I introduced the variable thingName at the moment hardcoded for Schlafzimmer = bedroom.

Within the log what I analysed so far it seems not to be a problem with the rule executed twice, because it is always a sequence like this

//Pause sleepTime
brightSchlafzimmer received command 2
brightSchlafzimmer changed from 0 to 2
brightSchlafzimmer changed from 2 to 3
Wecker Schlafzimmer: Dimmer plus 1 gesetzt auf 2
//Pause sleepTime
Wecker Schlafzimmer: Dimmer war schon auf 3
//Pause sleepTime
...

I think you have timing issues
The rule will loop one and execute the first if condotion and in the next loop execute the second if condition

Try swapping the first two lines

            var dimmerStatus = (bright.state as DecimalType).intValue
            logInfo("Wecker", "dimmerStatus Variable: " + dimmerStatus.toString)
            Thread::sleep(sleepTime)

Hi,

I think this suggestion is against my logic I wan’t to implement:

In words what I wan’t to do:

1. Set new value (sendCommand)
2. Wait vor X Seconds (Thread::sleep)
3. Check whether the dimmer has been changed by user while waiting (dimmerStatus = ...)
3.2. If no start loop again at 1 (dimmer++)
3.1. If yes abort loop (dimmer=100)

If I change to your suggestion I would check for user interaction only in the very small timebox between sendCommand and evaluation of the dimmerStatus

I although don’t see a timing problem at my code, because between “sendCommand” (step1) and checking “var dimmerStatus = (bright.state as DecimalType).intValue” (step3) there are several seconds (3-20 seconds) (step2).

And if you look at the log of my first post you see that there is only one received command every 3 seconds but two changes of the value resulting by the sendCommand. I don’t think this is a problem in my rule

//for example

2018-05-02 00:05:08.030 [ome.event.ItemCommandEvent] - Item 'brightSchlafzimmer' received command 3
2018-05-02 00:05:08.051 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 2 to 3
2018-05-02 00:05:08.075 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 3 to 4

After this it waits 3 seconds and then get the “correct” value 4 for dimmerStatus which should be 3 (= expected value for received command 3)

Apologies, I misread your code. I get what you want to do.
It looks like that the binding is not accepting steps of 1% and automatically increases the value to the next integer 3 to 4, 5 to 6 …
Your rule works because when it does that you have an interval of 6 seconds instead of 3
Now the question is, why does the binding do that, or why does the gateway only accepts brightness in steps of 2?

No Problem.

The second else if path I just added for this BUG-case

Yes maybe it only can handle 2,4,6,8,…, will check this today in the evening by changing step-width to 2.

Will come back with the results of the test

I was going to suggest that. There will be no different to the eye. 50 steps of increasing brightness will seem just as smooth as 100, I think.
However I think there is still an issue and having your rule working in steps of 2 is only a workaround.

I did a quickcheck right know by doing an Setpoint inside my sitemap with step=2

it even makes thing worse here a part of the logs:

2018-05-02 15:31:19.762 [ome.event.ItemCommandEvent] - Item 'brightSchlafzimmer' received command 11
2018-05-02 15:31:19.770 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 13 to 11
2018-05-02 15:31:19.894 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 11 to 13
2018-05-02 15:31:20.259 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 13 to 15
2018-05-02 15:31:20.498 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 15 to 12
2018-05-02 15:31:20.655 [ome.event.ItemCommandEvent] - Item 'brightSchlafzimmer' received command 13
2018-05-02 15:31:20.666 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 12 to 13
2018-05-02 15:31:21.243 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 13 to 12
2018-05-02 15:31:22.253 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 12 to 13
2018-05-02 15:31:22.436 [ome.event.ItemCommandEvent] - Item 'brightSchlafzimmer' received command 11
2018-05-02 15:31:22.464 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 13 to 11
2018-05-02 15:31:22.467 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 11 to 12
2018-05-02 15:31:23.456 [ome.event.ItemCommandEvent] - Item 'brightSchlafzimmer' received command 10
2018-05-02 15:31:23.488 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 12 to 10
2018-05-02 15:31:23.726 [ome.event.ItemCommandEvent] - Item 'brightSchlafzimmer' received command 8
2018-05-02 15:31:23.734 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 10 to 8
2018-05-02 15:31:24.258 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 8 to 10
2018-05-02 15:31:25.251 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 10 to 8
2018-05-02 15:31:25.466 [ome.event.ItemCommandEvent] - Item 'brightSchlafzimmer' received command 6
2018-05-02 15:31:25.482 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 8 to 6
2018-05-02 15:31:26.322 [ome.event.ItemCommandEvent] - Item 'brightSchlafzimmer' received command 4
2018-05-02 15:31:26.342 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 6 to 4
2018-05-02 15:31:26.951 [ome.event.ItemCommandEvent] - Item 'brightSchlafzimmer' received command 2
2018-05-02 15:31:26.959 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 4 to 2
2018-05-02 15:31:27.261 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 2 to 4
2018-05-02 15:31:27.485 [ome.event.ItemCommandEvent] - Item 'brightSchlafzimmer' received command 2
2018-05-02 15:31:27.493 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 4 to 2
2018-05-02 15:31:28.381 [ome.event.ItemCommandEvent] - Item 'brightSchlafzimmer' received command 0
2018-05-02 15:31:28.397 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 2 to 0
2018-05-02 15:31:28.414 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 0 to 2
2018-05-02 15:31:28.442 [vent.ItemStateChangedEvent] - brightSchlafzimmer changed from 2 to 0

Let’s add some logging to find out what’s going on…

        while (dimmer < maxHell) {
            Thread::sleep(sleepTime)
            var dimmerStatus = (bright.state as DecimalType).intValue
            logInfo("DEBUG", "dimmerStatus: " + dimmerStatus.toString)
            if (dimmerStatus == dimmer) {
                logInfo("DEBUG", "dimmer: " + dimmer.toString)
                dimmer = dimmer + 1
                if (dimmer <= 100) {
                    bright.sendCommand(dimmer)
                }
                logDebug("Wecker", "Wecker " + thingName + ": Dimmer plus 1 gesetzt auf " + dimmer)
            } else if (dimmerStatus == dimmer + 1) { 
                //BUG da das item immer automatisch um 1 erhöht wird gebe Fehlermeldung aus!
                dimmer = dimmerStatus
                logInfo("DEBUG", "dimmerStatus: " + dimmerStatus.toString)
                logDebug("Wecker", "Wecker " + thingName + ": Dimmer war schon auf " + dimmer)
            } else {
                dimmer = 100
                logInfo("Wecker", "Wecker " + thingName + ": Abbruch durch Tastendruck")
            }
        }

As you can see above I can reproduce the problem outside rules by using a Setpoint inside a sitemap. So I think more debugging inside the rule does not give any further hint.

To you know which package I have to set to DEBUG level to debug the tradfri binding itself?

I’m a little concerned by these Rules. There are only five execution threads available for running Rules. When you run out, no Rules will run until the five you currently have running exit. This is why any rule that takes longer than 500 msec can cause problems.

In this case I see a lambda which implies that it can be called by more than one Rule and I see, assuming that I’m interpreting this correctly, that the lambda may take many minutes to complete. Even if it only takes multiple seconds it would be a problem.

I also see there is no way to cancel the dimming up or down, but I’m going to ignore this for now.

So, without a major restructuring of what you are doing, there is a little trick you can use to spin your while()dimmer < maxHell) off into a separate thread by moving it to a Timer.

var Timer dimmingLoop = null

val Functions$Function4<String, Number, Number, String, Timer> runWecker = [ thingName, maxHell, dauer, timer | 
    ...

    bright.sendCommand(dimmer)
    timer = createTimer(now.plusMillis(sleepTime), [|
        var dimmerStatus = = (bright.state as DecimalType).intValue
        ...

        if(dimmer < maxHell) timer.reschedule(now.plusMillis(sleepTime))
    ]
]

If you ever want to cancel the dimming from another Rule (e.g. cancel the dimming before trying calling your lambda again) just call

dimmingLoop?.cancel

@rlkoshak thanks for this hint, I will refactor this, for better performance.

But this does not help me with my initial problem.

I never said it would.

Which means the problem is not with the Rules code but with the binding.

It isn’t better performance I’m worried about. It is having your Rules come to a halt at times because you run out of Rules.

That is in my opinion better Performance as well, so thanks again for the useful hint.

Hi @DerOetzi,

Dit you maybe have found a solution for the behaviour for using Brightness control with a Rule ?
Have got the same issue when sending a brightness level. Its a ‘bit’ jumpy.

Thanks,
Olaf

Unfortunately I had some other issues inside my configuration with higher priority. But I will have a new try in 2-3 weeks. Can you give me some more details of your configuration.

Do you have more then one bulb in a group? If yes to you have a master Group:Dimmer or do you combine them by adding several channels to a Dimmer item.

Thanks for information and I’ll keep you updated here, when I start my new try.

Hi,

Have tried both configs, so a single light and within a master group.
response is the same.

With help in this community, I got a working rule. My original one put me in a infinity loop.
But when sending a dimmer value, I get the following response.
This moment its in a group as you can see below.

2018-06-21 20:52:16.729 [vent.ItemStateChangedEvent] - ZWaveNode4ZME_KFOBSSecure4ButtonKeyChainController_SceneNumber changed from 1.0 to 1.2

2018-06-21 20:52:16.770 [ome.event.ItemCommandEvent] - Item 'Brightness_ALL_Hal_BG' received command 20
2018-06-21 20:52:16.794 [vent.ItemStateChangedEvent] - Brightness_ALL_Hal_BG changed from 2 to 20
2018-06-21 20:52:16.844 [vent.ItemStateChangedEvent] - Brightness_Hal_BG_1 changed from 2 to 21
2018-06-21 20:52:16.863 [vent.ItemStateChangedEvent] - Brightness_ALL_Hal_BG changed from 20 to 21
2018-06-21 20:52:16.868 [vent.ItemStateChangedEvent] - Brightness_Hal_BG_2 changed from 2 to 21

Have played with the increase value. Its now 18 per rule cycle. When I go from 0 to 100% in one go, it gets a bit jumpy from 50%

2018-06-21 20:56:49.767 [ome.event.ItemCommandEvent] - Item 'Brightness_ALL_Hal_BG' received command 76
2018-06-21 20:56:49.784 [vent.ItemStateChangedEvent] - Brightness_ALL_Hal_BG changed from 58 to 76
2018-06-21 20:56:49.805 [vent.ItemStateChangedEvent] - Brightness_Hal_BG_1 changed from 58 to 76
2018-06-21 20:56:49.819 [vent.ItemStateChangedEvent] - Brightness_Hal_BG_2 changed from 58 to 76
2018-06-21 20:56:49.877 [vent.ItemStateChangedEvent] - Brightness_Hal_BG_1 changed from 76 to 58
2018-06-21 20:56:49.880 [vent.ItemStateChangedEvent] - Brightness_ALL_Hal_BG changed from 76 to 58
2018-06-21 20:56:49.901 [vent.ItemStateChangedEvent] - Brightness_Hal_BG_2 changed from 76 to 58

It gets worse when doing small steps.
I think it has to do something with the request of the brightness status. But I’m a bit new to doing this with rules.

Below my rule, only the dimming part up and down.


var Timer dimmingTimer1 = null
var Timer dimmingTimer2 = null
var Timer dimmingTimer3 = null
var Timer dimmingTimer4 = null

rule "Schakelaar begane grond dimmer"
when
    Item ZWaveNode4ZME_KFOBSSecure4ButtonKeyChainController_SceneNumber changed
then

    // switch is being pressed
    if(ZWaveNode4ZME_KFOBSSecure4ButtonKeyChainController_SceneNumber.state == 1.2) {
        if(dimmingTimer1 === null){
            dimmingTimer1 = createTimer(now.plusSeconds(0), [ |
                var brightness = Brightness_ALL_Hal_BG.state as Number + 18
                if(brightness > 99) brightness = 100
                Brightness_ALL_Hal_BG.sendCommand(brightness)
                if(brightness == 100) {
                    dimmingTimer1 = null
                }
                else {
                    dimmingTimer1.reschedule(now.plusMillis(600)
               )}
            ])
        }
    }
    // Switch is not being pressed
    else if(ZWaveNode4ZME_KFOBSSecure4ButtonKeyChainController_SceneNumber.state == 1.1) {
        dimmingTimer1?.cancel
        dimmingTimer1 = null
    }

    // switch is being pressed
    if(ZWaveNode4ZME_KFOBSSecure4ButtonKeyChainController_SceneNumber.state == 5.2) {
        if(dimmingTimer2 === null){
            dimmingTimer2 = createTimer(now.plusSeconds(0), [ |
                var brightness = Brightness_ALL_Hal_BG.state as Number - 18
                if(brightness < 2) brightness = 1
                Brightness_ALL_Hal_BG.sendCommand(brightness)
                if(brightness == 1) {
                    dimmingTimer2 = null
                }
                else {
                    dimmingTimer2.reschedule(now.plusMillis(600)
               )}
            ])
        }
    }
    // Switch is not being pressed
    else if(ZWaveNode4ZME_KFOBSSecure4ButtonKeyChainController_SceneNumber.state == 5.1) {
        dimmingTimer2?.cancel
        dimmingTimer2 = null

}

end

Thanks for you help !!