跳至主要內容

设备 MQTT 接入

约 4534 字大约 15 分钟

设备 MQTT 接入

什么是 MQTT ?

MQTT 全称是 Message Queuing Telemetry Transport,它是一种基于消息队列的轻量级应用层通信协议,实现了消息发布和订阅。设备可以作为客户端的形式通过它来发布和接收消息,实现数据上报和实时控制。

MQTT 是一种简单的消息传递协议,设计用于具有低带宽的受限设备。因此,它是物联网设备接入的完美解决方案。

ThingsCloud 支持哪些设备?

ThingsCloud 云平台提供了标准的 MQTT 接入协议,支持 MQTT v3.1/v.5,任何支持 MQTT 协议的设备都可以通过相应的 MQTT 客户端代码接入云平台。

那么,设备要支持 MQTT,有哪些常见的方式呢?通常不外乎以下几种:

  • 各种单片机或嵌入式系统,使用支持 MQTT 或 TCP 协议的 2G/3G/4G/5G 、 NBIoT 等无线通信模组,通过 AT 指令、串口透传、SDK 等方式快速接入云平台。
  • 本身支持 OpenCPU 的通信模组,例如:ESP32、Air724UG 等,通过模组固件二次开发实现接入云平台。
  • 无法直接连网的传感器、IO 控制器、PLC 等设备,通过支持 MQTT 的网关/DTU 接入云平台。

我们也会不断提供各种常见设备的接入示例。

设备 MQTT 接入点

了解了基本概念后,我们开始学习如何让设备通过 MQTT 接入 ThingsCloud 云平台,并和云平台进行各类消息通信。

提示

在此之前,我们在 快速上手 的章节中简单介绍了在控制台创建设备,并完成了一些基本的 MQTT 通信,如果您没有阅读,建议您大概了解一下。

ThingsCloud 公有云支持全球多个区域,并随着设备接入量不断扩张。每个接入的设备有专用的 MQTT 接入点,获得设备 MQTT 接入点的正确方式,就是在控制台进入设备详情的【连接】页面,复制该设备的 MQTT 接入点。

我们提供多种类型的 MQTT 接入点和认证方式,如下:

接入类型用途接入点示例
MQTT普通认证方式,适合大多数普通设备或资源受限设备mqtt://<endpoint>:1883
MQTT over TLSX.509 认证方式,适合对通信安全要求严格的设备mqtts://<endpoint>:1884

MQTT 身份认证

设备通过 MQTT 协议连接云平台时,需要完成基于 MQTT 的身份认证,云平台支持以下认证方式。

普通认证方式

对于普通认证方式,在 MQTT 连接时,使用基于 username/password 的认证方式,需要用到设备的普通证书,如下:

MQTT 连接参数说明
usernameAccessToken设备创建后自动生成,每个设备唯一,量产设备可通过 API 自动获取 AccessToken,实现一型一密。
passwordProjectKey项目创建后自动生成,不支持修改。
clientId空或任意不对 clientId 做任何限制,可随意填写。

设备详情页 > 连接 中可以复制以上标识。

这里以 MQTT.fx 为例,连接参数填写大致如下图:

MQTT.fx 设置连接到 ThingsCloud
MQTT.fx 设置连接到 ThingsCloud

提示

请确保以上标识只用于设备固件开发,烧录到设备 ROM/Flash 中,避免泄露。

对于量产阶段的设备,无需手动复制每个设备的 AccessToken 进行单独烧录,可采用 一型一密 的方式,通过 API 自动获取 AccessToken,以及自动创建设备。

需要注意的是,ThingsCloud 对同一个设备身份信息只支持一个 MQTT 连接,也就是说,如果在两个或多个物理设备中,使用同样的 username/password 身份信息连接云平台,即便 clientId 使用不同的字符串,云平台仍然将这些连接视为同一个设备,这会导致后一个设备连接成功后会顶掉之前的设备连接。

X.509 TLS 认证方式

在一些对通信安全要求严格的物联网领域,比如智能门锁、电表、水表、燃气表等,您可以使用基于 X.509 TLS 的 MQTT 安全认证方式,我们目前只在 ThingsCloud 专有区和私有区中支持该认证方式。

更进一步的物联网安全措施,可以在设备端集成 SE 安全芯片,或使用内置 SE 安全芯片的通信模组,实现设备和云平台双向认证。ThingsCloud 对智能设备厂商的私有区服务提供 SE 解决方案。

MQTT 主题一览

ThingsCloud 作为物联网 PaaS 云平台,对设备 MQTT 接入提供了内置的访问协议规范,让设备和云平台的消息通信更加有章可循,大大简化了物联网项目的开发难度,缩短了产品的开发周期。

不同于普通的 MQTT 使用方式,我们提供了标准的内置主题,这足以实现绝大多数的物联网应用场景。

而对于另一些个性化的消息通信场景,我们也提供了灵活的自定义主题,您完全创建自己的主题,并配合包括云函数在内的规则引擎,实现任何消息通信需求。

发布主题

以下主题用于 设备向云平台发布消息

消息类型主题
设备上报属性值attributes
设备获取当前属性值attributes/get/<id>
设备上报事件event/report/<id>
设备回复命令command/reply/<id>
设备自定义数据上报data/<identifier>

请注意:

  • 以上的主题只能用于设备端发布消息,不能用来订阅。如需在应用端接收设备发布的消息,请使用 MQTT应用端订阅规则转发,更多介绍请浏览 API
  • 设备端在发布(publish)消息时,QoS 请使用 0,不要使用 1 或 2。ThingsCloud 不支持 QoS,以免通信模组重复发送。

订阅主题

以下主题用于 设备接收云平台下发的消息

消息类型主题
接收属性上报的响应attributes/response
接收属性获取的响应attributes/get/response/+
接收下发的属性attributes/push
接收事件上报的响应event/response/+
接收下发的命令command/send/+
接收命令回复的响应command/reply/response/+
接收自定义数据下发data/<identifier>/set

提示

以上自定义数据相关主题中的 identifier,是指自定义数据流的标识符。详细介绍请浏览 自定义数据流

请注意,以上主题只能用于设备端订阅,不能用来发布。如需在应用端向设备下发消息,可使用以下方式:

提示

您可能已经发现,所有的主题中并没有出现设备标识,这也是 ThingsCloud 的不同之处。

当设备连接 ThingsCloud 平台后,会通过独有的虚拟映射方式,拥有独立的主题命名空间,所以每次发布消息或订阅消息时,主题名称非常简洁,大大简化了开发和配置过程。

下面我们会逐个介绍每个发布主题和订阅主题的使用方法。

先看看最佳实践教程?

设备上报属性

当设备自身的属性发生变化时,通过向云平台上报属性,实现云平台设备属性的及时更新,以及应用系统的设备数据实时更新。

设备发布消息

设备上报属性使用以下主题:

attributes

消息内容必须是 JSON 格式,如果不是 JSON 格式的消息,设备会被云平台主动断开连接。

一个简单的属性上报消息如下:

{
    "temperature": 28.5,
    "light": 2000,
    "switch": true
}

设备发布以上消息后,控制台的设备详情页会实时更新显示设备属性的最新值。

提示

ThingsCloud 控制台通过 MQTT Websockets 方式订阅设备属性的实时更新,您可以在不刷新页面的情况下实时查看设备属性值的变化。有时网络原因导致 Websockets 连接中断,您只需刷新页面即可恢复。

我们也将这种 Websockets 订阅方式开放给应用开发,如果您的应用基于 ThingsCloud 云平台,便可以实现页面实时更新。

如果设备按一定时间间隔上报属性,就实现了一个基本的数据采集上报功能。

云平台会自动保存这些属性的时序数据,如下图:

属性上报
属性上报

对于 number 类型的属性,云平台还提供了时序图表,方便浏览历史曲线。

属性上报
属性上报

当然,您也可以使用如下的 JSON 消息格式来上报属性数据:

{
    "sensor_1": {
        "temperature": 28.5,
        "light": 2000,
        "switch": true  
    },
    "sensor_2": {
        "temperature": 27.1,
        "light": 1800,
        "switch": false  
    }
}

但是对于这种将属性值放入嵌套结构中的消息,云平台并不会直接保存嵌套结构内的属性时序数据,而只保存 sensor_1 这样的结构体属性值,供设备和应用查询。

如果设备一定要按这样的嵌套格式上报属性,或者有些时候您无法改变设备的上报规则,有没有办法让云平台也生成属性时序数据呢?答案是肯定的,那就是利用云平台托管的规则引擎,自动将嵌套结构中的属性数据,复制到 JSON 消息的顶层结构中,这样就会自动被云平台记录时序数据。具体的做法请参考后边的章节。

设备接收消息

如果我们想知道属性上报是否被云平台成功接收,可以订阅如下主题:

attributes/response

请注意,订阅主题只需要在设备 MQTT 成功连接云平台后执行一次即可。当设备上报属性后,便会通过该主题收到来自云平台的响应消息,如果云平台接收成功,响应消息如下:

{
  "result": 1,
  "ts": 1609143039050
}

如果云平台未成功接收,响应消息中会包含错误原因,例如:

{
  "result": 0,
  "message": "Device message frequency too fast, please wait for a moment",
  "errcode": 402
}

该错误表示属性上报间隔太短,所以云平台会自动忽略过于频繁的属性上报消息。

设备获取属性

对于连网设备,有些属性是在云端进行设置下发的。当设备重启后,需要立即从云平台获取属性当前值,实现设备初始化。

设备发送消息

当设备希望从云平台获取属性当前值时,发送消息到如下主题:

attributes/get/<id>

<id> 可以使用任意不超过 6 位的整数,例如:

attributes/get/1000

消息内容格式如下:

{
    "keys": []
}

这表示获取所有属性,也可以指定个别属性,如下:

{
    "keys": [
        "temperature",
        "humidity"
    ]
}

设备接收消息

请确保设备已经订阅了如下主题:

attributes/get/response/+

如果设备不支持 + MQTT 通配符,也可以订阅如下主题:

attributes/get/response/<id>

这里的 <id> 要和前边发送消息中的 <id> 一致,否则无法接收响应消息。

当设备发送获取属性的消息后,便会通过以上订阅主题,收到如下的响应消息:

{
  "result": 1,
  "attributes": {
    "temperature": 34.2,
    "humidity": 67
  }
}

设备接收云端下发属性

除了设备主动获取属性以外,我们也需要让设备可以实时接收云平台下发的属性更新。

非常简单,确保设备已订阅如下主题:

attributes/push

当云平台下发属性给设备时,设备会通过以上订阅主题,立即收到 JSON 结构的消息,例如:

{
    "switch": false
}

这个示例消息显然是通知设备关闭某个开关,设备通过自身的程序实现该功能后,可以接着向云平台上报属性或上报事件,让云平台得到确认。

那么,如何实现云平台下发属性呢?我们提供两种方式:

控制台

在控制台的设备详情【属性】页面中,这种方式适合开发调试阶段或小规模项目。

属性下发
属性下发

应用端 API

调用云平台提供的应用端 API,这种方式可以集成到任何应用系统中。

设备上报事件

前边都是属性相关的消息,这一节我们来了解一下事件。

设备发送消息

通过事件,设备可以向云端报告消息,而不需要上报任何属性。例如:设备的 AI 视觉传感器捕捉到活动人数,上报给云平台。

一个事件由如下内容组成:

  • 事件名称

可以理解为函数名,是事件的唯一表示。

  • 事件参数

可以理解为函数的参数,是 JSON 格式的结构体,包含若干参数。

设备可以随时向云平台上报事件,只需将事件消息发布到如下主题:

event/report/<id>

<id> 的取值为不超过 6 位的整数,例如:

event/report/1000

发布的事件消息格式如下:

{
    "method": "{name}",
    "params": {
        "key1": "{value1}",
        "key2": "{value2}",
        ...
    }
}

例如前边提到的,工厂生产线上的 AI 视觉传感器捕捉到产品数量后,上报事件给云平台,那么消息可能是这样的:

{
    "method": "productFound",
    "params": {
        "count": 3,
        "location": "REGION.B43",
        "tags": "RED",
        "detail": [
            "100474",
            "100475",
            "100342"
        ]
    }
}

设备接收消息

如果我们想知道事件上报是否被云平台成功接收,可以订阅如下主题:

event/response/+

或者

event/response/<id>

请注意,订阅主题只需要在设备 MQTT 成功连接云平台后执行一次即可。当设备上报事件后,便会通过该主题收到来自云平台的响应消息,如果云平台接收成功,响应消息如下:

{
  "result": 1,
  "ts": 1609143039050
}

值得注意的是,响应消息中的成功,只代表云平台成功收到了事件上报,并不代表对事件进行业务处理的结果

云平台收到设备的事件上报后,如何处理事件呢?规则引擎便派上用场了,通过规则引擎,您可以将事件实时推送到第三方 Webhook URL,或通过规则引擎的云函数实现告警策略,当然还可以实现对其它设备的联动控制。

设备接收云端下发命令

与事件相反,命令是由云平台向设备主动下发的一组消息,用来实时通知设备执行某个特定的功能。

设备接收消息

设备在 MQTT 连接云平台后,确保订阅如下主题:

command/send/+

如果设备不支持 + MQTT 通配符,也可以订阅如下主题:

command/send/<id>

订阅成功后,设备便处于等待接收命令的状态。当云平台下发命令时,设备便会收到命令消息。

命令消息的格式也是基于 JSON 的结构体,如下:

{
    "method": "{name}",
    "params": {
        "key1": "{value1}",
        "key2": "{value2}",
        ...
    },
    "id": "{id}"
}

您可能发现了,它和事件消息格式非常类似,只是多了一个 id。您可以认为它就是从云平台向设备的一个远程调用(RPC)。

设备回复消息

设备收到命令消息后,通过自身的代码逻辑实现特定的功能后,可以回复命令,也可以不回复命令。

云平台会自动接收回复命令,并和下发命令进行匹配,一次下发命令只能接收一次回复命令,它们的匹配正是通过使用一致的 <id> 来保证。

设备回复命令消息的格式如下:

{
    "method": "{name}",
    "params": {
        "key1": "{value1}",
        "key2": "{value2}",
        ...
	}
}

没错,它和命令下发的消息格式一模一样,回复命令发布的主题如下:

command/reply/<id>

请注意,回复命令的主题中的 <id>,一定要和对应的命令下发消息中的 id 保持一致。

设备自定义数据上报

详情浏览 自定义数据流的 MQTT 主题

设备接收自定义数据下发

详情浏览 自定义数据流的 MQTT 主题

MQTT 调试

在接入云平台的设备开发过程中,有多种方法可以帮助您快速调试,并验证消息收发通信。

MQTT 客户端工具

使用 MQTT 客户端工具,例如:

MQTT.fx 设置连接到 ThingsCloud
MQTT.fx 设置连接到 ThingsCloud
MQTT.fx 发布数据到 ThingsCloud
MQTT.fx 发布数据到 ThingsCloud