Member of Group Min -> TTS of the cheapest value doesn't work

This code extension will lock the code as long it is in use, in other words it can not be started again while it is running.
In order to use it copy the name of your rule onto the first three dots, copy rhe"when" part of your actual code onto the second three dots and all your code in the “then” part (except the “end”) onto the last three dots.

var Number lastgGasStations = 0
var String lastCheapestGasStation = ""

rule "My cheapest gas station"
when
    Item gGasStations received update
then
    val StringBuilder sb = new StringBuilder
    gGasStations.members.filter[ i | i.state == gGasStations.state].forEach[i | sb.append(", " + i.name) ]
    CheapestGasStation.postUpdate(sb.substring(2))
    if ((lastCheapestGasStation != CheapestGasStation.state.toString || lastgGasStations != gGasStations.state) && now.getHourOfDay() >7 && now.getHourOfDay() <21) {
        lastgGasStations = gGasStations.state as Number
        lastCheapestGasStation = CheapestGasStation.state.toString
        Wohnzimmer_TTS.sendCommand(String::format("xxx %s xxx %.3f Euro", CheapestGasStation.state, (gGasStations.state as DecimalType).floatValue))}
end

Okay i understand it now. :slight_smile:
“Include” gives me a:
missing EOF at ‘include’

include java.util.concurrent.locks.ReentrantLock
val ReentrantLock stompingLock = new ReentrantLock

var Number lastgGasStations = 0
var String lastCheapestGasStation = ""

rule "My cheapest gas station"

when 
    Item gGasStations received update
then
    try {
        stompingLock.lock()
    val StringBuilder sb = new StringBuilder
    gGasStations.members.filter[ i | i.state == gGasStations.state].forEach[i | sb.append(", " + i.name) ]
    CheapestGasStation.postUpdate(sb.substring(2))
    logInfo("***", String::format("%s %.3f Euro", CheapestGasStation.state, (gGasStations.state as DecimalType).floatValue))
    if((lastCheapestGasStation != CheapestGasStation.state || lastgGasStations != gGasStations.state) && now.getHourOfDay() >7 && now.getHourOfDay() <21) {
        lastgGasStations = gGasStations.state as Number
        lastCheapestGasStation = CheapestGasStation.state.toString
        Wohnzimmer_TTS.sendCommand(',' + String::format("%s %.3f Euro", CheapestGasStation.state, (gGasStations.state as DecimalType).floatValue))}

 
    } catch(Throwable t) { }
    finally {
        stompingLock.unlock()
    }
end

You can try first my last example without lock.It work fine.

Okay I will test it. Thank you very much.
Greetings,
Markus


2018-07-04 13:36:44.725 [vent.ItemStateChangedEvent] - Star changed from 1.459 to 1.499

2018-07-04 13:36:44.726 [GroupItemStateChangedEvent] - gGasStations changed from 1.459 to 1.499 through Star

2018-07-04 13:36:45.001 [vent.ItemStateChangedEvent] - Aral_G1_Update changed from 2018-07-04T11:36:44.975+0200 to 2018-07-04T13:36:44.995+0200

2018-07-04 13:36:45.002 [vent.ItemStateChangedEvent] - Shell_G1_Update changed from 2018-07-04T11:36:44.975+0200 to 2018-07-04T13:36:44.995+0200

2018-07-04 13:36:45.003 [vent.ItemStateChangedEvent] - PM_G1_Update changed from 2018-07-04T11:36:44.975+0200 to 2018-07-04T13:36:44.995+0200

2018-07-04 13:36:45.003 [vent.ItemStateChangedEvent] - Aral_G1_Update changed from 2018-07-04T11:36:44.975+0200 to 2018-07-04T13:36:44.998+0200

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

2018-07-04 13:36:45.005 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'My cheapest gas station': null

2018-07-04 13:36:45.007 [INFO ] [g.eclipse.smarthome.model.script.***] - Star, PM_G1 1,499 Euro

2018-07-04 13:36:45.008 [INFO ] [g.eclipse.smarthome.model.script.***] - Star, PM_G1 1,499 Euro

2018-07-04 13:36:45.008 [INFO ] [g.eclipse.smarthome.model.script.***] - Star, PM_G1 1,499 Euro

2018-07-04 13:36:45.011 [INFO ] [g.eclipse.smarthome.model.script.***] - Star, PM_G1 1,499 Euro

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

2018-07-04 13:36:45.011 [vent.ItemStateChangedEvent] - Star_Update changed from 2018-07-04T11:36:44.980+0200 to 2018-07-04T13:36:45.006+0200

2018-07-04 13:36:45.013 [ome.event.ItemCommandEvent] - Item 'Wohnzimmer_TTS' received command Star, PM_G1 1,499 Euro

2018-07-04 13:36:45.015 [ome.event.ItemCommandEvent] - Item 'Wohnzimmer_TTS' received command Star, PM_G1 1,499 Euro

2018-07-04 13:36:45.016 [ome.event.ItemCommandEvent] - Item 'Wohnzimmer_TTS' received command Star, PM_G1 1,499 Euro

2018-07-04 13:36:45.016 [ome.event.ItemCommandEvent] - Item 'Wohnzimmer_TTS' received command Star, PM_G1 1,499 Euro

2018-07-04 13:36:45.016 [vent.ItemStateChangedEvent] - Wohnzimmer_TTS changed from  to Star, PM_G1 1,499 Euro
var Number lastgGasStations = 0
var String lastCheapestGasStation = ""


rule "My cheapest gas station"

when 
    Item gGasStations received update
then
    val StringBuilder sb = new StringBuilder
    gGasStations.members.filter[ i | i.state == gGasStations.state].forEach[i | sb.append(", " + i.name) ]
    CheapestGasStation.postUpdate(sb.substring(2))
    logInfo("***", String::format("%s %.3f Euro", CheapestGasStation.state, (gGasStations.state as DecimalType).floatValue))
    if((lastCheapestGasStation != CheapestGasStation.state || lastgGasStations != gGasStations.state) && now.getHourOfDay() >7 && now.getHourOfDay() <21) {
        lastgGasStations = gGasStations.state as Number
        lastCheapestGasStation = CheapestGasStation.state.toString
        Wohnzimmer_TTS.sendCommand(String::format("%s %.3f Euro", CheapestGasStation.state, (gGasStations.state as DecimalType).floatValue))}
end

I can’t test your situation, because I haven’t installed the bindings and hardware. Sometimes little changes have big effects. This is one. My example I have tested and posted

    if ((lastCheapestGasStation != CheapestGasStation.state.toString || lastgGasStations != gGasStations.state) && now.getHourOfDay() >7 && now.getHourOfDay() <21) {

your code

    if((lastCheapestGasStation != CheapestGasStation.state || lastgGasStations != gGasStations.state) && now.getHourOfDay() >7 && now.getHourOfDay() <21) {

Oh sorry.
Haven’t seen it. I have changed now to CheapestGasStation.state.toString.
Hope that was the only difference to your rule.
Will test it and report.
Thank you very much.
Greetings,
Markus

Hi Harry.
I have tested it and sometimes it’s okay and sometimes it’s stutter again for two or three times.
I think the probelm is that the rule checks the last state of number and string and compares it. That’s okay. If there is no update it will do nothing.
But because of the update of all items in a few milliseconds, the rule starts again (perhaps through an update of the next item a few milliseconds later) before the other rule is at the end.
Greetings,
Markus

Try

Thread::sleep(xxx)

If i use thread::sleep the rule will start again when gGasStations received update or not?
Are the variables = 0 by second run or get them from the first run? Then it could work i think.

Hi Harry.
Have seen this in the logs
2018-07-08 16:42:23.016 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule ‘My cheapest gas station’: null
Any idea? Thanks and greetings,
Markus

Hi Harry.
I got some help from Rich and Udo and the result is:

var Number lastgGasStations = 0
var String lastCheapestGasStation = ""
var Timer timer = null

rule "My cheapest gas station"

when 
    Item gGasStations received update
then
    if(timer === null) {
        timer = createTimer(now.plusSeconds(1), [
    
    val StringBuilder sb = new StringBuilder
    gGasStations.members.filter[ i | i.state == gGasStations.state].forEach[i | sb.append(", " + i.name) ]
    CheapestGasStation.postUpdate(sb.substring(2))
    logInfo("***", String::format("%s %.3f Euro", CheapestGasStation.state, (gGasStations.state as DecimalType).floatValue))
    
    if ((lastCheapestGasStation != CheapestGasStation.state.toString || lastgGasStations != gGasStations.state) && now.getHourOfDay() >7 && now.getHourOfDay() <21) {
        lastgGasStations = gGasStations.state as Number
        lastCheapestGasStation = CheapestGasStation.state.toString
        Wohnzimmer_TTS.sendCommand(String::format("%s %.3f Euro", CheapestGasStation.state, (gGasStations.state as DecimalType).floatValue))
     }
             timer = null
        ])
    }
end

The timer stops the starting of the rule for the last 4 items when they got an update and gives the groupitem enough time to get all items updates to search for the min.

Thank you very much for your help about the last days and weeks.
I am so happy.
Greetings,
Markus