#update mqtt 上位机
This commit is contained in:
80
.idea/workspace.xml
generated
80
.idea/workspace.xml
generated
@@ -4,23 +4,18 @@
|
||||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="84ac1b15-3cfa-4375-9957-45b7b581d04e" name="Changes" comment="# commit">
|
||||
<list default="true" id="84ac1b15-3cfa-4375-9957-45b7b581d04e" name="Changes" comment="#update">
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/maibu-admin/src/main/resources/application-dev.yml" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-admin/src/main/resources/application-dev.yml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/maibu-common/src/main/java/com/maibu/core/business/Device.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-common/src/main/java/com/maibu/core/business/Device.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/maibu-external/src/main/java/com/maibu/uav/controller/UAVController.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-external/src/main/java/com/maibu/uav/controller/UAVController.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/maibu-external/src/main/java/com/maibu/uav/dto/UavDeviceStateResponseDetailDTO.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-external/src/main/java/com/maibu/uav/dto/UavDeviceStateResponseDetailDTO.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/maibu-external/src/main/java/com/maibu/uav/service/UAVService.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-external/src/main/java/com/maibu/uav/service/UAVService.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/maibu-framework/src/main/java/com/maibu/config/SecurityConfig.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-framework/src/main/java/com/maibu/config/SecurityConfig.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/netty/NettyServer.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/netty/NettyServer.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/maibu-common/src/main/java/com/maibu/constant/Constant.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-common/src/main/java/com/maibu/constant/Constant.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/maibu-common/src/main/java/com/maibu/memory/GlobalMemory.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-common/src/main/java/com/maibu/memory/GlobalMemory.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/maibu-common/src/main/java/com/maibu/memory/SiteMemory.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-common/src/main/java/com/maibu/memory/SiteMemory.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/maibu-common/src/main/java/com/maibu/mqtt/MqttTopic.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-common/src/main/java/com/maibu/mqtt/MqttTopic.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/init/InitThread.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/init/InitThread.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/netty/handler/DataToDataBaseHandler.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/netty/handler/DataToDataBaseHandler.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/netty/handler/DeviceConnectHandler.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/netty/handler/DeviceConnectHandler.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/netty/handler/HeaderFooterDecoder.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/netty/handler/HeaderFooterDecoder.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/netty/handler/HexEncoder.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/netty/handler/HexEncoder.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/maibu-service/maibu-iot-service/src/main/java/com/maibu/controller/DeviceController.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-service/maibu-iot-service/src/main/java/com/maibu/controller/DeviceController.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/maibu-service/maibu-iot-service/src/main/java/com/maibu/service/IDeviceService.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-service/maibu-iot-service/src/main/java/com/maibu/service/IDeviceService.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/maibu-service/maibu-iot-service/src/main/java/com/maibu/service/impl/DeviceServiceImpl.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-service/maibu-iot-service/src/main/java/com/maibu/service/impl/DeviceServiceImpl.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/maibu-service/maibu-iot-service/src/main/resources/mapper/iot/DeviceMapper.xml" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-service/maibu-iot-service/src/main/resources/mapper/iot/DeviceMapper.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/maibu-web-middleware/src/main/java/com/maibu/common/MiddleConstant.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-web-middleware/src/main/java/com/maibu/common/MiddleConstant.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/service/DeviceThreadService.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/service/DeviceThreadService.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/maibu-service/maibu-iot-service/src/main/java/com/maibu/service/impl/AlarmServiceImpl.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-service/maibu-iot-service/src/main/java/com/maibu/service/impl/AlarmServiceImpl.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/maibu-service/maibu-system-service/src/main/java/com/maibu/service/impl/IotDeviceCommonService.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-service/maibu-system-service/src/main/java/com/maibu/service/impl/IotDeviceCommonService.java" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
@@ -40,6 +35,11 @@
|
||||
</option>
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_BRANCH_BY_REPOSITORY">
|
||||
<map>
|
||||
<entry key="$PROJECT_DIR$" value="main" />
|
||||
</map>
|
||||
</option>
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="HttpClientEndpointsTabState">
|
||||
@@ -100,7 +100,7 @@
|
||||
"RunOnceActivity.git.unshallow": "true",
|
||||
"RunOnceActivity.typescript.service.memoryLimit.init": "true",
|
||||
"Spring Boot.MiddlePlatformApplication.executor": "Debug",
|
||||
"git-widget-placeholder": "main",
|
||||
"git-widget-placeholder": "dev__new__connect",
|
||||
"kotlin-language-version-configured": "true",
|
||||
"last_opened_file_path": "/home/maibu/Test/MiddlePlatform/maibu-external/src/main/java/com/maibu/uav",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
@@ -160,11 +160,11 @@
|
||||
<recent name="$PROJECT_DIR$/maibu-service/maibu-iot-service/src/main/java/com/maibu/service" />
|
||||
</key>
|
||||
<key name="CopyClassDialog.RECENTS_KEY">
|
||||
<recent name="com.maibu.mqtt" />
|
||||
<recent name="com.maibu.core.business.dto" />
|
||||
<recent name="com.maibu.uav.dto" />
|
||||
<recent name="com.maibu.uav.controller" />
|
||||
<recent name="com.maibu.mapper" />
|
||||
<recent name="com.maibu.core.business.uav" />
|
||||
</key>
|
||||
</component>
|
||||
<component name="RunManager" selected="Spring Boot.MiddlePlatformApplication">
|
||||
@@ -190,17 +190,6 @@
|
||||
<configuration name="MiddlePlatformApplication | #3" type="HttpClient.HttpRequestRunConfigurationType" factoryName="HTTP Request" temporary="true" nameIsGenerated="true" path="$APPLICATION_CONFIG_DIR$/scratches/MiddlePlatformApplication.http" executionIdentifier="#3" index="3" runType="Run single request">
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration default="true" type="JetRunConfigurationType">
|
||||
<module name="maibu-iot-service" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration default="true" type="KotlinStandaloneScriptRunConfigurationType">
|
||||
<module name="maibu-iot-service" />
|
||||
<option name="filePath" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="MiddlePlatformApplication" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot" temporary="true" nameIsGenerated="true">
|
||||
<option name="FRAME_DEACTIVATION_UPDATE_POLICY" value="UpdateClassesAndResources" />
|
||||
<module name="maibu-admin" />
|
||||
@@ -235,8 +224,8 @@
|
||||
<component name="SharedIndexes">
|
||||
<attachedChunks>
|
||||
<set>
|
||||
<option value="bundled-jdk-30f59d01ecdd-cffe25b9f5b3-intellij.indexing.shared.core-IU-253.28294.251" />
|
||||
<option value="bundled-js-predefined-d6986cc7102b-c7e53b3be11b-JavaScript-IU-253.28294.251" />
|
||||
<option value="bundled-jdk-30f59d01ecdd-26cb7f24e5b0-intellij.indexing.shared.core-IU-253.29346.138" />
|
||||
<option value="bundled-js-predefined-d6986cc7102b-9b0f141eb926-JavaScript-IU-253.29346.138" />
|
||||
</set>
|
||||
</attachedChunks>
|
||||
</component>
|
||||
@@ -294,6 +283,7 @@
|
||||
<workItem from="1779683678663" duration="17250000" />
|
||||
<workItem from="1779755672380" duration="9935000" />
|
||||
<workItem from="1779770107645" duration="17442000" />
|
||||
<workItem from="1786062684292" duration="833000" />
|
||||
</task>
|
||||
<task id="LOCAL-00001" summary="#update">
|
||||
<option name="closed" value="true" />
|
||||
@@ -543,7 +533,23 @@
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1779242181619</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="32" />
|
||||
<task id="LOCAL-00032" summary="#update">
|
||||
<option name="closed" value="true" />
|
||||
<created>1785982626224</created>
|
||||
<option name="number" value="00032" />
|
||||
<option name="presentableId" value="LOCAL-00032" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1785982626225</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00033" summary="#update">
|
||||
<option name="closed" value="true" />
|
||||
<created>1785991726504</created>
|
||||
<option name="number" value="00033" />
|
||||
<option name="presentableId" value="LOCAL-00033" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1785991726504</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="34" />
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
@@ -594,7 +600,6 @@
|
||||
<option name="CHECK_CODE_SMELLS_BEFORE_PROJECT_COMMIT" value="false" />
|
||||
<option name="CHECK_NEW_TODO" value="false" />
|
||||
<MESSAGE value="#init" />
|
||||
<MESSAGE value="#update" />
|
||||
<MESSAGE value="物模型的新增和修改和查看列表接口" />
|
||||
<MESSAGE value="SysUser新增权限字段,和需改增加和修改和查询列表接口" />
|
||||
<MESSAGE value="修改接口system/site/list 根据组织id得到场站list" />
|
||||
@@ -617,7 +622,8 @@
|
||||
<MESSAGE value="#id重复bug" />
|
||||
<MESSAGE value="#修复工单修改接口" />
|
||||
<MESSAGE value="# commit" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="# commit" />
|
||||
<MESSAGE value="#update" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="#update" />
|
||||
<option name="NON_MODAL_COMMIT_POSTPONE_SLOW_CHECKS" value="false" />
|
||||
</component>
|
||||
<component name="XDebuggerManager">
|
||||
@@ -700,17 +706,17 @@
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="java-line">
|
||||
<url>file://$PROJECT_DIR$/maibu-service/maibu-iot-service/src/main/java/com/maibu/service/impl/DeviceServiceImpl.java</url>
|
||||
<line>234</line>
|
||||
<line>237</line>
|
||||
<option name="timeStamp" value="51" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="java-line">
|
||||
<url>file://$PROJECT_DIR$/maibu-service/maibu-iot-service/src/main/java/com/maibu/service/impl/DeviceServiceImpl.java</url>
|
||||
<line>247</line>
|
||||
<line>250</line>
|
||||
<option name="timeStamp" value="52" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="java-line">
|
||||
<url>file://$PROJECT_DIR$/maibu-service/maibu-iot-service/src/main/java/com/maibu/service/impl/DeviceServiceImpl.java</url>
|
||||
<line>282</line>
|
||||
<line>285</line>
|
||||
<option name="timeStamp" value="61" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="java-method">
|
||||
@@ -725,7 +731,7 @@
|
||||
<line-breakpoint enabled="true" type="java-method">
|
||||
<url>file://$PROJECT_DIR$/maibu-service/maibu-iot-service/src/main/java/com/maibu/controller/IOTWorkOrderController.java</url>
|
||||
<line>58</line>
|
||||
<properties class="com.maibu.controller.IOTWorkOrderController" method="edit">
|
||||
<properties class="com.maibu.controller.IOTWorkOrderController" method="list">
|
||||
<option name="EMULATED" value="true" />
|
||||
<option name="WATCH_EXIT" value="false" />
|
||||
</properties>
|
||||
|
||||
@@ -24,4 +24,6 @@ public class Constant {
|
||||
public static final String WheelGainCoefficients = "WheelGainCoefficients";
|
||||
|
||||
public static final String mqttClientPrefix = "common-device-client-";
|
||||
|
||||
public static final String mqttHandleKey = "hostHandle";
|
||||
}
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
package com.maibu.memory;
|
||||
|
||||
import com.maibu.constant.Constant;
|
||||
import com.maibu.core.business.Device;
|
||||
import com.maibu.core.business.IoTCommonDevice;
|
||||
import com.maibu.influxdb.util.InfluxDBUtil;
|
||||
import com.maibu.mqtt.MqttClientUtil;
|
||||
import com.maibu.mqtt.*;
|
||||
import lombok.Data;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Component
|
||||
@@ -28,8 +26,9 @@ public class GlobalMemory {
|
||||
|
||||
public static InfluxDBUtil influxDBUtil;
|
||||
|
||||
public static MqttClientUtil mqttClientUtil;
|
||||
// public static MqttClientUtil mqttClientUtil;
|
||||
|
||||
public static CustomMqttDeviceMonitor customMqttDeviceMonitor = null; //这里面包含了 连我们自己的mqtt 和外部的一些设备,自己的用clientId 是固定的
|
||||
|
||||
|
||||
public static SiteMemory getSiteMemory(Long orgId, Long siteId) {
|
||||
@@ -52,7 +51,7 @@ public class GlobalMemory {
|
||||
|
||||
/**
|
||||
* 新增场站内存
|
||||
*
|
||||
*
|
||||
* @param orgId
|
||||
* @param siteId
|
||||
* @param siteMemory
|
||||
@@ -72,7 +71,7 @@ public class GlobalMemory {
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*
|
||||
*
|
||||
* @param orgId
|
||||
* @param siteId
|
||||
*/
|
||||
@@ -85,4 +84,29 @@ public class GlobalMemory {
|
||||
}
|
||||
}
|
||||
|
||||
public static void initMqttDeviceMonitor(String mqttHostUrl, String mqttClientId, String mqttUsername, String mqttPassword) {
|
||||
if (customMqttDeviceMonitor == null) {
|
||||
// 1. 创建 MQTT 监控器和消息处理器
|
||||
customMqttDeviceMonitor = new CustomMqttDeviceMonitor();
|
||||
// customMqttDeviceMonitor.registerHandler(new GenericPropertyMessageHandler());
|
||||
customMqttDeviceMonitor.registerHandler(new HostMessageHandler()); //专门处理上位机的
|
||||
// customMqttDeviceMonitor.registerHandler(new ActionMessageHandler());
|
||||
|
||||
//单独注册 对接上位机的
|
||||
// 注册设备到 MQTT 监控器
|
||||
CustomMqttDeviceConfig deviceConfig = new CustomMqttDeviceConfig();
|
||||
deviceConfig.setDeviceKey(mqttClientId);
|
||||
deviceConfig.setBrokerUrl(mqttHostUrl);
|
||||
deviceConfig.setClientId(mqttClientId);
|
||||
deviceConfig.setUsername(mqttUsername);
|
||||
deviceConfig.setPassword(mqttPassword);
|
||||
//TODO 添加所有需要订阅的
|
||||
deviceConfig.setSubscribeTopics(Arrays.asList(MqttTopic.MOWER_WILDCARD_LOCATION));
|
||||
deviceConfig.setHandlerType(Constant.mqttHandleKey); //唯一的 用于处理上位机mqtt的
|
||||
|
||||
customMqttDeviceMonitor.registerDevice(deviceConfig);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,8 +30,6 @@ public class SiteMemory {
|
||||
|
||||
public SysSite sysSite;
|
||||
|
||||
public CustomMqttDeviceMonitor CustomMqttDeviceMonitor;
|
||||
|
||||
public static final ConcurrentHashMap<String, MqttClient> mqttClientMap = new ConcurrentHashMap<>();
|
||||
|
||||
public static final ConcurrentHashMap<Long, OrderModel> orderModelMap = new ConcurrentHashMap<>();
|
||||
|
||||
@@ -0,0 +1,283 @@
|
||||
package com.maibu.mqtt;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.maibu.constant.Constant;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
|
||||
/**
|
||||
* mqtt相关的 上位机处理器
|
||||
*/
|
||||
@Slf4j
|
||||
public class HostMessageHandler implements CustomMqttMessageHandler {
|
||||
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
|
||||
@Override
|
||||
public String getHandlerType() {
|
||||
return Constant.mqttHandleKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(String handlerType) {
|
||||
return Constant.mqttHandleKey.equals(handlerType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 MQTT 消息
|
||||
*
|
||||
* <p>通配符订阅场景下,deviceKey 为配置中的固定标识(如 "host-monitor"),
|
||||
* 真正的设备 ID 需从 topic 中解析,通过 {@link #extractDeviceId(String)} 获取。</p>
|
||||
*/
|
||||
@Override
|
||||
public void handleMessage(String deviceKey, String topic, String payload, CustomMqttDeviceConfig config) {
|
||||
try {
|
||||
String deviceId = extractDeviceId(topic);
|
||||
if (deviceId == null) {
|
||||
log.warn("无法从topic解析deviceId: {}", topic);
|
||||
return;
|
||||
}
|
||||
|
||||
String action = extractAction(topic);
|
||||
if (action == null) {
|
||||
log.debug("未识别的topic: {}", topic);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case "location_post":
|
||||
handleLocationPost(deviceId, topic, payload);
|
||||
break;
|
||||
case "realtime_post":
|
||||
handleRealtimePost(deviceId, topic, payload);
|
||||
break;
|
||||
case "status_post":
|
||||
handleStatusPost(deviceId, topic, payload);
|
||||
break;
|
||||
case "heartbeat_post":
|
||||
handleHeartbeatPost(deviceId, topic, payload);
|
||||
break;
|
||||
case "error_post":
|
||||
handleErrorPost(deviceId, topic, payload);
|
||||
break;
|
||||
case "route_post":
|
||||
case "point_post":
|
||||
handleTaskPost(deviceId, topic, payload, action);
|
||||
break;
|
||||
case "task_status_post":
|
||||
case "task_finish_post":
|
||||
handleTaskPost(deviceId, topic, payload, action);
|
||||
break;
|
||||
case "config_reply":
|
||||
handleConfigReply(deviceId, topic, payload);
|
||||
break;
|
||||
case "control_reply":
|
||||
handleControlReply(deviceId, topic, payload);
|
||||
break;
|
||||
default:
|
||||
log.debug("割草机消息: deviceId={}, topic={}, action={}", deviceId, topic, action);
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("消息处理异常: topic={}, error={}", topic, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 GPS 位置数据上报
|
||||
* topic: mower/{deviceId}/property/location/post
|
||||
*/
|
||||
private void handleLocationPost(String deviceId, String topic, String payload) {
|
||||
try {
|
||||
JsonNode jsonNode = objectMapper.readTree(payload);
|
||||
|
||||
double latitude = getDouble(jsonNode, "latitude", "lat");
|
||||
double longitude = getDouble(jsonNode, "longitude", "lng", "lon");
|
||||
double speed = getDouble(jsonNode, "speed");
|
||||
double heading = getDouble(jsonNode, "heading", "direction");
|
||||
double altitude = getDouble(jsonNode, "altitude", "alt");
|
||||
int satellites = getInt(jsonNode, "satellites", "sats");
|
||||
String fixQuality = getString(jsonNode, "fixQuality", "fix_quality");
|
||||
Double batteryLevel = getDoubleObj(jsonNode, "batteryLevel", "battery");
|
||||
|
||||
log.info("【位置数据】deviceId={}, lat={}, lng={}, speed={}, heading={}, sats={}",
|
||||
deviceId, latitude, longitude, speed, heading, satellites);
|
||||
|
||||
onLocationUpdate(deviceId, latitude, longitude, speed, heading, altitude, satellites, fixQuality, batteryLevel);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("位置消息解析失败: deviceId={}, payload={}, error={}", deviceId, payload, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理实时运行数据
|
||||
* topic: mower/{deviceId}/property/realtime/post
|
||||
*/
|
||||
private void handleRealtimePost(String deviceId, String topic, String payload) {
|
||||
log.debug("【实时数据】deviceId={}, payload={}", deviceId, payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理状态变更事件
|
||||
* topic: mower/{deviceId}/event/status/post
|
||||
*/
|
||||
private void handleStatusPost(String deviceId, String topic, String payload) {
|
||||
log.info("【状态变更】deviceId={}, payload={}", deviceId, payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理心跳
|
||||
* topic: mower/{deviceId}/event/heartbeat/post
|
||||
*/
|
||||
private void handleHeartbeatPost(String deviceId, String topic, String payload) {
|
||||
log.debug("【心跳】deviceId={}", deviceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理错误告警
|
||||
* topic: mower/{deviceId}/event/error/post
|
||||
*/
|
||||
private void handleErrorPost(String deviceId, String topic, String payload) {
|
||||
log.warn("【错误告警】deviceId={}, payload={}", deviceId, payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理任务相关上报
|
||||
*/
|
||||
private void handleTaskPost(String deviceId, String topic, String payload, String action) {
|
||||
log.info("【任务上报】deviceId={}, action={}, payload={}", deviceId, action, payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理配置响应
|
||||
*/
|
||||
private void handleConfigReply(String deviceId, String topic, String payload) {
|
||||
log.debug("【配置响应】deviceId={}, payload={}", deviceId, payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理控制指令响应
|
||||
*/
|
||||
private void handleControlReply(String deviceId, String topic, String payload) {
|
||||
log.debug("【控制响应】deviceId={}, payload={}", deviceId, payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* 位置数据回调,子类可覆盖实现业务逻辑
|
||||
*/
|
||||
protected void onLocationUpdate(String deviceId, double latitude, double longitude,
|
||||
double speed, double heading, double altitude,
|
||||
int satellites, String fixQuality, Double batteryLevel) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 Topic 中解析 deviceId
|
||||
* Topic 格式:mower/{deviceId}/...
|
||||
*/
|
||||
private String extractDeviceId(String topic) {
|
||||
if (topic == null || topic.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
String[] parts = topic.split("/");
|
||||
if (parts.length < 2 || !"mower".equals(parts[0])) {
|
||||
return null;
|
||||
}
|
||||
return parts[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 Topic 中提取动作标识
|
||||
* 将 mower/{deviceId}/xxx/yyy/post 转为 xxx_yyy_post 形式
|
||||
*/
|
||||
private String extractAction(String topic) {
|
||||
String[] parts = topic.split("/");
|
||||
if (parts.length < 3 || !"mower".equals(parts[0])) {
|
||||
return null;
|
||||
}
|
||||
StringBuilder path = new StringBuilder();
|
||||
for (int i = 2; i < parts.length; i++) {
|
||||
if (i > 2) path.append("/");
|
||||
path.append(parts[i]);
|
||||
}
|
||||
String remaining = path.toString();
|
||||
|
||||
if (remaining.equals("property/location/post")) return "location_post";
|
||||
if (remaining.equals("property/realtime/post")) return "realtime_post";
|
||||
if (remaining.equals("event/status/post")) return "status_post";
|
||||
if (remaining.equals("event/heartbeat/post")) return "heartbeat_post";
|
||||
if (remaining.equals("event/error/post")) return "error_post";
|
||||
if (remaining.equals("task/route/post")) return "route_post";
|
||||
if (remaining.equals("task/point/post")) return "point_post";
|
||||
if (remaining.equals("task/status/post")) return "task_status_post";
|
||||
if (remaining.equals("task/finish/post")) return "task_finish_post";
|
||||
if (remaining.equals("action/config/reply")) return "config_reply";
|
||||
if (remaining.equals("action/control/reply")) return "control_reply";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private double getDouble(JsonNode node, String... names) {
|
||||
for (String name : names) {
|
||||
JsonNode fn = node.get(name);
|
||||
if (fn != null && !fn.isNull()) {
|
||||
if (fn.isNumber()) return fn.asDouble();
|
||||
try {
|
||||
return Double.parseDouble(fn.asText());
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
private Double getDoubleObj(JsonNode node, String... names) {
|
||||
for (String name : names) {
|
||||
JsonNode fn = node.get(name);
|
||||
if (fn != null && !fn.isNull()) {
|
||||
if (fn.isNumber()) return fn.asDouble();
|
||||
try {
|
||||
return Double.parseDouble(fn.asText());
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private int getInt(JsonNode node, String... names) {
|
||||
for (String name : names) {
|
||||
JsonNode fn = node.get(name);
|
||||
if (fn != null && !fn.isNull()) {
|
||||
if (fn.isNumber()) return fn.asInt();
|
||||
try {
|
||||
return Integer.parseInt(fn.asText());
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private String getString(JsonNode node, String... names) {
|
||||
for (String name : names) {
|
||||
JsonNode fn = node.get(name);
|
||||
if (fn != null && !fn.isNull()) {
|
||||
return fn.asText();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionLost(String deviceKey, Throwable cause) {
|
||||
log.warn("主机监控连接断开: deviceKey={}, reason={}", deviceKey, cause.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSubscribed(String deviceKey, String topic) {
|
||||
log.info("主机监控订阅主题: deviceKey={}, topic={}", deviceKey, topic);
|
||||
}
|
||||
}
|
||||
@@ -18,12 +18,12 @@ public class MqttTopic {
|
||||
// ==================== 设备连接与状态 ====================
|
||||
/** 设备上线/下线事件上报(设备->平台),对应 TCP 0x03 connect */
|
||||
public static final String MOWER_STATUS_POST = "mower/%s/event/status/post";
|
||||
/** 状态变更确认回复(平台->设备) */
|
||||
// public static final String MOWER_STATUS_REPLY = "mower/%s/event/status/reply";
|
||||
|
||||
// ==================== 实时运行数据 ====================
|
||||
/** 实时运行数据上报:电压/速度/温度/位置等(设备->平台),对应 TCP 0x02 status */
|
||||
public static final String MOWER_REALTIME_POST = "mower/%s/property/realtime/post";
|
||||
/** GPS 位置数据上报:经纬度、速度、航向等(设备->平台) */
|
||||
public static final String MOWER_LOCATION_POST = "mower/%s/property/location/post";
|
||||
|
||||
// ==================== 心跳保活 ====================
|
||||
/** 设备心跳上报(设备->平台),对应 TCP 0xFF heartbeat */
|
||||
@@ -43,22 +43,12 @@ public class MqttTopic {
|
||||
/** 远程控制指令下发:前进/后退/转向/割草等(平台->设备),对应 TCP 0x00 remoteControl */
|
||||
public static final String MOWER_CONTROL_SET = "mower/%s/action/control/set";
|
||||
|
||||
// /** 控制指令响应(设备->平台) */
|
||||
// public static final String MOWER_CONTROL_REPLY = "mower/%s/action/control/reply";
|
||||
|
||||
// ==================== 任务管理 ====================
|
||||
/** 路径规划下发(平台->设备),对应 TCP 0x01 path */
|
||||
public static final String MOWER_TASK_ROUTE_SET = "mower/%s/task/route/set";
|
||||
public static final String MOWER_TASK_ROUTE_POST = "mower/%s/task/route/post";
|
||||
/** 启动任务执行(平台->设备),对应 TCP 0x12 interaction */
|
||||
public static final String MOWER_TASK_STATUS_SET = "mower/%s/task/status/set";
|
||||
// /** 暂停任务(平台->设备) */
|
||||
// public static final String MOWER_TASK_PAUSE_SET = "mower/%s/task/pause/set";
|
||||
// /** 继续任务(平台->设备) */
|
||||
// public static final String MOWER_TASK_RESUME_SET = "mower/%s/task/resume/set";
|
||||
// /** 取消任务(平台->设备) */
|
||||
// public static final String MOWER_TASK_CANCEL_SET = "mower/%s/task/cancel/set";
|
||||
// /** 到达路径点上报(设备->平台) */
|
||||
public static final String MOWER_TASK_POINT_POST = "mower/%s/task/point/post";
|
||||
/** 任务状态变更上报:执行中/暂停/完成等(设备->平台) */
|
||||
public static final String MOWER_TASK_STATUS_POST = "mower/%s/task/status/post";
|
||||
@@ -90,6 +80,8 @@ public class MqttTopic {
|
||||
public static final String MOWER_WILDCARD_STATUS = "mower/+/event/status/post";
|
||||
/** 订阅所有设备的实时运行数据 */
|
||||
public static final String MOWER_WILDCARD_REALTIME = "mower/+/property/realtime/post";
|
||||
/** 上位机的额外消息 */
|
||||
public static final String MOWER_WILDCARD_LOCATION = "mower/+/property/location/post";
|
||||
/** 订阅所有设备的错误告警 */
|
||||
public static final String MOWER_WILDCARD_ERROR = "mower/+/event/error/post";
|
||||
/** 订阅所有设备的任务状态变更 */
|
||||
|
||||
@@ -121,8 +121,9 @@ public class InitThread implements ApplicationRunner {
|
||||
private void init() throws MqttException {
|
||||
// 初始化InfluxDBUtil
|
||||
GlobalMemory.influxDBUtil = new InfluxDBUtil(influxDBUrl, influxDBToken, influxDBOrg, influxDBBucket);
|
||||
// 初始化MqttClientUtil
|
||||
GlobalMemory.mqttClientUtil = new MqttClientUtil(mqttHostUrl, mqttClientId, mqttUsername, mqttPassword);
|
||||
|
||||
GlobalMemory.initMqttDeviceMonitor(mqttHostUrl, mqttClientId, mqttUsername, mqttPassword);
|
||||
|
||||
// 设备错误监听线程
|
||||
deviceErrorMonitorExecutor.execute(() -> {
|
||||
try {
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.eclipse.paho.client.mqttv3.MqttException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
@@ -63,6 +64,10 @@ public class DataToDataBaseHandler extends SimpleChannelInboundHandler<String> {
|
||||
@Autowired
|
||||
private DeviceRunParamMapper deviceRunParamMapper;
|
||||
|
||||
|
||||
@Value("${mqtt.client-id}")
|
||||
private String mqttClientId;
|
||||
|
||||
private static final Long recordInterval = 5000L; // 5秒记录一次
|
||||
|
||||
// private static final Long pushInterval = 500L; // 0.5秒推送一次
|
||||
@@ -97,9 +102,11 @@ public class DataToDataBaseHandler extends SimpleChannelInboundHandler<String> {
|
||||
String[] split = deviceStatus.split(",");
|
||||
WebStatusMessageDTO dto = createWebDeviceStatusMessage(split);
|
||||
try {
|
||||
GlobalMemory.mqttClientUtil.publish(
|
||||
String.format(MqttTopic.DEVICE_STATUS_TOPIC, deviceID),
|
||||
GlobalMemory.customMqttDeviceMonitor.publish(mqttClientId, String.format(MqttTopic.DEVICE_STATUS_TOPIC, deviceID),
|
||||
JsonUtils.toJsonString(dto));
|
||||
// GlobalMemory.mqttClientUtil.publish(
|
||||
// String.format(MqttTopic.DEVICE_STATUS_TOPIC, deviceID),
|
||||
// JsonUtils.toJsonString(dto));
|
||||
} catch (MqttException e) {
|
||||
logger.error("发送实时状态数据错误: {}", e.getMessage());
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import org.eclipse.paho.client.mqttv3.MqttException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
@@ -82,6 +83,9 @@ public class DeviceConnectHandler extends SimpleChannelInboundHandler<String> {
|
||||
@Resource
|
||||
private WebsocketMesDispather websocketMesDispather;
|
||||
|
||||
@Value("${mqtt.client-id}")
|
||||
private String mqttClientId;
|
||||
|
||||
public DeviceConnectHandler(DeviceSessionManager sessionManager) {
|
||||
this.sessionManager = sessionManager;
|
||||
}
|
||||
@@ -364,8 +368,12 @@ public class DeviceConnectHandler extends SimpleChannelInboundHandler<String> {
|
||||
changeDTO.setTaskId(taskId);
|
||||
|
||||
try {
|
||||
GlobalMemory.mqttClientUtil.publish(String.format(MqttTopic.DEVICE_TASK_STATUS_TOPIC, taskId),
|
||||
|
||||
GlobalMemory.customMqttDeviceMonitor.publish(mqttClientId, String.format(MqttTopic.DEVICE_TASK_STATUS_TOPIC, taskId),
|
||||
JsonUtils.toJsonString(changeDTO));
|
||||
|
||||
// GlobalMemory.mqttClientUtil.publish(String.format(MqttTopic.DEVICE_TASK_STATUS_TOPIC, taskId),
|
||||
// JsonUtils.toJsonString(changeDTO));
|
||||
} catch (MqttException e) {
|
||||
logger.error("任务完成状态推送失败 task:{},device:{}error:{}", taskId, deviceId, e.getMessage());
|
||||
}
|
||||
@@ -392,8 +400,10 @@ public class DeviceConnectHandler extends SimpleChannelInboundHandler<String> {
|
||||
reportDTO.setType(MesType.device_task_arrive_point);
|
||||
try {
|
||||
|
||||
GlobalMemory.mqttClientUtil.publish(String.format(MqttTopic.DEVICE_TASK_ARRIVE_TOPIC, taskId),
|
||||
GlobalMemory.customMqttDeviceMonitor.publish(mqttClientId, String.format(MqttTopic.DEVICE_TASK_ARRIVE_TOPIC, taskId),
|
||||
JsonUtils.toJsonString(reportDTO));
|
||||
// GlobalMemory.mqttClientUtil.publish(String.format(MqttTopic.DEVICE_TASK_ARRIVE_TOPIC, taskId),
|
||||
// JsonUtils.toJsonString(reportDTO));
|
||||
} catch (MqttException e) {
|
||||
logger.error("任务点位到达推送失败 task:{},device:{}error:{}", taskId, deviceId, e.getMessage());
|
||||
}
|
||||
|
||||
@@ -15,9 +15,11 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.maibu.memory.DeviceSessionManager;
|
||||
import com.maibu.utils.json.JsonUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -69,6 +71,9 @@ public class DeviceThreadService {
|
||||
@Autowired
|
||||
private AlertPushService alertPushService;
|
||||
|
||||
@Value("${mqtt.client-id}")
|
||||
private String mqttClientId;
|
||||
|
||||
public void deviceErrorMonitor() throws InterruptedException, IOException {
|
||||
initStandard();
|
||||
|
||||
@@ -184,7 +189,8 @@ public class DeviceThreadService {
|
||||
// }
|
||||
// }
|
||||
try {
|
||||
GlobalMemory.mqttClientUtil.publish(String.format(MqttTopic.DEVICE_ERROR_PUSH_TOPIC, deviceId), dto);
|
||||
GlobalMemory.customMqttDeviceMonitor.publish(mqttClientId, String.format(MqttTopic.DEVICE_ERROR_PUSH_TOPIC, deviceId), dto);
|
||||
// GlobalMemory.mqttClientUtil.publish(String.format(MqttTopic.DEVICE_ERROR_PUSH_TOPIC, deviceId), dto);
|
||||
List<NettyDevice> controlMasters = sessionManager.getAllSlaveControl(deviceId);
|
||||
if (!CollectionUtils.isEmpty(controlMasters)) {
|
||||
controlMasters.forEach(x -> {
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.maibu.core.enums.AlarmType;
|
||||
import com.maibu.core.redis.RedisCache;
|
||||
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
@@ -51,6 +52,10 @@ public class AlarmServiceImpl extends ServiceImpl<AlarmMapper, Alarm> implements
|
||||
@Autowired
|
||||
private RedisCache redisCache;
|
||||
|
||||
@Value("${mqtt.client-id}")
|
||||
private String mqttClientId;
|
||||
|
||||
|
||||
@Override
|
||||
public List<Alarm> selectAlarmPage(AlarmQueryDTO queryDTO) {
|
||||
// validateQueryParams(queryDTO);
|
||||
@@ -407,7 +412,8 @@ public class AlarmServiceImpl extends ServiceImpl<AlarmMapper, Alarm> implements
|
||||
|
||||
public void pushErrorMessage(String deviceId, String dto) {
|
||||
try {
|
||||
GlobalMemory.mqttClientUtil.publish(String.format(MqttTopic.DEVICE_ERROR_PUSH_TOPIC, deviceId), dto);
|
||||
GlobalMemory.customMqttDeviceMonitor.publish(mqttClientId, String.format(MqttTopic.DEVICE_ERROR_PUSH_TOPIC, deviceId), dto);
|
||||
// GlobalMemory.mqttClientUtil.publish(String.format(MqttTopic.DEVICE_ERROR_PUSH_TOPIC, deviceId), dto);
|
||||
// List<NettyDevice> controlMasters =
|
||||
// sessionManager.getAllSlaveControl(deviceId);
|
||||
// if (!CollectionUtils.isEmpty(controlMasters)) {
|
||||
|
||||
@@ -273,25 +273,15 @@ public class IotDeviceCommonService {
|
||||
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
|
||||
executor.scheduleWithFixedDelay(() -> {
|
||||
try {
|
||||
CustomMqttDeviceMonitor monitor = GlobalMemory.customMqttDeviceMonitor;
|
||||
GlobalMemory.getAllSiteMemory().forEach(siteMemory -> {
|
||||
|
||||
|
||||
CustomMqttDeviceMonitor monitor = siteMemory.getCustomMqttDeviceMonitor();
|
||||
if (monitor == null) {
|
||||
// 1. 创建 MQTT 监控器和消息处理器
|
||||
monitor = new CustomMqttDeviceMonitor();
|
||||
monitor.registerHandler(new GenericPropertyMessageHandler());
|
||||
monitor.registerHandler(new ActionMessageHandler());
|
||||
|
||||
siteMemory.setCustomMqttDeviceMonitor(monitor);
|
||||
}
|
||||
// 2. 查询所有外部设备
|
||||
List<IoTCommonDevice> deviceList = siteMemory.getAllCommonDevice();
|
||||
if (CollectionUtils.isEmpty(deviceList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
for (IoTCommonDevice device : deviceList) {
|
||||
if (!ConnectType.MQTT.equals(device.getConnectType())) {
|
||||
continue;
|
||||
@@ -333,8 +323,6 @@ public class IotDeviceCommonService {
|
||||
|
||||
monitor.registerDevice(deviceConfig);
|
||||
}
|
||||
|
||||
siteMemory.setCustomMqttDeviceMonitor(monitor);
|
||||
monitor.start();
|
||||
});
|
||||
} catch (Exception e) {
|
||||
|
||||
Reference in New Issue
Block a user