I’m trying to create a rule to calculate a value from two items and post that value to a third item…
The two initial items are both defined as numbers as below with the third item also a number…
Number SERVER1_Swap_Total
"Swap Memory Total [%d]"
(gNet_WGB01AP1001)
{snmp="<[server1:xxxx:.1.3.6.1.4.1.2021.4.3.0:10000]"}
Number SERVER1_Swap_Available
"Swap Memory Available [%d]"
(gNet_WGB01AP1001,gChart)
{snmp="<[server1:xxxx:.1.3.6.1.4.1.2021.4.4.0:10000]"}
Number SERVER1_Swap_Used
"Swap Memory Used [%d]"
(gNet_WGB01AP1001,gChart)
And the rule to perform the calculation and update the third item is as below…
rule "Swap Used Calculation"
when
Member of fgSwapAvailable changed
then
var Host = triggeringItem.name.split("_").get(0)
var Total = Host + "_Swap_Total"
var SwapUsed = ((Total).state as Number) - (triggeringItem.state as Number)
Host_Swap_Used.sendCommand(SwapUsed)
logInfo("SNMP", triggeringItem.name + " - " + Host + " - " + Total)
end
Essentially, the triggering item should contain something like SERVER1_Swap_Available. The first var (Host) splits the triggering item on the _ character and correctly sets the variable Host to SERVER1. The second var (Total) is then set to the string SERVER1_Swap_Total and I’m trying to use this string as the item to obtain a state to perform a calculation, store the result of that calculation in a third variable and then post that value to the state of an item called SERVER1_Swap_Used with the SERVER1 element being the string contained in the Host variable.
import org.eclipse.smarthome.model.script.ScriptServiceUtil
rule "Swap Used Calculation"
when
Member of fgSwapAvailable changed
then
val String Host = triggeringItem.name.split("_").get(0)
val Total = ScriptServiceUtil.getItemRegistry.getItem(Host + "_Swap_Total")
val SwapUsed = (Total.state as Number) - (triggeringItem.state as Number)
Host_Swap_Used.sendCommand(SwapUsed)
logInfo("SNMP", triggeringItem.name + " - " + Host + " - " + Total.name.toString)
end
Yes this is possible, please take a look at this very educative Design pattern of @rlkoshak:
Based on this, I use something like this myself:
val name = triggeringItem.name.split("_").get(0)
val setpoint = AllThermostatSetpoints.members.findFirst[ t | t.name == name + "_SetpointHeat" ] as NumberItem
val temp = AllThermostats.members.findFirst[ t | t.name == name + "_CurrentTemperature" ] as NumberItem
val mode = AllThermostatModes.members.findFirst[ t | t.name == name + "_ThermostatMode"] as NumberItem
So for example I have a rule which is triggered when Member of AllThermostatSetpoints changed or Member of AllThermostats changed, and all items in these groups have a name like Thermostat1_SetpointHeat or Thermostat_CurrentTemperature, respectively.
So the first line gets the base name, so “Thermostat1” in this example. Then setpoint finds the item Thermostat1_SetpointHeat, so that holds that item, and so on.
Subsequently you can use setpoint.state to get the value of the setpoint item, mode.sendCommand to set the value of the Thermostat1_ThermostatMode item, and so on.
Essential in this approach is that all _SetpointHeat items are in the same AllThermostatSetpoints group, and so on.
EDIT: @vzorglub beat me to it, with another nice approach, which might also be more efficient in this case.
I would have pointed to that DP but it’s only worth it when dealing with several items in the same rule
Are we are only dealing with one in this case, it is simpler to use ScriptServiceUtil.getItemRegistry.getItem(
The trick is that you cannot just make up a string like “myItem” and expect the rules interpreter to understand it’s supposed to mean ‘find an Item with name’. Why wouldn’t you be putting it in a message for example; it’s just a string.
So in order to get hold of an actual Item called by “string” name, you need to use a method to find and retrieve that Item - if it exists. Once you’ve got the Item you can look at it’s state, send commands etc.
There’s a couple of non-obvious ways to do that, shown already.