Docs
/
Tags
/

Expression Tags

Expression Tags

Expression tags compute their value from a formula evaluated by the Expression Evaluator service. Expressions can reference tags, devices, AI models, and model bindings, use arithmetic and logical operators, and call built-in math and statistical functions.

Expressions are evaluated in one of two ways:

  • Reactive — when any referenced tag's value changes, the expression re-evaluates immediately (within milliseconds). This is the default when the expression references at least one tag value.
  • Timer-based — if the expression has no reactive tag dependencies (e.g. it only references device or model status), it evaluates on a configurable interval set by the Evaluation Rate field.

Common use cases include:

  • Unit conversions (e.g. Celsius to Fahrenheit)
  • Scaling raw signals (e.g. 4–20 mA to 0–100%)
  • Averaging multiple sensors
  • Smoothing noisy readings with time-aware filters
  • Computing rate of change for trend detection
  • Status-based fallback logic (switch to backup sensor if primary fails)
  • Alarm thresholds with deadband filtering
  • Health monitoring (react to device or model failures)

References

Type @ in the expression editor to search and insert a reference. The autocomplete menu shows tags, devices, AI models, and model bindings — each with the fields you can reference.

Tag References

Reference a tag's live value, status, or error code:

@[Temperature Sensor:value]       → current numeric value
@[Temperature Sensor:status]      → 1 if running, 0 if stopped/failed
@[Temperature Sensor:error_code]  → numeric error code (0 = no error)

Tag value references are reactive — the expression re-evaluates immediately when the referenced tag's value changes.

Device References

Reference a device's connection status or error code:

@[OPC-UA Server 1:status]      → 1 if running, 0 if stopped/failed
@[OPC-UA Server 1:error_code]  → numeric error code (0 = no error)

Device references are useful for building failover logic — for example, switching to a backup device's tags when the primary device goes down.

Model References

Reference an AI model's status or error code:

@[Chiller Model:status]      → 1 if running, 0 if stopped/failed
@[Chiller Model:error_code]  → numeric error code (0 = no error)

Binding References

Reference the raw prediction value from a model output binding:

@[Chiller Model / Supply Temp:value]       → the binding's output value
@[Chiller Model / Supply Temp:status]      → 1 if running, 0 if stopped/failed
@[Chiller Model / Supply Temp:error_code]  → numeric error code (0 = no error)

Binding value references give you access to a model's prediction output without needing an in-memory tag to historize it first.

Arithmetic Operations

Standard math operators are supported:

OperationSymbolExampleResult
Addition+5 + 38
Subtraction-10 - 46
Multiplication*6 * 742
Division/20 / 45.0
Power**2 ** 38
Modulo%10 % 31

Comparison Operations

Comparisons return True or False and are commonly used inside conditional expressions:

OperationSymbolExampleResult
Equal==5 == 5True
Not Equal!=5 != 3True
Greater Than>10 > 5True
Less Than<3 < 7True
Greater or Equal>=5 >= 5True
Less or Equal<=3 <= 5True

Logical Operations

Combine conditions with and, or, and not:

True and True    → True
True or False    → True
not True         → False

Math Functions

Built-in math functions for common calculations:

FunctionDescriptionExampleResult
sin(x)Sine (radians)sin(1.5708)1.0
cos(x)Cosine (radians)cos(3.14159)-1.0
tan(x)Tangent (radians)tan(0.7854)1.0
sqrt(x)Square rootsqrt(16)4.0
exp(x)e raised to power xexp(1)2.718
log(x)Natural logarithmlog(2.71828)1.0
log10(x)Base-10 logarithmlog10(100)2.0
fabs(x)Absolute valuefabs(-5.5)5.5
ceil(x)Round up to integerceil(4.3)5
floor(x)Round down to integerfloor(4.7)4
trunc(x)Truncate to integertrunc(4.7)4
pow(x, y)x raised to power ypow(2, 3)8
degrees(x)Radians to degreesdegrees(3.14159)180.0
radians(x)Degrees to radiansradians(180)3.14159

Statistical Functions

Functions that operate on lists of values:

FunctionDescriptionExampleResult
mean(list)Average of valuesmean([1, 2, 3, 4, 5])3.0
median(list)Middle valuemedian([1, 3, 5, 7, 9])5
min(list)Minimum valuemin([5, 2, 8, 1, 9])1
max(list)Maximum valuemax([5, 2, 8, 1, 9])9
sum(list)Sum of all valuessum([1, 2, 3, 4, 5])15

Filter Functions

Filter functions smooth, transform, or gate input signals. They maintain internal state across evaluations, so each call remembers its previous output.

filter — Exponential Moving Average

filter(value, tau) applies an exponential moving average. The tau parameter is the time constant in seconds — it controls how quickly the output tracks the input, regardless of how often the expression evaluates.

ParameterDescription
valueThe current input value
tauTime constant in seconds. Larger values = more smoothing

At each evaluation the filter computes: alpha = 1 - e^(-dt / tau), then output = alpha x input + (1 - alpha) x previous. On the first evaluation the output equals the input.

ExpressionDescriptionUse Case
filter(@[Temperature:value], 5)5-second time constantFast-changing signals, light smoothing
filter(@[Pressure:value], 30)30-second time constantModerate noise reduction
filter(@[Level:value], 120)2-minute time constantVery noisy sensors, stable reading needed

moving_avg — Moving Average

moving_avg(value, window) computes the average of all samples received within the last window seconds.

ParameterDescription
valueThe current input value
windowWindow size in seconds
ExpressionDescription
moving_avg(@[Flow:value], 60)Average flow over the last 60 seconds
moving_avg(@[Power:value], 300)5-minute rolling average of power consumption

rate — Rate of Change

rate(value) returns the rate of change of the input in units per second. It only updates when the input actually changes, so repeated evaluations with a stale value don't distort the result.

ParameterDescription
valueThe current input value
ExpressionDescription
rate(@[Temperature:value])Degrees per second of temperature change
rate(@[Level:value]) * 60Level change per minute

deadband — Deadband Filter

deadband(value, threshold) only passes through changes larger than threshold. The output holds its last accepted value until the input moves far enough away.

ParameterDescription
valueThe current input value
thresholdMinimum change to pass through (must be > 0)
ExpressionDescription
deadband(@[Setpoint:value], 0.5)Ignore changes smaller than 0.5
deadband(filter(@[Noisy:value], 10), 1.0)Smooth first, then deadband

Conditional Expressions

Use Python's ternary syntax for if-else logic:

value_if_true if condition else value_if_false
ExpressionDescription
1 if @[Switch:value] == 1 else 0Binary output based on switch state
@[Temp:value] * 1.8 + 32 if @[Units:value] == 1 else @[Temp:value]Convert to Fahrenheit if units flag is set
"High" if @[Level:value] > 80 else "Low"Text output based on threshold
100 if @[Valve:value] == 1 else 50 if @[Valve:value] == 0.5 else 0Multiple conditions (nested)

Practical Examples

Temperature Conversion

Celsius to Fahrenheit:

@[Temperature C:value] * 1.8 + 32

Scaling and Offset

Convert a 4–20 mA signal to 0–100%:

(@[Current:value] - 4) * 100 / 16

Average of Multiple Sensors

(@[Sensor1:value] + @[Sensor2:value] + @[Sensor3:value]) / 3

Status-Based Fallback

Use a backup sensor if the primary tag fails:

@[Primary:value] if @[Primary:status] == 1 else @[Backup:value]

Device Failover

Switch to a backup device's sensor when the primary device connection goes down:

@[Primary Sensor:value] if @[Primary OPC-UA:status] == 1 else @[Backup Sensor:value]

Model Health Check

Output 1 when the AI model is running, 0 when it's stopped or failed:

1 if @[Chiller Model:status] == 1 else 0

Alarm with Deadband

High alarm with a 5-unit deadband — turns on above 95, off below 90, holds previous state in between:

1 if @[Process:value] > 95 else (0 if @[Process:value] < 90 else @[Alarm:value])

Smoothed Differential

Smoothed pressure differential with a 30-second time constant:

filter(@[Pressure In:value] - @[Pressure Out:value], 30)

Rate of Temperature Change

Degrees per minute:

rate(@[Supply Temp:value]) * 60

Smoothed Deadband

Reduce noise first, then gate small changes:

deadband(filter(@[Vibration:value], 10), 0.5)