[SOLVED] Referencing item/group names in rules

Hello,

this is a continuation of the previous topic ([SOLVED] Control underfloor heating for multiple floors (OH as thermostat)) - we are getting into the part of the year where I would like to have heating working on its own but I’m struggling with making the code from @Confused work with my own setup. My setup is far less complex, I have altogether 3 zones (Basement Floor, Ground Floor and First Floor) with a standard naming convention (BF_, GF_, FF_). I am collecting the average temperatures into 3 AvgTemp variables which I want compared to the preset temp and the heating turned on/off accordingly. Heating works based on the setup we agreed on the previous topic, so setting e.g. BF_Heat_Need to “ON” turns on the heating for the floor. BF_Target_Temp variables store the preset temperature for the floor (each being a member of gHeatingTargetTemp).

Item example:

Number BF_TEMP1 "Pince hőm. [%.1f °C]" <temperature> (gTemp, BF_AvgTemp) { channel="mqtt:topic:mqttbroker:pince_homero:temperature" }

Group:Number:AVG	BF_AvgTemp	"Átlaghőmérséklet Pince [%.1f °C]"

An here’s the rule itself:

rule "Check heating actuators every 15 minutes"
when
    Time cron "* 0/15 * * * ?" or
    Item gHeatingTargetTemp received update
then
    if (Heating_Mode_Auto.state == ON) {
        var Number hylow = 0
        var Number hyhigh = 0
        gHeatingTargetTemp.members.forEach[ temp |
            if (temp.state !== NULL || temp.state !== UNDEF)
            {
                hylow = (temp.state as Number) - hysteresis
                hyhigh  = (temp.state as Number) + hysteresis
                 var String GroupName = temp.name.substring(0, 3) // set groupname based on first 3 bytes
                if (GroupName+"AvgTemp".value <= hylow && GroupName+"Heat_Need".state == OFF) { //if average temp lower than preset-hysteresis and heating not working
                    GroupName+"Heat_Need".sendCommand(ON) //turn heating on
                }
                if(GroupName+"AvgTemp".value >= hyhigh && GroupName+"Heat_Need".state == ON) { //if average temp higher than preset+hysteresis and heating is working
                    GroupName+"Heat_Need".sendCommand(OFF) // turn heating off
                }
            }
        ]
    }
end

Can you please help with what is the correct way to reference the GroupName_Heat_Need variables & their values correctly? I was looking at the design template but I couldn’t find this specific one (where you are constructing the item name from a variable and a string).

You can easily do this using Jython or…

1 Like

You can’t access an item by combining strings together into a name.

You’ll need to do something like this:

val avgtemp = ScriptServiceUtil.getItemRegistry.getItem(GroupName + "AvgTemp")
val needheat = ScriptServiceUtil.getItemRegistry.getItem(GroupName + "NeedHeat")
if (avgtemp.value <= hylow && needheat.state == OFF) {
  needheat.sendCommand(ON)
}
1 Like

Thanks, I think I’m making progress because there are no errors when the rule is loaded, however when I update the target temp, I’m getting the below error:

2020-10-02 13:03:05.170 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Check heating actuators every 15 minutes': 'value' is not a member of 'org.eclipse.smarthome.core.items.Item'; line 43, column 9, length 13

The rule looks like this now (line 43 is the first if that checks for turning on the heating):

rule "Check heating actuators every 15 minutes"
when
    Time cron "* 0/15 * * * ?" or
    Item gHeatingTargetTemp received update
then
    if (Heating_Mode_Auto.state == ON) { // automatic heating enabled
        var Number hylow = 0
        var Number hyhigh = 0
        gHeatingTargetTemp.members.forEach[ temp |
            if (temp.state !== NULL || temp.state !== UNDEF)
            {
                hylow = (temp.state as Number) - hysteresis
                hyhigh  = (temp.state as Number) + hysteresis
                var String GroupName = temp.name.substring(0, 3) // set groupname based on first 3 bytes
                val avgtemp = ScriptServiceUtil.getItemRegistry.getItem(GroupName + "AvgTemp")
                val needheat = ScriptServiceUtil.getItemRegistry.getItem(GroupName + "Heat_Need")
                if (avgtemp.value <= hylow && needheat.state == OFF) { //if average temp lower than preset-hysteresis and heating is not working
                    needheat.sendCommand(ON) //turn heating on
                }
                if (avgtemp.value >= hyhigh && needheat.state == ON) { //if average temp higher than preset+hysteresis and heating is working
                    needheat.sendCommand(OFF) // turn heating off
                }
            }
        ]
    }
end

I’m sorry, I forgot that as it doesn’t know what type of item it is, you’ll need to cast it:

if ((avgtemp.state as Number) <= hylow && needheat.state == OFF) {

1 Like

Thanks @Confused, it’s working now. No more cold feet :smiley:

Here’s the entire rule in case somebody wants to look at it:

rule "Check heating actuators every 15 minutes"
when
    Time cron "* 0/15 * * * ?" or
    Item gHeatingTargetTemp received update
then
    if (Heating_Mode_Auto.state == ON) { // automatic heating enabled
        var Number hylow = 0
        var Number hyhigh = 0
        gHeatingTargetTemp.members.forEach[ temp |
            if (temp.state !== NULL || temp.state !== UNDEF)
            {
                hylow = (temp.state as Number) - hysteresis
                hyhigh  = (temp.state as Number) + hysteresis
                var String GroupName = temp.name.substring(0, 3) // set groupname based on first 3 bytes
                val avgtemp = ScriptServiceUtil.getItemRegistry.getItem(GroupName + "AvgTemp")
                val needheat = ScriptServiceUtil.getItemRegistry.getItem(GroupName + "Heat_Need")
                if ((avgtemp.state as Number) <= hylow && needheat.state == OFF) { //if average temp lower than preset-hysteresis and heating is not working
                    needheat.sendCommand(ON) //turn heating on
                }
                if ((avgtemp.state as Number) >= hyhigh && needheat.state == ON) { //if average temp higher than preset+hysteresis and heating is working
                    needheat.sendCommand(OFF) // turn heating off
                }
            }
        ]
    }
end

Or I think you can specify it in the creation of the variable, for less repetition?

val Number avgtemp = ScriptServiceUtil.getItemRegistry.getItem(GroupName + "AvgTemp")
if (avgtemp <= hylow)...

That doesn’t work for some reason. Keeps throwing this error:

2020-10-02 13:17:05.779 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Check heating actuators every 15 minutes': Could not invoke method: org.eclipse.smarthome.model.script.lib.NumberExtensions.operator_lessEqualsThan(java.lang.Number,java.lang.Number) on instance: null

Ah, OK, stick with what you’ve got working then :smiley:

1 Like