把 ThinkLink 接进 Home Assistant 与 Node-RED:一条 MQTT 转发器能走通的路

LoRaWAN 项目里有一类需求很常见:数据已经在 ThinkLink 上跑起来了,但用户想看的界面不是 ThinkLink 的------他想看 Home Assistant 的仪表盘,或者想在 Node-RED 里画一条自己的流程线。

这个需求合理。Home Assistant 的 Dashboard 和自动化规则确实好用,Node-RED 的可视化编排在做跨系统联动时也确实顺手。但要把数据送过去,得先搞清楚一件事:​这两个平台都不认识 LoRaWAN​。

Home Assistant 官方支持的通信方式是 MQTT、Zigbee、Z-Wave、HTTP 这些,没有 LoRaWAN。它不能直连网关,也不解析 LoRaWAN 帧。Node-RED 同理------它只是一个流程引擎,数据从哪来完全取决于你给它接什么输入节点。

所以中间必须有一个网络服务器(NS)先把 LoRaWAN 帧解成结构化数据。ThinkLink 干的正是这一步:网关收到射频帧 → NS 解密 → 物模型解析脚本把二进制变成有名字的字段 → 这时数据才变成"温度 24.6 度"这种能被消费的东西。

剩下的问题只有一个:怎么把解析后的数据送到 HA / Node-RED 手里。


一、先说一个版本变化:内置 HA 集成已经没有了

这一条要写在最前面,因为它决定了整篇文章的做法。

如果翻旧版本的手册,能看到"物模型里配置 Home Assistant 字段""服务器配置里填 HA 地址"这类说明。但官方文档在 2.00.066 的说明里写得很明确:​本轮源码移除了内置 ThingsBoard / Home Assistant 集成及相关字段 ​,下文旧版的 HA / ThingsBoard 配置说明"仅适用于旧版本,不可作为 2.00.066 的操作步骤"。同一段里还特别注明:BACnet / Modbus 保留。

也就是说,从 2.00.066 起,"在 ThinkLink 里填一个 HA 地址就能自动推实体"这条路不存在了。取而代之的是通用能力:​**MQTT 转发器(Broker + Forwarder)**​。

这个变化不是退化。内置集成的问题是它把对接方式写死了------平台只能按自己定义的格式推,对方系统必须配合。改成 MQTT 转发器之后,Topic 怎么改、Payload 怎么重组、要不要过滤,全在一个 JavaScript 脚本里,对接任何系统都用同一套机制。HA、Node-RED、ThingsBoard、自研应用,在 ThinkLink 这一侧的差别只剩脚本内容不同。

还有一处口径需要注意:产品对比资料里提到 ThinkLink 边缘形态(TKG,网关内置)预置了 Home Assistant OS 与 ThingsBoard CE 组件。那是同一台硬件上另外跑一个 HA 实例的部署方式,不是"ThinkLink 把数据推进 HA"。两件事不要混为一谈------本文讲的是后者,即把数据从 ThinkLink 送到一个已有的 HA / Node-RED 实例。


二、三条可用路径,先选对再动手

对接之前有个选择题。官方文档里其实出现过三种推送方式,可用性和推荐度差别很大。

路径 机制 状态 适用
设备侧"第三方转发"开关 + 服务器配置 ThirdParty 老式直推 旧版配置,已停用 不建议新项目使用
服务器配置 → 第三方 MQTT(ThirdParty) 平台侧配一个 Broker 地址 文档口径存在冲突,见下 需要与实际版本确认
高级功能 → Broker + 转发器 订阅内部 Topic,转发到目标 Broker 当前版本的正式做法 推荐

这里有一个必须如实说明的文档冲突:MQTT 转发器文档 明确写着"无需在设备侧开启任何'第三方转发'开关,也无需在'服务器配置'中配置任何第三方平台。旧版本中的这两处配置已经停用";而服务器配置文档的 1.2 节仍然保留着 ThirdParty 配置区(Protocol / Host / Port / Telemetry Topic / Username / Password)与"设备详情页启用 ThirdParty 开关"的操作说明。

两份文档说的不是同一件事,或者至少不是同一个版本。处理办法很简单:以实际平台版本为准,先在界面上看有没有"高级功能 → Broker / 转发器"入口。 有,就走转发器;那是新版本的主路径,也是本文下面讲的做法。


三、转发器:两步配置,五个字段

数据流是这样的:

ThinkLink 内部 Broker(AS 或 ThinkLink) ↓ Source Broker / Subscription Topic 转发器规则(可选 JavaScript 转换) ↓ Target Broker 第三方 MQTT Broker(Customize)

第一步:建两个 Broker 连接

进入​高级功能 → Broker​。一条转发规则需要一个来源连接和一个目标连接。

来源 Broker 有两种内部类型,选哪个决定了你拿到的数据形态:

  • ThinkLink:经过物模型解析后的遥测数据。字段已经有了名字和单位。
  • AS:LoRaWAN 解密后的上行原始数据,还没过物模型。

绝大多数场景选 ThinkLink。选 AS 的理由只有一个:你想在外部系统里自己做解析,或者要拿 RSSI / SNR 这类射频侧信息做网络质量分析。如果目的只是"让 HA 显示一个温度",选 AS 等于把已经做完的解析工作重做一遍。

内部 Broker 的地址和租户凭据由平台自动填写,不需要去服务器配置页找。

目标 Broker 新增一个 Customize 类型,填对方的信息:

名称和启用状态 MQTT URL,例如 mqtt://192.168.1.50:1883 或 mqtts://host:8883 用户名和密码(对方要求时) CA 证书、客户端证书等 TLS 信息(对方要求时)

如果 HA 和 Node-RED 都装在同一台机器上(常见情况),目标就是这台机器上跑的 Mosquitto,或者 HA 自带的 MQTT 插件(HA Add-on: Mosquitto broker)。

保存启用后,先看 Broker 列表的运行状态:正常是 RUNNING,出现 ERROR 就查 ErrMsg,逐项核对 URL、端口、凭据、证书、网络连通性。

第二步:建转发器规则

进入​高级功能 → 转发器 → 新增​:

字段 说明
名称 转发规则名称
启用 开启后规则才会订阅和转发
Source Broker 要订阅的来源 Broker
Target Broker 要发布到的目标 Broker
Subscription Topic 来源 Broker 上的订阅 Topic,支持 + 和 # 通配符
Custom Script 可选;转换 Topic、消息内容或 retain 选项
备注 / 提交说明 可选;用于说明规则和版本变更

一条硬约束:​Source Broker 和 Target Broker 不允许同时选 AS / ThinkLink 内部类型​,避免内部循环。第三方转发的正常组合是:

Source Broker = AS 或 ThinkLink Target Broker = Customize

订阅 Topic 怎么填

这是最容易填错的一项,因为没有默认值,占位符必须替换。

Source Broker 数据类型 Subscription Topic
ThinkLink 物模型解析后的遥测数据 /v32/{tenant}/tkl/up/telemetry/#
AS LoRaWAN 解密后的上行原始数据 /v32/{tenant}/as/up/data/#
AS 多网关收集完成后的完整上行消息 /v32/{tenant}/as/up/dataAll/#

{tenant} 要替换成实际组织账号,在个人中心可以查看,​不要原样保留占位符 ​。# 表示该组织下所有设备;只想转发一台设备时,把 # 换成那台设备的 DevEUI。

举一个具体的例子:组织账号是 mtfac,要转发全部设备的解析后遥测,订阅 Topic 就是 /v32/mtfac/tkl/up/telemetry/#。


不配脚本时,转发器原样保留 Topic 和消息内容------这其实是一个很好的起点:先让消息直通,在 HA / Node-RED 那边抓一条真实消息,看清字段结构,再决定要不要写脚本。 凭想象写的脚本往往第一次跑不通。

需要改格式时,入口函数只有一个:

function forwardScript({ topic, msg, org_params }) { if (!msg?.telemetry_data) return null

return { topic: ${org_params.target_topic_prefix}/${msg.device_id}, option: { retain: false }, msg: { temperature: msg.telemetry_data.T, humidity: msg.telemetry_data.H } } }

三个输入参数:topic 是收到消息时的原始 Topic,msg 是解析后的消息内容,org_params 是只读的组织参数。

返回对象支持三个字段:topic(发到目标 Broker 的 Topic)、msg(发布的消息内容)、option(MQTT 发布选项,比如 { retain: true })。​返回 null 或不返回内容,这条消息就被丢弃​------这是做过滤的正路,比如只转发某一类设备、只在数值超阈值时才推。

官方示例里出现的字段是 msg.device_id 和 msg.telemetry_data,telemetry_data 下面的键(示例里是 T 和 H)由物模型里的字段名决定。不要猜字段名,抓一条真实消息确认。 第 21 期讲过物模型解析脚本,那里定义的字段键就是这里能取到的键。

org_params 值得单独说一句。它是​组织级别的"环境变量"​,在系统管理 → 服务器配置 → 组织参数 按键值对维护,一次维护全租户共享,平台执行脚本时自动注入。设计目的是把对接外部系统用的地址、前缀、业务标识从脚本里剥离出来------换环境、切前缀只改一处,不用逐个改脚本。而且它无需重启服务即刻生效,只有组织管理员能看见。


五、Home Assistant 侧:两种接法

说明:以下 Home Assistant 的配置方式属于 ​Home Assistant 通用知识​,不是 ThinkLink 官方文档内容。HA 版本迭代较快,字段名以你所用版本为准。

数据到了 HA 用的 Broker 之后,HA 要把它变成实体(entity)。有两条路。

第一条:手写 MQTT sensor。 在 configuration.yaml 里声明传感器,用 state_topic 指向转发器发布过来的 Topic,用 value_template 从 JSON 里取值。这条路最稳,字段完全可控,代价是每台设备每个测点要写一段配置。设备数量少、点位固定时非常适合。

第二条:自己造 MQTT 自动发现消息。 HA 的 MQTT 集成支持 discovery 机制:往约定的 discovery Topic(默认前缀 homeassistant/)发一条带设备元数据的消息,HA 就会自动创建对应实体。ThinkLink 不会原生产出这种格式,但可以在​转发脚本里造出来 ​------forwardScript 的返回值里 topic 和 msg 都是你说了算,完全可以让第一条上行消息触发一个 discovery 消息。

这条路的优势是加设备不用改 HA 配置,代价是脚本复杂度和一次性的调试成本。设备数量多、经常增减时值得做。

一个实操提醒:ThinkLink 的遥测消息是​一台设备一条消息、里面多个字段 ​,而 HA 的实体是​一个实体一个值 ​。这个一对多的转换要么在 HA 侧用 value_template 拆,要么在转发脚本里把一条消息拆成多条按字段发布。想清楚在哪一层拆,比后面反复改要省事。

还有一点必须提醒:HA 的 Dashboard 上显示"未知"或"不可用",很多时候不是 HA 的问题,而是数据压根没到 Broker。先在 Broker 上用命令行订阅确认消息真的到了,再去查 HA 配置。


六、Node-RED:三个节点就能跑起来

Node-RED 接 MQTT 比 HA 更直接,因为它不要求实体模型,拿到什么处理什么。

最小流程是三个节点:​mqtt in ​(订阅 Broker 上的 Topic)→ ​json ​(把字符串解析成对象)→ ​debug 或 dashboard 节点​。

mqtt in 里填的就是转发器发到目标 Broker 的 Topic,也就是 forwardScript 返回的那个 topic。如果走了直通没写脚本,那它就是原始 Topic /v32/mtfac/tkl/up/telemetry/{eui}。

Node-RED 比 HA 好用的地方在中间那层:你可以在流程里插 function 节点做任意逻辑------单位换算、阈值判断、跨设备关联、写入数据库、调第三方 API。做"温湿度超限时先查同一区域另一个传感器,两个都超才告警"这类联动,Node-RED 比在平台侧写触发脚本更直观,也比在 HA 自动化里写更灵活。

反向控制也是一条 mqtt out 节点的事,但下一节的警告一定要看。


七、写方向:从 HA / Node-RED 回到设备,别只看"发送成功"

这是整个对接里最容易产生误判的地方,和第 24 期讲 BACnet 写入时是同一个道理。

从 HA 或 Node-RED 发一条控制指令,到设备真的执行,中间至少三件事:

  1. 指令被平台接受------这一步是即时的。
  2. RPC 下发到设备 ------如果设备是 Class A 的 LoRaWAN 终端,下行只能在每次上行之后的接收窗口发出(RX1 约 1 秒、RX2 约 2 秒)。设备十分钟上报一次,这条指令最坏要等十分钟才落到设备。
  3. 设备回传新值------执行结果要等下一次上行才能看到。

所以 HA 上点了一个按钮、界面上没反应,不等于指令失败了。验收时要写成"​下发后在 N 个上报周期内回读确认​",而不是"点击后立刻看结果"。

给集成方的一条实用建议:如果这个项目里控制指令的时效性要求高(比如要在几秒内响应),Class A 终端本身就不是合适的选择,应该考虑 Class C。这个判断要在设备选型阶段做,不是对接阶段能补救的。


八、在线状态:一个必须单独开的开关

HA 和 Node-RED 都需要知道某个传感器还活着吗。

2.00.084 起,转发器在 ThinkLink 来源规则里可以订阅设备状态主题:

/v32/{tenant}/tkl/device/status/{eui}

或者在授权组织范围内用 /v32/{tenant}/tkl/device/status/+。

有两个坑必须提前说:

第一,状态消息的产生要求设备 notify_offline="TRUE",这个开关默认是关闭的。 不开就没有状态消息,转发器再怎么配也收不到。注意转发器本身不要求设备侧任何"第三方转发"开关,状态消息的产生只取决于 notify_offline。

第二,这条消息没有 telemetry_data。 上面那段示例脚本开头的 if (!msg?.telemetry_data) return null 会把它直接丢掉。要转发状态,要么走原消息直通,要么在脚本里按状态格式单独处理。

另外,平台上的"在线"有三个口径,彼此不能互换(第 22 期讲过):设备列表的活动时间、server_attrs.online、MQTT 通知里的布尔值。对接外部系统时用哪个,要在交付文档里写清楚,别让两边对同一个"在线"有不同理解。


九、2.00.070 之后:别只盯着 RUNNING

转发器的连接与订阅行为在 2.00.070 有一轮改动,直接影响排障判断。

登记成功不等于订阅成功。 规则启用时,即使来源 Broker 离线,也会先登记订阅需求,连接恢复后自动发起订阅。但只有收到 SUBACK 才确认订阅真的成了。连接期间失败的订阅每 3 秒自动重试。

目标不可用时不缓冲、不补发。 规则启动时会在原连接超时上限内等待自己启用的目标 Broker 就绪,超时后仍登记源订阅;目标不可用时沿用跳过转发策略,​不新增消息缓冲或离线补发保证​。这意味着转发器不是可靠消息队列------断线期间的数据不会事后补。

不提供 exactly-once。 MQTT 重投递或发送端重复发送都可能产生重复消息,需要业务去重就自己在消息里带标识。

一句话总结:不能只依据"规则已启用"或"Broker 已连接"判断转发成功,必须看真实消息流。

另外,同一组织的转发 Broker 并行加载,某个连接较慢不会让其他 Broker 排队等待。多个脚本共用一个主题时,移除其中一个不影响其他脚本;最后一个回调移除后才退订。


十、排障:按这个顺序查

官方文档给的五步,实测很管用:

  1. 确认来源和目标 Broker 都已启用,目标 Broker 状态为 RUNNING。
  2. 检查 ErrMsg、主机、端口、账号密码和 TLS 证书。
  3. 确认转发器本身已启用(不是只保存了)。
  4. 确认 Subscription Topic 与实际消息 Topic 匹配------尤其检查 {tenant} 有没有替换、有没有多写或少写一层。
  5. 暂时关掉自定义脚本,确认原消息能否直通;能通再排查脚本返回值。

第 5 步是最容易被跳过、也最常查出问题的一步。新手最常见的脚本错误就是返回了 null(比如 msg.telemetry_data 不存在)却不自知,以为"数据没转发过来",实际上是自己把消息丢了。

补充两条实操经验:

  • 每次保存转发器脚本都会产生版本快照,可以在编辑器里查看详情或还原。还原会生成一条新的版本记录,不删除原有历史------所以脚本改坏了不要慌,还原即可。
  • 系统平台可以维护公共转发器 :公共规则在租户侧可见但只读;选择具体组织时,规则可以引用该组织的 Broker 和 org_params。多组织复用同一套转发逻辑时用这个。

十一、验收清单

# 项目 通过标准
1 路径选择 使用"高级功能 → Broker + 转发器",未依赖已停用的旧版第三方转发开关
2 来源 Broker 按需求选定 ThinkLink(已解析)或 AS(原始),未混淆
3 目标 Broker 类型为 Customize,保存后状态为 RUNNING,ErrMsg 为空
4 订阅 Topic {tenant} 已替换为实际组织账号;层级与官方口径一致
5 规则启用 转发器"启用"已打开(不是只保存);已收到 SUBACK 确认
6 真实消息流 在目标 Broker 上实测订阅到消息,不只依据状态显示
7 脚本行为 直通先行验证;启用脚本后确认未误返回 null 丢弃消息
8 字段口径 telemetry_data 下的字段名已用真实消息确认,未凭想象命名
9 HA / Node-RED 侧 实体或流程读到值,且与平台侧显示一致
10 在线状态 设备 notify_offline="TRUE" 已开;状态主题已订阅且未被脚本丢弃
11 写控制 下发后按上报周期回读确认,未以"发送成功"作为验收依据
12 断线行为 已确认断线期间消息不补发;业务侧有去重或补偿设计
13 版本留档 转发器脚本版本、平台版本、目标 Broker 配置已记录

十二、结语

从 2.00.066 起,ThinkLink 把"对接某个具体平台"换成了"对接任意 MQTT 端点"。对 Home Assistant 和 Node-RED 来说,这不是坏消息------内置集成能给的只是一个固定格式,而转发器给的是一个可以自己写转换的地方。

代价是这段脚本要你自己写、自己调。但它的边界很清晰:Topic 怎么填有固定口径,脚本入口只有一个函数,返回值只有三个字段,排障顺序官方给了五步。真正容易出错的都是细节------{tenant} 没替换、脚本返回了 null、状态消息没有 telemetry_data、目标 Broker 断线期间的消息不会补发。

把这些细节写进验收清单,比反复试错省时间。


相关阅读

  • 第 21 期:ThinkLink 物模型解码脚本实战------把 15 个字节变成一张能看的表
  • 第 22 期:ThinkLink 触发模型与告警规则实战------不迟到、不刷屏、找对人
  • 第 24 期:BACnet/IP 与 Modbus TCP 在 ThinkLink 上的对接实战------从字段映射到 YABE 调试

本文基于 ThinkLink 官方文档撰写,配置路径与参数以实际平台版本为准。官方手册:www.think-link.net/docs/zh/Adv...www.think-link.net/docs/zh/Qui...www.think-link.net/docs/zh/Pro...

相关推荐
没事写点啥1 小时前
WeKnora 回答溯源
前端·后端·ai编程
LuHang2 小时前
Vue3 大屏项目 MQTT 实战:机场与无人机 OSD 实时数据总线
前端
2401_885885042 小时前
芬兰语音通知接口怎样对接?语音提醒接入流程
android·前端·python·php·语音识别
铁皮饭盒2 小时前
这6个小模型各有绝活, 且都可cpu/浏览器端运行
前端·后端
徐小夕2 小时前
JitKnow AI知识库 4.7 发布|多文档推理+拖拽 Agent + 技能库,打造更懂业务的 AI 知识中台
前端·vue.js·github
小poop3 小时前
从“雷峰塔”到“对象”:JavaScript基础语法入门指南
前端·javascript
ReStock活库3 小时前
Zephyr异步SPI调用返回后,为什么不能立即复用发送缓冲区?
java·前端·网络
计算机魔术师3 小时前
半年营收163亿,算力债却到7800亿,这账谁算得清
前端
chunyublog3 小时前
HDFS 上传文件名空格问题排障教程
前端·javascript·npm