678 lines
27 KiB
Java
678 lines
27 KiB
Java
package com.ruoyi.device.service.impl;
|
||
|
||
import com.alibaba.fastjson2.JSON;
|
||
import com.ruoyi.device.api.domain.PayloadVO;
|
||
import com.ruoyi.device.api.enums.PayloadStatusEnum;
|
||
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.constants.DeviceAttributes;
|
||
import com.ruoyi.device.domain.model.thingsboard.constants.DeviceTelemetry;
|
||
import com.ruoyi.device.domain.model.weather.Weather;
|
||
import com.ruoyi.device.service.api.IBufferDeviceService;
|
||
import com.ruoyi.device.service.dto.AircraftDTO;
|
||
import com.ruoyi.device.service.dto.AircraftDetailDTO;
|
||
import com.ruoyi.device.service.dto.DockDetailDTO;
|
||
import com.ruoyi.device.api.enums.AircraftStatusEnum;
|
||
import com.ruoyi.device.api.enums.DockStatusEnum;
|
||
import com.ruoyi.device.api.enums.NetworkTypeEnum;
|
||
import com.ruoyi.device.api.enums.AirConditionerStatusEnum;
|
||
import com.ruoyi.device.api.enums.CabinDoorStatusEnum;
|
||
|
||
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.ArrayList;
|
||
import java.util.HashMap;
|
||
import java.util.List;
|
||
import java.util.Map;
|
||
import java.util.stream.Collectors;
|
||
|
||
/**
|
||
* 设备缓冲服务实现
|
||
* 整合数据库数据和ThingsBoard数据
|
||
*
|
||
* @author ruoyi
|
||
* @date 2026-01-20
|
||
*/
|
||
@Service
|
||
@Slf4j
|
||
public class BufferDeviceImpl implements IBufferDeviceService
|
||
{
|
||
@Autowired
|
||
private IDockDomain dockDomain;
|
||
|
||
@Autowired
|
||
private IDeviceDomain deviceDomain;
|
||
|
||
@Autowired
|
||
private IAircraftDomain aircraftDomain;
|
||
|
||
@Autowired
|
||
private IAircraftPayloadDomain aircraftPayloadDomain;
|
||
|
||
@Autowired
|
||
private IDockAircraftDomain dockAircraftDomain;
|
||
|
||
@Autowired
|
||
private IThingsBoardDomain thingsBoardDomain;
|
||
|
||
@Autowired
|
||
private IPayloadDomain payloadDomain;
|
||
|
||
@Autowired
|
||
private IWeatherDomain iWeatherDomain;
|
||
|
||
@Override
|
||
public DockDetailDTO getDockDetailById(Long dockId)
|
||
{
|
||
|
||
Dock dock = dockDomain.selectDockByDockId(dockId);
|
||
log.info("selectDockByDockId {}",JSON.toJSONString(dock));
|
||
if (dock == null)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
Device device = deviceDomain.selectDeviceByDeviceId(dock.getDeviceId());
|
||
log.info("selectDeviceByDeviceId {}",JSON.toJSONString(device));
|
||
|
||
DockDetailDTO dto = getChangeAbleDockDetailDTO(device.getIotDeviceId());
|
||
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());
|
||
|
||
|
||
List<DockAircraft> aircrafts = dockAircraftDomain.selectDockAircraftByDockId(dockId);
|
||
|
||
if(!CollectionUtils.isEmpty(aircrafts)){
|
||
DockAircraft dockAircraft = aircrafts.get(0);
|
||
Aircraft aircraft = aircraftDomain.selectAircraftByAircraftId(dockAircraft.getAircraftId());
|
||
dto.setAircraftId(aircraft.getAircraftId());
|
||
dto.setAircraftName(aircraft.getAircraftName());
|
||
|
||
Device airDevice = deviceDomain.selectDeviceByDeviceId(aircraft.getDeviceId());
|
||
dto.setAircraftIotId(airDevice.getIotDeviceId());
|
||
|
||
|
||
|
||
List<AircraftPayload> aircraftPayloads =
|
||
aircraftPayloadDomain.selectAircraftPayloadByAircraftId(aircraft.getAircraftId());
|
||
|
||
if(!CollectionUtils.isEmpty(aircraftPayloads)){
|
||
List<PayloadVO> payloads = new ArrayList<>(aircraftPayloads.size());
|
||
for(AircraftPayload aircraftPayload : aircraftPayloads){
|
||
Payload payload = payloadDomain.selectPayloadByPayloadId(aircraftPayload.getPayloadId());
|
||
PayloadVO payloadVO = new PayloadVO();
|
||
payloadVO.setPayloadId(aircraftPayload.getPayloadId());
|
||
payloadVO.setPayloadName(payload.getPayloadName());
|
||
payloadVO.setPayloadType(payload.getPayloadType());
|
||
payloadVO.setPayloadStatus(PayloadStatusEnum.ONLINE.getCode());
|
||
|
||
payloads.add(payloadVO);
|
||
}
|
||
dto.setPayloadList(payloads);
|
||
}
|
||
|
||
|
||
AircraftDetailDTO aircraftDetailDTO = getChangeAbleAirDetailDTO(airDevice.getIotDeviceId(), device.getIotDeviceId());
|
||
/**
|
||
* 设置无人机状态
|
||
*/
|
||
dto.setAircraftStatus(aircraftDetailDTO.getAircraftStatus());
|
||
/**
|
||
* 设置作业架次
|
||
*/
|
||
dto.setMissionCount(aircraftDetailDTO.getMissionCount());
|
||
|
||
}
|
||
|
||
|
||
|
||
return dto;
|
||
|
||
|
||
}
|
||
|
||
@Override
|
||
public AircraftDetailDTO getAircraftDetailById(Long aircraftId) {
|
||
Aircraft aircraft = aircraftDomain.selectAircraftByAircraftId(aircraftId);
|
||
|
||
log.info("selectAircraftByAircraftId {}",JSON.toJSONString(aircraft));
|
||
if (aircraft == null)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
Device device = deviceDomain.selectDeviceByDeviceId(aircraft.getDeviceId());
|
||
log.info("selectDeviceByDeviceId {}",JSON.toJSONString(device));
|
||
|
||
// 查找无人机关联的机场
|
||
List<DockAircraft> dockAircrafts = dockAircraftDomain.selectDockAircraftByAircraftId(aircraftId);
|
||
String dockDeviceIotId = null;
|
||
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) {
|
||
dockDeviceIotId = dockDevice.getIotDeviceId();
|
||
}
|
||
}
|
||
}
|
||
|
||
AircraftDetailDTO dto = getChangeAbleAirDetailDTO(device.getIotDeviceId(), dockDeviceIotId);
|
||
dto.setAircraftId(aircraft.getAircraftId());
|
||
dto.setAircraftName(aircraft.getAircraftName());
|
||
dto.setSnNumber(device.getDeviceSn());
|
||
dto.setBindTime(device.getCreateTime().getTime());
|
||
|
||
|
||
List<AircraftPayload> aircraftPayloads =
|
||
aircraftPayloadDomain.selectAircraftPayloadByAircraftId(aircraft.getAircraftId());
|
||
|
||
if(!CollectionUtils.isEmpty(aircraftPayloads)){
|
||
List<PayloadVO> payloads = new ArrayList<>(aircraftPayloads.size());
|
||
for(AircraftPayload aircraftPayload : aircraftPayloads){
|
||
Payload payload = payloadDomain.selectPayloadByPayloadId(aircraftPayload.getPayloadId());
|
||
PayloadVO payloadVO = new PayloadVO();
|
||
payloadVO.setPayloadId(aircraftPayload.getPayloadId());
|
||
payloadVO.setPayloadName(payload.getPayloadName());
|
||
payloadVO.setPayloadType(payload.getPayloadType());
|
||
payloadVO.setPayloadStatus(PayloadStatusEnum.ONLINE.getCode());
|
||
|
||
payloads.add(payloadVO);
|
||
}
|
||
dto.setPayloadList(payloads);
|
||
}
|
||
|
||
// 获取电池SN号 - 从 batteries 数组里面的第一个的 SN号
|
||
TelemetryMap telemetryMap = thingsBoardDomain.getPredefinedDeviceTelemetry(device.getIotDeviceId());
|
||
telemetryMap.get(DeviceTelemetry.BATTERY)
|
||
.ifPresent(telemetryValue -> {
|
||
var batteryData = telemetryValue.getValue();
|
||
if (batteryData != null && !CollectionUtils.isEmpty(batteryData.getBatteries())) {
|
||
// log.info("batteries {}",JSON.toJSONString(batteryData));
|
||
String batterySn = batteryData.getBatteries().get(0).getSn();
|
||
dto.setVoltage(batteryData.getBatteries().get(0).getVoltage());
|
||
dto.setBatteryLevel(batteryData.getBatteries().get(0).getCapacityPercent());
|
||
dto.setBatteryTemperature(batteryData.getBatteries().get(0).getTemperature());
|
||
dto.setBatteryLevel(batteryData.getBatteries().get(0).getCapacityPercent());
|
||
dto.setCycleCount(batteryData.getBatteries().get(0).getLoopTimes());
|
||
dto.setFlightTimeRemaining(batteryData.getRemainFlightTime());
|
||
dto.setBatterySn(batterySn);
|
||
}
|
||
});
|
||
|
||
// 飞行时长 - 从 total_flight_time 获取秒数并转换为天
|
||
telemetryMap.get(DeviceTelemetry.Total_Flight_Time)
|
||
.ifPresent(telemetryValue -> {
|
||
Integer seconds = telemetryValue.getValue();
|
||
if (seconds != null) {
|
||
// 将秒转换为天:秒 / (60 * 60 * 24)
|
||
Integer days = seconds / (60 * 60 * 24);
|
||
dto.setFlightDuration(days);
|
||
}
|
||
});
|
||
|
||
return dto;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
private DockDetailDTO getChangeAbleDockDetailDTO(String dockerDeviceIotId)
|
||
{
|
||
DockDetailDTO dto = new DockDetailDTO();
|
||
AttributeMap attributeMap = thingsBoardDomain.getPredefinedDeviceAttributes(dockerDeviceIotId);
|
||
TelemetryMap telemetryMap = thingsBoardDomain.getPredefinedDeviceTelemetry(dockerDeviceIotId);
|
||
|
||
// 根据 ACTIVE 属性和 MODE_CODE 设置机场状态
|
||
// 先检查 ACTIVE 属性判断是否离线,只有在线时才通过 MODE_CODE 判断具体状态
|
||
// MODE_CODE 定义: {"0":"空闲中","1":"现场调试","2":"远程调试","3":"固件升级中","4":"作业中","5":"待标定"}
|
||
Boolean isActive = attributeMap.get(DeviceAttributes.ACTIVE).orElse(false);
|
||
|
||
if (!isActive) {
|
||
// 设备离线
|
||
dto.setDockStatus(DockStatusEnum.OFFLINE.getCode());
|
||
} else {
|
||
// 设备在线,根据 MODE_CODE 判断具体状态
|
||
attributeMap.get(DeviceAttributes.MODE_CODE).ifPresent(modeCode -> {
|
||
String dockStatus = mapModeCodeToDockStatus(modeCode);
|
||
dto.setDockStatus(dockStatus);
|
||
});
|
||
}
|
||
|
||
// 设置备降点坐标数据
|
||
// 备降点经度
|
||
telemetryMap.get(DeviceTelemetry.Alternate_land_point_Longitude)
|
||
.ifPresent(telemetryValue -> dto.setBackupLongitude(telemetryValue.getValue()));
|
||
|
||
// 备降点纬度
|
||
telemetryMap.get(DeviceTelemetry.Alternate_land_point_Latitude)
|
||
.ifPresent(telemetryValue -> dto.setBackupLatitude(telemetryValue.getValue()));
|
||
|
||
// 从 acc_time 获取运行时间,转换为天为单位
|
||
// acc_time 单位是秒,需要转换为天:秒 / (60 * 60 * 24)
|
||
telemetryMap.get(DeviceTelemetry.Acc_Time)
|
||
.ifPresent(telemetryValue -> {
|
||
Integer seconds = telemetryValue.getValue();
|
||
if (seconds != null) {
|
||
// 将秒转换为天
|
||
Integer days = seconds / (60 * 60 * 24);
|
||
dto.setRunningDuration(days);
|
||
}
|
||
});
|
||
|
||
// 设置环境数据
|
||
// 风速(单位:米每秒)
|
||
telemetryMap.get(DeviceTelemetry.Wind_Speed)
|
||
.ifPresent(telemetryValue -> dto.setWindSpeed(telemetryValue.getValue()));
|
||
|
||
// 降雨量(枚举值:0-无雨,1-小雨,2-中雨,3-大雨)
|
||
telemetryMap.get(DeviceTelemetry.Rainfall)
|
||
.ifPresent(telemetryValue -> {
|
||
Integer rainfallCode = telemetryValue.getValue();
|
||
if (rainfallCode != null) {
|
||
dto.setRainfall(rainfallCode.doubleValue());
|
||
}
|
||
});
|
||
|
||
// 环境温度(环境温度)
|
||
telemetryMap.get(DeviceTelemetry.Environment_Temperature)
|
||
.ifPresent(telemetryValue -> dto.setEnvironmentTemperature(telemetryValue.getValue()));
|
||
|
||
// 设置网络类型和网络速率
|
||
// 网络类型(枚举值:1-4G,2-以太网)
|
||
telemetryMap.get(DeviceTelemetry.Network_State_Type)
|
||
.ifPresent(telemetryValue -> {
|
||
Integer networkTypeCode = telemetryValue.getValue();
|
||
String networkType = mapNetworkTypeCodeToEnum(networkTypeCode);
|
||
dto.setNetworkType(networkType);
|
||
});
|
||
|
||
// 网络速率(单位:千字节每秒 KB/s)
|
||
telemetryMap.get(DeviceTelemetry.Network_State_Rate)
|
||
.ifPresent(telemetryValue -> {
|
||
Double rate = telemetryValue.getValue();
|
||
if (rate != null) {
|
||
// 将速率转换为网络延迟(假设延迟与速率成反比)
|
||
// 这里可以根据实际业务逻辑调整
|
||
dto.setNetworkDelay(rate.intValue());
|
||
}
|
||
});
|
||
|
||
// 设置硬件状态数据
|
||
// 空调状态(枚举值:0-空闲模式,1-制冷模式,2-制热模式,3-除湿模式等)
|
||
telemetryMap.get(DeviceTelemetry.AIR_CONDITIONER_STATE)
|
||
.ifPresent(telemetryValue -> {
|
||
Integer stateCode = telemetryValue.getValue();
|
||
if (stateCode != null) {
|
||
dto.setAirConditionerStatus(mapAirConditionerState(stateCode));
|
||
}
|
||
});
|
||
|
||
// 舱门状态(枚举值:0-关闭,1-打开,2-半开,3-舱盖状态异常)
|
||
telemetryMap.get(DeviceTelemetry.Cover_State)
|
||
.ifPresent(telemetryValue -> {
|
||
Integer coverState = telemetryValue.getValue();
|
||
if (coverState != null) {
|
||
dto.setCabinDoorStatus(mapCabinDoorState(coverState));
|
||
}
|
||
});
|
||
|
||
// 舱内温度
|
||
telemetryMap.get(DeviceTelemetry.TEMPERATURE)
|
||
.ifPresent(telemetryValue -> dto.setCabinTemperature(telemetryValue.getValue()));
|
||
|
||
// 舱内湿度
|
||
telemetryMap.get(DeviceTelemetry.HUMIDITY)
|
||
.ifPresent(telemetryValue -> dto.setCabinHumidity(telemetryValue.getValue()));
|
||
|
||
// 赋予经纬度
|
||
// log.info("开始获取经纬度数据,dockerDeviceIotId: {}", dockerDeviceIotId);
|
||
|
||
// 纬度
|
||
attributeMap.get(DeviceAttributes.Latitude)
|
||
.ifPresentOrElse(
|
||
latitude -> {
|
||
// log.info("获取到纬度数据: {}", latitude);
|
||
dto.setLatitude(latitude);
|
||
},
|
||
() -> log.warn("未获取到纬度数据,dockerDeviceIotId: {}", dockerDeviceIotId)
|
||
);
|
||
|
||
// 经度
|
||
attributeMap.get(DeviceAttributes.Longitude)
|
||
.ifPresentOrElse(
|
||
longitude -> {
|
||
log.info("获取到经度数据: {}", longitude);
|
||
dto.setLongitude(longitude);
|
||
},
|
||
() -> log.warn("未获取到经度数据,dockerDeviceIotId: {}", dockerDeviceIotId)
|
||
);
|
||
|
||
Weather weather =iWeatherDomain.weatherInfo(dto.getLatitude().toString(), dto.getLongitude().toString());
|
||
if (weather != null) {
|
||
dto.setWindSpeed(weather.getWindSpeed());
|
||
dto.setRainfall(weather.getRainfall());
|
||
dto.setEnvironmentTemperature(weather.getEnvironmentTemperature());
|
||
dto.setEnvironmentHumidity(weather.getEnvironmentHumidity());
|
||
// log.info("weather {}",weather);
|
||
}
|
||
|
||
|
||
// 无人机充电状态(枚举值:0-空闲,1-充电中)
|
||
telemetryMap.get(DeviceTelemetry.Drone_Charge_State_State)
|
||
.ifPresent(telemetryValue -> {
|
||
Integer chargeState = telemetryValue.getValue();
|
||
if (chargeState != null) {
|
||
String chargingStatus = mapChargeStateToStatus(chargeState);
|
||
dto.setChargingStatus(chargingStatus);
|
||
}
|
||
});
|
||
|
||
// 电量百分比
|
||
telemetryMap.get(DeviceTelemetry.Drone_Charge_State_Capacity_Percent)
|
||
.ifPresent(telemetryValue -> {
|
||
Integer capacityPercent = telemetryValue.getValue();
|
||
dto.setCapacity_percent(capacityPercent);
|
||
});
|
||
|
||
return dto;
|
||
}
|
||
|
||
/**
|
||
* 将 MODE_CODE 映射到机场状态
|
||
* @param modeCode 模式代码
|
||
* @return 机场状态字符串
|
||
*/
|
||
private String mapModeCodeToDockStatus(Integer modeCode) {
|
||
switch (modeCode) {
|
||
case 0:
|
||
return DockStatusEnum.IDLE.getCode();
|
||
case 1:
|
||
case 2:
|
||
return DockStatusEnum.Debugging.getCode();
|
||
case 3:
|
||
return DockStatusEnum.FIRMWARE_UPGRADING.getCode();
|
||
case 4:
|
||
return DockStatusEnum.WORKING.getCode();
|
||
case 5:
|
||
default:
|
||
return DockStatusEnum.UNKNOWN.getCode();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 将网络类型代码映射到 NetworkTypeEnum
|
||
* @param networkTypeCode 网络类型代码(1-4G,2-以太网)
|
||
* @return 网络类型枚举的 code
|
||
*/
|
||
private String mapNetworkTypeCodeToEnum(Integer networkTypeCode) {
|
||
if (networkTypeCode == null) {
|
||
return null;
|
||
}
|
||
|
||
switch (networkTypeCode) {
|
||
case 1:
|
||
return NetworkTypeEnum.FOUR_G.getCode();
|
||
case 2:
|
||
return NetworkTypeEnum.ETHERNET.getCode();
|
||
default:
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 将充电状态代码映射到充电状态字符串
|
||
* @param chargeState 充电状态代码(0-空闲,1-充电中)
|
||
* @return 充电状态字符串
|
||
*/
|
||
private String mapChargeStateToStatus(Integer chargeState) {
|
||
if (chargeState == null) {
|
||
return "未知";
|
||
}
|
||
|
||
switch (chargeState) {
|
||
case 0:
|
||
return "FREE";
|
||
case 1:
|
||
return "CHARGING";
|
||
default:
|
||
return "UNKNOWN";
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 将空调状态代码映射到 AirConditionerStatusEnum
|
||
* @param stateCode 空调状态代码
|
||
* @return 空调状态枚举的 code
|
||
*/
|
||
private String mapAirConditionerState(Integer stateCode) {
|
||
if (stateCode == null) {
|
||
return null;
|
||
}
|
||
|
||
// 只映射主要的四种模式,其他状态返回 null
|
||
switch (stateCode) {
|
||
case 0:
|
||
return AirConditionerStatusEnum.IDLE.getCode();
|
||
case 1:
|
||
return AirConditionerStatusEnum.COOLING.getCode();
|
||
case 2:
|
||
return AirConditionerStatusEnum.HEATING.getCode();
|
||
case 3:
|
||
return AirConditionerStatusEnum.DEHUMIDIFYING.getCode();
|
||
default:
|
||
// 其他状态(准备模式、退出模式等)不映射
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 将舱门状态代码映射到 CabinDoorStatusEnum
|
||
* @param coverState 舱门状态代码(0-关闭,1-打开,2-半开,3-舱盖状态异常)
|
||
* @return 舱门状态枚举的 code
|
||
*/
|
||
private String mapCabinDoorState(Integer coverState) {
|
||
if (coverState == null) {
|
||
return null;
|
||
}
|
||
|
||
switch (coverState) {
|
||
case 0:
|
||
return CabinDoorStatusEnum.CLOSED.getCode();
|
||
case 1:
|
||
return CabinDoorStatusEnum.OPEN.getCode();
|
||
case 2:
|
||
return CabinDoorStatusEnum.HALF_OPEN.getCode();
|
||
case 3:
|
||
return CabinDoorStatusEnum.ABNORMAL.getCode();
|
||
default:
|
||
return null;
|
||
}
|
||
}
|
||
|
||
private AircraftDetailDTO getChangeAbleAirDetailDTO(String aircraftDeviceIotId, String dockDeviceIotId)
|
||
{
|
||
|
||
AircraftDetailDTO dto = new AircraftDetailDTO();
|
||
AttributeMap attributeMap = thingsBoardDomain.getPredefinedDeviceAttributes(aircraftDeviceIotId);
|
||
TelemetryMap telemetryMap = thingsBoardDomain.getPredefinedDeviceTelemetry(aircraftDeviceIotId);
|
||
|
||
|
||
// AttributeMap attributeDockMap = thingsBoardDomain.getPredefinedDeviceAttributes(dockDeviceIotId);
|
||
TelemetryMap telemetryDockMap = thingsBoardDomain.getPredefinedDeviceTelemetry(dockDeviceIotId);
|
||
|
||
//设置aircraftStatus
|
||
// drone_in_dock 表示是否在舱外
|
||
// device_online_status 表示是否开机
|
||
// 先判断机场的状态是否是
|
||
// 任务中 和 调试, 这两个状态用机场的, 暂时不要用离线状态
|
||
//
|
||
|
||
String aircraftStatus = determineAircraftStatus(attributeMap, telemetryMap,telemetryDockMap);
|
||
dto.setAircraftStatus(aircraftStatus);
|
||
|
||
// 从 TelemetryMap 中获取 total_flight_sorties 赋予 missionCount
|
||
telemetryMap.get(DeviceTelemetry.Total_Flight_Sorties)
|
||
.ifPresent(telemetryValue -> dto.setMissionCount(telemetryValue.getValue()));
|
||
|
||
// RTK 信号 - 从 position_state.rtk_number 获取 RTK 搜星数量
|
||
telemetryMap.get(DeviceTelemetry.Position_State_Rtk_Number)
|
||
.ifPresent(telemetryValue -> {
|
||
Integer rtkNumber = telemetryValue.getValue();
|
||
if (rtkNumber != null) {
|
||
dto.setRtkSignal(rtkNumber);
|
||
}
|
||
});
|
||
|
||
telemetryMap.get(DeviceTelemetry.Position_State_GPS_Number)
|
||
.ifPresent(telemetryValue -> {
|
||
Integer gpsNumber = telemetryValue.getValue();
|
||
if (gpsNumber != null) {
|
||
dto.setGpsSignal(gpsNumber);
|
||
}
|
||
});
|
||
|
||
// 限高
|
||
telemetryMap.get(DeviceTelemetry.Height_Limit)
|
||
.ifPresent(telemetryValue -> dto.setMaxAltitude(telemetryValue.getValue()));
|
||
|
||
// 限远
|
||
telemetryMap.get(DeviceTelemetry.Distance_Limit_Status_Distance_Limit)
|
||
.ifPresent(telemetryValue -> dto.setMaxDistance(telemetryValue.getValue()));
|
||
|
||
return dto;
|
||
}
|
||
|
||
/**
|
||
* 根据设备属性和遥测数据确定无人机状态
|
||
*
|
||
* @param attributeMap 无人机 属性映射
|
||
* @param telemetryMap 机场 遥测数据映射
|
||
* @return 无人机状态字符串
|
||
*/
|
||
private String determineAircraftStatus(AttributeMap attributeMap,TelemetryMap telemetryAirportMap,TelemetryMap telemetryMap) {
|
||
// 先检查 MODE_CODE,判断是否处于任务中或调试状态
|
||
// MODE_CODE 定义: {"0":"待机","1":"起飞准备","2":"起飞准备完毕","3":"手动飞行","4":"自动起飞",
|
||
// "5":"航线飞行","6":"全景拍照","7":"智能跟随","8":"ADS-B 躲避","9":"自动返航",
|
||
// "10":"自动降落","11":"强制降落","12":"三桨叶降落","13":"升级中","14":"未连接",
|
||
// "15":"APAS","16":"虚拟摇杆状态","17":"指令飞行","18":"空中 RTK 收敛模式",
|
||
// "19":"机场选址中","20":"POI环绕"}
|
||
Integer modeCode = attributeMap.get(DeviceAttributes.MODE_CODE).orElse(null);
|
||
|
||
if (modeCode != null) {
|
||
// 14 = 未连接,直接返回离线状态
|
||
if (modeCode == 14) {
|
||
return AircraftStatusEnum.OFFLINE.getCode();
|
||
}
|
||
|
||
// 判断是否在任务中 (飞行相关状态: 1-12, 15-20)
|
||
if (modeCode >= 1 && modeCode <= 12 || modeCode >= 15 && modeCode <= 20) {
|
||
return AircraftStatusEnum.IN_MISSION.getCode();
|
||
}
|
||
}
|
||
|
||
// {"0":"关闭","1":"打开","2":"半开","3":"舱盖状态异常"}
|
||
Integer cover_state = telemetryMap.get(DeviceTelemetry.Cover_State)
|
||
.map(telemetryValue -> telemetryValue.getValue())
|
||
.orElse(null);
|
||
|
||
Integer droneInDock = 1;
|
||
|
||
if (cover_state != null && cover_state == 0) {
|
||
droneInDock = 1;
|
||
}else {
|
||
droneInDock = 0;
|
||
}
|
||
|
||
// // 获取无人机是否在舱内: {"0":"舱外","1":"舱内"}
|
||
// Integer droneInDock = telemetryMap.get(DeviceTelemetry.Drone_In_Dock)
|
||
// .map(telemetryValue -> telemetryValue.getValue())
|
||
// .orElse(null);
|
||
|
||
// 从 telemetryAirportMap 中取 total_flight_time, 如果时间是在一分钟以内更新的,则为开机,否则为关机
|
||
|
||
// 获取无人机是否开机: {"0":"关机","1":"开机"}
|
||
Integer deviceOnlineStatus = telemetryMap.get(DeviceTelemetry.Sub_Device_Online_Status)
|
||
.map(telemetryValue -> telemetryValue.getValue())
|
||
.orElse(null);
|
||
|
||
// 根据舱内/舱外和开机/关机状态确定无人机状态
|
||
boolean isInCabin = droneInDock != null && droneInDock == 1;
|
||
boolean isPowerOn = deviceOnlineStatus != null && deviceOnlineStatus == 1;
|
||
|
||
if (isInCabin) {
|
||
// 舱内
|
||
if (isPowerOn) {
|
||
return AircraftStatusEnum.POWER_ON_IN_CABIN.getCode();
|
||
} else {
|
||
return AircraftStatusEnum.POWER_OFF_IN_CABIN.getCode();
|
||
}
|
||
} else {
|
||
// 舱外
|
||
if (isPowerOn) {
|
||
return AircraftStatusEnum.POWER_ON_OUT_CABIN.getCode();
|
||
} else {
|
||
return AircraftStatusEnum.POWER_OFF_OUT_CABIN.getCode();
|
||
}
|
||
}
|
||
}
|
||
|
||
@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;
|
||
}
|
||
|
||
}
|