Device Attribute Forwarding and Process Data
The Forward selection in device details controls which server/shared attribute fields enter MQTT data messages. Process Data (process_data, also called process attributes) stores intermediate script state. Together they let you retain calculation state while reducing unnecessary messages and server bandwidth.
This guide describes the 2.00.066 source behavior. The corresponding frontend, backend and database migrations must be deployed in the target environment.
Choose where to store data
| Data | Recommended location | Forwarding behavior |
|---|---|---|
| Measurements used for charts and automation | telemetry_data | Existing telemetry processing |
| Thresholds, business state, platform parameters | server_attrs | Not forwarded by default; only selected top-level fields are sent |
| Device configuration feedback and shared parameters | shared_attrs | Not forwarded by default; only selected top-level fields are sent |
| Counters, previous readings, calculation caches | process_data | Excluded from built-in forwarding |
Enable field forwarding only when an external consumer needs it. Prefer process data for frequently changing large objects and calculation caches. Process data is persistent state, not automatically expiring memory.
Upgrading does not automatically move existing server_attrs or shared_attrs into process_data. When adapting an existing calculation script, verify and initialize the required state before switching its reads, so an empty process-data object does not unintentionally reset a cumulative calculation.
Configure attribute forwarding
- Open Maintenance → Device Management → Details.
- Select Server Attributes or Shared Attributes.
- Select the required fields in the Forward column. The header checkbox selects or clears the fields in that table.
- Submit the device configuration. Subsequent forwarding uses the saved rules; changing rules alone sends no message.
Devices and templates store a complete forward_fields allowlist, for example:
{
"server_attrs": ["threshold", "state"],
"shared_attrs": []
}Only threshold and state from server attributes can enter MQTT messages; shared attributes are not forwarded. Attributes are not forwarded by default: an absent configuration, null, {}, or an empty array for a group forwards none of that group.
- Selection matches top-level field names, without expanding nested objects. Only selected fields that exist are sent. The group's
update_timeis not included automatically. - Filtering preserves complete attributes in memory and the database. Client/MAC attributes and telemetry retain their existing behavior. Modbus uses its register mappings, independently of this MQTT allowlist.
- Rules apply to realtime, historical and RPC-initiated forwarding. No empty message is published when there are no valid data groups.
- MQTT attribute messages can contain a subset of the complete attributes. Consumers must merge received fields rather than replacing the entire group.
- Field selection works alongside Broker and Forwarder connections and topic rules. It does not represent a LoRaWAN radio downlink. Editing shared attribute configuration does not prove the device received a setting; execute the relevant RPC when a downlink is needed.
Batch configuration and templates
Select devices in the list, open Batch Modify Parameters → Forwarding Fields, and choose fields to enable or disable for each server/shared group. Select existing fields or enter new field names. A field cannot be enabled and disabled in the same operation. Empty selections mean no change, preserving each device's other rules.
Device templates also store forward_fields. Creating a template from a device copies its rules. Applying or resetting a template replaces device rules with template rules; an old template with no rules uses {}, forwarding nothing by default. Process data is not part of template defaults and is not copied or reset as template configuration. Newly auto-created sub-devices inherit a copy of parent rules; existing sub-device rules are preserved.
Configuration timestamp
The server maintains config_update_time when configuration, bindings or forwarding rules actually change. Attribute-value, process-data and telemetry updates do not advance it. Realtime and historical MQTT messages include it at the top level as the current configuration change time, not the historical sample time.
View and delete process data
- Open Process Data in device details to view fields and their update time.
- Entering the tab or clicking Refresh Process Data fetches the latest values. This tab does not subscribe to process data over MQTT.
- Delete unwanted keys using the row action. The page supports viewing, refreshing and deleting; additions and edits come from Thing Model or RPC scripts.
Deletion immediately updates the cache and queues persistence; it does not require submitting attribute configuration. Keys match exactly at the top level: a dot in a key is not a path. Repeated deletion of an absent key causes no new update; deleting all keys saves {}. Deletion itself triggers no MQTT, Modbus or Trigger notification. A running script may subsequently recreate the key.
Thing Model: save state and select forwarded fields
Return the result directly from a custom parser. device is read-only; assigning to device.process_data does not save changes. Example script body:
const count = Number(device.process_data?.count ?? 0) + 1;
return {
process_data: { count },
server_attrs: { state: "ready", debug_count: count },
forward_fields: {
server_attrs: { state: true, debug_count: false }
}
};process_data.count remains available for future calculations. state can be forwarded; debug_count stays in server attributes without being forwarded.
Process data merging: top-level keys are shallow-merged; nested objects are replaced as a whole. {} leaves data unchanged, and a field value of null is stored as a regular value, not deleted. Realtime, historical and sub-device parser results support process_data; sub-device results update the corresponding sub-device. A process-only update triggers no MQTT, Modbus, virtual-device notification or Trigger. Telemetry and actions returned alongside it follow their existing paths. Triggers can read device.process_data; write through parser results or RPC actions.
Script forwarding patches: a parser result's forward_fields is a boolean patch, unlike the array allowlist stored in device/template configuration. Only server_attrs and shared_attrs are supported: true adds uniquely, false removes, and omitted groups or fields remain unchanged. Field names must be nonempty and values must be booleans. Empty or unchanged patches cause no configuration write. Forwarding from the same parser result immediately uses the new rules.
RPC: save process data and control this notification
return [
{
type: "modifyForwardFields",
dnMsg: { server_attrs: { state: true, debug_count: false } }
},
{
type: "modifyAttrs",
forward: false,
dnMsg: {
process_data: { previous_value: 25 },
server_attrs: { state: "ready" }
}
}
];modifyForwardFields is a separate action, applied in array order; subsequent actions immediately use the new rules. modifyAttrs.forward defaults to true. When false, values are still saved, but MQTT and Modbus notifications for that action are skipped. Later explicit forwarding actions remain available. Even when true, server/shared attributes still pass through the field allowlist.
forwardTelemetry excludes process data. Script-authored customMqtt payloads are controlled by the author and are not covered by this built-in exclusion. Saving or testing a script does not mean device actions have executed.
API read and delete
All endpoints use POST and the authenticated tenant. Look up the real device ID first. Configuration-save endpoints do not accept process-data writes.
| Path | Request body | Result / purpose |
|---|---|---|
/thinklink/device/find-process-data | {"id":"device ID"} | {content, update_time}; cache first; no data returns {content:{}, update_time:null} |
/thinklink/device/delete-process-data | {"id":"device ID","fields":["scratch"]} | Delete top-level keys and return latest {content, update_time} |
/thinklink/device/find-current-attrs | {"id":"device ID"} | Complete server/shared/client/mac attributes and telemetry, excluding process data; useful for RPC parameter defaults |
/thinklink/device/update-config | {"id":"device ID","changes":{"forward_fields":{"server_attrs":["state"],"shared_attrs":[]}}} | Replace complete rules; first read and preserve groups/fields you do not intend to change |
/thinklink/device/batch-update-partial | {"dataList":[{"id":"device ID"}],"updateColumns":[],"forward_fields_patch":{"server_attrs":{"state":true}}} | Patch selected devices' rules; cannot also replace forward_fields; returns actual changed-device {count} |
Persistence and troubleshooting
Process data updates memory immediately and is persisted through a separate buffer (5-second cycle, with an early flush at 500 pending devices). Persisted values survive restarts, but forced termination or power loss can lose pending writes. Successful cache reads or deletion responses do not prove disk persistence. Deleting a device cleans up its process data.
| Symptom | Check |
|---|---|
| An attribute has a value but is absent from MQTT | Check field selection and saved configuration; changing rules alone sends no message |
forward: true still produces no attribute message | It does not bypass the allowlist; the selected field must exist |
| Process Data does not update automatically | Click Refresh; the tab fetches on demand without MQTT subscription |
Assignment to device.process_data is not saved | Return process_data or a modifyAttrs action |
A key remains after returning null | null is a regular value; use the row action or deletion endpoint |
| Attributes stop forwarding after applying a template | Check template rules; old templates without rules replace them with an empty allowlist |
Related: Device Management · Thing Model · RPC Model · Device Template