Skip to content

ChirpStack v4 / TTN v3 ↔ ThinkLink 数据接入桥(BizCode 90004)

通用 MQTT 转发桥,将 ChirpStack v4 或 TTN v3 的 LoRaWAN 设备数据双向接入 ThinkLink 平台,无需改动设备侧配置。


1. 概述

本桥是一个通用 MQTT 转发桥,面向已在 ChirpStack v4 或 TTN v3(The Things Stack)上运行 LoRaWAN 设备、希望将设备数据同步接入 ThinkLink 物联网平台的用户。桥由 4 个 ThinkLink 转发器组成,分别处理两种 NS 各自的上行(设备 → 平台)和下行(平台 → 设备)方向。上行报文在转发层统一归一为 ThinkLink AS 标准格式后,由平台侧物模型解码并落库;下行 RPC 则由平台下发至对应 NS 的下行入队接口。新增设备无需修改转发脚本,只需在平台预建设备实体并绑定物模型即可。


2. 架构与数据流

2.1 上行链路

┌─────────────────────────────────────────────────────────┐
│ 外部 NS MQTT Broker                                      │
│ ChirpStack: application/{appId}/device/{devEui}/event/up │
│ TTN:        v3/{appId}@{tenantId}/devices/{devId}/up    │
└────────────────────┬────────────────────────────────────┘
                     │ 订阅(source broker)

         ┌───────────────────────┐
         │   ThinkLink 转发器     │
         │   forwardScript()      │
         │  (chirpstack-up 或     │
         │   ttn-up)              │
         │  从 org_params 读租户码 │
         │  归一成 AS 上行格式     │
         └───────────┬───────────┘
                     │ 发布(target broker)

        ┌────────────────────────────────┐
        │ ThinkLink AS MQTT Broker        │
        │ /v32/{tenant}/as/up/data/{eui} │
        └────────────────────────────────┘


        平台 payload_parser_type=CHIRPSTACK 物模型解析
        → 遥测落库 / 触发器 / 告警

各跳说明

  • 外部 NS Broker → 转发器:转发器订阅 NS 的上行 topic(通配符 + 匹配所有应用和设备),收到原始上行 JSON。
  • 转发器处理:从原始报文提取 EUI、fPort、base64 payload、网关 RSSI/SNR/时间戳,归一成 ThinkLink AS 上行格式,并从 org_params['lns.tenant'] 读取租户码拼出目标 topic。
  • ThinkLink AS Broker → 平台:平台消费 AS MQTT 消息,按 EUI 匹配设备,调用物模型 codec(payload_parser_type=CHIRPSTACK)解码 payload,写入遥测、触发告警/触发器。

2.2 下行链路

        平台下发 RPC / 定时任务 / 手动下行


        ┌────────────────────────────────┐
        │ ThinkLink AS MQTT Broker        │
        │ /v32/{tenant}/as/dn/data/{eui} │
        └────────────────────────────────┘
                     │ 订阅(source broker = AS)

         ┌───────────────────────┐
         │   ThinkLink 转发器     │
         │   forwardScript()      │
         │  (chirpstack-down 或   │
         │   ttn-down)            │
         │  从 topic 末段取 eui   │
         │  组装 NS 下行入队 body  │
         └───────────┬───────────┘
                     │ 发布(target = NS broker)

┌──────────────────────────────────────────────────────────┐
│ 外部 NS MQTT Broker                                       │
│ ChirpStack: application/{appId}/device/{devEui}/command/down │
│ TTN:        v3/{appId}@{tenantId}/devices/{devId}/down/push  │
└──────────────────────────────────────────────────────────┘

各跳说明

  • 平台 → AS Broker:平台对设备下发 RPC 时,将下行报文发布到 AS 下行 topic,topic 末段为设备 EUI。
  • 转发器处理:从 topic 末段提取 EUI,从 msg.userdata 取 fPort、payload、confirmed 标志,组装目标 NS 的下行入队消息体,并从 org_params 读取 appId/tenantId 拼出目标 topic。
  • AS Broker → 外部 NS:NS 收到下行入队消息后,在下一个可用下行窗口(Class A)或立即(Class C)将报文发送给设备。

单 NS 约定(本期)chirpstack-downttn-down 均订阅同一 AS 下行 topic /v32/{tenant}/as/dn/data/+。本期约定一个 ThinkLink 租户只接入一个 NS(只启用对应的 *-down 转发器,另一个保持禁用),避免同一条下行指令被两个 NS 同时下发。多 NS 混用场景留待后续版本支持。


3. 前置条件

在部署本转发桥之前,请确认以下事项:

  1. 设备在 ThinkLink 平台已预建:每台 LoRa 设备须在 ThinkLink 平台按 EUI 创建设备实体,EUI 与 NS 侧保持一致(大小写不敏感,桥接脚本统一转小写)。
  2. 物模型类型为 CHIRPSTACK:设备绑定的遥测物模型须将 payload_parser_type 设为 CHIRPSTACK,且 codec 实现标准函数签名 Decode(fPort, bytes)——ThinkLink 将以此解析归一后的上行 payload。
  3. NS MQTT Broker 可达:ChirpStack 或 TTN 的 MQTT broker 地址、端口、认证凭据须已知,且部署 ThinkLink 的服务器网络能够访问该 broker。
  4. ThinkLink AS Broker 账密:需从平台系统配置中取得内部 AS MQTT broker 的连接凭据(地址通常为平台内部域名或 IP)。

4. 上行接入

4.1 ChirpStack v4 上行

转发器订阅 topic(订阅 ChirpStack broker):

application/{appId}/device/{devEui}/event/up

实际部署时以通配符 application/+/device/+/event/up 订阅,匹配所有设备。

字段来源映射

ThinkLink AS 归一字段ChirpStack v4 原始字段说明
euimsg.deviceInfo.devEui转小写
userdata.portmsg.fPort必需,缺失则丢弃
userdata.seqnomsg.fCnt帧计数
userdata.payloadmsg.database64,必需,缺失则丢弃
gwrx[0].euimsg.rxInfo[0].gatewayId转小写
gwrx[0].rssimsg.rxInfo[0].rssidBm
gwrx[0].lsnrmsg.rxInfo[0].snrdB
gwrx[0].timemsg.rxInfo[0].timeISO 8601

4.2 TTN v3 上行

转发器订阅 topic(订阅 TTN broker):

v3/{appId}@{tenantId}/devices/{devId}/up

实际部署时以通配符 v3/+/devices/+/up 订阅。

字段来源映射

ThinkLink AS 归一字段TTN v3 原始字段说明
euimsg.end_device_ids.dev_eui转小写
userdata.portmsg.uplink_message.f_port必需
userdata.seqnomsg.uplink_message.f_cnt帧计数
userdata.payloadmsg.uplink_message.frm_payloadbase64,必需
gwrx[0].euimsg.uplink_message.rx_metadata[0].gateway_ids.eui转小写
gwrx[0].rssimsg.uplink_message.rx_metadata[0].rssidBm
gwrx[0].lsnrmsg.uplink_message.rx_metadata[0].snrdB
gwrx[0].timemsg.uplink_message.rx_metadata[0].timeISO 8601

如果 NS 不携带网关接收信息(rxInfo / rx_metadata 为空),gwrx 字段将为空数组 [],不影响遥测落库。

两种 NS 的上行报文经转发器处理后,均以以下格式发布到:

发布 topic/v32/{tenant}/as/up/data/{eui}{eui} 为小写)

json
{
  "if": "loraWAN",
  "type": "data",
  "version": "3.0",
  "moteeui": "6353012b00021678",
  "gwrx": [
    {
      "eui": "a840411e5f8e7200",
      "rssi": -85,
      "lsnr": 7.5,
      "time": "2026-06-14T08:00:00Z"
    }
  ],
  "userdata": {
    "adr": false,
    "port": 1,
    "class": "ClassA",
    "seqno": 123,
    "payload": "AQIDBA==",
    "confirmed": false
  }
}

必需字段userdata.payload(base64)和 userdata.port 均不可为空;任一缺失时转发器返回 null,该帧被静默丢弃(不转发、不报错)。


5. 下行接入

平台对设备下发 RPC 或手动下行时,在 ThinkLink AS broker 发布如下格式:

AS 下行入口 topic/v32/{tenant}/as/dn/data/{eui}

转发器从 topic 末段取 eui,从 msg.userdata 取以下字段:

字段含义
msg.userdata.portLoRa fPort,必需
msg.userdata.payloadbase64 下行 payload,必需
msg.userdata.confirmed是否需要确认帧(可选,默认 false

5.1 转发至 ChirpStack v4

发布 topicapplication/{appId}/device/{eui}/command/down

appId 来自 org_params['lns.chirpstack.appId']

json
{
  "devEui": "6353012b00021678",
  "confirmed": false,
  "fPort": 1,
  "data": "AQIDBA=="
}

5.2 转发至 TTN v3

发布 topicv3/{appId}@{tenantId}/devices/{devId}/down/push

appId 来自 org_params['lns.ttn.appId']tenantId 来自 org_params['lns.ttn.tenantId']

json
{
  "downlinks": [
    {
      "f_port": 1,
      "frm_payload": "AQIDBA==",
      "priority": "NORMAL",
      "confirmed": false
    }
  ]
}

TTN 下行 device_id 映射:TTN 下行 topic 使用字符串型 devId(非裸 EUI)。转发器按以下顺序确定 devId

  1. 优先查 org_params['lns.ttn.deviceMap'][eui](运营人员在组织参数中配置的精确映射);
  2. 若映射表为空或该 EUI 不在表中,则回退使用 eui 本身作为 devId(适用于 TTN 侧 device id 与 EUI 一致的常见部署)。

6. 配置项(org_params)

租户管理员在平台 系统管理 → 服务器配置 → 组织参数 中维护以下 5 个键值:

key用途示例
lns.tenantThinkLink 租户码,用于拼接 AS topic /v32/{tenant}/as/...demo
lns.chirpstack.appIdChirpStack application id(整数字符串)1
lns.ttn.appIdTTN application idmy-app
lns.ttn.tenantIdTTN tenant id(The Things Stack 多租户标识)ttn
lns.ttn.deviceMapJSON 对象 {"eui": "ttn-device-id"};若 TTN device id 与 EUI 相同可填空对象 {}{"a1b2c3d4e5f60708":"my-sensor-01"}

安全要求:以上均为运营配置,不得写入代码仓库。Broker 账密和 API Key 在平台 Broker 连接配置中单独维护,不存入 org_params。


7. 部署步骤

步骤一:建立 3 个 MQTT Broker 连接

平台路径:系统配置 → 服务器配置 → Broker 连接管理

1a. ThinkLink AS Broker(内部)

参数说明
连接类型AS(平台内置 AS broker)
地址 / 端口在系统配置 → 服务器配置 → 内部 MQTT 查看实际地址和端口
账号 / 密码同上,取平台内部 MQTT 账密
用途上行转发器的 target;下行转发器的 source

1b. ChirpStack Broker

参数说明
连接类型Customize(自定义外部 broker)
地址 / 端口从 ChirpStack 集成页 → MQTT integration → Server 取地址(如 mqtt://chirpstack.example.com:1883
账号 / 密码ChirpStack MQTT integration 中配置的凭据
TLS按 ChirpStack 实际配置决定是否启用,生产环境建议开启
用途chirpstack-up 的 source;chirpstack-down 的 target

1c. TTN Broker

参数说明
连接类型Customize(自定义外部 broker)
地址 / 端口从 TTN Console → 应用 → Integrations → MQTT 取地址(如 mqtts://eu1.cloud.thethings.network:8883
账号 / 密码TTN MQTT 账密(username 格式 {appId}@{tenantId},password 为 API Key)
TLSTTN 云服务默认启用 TLS
用途ttn-up 的 source;ttn-down 的 target

步骤二:创建 4 个转发器

平台路径:高级功能 → 转发器 → 新增

逐个按下表填写,脚本内容粘贴对应转发脚本的完整内容。

2a. chirpstack-up(ChirpStack 上行)

参数
名称chirpstack-up
Source BrokerChirpStack broker(步骤 1b)
订阅 Topicapplication/+/device/+/event/up
Target BrokerThinkLink AS broker(步骤 1a)

2b. ttn-up(TTN 上行)

参数
名称ttn-up
Source BrokerTTN broker(步骤 1c)
订阅 Topicv3/+/devices/+/up
Target BrokerThinkLink AS broker(步骤 1a)

2c. chirpstack-down(ChirpStack 下行)

参数
名称chirpstack-down
Source BrokerThinkLink AS broker(步骤 1a)
订阅 Topic/v32/{tenant}/as/dn/data/+(将 {tenant} 替换为实际租户码,与 lns.tenant 一致)
Target BrokerChirpStack broker(步骤 1b)

2d. ttn-down(TTN 下行)

参数
名称ttn-down
Source BrokerThinkLink AS broker(步骤 1a)
订阅 Topic/v32/{tenant}/as/dn/data/+(同上,替换为实际租户码)
Target BrokerTTN broker(步骤 1c)

单 NS 约定chirpstack-downttn-down 订阅同一 AS 下行 topic。本期一个租户只接一个 NS——只启用对应的 *-down 转发器,另一个保持禁用,避免同一条下行同时被两个 NS 下发。

步骤三:填写 org_params

平台路径:系统管理 → 服务器配置 → 组织参数

在目标租户的组织参数中维护以下键值(仅填写实际使用的 NS 对应项,不用的可留空):

key说明示例(请替换为实际值)
lns.tenantThinkLink 租户码demo
lns.chirpstack.appIdChirpStack application id1
lns.ttn.appIdTTN application idmy-app
lns.ttn.tenantIdTTN tenant idttn
lns.ttn.deviceMap{"eui":"ttn-device-id"} 映射,device id 与 EUI 相同时填 {}{"a1b2c3d4e5f60708":"my-sensor-01"}

对每台需要接入的 LoRa 设备:

  1. 在平台按设备 EUI 创建设备实体(EUI 与 NS 侧保持一致)。
  2. 为设备绑定遥测物模型,确认物模型 payload_parser_typeCHIRPSTACK,codec 实现 Decode(fPort, bytes) 函数。
  3. 确认设备 EUI 在平台侧存储为小写(或平台查询时不区分大小写)。

步骤五:端到端联调

上行验证

  1. 从 ChirpStack / TTN 控制台或模拟器发送一帧上行数据(有效 fPort + payload)。
  2. 在 ThinkLink 平台 → 设备详情 → 遥测 中确认数据已落库。
  3. 若遥测为空,检查平台转发器运行日志(高级功能 → 转发器 → 运行日志),确认 lns.tenant、设备预建状态、物模型类型。

下行验证

  1. 在 ThinkLink 平台对目标设备手动下发 RPC 或调用下行接口。
  2. 在 ChirpStack → 设备 → LoRaWAN Frames 或 TTN Console → Live data 中确认下行已入队。
  3. 若下行未到 NS,检查下行转发器订阅 topic 中 {tenant} 是否已替换为实际值,以及相关 org_params 是否填写。

8. 故障排查

现象可能原因排查路径
上行遥测不落库lns.tenant 与实际租户码不符检查 org_params + 转发器运行日志
上行遥测不落库设备未预建或 EUI 不一致平台设备列表核查
上行遥测不落库物模型未设为 CHIRPSTACK 类型查看设备绑定的物模型详情
下行 NS 未收到下行转发器订阅 topic 中 {tenant} 未替换为实际值转发器配置详情
下行 NS 未收到appId / tenantId 等 org_params 未填写org_params 配置页
TTN 下行 topic 报错lns.ttn.deviceMap 缺失且 TTN device id 不等于 EUI补填 lns.ttn.deviceMap
两个 NS 同时收到下行chirpstack-downttn-down 同时处于启用状态禁用未使用的 *-down 转发器(单 NS 约定)