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

278 lines
10 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.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();
}
}
}
}