No calculation in rule

  • Platform information:
    • Hardware: Raspberry Pi 3 Model B Rev 1.2
    • OS: Raspbian GNU/Linux 10 (buster)
    • Java Runtime Environment: openjdk version “1.8.0_222”
    • openHAB version: openHAB 2.5.8-1
  • Issue of the topic: Calculation in the rule does not work

Sorry to bother with this I guess very basic question …
I am trying to calculate some values inside a rule with other values defined in that rule.
I feel it could be a big basic mistake in how I use data types and conversions but not sure at all.
Here is the rule with comments so you hopefully can understand what is intended:

// values that can change (different reservoirs, distance of sensor)
// Distance (Sensor) to max Waterlevel in cm
val int Zisterne_Abstand = 5
// height reservoir in cm
val int Zisterne_Gesamthoehe = 130
// ground level not usable in cm
val int Zisterne_Bodensatz = 5
// diameter of reservoir
val int Zisterne_Durchmesser = 80

// fixed value of pi (circle constant)
val float pi = 3.141592

// first calculations
// max usable waterlevel from data before
val int Zisterne_maximal =  Zisterne_Gesamthoehe - (Zisterne_Abstand + Zisterne_Bodensatz)
// calculate radius from diameter
val int Zisterne_Radius = Zisterne_Durchmesser / 2


rule "Inhalt Liter aus Fuellhoehe"
when
	// when item Zisterne_Distanz is updated because sensor sends a value
    Item Zisterne_Distanz received update
then
	// calculate usable number from the Item status
    var int Zisterne_Hoehe_gemessen = (Zisterne_Distanz.state as Number).intValue
    // calculate current waterlevel from: (see above: usable waterlevel Zisterne_maximal)
    // subtract actual distance; actual distance = Zisterne_Hoehe_gemessen - Zisterne_Abstand
    var int Zisterne_Wasserstand_aktuell = (Zisterne_maximal - (Zisterne_Hoehe_gemessen - Zisterne_Abstand))
    // itermediate step: Liter calculated from Zisternenradius, Pi, usable waterlevel
    var float Zisterne_Liter1 = ((Zisterne_Radius * Zisterne_Radius) * pi *  Zisterne_Wasserstand_aktuell) / 1000
    // convert float to int / Liter
    var int Zisterne_Liter2 = Math::round(Zisterne_Liter1)

    // Update of the Item which contains liter
    Zisterne_Liter.postUpdate(Zisterne_Liter2)
end

Definition of the used items:

Number Zisterne_Distanz "Distanz gemessen Zisterne [%s cm]" <incline> 
Number Zisterne_Liter "Inhalt (nutzbar) Zisterne in Liter [%s l]" <water>

I can update the item Zisterne_Distanz from the sensor via REST, no problem. E.g. with 15 (cm).
But then nothing else is calculated.

What am I doing wrong (guess a lot)?

There are errors in the log:

2022-01-09 11:47:43.695 [vent.ItemStateChangedEvent] - Zisterne_Distanz changed from 16 to 15


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

2022-01-09 11:49:22.418 [WARN ] [me.internal.engine.RuleContextHelper] - Variable 'Zisterne_maximal' on rule file 'Zisterne.rules' cannot be initialized with value '<XFeatureCallImplCustom> - <XBinaryOperationImplCustom>': An error occurred during the script execution: Could not invoke method: org.eclipse.xtext.xbase.lib.IntegerExtensions.operator_plus(int,int) on instance: null

2022-01-09 11:49:22.492 [WARN ] [me.internal.engine.RuleContextHelper] - Variable 'Zisterne_Radius' on rule file 'Zisterne.rules' cannot be initialized with value '<XFeatureCallImplCustom> / <XNumberLiteralImpl>': An error occurred during the script execution: Could not invoke method: org.eclipse.xtext.xbase.lib.IntegerExtensions.operator_divide(int,int) on instance: null

2022-01-09 11:49:22.542 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Inhalt Liter und Fuellstand in % aus gemessenem Abstand': An error occurred during the script execution: Could not invoke method: org.eclipse.xtext.xbase.lib.IntegerExtensions.operator_minus(int,int) on instance: null

Unfortunately I am not able to interpret in the right way …

Thanks a lot!
Andreas

Declaring these outside of a rule will not work. “Global” variables cannot “see” each other in the file-level environment.
In other words
x = 1
y = x + 1
cannot work as a “global”, y cannot see x

That’s okay, all these are fixed numbers anyway. Just assign the constant, don’t calculate it.

Hi @rossko57 ,
thanks for your fast reply.
Does it mean I need to do the calculation part inside the rule?
I would like to calculate the derived values because the base values like Zisterne_Gesamthoehe, Zisterne_Abstand, Zisterne_Bodensatz etc. might vary from time to time …
Thanks again!

Ok, just tried it.
The following works:

// values that can change (different reservoirs, distance of sensor)
// Distance (Sensor) to max Waterlevel in cm
val int Zisterne_Abstand = 5
// height reservoir in cm
val int Zisterne_Gesamthoehe = 130
// ground level not usable in cm
val int Zisterne_Bodensatz = 5
// diameter of reservoir
val int Zisterne_Durchmesser = 80

// fixed value of pi (circle constant)
val float pi = 3.141592


rule "Inhalt Liter aus Fuellhoehe"
when
	// when item Zisterne_Distanz is updated because sensor sends a value
    Item Zisterne_Distanz received update
then
	// first calculations
    // max usable waterlevel from data before
    val int Zisterne_maximal =  Zisterne_Gesamthoehe - (Zisterne_Abstand + Zisterne_Bodensatz)
    // calculate radius from diameter
    val int Zisterne_Radius = Zisterne_Durchmesser / 2
    
    // calculate usable number from the Item status
    var int Zisterne_Hoehe_gemessen = (Zisterne_Distanz.state as Number).intValue
    // calculate current waterlevel from: (see above: usable waterlevel Zisterne_maximal)
    // subtract actual distance; actual distance = Zisterne_Hoehe_gemessen - Zisterne_Abstand
    var int Zisterne_Wasserstand_aktuell = (Zisterne_maximal - (Zisterne_Hoehe_gemessen - Zisterne_Abstand))
    // itermediate step: Liter calculated from Zisternenradius, Pi, usable waterlevel
    var float Zisterne_Liter1 = ((Zisterne_Radius * Zisterne_Radius) * pi *  Zisterne_Wasserstand_aktuell) / 1000
    // convert float to int / Liter
    var int Zisterne_Liter2 = Math::round(Zisterne_Liter1)

    // Update of the Item which contains liter
    Zisterne_Liter.postUpdate(Zisterne_Liter2)
end

Thanks for the hint in the right direction :slight_smile:

1 Like