Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
var mqtt = require('mqtt');
var client = mqtt.connect('mqtt://localhost', {
username: process.env.TOKEN
});

client.on('connect', function () {
console.log('connected');
client.subscribe('v1/gateway/attributes/response');
// clientKeys/sharedKeys are comma-separated strings. An empty value returns
// ALL keys in that scope, e.g. sharedKeys: "". Omit a field to exclude a scope.
var request = { id: 1, device: 'Device A', clientKeys: 'fw_version,battery', sharedKeys: 'targetFwVersion' };
client.publish('v1/gateway/attributes/request', JSON.stringify(request));
Comment thread
ShvaykaD marked this conversation as resolved.
});

client.on('message', function (topic, message) {
console.log('response.topic: ' + topic);
console.log('response.body: ' + message.toString());
client.end();
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
var mqtt = require('mqtt');
var client = mqtt.connect('mqtt://localhost', {
username: process.env.TOKEN
});
var requestId = 1;

client.on('connect', function () {
console.log('connected');
client.subscribe('v1/devices/me/attributes/response/+');
// Specify keys as comma-separated strings. An empty value returns ALL keys
// in that scope, e.g. sharedKeys: "". Omit a field to exclude that scope.
var request = { clientKeys: 'firmwareVersion,serialNumber', sharedKeys: 'targetTemperature,enabled' };
client.publish('v1/devices/me/attributes/request/' + requestId, JSON.stringify(request));
Comment thread
ShvaykaD marked this conversation as resolved.
});

client.on('message', function (topic, message) {
console.log('response.topic: ' + topic);
console.log('response.body: ' + message.toString());
client.end();
});
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Base URL: `coap://{EDGE_HOST}/api/v1/{accessToken}`
|-----------|--------|------|
| Publish telemetry | POST | `/telemetry` |
| Publish client-side attributes | POST | `/attributes` |
| Get attributes | GET | `/attributes?clientKeys=…&sharedKeys=…` |
| Get attributes | GET | `/attributes?clientKeys=…&sharedKeys=…` (or `allClientKeys=true` / `allSharedKeys=true`) |
| Subscribe to shared attribute updates | GET + Observe | `/attributes/updates` |
| Subscribe to server-side RPC | GET + Observe | `/rpc` |
| Respond to server-side RPC | POST | `/rpc/{requestId}` |
Expand Down Expand Up @@ -82,14 +82,23 @@ coap-client -m post \
-e '{"firmware_version": "1.2.0", "serial": "SN-001"}'
```

Get client and shared attributes:
Read client-side and/or shared attributes. The response groups results by scope: `{"client": {...}, "shared": {...}}`. Choose which attributes to return with these query parameters:

| Parameter | Description |
|-----------|-------------|
| `clientKeys` | Comma-separated list of client-side attribute keys to return |
| `sharedKeys` | Comma-separated list of shared attribute keys to return |
| `allClientKeys` | Set to `true` to return all client-side attributes (overrides `clientKeys`) |
| `allSharedKeys` | Set to `true` to return all shared attributes (overrides `sharedKeys`) |

**Example:**

```bash
coap-client -m get \
"coap://$EDGE_HOST/api/v1/$ACCESS_TOKEN/attributes?clientKeys=serial&sharedKeys=firmware_version"
```

Response example:
**Response:**

```json
{"client": {"serial": "SN-001"}, "shared": {"firmware_version": "1.2.0"}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,27 +153,72 @@ mosquitto_pub -h "$EDGE_HOST" -t "v1/gateway/attributes" \

### Request attribute values

Subscribe to the response topic first, then publish the request.
Subscribe to the response topic first, then publish the request. Because subscribing and publishing must happen in the same MQTT session, this cannot be shown with `mosquitto_pub`/`mosquitto_sub` as two separate commands. Use a script instead.

**Subscribe topic:** `v1/gateway/attributes/response`

**Publish topic:** `v1/gateway/attributes/request`

**Payload:**
**Request payload:**

```json
{
"id": 1,
"device": "Device A",
"client": ["key1", "key2"],
"shared": ["key3", "key4"]
"clientKeys": "fw_version,battery",
"sharedKeys": "targetFwVersion"
}
```

- **id** — required. Integer request identifier. The response includes the same `id`.
- **id** — required. Integer request identifier. The response echoes the same `id`.
- **device** — required. The device name in ThingsBoard.
- **client** — optional. Client-side attribute keys to retrieve.
- **shared** — optional. Shared attribute keys to retrieve.
- **clientKeys** — optional. Comma-separated client-side attribute keys. Set to `""` (empty string) to retrieve all client-side attributes. Omit to exclude client attributes from the response.
- **sharedKeys** — optional. Comma-separated shared attribute keys. Set to `""` (empty string) to retrieve all shared attributes. Omit to exclude shared attributes from the response.

<Aside type="caution">
The older `client` (boolean) + `key`/`keys` request fields are deprecated. Use `clientKeys`/`sharedKeys` instead.
</Aside>

Omitting **both** `clientKeys` and `sharedKeys` (sending only `id` and `device`) returns **all** client and **all** shared attributes in a single scope-separated response.

**Response payload:**

```json
{
"id": 1,
"device": "Device A",
"client": {"fw_version": "1.0", "battery": 87},
"shared": {"targetFwVersion": "2.0"}
}
```

The response is scope-separated: `client` contains client-side attributes, `shared` contains shared attributes. A scope key is omitted from the response if it was not requested.

**Example (Node.js / mqtt.js):**

```js
const mqtt = require('mqtt');
const client = mqtt.connect('mqtt://$EDGE_HOST', { username: '$ACCESS_TOKEN' });

client.on('connect', () => {
client.subscribe('v1/gateway/attributes/response', () => {
client.publish(
'v1/gateway/attributes/request',
JSON.stringify({
id: 1,
device: 'Device A',
clientKeys: 'fw_version,battery',
sharedKeys: 'targetFwVersion',
})
);
});
});

client.on('message', (_topic, message) => {
console.log(message.toString());
client.end();
});
```

### Subscribe to attribute updates

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Base URL: `http://{EDGE_HOST}:8080/api/v1/{accessToken}`
|-----------|--------|------|
| Publish telemetry | POST | `/telemetry` |
| Publish client-side attributes | POST | `/attributes` |
| Get attributes | GET | `/attributes?clientKeys=…&sharedKeys=…` |
| Get attributes | GET | `/attributes?clientKeys=…&sharedKeys=…` (or `allClientKeys=true` / `allSharedKeys=true`) |
| Subscribe to shared attribute updates (long-poll) | GET | `/attributes/updates?timeout={ms}` |
| Subscribe to RPC commands (long-poll) | GET | `/rpc?timeout={ms}` |
| Respond to server-side RPC | POST | `/rpc/{requestId}` |
Expand Down Expand Up @@ -64,12 +64,23 @@ curl -v -X POST \
</TabItem>
<TabItem label="Get attributes">

Read client-side and/or shared attributes. The response groups results by scope: `{"client": {...}, "shared": {...}}`. Choose which attributes to return with these query parameters:

| Parameter | Description |
|-----------|-------------|
| `clientKeys` | Comma-separated list of client-side attribute keys to return |
| `sharedKeys` | Comma-separated list of shared attribute keys to return |
| `allClientKeys` | Set to `true` to return all client-side attributes (overrides `clientKeys`) |
| `allSharedKeys` | Set to `true` to return all shared attributes (overrides `sharedKeys`) |

**Example:**

```bash
curl -v \
"http://$EDGE_HOST:8080/api/v1/$ACCESS_TOKEN/attributes?clientKeys=serial&sharedKeys=firmware_version"
```

Response example:
**Response:**

```json
{"client": {"serial": "SN-001"}, "shared": {"firmware_version": "1.2.0"}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,13 @@ Subscribe to `v1/devices/me/attributes/response/+`, then publish to `v1/devices/
{"clientKeys": "attribute1,attribute2", "sharedKeys": "shared1,shared2"}
```

| Field | Description |
|-------|-------------|
| `clientKeys` | Comma-separated client-side attribute keys to return; `""` returns all client attributes; omit to exclude the client scope |
| `sharedKeys` | Comma-separated shared attribute keys to return; `""` returns all shared attributes; omit to exclude the shared scope |

An empty request body (`{}`) returns all client and all shared attributes.

The following example uses MQTT.js because subscribe and publish must happen in the same session:

```js
Expand All @@ -156,6 +163,32 @@ Response example:
{"client": {"attribute1": "value1", "attribute2": true}}
```

To retrieve all shared attributes, pass an empty string for `sharedKeys`:

```js
var mqtt = require('mqtt');
var client = mqtt.connect('mqtt://' + process.env.EDGE_HOST, {
username: process.env.ACCESS_TOKEN
});

client.on('connect', function () {
client.subscribe('v1/devices/me/attributes/response/+');
client.publish('v1/devices/me/attributes/request/1',
JSON.stringify({sharedKeys: ''}));
});
Comment thread
ShvaykaD marked this conversation as resolved.

client.on('message', function (topic, message) {
console.log('Attributes:', message.toString());
client.end();
});
```

Response example:

```json
{"shared": {"targetTemperature": 24, "enabled": true}}
```

### Subscribe to shared attribute updates

Subscribe to `v1/devices/me/attributes` to receive shared attribute changes pushed by the server:
Expand Down
29 changes: 18 additions & 11 deletions src/content/_includes/docs/reference/coap-api/attributes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -30,33 +30,40 @@ Send a `POST` request to upload client-side attributes:

## Request Attribute Values

Send a `GET` request with `clientKeys` and `sharedKeys` query parameters:
Send a `GET` request to the attributes endpoint to read client-side and/or shared attribute values. The response groups results by scope: `{"client": {...}, "shared": {...}}`.

| Credential type | URL |
|-----------------|-----|
| Access Token | <HostInline product={props.product} code="coap(s)://{COAP_HOST_LABEL}:5683/api/v1/$ACCESS_TOKEN/attributes?clientKeys=attr1,attr2&sharedKeys=shared1,shared2" /> |
| X.509 Certificate | <HostInline product={props.product} code="coaps://{COAP_HOST_LABEL}/api/v1/attributes?clientKeys=attr1,attr2&sharedKeys=shared1,shared2" /> |
**Endpoint:**

| Credential type | Endpoint |
|-----------------|----------|
| Access Token | <HostInline product={props.product} code="coap(s)://{COAP_HOST_LABEL}:5683/api/v1/$ACCESS_TOKEN/attributes" /> |
| X.509 Certificate | <HostInline product={props.product} code="coaps://{COAP_HOST_LABEL}/api/v1/attributes" /> |

**Query parameters** — choose which attributes to return:

| Parameter | Description |
|-----------|-------------|
| `clientKeys` | Comma-separated list of client-side attribute keys to return |
| `sharedKeys` | Comma-separated list of shared attribute keys to return |
| `allClientKeys` | Set to `true` to return all client-side attributes (overrides `clientKeys`) |
| `allSharedKeys` | Set to `true` to return all shared attributes (overrides `sharedKeys`) |

<Aside type="note">
Use `coap-client` (not `coap-cli`) — the `coap-cli` npm tool does not support query parameters.
</Aside>

**Access Token:**
**Example** (Access Token):

<HostCode product={props.product} lang="bash" code={`coap-client -v 6 -m GET "coap://{COAP_HOST}:5683/api/v1/$ACCESS_TOKEN/attributes?clientKeys=attribute1,attribute2&sharedKeys=shared1,shared2"`} />

Response:
**Response:**

```json
{"client": {"attribute1": "value1", "attribute2": true}, "shared": {"shared1": "value2", "shared2": false}}
```

When the device profile payload type is set to Protobuf, the request and response use fixed schemas. See <DocLink product={props.product} path='reference/mqtt-api/attributes#request-attribute-values-from-server'>MQTT Attributes</DocLink> for the Protobuf schemas.

<Aside type="note">
Avoid using the same key names for client-side and shared attributes — overlapping keys lead to ambiguous responses.
</Aside>

## Subscribe to Shared Attribute Updates

Use the CoAP **Observe** option to receive push notifications when shared attributes change. The connection stays open and ThingsBoard sends a response each time a shared attribute is updated.
Expand Down
73 changes: 62 additions & 11 deletions src/content/_includes/docs/reference/gateway-api/attributes.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import DocLink from '@components/DocLink.astro';
import HostCode from '~/components/HostCode.astro';
import { Aside } from '@astrojs/starlight/components';

## Publish Client-Side Attributes

Expand All @@ -24,24 +25,74 @@ Subscribe to the response topic first, then publish the request.

**Publish:** `v1/gateway/attributes/request`

**Request:**

```json
{
"id": 1,
"device": "Device A",
"client": ["fw_version", "battery"],
"shared": ["targetFwVersion"]
}
{"id": 1, "device": "Device A", "clientKeys": "fw_version,battery", "sharedKeys": "targetFwVersion"}
```

| Field | Required | Description |
|-------|----------|-------------|
| `id` | Yes | Integer request identifier — echoed in the response |
| `device` | Yes | Device name |
| `client` | No | Client-side attribute keys to return |
| `shared` | No | Shared attribute keys to return |
| `device` | Yes | Name of a device connected through this gateway |
| `clientKeys` | No | Comma-separated client attribute keys to return; use `""` (empty string) to return all client attributes; omit the field entirely to exclude the client scope |
| `sharedKeys` | No | Comma-separated shared attribute keys to return; use `""` (empty string) to return all shared attributes; omit the field entirely to exclude the shared scope |

<Aside type="caution">The older `client` (boolean) + `key`/`keys` request fields are deprecated. Use `clientKeys`/`sharedKeys` instead.</Aside>

Omitting **both** `clientKeys` and `sharedKeys` (sending only `id` and `device`) returns **all** client and **all** shared attributes in a single scope-separated response.

**Response:**

```json
{"id": 1, "device": "Device A", "client": {"fw_version": "1.0", "battery": 87}, "shared": {"targetFwVersion": "2.0"}}
```

### Example

The following example is written in JavaScript and is based on [mqtt.js](https://github.com/mqttjs/MQTT.js). A pure command-line example is not available because subscribe and publish must happen in the same MQTT session.

1. Save the <a href="/resources/docs/reference/gateway-api/mqtt-js-gateway-attributes-request.js" download="mqtt-js-gateway-attributes-request.js">**mqtt-js-gateway-attributes-request.js**</a> file to your PC.

<Aside type="caution">
In this example, the hostname refers to a local ThingsBoard installation.
If your ThingsBoard instance is deployed on a different host, make sure to replace `localhost` with the appropriate hostname or IP address.
</Aside>

The content of the **mqtt-js-gateway-attributes-request.js** file:

```js download='mqtt-js-gateway-attributes-request.js' title="mqtt-js-gateway-attributes-request.js"
var mqtt = require('mqtt');
var client = mqtt.connect('mqtt://localhost', {
username: process.env.TOKEN
});

client.on('connect', function () {
console.log('connected');
client.subscribe('v1/gateway/attributes/response');
// clientKeys/sharedKeys are comma-separated strings. An empty value returns
// ALL keys in that scope, e.g. sharedKeys: "". Omit a field to exclude a scope.
var request = { id: 1, device: 'Device A', clientKeys: 'fw_version,battery', sharedKeys: 'targetFwVersion' };
client.publish('v1/gateway/attributes/request', JSON.stringify(request));
Comment thread
ShvaykaD marked this conversation as resolved.
});

client.on('message', function (topic, message) {
console.log('response.topic: ' + topic);
console.log('response.body: ' + message.toString());
client.end();
});
```

2. Now, follow these steps:

<Aside type="caution">
Replace `$ACCESS_TOKEN` with your gateway device's access token.
</Aside>

<HostCode product={props.product} lang="bash" code={`mosquitto_sub -h "{MQTT_HOST}" -t "v1/gateway/attributes/response" -u "$ACCESS_TOKEN" &
mosquitto_pub -h "{MQTT_HOST}" -t "v1/gateway/attributes/request" -u "$ACCESS_TOKEN" -m '{"id":1,"device":"Device A","client":["fw_version"],"shared":["targetFwVersion"]}'`} />
```bash
export TOKEN=$ACCESS_TOKEN
node mqtt-js-gateway-attributes-request.js
```

## Subscribe to Shared Attribute Updates

Expand Down
Loading