How to define global variables in Rules?

Hi,

it’s a general question about openHAB 3 and Rules. I have desperately researched, but found nothing zufriendstellendes. Supposedly this would work if I would use JavaScript. But I simply do not want to.

I have a rule that worked in openHAB 2 without any problems:

import java.util.List
import java.util.ArrayList

var List<GenericItem> hueLampsMWColor = null
var List<GenericItem> hueLampsMWToggle = null
var List<GenericItem> hueLampsMWCT = null
var List<GenericItem> hueLampsMWBright = null

var List<HSBType> rainbowColors = null


rule "Initialize"
when
        // Rule is executed every time system is restarted or rules-file is reloaded
        System started
then
        // Initialize array with mw lamps color items in correct order
        if(hueLampsMWColor === null){
                hueLampsMWColor = new ArrayList<GenericItem>
                hueLampsMWColor.add(iMultimedia_Hue_Lampe1_Farbe)
                hueLampsMWColor.add(iMultimedia_Hue_Lampe2_Farbe)
                hueLampsMWColor.add(iMultimedia_Hue_Lampe3_Farbe)
                hueLampsMWColor.add(iMultimedia_Hue_Lampe4_Farbe)
                hueLampsMWColor.add(iMultimedia_Hue_Lampe5_Farbe)
                hueLampsMWColor.add(iMultimedia_Hue_Lampe6_Farbe)
                logInfo("rules", "List: hueLampsMWColor initialized")
        }

        // Initialize array with mw lamps toggle items in correct order
        if(hueLampsMWToggle === null){
                hueLampsMWToggle = new ArrayList<GenericItem>
                hueLampsMWToggle.add(iMultimedia_Hue_Lampe1_Schalter)
                hueLampsMWToggle.add(iMultimedia_Hue_Lampe2_Schalter)
                hueLampsMWToggle.add(iMultimedia_Hue_Lampe3_Schalter)
                hueLampsMWToggle.add(iMultimedia_Hue_Lampe4_Schalter)
                hueLampsMWToggle.add(iMultimedia_Hue_Lampe5_Schalter)
                hueLampsMWToggle.add(iMultimedia_Hue_Lampe6_Schalter)
                logInfo("rules", "List: hueLampsMWToggle initialized")
        }

        // Initialize array with mw lamps temperature items in correct order
        if(hueLampsMWCT === null){
                hueLampsMWCT = new ArrayList<GenericItem>
                hueLampsMWCT.add(iMultimedia_Hue_Lampe1_Farbtemperatur)
                hueLampsMWCT.add(iMultimedia_Hue_Lampe2_Farbtemperatur)
                hueLampsMWCT.add(iMultimedia_Hue_Lampe3_Farbtemperatur)
                hueLampsMWCT.add(iMultimedia_Hue_Lampe4_Farbtemperatur)
                hueLampsMWCT.add(iMultimedia_Hue_Lampe5_Farbtemperatur)
                hueLampsMWCT.add(iMultimedia_Hue_Lampe6_Farbtemperatur)
                logInfo("rules", "List: hueLampsMWTemperature initialized")
        }

        // Initialize array with mw lamps brightness items in correct order
        if(hueLampsMWBright === null){
                hueLampsMWBright = new ArrayList<GenericItem>
                hueLampsMWBright.add(iMultimedia_Hue_Lampe1_Helligkeit)
                hueLampsMWBright.add(iMultimedia_Hue_Lampe2_Helligkeit)
                hueLampsMWBright.add(iMultimedia_Hue_Lampe3_Helligkeit)
                hueLampsMWBright.add(iMultimedia_Hue_Lampe4_Helligkeit)
                hueLampsMWBright.add(iMultimedia_Hue_Lampe5_Helligkeit)
                hueLampsMWBright.add(iMultimedia_Hue_Lampe6_Helligkeit)
                logInfo("rules", "List: hueLampsMWBright initialized")
        }

        // Initialize hand selected rainbow colors
        if(rainbowColors === null){
                rainbowColors = new ArrayList<HSBType>
                rainbowColors.add(HSBType.fromRGB(255,0,0))
                rainbowColors.add(HSBType.fromRGB(255,127,0))
                rainbowColors.add(HSBType.fromRGB(255,255,0))
                rainbowColors.add(HSBType.fromRGB(127,255,0))
                rainbowColors.add(HSBType.fromRGB(0,255,0))
                rainbowColors.add(HSBType.fromRGB(0,255,127))
                rainbowColors.add(HSBType.fromRGB(0,255,255))
                rainbowColors.add(HSBType.fromRGB(0,127,255))
                rainbowColors.add(HSBType.fromRGB(0,0,255))
                rainbowColors.add(HSBType.fromRGB(127,0,255))
                rainbowColors.add(HSBType.fromRGB(255,0,255))
                rainbowColors.add(HSBType.fromRGB(255,0,127))
                logInfo("rules", "List: rainbowColors initialized")
        }

        logInfo("rules", "Initialization of global states is done")
end

rule "WindowsOpen"
when
        Item iKonferenz_Homematic_Fenster1_Position changed to OPEN or
        Item iKonferenz_Homematic_Fenster2_Position changed to OPEN or
        Item iKonferenz_Homematic_Fenster3_Position changed to OPEN or
        Item iKonferenz_Homematic_Fenster4_Position changed to OPEN or
        Item iKonferenz_Homematic_Fenster5_Position changed to OPEN or
        Item iKonferenz_Homematic_Fenster6_Position changed to OPEN or
        Item iMultimedia_Homematic_Fenster1_Position changed to OPEN or
        Item iMultimedia_Homematic_Fenster2_Position changed to OPEN or
        Item iMultimedia_Homematic_Fenster3_Position changed to OPEN

then
        logInfo("rules", "Fenster 1 state {}", iKonferenz_Homematic_Fenster1_Position.state.toString)
        logInfo("rules", "Fenster 2 state {}", iKonferenz_Homematic_Fenster2_Position.state.toString)
        logInfo("rules", "Fenster 3 state {}", iKonferenz_Homematic_Fenster3_Position.state.toString)
        logInfo("rules", "Fenster 4 state {}", iKonferenz_Homematic_Fenster4_Position.state.toString)
        logInfo("rules", "Fenster 5 state {}", iKonferenz_Homematic_Fenster5_Position.state.toString)
        logInfo("rules", "Fenster 6 state {}", iKonferenz_Homematic_Fenster6_Position.state.toString)

        logInfo("rules", "Windows open")

        if((iKonferenz_Homematic_Fenster1_Position.state == "TILTED") ||
                (iKonferenz_Homematic_Fenster2_Position.state == "TILTED") ||
                (iKonferenz_Homematic_Fenster3_Position.state == "TILTED") ||
                (iKonferenz_Homematic_Fenster4_Position.state == "TILTED") ||
                (iKonferenz_Homematic_Fenster5_Position.state == "TILTED") ||
                (iKonferenz_Homematic_Fenster6_Position.state == "TILTED") ||
                (iMultimedia_Homematic_Fenster1_Position.state == "TILTED") ||
                (iMultimedia_Homematic_Fenster2_Position.state == "TILTED") ||
                (iMultimedia_Homematic_Fenster3_Position.state == "TILTED")) {

                logInfo("rules", "One or more windows are tilted or opened")

                // Show red lamps
                for(var int i = 0; i < hueLampsMWToggle.size(); i++){
                        hueLampsMWToggle.get(i).sendCommand(ON)
                }
                Thread::sleep(100)
                for(var int i = 0; i < hueLampsMWBright.size(); i++){
                        hueLampsMWBright.get(i).sendCommand(100)
                }
                Thread::sleep(100)
                for(var int i = 0; i < hueLampsMWColor.size(); i++){
                        hueLampsMWColor.get(i).sendCommand(HSBType.RED)
                }
        } else {
                logInfo("rules", "One or more windows are opened")

                // Show red lamps
                for(var int i = 0; i < hueLampsMWToggle.size(); i++){
                        hueLampsMWToggle.get(i).sendCommand(ON)
                }
                Thread::sleep(100)
                for(var int i = 0; i < hueLampsMWBright.size(); i++){
                        hueLampsMWBright.get(i).sendCommand(100)
                }
                Thread::sleep(100)
                for(var int i = 0; i < hueLampsMWColor.size(); i++){
                        hueLampsMWColor.get(i).sendCommand(HSBType.RED)
                }
        }
        logInfo("rules", "Windows open")
end

rule "WindowsTilted"
when
        Item iKonferenz_Homematic_Fenster1_Position changed to TILTED or
        Item iKonferenz_Homematic_Fenster2_Position changed to TILTED or
        Item iKonferenz_Homematic_Fenster3_Position changed to TILTED or
        Item iKonferenz_Homematic_Fenster4_Position changed to TILTED or
        Item iKonferenz_Homematic_Fenster5_Position changed to TILTED or
        Item iKonferenz_Homematic_Fenster6_Position changed to TILTED or
        Item iMultimedia_Homematic_Fenster1_Position changed to TILTED or
        Item iMultimedia_Homematic_Fenster2_Position changed to TILTED or
        Item iMultimedia_Homematic_Fenster3_Position changed to TILTED

then
        logInfo("rules", "Fenster 1 state {}", iKonferenz_Homematic_Fenster1_Position.state.toString)
        logInfo("rules", "Fenster 2 state {}", iKonferenz_Homematic_Fenster2_Position.state.toString)
        logInfo("rules", "Fenster 3 state {}", iKonferenz_Homematic_Fenster3_Position.state.toString)
        logInfo("rules", "Fenster 4 state {}", iKonferenz_Homematic_Fenster4_Position.state.toString)
        logInfo("rules", "Fenster 5 state {}", iKonferenz_Homematic_Fenster5_Position.state.toString)
        logInfo("rules", "Fenster 6 state {}", iKonferenz_Homematic_Fenster6_Position.state.toString)

        logInfo("rules", "Windows tilted")

        if((iKonferenz_Homematic_Fenster1_Position.state == "OPEN") ||
                (iKonferenz_Homematic_Fenster2_Position.state == "OPEN") ||
                (iKonferenz_Homematic_Fenster3_Position.state == "OPEN") ||
                (iKonferenz_Homematic_Fenster4_Position.state == "OPEN") ||
                (iKonferenz_Homematic_Fenster5_Position.state == "OPEN") ||
                (iKonferenz_Homematic_Fenster6_Position.state == "OPEN") ||
                (iMultimedia_Homematic_Fenster1_Position.state == "OPEN") ||
                (iMultimedia_Homematic_Fenster2_Position.state == "OPEN") ||
                (iMultimedia_Homematic_Fenster3_Position.state == "OPEN")) {

                logInfo("rules", "One or more windows are tilted or opened")

                // Show red lamps
                for(var int i = 0; i < hueLampsMWToggle.size(); i++){
                        hueLampsMWToggle.get(i).sendCommand(ON)
                }
                Thread::sleep(100)
                for(var int i = 0; i < hueLampsMWBright.size(); i++){
                        hueLampsMWBright.get(i).sendCommand(100)
                }
                Thread::sleep(100)
                for(var int i = 0; i < hueLampsMWColor.size(); i++){
                        hueLampsMWColor.get(i).sendCommand(HSBType.RED)
                }
        } else {
                logInfo("rules", "One or more windows are tilted")

                // Show green lamps
                for(var int i = 0; i < hueLampsMWToggle.size(); i++){
                        hueLampsMWToggle.get(i).sendCommand(ON)
                }
                Thread::sleep(100)
                for(var int i = 0; i < hueLampsMWBright.size(); i++){
                        hueLampsMWBright.get(i).sendCommand(100)
                }
                Thread::sleep(100)
                for(var int i = 0; i < hueLampsMWColor.size(); i++){
                        hueLampsMWColor.get(i).sendCommand(HSBType.GREEN)
                }
        }
        logInfo("rules", "Windows tilted")
end

rule "WindowsClosed"
when
        Item iKonferenz_Homematic_Fenster1_Position changed to CLOSED or
        Item iKonferenz_Homematic_Fenster2_Position changed to CLOSED or
        Item iKonferenz_Homematic_Fenster3_Position changed to CLOSED or
        Item iKonferenz_Homematic_Fenster4_Position changed to CLOSED or
        Item iKonferenz_Homematic_Fenster5_Position changed to CLOSED or
        Item iKonferenz_Homematic_Fenster6_Position changed to CLOSED or
        Item iMultimedia_Homematic_Fenster1_Position changed to CLOSED or
        Item iMultimedia_Homematic_Fenster2_Position changed to CLOSED or
        Item iMultimedia_Homematic_Fenster3_Position changed to CLOSED
then
        logInfo("rules", "Fenster 1 state {}", iKonferenz_Homematic_Fenster1_Position.state.toString)
        logInfo("rules", "Fenster 2 state {}", iKonferenz_Homematic_Fenster2_Position.state.toString)
        logInfo("rules", "Fenster 3 state {}", iKonferenz_Homematic_Fenster3_Position.state.toString)
        logInfo("rules", "Fenster 4 state {}", iKonferenz_Homematic_Fenster4_Position.state.toString)
        logInfo("rules", "Fenster 5 state {}", iKonferenz_Homematic_Fenster5_Position.state.toString)
        logInfo("rules", "Fenster 6 state {}", iKonferenz_Homematic_Fenster6_Position.state.toString)

        logInfo("rules", "Windows closed")

        if((iKonferenz_Homematic_Fenster1_Position.state == "CLOSED" || iKonferenz_Homematic_Fenster1_Position.state === NULL || iKonferenz_Homematic_Fenster1_Position.state == UNDEF) &&
                (iKonferenz_Homematic_Fenster2_Position.state == "CLOSED" || iKonferenz_Homematic_Fenster2_Position.state === NULL || iKonferenz_Homematic_Fenster2_Position.state == UNDEF) &&
                (iKonferenz_Homematic_Fenster3_Position.state == "CLOSED" || iKonferenz_Homematic_Fenster3_Position.state === NULL || iKonferenz_Homematic_Fenster3_Position.state == UNDEF) &&
                (iKonferenz_Homematic_Fenster4_Position.state == "CLOSED" || iKonferenz_Homematic_Fenster4_Position.state === NULL || iKonferenz_Homematic_Fenster4_Position.state == UNDEF) &&
                (iKonferenz_Homematic_Fenster5_Position.state == "CLOSED" || iKonferenz_Homematic_Fenster5_Position.state === NULL || iKonferenz_Homematic_Fenster5_Position.state == UNDEF) &&
                (iKonferenz_Homematic_Fenster6_Position.state == "CLOSED" || iKonferenz_Homematic_Fenster6_Position.state === NULL || iKonferenz_Homematic_Fenster6_Position.state == UNDEF) &&
                (iMultimedia_Homematic_Fenster1_Position.state == "CLOSED" || iMultimedia_Homematic_Fenster1_Position.state === NULL || iMultimedia_Homematic_Fenster1_Position.state == UNDEF) &&
                (iMultimedia_Homematic_Fenster2_Position.state == "CLOSED" || iMultimedia_Homematic_Fenster2_Position.state === NULL || iMultimedia_Homematic_Fenster2_Position.state == UNDEF) &&
                (iMultimedia_Homematic_Fenster3_Position.state == "CLOSED" || iMultimedia_Homematic_Fenster3_Position.state === NULL || iMultimedia_Homematic_Fenster3_Position.state == UNDEF)) {

                logInfo("rules", "All windows are closed")

                // Switch lamps off
                for(var int i = 0; i < hueLampsMWBright.size(); i++){
                        hueLampsMWBright.get(i).sendCommand(100)
                }
                Thread::sleep(100)
                for(var int i = 0; i < hueLampsMWColor.size(); i++){
                        hueLampsMWColor.get(i).sendCommand(HSBType.WHITE)
                }
                Thread::sleep(100)
                for(var int i = 0; i < hueLampsMWToggle.size(); i++){
                        hueLampsMWToggle.get(i).sendCommand(OFF)
                }
        } else {
                if((iKonferenz_Homematic_Fenster1_Position.state == "OPEN") ||
                        (iKonferenz_Homematic_Fenster2_Position.state == "OPEN") ||
                        (iKonferenz_Homematic_Fenster3_Position.state == "OPEN") ||
                        (iKonferenz_Homematic_Fenster4_Position.state == "OPEN") ||
                        (iKonferenz_Homematic_Fenster5_Position.state == "OPEN") ||
                        (iKonferenz_Homematic_Fenster6_Position.state == "OPEN") ||
                        (iMultimedia_Homematic_Fenster1_Position.state == "OPEN") ||
                        (iMultimedia_Homematic_Fenster2_Position.state == "OPEN") ||
                        (iMultimedia_Homematic_Fenster3_Position.state == "OPEN")) {

                        logInfo("rules", "One or more windows are opened")

                        // Show red lamps
                        for(var int i = 0; i < hueLampsMWToggle.size(); i++){
                                hueLampsMWToggle.get(i).sendCommand(ON)
                        }
                        Thread::sleep(100)
                        for(var int i = 0; i < hueLampsMWBright.size(); i++){
                                hueLampsMWBright.get(i).sendCommand(100)
                        }
                        Thread::sleep(100)
                        for(var int i = 0; i < hueLampsMWColor.size(); i++){
                                hueLampsMWColor.get(i).sendCommand(HSBType.RED)
                        }
                } else if((iKonferenz_Homematic_Fenster1_Position.state == "TILTED" && iKonferenz_Homematic_Fenster1_Position.state != "OPEN") ||
                        (iKonferenz_Homematic_Fenster2_Position.state == "TILTED" && iKonferenz_Homematic_Fenster2_Position.state != "OPEN") ||
                        (iKonferenz_Homematic_Fenster3_Position.state == "TILTED" && iKonferenz_Homematic_Fenster3_Position.state != "OPEN") ||
                        (iKonferenz_Homematic_Fenster4_Position.state == "TILTED" && iKonferenz_Homematic_Fenster4_Position.state != "OPEN") ||
                        (iKonferenz_Homematic_Fenster5_Position.state == "TILTED" && iKonferenz_Homematic_Fenster5_Position.state != "OPEN") ||
                        (iKonferenz_Homematic_Fenster6_Position.state == "TILTED" && iKonferenz_Homematic_Fenster6_Position.state != "OPEN") ||
                        (iMultimedia_Homematic_Fenster1_Position.state == "TILTED" && iMultimedia_Homematic_Fenster1_Position.state != "OPEN") ||
                        (iMultimedia_Homematic_Fenster2_Position.state == "TILTED" && iMultimedia_Homematic_Fenster2_Position.state != "OPEN") ||
                        (iMultimedia_Homematic_Fenster3_Position.state == "TILTED" && iMultimedia_Homematic_Fenster3_Position.state != "OPEN")) {

                        logInfo("rules", "One or more windows are tilted")

                        // Show green lamps
                        for(var int i = 0; i < hueLampsMWToggle.size(); i++){
                                hueLampsMWToggle.get(i).sendCommand(ON)
                        }
                        Thread::sleep(100)
                        for(var int i = 0; i < hueLampsMWBright.size(); i++){
                                hueLampsMWBright.get(i).sendCommand(100)
                        }
                        Thread::sleep(100)
                        for(var int i = 0; i < hueLampsMWColor.size(); i++){
                                hueLampsMWColor.get(i).sendCommand(HSBType.GREEN)
                        }
                } else {
                        logInfo("rules", "One or more windows are opened or tilted")

                        // Show red lamps
                        for(var int i = 0; i < hueLampsMWToggle.size(); i++){
                                hueLampsMWToggle.get(i).sendCommand(ON)
                        }
                        Thread::sleep(100)
                        for(var int i = 0; i < hueLampsMWBright.size(); i++){
                                hueLampsMWBright.get(i).sendCommand(100)
                        }
                        Thread::sleep(100)
                        for(var int i = 0; i < hueLampsMWColor.size(); i++){
                                hueLampsMWColor.get(i).sendCommand(HSBType.RED)
                        }
                }
        }
        logInfo("rules", "Windows Closed")
end

What I could find was that in all the rules my “global” variables were zero. In openHAB 2, as I said, the approach was that I had a trigger with System started that I could use to initialize the variables for all the Rules. I can not do that outside of this rule, because at a system start, for example, not all items would be loaded. Otherwise I could do the whole thing outside of the rule. That’s for sure not the solution:

import java.util.List
import java.util.ArrayList

var List<GenericItem> hueLampsMWColor = null
var List<GenericItem> hueLampsMWToggle = null
var List<GenericItem> hueLampsMWCT = null
var List<GenericItem> hueLampsMWBright = null

var List<HSBType> rainbowColors = null

// Initialize array with mw lamps color items in correct order
if(hueLampsMWColor === null){
        hueLampsMWColor = new ArrayList<GenericItem>
        hueLampsMWColor.add(iMultimedia_Hue_Lampe1_Farbe)
        hueLampsMWColor.add(iMultimedia_Hue_Lampe2_Farbe)
        hueLampsMWColor.add(iMultimedia_Hue_Lampe3_Farbe)
        hueLampsMWColor.add(iMultimedia_Hue_Lampe4_Farbe)
        hueLampsMWColor.add(iMultimedia_Hue_Lampe5_Farbe)
        hueLampsMWColor.add(iMultimedia_Hue_Lampe6_Farbe)
        logInfo("rules", "List: hueLampsMWColor initialized")
}

// Initialize array with mw lamps toggle items in correct order
if(hueLampsMWToggle === null){
        hueLampsMWToggle = new ArrayList<GenericItem>
        hueLampsMWToggle.add(iMultimedia_Hue_Lampe1_Schalter)
        hueLampsMWToggle.add(iMultimedia_Hue_Lampe2_Schalter)
        hueLampsMWToggle.add(iMultimedia_Hue_Lampe3_Schalter)
        hueLampsMWToggle.add(iMultimedia_Hue_Lampe4_Schalter)
        hueLampsMWToggle.add(iMultimedia_Hue_Lampe5_Schalter)
        hueLampsMWToggle.add(iMultimedia_Hue_Lampe6_Schalter)
        logInfo("rules", "List: hueLampsMWToggle initialized")
}

// Initialize array with mw lamps temperature items in correct order
if(hueLampsMWCT === null){
        hueLampsMWCT = new ArrayList<GenericItem>
        hueLampsMWCT.add(iMultimedia_Hue_Lampe1_Farbtemperatur)
        hueLampsMWCT.add(iMultimedia_Hue_Lampe2_Farbtemperatur)
        hueLampsMWCT.add(iMultimedia_Hue_Lampe3_Farbtemperatur)
        hueLampsMWCT.add(iMultimedia_Hue_Lampe4_Farbtemperatur)
        hueLampsMWCT.add(iMultimedia_Hue_Lampe5_Farbtemperatur)
        hueLampsMWCT.add(iMultimedia_Hue_Lampe6_Farbtemperatur)
        logInfo("rules", "List: hueLampsMWTemperature initialized")
}

// Initialize array with mw lamps brightness items in correct order
if(hueLampsMWBright === null){
        hueLampsMWBright = new ArrayList<GenericItem>
        hueLampsMWBright.add(iMultimedia_Hue_Lampe1_Helligkeit)
        hueLampsMWBright.add(iMultimedia_Hue_Lampe2_Helligkeit)
        hueLampsMWBright.add(iMultimedia_Hue_Lampe3_Helligkeit)
        hueLampsMWBright.add(iMultimedia_Hue_Lampe4_Helligkeit)
        hueLampsMWBright.add(iMultimedia_Hue_Lampe5_Helligkeit)
        hueLampsMWBright.add(iMultimedia_Hue_Lampe6_Helligkeit)
        logInfo("rules", "List: hueLampsMWBright initialized")
}

// Initialize hand selected rainbow colors
if(rainbowColors === null){
        rainbowColors = new ArrayList<HSBType>
        rainbowColors.add(HSBType.fromRGB(255,0,0))
        rainbowColors.add(HSBType.fromRGB(255,127,0))
        rainbowColors.add(HSBType.fromRGB(255,255,0))
        rainbowColors.add(HSBType.fromRGB(127,255,0))
        rainbowColors.add(HSBType.fromRGB(0,255,0))
        rainbowColors.add(HSBType.fromRGB(0,255,127))
        rainbowColors.add(HSBType.fromRGB(0,255,255))
        rainbowColors.add(HSBType.fromRGB(0,127,255))
        rainbowColors.add(HSBType.fromRGB(0,0,255))
        rainbowColors.add(HSBType.fromRGB(127,0,255))
        rainbowColors.add(HSBType.fromRGB(255,0,255))
        rainbowColors.add(HSBType.fromRGB(255,0,127))
        logInfo("rules", "List: rainbowColors initialized")
}

I have a few questions about this now. Also because of such aspects as the scalability.

  • Is it at all possible that multiple rules access one and the same variable in openHAB 3?
  • Is it possible to access variables with the same name only within one text file or could I create multiple xxx.rules files and only in one of these files a variable is initialized?
  • The cross check: Can I create global variables in two or more different xxx.rules files without them interfering with each other? So quasi if global variables are global only within one file.

What is clear to me is that val works in multiple rules because I just assign a final value outside there. As described above, I don’t want to keep null when I use var, but I want my “init” method to change this so that I don’t have to repeat this step in all three rules.

Thanks in advance.

It will work the same in OH 3 with one difference. The System started trigger now does exactly what it says, it triggers when openHAB has started. If after OH has started the .rules file is reloaded, that rule will not trigger again because OH hasn’t restarted.

However, reloading a .rules file means everything in that file is unloaded/destroyed, including the “global” variables (they are not truly global, just global to this one file).

There is an issue open to add a “file loaded” trigger or somesuch but I don’t think it’s been implemented and merged. So in the mean time you can run the System started rule manually from MainUI or the Karaf Console. Or you can restart OH itself when you change this one file.

Yes if and only if they are in the same .rules file. The same general answer goes for the other languages too.

There is also a registry that has been implemented but not yet merged that can be used as a way to share data between rules not defined in the same file (UI rules don’t even have a file so without this there is no sharing at all). JS Scripting, in the mean time, has a cache which is simpler but serves the same purpose as the registry.

There used to a subtle issue in Rules DSL which required you to use unique names for all your “global” variables, even if they are defined in separate files. But I think that was fixed but maybe not.

See above.

If you really care about scalability, Rules DSL is a poor choice for language. Almost every language feature that addresses that sort of thing simply does not exist in Rules DSL or, when it exists, is significantly limited.

Another alternative would be to put your System started method into a lambda (see Reusable Functions: A simple lambda example with copious notes) and put the test for null in the rules that depend on these variables being initialized and call that lambda from the rule.

However, looking at what these variables do and what you use them for, I’m going to guess you don’t know about Groups and their various uses.

For example, you could replace the global variable hueLampsMWColor with a Group Item that has all those Items as its members. Then you can replace

                for(var int i = 0; i < hueLampsMWColor.size(); i++){
                        hueLampsMWColor.get(i).sendCommand(HSBType.RED)
                }

with

hueLampsMWColor.sendCommand(HSBType.RED)

So not only do your rules become simpler, you don’t even need the System started rule nor the global variables in the first place.

Using Groups the code above could be reduced to:

rule "WindowsOpen"
when
    Member of Windows changed to OPEN
then
    Windows.members.forEach[ i, window | logInfo("rules", "{} state {}", window.label, window.state)]

    logInfo("rules", "Windows open")

    // Let's just count the number of open windows
    if(Windows.members.filter[ window | window.state == "TILTED"].size > 0) {
        // You can turn on, turn up the brightness and set the color to RED in one command
        // A command to the Group goes to all its members
        hueLampsMWColor.sendCommand("0,100,100")
    } 
    else {
        logInfo("rules", "One or more windows are opened")
        hueLampsMWColor.sendCommand("0,100,100") // Why does it do the same thing?
    }
    logInfo("rules", "Windows open")
end

OK, now that I’ve done that I notice something, this rule will command the lights to RED no matter what. So why have the if statement in the first place. You want the light to be on and red if and window is open or tilted. So let’s just do that.

The same for closed but this actually doesn’t make sense. If any one window is OPEN or TILTED you set the light to red. But if, for example, you have 3 windows open and close one of them, all the light will turn off even though two windows are still open. Wouldn’t you want to wait for all the windows to be CLOSED?

To do that, set the aggregation function on Windows to AND(CLOSED,OPEN). That will set the state of Windows to CLOSED only when all its members are CLOSED.

rule "Windows Open or Tilted"
when
    Member of Windows changed to TILTED or
    Member of Windows changed to OPEN
then
    Windows.members.forEach[ i, window | logInfo("rules", "{} state {}", window.label, window.state)]

    logInfo("rules", "Windows OPEN or TILTED")
    
    // the fact that this rule triggered we know at least one window is now open or tilted
    hueLampsMWColor.sendCommand("0,100,100")

    logInfo("rules", "Windows open or tilted")
end

rule "Windows Closed"
when
    Item Windows changed to CLOSED
then
    Windows.members.forEach[ i, window | logInfo("rules", "{} state {}", window.label, window.state)]
    
    logInfo("rules", "All windows are closed")

    hueLampsMWColor.sendCommand("0,0,0")

    logInfo("rules", "Windows Closed")
end

I looked up the colors online to get the HSB values. But hopefully you can see by using Groups we can do the same thing without globals, a System started rule, and in fewer lines of code as just one of the three rules.

We could go even further.

rule "Windows Lights"
when
    Member of Windows changed
then
    Windows.members.forEach[ i, window | logInfo("rules", "{} state {}", window.label, window.state)]

    var newState = "0,0,0"

    if(Windows.members.filter[ window | window.state == "OPEN" || window.state == "TILTED" ].size > 0) {
        logInfo("rules", "At least one window is OPEN or TILTED")
        newState = "0,100,100"
    }
    else {
        logInfo("rules", "All windows are CLOSED")
    }

    // Adjust the lights
    hueLampsMWToggle.sendCommand(newState)
end
1 Like

For the sake of completeness, the rule has changed as follows:

rule "Windows Lights"
when
    Member of WindowPosition changed
then
    logInfo("rules", "Window positions changed")

    WindowPosition.members.forEach[ window |
        logInfo("rules", "Window position of {} changed to state {}", window.name, window.state)
    ]

    var toggleState = "OFF"
    var brightnessState = 0
    var colorState = HSBType.WHITE

    if(WindowPosition.members.filter[ window | window.state == "OPEN" ].size > 0) {
        logInfo("rules", "At least one window is OPEN or TILTED")
        toggleState = "ON"
        brightnessState = 100
        colorState = HSBType.RED

        hueLampsMWBright.sendCommand(brightnessState)
        hueLampsMWColor.sendCommand(colorState)
    } else if(WindowPosition.members.filter[ window | window.state == "TILTED" ].size > 0) {
        toggleState = "ON"
        brightnessState = 100

        if(WindowPosition.members.filter[ window | window.state == "OPEN" ].size > 0) {
            logInfo("rules", "At least one window is OPEN or TILTED")
            colorState = HSBType.RED
        } else {
            logInfo("rules", "At least one window is TILTED")
            colorState = HSBType.GREEN
        }

        hueLampsMWBright.sendCommand(brightnessState)
        hueLampsMWColor.sendCommand(colorState)
    } else {
        logInfo("rules", "All windows are CLOSED")
    }

    hueLampsMWToggle.sendCommand(toggleState)
end

I tested it out when sending the brightness and color, I had to include this in the if branches because otherwise the lamps would switch back to white when turned off.