Skip to content

# Script Condition

The Script condition allows you to write an arbitrarily complex expression as a Rule condition. The expression must result in a boolean (true/false) value or null, just like any other condition. If the expression produces any other value as its final result, Reactor will issue a warning alert.

Here's a simple Script condition:

This script has a simple expression that returns the `power_switch.state` attribute of a switch (a boolean value). The condition will therefore be true when the switch is on, and false when the switch is off. This is, in essence, an expression implementation of an Entity condition.

But let's say you wanted to do something a little more complicated. Here's a Script condition expression that takes temperature and humidity from a Z-Wave sensor and converts it to a "comfort" value, and then returns true if the value is outside of a comfortable range.

    local idealTemp = 22.0,
    local idealRH = 50.0,
    local comfortLimit = 50,  /* 0 is lowest comfort, 100 is highest */

    local sensor = getEntity( "zwavejs>6-0" ),
    local temp = max(0, min(40, sensor.attributes.temperature_sensor.value)),
    local rh = sensor.attributes.humidity_sensor.value,

    local tempDiff = abs(temp - idealTemp),
    local tempDiscomfort = tempDiff * tempDiff * 0.8,
    local sticky = pow(abs(rh - idealRH) / 10 + max(0, rh - idealRH) * 0.5, 2) * 15,
    local comfort = 100 - max(0, min(100, tempDiscomfort + sticky ) ),

    comfort < comfortLimit

Notice that the last statement in the expression is a comparison using the less-than (`<`) operator. This produces the required boolean value that all Script condition expressions must return. In this case, true means we are below the comfort level limit and, perhaps, action can be taken in the Set Reaction of our Rule to restore ambient temperature and humidity to pleasant values.

Just for information, the graph below shows the "comfort zone" (green) computation by this script (horizontal axis is temperature, vertical is relative humidity):

Script conditions can access global variables/expressions. They can also access local variables/expressions defined on the same Rule just like Variable Value conditions. All you need to do is refer to them by name in the expression. For example, one could choose to declare the `idealTemp`, `idealRH`, and `comfortLimit` constants as Global or Rule-based variables, and remove those lines from the Script expression.

Script conditions can also set the value of expressionless variables with a normal variable assignment statement. If the variable `comfort` was also declared as a global or Rule-based expressionless variable, its value would be updated every time the Script condition is evaluated. This would be handy, so you can see what the script actually computed to make the final comparison.

You can also set temporary variables. If you were to just enter the script expression above and create no Rule-based variables for any of those variables named, all of the variables in the example would be temporary variables. Beyond their use in the single Script condition, these variables are available to the Rule's other Script conditions and to the Rule's Script actions in its Set and Reset Reactions. You can, therefore, use these temporary variables to pass data between conditions and actions. However, unlike declared Rule-based variables (in the Rule under Expressions), the values of these temporary variables do not survive restarts of the Rule or Reactor.

Script conditions are sensitive to changes in Global and Rule-based expressions they reference — changes to referenced variables will cause a re-evaluation of the Rule's conditions. The exception is a variable that the Script condition expression itself changes — these are ignored to prevent infinite re-evaluation loops.

Special functions that work in Rule-based variables/expressions also work in Script conditions, so you can use `getEntity()`, `isRuleSet()`, and so on.

The `alarm()` function also works in Script conditions. When used, the expiration of the alarm timer causes the Rule's conditions to be re-evaluated, including the Script condition that set the alarm. The timer used for the `alarm()` function is bound to the condition (i.e. there's only one timer per Script condition). However, you can create any number of Script conditions in a Rule, and each will have its own, separate timer.

Use of `performAction()`

While the `performAction()` function currently works in Script conditions, this may not be supported in future. Users are advised to avoid doing this.

Future Direction

If this works out as I expect/hope, the use of Script conditions and actions will eventually replace the functionality of Rule-based expressions/variables.

## Tips for Debugging Scripts

When scripts grow beyond a couple of lines, it can become challenging to troubleshoot/debug them. Here are some things you can do to make life a little easier:

- Use the `print()` expression function to print diagnostic information and variable values in your expression. This function writes its output to the log file.

- Declare a temporary variable as a Rule-based variable (in the Expressions section of the Rule Editor) and it's final value will be captured and displayed in the Reactor UI.

- Reactor's script language extensions include a `dumpVars()` function that can be used anywhere in a script to dump the current values of all known variables (including temporary and globals).

Updated: 2025-Nov-10