From 34592ef4b428d11dc7240354e5fabb20cb4af604 Mon Sep 17 00:00:00 2001 From: IrynaMatveieva Date: Fri, 25 Apr 2025 16:49:29 +0300 Subject: [PATCH] added description --- .../ctx/state/BaseCalculatedFieldState.java | 6 +- .../en_US/calculated-field/expression_fn.md | 127 +++++++++++++----- 2 files changed, 96 insertions(+), 37 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/BaseCalculatedFieldState.java b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/BaseCalculatedFieldState.java index 84c61661ae..35879ac9aa 100644 --- a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/BaseCalculatedFieldState.java +++ b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/BaseCalculatedFieldState.java @@ -111,13 +111,11 @@ public abstract class BaseCalculatedFieldState implements CalculatedFieldState { private void updateLastUpdateTimestamp(ArgumentEntry entry) { if (entry instanceof SingleValueArgumentEntry singleValueArgumentEntry) { - long ts = singleValueArgumentEntry.getTs(); - this.lastUpdateTimestamp = Math.max(this.lastUpdateTimestamp, ts); + this.lastUpdateTimestamp = singleValueArgumentEntry.getTs(); } else if (entry instanceof TsRollingArgumentEntry tsRollingArgumentEntry) { Map.Entry lastEntry = tsRollingArgumentEntry.getTsRecords().pollLastEntry(); if (lastEntry != null) { - long ts = lastEntry.getKey(); - this.lastUpdateTimestamp = Math.max(this.lastUpdateTimestamp, ts); + this.lastUpdateTimestamp = lastEntry.getKey(); } } } diff --git a/ui-ngx/src/assets/help/en_US/calculated-field/expression_fn.md b/ui-ngx/src/assets/help/en_US/calculated-field/expression_fn.md index 373c50e2c6..9a988df042 100644 --- a/ui-ngx/src/assets/help/en_US/calculated-field/expression_fn.md +++ b/ui-ngx/src/assets/help/en_US/calculated-field/expression_fn.md @@ -1,7 +1,7 @@ ## Calculated Field TBEL Script Function The **calculate()** function is a user-defined script that enables custom calculations using [TBEL](${siteBaseUrl}/docs${docPlatformPrefix}/user-guide/tbel/) on telemetry and attribute data. -It receives arguments configured in the calculated field setup, along with an additional `ctx` object that provides access to all arguments. +It receives arguments configured in the calculated field setup, along with an additional `ctx` object that stores `msgTs` and provides access to all arguments. ### Function Signature @@ -44,7 +44,7 @@ Let's modify the function that converts Fahrenheit to Celsius to also return the var temperatureC = (temperatureF - 32) / 1.8; return { "ts": ctx.args.temperatureF.ts, - "values": { "temperatureC": toFixed(temperatureC, 2) } + "values": {"temperatureC": toFixed(temperatureC, 2)} }; ``` @@ -60,10 +60,22 @@ These contain time series data within a defined time window. Example format: "endTs": 1740644662896 }, "values": [ - { "ts": 1740644350000, "value": 72.32 }, - { "ts": 1740644360000, "value": 72.86 }, - { "ts": 1740644370000, "value": 73.58 }, - { "ts": 1740644380000, "value": "NaN" } + { + "ts": 1740644350000, + "value": 72.32 + }, + { + "ts": 1740644360000, + "value": 72.86 + }, + { + "ts": 1740644370000, + "value": 73.58 + }, + { + "ts": 1740644380000, + "value": "NaN" + } ] } } @@ -81,14 +93,18 @@ var firstItemTs = firstItem.ts; var firstItemValue = firstItem.value; var sum = 0.0; // iterate through all values and calculate the sum using foreach: -foreach(t: temperature) { - if(!isNaN(t.value)) { // check that the value is a valid number; +foreach(t +: +temperature +) +{ + if (!isNaN(t.value)) { // check that the value is a valid number; sum += t.value; } } // iterate through all values and calculate the sum using for loop: sum = 0.0; -for(var i = 0; i < temperature.values.size; i++) { +for (var i = 0; i < temperature.values.size; i++) { sum += temperature.values[i].value; } // use built-in function to calculate the sum @@ -146,12 +162,13 @@ function calculate(ctx, altitude, temperature) { Time series rolling arguments can be **merged** to align timestamps across multiple datasets. -| Method | Description | Returns | Example | -|:-----------------------------|:--------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `merge(other, settings)` | Merges with another rolling argument. Aligns timestamps and filling missing values with the previous available value. | Merged object with `timeWindow` and aligned values. |

| -| `mergeAll(others, settings)` | Merges multiple rolling arguments. Aligns timestamps and filling missing values with the previous available value. | Merged object with `timeWindow` and aligned values. |

| +| Method | Description | Returns | Example | +|:-----------------------------|:----------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `merge(other, settings)` | Merges with another rolling argument. Aligns timestamps and filling missing values with the previous available value. | Merged object with `timeWindow` and aligned values. |

| +| `mergeAll(others, settings)` | Merges multiple rolling arguments. Aligns timestamps and filling missing values with the previous available value. | Merged object with `timeWindow` and aligned values. |

| ##### Parameters + | Parameter | Description | |:---------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `other` or `others` | Another rolling argument or array of rolling arguments to merge with. | @@ -166,7 +183,11 @@ function calculate(ctx, temperature, defrost) { var merged = temperature.merge(defrost); var result = []; - foreach(item: merged) { + foreach(item +: + merged +) + { if (item.v1 > -5.0 && item.v2 == 0) { result.add({ ts: item.ts, @@ -187,29 +208,51 @@ function calculate(ctx, temperature, defrost) { The result is a list of issues that may be used to configure alarm rules: ```json -[{ +[ + { "ts": 1741613833843, "values": { - "issue": { - "temperature": -3.12, - "defrostState": false - } + "issue": { + "temperature": -3.12, + "defrostState": false + } } -}, { + }, + { "ts": 1741613923848, "values": { - "issue": { - "temperature": -4.16, - "defrostState": false - } + "issue": { + "temperature": -4.16, + "defrostState": false + } } -}] + } +] ``` ### Function return format The return format depends on the output type configured in the calculated field settings (default: **Time Series**). +### Message timestamp + +The `ctx` object also includes property `msgTs`, which represents the timestamp of the incoming telemetry message that triggered the calculated field execution in milliseconds. + +You can use `ctx.msgTs` to set the timestamp of the resulting output explicitly when returning a time series object. + +```javascript +var temperatureC = (temperatureF - 32) / 1.8; +return { + ts: ctx.msgTs, + values: { + "temperatureC": toFixed(temperatureC, 2) + } +} + +``` + +This ensures that the calculated data point aligns with the timestamp of the triggering telemetry. + ##### Time Series Output The function must return a JSON object or array with or without a timestamp. @@ -225,8 +268,14 @@ Without timestamp: "hvacState": "IDLE", "configuration": { "someNumber": 42, - "someArray": [1,2,3], - "someNestedObject": {"key": "value"} + "someArray": [ + 1, + 2, + 3 + ], + "someNestedObject": { + "key": "value" + } } } ``` @@ -243,10 +292,16 @@ With timestamp: "hvacState": "IDLE", "configuration": { "someNumber": 42, - "someArray": [1,2,3], - "someNestedObject": {"key": "value"} + "someArray": [ + 1, + 2, + 3 + ], + "someNestedObject": { + "key": "value" + } } - } + } } ``` @@ -265,7 +320,7 @@ Array containing multiple timestamps and different values of the `airDensity` : "values": { "airDensity": 1.07 } - } + } ] ``` @@ -282,8 +337,14 @@ Example below return 5 data points: airDensity (double), humidity (integer), hva "hvacState": "IDLE", "configuration": { "someNumber": 42, - "someArray": [1,2,3], - "someNestedObject": {"key": "value"} + "someArray": [ + 1, + 2, + 3 + ], + "someNestedObject": { + "key": "value" + } } } ```