Getting array in rules, doesn't work all the times

Hi, I have a set point for temperature and humidity which change every 12 hours. For this, I have a array to set from it. some times when 12 hour passes, the next number in the line does not set and it stuck at previous number until i change rule names or restart whole raspberry. some times it need multiple reset to sort it out. here is my rules:

var Number tmcount


val theArray1 = newArrayList(40, 40, 50, 50, 60, 60, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 49, 49, 49, 49, 49, 49, 54, 54, 54, 55, 55, 55, 60, 60, 60, 60, 60, 60, 60, 82, 82, 82)

val theArray2 = newArrayList(100, 100, 100, 100, 100, 100, 78, 78, 78, 78, 78, 78, 78, 78, 70, 70, 70, 70, 70, 70, 58, 58, 58, 58, 58, 58, 46, 46, 46, 46, 46, 46, 32, 32, 32, 32, 32, 32, 22, 22, 22, 22, 22, 22, 15, 15, 15, 15, 15, 15, 15, 26, 26, 26)

rule "Restarting"
when
    System started
then
        Thread::sleep(1000)
        if(prepare.state == ON){
	Thread::sleep(2000)
          prepare.sendCommand("OFF")
          Thread::sleep(5000)
	        set.sendCommand("OFF")
          Thread::sleep(2000)
          stage1.sendCommand(stage2.state as Number)
          Thread::sleep(10000)
          prepare.sendCommand("ON")
        }
end

rule "wqtaging1"
when
      Item stage2 received update
then

if(rush175.state == ON)  {
goaltemp.sendCommand(theArray1.get((stage2.state as Number).intValue))
goalhumidity.sendCommand(theArray2.get((stage2.state as Number).intValue))
}

end

rule "tmcounting"
when
      Time cron "0 0 0/12 1/1 * ? *"
then

if(start.state == ON) {

  if(pause.state == OFF) {

        tmcount = tmcount + 1
        stage2.sendCommand(tmcount)
        stage2.postUpdate(tmcount)
  }

}
end

each 12 hours tmcount goes +1 and stage 2 updates. when stage 2 updates, goaltemp and goalhumidity should update accordingly. it usually does. but some times it stuck. some times the power outage cause this problem. Is there any solution here? or other way instead of using arrays?
thanks in advance.

  • Platform information:
    • Hardware: RPI400
    • OS: Raspbian
    • Java Runtime Environment: 1.8
    • openHAB version: 2.5

Not really sure, but you should not use thread.sleep but timers instead.
Especially as you have quite long sleeping times.

1 Like

I believe cron works on a 24 hour clock. Shouldn’t the trigger use 0/23 instead of 0/12?

And I’ll second @hmerk’s advice. Long running rules should be avoided. Long running is anything over 250 msec. A rule that takes 20 seconds to complete is a really bad idea. Though since this is a rule only triggered once at system startup, you are less likely to encounter some of the problems that can arise from long running rules.

Implemented with timers would look something like:

then
    createTimer(now.plusSeconds(1), [ |
        if(prepare.state == ON) {
            createTimer(now.plusSeconds(2), [ |
                prepare.sendCommand("OFF")
                createTimer(now.plusSeconds(5), [ | set.sendCommand("OFF")])
                createTimer(now.plusSeconds(7), [ | stage1.sendCommand(state2.state as Number) ])
                createTimer(now.plusSeconds(17), [ | prepare.sendCommand("ON") ])
            ])
        }
    ])
end

It gets simpler if you don’t have to wait that first second before you test to see if prepare.state is ON.

if(prepare.state == ON) {
    createTimer(now.plusSeconds(3), [ | prepare.sendCommand("OFF") ])
    createTimer(now.plusSeconds(8), [ | set.sendCommand("OFF") ])
    createTimer(now.plusSeconds(10), [ | stage1.sendCommand(stage2.state as Number) ])
    createTimer(now.plusSeconds(20), [ | prepare.sendCommand("ON") ])
}

If using JS Scripting with the OHRT library it would look something like this,

var { Deferred } = require('openhab_rules_tools');

setTimeout(() => { 
  if(prepare.state == "ON") {
    Deferred.defer("prepare", "OFF", "PT2S");
    Deferred.defer("set", "OFF", "PT7S");
    Deferred.defer("stage1", items.state2.state, "PT9S");
    Deferred.defer("prepare", "ON", "PT19S");
  }
}

Using Gatekeeper from OHRT would look something like:

var { Gatekeeper } = require('openhab_rules_tools');
cache.private.get('gk', () => Gatekeeper());

gk.addCommand('PT1S', () => {}); // do nothing for the first second
gk.addCommand('PT2S', () => { 
  if(prepare.state == "ON") {
    gk.addCommand('PT5S', () => items.prepare.sendCommand("OFF") );
    gk.addCommand('PT2S', () => items.set.sendCommand("OFF") );
    gk.addCommand('PT10S', () => items.stage1.sendCommand(items.stage2.state) );
    gk.addCommand('PT0S', () => items.prepare.sendCommand("ON") );
  }
});

Gatekeeper is the best way to schedule a sequence of commands. The time is how long to wait after executing the command before allowing the next command to run. Think of it like irrigation, the time is how long you want the water to stay on before stopping it and moving on to the next valve.

1 Like

Can he use OHRT with openHAB 2.5?
I doubt so….

  • To alleviate power outage and your counter resetting back, you can use persistence with restore on startup
  • What happens when tmcounter goes beyond the number of elements in the array?
  • What’s the initial state of stage2? Where is it initialised?
  • Why is tmcount not initialised?
  • Are stage1 and stage2 used elsewhere, or are they just for this purpose?
1 Like

thanks. I’m sure that this rule execute each 12 hours without any problem

rule "tmcounting"
when
      Time cron "0 0 0/12 1/1 * ? *"
then

if(start.state == ON) {

  if(pause.state == OFF) {

        tmcount = tmcount + 1
        stage2.sendCommand(tmcount)
        stage2.postUpdate(tmcount)
  }

}
end

it increases tmcount and stage2
the problem is in this rule:

rule "wqtaging1"
when
      Item stage2 received update
then

if(rush175.state == ON)  {
goaltemp.sendCommand(theArray1.get((stage2.state as Number).intValue))
goalhumidity.sendCommand(theArray2.get((stage2.state as Number).intValue))
}

end

some times it stuck at previous index of the array despite stage2 updates to new number
do you mean that this problem relates to thread::sleep which i use in start ups?

hi, i persist every thing, counter works as I wrote in my previous post and explained there more. the problem is stage2 some times has problem getting new indexes of the array.
2 - if tm counter goes beyond it stays at last index of the array
3- at frist user in basicUi define a stage1 and I use that to set stage2 at the begining.
4

rule "preparng"
when
    Item prepare received command ON
then
    start.sendCommand("ON")
    tmcount = stage1.state as Number
    stage2.postUpdate(tmcount)
    Fan.sendCommand(ON)
    pause.sendCommand("OFF")
end

it initialised as above
The user in basicui define stage1 with a set point. after prepare button clicks. tmcount and stage2 sets.

According to ArrayList (Java Platform SE 8 ) it would throw an error if it goes out of bounds.

Maybe rush175 state is not ON?

Since you’re on openhab 2, I don’t know. Things have changed in OH3 and OH4 in regards to threading and rule executions.

I’m not sure if the thread::sleep caused this problem. If it did, it would only cause problems for the first however many seconds in total, and after that it should have no bearing on the issue. Although you should still follow @rlkoshak’s suggestion to use timers, because Thread::Sleep blocks the script/rule.

1 Like

I didn’t see that he was on 2.5. I should have looked more closely. I wonder if it makes sense to have a “Legacy” category in the forum where anyone running a version of OH older than say two years or four years can post and perhaps find people able to help. I can usually help with generic stuff that is still the same today as it was back in 2.5 but I do not trust my ability to support most of the stuff that has changed since 2.5 any more.

And it may not be fair, but it’s hard to not have the feeling that if you want to keep running unsupported versions of software years and years after it’s no longer supported, you shouldn’t be changing anything: no new rules, no new bindings and things and Items, no updates to the OS. It should be a time capsule humming along until something outside the system breaks it and you are forced to upgrade, which is going to be a whole lot more work all at once than keeping up with the upgrades would have been.

Anyway, I was mainly posting for future readers of this thread who balk at how awkward the timer approach in Rules DSL is to show there are better ways. I don’t expect @Javad_Effat_doost to change their rules over to some other language, if for no other reason than for the most part those users who are willing to change have done so already. Anyone left using Rules DSL is likely unwilling to change.

But there is a version of OHRT written in Python that could be used in 2.5 which provides both deferred and gatekeeper. GitHub - rkoshak/openhab-rules-tools at before-npm. I originally wrote OHRT for 2.5 in Jython way back in the OH 2.x days. I converted it to JS Scripting in OH 3.0 because it took some time for Jython support to come to OH 3 and at the time the JS Scripting devs were the only ones willing to help address the needs of managed rules users.

Two different problems. The Thread::sleep problem is a potential problem unrelated to the arraylist index.

Why both a command and an update? Unless you’ve disabled autoupdate, the command will result in an update meaning statge2 receives two updates and the rule runs twice.

How do you know the index is stuck? Log out what you postUpdate and sendCommand in the one rule and log out what is it in the rule that triggers based on the updates. Also log out what’s in the ArrayList. Maybe it’s not what you assume. When code doesn’t work you cannot assume anything. You must verify everything.

It’s less of a problem to use Thread::sleep on OH 3.0+ than it was to use it in Rules DSL in 2.5 and before.

In OH 2.5 there were only five threads (IIRC) available to run rules and there was no lock to prevent the same rule from being triggered again and running in more than one thread at the same time. Since the one rule can take up more than one thread and there are only five threads a long running rule can consume all the available threads and starve out all the rest of your rules, forcing them to wait until one of those long running rules exits before any other rule can run. (OH 1.x and OH 2.x Rules DSL only] Why have my Rules stopped running? Why Thread::sleep is a bad idea

Additional problems includes that each thread running the rule is running the same rule meaning that one thread can modify variables that impact all the other threads running that same rule.

In OH 3.0+ each rule gets it’s very own thread and that thread is locked so you can never have more than one copy of a rule running at a time. So at worst you would starve out that one rule’s ability to run as triggeres queue up and are worked off in sequence instead of starving out all your rules.

But because this is a system started triggered rule, it’s only ever going to be triggered the one time so the risks that come with long running rules is reduced.

3 Likes

I use tread::sleep in other places too! for example it may triggers by users who want to pause the program like this:

rule "pause"
when
    Item pause received command ON
then
    Heater.sendCommand(OFF)
    Thread::sleep(2000)
    Vent.sendCommand(OFF)
    Thread::sleep(2000)
    Fan.sendCommand(OFF)
    Thread::sleep(2000)
    Spray.sendCommand(OFF)
end

can I use these and reduce them to 250 milliseconds?
the reason i’m using tread::sleep is because i’m using MQTT to control some relays and I want to be sure that commands works without any interference, so I added the Tread::sleep. I may be wrong about this. If you have any information about this, it would be helpful. Can I remove them entirely?

one time I added the postUpdate to solve this problem!! it stayed there after that. should have remove them.

I have stage2 shown in basicUI, the number changes. I think there is some error in the system. because when this happens, If I turn off the process, set the stage2 again(I have a set point in the basicUI to set stage2). It does not work. it stuck at the same array index.
consider this: I have two process, each of them has different arrays. when this problem occurs for one process, If I trigger the other process, it easily gets the correct array index, but when I trigger the first one which has the problem, the problem is still there unless i restarts the system.
if with this information, no light shed on the problem, I may have change things …because I turned off the logs entirely, this is due to the SD Card failures. without logs, my cards are working for almost two years without any problem.

I see, I will take care of it. thanks.

No, It is on.

thanks again for your time and patience. :slightly_smiling_face:

You should use timers instead of sleeps in any situation where any given rule can be triggered faster than it takes for the rule to run. The longer the rule takes to run, the higher the likelihood that you’ll starve out all of your rules.

Almost certainly you can remove them. If you are worried about things on the MQTT side, set the QOS on both the MQTT Thing and the subscribers to 2 which will guarantee each message gets delivered and only delivered once.

Though in practice, on a typical LAN, even on a QOS 0 each message gets delivered every time and only delivered once. If for some reason you do need to space these commands out it will be because of the end device, not MQTT.

Don’t solve problems you don’t know you even have and don’t understand. This leads to “Galello’s Column” style problems (tl;dr an engineer wanted to keep columns which are laid on their side on supports at either end from cracking so they added a support in the middle and increased the likelihood that the column cracks instead of reduces it) or brand new problems.

So start without any delays. Then if and only if there are problems start to experimentally determine what delay is actually required and implement the minimum delay required to reliably work. And if your delays lead to a long running rule, use timers instead of sleeps.

This is only going to tell you what you already know, it doesn’t work. It’s not going to tell you why it doesn’t work. For this you need to know the value of everything that the rule is working with and what it does with that data and the only place to get that is from the rule itself.

1 Like