Skip to content
This repository was archived by the owner on May 22, 2026. It is now read-only.

Commit 9c58e96

Browse files
committed
Merge branch 'staging/4.2' into release/4.2
2 parents f3bceb3 + 12f3727 commit 9c58e96

43 files changed

Lines changed: 1125 additions & 566 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

_config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,4 @@ release:
102102
pe_dart_client_ver: 4.0.0
103103
broker_full_ver: 2.2.0
104104
broker_branch: release-2.2.0
105-
trendz_ver: 1.13.2
105+
trendz_ver: 1.14.0

_data/trendz/installation.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ toc:
2525
path: /docs/trendz/install/trndz-upgrade-instructions/
2626
- title: Kubernetes
2727
path: /docs/trendz/install/trndz-upgrade-instructions-kubernetes/
28+
- title: Python Executor Configuration
29+
section:
30+
- title: Windows
31+
path: /docs/trendz/install/python-executor-configuration-windows/
32+
- title: Linux or Mac OS
33+
path: /docs/trendz/install/python-executor-configuration-linux/
2834
- title: Connect Trendz to Thingsboard
2935
path: /docs/trendz/connect-thingsboard/
3036
- title: Configuration properties

_includes/cookie-consent.html

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,41 +13,46 @@
1313
color: rgba(255, 255, 255, 1);
1414
}
1515

16-
#cookie-notice-text {
16+
.buttons-block {
1717
display: flex;
18-
flex-direction: column;
19-
justify-content: center;
20-
width: 65%;
18+
gap: 16px;
2119
}
2220

23-
#cookie-notice-close {
24-
position: absolute;
25-
top: 1.5rem;
26-
right: 1.5rem;
27-
color: #fff;
21+
.buttons-block button {
22+
font-size: 16px;
23+
font-weight: 500;
24+
line-height: 28px;
25+
border-radius: 4px;
26+
height: 40px;
27+
width: 140px;
28+
color: #FFF;
2829
}
2930

30-
#cookie-notice-close i {
31-
font-size: 20px;
31+
.buttons-block button:hover {
32+
opacity: 0.8;
3233
}
3334

34-
#cookie-notice-text span {
35-
font-size: 14px;
35+
.buttons-block button#cookie-notice-accept {
36+
background: #2A7DEC;
3637
}
3738

38-
#cookie-notice-text label {
39-
font-size: 20px;
39+
.buttons-block button#cookie-notice-close {
40+
background: rgba(255, 255, 255, 0.05);
4041
}
4142

42-
#cookie-notice #cookie-notice-accept {
43+
#cookie-notice-text {
4344
display: flex;
44-
text-align: center;
45+
flex-direction: column;
4546
justify-content: center;
46-
cursor: pointer;
47-
margin-left: 3.5rem;
48-
height: 40px;
49-
font-size: 18px;
50-
width: 140px;
47+
width: 65%;
48+
}
49+
50+
#cookie-notice-text span {
51+
font-size: 14px;
52+
}
53+
54+
#cookie-notice-text label {
55+
font-size: 20px;
5156
}
5257

5358
@media (max-width: 767px) {
@@ -58,12 +63,7 @@
5863

5964
#cookie-notice-text {
6065
width: 100%;
61-
}
62-
63-
#cookie-notice #cookie-notice-accept {
64-
margin-top: 1.3rem;
65-
margin-left: 0;
66-
width: 100%;
66+
margin-bottom: 40px;
6767
}
6868
}
6969
</style>
@@ -74,10 +74,10 @@
7474
href="/cookie-policy/" target="_blank">cookie policy.</a><span class=""></span>
7575
</span>
7676
</div>
77-
<button id="cookie-notice-accept" class="btn btn-primary btn-sm">Accept</button>
78-
<button id="cookie-notice-close" aria-label="Close the cookie notice button">
79-
<i class="fa fa-times"></i>
80-
</button>
77+
<div class="buttons-block">
78+
<button id="cookie-notice-accept">Accept</button>
79+
<button id="cookie-notice-close" aria-label="Close the cookie notice button">Deny</button>
80+
</div>
8181
</div>
8282
<script>
8383
function readCookieValue(value) {

_includes/docs/pe/user-guide/groups.md

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,72 @@ For example, let's create an action to quickly go to the dashboard with full inf
9797

9898
{% include images-gallery.html imageCollection="action-configuration" showListImageTitles="true" %}
9999

100-
### Batch operations
100+
### Group permissions
101+
Use the Permissions tab to define who can access the entities inside this group and what actions they can perform.
102+
A permission links a Group role to a User group and applies only to the entities inside this group.
103+
Permissions supplement tenant-wide RBAC and do not override global restrictions. See [Group roles in RBAC](/docs/{{docsPrefix}}user-guide/rbac/#group-role){:target="_blank"}.
104+
105+
**How to add group permissions:**
106+
- Open **Entity group details****Permissions** tab.
107+
- Click "**+**" (Plus icon) to add a group permission.
108+
- Select **Role** (Group role) from dropdown list.
109+
- Select **User group owner** [Tenant](/docs/{{docsPrefix}}user-guide/ui/tenants){:target="_blank"} or a specific [Customer](/docs/{{docsPrefix}}user-guide/ui/customers){:target="_blank"}, and **User group**
110+
- Click "**Add**" to save. The group permission appears in the table.
111+
112+
You can **Edit** or **Delete** existing group permissions at any time from **Permissions** tab:
113+
- **Edit**: click "**Edit**" (pencil icon) of the target permission → update fields → "**Save**".
114+
- **Delete**: click "**Delete**" (trash icon) of the target permission → "**Confirm**".
115+
116+
Changes take effect immediately for all members who can access the group.
117+
118+
To review assigned permissions from the [user side](/docs/{{docsPrefix}}user-guide/ui/users/#assigning-permissions-to-user-group): Open **Users group** details → **Roles** tab.
119+
120+
## Batch operations
101121

102122
Over each entity of the group, you can perform operations such as: change the owner of the entity, move it to another group, add or remove an entity from the group.
103123

104124
{% include images-gallery.html imageCollection="batch-operations" showListImageTitles="true" %}
105125

126+
## Share entity group
127+
128+
Sharing a group provides access to all entities inside the group at once and creates a permission entry that links this entity group to the selected user group.
129+
130+
**How to share an entity group:**
131+
- In **Groups** tab, click "**Share**" icon in the row of the target group.
132+
- Choose [**Customer**](/docs/{{docsPrefix}}user-guide/ui/customers/){:target="_blank"} from dropdown list.
133+
- (Optional) Enable **All users** checkbox to provide access to every user of that customer.
134+
- Choose the Permissions access: Read, Write, or Other (Roles).
135+
- Click "**Share**" to apply. The access is propagated to all entities within the group.
136+
137+
To update or revoke access, open the group [permissions](#group-permissions) tab and edit/delete the corresponding permission.
138+
139+
## Make group public or private
140+
141+
Public groups provide read-only access to anyone (no sign-in). Use it for non-sensitive data only. When you set a group as Public,
142+
the platform adds permissions to that entity group for the Public customer’s "Public users" group.
143+
144+
**Make public:**
145+
146+
- In the **Groups** tab, click "**Make public**" icon of the target group.
147+
148+
- Confirm in the dialog.
149+
150+
The Public checkbox becomes enabled for this group.
151+
152+
{% capture public %}
153+
**Note:** Public dashboards that use device data, require the dashboard and the related device group must be public.
154+
{% endcapture %}
155+
{% include templates/info-banner.md content=public %}
156+
157+
**Make private (revoke public access):**
158+
159+
- In the Groups tab, click "**Make private**" icon of the target group.
160+
161+
- Confirm in the dialog. Public access is removed.
162+
163+
If you need controlled access for specific customers or users, use [Share entity group](#share-entity-group)
164+
or configure entries on the [Permissions](#group-permissions) tab.
165+
106166
## Delete entity group
107167

108168
You can delete an entity group along with all its entities using one of the following ways:

_includes/docs/user-guide/widgets.md

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ A data key identifies the telemetry, attribute, or entity field a widget should
152152

153153
<b><font size="3">Sources of keys</font></b>
154154
- **Attributes** — the combined set of Client, Server, and Shared [attributes](/docs/{{docsPrefix}}user-guide/attributes/){:target="_blank"} of the selected entity. If a needed attribute doesn&#39;t exist yet, you can still add the key; the widget will show data once the device reports it.
155-
- **Time series** — telemetry keys reported by devices or written by the Rule Engine / [REST API](/docs/{{docsPrefix}}reference/rest-api/){:target="_blank"}.
155+
- **Time series** — telemetry keys reported by devices or written by the [Rule Engine](/docs/{{docsPrefix}}user-guide/rule-engine-2-0/overview/){:target="_blank"} / [REST API](/docs/{{docsPrefix}}reference/rest-api/){:target="_blank"}.
156156
- **Entity fields** — metadata fields that depend on entity type and may evolve over time (e.g. created time, entity type, name, type, label).
157157

158158
The data keys list for data source depends on the [widget type](/docs/{{docsPrefix}}user-guide/widgets/#widget-types){:target="_blank"}:
@@ -222,9 +222,9 @@ Let&#39;s look at the basic data key settings an example of the "Entities table"
222222

223223
{% include images-gallery.html imageCollection="data-key-configuration-color" %}
224224

225-
- **Use data postprocessing function** — enable a custom function to transform raw values before display.
225+
- [**Use data post-processing function**](#data-post-processing-function) — enable a custom function to transform raw values before display.
226226

227-
**Aggregation of key**
227+
##### Aggregation of key
228228

229229
By default, the Latest values widgets do not have the time window. If you enable aggregation for any data
230230
key in the **Latest values** widgets, the time window control will appear. You can set up aggregation for each telemetry
@@ -305,7 +305,30 @@ This option allows you to specify how the result should be displayed:
305305

306306
- **Delta (percent)** - Displays the result as a percentage relative to the previous interval <br>formula: **(IntervalValue - prevIntervalValue)/prevIntervalValue*100**
307307

308-
**Use data post-processing function.** The data post-processing function allows changing the output data depending on your wishes. To use data post-processing function, you must check the "Use data post-processing function" checkbox and enter the function in the field below. Then click the "Save" button in the lower-right corner.
308+
##### Data post-processing function
309+
The data post-processing function enables real-time transformation of incoming telemetry values before they are displayed
310+
in widgets. This feature allows you to apply custom JavaScript logic to each data point — for example, convert units,
311+
filter out anomalies, or calculate derived metrics without touching upstream sources.
312+
313+
**How to use:**
314+
- In the widget → go to section with **Data keys** → click the **Pencil** icon of the target data key.
315+
- Enable toggle **Use data post-processing function**.
316+
- Enter your code in the function body. The platform automatically injects the function header:
317+
<br> **function** (time, value, prevValue, timePrev, prevOrigValue) {
318+
<br> **`YOUR_JS_CODE`**
319+
<br> }
320+
- Click **Save** button.
321+
322+
**Once enabled, the function has access to the following parameters:**
323+
324+
- **time** – timestamp of the current value,
325+
- **value** – the current value,
326+
- **prevValue** – value returned by the previous function call,
327+
- **timePrev** – timestamp of the previous value,
328+
- **prevOrigValue** – original previous value.
329+
330+
The function must **return** a value (**number**|**string**|**boolean**|**null**).
331+
Returning **null** excludes the data point from visualization.
309332

310333
{% include images-gallery.html imageCollection="data-key-configuration-settings-post-processing" %}
311334

_includes/footer.html

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,15 @@
1212
$('#mlb2-7341216').css('display', 'block');
1313
}
1414
</script>
15-
<button id="Footer_SignUpForNews" class="n-button try subscribe gtm_button "
16-
onClick="subscribeForNewsletter(event)">Sign up for ThingsBoard news</button>
15+
<div class="footer-top-section">
16+
<button id="Footer_SignUpForNews" class="n-button try subscribe gtm_button "
17+
onClick="subscribeForNewsletter(event)">Sign up for ThingsBoard news</button>
18+
<div class="footer-top-img-section">
19+
<img src="https://img.thingsboard.io/crozdesk-2.webp" alt="ThingsBoard achievement — Crozdesk Quality Choice Top-Ranked Solution 2025">
20+
<img src="https://img.thingsboard.io/crozdesk-1.webp" alt="ThingsBoard achievement — Crozdesk Trusted Vendor High Market Presence 2025">
21+
<img src="https://img.thingsboard.io/supplier-retail.webp" alt="ThingsBoard achievement — Top Supplier in Retail 2024">
22+
</div>
23+
</div>
1724
<div id="mlb2-7341216" class="ml-subscribe-form ml-subscribe-form-7341216" style="display: none; max-width: 100%;">
1825
<!-- <div id="mlb2-7341216" class="ml-subscribe-form ml-subscribe-form-7341216" style="display: block;">-->
1926
<div class="ml-vertical-align-center">

_includes/integrators.json

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -83,18 +83,6 @@
8383
"target": "_blank"
8484
}
8585
},
86-
{
87-
"type": ["Asia"],
88-
"country": ["China"],
89-
"name": "Arapo Ltd.",
90-
"contact": {
91-
"href": "tamati.iro@gmail.com"
92-
},
93-
"site": {
94-
"href": "",
95-
"target": "_blank"
96-
}
97-
},
9886
{
9987
"type": ["Asia"],
10088
"country": ["Taiwan"],
@@ -659,6 +647,18 @@
659647
"target": "_blank"
660648
}
661649
},
650+
{
651+
"type": ["Europe"],
652+
"country": ["Sweden"],
653+
"name": "JHA IT AB",
654+
"contact": {
655+
"href": "info@jha-it.se"
656+
},
657+
"site": {
658+
"href": "www.jha-it.se",
659+
"target": "_blank"
660+
}
661+
},
662662
{
663663
"type": ["Asia"],
664664
"country": ["Taiwan"],
@@ -1259,6 +1259,18 @@
12591259
"target": "_blank"
12601260
}
12611261
},
1262+
{
1263+
"type": ["Europe"],
1264+
"country": ["Spain", "Portugal"],
1265+
"name": "Wavecom",
1266+
"contact": {
1267+
"href": "wavecom@wavecom.pt"
1268+
},
1269+
"site": {
1270+
"href": "wavecom.pt",
1271+
"target": "_blank"
1272+
}
1273+
},
12621274
{
12631275
"type": ["Asia"],
12641276
"country": ["Thailand"],
Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,58 @@
1-
Let's review more examples of alternative responses addresses.
1+
Alternative response addresses field allows you to specify an alternative IP address for device responses.
2+
It is especially useful when the gateway and the BACnet device are located in different networks.
23

3-
This field allows you to specify an alternative address for responses from the device.
4-
It is useful when the gateway and BACnet device are located in different networks.
4+
For example, consider the following network setup:
5+
6+
![image](https://img.thingsboard.io/gateway/bacnet-connector/examples/alternative-responses-addresses-network-setup.png)
7+
8+
In this setup, the gateway runs inside a Docker container and the BACnet device is located on a local network with IP
9+
address `192.168.1.200:45606` and is not directly accessible from the Docker container. BACPypes sends APDUs to the
10+
gateway without including the port number, making it impossible for the connector to determine whether a response came
11+
from an allowed device. When you configure an alternative response address, the connector uses this IP to correctly
12+
recognize and validate the device.
13+
14+
To configure the alternative response address, you need to add the `altResponsesAddresses` field to the device
15+
configuration. Here is an example configuration snippet:
516

6-
For example, if gateway running via the docker container and the BACnet device is located in the local network under
7-
192.168.1.200:45606, you can specify the IP address of the BACnet device in the alternative responses addresses field.
817
```json
9-
"altResponsesAddresses": ["192.168.1.200"]
18+
{
19+
"application": {
20+
"objectName": "TB_gateway",
21+
"host": "0.0.0.0",
22+
"port": 47808,
23+
"mask": 24,
24+
"objectIdentifier": 599,
25+
"maxApduLengthAccepted": 1476,
26+
"segmentationSupported": "segmentedBoth",
27+
"vendorIdentifier": 15,
28+
"deviceDiscoveryTimeoutInSec": 5,
29+
"devicesDiscoverPeriodSeconds": 30
30+
},
31+
"devices": [
32+
{
33+
"deviceInfo": {
34+
"deviceNameExpressionSource": "expression",
35+
"deviceNameExpression": "BACnet Device ${objectName}",
36+
"deviceProfileExpressionSource": "constant",
37+
"deviceProfileExpression": "default"
38+
},
39+
"host": "192.168.1.200",
40+
"port": 45606,
41+
"altResponsesAddresses": ["192.168.1.200"],
42+
"pollPeriod": 10000,
43+
"attributes": [],
44+
"timeseries": "*",
45+
"attributeUpdates": [],
46+
"serverSideRpc": []
47+
}
48+
]
49+
}
1050
```
51+
{:.copy-code}
52+
53+
After applying this configuration, the connector will use the specified alternative response address
54+
`192.168.1.200:45606` to recognize and validate responses from the BACnet device. This ensures that the connector can
55+
communicate effectively with the device even when they are located in different networks. As a result, you should see
56+
created device in ThingsBoard:
1157

12-
This is important because bacpypes provide APDU to the gateway without port number, so the connector can't determine if
13-
it is an allowed device. In this case, the connector will use the alternative address to determine that it is an allowed
14-
device.
58+
![image](https://img.thingsboard.io/gateway/bacnet-connector/examples/alternative-responses-addresses-overview.png)

0 commit comments

Comments
 (0)