278 lines
10 KiB
Java
278 lines
10 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.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 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.List;
|
||
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;
|
||
|
||
@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());
|
||
/**
|
||
* 设置无人机状态
|
||
*/
|
||
dto.setAircraftStatus(aircraftDetailDTO.getAircraftStatus());
|
||
|
||
}
|
||
|
||
|
||
|
||
return dto;
|
||
|
||
|
||
}
|
||
|
||
@Override
|
||
public AircraftDetailDTO getAircraftDetailById(Long aircraftId) {
|
||
return null;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
private DockDetailDTO getChangeAbleDockDetailDTO(String deviceIotId)
|
||
{
|
||
DockDetailDTO dto = new DockDetailDTO();
|
||
AttributeMap attributeMap = thingsBoardDomain.getPredefinedDeviceAttributes(deviceIotId);
|
||
TelemetryMap telemetryMap = thingsBoardDomain.getPredefinedDeviceTelemetry(deviceIotId);
|
||
|
||
// 根据 MODE_CODE 设置机场状态
|
||
// MODE_CODE 定义: {"0":"空闲中","1":"现场调试","2":"远程调试","3":"固件升级中","4":"作业中","5":"待标定"}
|
||
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);
|
||
}
|
||
});
|
||
|
||
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();
|
||
}
|
||
}
|
||
|
||
private AircraftDetailDTO getChangeAbleAirDetailDTO(String deviceIotId)
|
||
{
|
||
|
||
AircraftDetailDTO dto = new AircraftDetailDTO();
|
||
AttributeMap attributeMap = thingsBoardDomain.getPredefinedDeviceAttributes(deviceIotId);
|
||
TelemetryMap telemetryMap = thingsBoardDomain.getPredefinedDeviceTelemetry(deviceIotId);
|
||
|
||
//设置aircraftStatus
|
||
// drone_in_dock 表示是否在舱外
|
||
// device_online_status 表示是否开机
|
||
// 先判断机场的状态是否是
|
||
// 任务中 和 调试, 这两个状态用机场的, 暂时不要用离线状态
|
||
//
|
||
|
||
String aircraftStatus = determineAircraftStatus(attributeMap, telemetryMap);
|
||
dto.setAircraftStatus(aircraftStatus);
|
||
|
||
|
||
|
||
return dto;
|
||
}
|
||
|
||
/**
|
||
* 根据设备属性和遥测数据确定无人机状态
|
||
*
|
||
* @param attributeMap 设备属性映射
|
||
* @param telemetryMap 设备遥测数据映射
|
||
* @return 无人机状态字符串
|
||
*/
|
||
private String determineAircraftStatus(AttributeMap attributeMap, 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":"舱内"}
|
||
Integer droneInDock = telemetryMap.get(DeviceTelemetry.Drone_In_Dock)
|
||
.map(telemetryValue -> telemetryValue.getValue())
|
||
.orElse(null);
|
||
|
||
// 获取无人机是否开机: {"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();
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|