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 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 getDockDetailsByIds(List dockIds) { if (CollectionUtils.isEmpty(dockIds)) { return new HashMap<>(); } Map 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 getAircraftDetailsByIds(List aircraftIds) { if (CollectionUtils.isEmpty(aircraftIds)) { return new HashMap<>(); } Map 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_totalVoltage(BMS电池电压),如果没有则使用 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); } } }