package com.ruoyi.device.service.impl; import com.ruoyi.device.domain.api.IAircraftDomain; import com.ruoyi.device.domain.api.IDeviceDomain; import com.ruoyi.device.domain.api.IDockAircraftDomain; import com.ruoyi.device.domain.api.IDockDomain; import com.ruoyi.device.domain.api.IThingsBoardDomain; import com.ruoyi.device.domain.impl.DockDomainImpl; import com.ruoyi.device.domain.impl.djimqtt.callback.IDockDataCallback; import com.ruoyi.device.domain.impl.djimqtt.callback.IDroneDataCallback; import com.ruoyi.device.domain.impl.djimqtt.config.DjiMqttClientConfig; import com.ruoyi.device.service.config.DjiMqttProperties; import com.ruoyi.device.domain.impl.djimqtt.handler.DjiMqttMessageHandler; import com.ruoyi.device.domain.impl.djimqtt.manager.DjiMqttClientManager; import com.ruoyi.device.domain.impl.djimqtt.model.DockData; import com.ruoyi.device.domain.impl.djimqtt.model.DroneData; import com.ruoyi.device.domain.model.Aircraft; import com.ruoyi.device.domain.model.Device; import com.ruoyi.device.domain.model.Dock; import com.ruoyi.device.domain.model.DockAircraft; import com.ruoyi.device.websocket.StatisticsWebSocket; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import java.util.Date; import java.util.List; import java.util.Objects; @Service @Slf4j public class DjiService { @Autowired private DjiMqttClientManager clientManager; @Autowired private DjiMqttProperties mqttProperties; @Autowired private IDockDomain dockDomain; @Autowired private IDeviceDomain deviceDomain; @Autowired private IAircraftDomain aircraftDomain; @Autowired private IDockAircraftDomain dockAircraftDomain; @Autowired private IThingsBoardDomain thingsBoardDomain; @Autowired StatisticsWebSocket statisticsWebSocket; @EventListener(ApplicationReadyEvent.class) public void onApplicationReady() { // 从配置文件读取配置 DjiMqttClientConfig config = DjiMqttClientConfig.builder() .host(mqttProperties.getHost()) .port(mqttProperties.getPort()) .clientId(mqttProperties.getClientId()) .username(mqttProperties.getUsername()) .password(mqttProperties.getPassword()) .connectionTimeout(mqttProperties.getConnectionTimeout()) .keepAliveInterval(mqttProperties.getKeepAliveInterval()) .autoReconnect(mqttProperties.getAutoReconnect()) .cleanSession(mqttProperties.getCleanSession()) .useSharedSubscription(true) .sharedGroupName("dji-group") .build(); // 创建客户端 String clientId = clientManager.createClient(config); // 获取消息处理器 DjiMqttMessageHandler handler = clientManager.getHandler(clientId); // 注册无人机数据回调 handler.registerDroneDataCallback(new IDroneDataCallback() { @Override public void onDroneData(DroneData droneData) { if(droneData.getDeviceSn().startsWith("TH")){ return; } // log.info("droneData:{}", droneData); // 判断是否是 state 触发 boolean isStateMessage = "state".equalsIgnoreCase(droneData.getMessageType()); // 更新 Dock 表的 lastActiveTime log.info("准备查询设备: device_sn={}", droneData.getDeviceSn()); Device device = deviceDomain.selectDeviceByDeviceSn(droneData.getDeviceSn()); log.info("查询设备成功: device_sn={}, deviceId={}", droneData.getDeviceSn(), device != null ? device.getDeviceId() : null); if(Objects.nonNull(device)) { Aircraft aircraft = aircraftDomain.selectAircraftByDeviceId(device.getDeviceId()); if(Objects.nonNull(aircraft)) { List aircrafts = dockAircraftDomain.selectDockAircraftByAircraftId(aircraft.getAircraftId()); if(!aircrafts.isEmpty()) { for(DockAircraft dockAircraft : aircrafts) { Dock dock = dockDomain.selectDockByDockId(dockAircraft.getDockId()); if(Objects.nonNull(dock)) { dock.setLastActiveTime(new Date()); dockDomain.updateDock(dock); // 如果是 state 消息,清除无人机和机场的 ThingsBoard 缓存并广播 if(isStateMessage) { // 清除机场缓存 Device dockDevice = deviceDomain.selectDeviceByDeviceId(dock.getDeviceId()); if(Objects.nonNull(dockDevice) && Objects.nonNull(dockDevice.getIotDeviceId())) { thingsBoardDomain.evictDeviceAttributesCache(dockDevice.getIotDeviceId()); thingsBoardDomain.evictDeviceTelemetryCache(dockDevice.getIotDeviceId()); } thingsBoardDomain.evictDeviceAttributesCache(device.getIotDeviceId()); thingsBoardDomain.evictDeviceTelemetryCache(device.getIotDeviceId()); // 广播机场 ID statisticsWebSocket.broadcast(String.valueOf(dock.getDockId())); log.debug("已广播机场ID: dockId={}", dock.getDockId()); } } } } } } } }); // 注册机场数据回调 handler.registerDockDataCallback(new IDockDataCallback() { @Override public void onDockData(DockData dockData) { // log.info("dockData:{}", dockData); // 判断是否是 state 触发 boolean isStateMessage = "state".equalsIgnoreCase(dockData.getMessageType()); // 如果是 state 消息,处理缓存清除和广播 if(isStateMessage) { Device dockDevice = deviceDomain.selectDeviceByDeviceSn(dockData.getDeviceSn()); if(Objects.nonNull(dockDevice)) { // 查找机场 Dock dock = dockDomain.selectDockByDeviceId(dockDevice.getDeviceId()); if(Objects.nonNull(dock)) { // 清除机场设备的 ThingsBoard 缓存 if(Objects.nonNull(dockDevice.getIotDeviceId())) { thingsBoardDomain.evictDeviceAttributesCache(dockDevice.getIotDeviceId()); thingsBoardDomain.evictDeviceTelemetryCache(dockDevice.getIotDeviceId()); // log.debug("已清除机场缓存: deviceSn={}, iotDeviceId={}", dockData.getDeviceSn(), dockDevice.getIotDeviceId()); } // 清除机场关联的所有无人机缓存 List dockAircrafts = dockAircraftDomain.selectDockAircraftByDockId(dock.getDockId()); if(!dockAircrafts.isEmpty()) { for(DockAircraft dockAircraft : dockAircrafts) { Aircraft aircraft = aircraftDomain.selectAircraftByAircraftId(dockAircraft.getAircraftId()); if(Objects.nonNull(aircraft)) { Device droneDevice = deviceDomain.selectDeviceByDeviceId(aircraft.getDeviceId()); if(Objects.nonNull(droneDevice) && Objects.nonNull(droneDevice.getIotDeviceId())) { thingsBoardDomain.evictDeviceAttributesCache(droneDevice.getIotDeviceId()); thingsBoardDomain.evictDeviceTelemetryCache(droneDevice.getIotDeviceId()); // log.debug("已清除无人机缓存: aircraftId={}, iotDeviceId={}", aircraft.getAircraftId(), droneDevice.getIotDeviceId()); } } } } // 广播机场 ID statisticsWebSocket.broadcast(String.valueOf(dock.getDockId())); log.debug("已广播机场ID: dockId={}", dock.getDockId()); } } } } }); log.info("客户端已创建并注册回调"); } }