a-tuoheng-device/src/main/java/com/ruoyi/device/service/impl/TuohengBufferDeviceImpl.java

836 lines
40 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.ruoyi.device.service.impl;
import com.ruoyi.device.domain.api.*;
import com.ruoyi.device.domain.impl.machine.state.CoverState;
import com.ruoyi.device.domain.impl.machine.state.DroneState;
import com.ruoyi.device.domain.impl.machine.state.MachineStates;
import com.ruoyi.device.domain.impl.machine.statemachine.MachineStateManager;
import com.ruoyi.device.domain.model.*;
import com.ruoyi.device.domain.model.thingsboard.AttributeMap;
import com.ruoyi.device.domain.model.thingsboard.TelemetryMap;
import com.ruoyi.device.domain.model.thingsboard.TelemetryValue;
import com.ruoyi.device.domain.model.thingsboard.tuoheng.constants.TuohengDeviceAttributes;
import com.ruoyi.device.domain.model.thingsboard.tuoheng.constants.TuohengDeviceTelemetry;
import com.ruoyi.device.service.api.IBufferDeviceService;
import com.ruoyi.device.service.dto.AircraftDetailDTO;
import com.ruoyi.device.service.dto.DockDetailDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 拓恒设备缓冲服务实现
* 专门处理拓恒设备的数据整合
*
* @author ruoyi
* @date 2026-02-04Ï
*/
@Service("tuohengBufferDeviceService")
@Slf4j
public class TuohengBufferDeviceImpl implements IBufferDeviceService {
/**
* 默认经纬度 - 南京市
*/
private static final Double DEFAULT_LONGITUDE = 118.796877;
private static final Double DEFAULT_LATITUDE = 32.060255;
@Autowired
private IDockDomain dockDomain;
@Autowired
private IDeviceDomain deviceDomain;
@Autowired
private IAircraftDomain aircraftDomain;
@Autowired
private IDockAircraftDomain dockAircraftDomain;
@Autowired
private IThingsBoardDomain thingsBoardDomain;
@Autowired
private MachineStateManager machineStateManager;
@Override
public DockDetailDTO getDockDetailById(Long dockId) {
log.info("获取拓恒机场详情: dockId={}", dockId);
// 查询机场基础信息
Dock dock = dockDomain.selectDockByDockId(dockId);
if (dock == null) {
log.warn("机场不存在: dockId={}", dockId);
return null;
}
log.info("Dock对象详细信息: dockId={}, cabinVideoUrl={}, outsideVideoUrl={}, liveVideoUrl={}",
dock.getDockId(), dock.getCabinVideoUrl(), dock.getOutsideVideoUrl(), dock.getLiveVideoUrl());
// 查询设备信息
Device device = deviceDomain.selectDeviceByDeviceId(dock.getDeviceId());
if (device == null) {
log.warn("机场对应的设备不存在: deviceId={}", dock.getDeviceId());
return null;
}
// 检查是否是拓恒设备
if (!"tuoheng".equals(device.getDeviceManufacturer())) {
log.warn("设备不是拓恒厂商: deviceId={}, manufacturer={}",
device.getDeviceId(), device.getDeviceManufacturer());
return null;
}
// 构建机场详情DTO
DockDetailDTO dto = new DockDetailDTO();
dto.setDockId(dock.getDockId());
dto.setDockName(dock.getDockName());
dto.setDockLocation(dock.getDockLocation());
dto.setInternalCamera(dock.getCabinVideoUrl());
dto.setExternalCamera(dock.getOutsideVideoUrl());
dto.setLiveCamera(dock.getLiveVideoUrl());
log.info("设置DTO视频地址: internalCamera={}, externalCamera={}, liveCamera={}",
dto.getInternalCamera(), dto.getExternalCamera(), dto.getLiveCamera());
dto.setDockIotId(device.getIotDeviceId());
dto.setSnNumber(device.getDeviceSn());
dto.setBindTime(device.getCreateTime().getTime());
dto.setDockManufacturer(device.getDeviceManufacturer());
// 查询关联的无人机,获取无人机的 iotDeviceId
String aircraftIotDeviceId = null;
List<DockAircraft> aircrafts = dockAircraftDomain.selectDockAircraftByDockId(dockId);
if (!CollectionUtils.isEmpty(aircrafts)) {
DockAircraft dockAircraft = aircrafts.get(0);
Aircraft aircraft = aircraftDomain.selectAircraftByAircraftId(dockAircraft.getAircraftId());
if (aircraft != null) {
dto.setAircraftId(aircraft.getAircraftId());
dto.setAircraftName(aircraft.getAircraftName());
Device airDevice = deviceDomain.selectDeviceByDeviceId(aircraft.getDeviceId());
if (airDevice != null) {
aircraftIotDeviceId = airDevice.getIotDeviceId();
dto.setAircraftIotId(aircraftIotDeviceId);
dto.setAircraftManufacturer(airDevice.getDeviceManufacturer());
dto.setAircraftModel(airDevice.getDeviceModel());
}
}
}
// 获取ThingsBoard数据并填充到DTO传入无人机的 iotDeviceId 用于判断工作状态)
fillTuohengDockDetail(dto, device.getIotDeviceId(), aircraftIotDeviceId);
return dto;
}
@Override
public AircraftDetailDTO getAircraftDetailById(Long aircraftId) {
log.info("获取拓恒无人机详情: aircraftId={}", aircraftId);
// 查询无人机基础信息
Aircraft aircraft = aircraftDomain.selectAircraftByAircraftId(aircraftId);
if (aircraft == null) {
log.warn("无人机不存在: aircraftId={}", aircraftId);
return null;
}
// 查询设备信息
Device device = deviceDomain.selectDeviceByDeviceId(aircraft.getDeviceId());
if (device == null) {
log.warn("无人机对应的设备不存在: deviceId={}", aircraft.getDeviceId());
return null;
}
// 检查是否是拓恒设备
if (!"tuoheng".equals(device.getDeviceManufacturer())) {
log.warn("设备不是拓恒厂商: deviceId={}, manufacturer={}",
device.getDeviceId(), device.getDeviceManufacturer());
return null;
}
// 构建无人机详情DTO
AircraftDetailDTO dto = new AircraftDetailDTO();
dto.setAircraftId(aircraft.getAircraftId());
dto.setAircraftName(aircraft.getAircraftName());
dto.setSnNumber(device.getDeviceSn());
dto.setBindTime(device.getCreateTime().getTime());
dto.setAircraftManufacturer(device.getDeviceManufacturer());
// 查询无人机关联的机场获取机场SN用于从MachineStateManager获取状态
String dockSn = null;
List<DockAircraft> dockAircrafts = dockAircraftDomain.selectDockAircraftByAircraftId(aircraftId);
if (!CollectionUtils.isEmpty(dockAircrafts)) {
DockAircraft dockAircraft = dockAircrafts.get(0);
Dock dock = dockDomain.selectDockByDockId(dockAircraft.getDockId());
if (dock != null) {
Device dockDevice = deviceDomain.selectDeviceByDeviceId(dock.getDeviceId());
if (dockDevice != null) {
dockSn = dockDevice.getDeviceSn();
}
}
}
// 获取ThingsBoard数据并填充到DTO传入机场SN用于获取状态
fillTuohengAircraftDetail(dto, device.getIotDeviceId(), dockSn);
return dto;
}
@Override
public Map<Long, DockDetailDTO> getDockDetailsByIds(List<Long> dockIds) {
if (CollectionUtils.isEmpty(dockIds)) {
return new HashMap<>();
}
Map<Long, DockDetailDTO> resultMap = new HashMap<>(dockIds.size());
for (Long dockId : dockIds) {
try {
DockDetailDTO dto = getDockDetailById(dockId);
if (dto != null) {
resultMap.put(dockId, dto);
}
} catch (Exception e) {
log.error("获取拓恒机场详情失败, dockId: {}", dockId, e);
}
}
return resultMap;
}
@Override
public Map<Long, AircraftDetailDTO> getAircraftDetailsByIds(List<Long> aircraftIds) {
if (CollectionUtils.isEmpty(aircraftIds)) {
return new HashMap<>();
}
Map<Long, AircraftDetailDTO> resultMap = new HashMap<>(aircraftIds.size());
for (Long aircraftId : aircraftIds) {
try {
AircraftDetailDTO dto = getAircraftDetailById(aircraftId);
if (dto != null) {
resultMap.put(aircraftId, dto);
}
} catch (Exception e) {
log.error("获取拓恒无人机详情失败, aircraftId: {}", aircraftId, e);
}
}
return resultMap;
}
/**
* 填充拓恒机场详情数据
*
* @param dto 机场详情DTO
* @param iotDeviceId ThingsBoard设备ID机场
* @param aircraftIotDeviceId 无人机ThingsBoard设备ID用于判断工作状态
*/
private void fillTuohengDockDetail(DockDetailDTO dto, String iotDeviceId, String aircraftIotDeviceId) {
try {
log.info("========== 开始填充拓恒机场详情 ==========");
log.info("iotDeviceId: {}", iotDeviceId);
// 获取拓恒设备属性
AttributeMap attributes = thingsBoardDomain.getPredefinedTuohengDeviceAttributes(iotDeviceId);
// log.info("拓恒设备属性数据: {}", attributes);
// 获取拓恒设备遥测数据
TelemetryMap telemetry = thingsBoardDomain.getPredefinedTuohengDeviceTelemetry(iotDeviceId);
// log.info("拓恒设备遥测数据: {}", telemetry);
// 设置固件版本(从属性中获取 hardware_version
attributes.get(TuohengDeviceAttributes.HARDWARE_VERSION)
.ifPresent(value -> {
log.info("HARDWARE_VERSION 固件版本: {}", value);
dto.setFirmwareVersion(value);
});
// 设置机场位置(从属性中获取 home.longitude 和 home.latitude取不到则使用南京市默认值
log.info("---------- 解析机场位置数据 ----------");
Double homeLongitude = attributes.get(TuohengDeviceAttributes.HOME_LONGITUDE)
.orElse(null);
if (homeLongitude != null) {
log.info("HOME_LONGITUDE 机场经度: {}", homeLongitude);
dto.setLongitude(homeLongitude);
} else {
log.info("HOME_LONGITUDE 未设置,使用默认值(南京市): {}", DEFAULT_LONGITUDE);
dto.setLongitude(DEFAULT_LONGITUDE);
}
Double homeLatitude = attributes.get(TuohengDeviceAttributes.HOME_LATITUDE)
.orElse(null);
if (homeLatitude != null) {
log.info("HOME_LATITUDE 机场纬度: {}", homeLatitude);
dto.setLatitude(homeLatitude);
} else {
log.info("HOME_LATITUDE 未设置,使用默认值(南京市): {}", DEFAULT_LATITUDE);
dto.setLatitude(DEFAULT_LATITUDE);
}
// 设置备降点位置(从属性中获取 backup.longitude 和 backup.latitude取不到则使用南京市默认值
log.info("---------- 解析备降点位置数据 ----------");
Double backupLongitude = attributes.get(TuohengDeviceAttributes.BACKUP_LONGITUDE)
.orElse(null);
if (backupLongitude != null) {
log.info("BACKUP_LONGITUDE 备降点经度: {}", backupLongitude);
dto.setBackupLongitude(backupLongitude);
} else {
log.info("BACKUP_LONGITUDE 未设置,使用默认值(南京市): {}", DEFAULT_LONGITUDE);
dto.setBackupLongitude(DEFAULT_LONGITUDE);
}
Double backupLatitude = attributes.get(TuohengDeviceAttributes.BACKUP_LATITUDE)
.orElse(null);
if (backupLatitude != null) {
log.info("BACKUP_LATITUDE 备降点纬度: {}", backupLatitude);
dto.setBackupLatitude(backupLatitude);
} else {
log.info("BACKUP_LATITUDE 未设置,使用默认值(南京市): {}", DEFAULT_LATITUDE);
dto.setBackupLatitude(DEFAULT_LATITUDE);
}
// 设置运行数据(从属性中获取 runningDuration 和 missionCount取不到则默认为 0
log.info("---------- 解析运行数据 ----------");
Integer runningDuration = attributes.get(TuohengDeviceAttributes.RUNNING_DURATION)
.orElse(0);
log.info("RUNNING_DURATION 运行时长: {} 小时", runningDuration);
dto.setRunningDuration(runningDuration);
Integer missionCount = attributes.get(TuohengDeviceAttributes.MISSION_COUNT)
.orElse(0);
log.info("MISSION_COUNT 作业架次: {}", missionCount);
dto.setMissionCount(missionCount);
// 设置在线状态 - 基于心跳时间戳判断离线基于无人机mode判断工作状态
telemetry.get(TuohengDeviceTelemetry.STATUS).ifPresentOrElse(statusValue -> {
long lastHeartbeatTime = statusValue.getTimestamp();
long currentTime = System.currentTimeMillis();
long timeDiff = currentTime - lastHeartbeatTime;
log.info("STATUS 心跳时间戳: {}, 当前时间: {}, 时间差: {}ms ({}秒)",
lastHeartbeatTime, currentTime, timeDiff, timeDiff / 1000);
// 5分钟 = 300000 毫秒
if (timeDiff > 300000) {
dto.setDockStatus("OFFLINE");
log.info("心跳超时(>5分钟),设置机场状态为 OFFLINE");
} else {
// 心跳正常机场在线通过无人机mode和舱门状态判断是IDLE还是WORKING
String dockStatus = "IDLE"; // 默认空闲
if (aircraftIotDeviceId != null) {
try {
// 获取无人机遥测数据
TelemetryMap aircraftTelemetry = thingsBoardDomain.getPredefinedTuohengDeviceTelemetry(aircraftIotDeviceId);
// 通过mode字段判断工作状态
String mode = aircraftTelemetry.get(TuohengDeviceTelemetry.MODE)
.map(TelemetryValue::getValue)
.orElse("");
log.info("无人机MODE值: {}", mode);
// 通过 MachineStateManager 获取舱门状态
MachineStates machineStates =
machineStateManager.getStates(dto.getSnNumber());
CoverState coverState =
machineStates.getCoverState();
log.info("机场舱门状态(从MachineStateManager): {}", coverState);
// 通过MODE判断飞行模式暂时注释掉数据不准确
// boolean isFlyingMode = "auto".equalsIgnoreCase(mode) ||
// "guided".equalsIgnoreCase(mode) ||
// "loiter".equalsIgnoreCase(mode) ||
// "rtl".equalsIgnoreCase(mode);
// if (isFlyingMode) {
// dockStatus = "WORKING";
// log.info("无人机处于{}模式,设置机场状态为 WORKING", mode);
// } else if (coverState == CoverState.OPENED) {
if (coverState == CoverState.OPENED) {
dockStatus = "WORKING";
log.info("舱门打开,设置机场状态为 WORKING");
} else {
log.info("舱门关闭,设置机场状态为 IDLE");
}
} catch (Exception e) {
log.warn("获取无人机mode或舱门状态失败默认设置为IDLE: {}", e.getMessage());
}
} else {
log.info("机场未绑定无人机,设置机场状态为 IDLE");
}
dto.setDockStatus(dockStatus);
log.info("心跳正常,设置机场状态: {}", dockStatus);
}
}, () -> {
dto.setDockStatus("OFFLINE");
log.info("没有心跳数据,设置机场状态为 OFFLINE");
});
// 设置舱内温度和湿度
log.info("---------- 解析舱内环境数据 ----------");
telemetry.get(TuohengDeviceTelemetry.NEST_INNER_TEMP)
.ifPresent(value -> {
log.info("NEST_INNER_TEMP 舱内温度: {}", value.getValue());
dto.setCabinTemperature(value.getValue());
});
telemetry.get(TuohengDeviceTelemetry.NEST_INNER_HUM)
.ifPresent(value -> {
log.info("NEST_INNER_HUM 舱内湿度: {}", value.getValue());
dto.setCabinHumidity(value.getValue());
});
/**
* 通过 MachineStateManager 获取舱门状态
*/
// 设置舱门状态
log.info("---------- 解析舱门状态 ----------");
try {
MachineStates machineStates =
machineStateManager.getStates(dto.getSnNumber());
CoverState coverState =
machineStates.getCoverState();
log.info("舱门状态(从MachineStateManager): {}", coverState);
String cabinDoorStatus;
if (coverState == CoverState.OPENED) {
cabinDoorStatus = "OPEN";
} else if (coverState == CoverState.CLOSED) {
cabinDoorStatus = "CLOSED";
} else {
cabinDoorStatus = "UNKNOWN";
}
dto.setCabinDoorStatus(cabinDoorStatus);
log.info("设置舱门状态: {}", cabinDoorStatus);
} catch (Exception e) {
log.warn("从MachineStateManager获取舱门状态失败: {}", e.getMessage());
dto.setCabinDoorStatus("UNKNOWN");
}
// 设置空调状态(从属性中获取 airConditionerStatus取不到则默认为 IDLE
log.info("---------- 解析空调状态 ----------");
String airConditionerStatus = attributes.get(TuohengDeviceAttributes.AIR_CONDITIONER_STATUS)
.orElse("IDLE");
log.info("AIR_CONDITIONER_STATUS 空调状态: {}", airConditionerStatus);
dto.setAirConditionerStatus(airConditionerStatus);
// 设置环境数据
log.info("---------- 解析气象数据 ----------");
// 环境温度和湿度从属性中获取(手动维护),取不到则为 null
attributes.get(TuohengDeviceAttributes.ENVIRONMENT_TEMPERATURE)
.ifPresent(value -> {
log.info("ENVIRONMENT_TEMPERATURE 环境温度: {}", value);
dto.setEnvironmentTemperature(value);
});
attributes.get(TuohengDeviceAttributes.ENVIRONMENT_HUMIDITY)
.ifPresent(value -> {
log.info("ENVIRONMENT_HUMIDITY 环境湿度: {}", value);
dto.setEnvironmentHumidity(value);
});
// 风速和降雨量从遥测数据中获取
telemetry.get(TuohengDeviceTelemetry.WEATHER_WIND_SPEED)
.ifPresent(value -> {
log.info("WEATHER_WIND_SPEED 风速: {}", value.getValue());
dto.setWindSpeed(value.getValue());
});
telemetry.get(TuohengDeviceTelemetry.WEATHER_RAINFALL)
.ifPresent(value -> {
log.info("WEATHER_RAINFALL 降雨量: {}", value.getValue());
dto.setRainfall(value.getValue());
});
// 设置电池信息(从无人机设备获取)
log.info("---------- 解析电池数据 ----------");
if (aircraftIotDeviceId != null) {
try {
// 获取无人机遥测数据
TelemetryMap aircraftTelemetry = thingsBoardDomain.getPredefinedTuohengDeviceTelemetry(aircraftIotDeviceId);
// 从无人机获取电池电量(使用 battery_remain
aircraftTelemetry.get(TuohengDeviceTelemetry.BATTERY_REMAIN)
.ifPresent(value -> {
log.info("BATTERY_REMAIN 无人机电池电量: {}", value.getValue());
dto.setCapacity_percent(value.getValue());
});
} catch (Exception e) {
log.warn("从无人机获取电池电量失败,尝试从机场获取: {}", e.getMessage());
// 如果无人机数据获取失败,降级使用机场的 BATTERY_LEVEL
telemetry.get(TuohengDeviceTelemetry.BATTERY_LEVEL)
.ifPresent(value -> {
log.info("BATTERY_LEVEL 机场电池电量(降级): {}", value.getValue());
dto.setCapacity_percent(value.getValue());
});
}
} else {
// 如果没有绑定无人机,使用机场的 BATTERY_LEVEL
log.info("机场未绑定无人机,使用机场电池电量");
telemetry.get(TuohengDeviceTelemetry.BATTERY_LEVEL)
.ifPresent(value -> {
log.info("BATTERY_LEVEL 机场电池电量: {}", value.getValue());
dto.setCapacity_percent(value.getValue());
});
}
// 设置充电状态
telemetry.get(TuohengDeviceTelemetry.BATTERY_B_CHARGING)
.ifPresent(value -> {
log.info("BATTERY_B_CHARGING 充电状态原始值: {}", value.getValue());
String chargingStatus = value.getValue() == 1 ? "CHARGING" : "FREE";
dto.setChargingStatus(chargingStatus);
log.info("设置充电状态: {}", chargingStatus);
});
// 设置机场设备自检数据升降架、X轴夹器、Y轴夹器
log.info("---------- 解析机场设备自检数据 ----------");
// 升降架状态,取不到值时默认为 NORMAL
String elevatorPosition = telemetry.get(TuohengDeviceTelemetry.LIFTER_STATUS)
.map(value -> {
Integer lifterStatus = value.getValue();
log.info("LIFTER_STATUS 升降架状态原始值: {}", lifterStatus);
// 0=正常, 非0=异常
return (lifterStatus != null && lifterStatus == 0) ? "NORMAL" : "ABNORMAL";
})
.orElse("NORMAL");
dto.setElevatorPosition(elevatorPosition);
log.info("设置升降架位置: {}", elevatorPosition);
// X轴夹器状态取不到值时默认为 NORMAL
String xAxisClampStatus = telemetry.get(TuohengDeviceTelemetry.HOLDER_X_STATUS)
.map(value -> {
Integer holderXStatus = value.getValue();
log.info("HOLDER_X_STATUS X轴夹器状态原始值: {}", holderXStatus);
// 0=正常, 非0=异常
return (holderXStatus != null && holderXStatus == 0) ? "NORMAL" : "ABNORMAL";
})
.orElse("NORMAL");
dto.setXAxisClampStatus(xAxisClampStatus);
log.info("设置X轴夹器状态: {}", xAxisClampStatus);
// Y轴夹器状态取不到值时默认为 NORMAL
String yAxisClampStatus = telemetry.get(TuohengDeviceTelemetry.HOLDER_Y_STATUS)
.map(value -> {
Integer holderYStatus = value.getValue();
log.info("HOLDER_Y_STATUS Y轴夹器状态原始值: {}", holderYStatus);
// 0=正常, 非0=异常
return (holderYStatus != null && holderYStatus == 0) ? "NORMAL" : "ABNORMAL";
})
.orElse("NORMAL");
dto.setYAxisClampStatus(yAxisClampStatus);
log.info("设置Y轴夹器状态: {}", yAxisClampStatus);
// 填充无人机状态信息
if (aircraftIotDeviceId != null) {
fillTuohengAircraftStatus(dto, aircraftIotDeviceId);
}
log.info("拓恒机场详情填充完成: iotDeviceId={}, dockStatus={}", iotDeviceId, dto.getDockStatus());
log.info("========== 拓恒机场详情填充结束 ==========");
} catch (Exception e) {
log.error("填充拓恒机场详情失败: iotDeviceId={}, error={}", iotDeviceId, e.getMessage(), e);
}
}
/**
* 填充拓恒无人机状态信息(用于机场详情中的无人机状态)
*
* @param dto 机场详情DTO
* @param aircraftIotDeviceId 无人机ThingsBoard设备ID
*/
private void fillTuohengAircraftStatus(DockDetailDTO dto, String aircraftIotDeviceId) {
try {
log.info("========== 开始填充拓恒无人机状态(机场详情中) ==========");
log.info("aircraftIotDeviceId: {}", aircraftIotDeviceId);
// 获取拓恒无人机遥测数据
TelemetryMap aircraftTelemetry = thingsBoardDomain.getPredefinedTuohengDeviceTelemetry(aircraftIotDeviceId);
log.info("拓恒无人机遥测数据: {}", aircraftTelemetry);
// 获取机场遥测数据(用于获取舱门状态)
// 注意aircraftIotDeviceId 是无人机的ID我们需要获取机场的舱门状态
// 舱门状态在机场设备的遥测数据中,需要从 dto.getDockIotId() 获取
String dockIotId = dto.getDockIotId();
TelemetryMap dockTelemetry = null;
if (dockIotId != null) {
dockTelemetry = thingsBoardDomain.getPredefinedTuohengDeviceTelemetry(dockIotId);
log.info("拓恒机场遥测数据(用于获取舱门状态): {}", dockTelemetry);
}
// 获取 mode 字段
String mode = aircraftTelemetry.get(TuohengDeviceTelemetry.MODE)
.map(TelemetryValue::getValue)
.orElse("");
log.info("无人机 MODE 值: {}", mode);
// 通过 MachineStateManager 获取舱门状态使用机场SN
CoverState coverState = null;
try {
MachineStates machineStates =
machineStateManager.getStates(dto.getSnNumber());
coverState = machineStates.getCoverState();
log.info("机场舱门状态(从MachineStateManager): {}", coverState);
} catch (Exception e) {
log.warn("从MachineStateManager获取舱门状态失败: {}", e.getMessage());
}
// 从 MachineStateManager 获取无人机开关机状态
DroneState droneState = null;
try {
MachineStates machineStates =
machineStateManager.getStates(dto.getSnNumber());
droneState = machineStates.getDroneState();
log.info("无人机状态(从MachineStateManager): {}", droneState);
} catch (Exception e) {
log.warn("从MachineStateManager获取无人机状态失败: {}", e.getMessage());
}
boolean isPowerOn = (droneState != null && droneState != DroneState.POWER_OFF && droneState != DroneState.UNKNOWN);
log.info("无人机开关机状态: {}", isPowerOn ? "开机" : "关机");
// 判断逻辑:开仓且开机才是任务中
String aircraftStatus;
if (coverState == CoverState.OPENED && isPowerOn) {
// 舱门打开且开机,表示正在执行任务
aircraftStatus = "IN_MISSION";
log.info("舱门打开 + 开机 → IN_MISSION");
} else if (coverState == CoverState.OPENED && !isPowerOn) {
// 舱门打开但关机
aircraftStatus = "POWER_OFF_OUT_CABIN";
log.info("舱门打开 + 关机 → POWER_OFF_OUT_CABIN");
} else if (coverState == CoverState.CLOSED) {
// 舱门关闭(舱内),根据开关机状态判断
if (isPowerOn) {
aircraftStatus = "POWER_ON_IN_CABIN";
log.info("舱门关闭 + 开机 → POWER_ON_IN_CABIN");
} else {
aircraftStatus = "POWER_OFF_IN_CABIN";
log.info("舱门关闭 + 关机 → POWER_OFF_IN_CABIN");
}
} else {
// 无法获取舱门状态,默认根据开关机状态判断
if (isPowerOn) {
aircraftStatus = "POWER_ON_IN_CABIN";
log.warn("无法获取舱门状态,默认设置: POWER_ON_IN_CABIN");
} else {
aircraftStatus = "POWER_OFF_IN_CABIN";
log.warn("无法获取舱门状态,默认设置: POWER_OFF_IN_CABIN");
}
}
dto.setAircraftStatus(aircraftStatus);
log.info("拓恒无人机状态填充完成: aircraftIotDeviceId={}, aircraftStatus={}",
aircraftIotDeviceId, dto.getAircraftStatus());
log.info("========== 拓恒无人机状态填充结束 ==========");
} catch (Exception e) {
log.error("填充拓恒无人机状态失败: aircraftIotDeviceId={}, error={}",
aircraftIotDeviceId, e.getMessage(), e);
}
}
/**
* 填充拓恒无人机详情数据
*
* @param dto 无人机详情DTO
* @param iotDeviceId ThingsBoard设备ID
* @param dockSn 机场SN号用于从MachineStateManager获取状态
*/
private void fillTuohengAircraftDetail(AircraftDetailDTO dto, String iotDeviceId, String dockSn) {
try {
log.info("========== 开始填充拓恒无人机详情 ==========");
log.info("iotDeviceId: {}", iotDeviceId);
// 获取拓恒设备属性
AttributeMap attributes = thingsBoardDomain.getPredefinedTuohengDeviceAttributes(iotDeviceId);
log.info("拓恒无人机属性数据: {}", attributes);
// 获取拓恒设备遥测数据
TelemetryMap telemetry = thingsBoardDomain.getPredefinedTuohengDeviceTelemetry(iotDeviceId);
log.info("拓恒无人机遥测数据: {}", telemetry);
// 设置无人机状态
log.info("---------- 解析无人机状态 ----------");
// 获取 mode 字段
String mode = telemetry.get(TuohengDeviceTelemetry.MODE)
.map(TelemetryValue::getValue)
.orElse("");
log.info("无人机 MODE 值: {}", mode);
// // 获取 tsingal图传信号强度用于判断开关机
// Integer tsingal = telemetry.get(TuohengDeviceTelemetry.TSINGAL)
// .map(TelemetryValue::getValue)
// .orElse(0);
// log.info("无人机 TSINGAL 值: {}", tsingal);
// 从 MachineStateManager 获取无人机开关机状态
DroneState droneState = null;
if (dockSn != null) {
try {
MachineStates machineStates = machineStateManager.getStates(dockSn);
droneState = machineStates.getDroneState();
log.info("无人机状态(从MachineStateManager): {}", droneState);
} catch (Exception e) {
log.warn("从MachineStateManager获取无人机状态失败: {}", e.getMessage());
}
} else {
log.warn("机场SN为空无法从MachineStateManager获取无人机状态");
}
boolean isPowerOn = (droneState != null && droneState != DroneState.POWER_OFF && droneState != DroneState.UNKNOWN);
log.info("无人机开关机状态: {}", isPowerOn ? "开机" : "关机");
// 从 MachineStateManager 获取舱门状态
CoverState coverState = null;
if (dockSn != null) {
try {
MachineStates machineStates = machineStateManager.getStates(dockSn);
coverState = machineStates.getCoverState();
log.info("机场舱门状态(从MachineStateManager): {}", coverState);
} catch (Exception e) {
log.warn("从MachineStateManager获取舱门状态失败: {}", e.getMessage());
}
} else {
log.warn("机场SN为空无法从MachineStateManager获取舱门状态");
}
// 判断逻辑:开仓且开机才是任务中
String aircraftStatus;
if (coverState == CoverState.OPENED && isPowerOn) {
// 舱门打开且开机,表示正在执行任务
aircraftStatus = "IN_MISSION";
log.info("舱门打开 + 开机 → IN_MISSION");
} else if (coverState == CoverState.OPENED && !isPowerOn) {
// 舱门打开但关机
aircraftStatus = "POWER_OFF_OUT_CABIN";
log.info("舱门打开 + 关机 → POWER_OFF_OUT_CABIN");
} else if (coverState == CoverState.CLOSED) {
// 舱门关闭(舱内),根据开关机状态判断
if (isPowerOn) {
aircraftStatus = "POWER_ON_IN_CABIN";
log.info("舱门关闭 + 开机 → POWER_ON_IN_CABIN");
} else {
aircraftStatus = "POWER_OFF_IN_CABIN";
log.info("舱门关闭 + 关机 → POWER_OFF_IN_CABIN");
}
} else {
// 无法获取舱门状态,默认根据开关机状态判断
if (isPowerOn) {
aircraftStatus = "POWER_ON_IN_CABIN";
log.warn("无法获取舱门状态,默认设置: POWER_ON_IN_CABIN");
} else {
aircraftStatus = "POWER_OFF_IN_CABIN";
log.warn("无法获取舱门状态,默认设置: POWER_OFF_IN_CABIN");
}
}
dto.setAircraftStatus(aircraftStatus);
// 设置作业架次(从属性中获取,取不到则默认为 0
log.info("---------- 解析作业架次 ----------");
Integer missionCount = attributes.get(TuohengDeviceAttributes.MISSION_COUNT)
.orElse(0);
log.info("MISSION_COUNT 作业架次: {}", missionCount);
dto.setMissionCount(missionCount);
// 设置GPS信号
log.info("---------- 解析GPS数据 ----------");
telemetry.get(TuohengDeviceTelemetry.SAT_COUNT)
.ifPresent(value -> {
log.info("SAT_COUNT 卫星数量: {}", value.getValue());
dto.setGpsSignal(value.getValue());
});
// 设置电池信息
log.info("---------- 解析电池数据 ----------");
telemetry.get(TuohengDeviceTelemetry.BATTERY_REMAIN)
.ifPresent(value -> {
log.info("BATTERY_REMAIN 剩余电量: {}", value.getValue());
dto.setBatteryLevel(value.getValue());
});
// 优先使用 battery_totalVoltageBMS电池电压如果没有则使用 voltage无人机电压
// 注意电压需要乘以1000转换为毫伏mV
Double voltageValue = telemetry.get(TuohengDeviceTelemetry.BATTERY_TOTAL_VOLTAGE)
.map(TelemetryValue::getValue)
.orElse(null);
if (voltageValue != null) {
log.info("BATTERY_TOTAL_VOLTAGE 总电压: {} V", voltageValue);
dto.setVoltage((int) (voltageValue * 1000)); // 转换为毫伏
log.info("设置电压: {} mV", dto.getVoltage());
} else {
telemetry.get(TuohengDeviceTelemetry.VOLTAGE)
.ifPresent(value -> {
log.info("VOLTAGE 电压(备用): {} V", value.getValue());
Double voltage = value.getValue();
if (voltage != null) {
dto.setVoltage((int) (voltage * 1000)); // 转换为毫伏
log.info("设置电压: {} mV", dto.getVoltage());
}
});
}
telemetry.get(TuohengDeviceTelemetry.BATTERY_CELL_TEMP)
.ifPresent(value -> {
log.info("BATTERY_CELL_TEMP 电池温度: {}", value.getValue());
dto.setBatteryTemperature(value.getValue());
});
telemetry.get(TuohengDeviceTelemetry.BATTERY_NUM_CYCLES)
.ifPresent(value -> {
log.info("BATTERY_NUM_CYCLES 循环次数: {}", value.getValue());
dto.setCycleCount(value.getValue());
});
// 设置飞行时长(从属性中获取,取不到则默认为 null
log.info("---------- 解析飞行数据 ----------");
Integer flightDuration = attributes.get(TuohengDeviceAttributes.FLIGHT_DURATION)
.orElse(null);
if (flightDuration != null) {
log.info("FLIGHT_DURATION 飞行时长: {} 秒", flightDuration);
dto.setFlightDuration(flightDuration);
} else {
log.info("FLIGHT_DURATION 未设置");
}
// 设置最大飞行高度(从属性中获取,取不到则默认为 null
log.info("---------- 解析飞行限制 ----------");
Integer maxAltitude = attributes.get(TuohengDeviceAttributes.MAX_ALTITUDE)
.orElse(null);
if (maxAltitude != null) {
log.info("MAX_ALTITUDE 最大飞行高度: {} 米", maxAltitude);
dto.setMaxAltitude(maxAltitude);
} else {
log.info("MAX_ALTITUDE 未设置");
}
// 设置最大飞行距离(从属性中获取,取不到则默认为 null
Integer maxDistance = attributes.get(TuohengDeviceAttributes.MAX_DISTANCE)
.orElse(null);
if (maxDistance != null) {
log.info("MAX_DISTANCE 最大飞行距离: {} 米", maxDistance);
dto.setMaxDistance(maxDistance);
} else {
log.info("MAX_DISTANCE 未设置");
}
log.info("拓恒无人机详情填充完成: iotDeviceId={}, aircraftStatus={}", iotDeviceId, dto.getAircraftStatus());
log.info("========== 拓恒无人机详情填充结束 ==========");
} catch (Exception e) {
log.error("填充拓恒无人机详情失败: iotDeviceId={}, error={}", iotDeviceId, e.getMessage(), e);
}
}
}