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

738 lines
35 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.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;
@Override
public DockDetailDTO getDockDetailById(Long dockId) {
log.info("获取拓恒机场详情: dockId={}", dockId);
// 查询机场基础信息
Dock dock = dockDomain.selectDockByDockId(dockId);
if (dock == null) {
log.warn("机场不存在: dockId={}", dockId);
return null;
}
// 查询设备信息
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.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());
// 获取ThingsBoard数据并填充到DTO
fillTuohengAircraftDetail(dto, device.getIotDeviceId());
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);
// 获取舱门状态(从机场遥测数据中获取)
Integer doorStatus = telemetry.get(TuohengDeviceTelemetry.NEST_DOOR_STATUS)
.map(TelemetryValue::getValue)
.orElse(null);
log.info("机场舱门状态: {}", doorStatus);
// WORKING状态需要同时满足mode=="auto" 且舱门打开(doorStatus==0)
if ("auto".equalsIgnoreCase(mode) && doorStatus != null && doorStatus == 0) {
dockStatus = "WORKING"; // auto模式且舱门打开表示正在执行任务
log.info("无人机处于auto模式且舱门打开设置机场状态为 WORKING");
} else {
if ("auto".equalsIgnoreCase(mode) && (doorStatus == null || doorStatus != 0)) {
log.info("无人机处于auto模式但舱门未打开(doorStatus={}), 设置机场状态为 IDLE", doorStatus);
} else {
log.info("无人机处于{}模式,设置机场状态为 IDLE", mode);
}
}
} 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());
});
// 设置舱门状态
log.info("---------- 解析舱门状态 ----------");
telemetry.get(TuohengDeviceTelemetry.NEST_DOOR_STATUS)
.ifPresent(value -> {
Integer doorStatus = value.getValue();
log.info("NEST_DOOR_STATUS 舱门状态原始值: {}", doorStatus);
// 0=打开, 1=关闭
String cabinDoorStatus = (doorStatus != null && doorStatus == 0) ? "OPEN" : "CLOSED";
dto.setCabinDoorStatus(cabinDoorStatus);
log.info("设置舱门状态: {}", cabinDoorStatus);
});
// 设置空调状态(从属性中获取 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("---------- 解析机场设备自检数据 ----------");
telemetry.get(TuohengDeviceTelemetry.LIFTER_STATUS)
.ifPresent(value -> {
Integer lifterStatus = value.getValue();
log.info("LIFTER_STATUS 升降架状态原始值: {}", lifterStatus);
// 0=正常, 非0=异常
String elevatorPosition = (lifterStatus != null && lifterStatus == 0) ? "NORMAL" : "ABNORMAL";
dto.setElevatorPosition(elevatorPosition);
log.info("设置升降架位置: {}", elevatorPosition);
});
telemetry.get(TuohengDeviceTelemetry.HOLDER_X_STATUS)
.ifPresent(value -> {
Integer holderXStatus = value.getValue();
log.info("HOLDER_X_STATUS X轴夹器状态原始值: {}", holderXStatus);
// 0=正常, 非0=异常
String xAxisClampStatus = (holderXStatus != null && holderXStatus == 0) ? "NORMAL" : "ABNORMAL";
dto.setXAxisClampStatus(xAxisClampStatus);
log.info("设置X轴夹器状态: {}", xAxisClampStatus);
});
telemetry.get(TuohengDeviceTelemetry.HOLDER_Y_STATUS)
.ifPresent(value -> {
Integer holderYStatus = value.getValue();
log.info("HOLDER_Y_STATUS Y轴夹器状态原始值: {}", holderYStatus);
// 0=正常, 非0=异常
String yAxisClampStatus = (holderYStatus != null && holderYStatus == 0) ? "NORMAL" : "ABNORMAL";
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);
// 获取 tsingal图传信号强度用于判断开关机
Integer tsingal = aircraftTelemetry.get(TuohengDeviceTelemetry.TSINGAL)
.map(TelemetryValue::getValue)
.orElse(0);
log.info("无人机 TSINGAL 值: {}", tsingal);
boolean isPowerOn = tsingal > 60; // tsingal > 60 表示开机
log.info("无人机开关机状态: {}", isPowerOn ? "开机" : "关机");
// 获取 nest_door_status舱门状态
Integer doorStatus = null;
if (dockTelemetry != null) {
doorStatus = dockTelemetry.get(TuohengDeviceTelemetry.NEST_DOOR_STATUS)
.map(TelemetryValue::getValue)
.orElse(null);
log.info("机场舱门状态: {}", doorStatus);
}
// 判断逻辑IN_MISSION 需要同时满足 mode=="auto" 且舱门打开
String aircraftStatus;
if ("auto".equalsIgnoreCase(mode) && doorStatus != null && doorStatus == 0) {
// mode == "auto" 且舱门打开,表示正在执行任务
aircraftStatus = "IN_MISSION";
log.info("无人机处于 auto 模式且舱门打开,设置状态: IN_MISSION");
} else {
// 其他情况,根据 tsingal 和 nest_door_status 判断
if (doorStatus != null && doorStatus == 1) {
// 舱门关闭(舱内)
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 (doorStatus != null && doorStatus == 0) {
// 舱门打开(舱外),但不是 auto 模式
if (isPowerOn) {
aircraftStatus = "POWER_ON_OUT_CABIN";
log.info("舱门打开 + 开机(非auto模式) → POWER_ON_OUT_CABIN");
} else {
aircraftStatus = "POWER_OFF_OUT_CABIN";
log.info("舱门打开 + 关机 → POWER_OFF_OUT_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
*/
private void fillTuohengAircraftDetail(AircraftDetailDTO dto, String iotDeviceId) {
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);
boolean isPowerOn = tsingal > 60; // tsingal > 60 表示开机
log.info("无人机开关机状态: {}", isPowerOn ? "开机" : "关机");
// 判断逻辑
// 注意:无人机详情接口无法获取机场舱门状态
// 如果 mode == "auto" 且开机,推测为 IN_MISSION
// 否则根据开关机状态判断
String aircraftStatus;
if ("auto".equalsIgnoreCase(mode) && isPowerOn) {
// mode == "auto" 且开机,推测正在执行任务
aircraftStatus = "IN_MISSION";
log.info("无人机处于 auto 模式且开机,推测状态: IN_MISSION");
} else {
// 其他情况,根据开关机状态判断(默认舱内)
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");
}
}
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);
}
}
}