重新连接是针对与mqtt服务器的连接断开时,直接用mqttConnectOptions去重新连接
如果代码报错导致连接断开,则需要通过重新初始化去连接
package com.xw.elevator.platform.mqtt;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.util.concurrent.ScheduledExecutorService;
@Component
public class Client {
private static final Logger logger = LoggerFactory.getLogger(PushCallback.class);
public static final String HOST = "tcp://192.168.121.36";
private static final String clientid = "client124";
public static String Issue_Topic = "Fatri/Devs/{DeviceNo}/Issue";
public static final String DevInfo_Topic = "Fatri/Devs/Report/DevInfo";
public static final String EleStatus_Topic = "Fatri/Devs/Report/EleStatus";
public static final String EleWran_Topic = "Fatri/Devs/Report/EleWarn";
static MqttClient client;
private static MqttConnectOptions mqttConnectOptions = null;
private static String userName = "admin";
private static String passWord = "123456";
private ScheduledExecutorService scheduler;
MqttMessage message;
volatile static MqttTopic topic;
MqttTopic topicD;
MqttTopic topicR;
static {
init(clientid);
start();
}
//初始化,连接mqtt服务器
public static void init(String clientId) {
mqttConnectOptions = new MqttConnectOptions();
if (null != mqttConnectOptions) {
// 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,设置为true表示每次连接到服务器都以新的身份连接
mqttConnectOptions.setCleanSession(false);
mqttConnectOptions.setUserName(userName);
mqttConnectOptions.setPassword(passWord.toCharArray());
// 设置超时时间
mqttConnectOptions.setConnectionTimeout(10);
// 设置会话心跳时间
mqttConnectOptions.setKeepAliveInterval(20);
try {
//new MemoryPersistence() 存储方式
client = new MqttClient(HOST, clientid, new MemoryPersistence());
} catch (MqttException e) {
e.printStackTrace();
}
//设置回调
if (null != client) {
client.setCallback(new PushCallback());
try {
//连接
client.connect(mqttConnectOptions);
} catch (MqttException e) {
e.printStackTrace();
}
}
}
}
//订阅主题
public static void start() {
try {
int[] Qos = new int[]{0, 0, 0};
String[] topics = new String[]{DevInfo_Topic, EleStatus_Topic, EleWran_Topic};
client.subscribe(topics, Qos);
logger.info("订阅主题成功");
} catch (Exception e) {
e.printStackTrace();
}
}
//发布
public void publish(MqttTopic topic, MqttMessage message) throws MqttPersistenceException, MqttException {
MqttDeliveryToken token = topic.publish(message);
token.waitForCompletion();
logger.info("Client message is published completely! " + token.isComplete());
}
//重连
public void reConnect() throws MqttException {
logger.info("进reConnect方法了");
if (null != client) {
logger.info("client:{}", client);
logger.info("isConnected?{}", client.isConnected());
if (!client.isConnected()) {
// logger.info("mqttConnectOptions:{}",mqttConnectOptions);
if (null != mqttConnectOptions) {
logger.info("重新连接");
client.setCallback(new PushCallback());
// try {
logger.info("连接");
//此处的重新连接是针对与mqtt服务器的连接断开时,直接用mqttConnectOptions去重新连接
client.connect(mqttConnectOptions);
//如果代码报错导致连接断开,则需要通过重新初始化去连接
// init(clientid);
start();
} else {
logger.info("mqttConnectOptions is null");
init(clientid);
start();
}
}
} else {
logger.info("重新初始化");
init(clientid);
start();
}
}
}
回调函数
package com.xw.elevator.platform.mqtt;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttPersistenceException;
import org.eclipse.paho.client.mqttv3.MqttTopic;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import net.sf.json.JSONObject;
import com.alibaba.fastjson.JSON;
import com.xw.elevator.platform.biz.dto.Feature;
import com.xw.elevator.platform.biz.dto.ReveiveElevatorInfoDTO;
import com.xw.elevator.platform.web.ResponseOfReveiveElevatorInfo;
/**
* 发布消息的回调类
* <p>
* 必须实现MqttCallback的接口并实现对应的相关接口方法CallBack 类将实现 MqttCallBack。
* 每个客户机标识都需要一个回调实例。在此示例中,构造函数传递客户机标识以另存为实例数据。 在回调中,将它用来标识已经启动了该回调的哪个实例。
* 必须在回调类中实现三个方法:
* <p>
* public void messageArrived(MqttTopic topic, MqttMessage message)接收已经预订的发布。
* <p>
* public void connectionLost(Throwable cause)在断开连接时调用。
* <p>
* public void deliveryComplete(MqttDeliveryToken token)) 接收到已经发布的 QoS 1 或 QoS 2
* 消息的传递令牌时调用。 由 MqttClient.connect 激活此回调。
*/
public class PushCallback implements MqttCallback {
private static final Logger logger = LoggerFactory.getLogger(PushCallback.class);
private static int number = 0;// 唯一数字,集群第一台=0,第二台=200000,第三台=400000
private static int maxNum = 200000;// 最大值,集群第一台=200000,第二台=400000,第三台=600000
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");// 年月日格式
MqttTopic topic1;
public void connectionLost(Throwable cause) {
// 连接丢失后,一般在这里面进行重连
logger.info("连接断开,可以做重连");
// Client client = new Client();
Client myMqttClient = new Client();
for (int i = 0; i < 10; i++) {
try {
myMqttClient.reConnect();
logger.info("客户端重新连接成功");
} catch (Exception e) {
logger.info("重新连接失败:{},"+"正在第"+i+"次尝试",e.getMessage());
continue;
}
return;
}
throw new RuntimeException("无法连接服务器");
}
public void deliveryComplete(IMqttDeliveryToken token) {
logger.info("deliveryComplete---------" + token.isComplete());
}
public void publish(MqttTopic topic, MqttMessage message) throws MqttPersistenceException, MqttException {
MqttDeliveryToken token = topic.publish(message);
token.waitForCompletion();
logger.info("message is published completely! " + token.isComplete());
}
public void messageArrived(String topic, MqttMessage message) throws Exception {
// subscribe后得到的消息会执行到这里面
logger.info("接收消息主题:{}", topic);
logger.info("接收消息Qos:{}", message.getQos());
logger.info("接收消息内容:{}", new String(message.getPayload()));
JSONObject jsonObject = JSONObject.fromObject(new String(message.getPayload()));
logger.info("jsonObject:" + jsonObject);
String DeviceNo = jsonObject.getString("DeviceNo");
String MessageType = jsonObject.getString("MessageType");
// 获取当前时间的字符串
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date = sdf.format(new Date());
logger.info("MessageType:" + MessageType);
// 1.接收心跳报文不用应答
if (null != MessageType && MessageType.equals("AliveInfo")) {
logger.info("接收的是心跳报文");
return;
}
logger.info("DeviceNo:" + DeviceNo);
// 2.接收的是注册报文,则需要发布注册应答报文.
if (null != MessageType && MessageType.equals("DeviceReg")) {
logger.info("接收的是注册报文,需要发布注册应答报文.");
Client client = new Client();
client.message = new MqttMessage();
client.message.setQos(2);
client.message.setRetained(true);
// client.Issue_Topic.replace("{DeviceNo}", DeviceNo);
client.topic = client.client.getTopic(client.Issue_Topic.replace("{DeviceNo}", DeviceNo));
RegReply r = new RegReply();
Data d = new Data();
d.setDateTimestamp(date);
r.setMessageType("RegReply");
r.setDeviceNo(DeviceNo);
r.setData(d);
logger.info(r.toString());
String s = JSON.toJSONString(r);
logger.info("s:" + s);
client.message.setPayload(s.getBytes());
logger.info("client.topic:" + client.topic + "," + "client.message:" + client.message);
client.publish(client.topic, client.message);
logger.info("注册应答报文发送成功");
}
// 3.接收的是设备信息报文,则需要发送设备信息应答报文
if (null != MessageType && MessageType.equals("DeviceInfo")) {
logger.info("接收的是设备信息报文,需要发送设备信息应答报文");
Client client = new Client();
client.message = new MqttMessage();
client.message.setQos(2);
client.message.setRetained(true);
// client.Issue_Topic.replace("{DeviceNo}", DeviceNo);
Client.topic = Client.client.getTopic(Client.Issue_Topic.replace("{DeviceNo}", DeviceNo));
RegReply r = new RegReply();
Data d = new Data();
d.setDateTimestamp(date);
r.setMessageType("InfoReply");
r.setDeviceNo(DeviceNo);
r.setData(d);
logger.info(r.toString());
String s = JSON.toJSONString(r);
logger.info("s:" + s);
client.message.setPayload(s.getBytes());
logger.info("client.topic:" + client.topic + "," + "client.message:" + client.message);
client.publish(client.topic, client.message);
logger.info("设备信息应答报文发送成功");
}
// 4.接收的是电梯状态信息报文
if (null != MessageType && MessageType.equals("ElevatorInfo")) {
logger.info("接收的是电梯状态信息报文");
String Data = jsonObject.getString("Data");
JSONObject jsonData = JSONObject.fromObject(Data);
String DateTimestamp = jsonData.getString("DateTimestamp");
String Floor = jsonData.getString("Floor");
String Direction = jsonData.getString("Direction");
String DoorStatus = jsonData.getString("DoorStatus");
String Speed = jsonData.getString("Speed");
String WaterDepth = null;
String ActivePower = null;
String ReactivePower = null;
String SeismicWavePeak = null;
if (jsonData.has("WaterDepth")) {
WaterDepth = jsonData.getString("WaterDepth");
}
if (jsonData.has("ActivePower")) {
ActivePower = jsonData.getString("ActivePower");
}
if (jsonData.has("ReactivePower")) {
ReactivePower = jsonData.getString("ReactivePower");
}
if (jsonData.has("SeismicWavePeak")) {
SeismicWavePeak = jsonData.getString("SeismicWavePeak");
}
// number++;// 唯一数字自增
// if (number >= maxNum) { // 值的上限,超过就归零
// number = maxNum - 200000;
// }
// String deviceId = sdf.format(new Date()) + number;// 返回时间+一毫秒内唯一数字的编号,区分机器可以加字母ABC...
ReveiveElevatorInfoDTO reveiveElevatorInfoDTO = new ReveiveElevatorInfoDTO();
reveiveElevatorInfoDTO.setDeviceId(DeviceNo);
List<Feature> list = new ArrayList<>();
// Long updatedAt = new Date().getTime() / 1000;
long updatedAt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(DateTimestamp).getTime() / 1000;
if (null != Floor) {
Feature feature = new Feature();
feature.setIdentifier("Floor");
feature.setName("当前楼层");
feature.setValue(Floor);
feature.setType("STRING");
feature.setUpdatedAt(updatedAt);
list.add(feature);
}
if (null != Direction) {
Feature feature = new Feature();
feature.setIdentifier("Direction");
feature.setName("电梯当前运行方向");
feature.setValue(Direction);
feature.setType("STRING");
feature.setUpdatedAt(updatedAt);
list.add(feature);
}
if (null != DoorStatus) {
Feature feature = new Feature();
feature.setIdentifier("DoorStatus");
feature.setName("电梯门开关状态");
feature.setValue(DoorStatus);
feature.setType("STRING");
feature.setUpdatedAt(updatedAt);
list.add(feature);
}
if (null != Speed) {
Feature feature = new Feature();
feature.setIdentifier("Speed");
feature.setName("速度");
feature.setValue(Speed);
feature.setType("STRING");
feature.setUpdatedAt(updatedAt);
list.add(feature);
}
if (null != WaterDepth) {
Feature feature = new Feature();
feature.setIdentifier("WaterDepth");
feature.setName("电梯井水位深度");
feature.setValue(WaterDepth);
feature.setType("STRING");
feature.setUpdatedAt(updatedAt);
list.add(feature);
}
if (null != ActivePower) {
Feature feature = new Feature();
feature.setIdentifier("ActivePower");
feature.setName("电梯主电源总有功功率");
feature.setValue(ActivePower);
feature.setType("STRING");
feature.setUpdatedAt(updatedAt);
list.add(feature);
}
if (null != ReactivePower) {
Feature feature = new Feature();
feature.setIdentifier("ReactivePower");
feature.setName("电梯主电源总无功功率");
feature.setValue(ReactivePower);
feature.setType("STRING");
feature.setUpdatedAt(updatedAt);
list.add(feature);
}
if (null != SeismicWavePeak) {
Feature feature = new Feature();
feature.setIdentifier("SeismicWavePeak");
feature.setName("楼宇震幅(方向)");
feature.setValue(SeismicWavePeak);
feature.setType("STRING");
feature.setUpdatedAt(updatedAt);
list.add(feature);
}
reveiveElevatorInfoDTO.setData(list);
String url = "http://192.168.121.189:8081/receive/elevatorInfo";
String url1 = "http://dev2.sefuture.cn/receive/elevatorInfo";
RestTemplate restTemplate = new RestTemplate();
try {
restTemplate.postForEntity(url, reveiveElevatorInfoDTO, ResponseOfReveiveElevatorInfo.class);
restTemplate.postForEntity(url1, reveiveElevatorInfoDTO, ResponseOfReveiveElevatorInfo.class);
logger.info("推送电梯状态消息消息成功");
} catch (RestClientException e) {
logger.error("推送消息异常:{}",e.getMessage());
}
}
// 5.接收的是电梯故障预警报文
if (null != MessageType && MessageType.equals("ElevatorWarn")) {
logger.info("接收的是电梯故障预警报文");
String Data = jsonObject.getString("Data");
JSONObject jsonData = JSONObject.fromObject(Data);
String DateTimestamp = jsonData.getString("DateTimestamp");
String WarnType = jsonData.getString("WarnType");
String WarnStatus = jsonData.getString("WarnStatus");
String Detail = null;
if (jsonData.has("Detail")) {
Detail = jsonData.getString("Detail");
}
// String OriginalData = jsonData.getString("OriginalData");
long updatedAt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(DateTimestamp).getTime() / 1000;
ReveiveElevatorInfoDTO reveiveElevatorInfoDTO = new ReveiveElevatorInfoDTO();
// reveiveElevatorInfoDTO.setDeviceId(deviceId);
List<Feature> list = new ArrayList<>();
if ("DoorLock".equals(WarnType)) {
Feature feature = new Feature();
feature.setIdentifier("Warn_DoorLock");
feature.setName("门锁回路告警");
feature.setValue(WarnStatus);
feature.setUpdatedAt(updatedAt);
if (null != Detail) {
feature.setDetail(Detail);
}
list.add(feature);
}
if ("Noise".equals(WarnType)) {
Feature feature = new Feature();
feature.setIdentifier("Warn_Noise");
feature.setName("轿厢噪音告警");
feature.setValue(WarnStatus);
feature.setUpdatedAt(updatedAt);
if (null != Detail) {
feature.setDetail(Detail);
}
list.add(feature);
}
if ("Shake".equals(WarnType)) {
Feature feature = new Feature();
feature.setIdentifier("Warn_Shake");
feature.setName("轿厢晃动超标预警");
feature.setValue(WarnStatus);
feature.setUpdatedAt(updatedAt);
if (null != Detail) {
feature.setDetail(Detail);
}
list.add(feature);
}
if ("OpenDoorRun".equals(WarnType)) {
Feature feature = new Feature();
feature.setIdentifier("Warn_OpenDoorRun");
feature.setName("开门走梯告警");
feature.setValue(WarnStatus);
feature.setUpdatedAt(updatedAt);
if (null != Detail) {
feature.setDetail(Detail);
}
list.add(feature);
}
if ("KeepOpen".equals(WarnType)) {
Feature feature = new Feature();
feature.setIdentifier("Warn_KeepOpen");
feature.setName("开门时间过长告警");
feature.setValue(WarnStatus);
feature.setUpdatedAt(updatedAt);
if (null != Detail) {
feature.setDetail(Detail);
}
list.add(feature);
}
if ("Speed".equals(WarnType)) {
Feature feature = new Feature();
feature.setIdentifier("Warn_Speed");
feature.setName("电梯移动超速预警");
feature.setValue(WarnStatus);
feature.setUpdatedAt(updatedAt);
if (null != Detail) {
feature.setDetail(Detail);
}
list.add(feature);
}
if ("InvalidStop".equals(WarnType)) {
Feature feature = new Feature();
feature.setIdentifier("Warn_InvalidStop");
feature.setName("异常停层预警");
feature.setValue(WarnStatus);
feature.setUpdatedAt(updatedAt);
if (null != Detail) {
feature.setDetail(Detail);
}
list.add(feature);
logger.info("接到异常停层预警");
}
if ("SafetyLoop".equals(WarnType)) {
Feature feature = new Feature();
feature.setIdentifier("Warn_SafetyLoop");
feature.setName("安全回路告警");
feature.setValue(WarnStatus);
feature.setUpdatedAt(updatedAt);
if (null != Detail) {
feature.setDetail(Detail);
}
list.add(feature);
}
if ("Brake".equals(WarnType)) {
Feature feature = new Feature();
feature.setIdentifier("Warn_Brake");
feature.setName("曳引机抱闸异常预警");
feature.setValue(WarnStatus);
feature.setUpdatedAt(updatedAt);
if (null != Detail) {
feature.setDetail(Detail);
}
list.add(feature);
}
if ("Displacement".equals(WarnType)) {
Feature feature = new Feature();
feature.setIdentifier("Warn_Displacement");
feature.setName("抱闸移位预警");
feature.setValue(WarnStatus);
feature.setUpdatedAt(updatedAt);
if (null != Detail) {
feature.setDetail(Detail);
}
list.add(feature);
}
if ("OverTop".equals(WarnType)) {
Feature feature = new Feature();
feature.setIdentifier("Warn_OverTop");
feature.setName("轿厢冲顶预警");
feature.setValue(WarnStatus);
feature.setUpdatedAt(updatedAt);
if (null != Detail) {
feature.setDetail(Detail);
}
list.add(feature);
}
if ("UnderBottom".equals(WarnType)) {
Feature feature = new Feature();
feature.setIdentifier("Warn_UnderBottom");
feature.setName("轿厢蹲底预警");
feature.setValue(WarnStatus);
feature.setUpdatedAt(updatedAt);
if (null != Detail) {
feature.setDetail(Detail);
}
list.add(feature);
}
if ("ErrorLayer".equals(WarnType)) {
Feature feature = new Feature();
feature.setIdentifier("Warn_ErrorLayer");
feature.setName("开门未能准确平层告警");
feature.setValue(WarnStatus);
feature.setUpdatedAt(updatedAt);
if (null != Detail) {
feature.setDetail(Detail);
}
list.add(feature);
}
if ("CarStuck".equals(WarnType)) {
Feature feature = new Feature();
feature.setIdentifier("Warn_CarStuck");
feature.setName("轿厢卡在井道中告警");
feature.setValue(WarnStatus);
feature.setUpdatedAt(updatedAt);
if (null != Detail) {
feature.setDetail(Detail);
}
list.add(feature);
}
if ("TractionTemperature".equals(WarnType)) {
Feature feature = new Feature();
feature.setIdentifier("Warn_TractionTemperature");
feature.setName("曳引机温度告警");
feature.setValue(WarnStatus);
feature.setUpdatedAt(updatedAt);
if (null != Detail) {
feature.setDetail(Detail);
}
list.add(feature);
}
reveiveElevatorInfoDTO.setData(list);
//把设备序列号作为设备id,原先设备id是通过设备序列号绑定获得的
reveiveElevatorInfoDTO.setDeviceId(DeviceNo);
String url = "http://dev2.sefuture.cn/receive/elevatorInfo";
String url1 = "http://192.168.121.189:8081/receive/elevatorInfo";
// String url1 = "http://192.168.121.11:8888";
RestTemplate restTemplate = new RestTemplate();
if ("WARN".equals(WarnStatus) || "ERROR".equals(WarnStatus)) {
try {
restTemplate.postForEntity(url, reveiveElevatorInfoDTO, ResponseOfReveiveElevatorInfo.class);
restTemplate.postForEntity(url1, reveiveElevatorInfoDTO, ResponseOfReveiveElevatorInfo.class);
logger.info("推送电梯报警消息成功");
} catch (RestClientException e) {
logger.error("推送消息异常:{}", e.getMessage());
}
}
}
}
}