ThingsBoard
Интеграция ThingsBoard пересылает данные устройств приложения ONS в ThingsBoard по HTTP. На каждый uplink сервер отправляет два POST-запроса в HTTP API устройства ThingsBoard: атрибуты и телеметрию. Устройство ONS связывается со своим устройством ThingsBoard через токен доступа, который хранится в переменной устройства. Данные идут только в одну сторону: команды из ThingsBoard на устройства через эту интеграцию не попадают. Интеграцию настраивают на странице приложения в веб-интерфейсе; у приложения может быть одна интеграция ThingsBoard.
Как подключить
- В ThingsBoard создайте устройство и скопируйте его токен доступа (Access Token) со страницы устройства.
- В ONS откройте карточку этого устройства в разделе «Узлы», на вкладке «Настройки узла» включите режим «Расширенный» и в блоке «Переменные» добавьте переменную
ThingsBoardAccessTokenсо значением токена, см. Токен устройства. - Повторите шаги 1 и 2 для каждого устройства, данные которого нужны в ThingsBoard.
- Откройте приложение в разделе «Приложения» и в блоке «Интеграции» на карточке ThingsBoard.io нажмите «Add».
- В поле «Server» укажите адрес ThingsBoard, например
https://thingsboard.example.com, см. Поля интеграции. - Включите переключатель «Active». У новой интеграции он выключен, а выключенную интеграцию сервер не запускает.
- Нажмите «Сохранить».
Блок «Интеграции» есть только на странице существующего приложения: на странице добавления его нет. Подпись карточки — «Интеграция ThingsBoard.io пересылает данные на ThingsBoard.io через HTTP.».
- Заголовок страницы приложения — App ID, App EUI и имя приложения: блок «Интеграции» есть только на странице существующего приложения.
- Интеграции — блок с карточками интеграций приложения.
- Подпись карточки ThingsBoard.io — «Интеграция ThingsBoard.io пересылает данные на ThingsBoard.io через HTTP.».
- Add — открывает форму новой интеграции ThingsBoard. Кнопка видна, пока у приложения нет интеграции ThingsBoard.
Сохранённые настройки сервер применяет сразу, без перезапуска: активную интеграцию он перезапускает с новой конфигурацией, выключенную или удалённую — останавливает. Изменить настройки можно кнопкой «Edit» на карточке, удалить интеграцию — кнопкой «Удалить».
Поля интеграции
| Поле | Что задаёт |
|---|---|
| «Server» | Обязательно. Базовый адрес ThingsBoard: http:// или https://, хост, при необходимости порт и префикс пути — без /api/v1 и без / в конце. Например, https://thingsboard.example.com |
| «Active» | Включает интеграцию. У новой интеграции выключено |
- ThingsBoard.io — пока открыта форма, в заголовке блока «Интеграции» стоит название интеграции.
- Server — базовый адрес ThingsBoard, без
/api/v1и без/в конце. - Active — включает интеграцию; у новой интеграции выключен.
- Сохранить — сохраняет настройки, сервер применяет их сразу.
- Отмена — закрывает форму без сохранения.
Адреса запросов сервер собирает подстановкой строк: <Server>/api/v1/<токен>/attributes и <Server>/api/v1/<токен>/telemetry. С «Server» https://thingsboard.example.com и токеном my_device_token атрибуты уйдут на https://thingsboard.example.com/api/v1/my_device_token/attributes.
Форма проверяет поле «Server»: адрес должен начинаться с http:// или https:// и не заканчиваться на /. Пустое поле — ошибка «URL сервера обязателен», неверный адрес, в том числе с / в конце, — «URL сервера должен начинаться с http:// или https://. Например, http://example.com или https://example.com». Сервер при сохранении проверяет только, что поле задано и значение — строка: пустую строку он примет. Лишний /api/v1 в адресе форма не заметит, и запросы уйдут на …/api/v1/api/v1/….
Токен устройства
ThingsBoard определяет устройство по токену в адресе запроса. Сервер берёт токен из переменной устройства ThingsBoardAccessToken.
- Имя переменной — ровно
ThingsBoardAccessToken, с учётом регистра. Значение сервер подставляет в адрес как есть: не обрезает пробелы и не кодирует символы. - Где задать. В карточке существующего устройства, в режиме «Расширенный», блок «Переменные» — таблица с колонками «Ключ», «Значение», «Действие» и кнопками «Добавить» и «Удалить». Изменить переменную нельзя: удалите её и добавьте заново. Добавить ключ, который у устройства уже есть, сервер не даст: «Variable already exists.». В окне массового изменения узлов переменных нет — задать токен многим устройствам можно через REST API.
- Когда начинает действовать. Новый или изменённый токен действует для uplink, принятых после изменения, перезапуск не нужен. Uplink, которые уже стоят в очереди интеграции, уйдут со старым токеном.
- Устройство без токена. Если у устройства нет переменной
ThingsBoardAccessToken, сервер отбрасывает его uplink: в ThingsBoard ничего не уходит. Запись «ThingsBoardAccessToken not found in variables. Skipping data send.» появляется только в журнале сервиса, в веб-интерфейсе её не видно. Отправку данных остальных устройств приложения это не задерживает. - Кто видит токен. Значения переменных карточка показывает открытым текстом: токен видит каждый, кто может открыть устройство. Токен входит в адрес запроса. В журнал настроек попадает только факт изменения переменных, без значений.
- Соседство с настройками кодека. Те же переменные получает JS-кодек приложения как
input.variables; кодек Protocol 78 читает из нихdeviceTypeиlanguage. Токен и настройки кодека лежат в одном списке переменных устройства.
- Заголовок карточки — DevEUI, DevAddr и описание устройства.
- Простой / Расширенный — переключатель режима на вкладке «Настройки узла»; блок «Переменные» есть только в режиме «Расширенный».
- Переменные — блок переменных устройства внизу вкладки, под блоком «Теги».
- Ключ, Значение, Действие — колонки таблицы; значения видны открытым текстом.
- Строка добавления — в поле «Ключ» введите
ThingsBoardAccessToken, в поле «Значение» — токен устройства ThingsBoard. - Добавить — добавляет переменную сразу, кнопка «Сохранить» карточки для этого не нужна.
- Удалить — удаляет переменную после подтверждения. Изменить переменную нельзя: удалите её и добавьте заново.
Токен через REST API
Переменными устройства управляет REST API сервера, которым пользуется веб-интерфейс. Адрес — <база API>/node/{DevEUI}/variables/, только для активных устройств. База API зависит от развёртывания: /api/v1/ или /ons/api/v1/, если веб-интерфейс открыт по префиксу /ons/.
| Метод | Тело | Что делает | Нужное право |
|---|---|---|---|
GET | — | Возвращает переменные устройства словарём | Просмотр узла |
POST | {"ThingsBoardAccessToken": "<токен>"} | Добавляет переменные; за один запрос можно передать несколько | Изменение узла |
DELETE | {"variable": "ThingsBoardAccessToken"} | Удаляет переменную | Изменение узла |
Что отправляет сервер
На каждый uplink сервер одновременно отправляет два POST-запроса:
| Запрос | Адрес | Тело |
|---|---|---|
| Атрибуты | <Server>/api/v1/<токен>/attributes | См. Атрибуты |
| Телеметрия | <Server>/api/v1/<токен>/telemetry | См. Телеметрия |
- Заголовки:
Content-Type: application/jsonиUser-Agent: OnsHTTPClient. Тело — JSON. - Тайм-аут каждого запроса — 5 секунд.
- Ошибкой сервер считает ответ с кодом 400 и выше, тайм-аут и ошибку соединения. Что происходит при ошибках — в разделе Доставка и повторы.
- Сертификат TLS сервер проверяет всегда, см. «Что важно знать».
В интеграцию приходят только uplink с данными — подтверждаемые и неподтверждаемые (Confirmed и Unconfirmed Data Up). Join и статусы кадров downlink в неё не попадают.
Атрибуты
| Ключ | Значение |
|---|---|
dev_eui | DevEUI устройства |
dev_addr | DevAddr устройства |
app_id | App ID приложения, которому принадлежит устройство |
| Теги | Теги приложения и устройства: каждый тег — отдельный ключ |
{
"dev_eui": "6F1E570FFE14DBFC",
"dev_addr": "78130AE1",
"app_id": "77179F01",
"building": "A"
}
- Теги добавляются после трёх полей: сначала теги приложения, затем теги устройства. Тег устройства перекрывает одноимённый тег приложения, а тег с именем
dev_eui,dev_addrилиapp_idперекрывает одноимённое поле. - Атрибуты сервер отправляет заново с каждым uplink.
- По документации ThingsBoard запрос на
/attributesзаписывает клиентские (client-side) атрибуты устройства.
Телеметрия
| Ключ | Значение |
|---|---|
battery_level | Заряд батареи из последнего ответа устройства на запрос статуса (DevStatusAns): 0 — внешнее питание, 255 — устройство не может измерить заряд, иначе — проценты. null, пока сервер не получил такой ответ |
margin | Запас по SNR из того же ответа, дБ, от −32 до 31. null, пока сервер не получил ответ |
join_request_time | Время последнего Join Request устройства по часам шлюза. null, если сервер не видел активации устройства |
data_… | Данные JS-кодека, см. ниже |
Поля battery_level, margin и join_request_time есть в каждом запросе. Их смысл тот же, что у одноимённых полей сообщения realtime_data WebSocket API.
Данные кодека
Данные кодека попадают в телеметрию, только если у приложения задан JS-кодек и decodeUplink вернул поле data. Сервер берёт только data: errors и warnings кодека в ThingsBoard не уходят. Без JS-кодека в телеметрии остаются три поля статуса.
Объект data сервер раскладывает в плоский набор ключей:
- ключ — путь от корня с префиксом
dataи разделителем_; элемент массива получает в пути свой индекс; - передаются только конечные значения, в полном пути которых есть подстрока
value— строчными буквами:rawValueне подходит; - если
valueесть в имени родительского поля, напримерvalues, передаются все значения под ним.
data из decodeUplink | Что уйдёт в ThingsBoard |
|---|---|
{"temperature": {"value": 25.5, "unit": "C"}} | data_temperature_value: 25.5; unit отбрасывается |
{"sensors": {"temp": {"value": 22.0}}} | data_sensors_temp_value: 22.0 |
{"readings": [{"value": 1.0}, {"value": 2.0}]} | data_readings_0_value: 1.0, data_readings_1_value: 2.0 |
{"temperature": 21.5} | Ничего: в пути нет value |
Если кодек отдаёт плоский объект без value в именах, в ThingsBoard из его данных ничего не попадёт.
Пример: uplink TWM с кодеком Protocol 78
У приложения настроен JS-кодек Protocol 78, у устройства заданы переменные deviceType = TWM, language = ru и ThingsBoardAccessToken. Устройство прислало полезную нагрузку 782520125EC3732F04A8CD002D8101. Кодек вернул:
{
"data": {
"id": 120,
"seq": 37,
"language": "ru",
"device_type": "TWM",
"flags": {
"current_limited": { "value": false, "description": "current_limited" },
"temperature_low": { "value": false, "description": "Низкая температура" },
"temperature_high": { "value": false, "description": "Высокая температура" },
"tamper_magnet": { "value": false, "description": "Датчик магнитного поля (TAMPER)" },
"tamper_open": { "value": false, "description": "Обнаружен тампер" },
"time_need_update": { "value": true, "description": "Время устройства требует обновления" },
"tamper_overlight": { "value": false, "description": "tamper_overlight" },
"tamper_backflow": { "value": false, "description": "Обнаружен обратный поток" }
},
"payloads": [
{
"shift": 15,
"len": 12,
"pid": "0x12",
"sid": "Sensors",
"direct": {
"initialization": false,
"ts": 1742800606000,
"timestamp": 1742800606,
"utctimestamp": "2025-03-24T07:16:46.000Z",
"alarms": [],
"temperature": { "rawValue": 205, "value": 20.5, "coefficient": 0.1, "unit": "°C" },
"humidity": { "rawValue": 385, "value": 38.5, "coefficient": 0.1, "unit": "%" }
}
}
]
},
"errors": [],
"warnings": []
}
Тело запроса телеметрии:
{
"data_flags_current_limited_value": false,
"data_flags_temperature_low_value": false,
"data_flags_temperature_high_value": false,
"data_flags_tamper_magnet_value": false,
"data_flags_tamper_open_value": false,
"data_flags_time_need_update_value": true,
"data_flags_tamper_overlight_value": false,
"data_flags_tamper_backflow_value": false,
"data_payloads_0_direct_temperature_value": 20.5,
"data_payloads_0_direct_humidity_value": 38.5,
"battery_level": 100.0,
"join_request_time": "2026-10-01T06:12:40.114233Z",
"margin": 9
}
- Флаги кодек отдаёт как
{value, description}, поэтому в ThingsBoard уходят восемь ключейdata_flags_<флаг>_value. - Измерения лежат в
payloads[].direct: температура и влажность приходят какdata_payloads_0_direct_temperature_valueиdata_payloads_0_direct_humidity_value. Индекс нагрузки зависит от её места в кадре: в кадре с несколькими нагрузками то же измерение получит другой ключ. - Не уходят
id,seq,language,device_type,description,shift,len,pid,sid,initialization,alarms,rawValue,coefficient,unitи метки времениts,timestamp,utctimestamp.
Разобрать свой пакет кодеком и посмотреть его JSON можно в Playground Protocol 78.
Доставка и повторы
- Хватает одного успешного запроса. Если удался хотя бы один из двух запросов, сервер считает uplink доставленным. Если атрибуты ушли, а телеметрия нет, телеметрия этого uplink теряется.
- Оба запроса не удались — пауза. Сервер возвращает uplink в очередь и приостанавливает интеграцию: перестаёт читать очередь, значок на карточке — Disconnected. Первая пауза — около 20 секунд, следующие — 40, 80, 160 и 300 секунд, дальше по 300 секунд; к каждой добавляется до 10 %. После паузы интеграция снова читает очередь, и первая удачная отправка сбрасывает отсчёт пауз.
- Uplink уходят по одному. Uplink приложения сервер отправляет строго по одному и в порядке очереди: следующий — только после того, как закончил с предыдущим. Пока ThingsBoard отклоняет оба запроса по одному uplink — отвечает кодом 400 и выше или не отвечает за 5 секунд, — отправка в ThingsBoard по всему приложению стоит и возобновляется после пауз до 5 минут. Ждут и uplink остальных устройств.
- Неверный токен останавливает отправку. На неверный токен ThingsBoard, по его документации, отвечает кодом 401 на оба запроса. Сервер возвращает uplink в очередь, и отправка по всему приложению стоит. Исправление переменной не поможет uplink, которые уже в очереди: токен записан в них в момент приёма. Проверьте токены до включения интеграции.
- Пока ThingsBoard недоступен, uplink копятся. У каждой интеграции своя очередь на сервере; по умолчанию число сообщений в ней и срок их жизни не ограничены. После восстановления ThingsBoard сервер отправляет накопленное. По умолчанию очередь удаляется вместе с данными, если её не читают 14 дней.
- Повторы возможны. Доставка — «как минимум один раз»: например, если ThingsBoard принял оба запроса, но не ответил за 5 секунд, сервер отправит uplink ещё раз.
Состояние на карточке
| Значок | Что значит |
|---|---|
| Нет значка | Интеграция ещё не запускалась |
| Connected, зелёный | Интеграция запущена и готова отправлять. Это не значит, что ThingsBoard доступен |
| Disconnected, жёлтый | Интеграция не читает очередь. У активной интеграции — пауза после ошибки отправки, см. Доставка и повторы |
- Значок переключателя — зелёный: интеграция включена («Active»), серый — выключена.
- Значок состояния — здесь Connected, зелёный. Disconnected — жёлтый; у интеграции, которая ещё не запускалась, значка нет.
- Edit — открывает форму с текущими настройками.
- Удалить — удаляет интеграцию после подтверждения.
Состояния Error у интеграции ThingsBoard не бывает. Счётчиков успешных и неудачных отправок и истории запросов у неё нет: дошли ли данные, видно только в ThingsBoard.
Что важно знать
- Обратного канала нет. Команды и RPC из ThingsBoard через эту интеграцию на устройство не попадут. Отправить устройству downlink можно через интеграцию MQTT или WebSocket API.
- Время в ThingsBoard — время доставки. Телеметрия уходит без поля
ts, и по документации ThingsBoard в этом случае ставит время своего сервера. Показания, накопленные за время недоступности ThingsBoard, придут с временем доставки. Метки времени из кодека (ts,timestamp,utctimestampу Protocol 78) не передаются: в их пути нетvalue. - Параметры приёма не передаются. В ThingsBoard не уходят
rssi,lsnr,datr,freq,fcnt,fport, шлюз приёма,packet_loss_rateи сырые байты полезной нагрузки. Они есть в сообщениях интеграции MQTT и вrealtime_dataWebSocket API. - Самоподписанный сертификат не подойдёт. Сертификат TLS сервер проверяет всегда, настройки, отключающей проверку, у интеграции нет. ThingsBoard с самоподписанным сертификатом по
https://подключить не получится. - «Доступные приложения» добавляют чужие uplink. Интеграция получает и uplink приложений, выбранных в поле «Доступные приложения» её приложения. У таких uplink
app_idв атрибутах — App ID исходного приложения, а токен берётся из переменных устройства исходного приложения. - После выключения или удаления накопленное уйдёт при включении. Выключение («Active») и удаление останавливают чтение очереди, но очередь интеграции ThingsBoard сервер не удаляет. Uplink, накопленные за время выключения, уйдут в ThingsBoard при повторном включении, если интеграция была выключена меньше 14 дней. Если интеграцию удалили и создали заново в течение 14 дней, в ThingsBoard уйдут uplink, накопленные с момента удаления.
- Строки из цифр ThingsBoard может сохранить числами. По документации ThingsBoard параметр
transport.json.type_cast_enabled, по умолчанию включённый, превращает строковые значения телеметрии и атрибутов, похожие на число, в числа. Тогда DevAddr или DevEUI из одних цифр, например26011234, может сохраниться числом, а ведущие нули — пропасть.
См. также
- Приложения — блок «Интеграции» и поле «Доступные приложения».
- Узлы — теги и переменные устройства.
- MQTT — интеграция с downlink и полными данными uplink.
- Подписаться на данные в реальном времени — поля
battery_level,marginиjoin_request_time. - Playground Protocol 78 — разбор пакета кодеком Protocol 78.