# Formula Language

You can compute values derived from raw tag values by writing formulae similar to JavaScript expressions. The formulae are continuously evaluated as input tag values change. Currently, Clarity supports using formulae for notification conditions, but it may support them for more uses in the future.

## Examples

Test if either `tag1` or `tag2` is not available (`null`):

<pre><code><strong>tagValue("tag1") === null || tagValue("tag2") === null
</strong></code></pre>

Test if `flow` is less than 10 (in whatever units the tag has) while pumping, assmuing that the `pumping` tag is a `boolean`:

```
tagValue("pumping") && tagValue("flow") < 10
```

Test if `flow` has been above 10 (in whatever units the tag has) for at least an hour:

```
conditionHoldsFor(tagValue("flow") > 10, 1h)
```

Test if the max of three tags is above another tag:

```
max(
  tagValue("pressure1"),
  tagValue("pressure2"),
  tagValue("pressure3")
) > tagValue("pressureLimit")
```

## Language Reference

### Data Types

Formulae support JavaScript `number`, `boolean`, and `string` data types, as well as `null` (used when a value isn't available for a tag or an expression on that tag). Numbers are represented as 64-bit floating point values, although when performing bitwise operations, they are first converted to 32-bit integer values, then the result is converted back to a 64-bit floating point value.

#### No Coercion to Number or Boolean

Unlike JavaScript, formula won't automatically coerce other data types to `number` or `boolean` values, and any operation on mismatched data types (except for string concatenation with `+`) will be flagged as an error.

#### `null` propagation

Unlike JavaScript, the result of an arithmetic, bitwise, or comparison operation will be `null` if one of the operands is `null`. For example the expression `tagValue("a") + tagValue("b")` will be `null` if the value of either of the two tags is `null` (not available).

#### No `NaN`

Unlike JavaScript, there is no `NaN` constant; `null` is returned instead, for example from `0 / 0`.

### Keywords

`true`, `false`, and `null` have the same values as in JSON.

### Number Literals

As in JSON, a number may consist of decimal digits `0`-`9`, optional digits after a decimal place `.`, and and optional positive or negative exponent `e8` or `e-8`.

### String Literals

As in JSON, a string literal consists of text between double quotes (`"`), for example:

```
"hello world"
```

The backslash (`\`) allows you to escape special characters:

| Escape sequence                           | Actual Value      |
| ----------------------------------------- | ----------------- |
| `\\`                                      | `\`               |
| `\"`                                      | `"`               |
| `\n`                                      | newline           |
| `\r`                                      | carriage return   |
| `\t`                                      | horizontal tab    |
| `\b`                                      | backspace         |
| `\f`                                      | form feed         |
| `\u0000` (any hex digits, up to `\uffff`) | unicode character |

### Time Intervals

Some functions accept time intervals as arguments; a time interval is a number with a time unit suffix, for example:

| Literal | Meaning        |
| ------- | -------------- |
| `3s`    | 3 seconds      |
| `5ms`   | 5 milliseconds |
| `10m`   | 10 minutes     |
| `1h`    | 1 hour         |
| `3d`    | 3 days         |

### Built-in Functions

#### `tagValue(<tag>)`

Gets the value of the given `<tag>` at the current time. `<tag>` must be a string literal, for example:

```
tagValue("Site 1/battery/1/lifetimeWh")
```

`tagValue(<tag>)` may evaluate to a `number`, `string`, `boolean`, depending on the data type of the given tag, or `null` if a value for the given tag is not available at the current time.

#### `tagIsNAFor(<tag>, <interval>)`

Evaluates to `true` if the given `<tag>` has been unavailable for at least the given amount of time. If there is or was a value available for the tag more recently than the given amount of time before the present, evaluates to `false`.

`<tag>` must be a string literal and `<interval>` must be a [time interval](#time-intervals), for example:

```
tagIsNAFor("Site 1/battery/1/lifetimeWh", 5m)
```

#### `maxChange(<expression>, <interval>)`

Evaluates to the maximum amount the given `<expression>` has changed over the given `<interval>` of time since the present. Always evaluates to a positive number, the absolute difference between the minimum and maximum values of `<expression>` over the past `<interval>`.

`<expression>` can be any expression that evaluates to a `number` or `null`.

`<interval>` must be a [time interval](#time-intervals) no greater than one day.

#### `conditionHoldsFor(<expression>, <interval>)`

Evaluates to `true` if the given `<expression>` has remained `true` over the given `<interval>` of time since the present. Otherwise, evaluates to `false`.

`<expression>` can be any expression that evaluates to a `boolean` or `null`.

`<interval>` must be a [time interval](#time-intervals) no greater than one day.

#### Math functions

The following JavaScript `Math` functions are available:

<table><thead><tr><th width="297">Function</th><th>Description</th></tr></thead><tbody><tr><td><code>abs(x)</code></td><td>Returns the absolute value of <code>x</code>.</td></tr><tr><td><code>acos(x)</code></td><td>Returns the arccosine of <code>x</code>.</td></tr><tr><td><code>acosh(x)</code></td><td>Returns the hyperbolic arccosine of <code>x</code>.</td></tr><tr><td><code>asin(x)</code></td><td>Returns the arcsine of <code>x</code>.</td></tr><tr><td><code>asinh(x)</code></td><td>Returns the hyperbolic arcsine of <code>x</code>.</td></tr><tr><td><code>atan(x)</code></td><td>Returns the arctangent of <code>x</code>.</td></tr><tr><td><code>atan2(y, x)</code></td><td>Returns the arctangent of the quotient of its arguments.</td></tr><tr><td><code>atanh(x)</code></td><td>Returns the hyperbolic arctangent of <code>x</code>.</td></tr><tr><td><code>cbrt(x)</code></td><td>Returns the cube root of <code>x</code>.</td></tr><tr><td><code>ceil(x)</code></td><td>Returns the smallest integer greater than or equal to <code>x</code>.</td></tr><tr><td><code>cos(x)</code></td><td>Returns the cosine of <code>x</code>.</td></tr><tr><td><code>exp(x)</code></td><td>Returns ex, where x is the argument, and e is Euler's number (<code>2.718</code>…, the base of the natural logarithm).</td></tr><tr><td><code>expm1(x)</code></td><td>Returns subtracting <code>1</code> from <code>exp(x)</code>.</td></tr><tr><td><code>floor(x)</code></td><td>Returns the largest integer less than or equal to <code>x</code>.</td></tr><tr><td><code>fround(x)</code></td><td>Returns the nearest <a href="https://en.wikipedia.org/wiki/Single-precision_floating-point_format">single precision</a> float representation of <code>x</code>.</td></tr><tr><td><code>hypot(value1, ...values)</code></td><td>Returns the square root of the sum of squares of its arguments.</td></tr><tr><td><code>imul(x, y)</code></td><td>Returns the result of the 32-bit integer multiplication of <code>x</code> and <code>y</code>.</td></tr><tr><td><code>log(x)</code></td><td>Returns the natural logarithm (㏒e; also, ㏑) of <code>x</code>.</td></tr><tr><td><code>log10(x)</code></td><td>Returns the base-10 logarithm of <code>x</code>.</td></tr><tr><td><code>log1p(x)</code></td><td>Returns the natural logarithm (㏒e; also ㏑) of <code>1 + x</code> for the number <code>x</code>.</td></tr><tr><td><code>max(value1, ...values)</code></td><td>Returns the largest of zero or more numbers.</td></tr><tr><td><code>min(value1, ...values)</code></td><td>Returns the smallest of zero or more numbers.</td></tr><tr><td><code>pow(x, y)</code></td><td>Returns base <code>x</code> to the exponent power <code>y</code>.</td></tr><tr><td><code>round(x)</code></td><td>Returns the value of the number <code>x</code> rounded to the nearest integer.</td></tr><tr><td><code>sign(x)</code></td><td>Returns the sign of the <code>x</code>, indicating whether <code>x</code> is positive, negative, or zero.</td></tr><tr><td><code>sin(x)</code></td><td>Returns the sine of <code>x</code>.</td></tr><tr><td><code>sinh(x)</code></td><td>Returns the hyperbolic sine of <code>x</code>.</td></tr><tr><td><code>sqrt(x)</code></td><td>Returns the positive square root of <code>x</code>.</td></tr><tr><td><code>tan(x)</code></td><td>Returns the tangent of <code>x</code>.</td></tr><tr><td><code>trunc(x)</code></td><td>Returns the integer portion of <code>x</code>, removing any fractional digits.</td></tr></tbody></table>

### Operators

All operators are computed as in JavaScript, except that [no coercion to number or boolean is supported](#no-coercion-to-number-or-boolean).

When performing bitwise operations, the operands are first converted to 32-bit integer values, then the result of the operation is converted back to a 64-bit floating point value.

#### Equality and Strict Equality

Unlike JavaScript, the non-strict `==` and `!=` operators evaluate to `null` if either operand is `null`. That is, whereas in JavaScript, `null == null` is `true`, in Clarity formulae, `null == null` is `null`.

If you want to test for `null`, use the `===` and `!==` operators; `null === null` is true.

<table><thead><tr><th width="211">Precedence</th><th width="138">Associativity</th><th>Individual Operators</th></tr></thead><tbody><tr><td>grouping</td><td>n/a</td><td><code>(x)</code></td></tr><tr><td>prefix operators</td><td>n/a</td><td>Logical NOT <code>!x</code><br>Bitwise NOT <code>~x</code><br>Negation <code>-x</code></td></tr><tr><td>exponentiation</td><td>right-to-left</td><td><code>x ** y</code></td></tr><tr><td>multiplicative</td><td>left-to-right</td><td>Multiplication <code>x * y</code><br>Division <code>x / y</code><br>Remainder <code>x % y</code></td></tr><tr><td>additive</td><td>left-to-right</td><td>Addition <code>x + y</code><br>Subtraction <code>x - y</code></td></tr><tr><td>bitwise shift</td><td>left-to-right</td><td>Left shift <code>x &#x3C;&#x3C; y</code><br>Right shift <code>x >> y</code><br>Unsigned right shift <code>x >>> y</code></td></tr><tr><td>comparison</td><td>left-to-right</td><td>Less than <code>x &#x3C; y</code><br>Less than or equal <code>x &#x3C;= y</code><br>Greater than <code>x > y</code><br>Greater than or equal <code>x >= y</code></td></tr><tr><td>equality</td><td>left-to-right</td><td>Equality <code>x == y</code><br>Inequality <code>x != y</code><br>Strict Equality <code>x === y</code><br>Strict Inequality <code>x !== y</code></td></tr><tr><td>bitwise AND</td><td>left-to-right</td><td><code>x &#x26; y</code></td></tr><tr><td>bitwise XOR</td><td>left-to-right</td><td><code>x ^ y</code></td></tr><tr><td>bitwise OR</td><td>left-to-right</td><td><code>x | y</code></td></tr><tr><td>logical AND</td><td>left-to-right</td><td><code>x &#x26;&#x26; y</code></td></tr><tr><td>logical OR, nullish coalescing</td><td>left-to-right</td><td>Logical OR <code>x || y</code><br>Nullish coalescing operator <code>x ?? y</code></td></tr><tr><td>conditional (ternary) operator</td><td>right-to-left</td><td><code>x ? y : z</code></td></tr></tbody></table>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.jcore.io/clarity/formula-language.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
