OH3 Blockly with/without timer -> turned to be .rules file

Hello everyone,
I am trying to Blockly such a thing:
when window status is open
wait 10 minutes
switch on the light.

I suppose I cant do it with Rules, therefore I am trying to do it second easiest way: Blockly

I cant even do the simple thing in blockly - without 10 minutes timer:

if (itemRegistry.getItem('MagnetTerasaDetska_OpenStatus').getState() == 'OPEN') {
  events.sendCommand('BWSHP63_state', 'ON');
}

or graphical:
image

Is the state OPEN a variable, or a text? what about the command? is it simply text, or should it be variable? And what about command ON - text, or variable?
what about MagnetTerasaDetska_OpenStatus - should I do it with get item state, or simply without?

I have tried all the combinations, nothing works.

I know, beginners question, but I havent found any answer how to do it. Those are basic principles, which I need to understand.

Thanks for help!

I don’t know about Blocky however I can help you with your rule :slight_smile:


You can!
There are two ways:

  1. Using Thread::sleep(60*1000*10) //60 Seconds, 1000 millis, 10 Minutes
if (itemRegistry.getItem('MagnetTerasaDetska_OpenStatus').getState() == 'OPEN') {
    Thread::sleep(60*1000*10)  
    events.sendCommand('BWSHP63_state', 'ON')
}

It is advised to not use Thread::sleep for this long since it can cause other rules to be blocked and not run.
2. Timers

//On the top of the rule file
var Timer timer_till_command= null

//The Rule itself
if (itemRegistry.getItem('MagnetTerasaDetska_OpenStatus').getState() == 'OPEN') {
    var timer = new DateTime(now.toString).plusMinutes(10)
    timer_till_command= createTimer(timer,
        [ |
            events.sendCommand('BWSHP63_state', 'ON');
            timer_bis_ende_der_morgenroutine = null
        ]       
}

Blockly does not yet support creating timers nor does it support Thread.sleep.

A text constant, sometimes called a “string literal”. It is not a variable.

Also a String literal.

In this context using string literals are just fine. You’d only need to create a variable if you wanted to save a value and reuse it in multiple places, or if you want to gradually build up a value step by step or something like that.

This is not quite the same sort of problem in OH 3 any more. Instead of a relatively small pool of threads that all rules share, OH 3 gives each and every rule it’s own thread. So you can never starve out all of your rules like was possible in OH 2. At most you can starve out that one single rule because another change from 2.5 is that one one instance of a given rule can run at a time. So if the rule runs for a long time and gets triggered again while it’s running, those subsequent events will be queued up and processed when the rule becomes free in the order they occurred.

2 Likes

Interesting. Thanks for clarifying

Thanks Felix, I will try it.
But then I have a question - what is wrong on my Blockly without timer? Mine is not working at all. And it looks very similar to your script without timer? :confused:

What triggers your rule? You might want choose triggering by a change in that Item.

An Aquara magnet on window. So how it should look like in Blockly?

OK,
I have created my first rules (11 already working), now I am trying to do something a bit more complicated.

rule "Mijia & Aqara Door/Window Sensor"
when
    Item MagnetOknoDetska_OpenStatus changed to OPEN
then
    logInfo("vetranie", "O chvilu pride notifikacia o dlhom vetrani")
    Thread::sleep(15*1000*1)  //60 Seconds, 1000 millis, 8 Minutes
    **when**
        Item MagnetOknoDetska_OpenStatus changed to CLOSED
        **do nothing**
    **else**
        sendBroadcastNotification("Zavri okná a dvere, dlho vetráš", "flow")
end

How this should be written correctly?
The purpose of the script is to send broadcast message to all users in case a window has been opened for more than 6 minutes. I have marked the dummy commands in the code with stars.
The rest should be working.

Thank you!

See Felix’s post above. There is an example there for how to create a Timer.

when can only appear after a line starting with rule and it starts the section for defining what triggers cause the rule to run. You can’t use when inside a rule. You want to use an if statement.

if(MagnetOknoDetska_OpenStatus.state == OPEN) {
    sendBroadcast...
}

My timer is working, or at least it was (based on the first Felix’s example).

I am trying to solve the other half of the script. So now the if is correctly syntaxed, but can you help here, how to **do nothing** in case of Item MagnetOknoDetska_OpenStatus changed to CLOSED?

rule "Mijia & Aqara Door/Window Sensor"
when
    Item MagnetOknoDetska_OpenStatus changed to OPEN
then
    logInfo("vetranie", "O chvilu pride notifikacia o dlhom vetrani")
    Thread::sleep(15*1000*1)  //60 Seconds, 1000 millis, 8 Minutes
    if(Item MagnetOknoDetska_OpenStatus changed to CLOSED) {
      **do nothing** //How this should be done/named correctly?
    }
    else
    sendBroadcastNotification("Zavri okná a dvere, dlho vetráš", "flow")
end

Thanks,
M

That would be an instantaneous event. You’ll want to examine the (steady) state of the Item to see if it is still open.

1 Like

I see… as Felix and Rich wrote before, the process is sleeping, means if something happends in those 6 minutes, it will not be registered.
I suppose that changing to received update will not save me:
if(Item MagnetOknoDetska_OpenStatus received update CLOSED)
so I need it to be based on Felix second example of var Timer, right?

This is still looking for an event that would have to happen at the same nanosecond that your if(statement) ran.
Rich’s suggestion looks at the steady state, any time you like

if(MagnetOknoDetska_OpenStatus.state == OPEN) {

1 Like

My example already does nothing when it’s CLOSED.

What do you think an Item state is? It records the state of the Item. If it changes to CLOSED before the Timer runs, the Item’s state will be CLOSED when the Timer finally runs. That if statement will evaluate to false and since there is no else nothing happens. That’s why I test the Item’s state to see if it’s still open when the Timer goes off. If it is the broadcast is sent. If not it does nothing, just as you asked.

If you wanted to change your rule so that it cancels a timer when the Item changes to CLOSED you can certainly do that too. But not if you are using a Thread::sleep. Only if you use a Timer.

var Timer mytimer = null

rule "Mijia & Aqara Door/Window Sensor"
when
    Item MagnetOknoDetska_OpenStatus changed
then
    if(newState == OPEN){
        mytimer = createTimer(now.plusSeconds(15), [ | 
            sendBroadcastNotification("Zavri okná a dvere, dlho vetráš", "flow")
            mytimer = null
        ])
    }
    else {
        mytimer?.cancel // the ? means only call cancel if mytimer isn't null
        mytimer = null
    }
end
1 Like

OK, thanks, It is working now, even with custom xiaomi gateway sound :slight_smile:
rule “Vetranie”

when
    Item MagnetOknoDetska_OpenStatus changed to OPEN
then
        logInfo("vetranie", "O chvilu pride notifikacia o dlhom vetrani")
        Thread::sleep(15*1000*1)  //60 Seconds, 1000 millis, 8 Minutes
        if(MagnetOknoDetska_OpenStatus.state == OPEN) {
            XiaomiGW_SoundVolume.sendCommand(3)
            XiaomiGW_SoundSelector.sendCommand(10003)
            Thread::sleep(4000) /* wait for 4 seconds */
            XiaomiGW_SoundSelector.sendCommand(10000)
            XiaomiGW_SoundVolume.sendCommand(6)
            sendBroadcastNotification("Zavri okná a dvere, dlho vetráš")
        }
end

Now I want to add extra condition - to run the command when
Item MagnetOknoDetska_OpenStatus changed to OPEN
and the temperature outside is less than 18 degrees C: WeatherCompanyObservations_Temperature.state < 18

rule "Vetranie"
when
    Item MagnetOknoDetska_OpenStatus changed to OPEN
then
    logInfo("vetranie", "Rule vetranie spustene")
    if(WeatherCompanyObservations_Temperature.state < 18) {   //this does not work, but OH is not throwing any error
        logInfo("vetranie", "O chvilu pride notifikacia o dlhom vetrani")
        Thread::sleep(15*1000*1)  //60 Seconds, 1000 millis, 8 Minutes
        if(MagnetOknoDetska_OpenStatus.state == OPEN) {
            XiaomiGW_SoundVolume.sendCommand(3)
            XiaomiGW_SoundSelector.sendCommand(10003)
            Thread::sleep(4000) /* wait for 4 seconds */
            XiaomiGW_SoundSelector.sendCommand(10000)
            XiaomiGW_SoundVolume.sendCommand(6)
            sendBroadcastNotification("Zavri okná a dvere, dlho vetráš")
        }
    }
end

Should the line WeatherCompanyObservations_Temperature.state < 18 be defined somehow inbetween when and then too?

WeatherCompanyObservations_Temperature is an item with one channel:
image

Thanks guys!

Your Item is a Number:Temperature type, with units that are part of the value. You are comparing to 18 … 18 what, degrees K, metres, kWh?
You have to spell it out for openHAB - magic character pipe | is useful here with constant values.
if (WeatherCompanyObservations_Temperature.state < 18|°C)

1 Like

Thanks, it works! :slight_smile:

Something to make you smile to thank you all:
Now how does it feels like in our house:
Engineers - me
Charlie Chaplin - my wife

Hi. is it possible to create a stadaard “timer delay 10 seconds” script that can be used in other rules?
i have several infrared heaters and i want to switch them ON and OFF by the same condition but with a fixed delay of 10 seconds to prevent high voltage peeks on my home power grid.
i managed to switch tem On and OFF with the right conditions via this rule:

triggers:

  • id: “1”
    configuration:
    itemName: ZWaveNode006FGMS001MotionSensor_Sensortemperature
    type: core.ItemStateChangeTrigger
    conditions:
  • inputs: {}
    id: “3”
    configuration:
    itemName: ZWaveNode006FGMS001MotionSensor_Sensortemperature
    state: “20.3”
    operator: <
    type: core.ItemStateCondition
  • inputs: {}
    id: “4”
    configuration:
    startTime: 07:15
    endTime: 22:00
    type: core.TimeOfDayCondition
    actions:
  • inputs: {}
    id: “2”
    configuration:
    itemName: ZWaveNode003FGWP102MeteredWallPlugSwitch_Switch
    command: ON
    type: core.ItemCommandAction

Have you considered that you can create in one rule a set of timers - one which issue a command to one device in 10secs time; and another timer that will issue a command to a different device in 20secs time; etc.

is this possible via UI in the;

  • actions:
  • inputs: {}
    id: “2”
    configuration:
    itemName: ZWaveNode003FGWP102MeteredWallPlugSwitch_Switch
    command: ON
    type: core.ItemCommandAction

?