[SOLVED] OH2: I am sure there is a better way to write this rule?

    rule "PumpStation2 update flow and volume"
    when
        Item PumpStation2_Meter received update
    then
        if (Irrigation2_1_Valve.state == ON)
        {
            Irrigation2_1_ValveVolume.postUpdate(PumpStation2_Meter.state as Number)
            Irrigation2_1_ValveFlow.postUpdate(PumpStation2_Flow.state as Number)
        }
        if (Irrigation2_2_Valve.state == ON)
        {
            Irrigation2_2_ValveVolume.postUpdate(PumpStation2_Meter.state as Number)
            Irrigation2_2_ValveFlow.postUpdate(PumpStation2_Flow.state as Number)
        }
        if (Irrigation2_3_Valve.state == ON)
        {
            Irrigation2_3_ValveVolume.postUpdate(PumpStation2_Meter.state as Number)
            Irrigation2_3_ValveFlow.postUpdate(PumpStation2_Flow.state as Number)
        }
        if (Irrigation2_4_Valve.state == ON)
        {
            Irrigation2_4_ValveVolume.postUpdate(PumpStation2_Meter.state as Number)
            Irrigation2_4_ValveFlow.postUpdate(PumpStation2_Flow.state as Number)
        }
        if (Irrigation2_5_Valve.state == ON)
        {
            Irrigation2_5_ValveVolume.postUpdate(PumpStation2_Meter.state as Number)
            Irrigation2_5_ValveFlow.postUpdate(PumpStation2_Flow.state as Number)
        }
        if (Irrigation2_6_Valve.state == ON)
        {
            Irrigation2_6_ValveVolume.postUpdate(PumpStation2_Meter.state as Number)
            Irrigation2_6_ValveFlow.postUpdate(PumpStation2_Flow.state as Number)
        }
        if (Irrigation2_7_Valve.state == ON)
        {
            Irrigation2_7_ValveVolume.postUpdate(PumpStation2_Meter.state as Number)
            Irrigation2_7_ValveFlow.postUpdate(PumpStation2_Flow.state as Number)
        }
        if (Irrigation2_8_Valve.state == ON)
        {
            Irrigation2_8_ValveVolume.postUpdate(PumpStation2_Meter.state as Number)
            Irrigation2_8_ValveFlow.postUpdate(PumpStation2_Flow.state as Number)
        }
        if (Irrigation2_9_Valve.state == ON)
        {
            Irrigation2_9_ValveVolume.postUpdate(PumpStation2_Meter.state as Number)
            Irrigation2_9_ValveFlow.postUpdate(PumpStation2_Flow.state as Number)
        }
end

These valves are a member of the group gIrrigation2Valves, but I am not sure, whether looping through the group would work.

The reason this if monster exists is that the controller send a valve on|off for each valve, but reports the flow and volume under the same topic.

Any hints appreciated.

Try using Design Pattern: Associated Items

You have already used a good naming convention for your items, so implementing it should be quite easy.

Basically, you rule could be (provided you put all Irrigation*_Valve items in a group Irrigation_Valves):

rule "PumpStation2 update flow and volume"
    when
        Item PumpStation2_Meter received update
    then
        Irrigation_Valves.members.filter([item|item.state == ON]).forEach [ item |
          postUpdate(item.name + "Volume", PumpStation2_Meter.state as Number)
          postUpdate(item.name + "Flow", PumpStation2_Flow.state as Number)
        ]
end

Note: untested and written on my phone, might be syntax errors, but should demonstrate the basic principles.

2 Likes

How elegant is this! Nice! :slight_smile:

Much to my bewilderment the postUpdate ‘as Number’ bit errors with
Type mismatch: cannot convert from Number to String(org.eclipse.xtext.xbase.validation.IssueCodes.incompatible_types)

Now why would it do that, given there is a number being served? … and it would not error in the ifs.

Both flow and volume are number types…

Number   Irrigation2_1_ValveVolume          "Stn 2.1: Driveway west [%d l]"                 <water_drops>   (gPumpStation2_ZoneVolumes_Chart, gIrrigation2ValveVolumes, gPersist_rrd4j)
Number   Irrigation2_1_ValveFlow            "Stn 2.1: Driveway west [%d l/min]"             <sprinkler>     (gIrrigation2ValveFlows, gPersist_rrd4j)

I also tried this variant:

(item.name + "Flow").postUpdate(PumpStation2_Flow.state as Number)

… which produced the same error.

Ah, that’s true, the postUpdate action only supports String parameters, but it gets converted to the right type dependant on the Item type. So replace .state as Number with .state.toString and it should work.

1 Like

Works! Thank you.

An alternative is to use this method to get the item and then use the .postUpdate(State state) method.

Anders provided the answer I would have but I did want to address this sentence. If your MQTT reporting topic structure is a problem, do not be afraid to change it if you can. So if the fact that the on/off and flow/volume being reported on the same topic is a problem, consider splitting them into separate topics. A lot of complication can often be avoided sometimes be stepping outside of OH and restructuring things. This isn’t always possible but when it is one should consider it.

I this case, it’s not needed as Anders’ solution handles it cleanly.

1 Like

As always: thanks Rich :slight_smile:

You are absolutely right…

My controllers run on modular software, where Ethernet, MQTT, SPI, temperature (for a unique MAC) (DS18B20) etc. are standard modules… which I am not keen to modify unless absolutely necessary. This particular controller is the odd one out; that is: it simply takes in water flow hall sensor pulses and adds a valve number, by incrementing a counter on pump start (=valve open).
Eight independent valve timers are set to sprinkle in 30 minutes intervals.
My point: I did not want to change the existing modules:

void meter_pulse_counter_isr();
void meter_processing ();
bool meter_values_calculate (uint32_t last_time_counter_collected);
void meter_values_publish (float litres_total);

The state machine transitions:

void meter_initialising ();
void meter_finishing ();
void meter_idling ();

… take care of numbering/sequencing.
A minor thing depending on were one stands… but, I also thought there is a better way, which there was. openHAB’s job is to sort the values away, and report if there are more or less than 8 valves reporting home, then sends an email to check if a valve timer failed (which it does); as they do in the AU sun.