Rule-file-global varibles not accessible by all rules


I have used OpenHAB for a while for simpler tasks. I would now like to implement a PID regulator as a rule. I have used the ivPID ( as a starting point.

The problem is that I cannot get “global” variables to work. I understood from the documentation and from other forum posts that variables can be defined as global (where the global scope is the rule file) if they are declared outside of the rules. Some variables work from some rules, but not from all and I do not understand why. I know I could use items to store the calculations, but as I do not (at this point) intend to use them for anything I prefer to keep them hidden from event logs etc. by defining them as variables.

Please note the code is not complete, I have only added few functions to start off at some point.
Rule file:
import javax.measure.quantity
// PID regulator
// MF2020 - Based on ivPID Python code
val Kp = 0.07 as Number
val Ki = 0.0007 as Number
val Kd = 0 as Number
var sample_time = 0.0 as Number
var current_time = (now.getMillis() as Number)
var last_time = (now.getMillis() as Number)
var PTerm = (0.0 as Number).doubleValue
var ITerm = (0.0 as Number).doubleValue
var DTerm = (0.0 as Number).doubleValue
var last_error = 0.0 as Number
var error = 0.0 as Number
var windup_guard = 0.0 as Number
var output = (0.0 as Number).doubleValue
var max_output = 20 as Number
var min_output = 0 as Number

// Trigger updates
rule "shuntti_pid_update_trig" when Item pannu_paluuvesi received update then
        if (shuntti_pid_active.state == ON) {
                shuntti_pid_update.sendCommand((pannu_paluuvesi.state as QuantityType<Number>).doubleValue)

// Clear PID calculations
rule "shuntti_pid_clear_f" when Item shuntti_pid_active changed then
    logInfo("Shuntti_PID", "Cleared calculations")
    PTerm = (0.0 as Number).doubleValue
    ITerm = (0.0 as Number).doubleValue
    DTerm = (0.0 as Number).doubleValue
    last_error = 0.0 as Number
    error = 0.0 as Number
    windup_guard = 0.0 as Number
    output = 0.0 as Number


// Update PID calculation
rule “shuntti_pid_update_f” when Item shuntti_pid_update received command then
logInfo(“Shuntti_PID”, “Starting”)
error = ((shuntti_pid_setpoint.state as Number) - (shuntti_pid_update.state as Number))
current_time = now().getMillis() as Number
var delta_time = (current_time-last_time) as Number
var delta_error = (error - last_error) as Number

        if (delta_time >= sample_time){
                PTerm = Kp * error
                ITerm = ITerm + (error * delta_time)

                if (ITerm < -windup_guard) {
                        ITerm = -windup_guard
                else if (ITerm > windup_guard) {
                        ITerm = windup_guard
                if (delta_time > 0) {
                        logInfo("Shuntti_PID", "C1")
                        var Dtermc = delta_error / delta_time
                        logInfo("Shuntti_PID", Dtermc.toString())
                        Dterm = Dtermc

                last_time = current_time
                last_error = error
                logInfo("Shuntti_PID", "A")
                output = PTerm + (Ki * ITerm) + (Kd * Dterm)
//              var x_output = Pterm
                logInfo("Shuntti_PID", Pterm.toString())
                logInfo("Shuntti_PID", Ki.toString())
                logInfo("Shuntti_PID", ITerm.toString())
                output = PTerm + (Ki * ITerm)
                logInfo("Shuntti_PID", "G")
                if (output < min_output) {
                        output = min_output
                        logInfo("Shuntti_PID", "H")
                } else if (output > max_output) {
                        output = max_output
                        logInfo("Shuntti_PID", "I")
                logInfo("Shuntti_PID", "D")

To test the rule, I have activated (sent cmd ON) to shuntti_pid_activate (to run shuntti_pid_clear_f) and waited for the temperature pannu_panuuvesi to update.

2020-05-05 14:56:47.348 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model ‘shuntti_pid.rules’
2020-05-05 14:56:53.626 [INFO ] [e.smarthome.model.script.Shuntti_PID] - Cleared calculations
2020-05-05 14:57:58.789 [INFO ] [e.smarthome.model.script.Shuntti_PID] - Starting
2020-05-05 14:57:58.817 [INFO ] [e.smarthome.model.script.Shuntti_PID] - C1
2020-05-05 14:57:58.823 [INFO ] [e.smarthome.model.script.Shuntti_PID] - 0.00010255
2020-05-05 14:57:58.825 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule ‘shuntti_pid_update_f’: An error occurred during the script execution: Couldn’t invoke ‘assignValueTo’ for feature JvmVoid: (eProxyURI: shuntti_pid.rules#|::

What confuses me is that writing to some of the variables seem to work, but not to all. I have added some logInfo lines to show more clearly where the rule aborts (when setting Dterm = dTermc).
I think my variable declarations are overkill, but I tried to make them more specific to fix it, however without success. If I understand it correctly, based on missing errors, the shuntti_pid_clear_f can write to Dterm, but not shuntti_pid_update_f.

Thankful for any advice!

Items defined as follows, however I don’t know if relevant:
Number shuntti_pid_setpoint
Switch shuntti_pid_active
Number shuntti_pid_output
Number shuntti_pid_update
Switch shuntti_pid_clear

When starting, shuntti_pid_active is OFF, but changed to ON. shuntti_pid_setpoint is set to a numeric value (25).

  • Platform information:
    • Hardware: Raspberry Pi 3B+
    • OS: Raspbian + OpenHAB docker image
    • Java Runtime Environment: Standard from OpenHAB Docker image
    • openHAB version: 2.5

I think I’d start by simplifying typing. Treat Number as “native” type for DSL rules.

var Number DTerm = 0.0

I think you may be trying to assign a Number to a primitive double in your rule.

Thank you for your help!

I tried to re-define the variables as follows. Unfortunately, it still fails at the same point.
Variable definitions:
val Number Kp = 0.07
val Number Ki = 0.0007
val Number Kd = 0
var Number sample_time = 0.0
var Number current_time = (now.getMillis() as Number)
var Number last_time = (now.getMillis() as Number)
var Number PTerm = 0.0
var Number ITerm = 0.0
var Number DTerm = 0.0
var Number last_error = 0.0
var Number error = 0.0
var Number windup_guard = 0.0
var Number output = 0.0
var Number max_output = 20
var Number min_output = 0

2020-05-05 16:01:42.506 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model ‘shuntti_pid.rules’
2020-05-05 16:01:52.222 [INFO ] [e.smarthome.model.script.Shuntti_PID] - Cleared calculations
2020-05-05 16:02:11.539 [INFO ] [e.smarthome.model.script.Shuntti_PID] - Starting
2020-05-05 16:02:11.566 [INFO ] [e.smarthome.model.script.Shuntti_PID] - C1
2020-05-05 16:02:11.572 [INFO ] [e.smarthome.model.script.Shuntti_PID] - 0.00030334
2020-05-05 16:02:11.574 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule ‘shuntti_pid_update_f’: An error occurred during the script execution: Couldn’t invoke ‘assignValueTo’ for feature JvmVoid: (eProxyURI: shuntti_pid.rules#|::

The code that causes the error:
logInfo(“Shuntti_PID”, “C1”)
var Dtermc = delta_error / delta_time
logInfo(“Shuntti_PID”, Dtermc.toString())
Dterm = Dtermc

One of these things is not like the other, missed it before. T/t


Thank you! That solved the problem. It is too easy to be blinded by ones own code… :slight_smile: :man_facepalming:

It usually comes up with a more meaningful error than that.