Skip to main content
Version: Next

The Things Stack (TTS)

The TTS agent allows integration of LoRaWAN devices managed by The Things Stack (V3).

How It Works

The TTS agent acts as a bridge between OpenRemote and a The Things Stack Network Server by utilizing two primary communication channels:

Message Exchange (MQTT)

The agent connects to the TTS MQTT integration for real-time data flow:

  • Uplink messages: The agent subscribes to device events to receive sensor data.
  • Downlink messages: The agent publishes to command topics to send configuration or control packets back to the end-devices.

Device Management and Discovery (gRPC API)

The agent utilizes the The Things Stack gRPC API as the primary interface for managing device lifecycles and metadata. This is used for:

  • Real-time auto-discovery: Instead of periodic polling, the agent listens to the gRPC events stream. When a device sends an uplink or performs a Join, the agent detects it instantly.
  • Attribute-based Template Identification: Once a device is detected, the agent queries the gRPC API to retrieve the device's specific metadata. It looks for a custom TTS device attribute that defines the OpenRemote Asset Type, allowing the agent to apply the correct template automatically.

Agent configuration

The following describes the supported agent configuration attributes:

AttributeDescriptionRequiredDefault
MQTTHostThe hostname or IP address of the TTS MQTT broker.Y-
MQTTPortThe network port for the MQTT connection.Y-
clientIdThe unique identifier for this agent's session on the MQTT broker.Y-
secureModeBoolean flag indicating if the MQTT connection should use TLS/SSL encryption.Nfalse
usernamePasswordMQTT credentials (JSON format - see below)Y-
resumeSessionBoolean flag indicating if the MQTT broker should persist the session and queue messages during agent downtime.Nfalse
subscribeQosMQTT Quality of Service level for receiving uplinks (0, 1, 2).N0
publishQosMQTT Quality of Service level for sending downlinks (0, 1, 2).N0
hostThe hostname or IP address of the TTS gRPC API.Y-
portThe network port for the TTS gRPC API.NsecureGRPC==true -> 443, secureGRPC==false -> 80
applicationIdThe identifier of the TTS application to be integrated.Y-
tenantIdTTS tenant identifier.Y-
apiKeyTTS API key used to authenticate the gRPC connection.Y-
secureGRPCBoolean flag to enable gRPC TLS/SSL encryption.Ntrue

MQTT Credentials Format

The TTS agent requires the usernamePassword attribute to be provided in a specific JSON format. Note that the username is the combined Application and Tenant ID, while the password is your TTS API Key.

Format:

{
"username": "{applicationId}@{tenantId}",
"password": "{apiKey}"
}

Example:

MQTTHost: eu1.cloud.thethings.network
MQTTPort: 8883
clientId: or_tts_agent_1
secureMode: true
usernamePassword: >
{
"username": "parking-sensors@ttn",
"password": "NNSXS.FUFJDFQHVP7SRG2FAE3NS26LVDQQMFTKVVBPCGI.YHI2JQ6..."
}
resumeSession: true
host: eu1.cloud.thethings.network
port: 443
applicationId: parking-sensors
tenantId: ttn
apiKey: NNSXS.FUFJDFQHVP7SRG2FAE3NS26LVDQQMFTKVVBPCGI.YHI2JQ6...
secureGRPC: true

Device to Asset Mapping

To ensure the TTS agent can automatically create and configure assets, it must map a TTS device to a specific OpenRemote Asset Type.

Auto-discovery Mapping (TTS Attributes)

For devices discovered via the gRPC events stream, the mapping is defined within the TTS End Device Attributes. By adding a specific attribute to the device in the TTS Console, you provide the agent with the Asset Type template required to create the asset in OpenRemote:

Attribute KeyAttribute Value
openremote-asset-typeThe exact name of the OpenRemote Asset Type (e.g., WeatherStationAsset).

During auto-discovery, the agent reads this TTS device attribute and creates the corresponding asset in OpenRemote.

CSV Import Mapping

When importing devices via a CSV file, the asset type is defined directly within the file. The CSV must include a column that specifies the Asset Type name for each device record.

For a detailed breakdown of the required columns and an example file, see the CSV Import Format section below.

The TTS agent handles the transmission of sensor data (uplinks) and commands (downlinks) via the MQTT protocol. To eliminate the need for manual configuration of every attribute, the agent automatically provisions these communication links during the discovery or import process.

Automatic Provisioning Logic

Once a matching Asset Type template is identified, the agent configures the MQTT Agent Links based on the following workflow:

  1. Meta item Lookup: The agent scans the attributes of the selected Asset Type for a meta item named AGENT_LINK_CONFIG. For details on the format of this meta item, see LoRaWAN Asset Types.
  2. Link Creation: The agent uses the template defined in the meta item to generate the specific MQTT topics and data filters required for that individual device.

Attributes Configured

The following attributes are automatically populated on the resulting agent links to handle the MQTT protocol logic:

  • MQTT Specific: subscriptionTopic, publishTopic.
  • Generic Data Processing: valueFilters, messageMatchPredicate, messageMatchFilters, writeValue, and writeValueConverter.

CSV Import Format

Bulk provisioning allows you to create many assets at once. The agent processes each row to instantiate a new asset, using the specified assetType to identify which template to apply for automatic link configuration.

CSV Column Structure

Note: The CSV file must not contain a header row. The agent identifies the data based on the specific column order defined below.

ColRequiredAttributeDescription
1YdevEUIThe 16-character hexadecimal unique identifier.
2NdeviceNameThe display name for the asset in OpenRemote.
3YassetTypeThe exact name of the Asset Type template (case-sensitive).
4NvendorIdThe manufacturer of the device.
5NmodelIdThe specific hardware model identifier.
6NfirmwareVersionThe software version on the device.

Example File Content

a84043d8d1842175,Dragino LHT65 1,DraginoLHT65Asset,dragino,lht65,1.8
a84043d8d1842176,Dragino LHT65 2,DraginoLHT65Asset,dragino,lht65,1.8

LoRaWAN Asset Types

When using LoRaWAN agents such as ChirpStack or The Things Stack, OpenRemote can automatically provision assets and their communication links.

This automation relies on the use of specific LoRaWAN Asset Types. In these types, each attribute that is linked to a device data point must contain an AGENT_LINK_CONFIG meta item. This meta item acts as a blueprint, allowing the agent to automatically configure the underlying MQTT protocol agent links.

Configuration Keys

The AGENT_LINK_CONFIG meta item is a ValueType.ObjectMap containing the following keys:

KeyTypeDescription
uplinkPortIntegerFilters incoming messages by the LoRaWAN FPort.
valueFilterJsonPathStringThe JSON Path used to extract the value from the payload (see Payload Formats).
valueConverterMapDefines a value converter map for incoming values.
downlinkPortIntegerThe FPort used for sending downlink commands.
writeValueConverterMapMaps attribute values (e.g., TRUE/FALSE) to the required Base64 payloads.

Network Server Payload Formats

The valueFilterJsonPath specifies the exact location of sensor data within the incoming MQTT message. Because different LoRaWAN network servers wrap the decoded device data in different JSON envelopes, the root of your path must match your specific provider:

Network ServerPayload RootExample Path
ChirpStack$.object$.object.Temperature
The Things Stack$.uplink_message.decoded_payload$.uplink_message.decoded_payload.Temperature

Example Asset Type

The example demonstrates how to map a sensor reading (uplink) and a command switch (downlink).

@Entity
public class LoRaWanAsset extends Asset<LoRaWanAsset> {

// Uplink: Map temperature from Port 2
public static final AttributeDescriptor<Double> TEMPERATURE = new AttributeDescriptor<>("temperature", ValueType.NUMBER,
new MetaItem<>(MetaItemType.READ_ONLY),
new MetaItem<>(MetaItemType.AGENT_LINK_CONFIG, new ValueType.ObjectMap() {{
putAll(Map.of(
"uplinkPort", 2,
// For ChirpStack use $.object...
// For The Things Stack use $.uplink_message.decoded_payload...
"valueFilterJsonPath", "$.object.Temperature"
));
}})
).withUnits(UNITS_CELSIUS);

// Downlink: Map switch to Base64 payloads on Port 4
public static final AttributeDescriptor<Boolean> SWITCH = new AttributeDescriptor<>("switch", ValueType.BOOLEAN,
new MetaItem<>(MetaItemType.AGENT_LINK_CONFIG, new ValueType.ObjectMap() {{
putAll(Map.of(
"downlinkPort", 4,
"writeValueConverter", new ValueType.ObjectMap() {{
putAll(Map.of(
"TRUE", "DAE=",
"FALSE", "DAA="
));
}}
));
}})
);

public static final AttributeDescriptor<String> DEV_EUI = new AttributeDescriptor<>("devEUI", ValueType.TEXT, new MetaItem<>(MetaItemType.READ_ONLY));
public static final AttributeDescriptor<String> VENDOR_ID = new AttributeDescriptor<>("vendorId", ValueType.TEXT, new MetaItem<>(MetaItemType.READ_ONLY));
public static final AttributeDescriptor<String> MODEL_ID = new AttributeDescriptor<>("modelId", ValueType.TEXT, new MetaItem<>(MetaItemType.READ_ONLY));
public static final AttributeDescriptor<String> FIRMWARE_VERSION = new AttributeDescriptor<>("firmwareVersion", ValueType.TEXT, new MetaItem<>(MetaItemType.READ_ONLY));
public static final AttributeDescriptor<Boolean> SUPPORTS_CLASS_C = new AttributeDescriptor<>("supportsClassC", ValueType.BOOLEAN, new MetaItem<>(MetaItemType.READ_ONLY));

public static final AssetDescriptor<LoRaWanAsset> DESCRIPTOR = new AssetDescriptor<>("molecule-co2", "f18546", LoRaWanAsset.class);

protected LoRaWanAsset() {
}

public LoRaWanAsset(String name) {
super(name);
}
}

When sending commands to a LoRaWAN device, the network server (ChirpStack or The Things Stack) requires the raw binary payload to be formatted as a Base64 encoded string.

The writeValueConverter is used to perform this data transformation. It maps high-level OpenRemote attribute values to the specific Base64 strings required by the device's hardware commands.

In the example above, the device expects a 2-byte binary command to toggle a switch:

Attribute ValueRaw Hex CommandBase64 StringAction
TRUE0x0C01DAE=Switch On
FALSE0x0C00DAA=Switch Off

Device Metadata Attributes

To successfully manage LoRaWAN devices, the Asset Type must include specific attributes for identification and hardware context.

Mandatory: DevEUI

The devEUI attribute is mandatory. The agent uses this unique 64-bit identifier to match the physical device on the network server (ChirpStack or The Things Stack) to the corresponding asset in OpenRemote.

Optional Attributes

The following attributes are optional. These are typically populated during the CSV Import process:

  • vendorId: The manufacturer of the device (e.g., Dragino or Milesight).
  • modelId: The specific hardware model or part number (e.g., LHT65).
  • firmwareVersion: The version of the software running on the device.
  • supportsClassC: A boolean flag indicating if the device supports Class C (always-on) communication.

Reference Documentation

  • Agent Link Overview: Deep dive into generic OpenRemote attributes like filters and predicates.