CoAP Integration
CoAP Integration connects ThingsBoard to devices that use the CoAP protocol. It exposes a CoAP endpoint, receives device payloads, and transforms them into ThingsBoard telemetry and attributes via an uplink converter.
Prerequisites
Section titled “Prerequisites”In this tutorial, device SN-001 sends temperature and humidity readings to the CoAP Integration at coap://localhost.
The integration accepts three payload types:
SN-001,default,temperature,25.7,humidity,69{ "deviceName": "SN-001", "deviceType": "default", "temperature": 25.7, "humidity": 69}Hex string:
\x53\x4e\x2d\x30\x30\x31\x64\x65\x66\x61\x75\x6c\x74\x32\x35\x2e\x37\x36\x39Byte layout:
| Bytes | Hex | Value |
|---|---|---|
| 0–5 | \x53\x4e\x2d\x30\x30\x31 | Device name: SN-001 |
| 6–12 | \x64\x65\x66\x61\x75\x6c\x74 | Device type: default |
| 13–16 | \x32\x35\x2e\x37 | Temperature: 25.7 |
| 17–18 | \x36\x39 | Humidity: 69 |
ThingsBoard integration setup
Section titled “ThingsBoard integration setup”Create an uplink converter
Section titled “Create an uplink converter”CoAP uses a generic uplink converter. The decoder function receives the raw CoAP message body as a payload byte array. It must return an object with at least deviceName and deviceType. Optionally, it can include telemetry (time-series measurements) and attributes (device properties) as flat key-value maps.
Unlike HTTP or MQTT integrations, CoAP provides no transport-level metadata — device identity must come entirely from the payload itself.
- Go to Integrations center ⇾ Data converters.
- Click + Add data converter ⇾ Create new converter.
- Set Converter type to Uplink (default).
- Select integration type from the dropdown — CoAP.
- Enter a converter name:
CoAP Uplink Converter. - Paste the decoder function from the tab below.
Select the tab matching your payload type:
/** Decoder **/
// decode payload to stringvar strArray = decodeToString(payload);var payloadArray = strArray.replaceAll("\"", "").split(',');
var telemetryPayload = {};for (var i = 2; i < payloadArray.length; i = i + 2) { var telemetryKey = payloadArray[i]; var telemetryValue = parseFloat(payloadArray[i + 1]); telemetryPayload[telemetryKey] = telemetryValue;}
// Result object with device attributes/telemetry datavar result = { deviceName: payloadArray[0], deviceType: payloadArray[1], telemetry: telemetryPayload, attributes: {}};
/** Helper functions 'decodeToString' and 'decodeToJson' are already built-in **/
return result;/** Decoder **/
// decode payload to stringvar strArray = decodeToString(payload);var payloadArray = strArray.replace(/\"/g, "").replace(/\s/g, "").replace(/\\n/g, "").split(',');
var telemetryPayload = {};for (var i = 2; i < payloadArray.length; i = i + 2) { var telemetryKey = payloadArray[i]; var telemetryValue = parseFloat(payloadArray[i + 1]); telemetryPayload[telemetryKey] = telemetryValue;}
// Result object with device attributes/telemetry datavar result = { deviceName: payloadArray[0], deviceType: payloadArray[1], telemetry: telemetryPayload, attributes: {}};
/** Helper functions **/
function decodeToString(payload) { return String.fromCharCode.apply(String, payload);}
return result;The decoder expects a comma-separated string where position 0 is the device name, position 1 is the device type, and positions 2–N are alternating telemetry key/value pairs: deviceName,deviceType,key1,value1,key2,value2,...
To adapt this converter to your device:
- Change the separator by replacing
split(',')with your delimiter (e.g.split(';')orsplit('|')). - If the device name or type is at a different position, adjust the
payloadArray[0]/payloadArray[1]index. - If telemetry keys are fixed rather than embedded in the payload, replace the loop with explicit assignments:
telemetryPayload['temperature'] = parseFloat(payloadArray[2]);. - To extract attributes instead of telemetry, move fields from the
telemetrymap to theattributesmap.
/** Decoder **/
// decode payload to JSONvar data = decodeToJson(payload);
// Result object with device attributes/telemetry datavar result = { deviceName: data.deviceName, deviceType: data.deviceType, attributes: {}, telemetry: { temperature: data.temperature, humidity: data.humidity }};
/** Helper functions 'decodeToString' and 'decodeToJson' are already built-in **/
return result;/** Decoder **/
// decode payload to JSONvar data = decodeToJson(payload);
// Result object with device attributes/telemetry datavar result = { deviceName: data.deviceName, deviceType: data.deviceType, attributes: {}, telemetry: { temperature: data.temperature, humidity: data.humidity }};
/** Helper functions **/
function decodeToString(payload) { return String.fromCharCode.apply(String, payload);}
function decodeToJson(payload) { var str = decodeToString(payload); var data = JSON.parse(str); return data;}
return result;The decoder parses the payload as a JSON object and maps fields directly to deviceName, deviceType, and telemetry keys.
To adapt this converter to your device:
- Replace
data.deviceName/data.deviceTypewith the actual field names your device sends (e.g.data.id,data.model). - Add or remove telemetry fields to match your sensor output:
pressure: data.pressure, co2: data.co2. - Move fields to
attributesif they represent device properties rather than time-series data (e.g.firmware: data.fw).
/** Decoder **/
// decode payload to stringvar payloadStr = decodeToString(payload);
var deviceName = payloadStr.substring(0, 6);var deviceType = payloadStr.substring(6, 13);
// Result object with device attributes/telemetry datavar result = { deviceName: deviceName, deviceType: deviceType, attributes: {}, telemetry: { temperature: parseFloat(payloadStr.substring(13, 17)), humidity: parseFloat(payloadStr.substring(17, 19)) }};
/** Helper functions 'decodeToString' and 'decodeToJson' are already built-in **/
return result;/** Decoder **/
// decode payload to stringvar payloadStr = decodeToString(payload);
var deviceName = payloadStr.substring(0, 6);var deviceType = payloadStr.substring(6, 13);
// Result object with device attributes/telemetry datavar result = { deviceName: deviceName, deviceType: deviceType, attributes: {}, telemetry: { temperature: parseFloat(payloadStr.substring(13, 17)), humidity: parseFloat(payloadStr.substring(17, 19)) }};
/** Helper functions **/
function decodeToString(payload) { return String.fromCharCode.apply(String, payload);}
function decodeToJson(payload) { var str = decodeToString(payload); var data = JSON.parse(str); return data;}
return result;The decoder converts the raw bytes to a string and reads device identity and sensor values from fixed byte offsets. This approach is typical for compact, bandwidth-constrained binary protocols.
To adapt this converter to your device:
- Adjust the
substring(start, end)offsets to match your device’s byte layout. - For integer fields stored as raw bytes (not ASCII digits), use
parseBytesToInt(payload, offset, length, bigEndian)instead ofparseFloat(payloadStr.substring(...)). For example:temperature: parseBytesToInt(payload, 13, 2, true) / 100.0. - If the device name or type is fixed rather than embedded in the payload, replace the
substringcalls with string literals. - Add more telemetry fields by reading additional byte ranges and adding them to the
telemetrymap.
- Optionally, click Test payload decoder to validate.
- Click Add.
Create the integration
Section titled “Create the integration”- Go to Integrations center ⇾ Integrations and click + Add integration.
- Basic settings:
- Set Integration type to CoAP.
- Enable integration and Allow create devices or assets are on by default.
- Click Next.
- Uplink data converter:
- Select existing — choose a previously created
CoAP Uplink Converterfrom the list. - Click Next.
- Select existing — choose a previously created
- Connection:
- Security mode: NO SECURE
- Copy the auto-generated CoAP endpoint URL — you will use it to send test messages.
- Click Add.
Connection settings
Section titled “Connection settings”Security mode
Defines the transport security for the CoAP connection:
| Mode | Description |
|---|---|
| NO SECURE (default) | Plain CoAP over UDP — no encryption |
| DTLS | CoAP over DTLS 1.2 — encrypted |
| MIXED | Both plain and DTLS endpoints active simultaneously |
Both CON (Confirmable) and NON (Non-Confirmable) CoAP message types are supported in all modes. ThingsBoard acknowledges CON messages automatically.
For DTLS and MIXED modes, enable DTLS support in thingsboard.yml or set the following environment variables:
# Enable/disable DTLS 1.2 supportexport COAP_DTLS_ENABLED=true# Default CoAP DTLS bind portexport COAP_DTLS_BIND_PORT=5484# Path to the key store that holds the SSL certificateexport COAP_DTLS_KEY_STORE=coapserver.jks# Password used to access the key storeexport COAP_DTLS_KEY_STORE_PASSWORD=server_ks_password# Password used to access the keyexport COAP_DTLS_KEY_PASSWORD=server_key_password# Key aliasexport COAP_DTLS_KEY_ALIAS=serveralias# Skip certificate validity check for client certificatesexport TB_COAP_X509_DTLS_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT=falseBase URL
The base address of the ThingsBoard CoAP endpoint.
Example: coap://int.my.thingsboard
Path
Optional URL path appended to the base URL.
Example: coap://int.my.thingsboard/my-path
CoAP endpoint URL
Auto-generated from the Base URL and the path /i/$INTEGRATION_ROUTING_KEY. The /i/ prefix is a fixed segment that routes incoming CoAP messages to the integration; the routing key (UUID) is assigned at creation time. Devices must POST to this URL.
Execute remotely
When enabled, ThingsBoard generates an Integration key and Integration secret. These credentials allow the integration to run as a separate process — either on a remote server or at the edge — and communicate with ThingsBoard over a secure channel. Use this option for deployments where the integration service must reside outside the main ThingsBoard cluster (e.g., in a DMZ or on-premises gateway).
Test uplink
Section titled “Test uplink”Once the integration is created, the CoAP server registers the endpoint and waits for incoming data. Send a test message using coap-client (part of libcoap), replacing $YOUR_COAP_ENDPOINT_URL with the URL copied during setup:
echo -e 'SN-001,default,temperature,25.7,humidity,69' | coap-client -m post $YOUR_COAP_ENDPOINT_URL -t text/plain -f-echo -e -n '{"deviceName": "SN-001", "deviceType": "default", "temperature": 25.7, "humidity": 69}' | coap-client -m post $YOUR_COAP_ENDPOINT_URL -t application/json -f-echo -e -n '\x53\x4e\x2d\x30\x30\x31\x64\x65\x66\x61\x75\x6c\x74\x32\x35\x2e\x37\x36\x39' | coap-client -m post $YOUR_COAP_ENDPOINT_URL -t application/octet-stream -f-Go to Entities ⇾ Devices. Device SN-001 is auto-created on the first uplink. Open the Latest Telemetry tab to confirm temperature = 25.7 and humidity = 69.