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

424 lines
16 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 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.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());
/**
* 设置作业架次
*/
dto.setMissionCount(aircraftDetailDTO.getMissionCount());
}
return dto;
}
@Override
public AircraftDetailDTO getAircraftDetailById(Long aircraftId) {
return null;
}
private DockDetailDTO getChangeAbleDockDetailDTO(String dockerDeviceIotId)
{
DockDetailDTO dto = new DockDetailDTO();
AttributeMap attributeMap = thingsBoardDomain.getPredefinedDeviceAttributes(dockerDeviceIotId);
TelemetryMap telemetryMap = thingsBoardDomain.getPredefinedDeviceTelemetry(dockerDeviceIotId);
// 根据 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);
}
});
// 设置环境数据
// 风速(单位:米每秒)
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-4G2-以太网)
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()));
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-4G2-以太网)
* @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;
}
}
/**
* 将空调状态代码映射到 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 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);
// 从 TelemetryMap 中获取 total_flight_sorties 赋予 missionCount
telemetryMap.get(DeviceTelemetry.Total_Flight_Sorties)
.ifPresent(telemetryValue -> dto.setMissionCount(telemetryValue.getValue()));
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();
}
}
}
}