4、MQTT客户端库实战(一):使用Eclipse Paho Java客户端连接ThingsBoard,发送遥测与属性数据。
好,咱们进入实战环节了。前面几章我们把MQTT协议和ThingsBoard的通信机制讲了个透,现在该动手写代码了。这一章,我带你用Eclipse Paho Java客户端库,把ThingsBoard连起来,然后发点遥测数据和属性数据上去。
说实话,Paho这个库是我用得最多的Java MQTT客户端。它成熟、稳定,社区活跃。我在好几个物联网项目里都用它,从智能路灯到工业设备监控,从来没出过幺蛾子。你想想看,一个库能让你这么放心,那肯定是有道理的。
4.1 环境准备与依赖引入
先搞定开发环境。我假设你已经有了Java开发环境,JDK 8以上就行。我用的是Maven项目,如果你用Gradle,原理一样,改一下依赖坐标就行。
在pom.xml里加入这个依赖:
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>1.2.5</version>
</dependency>
嗯,版本号我建议用1.2.5,这是目前最稳定的版本。我曾经试过用最新的1.2.6,结果发现有个小bug,在重连逻辑上有点问题,后来还是退回了1.2.5。所以,别追新,稳定为王。
4.2 创建MQTT客户端并连接ThingsBoard
接下来,我们创建一个MQTT客户端,连接到ThingsBoard。这里有几个关键参数:
- Broker地址:ThingsBoard的MQTT Broker地址,通常是
tcp://your-thingsboard-host:1883。如果你用了SSL,那就是ssl://...,端口是8883。 - Client ID:每个设备必须有唯一的Client ID。在ThingsBoard里,这个ID就是设备的访问令牌(Access Token)。
- Clean Session:我建议设为
true,这样每次连接都是全新会话,避免旧消息干扰。
看代码:
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
public class ThingsBoardMqttClient {
private static final String BROKER = "tcp://demo.thingsboard.io:1883";
private static final String ACCESS_TOKEN = "YOUR_DEVICE_ACCESS_TOKEN";
private static final String CLIENT_ID = ACCESS_TOKEN; // 注意:Client ID就是Access Token
private MqttClient client;
public void connect() throws MqttException {
// 使用内存持久化,不存盘
MemoryPersistence persistence = new MemoryPersistence();
client = new MqttClient(BROKER, CLIENT_ID, persistence);
MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(true);
options.setConnectionTimeout(10);
options.setKeepAliveInterval(60);
System.out.println("正在连接 ThingsBoard...");
client.connect(options);
System.out.println("连接成功!");
}
}
关键点:Client ID必须等于Access Token。这是ThingsBoard的硬性要求,少一个字符都不行。我刚开始做的时候,以为Client ID可以随便起,结果连了半天连不上,查日志才发现是这个问题。
4.3 发送遥测数据
连接上了,就该干活了。遥测数据,说白了就是设备上报的实时数据,比如温度、湿度、电压这些。ThingsBoard要求遥测数据以JSON格式发送,并且要发布到特定的Topic上。
Topic格式:v1/devices/me/telemetry
来看一个完整的发送示例:
public void sendTelemetry() throws MqttException {
// 构造遥测数据JSON
String telemetryJson = "{"
+ "\"temperature\": 25.6,"
+ "\"humidity\": 68.2,"
+ "\"voltage\": 220.5"
+ "}";
MqttMessage message = new MqttMessage(telemetryJson.getBytes());
message.setQos(1); // QoS 1,确保至少送达一次
client.publish("v1/devices/me/telemetry", message);
System.out.println("遥测数据已发送: " + telemetryJson);
}
这里我用了QoS 1。为什么不用QoS 0?因为遥测数据虽然允许丢失,但在工业场景下,丢一个数据点可能就意味着错过一次告警。QoS 2又太重了,没必要。所以QoS 1是折中的好选择。我在项目里一直这么用,没出过问题。
小技巧:如果你要批量发送多个数据点,可以把它们放在一个JSON数组里。比如:[{"ts": 1630000000000, "values": {"temperature": 25.6}}, ...]。这样一次发布就能上报多条记录,效率更高。
4.4 发送属性数据
属性数据和遥测数据不同。属性通常是不怎么变化的数据,比如设备型号、固件版本、安装位置等。ThingsBoard把属性分为两类:客户端属性和服务端属性。我们这里发的是客户端属性,也就是设备主动上报的属性。
Topic格式:v1/devices/me/attributes
代码示例:
public void sendAttributes() throws MqttException {
String attributesJson = "{"
+ "\"firmwareVersion\": \"1.2.3\","
+ "\"deviceModel\": \"TB-100\","
+ "\"installationDate\": \"2024-01-15\""
+ "}";
MqttMessage message = new MqttMessage(attributesJson.getBytes());
message.setQos(1);
client.publish("v1/devices/me/attributes", message);
System.out.println("属性数据已发送: " + attributesJson);
}
你看,代码结构和发送遥测几乎一样,只是Topic不同。这就是ThingsBoard设计得好的地方——统一了通信模式,降低了学习成本。
4.5 完整示例:连接、发送、断开
把上面几段代码串起来,就是一个完整的客户端程序了。我习惯在main方法里按顺序调用:
public static void main(String[] args) {
ThingsBoardMqttClient tbClient = new ThingsBoardMqttClient();
try {
tbClient.connect();
tbClient.sendTelemetry();
tbClient.sendAttributes();
// 记得断开连接,释放资源
tbClient.client.disconnect();
System.out.println("已断开连接。");
} catch (MqttException e) {
System.err.println("发生错误: " + e.getMessage());
e.printStackTrace();
}
}
注意:一定要在程序结束时调用disconnect()。我曾经在一个长期运行的服务里忘了断开连接,结果导致连接池被占满,新设备连不上来。排查了半天才发现是这个问题。嗯,血的教训。
4.6 验证数据是否到达ThingsBoard
代码跑起来了,怎么知道数据真的到了ThingsBoard呢?最简单的方法:登录ThingsBoard的Web界面,找到你的设备,查看"最新遥测"和"属性"页面。
如果数据正确显示,恭喜你,你已经成功迈出了第一步。如果没显示,别急,先检查这几个地方:
- Access Token是否正确? 复制粘贴的时候容易多一个空格。
- Broker地址和端口是否可达? 用telnet测试一下。
- JSON格式是否合法? 可以用在线JSON校验工具检查。
我记得有一次,我怎么发数据ThingsBoard都不收,最后发现是JSON里多了一个逗号。这种小错误最坑人,所以我现在每次发数据前都会先打印一下JSON字符串,肉眼检查一遍。
4.7 小结
这一章我们做了三件事:创建Paho客户端连接ThingsBoard、发送遥测数据、发送属性数据。代码量不大,但每一步都是基础中的基础。你想想看,后面所有的复杂功能——比如设备固件升级、远程控制、告警触发——都是建立在这几个简单操作之上的。
下一章,我们会深入Paho客户端的回调机制,实现消息订阅和实时响应。到时候,你的设备就能"听"到ThingsBoard下发的指令了。做好准备,咱们继续。