Need help for my shottimer rule

Openhab 2.5.5 on rpi 3b

Hello,

I have a rule that should let a lamp flash after a certain time. After the rule has expired, the state of the lamp should be restored before the rule. Unfortunately this only works the first time, nothing happens the second time. Where is my mistake?

Thanks to the community

Rule:
var Timer tshot = null

var Timer tBlinken

var alterWert

var int loop = 6


rule "Shottimer"

when 

    Channel "shelly:shellybutton1:483fda6f2cea:status#button" triggered SHORT_PRESSED

then 

    if(tshot !== null) tshot.cancel

      alterWert = LEDstripe_EG_KuecheDH.state

      logInfo("Shottimer", "speichern alter Wert")

      tshot = createTimer(now.plusSeconds(5))[|  // Timer initialisieren und sofoert ausführen

        if(tBlinken === null) {

                

                tBlinken = createTimer(now, [  //der erste Durchlauf geschieht sofort

                    loop = loop - 1

                    LEDstripe_EG_KuecheDH.sendCommand(if(loop % 2 == 1) 0 else 100) //abwechselnd ON und OFF

                    logInfo("Shottimer", "Blinken startet")

                    if (loop > 0)

                        tBlinken.reschedule(now.plusSeconds(2)) //jeder weitere Durchlauf wird um 2 Sekunden verzögert

                    else

                        tBlinken = null //zuletzt Timer für nächsten Anruf initialisieren

                        logInfo("Shottimer", "Blinken endet")

                ])

            } 

        LEDstripe_EG_KuecheDH.sendCommand (alterWert)

        logInfo("Shottimer", "senden alter Wert")

    ]

    

    tshot = null

      

end

Log 1 Rule ok:

2021-02-10 18:51:54.425 [vent.ChannelTriggeredEvent] - shelly:shellybutton1:483fda6f2cea:status#button triggered SHORT_PRESSED

2021-02-10 18:51:54.714 [vent.ChannelTriggeredEvent] - shelly:shellybutton1:483fda6f2cea:status#button triggered SHORT_PRESSED

==> /var/log/openhab2/openhab.log <==

**2021-02-10 18:51:56.358** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - speichern alter Wert**

**2021-02-10 18:51:56.358** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - speichern alter Wert**

==> /var/log/openhab2/events.log <==

2021-02-10 18:52:00.354 [vent.ChannelTriggeredEvent] - shelly:shellybutton1:483fda6f2cea:status#button triggered SHORT_PRESSED

==> /var/log/openhab2/openhab.log <==

**2021-02-10 18:52:00.369** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - speichern alter Wert**

==> /var/log/openhab2/events.log <==

2021-02-10 18:52:00.497 [vent.ItemStateChangedEvent] - Shelly1PmMeterCurrentWatts changed from 971.7 W to 962.6 W

2021-02-10 18:52:00.522 [vent.ItemStateChangedEvent] - Shelly1PmMeterTotalKWH changed from 3.134 kWh to 3.139 kWh

==> /var/log/openhab2/openhab.log <==

**2021-02-10 18:52:01.381** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - senden alter Wert**

**2021-02-10 18:52:01.381** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - senden alter Wert**

**2021-02-10 18:52:01.399** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - Blinken startet**

**2021-02-10 18:52:01.406** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - Blinken startet**

**2021-02-10 18:52:01.421** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - Blinken endet**

**2021-02-10 18:52:01.426** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - Blinken endet**

==> /var/log/openhab2/events.log <==

2021-02-10 18:52:01.430 [ome.event.ItemCommandEvent] - Item 'LEDstripe_EG_KuecheDH' received command 0

2021-02-10 18:52:01.462 [ome.event.ItemCommandEvent] - Item 'LEDstripe_EG_KuecheDH' received command 0

2021-02-10 18:52:01.465 [nt.ItemStatePredictedEvent] - LEDstripe_EG_KuecheDH predicted to become 0

2021-02-10 18:52:01.483 [ome.event.ItemCommandEvent] - Item 'LEDstripe_EG_KuecheDH' received command 0

2021-02-10 18:52:01.506 [ome.event.ItemCommandEvent] - Item 'LEDstripe_EG_KuecheDH' received command 0

2021-02-10 18:52:01.509 [nt.ItemStatePredictedEvent] - LEDstripe_EG_KuecheDH predicted to become 0

2021-02-10 18:52:01.512 [nt.ItemStatePredictedEvent] - LEDstripe_EG_KuecheDH predicted to become 0

2021-02-10 18:52:01.519 [nt.ItemStatePredictedEvent] - LEDstripe_EG_KuecheDH predicted to become 0

2021-02-10 18:52:02.145 [vent.ItemStateChangedEvent] - Shelly1PmMeterCurrentWatts changed from 962.6 W to 962.1 W

==> /var/log/openhab2/openhab.log <==

**2021-02-10 18:52:03.438** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - Blinken startet**

**2021-02-10 18:52:03.457** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - Blinken endet**

==> /var/log/openhab2/events.log <==

2021-02-10 18:52:03.466 [ome.event.ItemCommandEvent] - Item 'LEDstripe_EG_KuecheDH' received command 100

2021-02-10 18:52:03.472 [nt.ItemStatePredictedEvent] - LEDstripe_EG_KuecheDH predicted to become 0

2021-02-10 18:52:04.612 [vent.ItemStateChangedEvent] - Shelly1PmMeterCurrentWatts changed from 962.1 W to 965.3 W

==> /var/log/openhab2/openhab.log <==

**2021-02-10 18:52:05.383** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - senden alter Wert**

==> /var/log/openhab2/events.log <==

2021-02-10 18:52:05.409 [ome.event.ItemCommandEvent] - Item 'LEDstripe_EG_KuecheDH' received command 0

2021-02-10 18:52:05.412 [nt.ItemStatePredictedEvent] - LEDstripe_EG_KuecheDH predicted to become 0

==> /var/log/openhab2/openhab.log <==

**2021-02-10 18:52:05.458** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - Blinken startet**

==> /var/log/openhab2/events.log <==

2021-02-10 18:52:05.469 [ome.event.ItemCommandEvent] - Item 'LEDstripe_EG_KuecheDH' received command 0

2021-02-10 18:52:05.472 [nt.ItemStatePredictedEvent] - LEDstripe_EG_KuecheDH predicted to become 0

==> /var/log/openhab2/openhab.log <==

**2021-02-10 18:52:05.480** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - Blinken endet**

**2021-02-10 18:52:07.496** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - Blinken startet**

**2021-02-10 18:52:07.513** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - Blinken endet**

==> /var/log/openhab2/events.log <==

2021-02-10 18:52:07.523 [ome.event.ItemCommandEvent] - Item 'LEDstripe_EG_KuecheDH' received command 100

2021-02-10 18:52:07.530 [nt.ItemStatePredictedEvent] - LEDstripe_EG_KuecheDH predicted to become 0

2021-02-10 18:52:08.251 [vent.ItemStateChangedEvent] - LEDstripe_EG_KuecheDH changed from 0 to 100

==> /var/log/openhab2/openhab.log <==

**2021-02-10 18:52:09.524** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - Blinken startet**

**2021-02-10 18:52:09.542** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - Blinken endet**

==> /var/log/openhab2/events.log <==

2021-02-10 18:52:09.543 [ome.event.ItemCommandEvent] - Item 'LEDstripe_EG_KuecheDH' received command 0

2021-02-10 18:52:09.546 [nt.ItemStatePredictedEvent] - LEDstripe_EG_KuecheDH predicted to become 100

==> /var/log/openhab2/openhab.log <==

**2021-02-10 18:52:11.553** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - Blinken startet**

**2021-02-10 18:52:11.562** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - Blinken endet**

Log 2 rule doesnt work:

  2021-02-10 18:52:38.989 [vent.ChannelTriggeredEvent] - shelly:shellybutton1:483fda6f2cea:status#button triggered SHORT_PRESSED

    ==> /var/log/openhab2/openhab.log <==

    **2021-02-10 18:52:39.003** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - speichern alter Wert**

    ==> /var/log/openhab2/events.log <==

    2021-02-10 18:52:39.205 [vent.ChannelTriggeredEvent] - shelly:shellybutton1:483fda6f2cea:status#button triggered SHORT_PRESSED

    ==> /var/log/openhab2/openhab.log <==

    **2021-02-10 18:52:39.220** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - speichern alter Wert**

    ==> /var/log/openhab2/events.log <==

    2021-02-10 18:52:39.607 [vent.ChannelTriggeredEvent] - shelly:shellybutton1:483fda6f2cea:status#button triggered SHORT_PRESSED

    ==> /var/log/openhab2/openhab.log <==

    **2021-02-10 18:52:39.619** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - speichern alter Wert**

    **2021-02-10 18:52:44.026** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - senden alter Wert**

    **2021-02-10 18:52:44.041** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - Blinken startet**

    ==> /var/log/openhab2/events.log <==

    2021-02-10 18:52:44.048 [ome.event.ItemCommandEvent] - Item 'LEDstripe_EG_KuecheDH' received command 100

    2021-02-10 18:52:44.052 [nt.ItemStatePredictedEvent] - LEDstripe_EG_KuecheDH predicted to become 100

    ==> /var/log/openhab2/openhab.log <==

    **2021-02-10 18:52:44.054** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - Blinken endet**

    ==> /var/log/openhab2/events.log <==

    2021-02-10 18:52:44.078 [ome.event.ItemCommandEvent] - Item 'LEDstripe_EG_KuecheDH' received command 100

    2021-02-10 18:52:44.082 [nt.ItemStatePredictedEvent] - LEDstripe_EG_KuecheDH predicted to become 100

    ==> /var/log/openhab2/openhab.log <==

    **2021-02-10 18:52:44.233** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - senden alter Wert**

    **2021-02-10 18:52:44.240** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - Blinken startet**

    **2021-02-10 18:52:44.247** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - Blinken endet**

    ==> /var/log/openhab2/events.log <==

    2021-02-10 18:52:44.251 [ome.event.ItemCommandEvent] - Item 'LEDstripe_EG_KuecheDH' received command 100

    2021-02-10 18:52:44.263 [ome.event.ItemCommandEvent] - Item 'LEDstripe_EG_KuecheDH' received command 100

    2021-02-10 18:52:44.265 [nt.ItemStatePredictedEvent] - LEDstripe_EG_KuecheDH predicted to become 100

    2021-02-10 18:52:44.267 [nt.ItemStatePredictedEvent] - LEDstripe_EG_KuecheDH predicted to become 100

    ==> /var/log/openhab2/openhab.log <==

    **2021-02-10 18:52:44.634** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - senden alter Wert**

    **2021-02-10 18:52:44.641** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - Blinken startet**

    **2021-02-10 18:52:44.648** **[INFO ]** **[pse.smarthome.model.script.Shottimer] - Blinken endet**

When you use createTimer() in a rule, it schedules the future job and then immediately moves on. The rule does not stop and wait for hours.
So your rule does -
Save the current state;
Create a timer for the future;
Restore saved state.

Some time later, the timer runs, but doesn’t do anything about saved states.

You want to be doing the restore at the last exit from your timer code.

Thank you for your quick reply. I thought I set the sending of “AlterWert” correctly. It should be sent as soon as the timer tshot and timer tBlinken have ended. The timer tBlinken is a timer in the timer tshot! Or have I thought incorrectly about that?

Yes.
createTimer creates a timer for future execution and the rest of the rule continues immediately.

When your rule is triggered,it executes this in a few milliseconds -

   if(tshot !== null) tshot.cancel
   alterWert = LEDstripe_EG_KuecheDH.state
   logInfo("Shottimer", "speichern alter Wert")
   tshot = createTimer(now.plusSeconds(5))[|  + code ] // Timer initialisieren und sofoert ausführen
   tshot = null
end

You’ve saved the state, created a timer, and then immediately destroyed the handle tshot for the timer. The timer still exists, but you cannot control it any more. If the rule re-triggers, there is nothing to stopit creating another timer alongside the running one.
Then the rule exits.

5 seconds later, this code runs (the “tshot” timer)

        if(tBlinken === null) {
        tBlinken = createTimer(now, [  + code ] //der erste Durchlauf geschieht sofort
            } 
        LEDstripe_EG_KuecheDH.sendCommand (alterWert)
        logInfo("Shottimer", "senden alter Wert")
    ] // end of timer code

You’ve created another timer (handle tBlinken) to start almost immediately. It just might start running before this timer code has finished, this is indeterminate. But as before, the rest of this “tshot” timer code carries on immediately, does not stop and wait.
You then restore the saved state of the LEDstripe.
Then the “tshot” timer exits.

Either immediately, or in two seconds time, the tBlinken timer code will run, and will trample over that restored LEDstrip state with on/off.

I think you want to do both the LEDstripe restore and the tshot=null at the point you finally exit tBlinken.
And you’ll want to reset loop=6 at that point.

Take care about what gets done with if-else statements.
You’ve got

                  else
                        tBlinken = null //zuletzt Timer für nächsten Anruf initialisieren
                        logInfo("Shottimer", "Blinken endet")

but really that can be written as

                  else {
                        tBlinken = null //zuletzt Timer für nächsten Anruf initialisieren
                   }
                  logInfo("Shottimer", "Blinken endet")

the logInfo is not part of the “else”.
Personally I always use { } even for one-liners, so that I can clearly see what is supposed to happen.

Ok, I understood what you wrote, but the implementation wasn’t that easy for me. With try and error I understood what you meant. This is what the rule currently looks like:

rule "Shottimer"

when 

    Channel "shelly:shellybutton1:483fda6f2cea:status#button" triggered SHORT_PRESSED

then 

    if(tshot !== null) tshot.cancel

      alterWert = LEDstripe_EG_KuecheDH.state

      logInfo("Shottimer", "speichern alter Wert")

      tshot = createTimer(now.plusSeconds(5))[|  // Timer initialisieren und sofoert ausführen

        if(tBlinken === null) {

                

                tBlinken = createTimer(now, [  //der erste Durchlauf geschieht sofort

                    loop = loop - 1

                    LEDstripe_EG_KuecheDH.sendCommand(if(loop % 2 == 1) 0 else 100) //abwechselnd ON und OFF

                    logInfo("Shottimer", "Blinken startet")

                    if (loop > 0)

                        tBlinken.reschedule(now.plusSeconds(2)) //jeder weitere Durchlauf wird um 2 Sekunden verzögert

                    else {

                        tBlinken = null //zuletzt Timer für nächsten Anruf initialisieren

                        }

                        logInfo("Shottimer", "Blinken endet")

                    LEDstripe_EG_KuecheDH.sendCommand(alterWert)

                    logInfo("Shottimer", "senden alter Wert")

                ])

            }

        tshot = null 

        

    ]   

      

end

The “old value” is established in the end, good! unfortunately it doesn’t work with the blinking yet! when the rule is running for the first time the stripe flashes three times. Do a second test, it flashes once and that’s it. Btw. I haven’t understood this loop function anyway.

You need to restore loop=6 when finished, or before starting, as well.

You can compress this into just one timer, the first 5 seconds is “do nothing” after all. (What’s that pause for?!)

var Timer tshot = null
var alterWert
var int loop = 0

rule "Shottimer"
when 
    Channel "shelly:shellybutton1:483fda6f2cea:status#button" triggered SHORT_PRESSED
then 
    if (tshot !== null) {
        tshot.cancel  // abort old timer but don't overwrite saved value
    } else {
        alterWert = LEDstripe_EG_KuecheDH.state  // save state now
    }
    logInfo("Shottimer", "speichern alter Wert")
    loop = 6
    tshot = createTimer(now.plusSeconds(5))[|  // Timer initialisieren und sofoert ausführen
        if (loop == 6) {
            logInfo("Shottimer", "Blinken startet")
        }
        LEDstripe_EG_KuecheDH.sendCommand(if(loop % 2 == 1) 0 else 100) //abwechselnd ON und OFF
        loop = loop - 1
        if (loop > 0) {
             tshot.reschedule(now.plusSeconds(2)) //jeder weitere Durchlauf wird um 2 Sekunden verzögert
        } else {
            logInfo("Shottimer", "Blinken endet")
            logInfo("Shottimer", "senden alter Wert")
            LEDstripe_EG_KuecheDH.sendCommand(alterWert) // restore
            tshot = null 
         }
     ])
end

I’ve changed the first if() so that if the sequence is already in progress, it doesn’t save an existing flashing state.

The Rule works fine… after a few tests for the correct position of loop 6 :slight_smile:

rule "Shottimer"

when 

    Channel "shelly:shellybutton1:483fda6f2cea:status#button" triggered SHORT_PRESSED

then 

    if(tshot !== null) tshot.cancel

      alterWert = LEDstripe_EG_KuecheDH.state

      logInfo("Shottimer", "speichern alter Wert")

      tshot = createTimer(now.plusSeconds(5))[|  // Timer initialisieren und sofoert ausführen

        if(tBlinken === null) {

                

                tBlinken = createTimer(now, [  //der erste Durchlauf geschieht sofort

                    loop = loop - 1

                    LEDstripe_EG_KuecheDH.sendCommand(if(loop % 2 == 1) 0 else 100) //abwechselnd ON und OFF

                    logInfo("Shottimer", "Blinken startet")

                    if (loop > 0)

                        tBlinken.reschedule(now.plusSeconds(2)) //jeder weitere Durchlauf wird um 2 Sekunden verzögert

                    else {

                        tBlinken = null //zuletzt Timer für nächsten Anruf initialisieren

                        loop=6

                        }

                        logInfo("Shottimer", "Blinken endet")

                    LEDstripe_EG_KuecheDH.sendCommand(alterWert)

                    logInfo("Shottimer", "senden alter Wert")    

                ]) 

            }

        tshot = null         

    ]       

end

Thank you for your patience and for your “not silver tablet solution”. I’ve learned a lot again.

Last question: the stripe is very sluggish. Could the time when switching from 0 to 100 could be increased a little. At the moment I only have a short flash.

Edit: I have only now seen that you have also revised the rule, thank you very much. I will test.

The first five seconds are really about 25-35 seconds. The rule is my shot timer, which means: when I start drawing off my espresso, I want to stop drawing off after about 25 seconds. Until now, I’ve always had to set my kitchen timer in a cumbersome manner. Now all I have to do is press a button and I can do other things while I am moving. The function is not a must, but a nice to have! :slight_smile:

Yes, we can change the reschedule time depending on loop counter odd or even.

Rework this part -

             LEDstripe_EG_KuecheDH.sendCommand(if(loop % 2 == 1) 0 else 100) //abwechselnd ON und OFF
              if (loop > 0)
                   tBlinken.reschedule(now.plusSeconds(2)) //jeder weitere Durchlauf wird um 2 Sekunden verzögert
              else {

into something like

            if(loop % 2 == 1) {  //odd or even
                LEDstripe_EG_KuecheDH.sendCommand(0) // flash off
                tBlinken.reschedule(now.plusSeconds(2)) //jeder weitere 
            } else if (loop > 0) {
                LEDstripe_EG_KuecheDH.sendCommand(100) // flash on
                tBlinken.reschedule(now.plusSeconds(3)) //jeder weitere 
            } else {

I tested your rule and it works much better. The blinking is very pleasant. I can adopt the rule just like that. What amazes me though: It only flashes twice !? But it doesn’t matter, the rule is exactly as I imagined it to be.

Many Thanks!

“loop” controls the number of flashes, try tweaking it, say 8.
What the rule doesn’t do is take account of existing on/off state when it starts a on/off flash cycle, so maybe there’s no immediate change.
All things are possible…

            if (loop > 0) {  // let's flash
                if (LEDstripe_EG_KuecheDH.state == 0) { // test if off now
                   LEDstripe_EG_KuecheDH.sendCommand(100) // flash on
                   tBlinken.reschedule(now.plusSeconds(3)) //jeder weitere 
                } else {
                    LEDstripe_EG_KuecheDH.sendCommand(0) // flash off
                    tBlinken.reschedule(now.plusSeconds(2)) //jeder weitere 
                }
            } else {   // else loop=0, exit

:joy: you are great!

The very last question :rofl:

The Espressomachine ist switched witch a shelly1pm. What trigger do i need for the rule, if i would start the rule with the Energycount? Example:

when

Shelly1PmMeterCurrentWatts  between 900W and 950W || Shelly1PmMeterCurrentWatts between 1650W and 1750W

then

Can’t do that.
Syntax requires you to say “when what?”, so first you need keyword Item.
Then you can do various checks on it, including equality, but not “between”.

What you can do is trigger a rule from any change, and then inside the body of the rule do any test you like before doing whatever.
There is no “between” test though, you have to create one using “more than this” AND “less than that” methods.

Once you’ve sorted that out, you need to think about what happens when the rule triggers again after the first start of the timer. You’ll probably want the existing timer to carry on, and not start a new one.

Ok, I understand. Item between is not possible.

I make this:

What do you think? Would that be okay or would there be problems here? After all, the rule is checked every time it changes “CurrentWatt”, and this happens very often …

var Timer tshot = null

var alterWert

var int loop = 0

rule "Shottimer"

when 

    Channel "shelly:shellybutton1:483fda6f2cea:status#button" triggered SHORT_PRESSED or 

    Item Shottimerdummyitem changed from OFF to ON

then 

    if (tshot !== null) {

        tshot.cancel  // abort old timer but don't overwrite saved value

    } else {

        alterWert = LEDstripe_EG_KuecheDH.state  // save state now

    }

    logInfo("Shottimer", "speichern alter Wert")

    loop = 6

    tshot = createTimer(now.plusSeconds(33))[|  // Timer initialisieren und sofoert ausführen

        if (loop == 6) {

            logInfo("Shottimer", "Blinken startet")

        }

        LEDstripe_EG_KuecheDH.sendCommand(if(loop % 2 == 1) 0 else 100) //abwechselnd ON und OFF

        loop = loop - 1

        if (loop > 0) {

             tshot.reschedule(now.plusSeconds(2)) //jeder weitere Durchlauf wird um 2 Sekunden verzögert

        } else {

            logInfo("Shottimer", "Blinken endet")

            logInfo("Shottimer", "senden alter Wert")

            LEDstripe_EG_KuecheDH.sendCommand(alterWert) // restore

            tshot = null 

         }

     ]

end

rule "Shottimer 1pm"

when 

    Item Shelly1PmMeterCurrentWatts changed 

then 

if ((Shelly1PmMeterCurrentWatts.state > 900 && Shelly1PmMeterCurrentWatts.state < 950) || (Shelly1PmMeterCurrentWatts.state > 1600 && Shelly1PmMeterCurrentWatts.state < 1750)) 

    {

        Shottimerdummyitem.sendCommand(ON)

    }

    else

    {

        Shottimerdummyitem.sendCommand(OFF)

    }

end

I’m not sure why you don’t put it all in one rule. There would be less triggering-of-rules-and-updating-items work for the system to do.

You may need to watch out that your power monitoring Item is or is not a Quantity type, meaning it has units like W, and should be compared with something else with units.

It’s easy for you to talk! I am at war with the rules! :hot_face: All of these ({[]}) confuse me!!!

The item is like this… Do i need the unit W?

Number:Power Shelly1PmMeterCurrentWatts "Aktueller Verbrauch [%.1f W]" {channel="shelly:shelly1pm:76b926:meter#currentWatts"}

But, I want to learn and of course I agree with you, it is better to have as many rules as necessary.

I tried myself once …

var Timer tshot = null

var alterWert

var int loop = 0

rule "Shottimer"

when 

    Channel "shelly:shellybutton1:483fda6f2cea:status#button" triggered SHORT_PRESSED or 

    Item Shelly1PmMeterCurrentWatts changed

then 

    if (tshot !== null) {

        tshot.cancel  // abort old timer but don't overwrite saved value

    } else 

        if ((Shelly1PmMeterCurrentWatts.state > 900.0 && Shelly1PmMeterCurrentWatts.state < 950.0) || (Shelly1PmMeterCurrentWatts.state > 1600.0 && Shelly1PmMeterCurrentWatts.state < 1750.0)) 

    

        {

        alterWert = LEDstripe_EG_KuecheDH.state  // save state now

        }

    logInfo("Shottimer", "speichern alter Wert")

    loop = 6

    tshot = createTimer(now.plusSeconds(33))[|  // Timer initialisieren und sofoert ausführen

        if (loop == 6) {

            logInfo("Shottimer", "Blinken startet")

        }

        LEDstripe_EG_KuecheDH.sendCommand(if(loop % 2 == 1) 0 else 100) //abwechselnd ON und OFF

        loop = loop - 1

        if (loop > 0) {

             tshot.reschedule(now.plusSeconds(2)) //jeder weitere Durchlauf wird um 2 Sekunden verzögert

        } else {

            logInfo("Shottimer", "Blinken endet")

            logInfo("Shottimer", "senden alter Wert")

            LEDstripe_EG_KuecheDH.sendCommand(alterWert) // restore

            tshot = null 

         }

     ]

end

if (condition is true) {do stuff in curly braces}
now do next thing, regardless

It’s worth spending time using indentation with this sort of thing. It makes no difference to the rule, but will preserve your sanity
Trivial -

    if (condition is true) {
        do stuff conditionally
    }
    do the next thing regardless
    and the next etc.

Getting more complicated -

    if (condition is true) {
        do stuff conditionally
        if ( different condition) {
            do this bit sometimes
        }
        but this bit every pass
    } else {
        do something different
    }
    do the next thing regardless
    and the next etc.

Yes, because it is not just a Number, it’s a Number:Power (with units).
But in DSL rules, you can’t just write “90W” and have it treat it like a Quantity (with units).
You do have to create a proper Quantity type variable, but there is handy shortcut provided for that, a magic character | pipe.
if (someItem.state > 100 | W) ...
The good news is that you need not care if the Item is in kW or mW or horsepower, openHAB sorts that out for you.

Don’t think you want that.
Wouldn’t you want to check the power before doing anything about timers?

Out of curiosity, what is the machine doing when power is 950 to 1600W that you want to ignore? Is not just >900W good enough to see that it was turned on, for your simple purpose here?

Alright, next -

    if (tshot !== null) {
        tshot.cancel    // abort old timer

You won’t want to kill the timer every time power consumption is reported.
What do you want to happen?
I’m guessing you want the timer to start the first time power >900W.
Any more reports, leave the already running timer alone?

What do you want to happen if power becomes <900W while timer is running?

What do you want to happen if timer finishes its flashing, and power still more than >900W? Go round again, or never do it again until power has returned below 900W perhaps?

These questions are nothing to do with writing DSL syntax, but everything to do with being clear about what you want to happen. That’s half the battle.

Thank you for the detailed explanation, maybe the rules and I will still become friends!

It is possible that the automatic start based on the power control is excessive. But if it would be possible, I’ll test it.

For explanation:
The espresso machine is a so-called dual boiler machine. The first boiler is only for the coffee water, the second is only for the steam boiler, so milk foam and such … Those are three energy states. No heating, heating only coffee water and heating coffee water and steam boiler. The pump is then used to identify a reference. This has an output of 48W. That means there are four power states in which the rule should switch:

  1. Water is hot and only the pump is running = consumption approx. 50W

  2. Coffee water is heated up and the pump is running = approx. 950W

  3. Coffee water is heated up and the steam boiler is heated up and the pump is running = approx. 1650W

  4. The steam boiler is heated up and the pump is running = approx. 750W

Maybe I shot over the target. I am very satisfied with the current button solution.

In any case, many thanks for your really detailed explanations. I’ve never seen it like this …

Sorry, now I have to contact you again. Somehow the rule is no longer working correctly. After the last log info (“senden alter Wert”) there are many error messages in the log. I think this has something to do with the timer but haven’t been able to find the error yet …

var Timer tshot = null

var alterWert

var int loop = 0

rule "Shottimer"

when 

    Channel "shelly:shellybutton1:483fda6f2cea:status#button" triggered SHORT_PRESSED //or 

    //Item Shelly1PmMeterCurrentWatts changed

then 

    if (tshot !== null) {

        tshot.cancel  // abort old timer but don't overwrite saved value

    } else 

       // if ((Shelly1PmMeterCurrentWatts.state > 900.0 && Shelly1PmMeterCurrentWatts.state < 950.0) || (Shelly1PmMeterCurrentWatts.state > 1600.0 && Shelly1PmMeterCurrentWatts.state < 1750.0)) 

    

        {

        alterWert = LEDstripe_EG_KuecheDH.state  // save state now

        }

    logInfo("Shottimer", "speichern alter Wert")

    loop = 2

    tshot = createTimer(now.plusSeconds(5))[|  // Timer initialisieren und sofoert ausführen

        if (loop == 2) {

            logInfo("Shottimer", "Blinken startet")

        }

        LEDstripe_EG_KuecheDH.sendCommand(if(loop % 2 == 1) 0 else 100) //abwechselnd ON und OFF

        loop = loop - 1

        if (loop > 0) {

             tshot.reschedule(now.plusSeconds(2)) //jeder weitere Durchlauf wird um 2 Sekunden verzögert

        } else {

            logInfo("Shottimer", "Blinken endet")

            logInfo("Shottimer", "senden alter Wert")

            LEDstripe_EG_KuecheDH.sendCommand(alterWert) // restore

            tshot = null 

         }

     ]

end

Log:

2021-03-03 21:21:44.930 [ERROR] [org.quartz.core.JobRunShell         ] - Job DEFAULT.Timer 771 2021-03-03T21:21:42.857+01:00: Proxy for org.eclipse.xtext.xbase.lib.Procedures$Procedure0: [ | {

  org.eclipse.xtext.xbase.impl.XIfExpressionImpl@f25a64 (conditionalExpression: false)

  <XFeatureCallImplCustom>.sendCommand(<XIfExpressionImpl>)

  <null>.loop = <XBinaryOperationImplCustom>

  org.eclipse.xtext.xbase.impl.XIfExpressionImpl@15166aa (conditionalExpression: false)

} ] threw an unhandled Exception: 

java.lang.IllegalStateException: Could not invoke method: org.eclipse.smarthome.model.script.actions.BusEvent.sendCommand(org.eclipse.smarthome.core.items.Item,java.lang.String) on instance: null

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1192) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1150) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._invokeFeature(XbaseInterpreter.java:1136) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeFeature(XbaseInterpreter.java:1081) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:151) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:861) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:231) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:215) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:458) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:239) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:215) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:475) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:255) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:215) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:458) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:239) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:215) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluate(XbaseInterpreter.java:201) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.ClosureInvocationHandler.doInvoke(ClosureInvocationHandler.java:46) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.AbstractClosureInvocationHandler.invoke(AbstractClosureInvocationHandler.java:29) ~[?:?]

	at com.sun.proxy.$Proxy191.apply(Unknown Source) ~[?:?]

	at org.eclipse.smarthome.model.script.internal.actions.TimerExecutionJob.execute(TimerExecutionJob.java:48) ~[?:?]

	at org.quartz.core.JobRunShell.run(JobRunShell.java:202) [bundleFile:?]

	at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [bundleFile:?]

Caused by: java.lang.IllegalArgumentException: java.lang.ClassCastException@adf63

	at sun.reflect.GeneratedMethodAccessor307.invoke(Unknown Source) ~[?:?]

	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_252]

	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_252]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1175) ~[?:?]

	... 27 more

==> /var/log/openhab2/events.log <==

2021-03-03 21:21:45.011 [nt.ItemStatePredictedEvent] - LEDstripe_EG_KuecheDH predicted to become 100

==> /var/log/openhab2/openhab.log <==

2021-03-03 21:21:44.969 [ERROR] [org.quartz.core.ErrorLogger         ] - Job (DEFAULT.Timer 771 2021-03-03T21:21:42.857+01:00: Proxy for org.eclipse.xtext.xbase.lib.Procedures$Procedure0: [ | {

  org.eclipse.xtext.xbase.impl.XIfExpressionImpl@f25a64 (conditionalExpression: false)

  <XFeatureCallImplCustom>.sendCommand(<XIfExpressionImpl>)

  <null>.loop = <XBinaryOperationImplCustom>

  org.eclipse.xtext.xbase.impl.XIfExpressionImpl@15166aa (conditionalExpression: false)

} ] threw an exception.

org.quartz.SchedulerException: Job threw an unhandled exception.

	at org.quartz.core.JobRunShell.run(JobRunShell.java:213) [bundleFile:?]

	at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [bundleFile:?]

Caused by: java.lang.IllegalStateException: Could not invoke method: org.eclipse.smarthome.model.script.actions.BusEvent.sendCommand(org.eclipse.smarthome.core.items.Item,java.lang.String) on instance: null

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1192) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1150) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._invokeFeature(XbaseInterpreter.java:1136) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeFeature(XbaseInterpreter.java:1081) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:151) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:861) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:231) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:215) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:458) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:239) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:215) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:475) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:255) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:215) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:458) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:239) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:215) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluate(XbaseInterpreter.java:201) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.ClosureInvocationHandler.doInvoke(ClosureInvocationHandler.java:46) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.AbstractClosureInvocationHandler.invoke(AbstractClosureInvocationHandler.java:29) ~[?:?]

	at com.sun.proxy.$Proxy191.apply(Unknown Source) ~[?:?]

	at org.eclipse.smarthome.model.script.internal.actions.TimerExecutionJob.execute(TimerExecutionJob.java:48) ~[?:?]

	at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ~[?:?]

	... 1 more

Caused by: java.lang.IllegalArgumentException: java.lang.ClassCastException@adf63

	at sun.reflect.GeneratedMethodAccessor307.invoke(Unknown Source) ~[?:?]

	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_252]

	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_252]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1175) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1150) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._invokeFeature(XbaseInterpreter.java:1136) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeFeature(XbaseInterpreter.java:1081) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:151) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:861) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:231) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:215) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:458) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:239) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:215) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:475) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:255) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:215) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:458) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:239) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:215) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluate(XbaseInterpreter.java:201) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.ClosureInvocationHandler.doInvoke(ClosureInvocationHandler.java:46) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.AbstractClosureInvocationHandler.invoke(AbstractClosureInvocationHandler.java:29) ~[?:?]

	at com.sun.proxy.$Proxy191.apply(Unknown Source) ~[?:?]

	at org.eclipse.smarthome.model.script.internal.actions.TimerExecutionJob.execute(TimerExecutionJob.java:48) ~[?:?]

	at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ~[?:?]

	... 1 more

We can guess this is a scheduled timer that has blown up from that part.

Okay, you have to unpick messages from timers, they are rather cryptic.

First question, have you been editing this or other rules in the same file? Timers that were already running when you save an edit get "orphaned"in that their environment is destroyed, but still go off at the appointed time. Usually then then fail with a mystery “null” error.

If you were not doing that -
message won’t point directly at the problem line, but …

It does gives a kind of skeleton trace of where it’s been.
Started with an if() that proved false
Then did a sendCommand
Then did some kind of operation on variable loop
Then another if() that proved false
Then blown up on a sendCommand
Timers usually complain about something null, it generally means something we thought still exists, just doesn’t anymore.

Those last few operations might all be pointing to this one compound line

LEDstripe_EG_KuecheDH.sendCommand(if(loop % 2 == 1) 0 else 100) //abwechselnd ON und OFF

We know loop existed just now because we already tested for loop==2 without a null error.
I can’t see much else to go wrong there.

Or, if we are just getting line-by-line messages, the trail leads to

LEDstripe_EG_KuecheDH.sendCommand(alterWert)

and then most likely it’s alterWert that’s null.

I can’t see how you would get into either possibility without editing the rules file.

Thanks for your answer. This is the only rule in the rule file. I only reduced the number of loops from 6 to 2.

Interestingly, your guess isn’t too bad. In the part

LEDstripe_EG_KuecheDH.sendCommand (alterWert)

.sendCommand is always underlined in red in VSC. It always did, but maybe this is the problem?

Must a “state as decimaltype” or something similar be used here?

I’m going to restart the system tonight, that has often helped. :laughing: