package com.ard.tianyu.service.impl; import com.ard.tianyu.config.TyConfiguration; import com.ard.tianyu.http.TyClient; import com.ard.tianyu.model.cache.UavSignalInfoCache; import com.ard.tianyu.model.cache.UavStateCache; import com.ard.tianyu.model.cache.UavTelemetryDataCache; import com.ard.tianyu.model.dto.BoxHistoryDTO; import com.ard.tianyu.model.dto.BoxPhotosDTO; import com.ard.tianyu.model.dto.BoxSettingsDTO; import com.ard.tianyu.model.dto.camera.CapturePicDto; import com.ard.tianyu.model.dto.camera.RecordDto; import com.ard.tianyu.model.dto.control.AbsAngleControlDto; import com.ard.tianyu.model.dto.control.AngleControlDto; import com.ard.tianyu.model.dto.control.SpeedControlDto; import com.ard.tianyu.model.dto.converter.UavSignalInfoConverter; import com.ard.tianyu.model.dto.converter.UavStateConverter; import com.ard.tianyu.model.dto.converter.UavTelemetryDataConverter; import com.ard.tianyu.model.dto.signal.SignalInfo; import com.ard.tianyu.model.dto.state.UavState; import com.ard.tianyu.model.dto.telemetry.TelemetryData; import com.ard.tianyu.model.receiver.*; import com.ard.tianyu.netty.command.*; import com.ard.tianyu.netty.TyNettyTcpClient; import com.ard.tianyu.netty.command.camera.*; import com.ard.tianyu.netty.command.control.AbsAngleControlCommand; import com.ard.tianyu.netty.command.control.AngleControlCommand; import com.ard.tianyu.netty.command.control.SpeedControlCommand; import com.ard.tianyu.netty.command.real.SignalInfoCommand; import com.ard.tianyu.netty.command.real.UavStateCommand; import com.ard.tianyu.netty.command.real.UavTelemetryDataCommand; import com.ard.tianyu.netty.command.register.*; import com.ard.tianyu.service.ITyService; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import lombok.extern.slf4j.Slf4j; import org.apache.poi.hssf.record.Record; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.List; /** * TyServiceImpl * * @author liusuyi * @date 2024年10月22日8:37 **/ @Slf4j @Service public class TyServiceImpl implements ITyService { @Resource private TyClient tyClient; @Resource private TyConfiguration tyConfiguration; /** * 获取天宇token信息 * * @return AccessTokenReceiver */ @Override public AccessTokenReceiver getAccessToken() { return tyConfiguration.getAccessToken(); } /** * 获取云盒列表 * * @return List */ @Override public List getBoxList() { //请求云盒列表 try { TyHttpCommonReceiver> boxListReveiver = tyClient.getBoxList(tyConfiguration.getAccessToken().convertFromDTO()); return boxListReveiver.getContent(); } catch (Exception e) { log.error("获取云盒列表失败:{}", e.getMessage()); return new ArrayList<>(); } } /** * 获取直播地址 * * @return BoxStreamUrlReceiver */ @Override public BoxStreamUrlReceiver getBoxLiveUrl(String boxSn) { TyHttpCommonReceiver boxLiveUrl = tyClient.getBoxLiveUrl(boxSn, tyConfiguration.getAccessToken().convertFromDTO()); return boxLiveUrl.getContent(); } /** * 获取飞行历史 * * @return List */ @Override public List getBoxHistory(BoxHistoryDTO boxHistoryDTO) { TyHttpCommonReceiver> boxHistory = tyClient.getBoxHistory(boxHistoryDTO, tyConfiguration.getAccessToken().convertFromDTO()); return boxHistory.getContent(); } /** * 获取盒子图片 * * @return List */ @Override public List getBoxPhotos(BoxPhotosDTO boxPhotosDTO) { TyHttpCommonReceiver> boxPhotos = tyClient.getBoxPhotos(boxPhotosDTO, tyConfiguration.getAccessToken().convertFromDTO()); return boxPhotos.getContent(); } /** * 修改云盒设置 */ @Override public Boolean updateBoxSettings(BoxSettingsDTO boxSettingsDTO) { TyHttpCommonReceiver result = tyClient.updateBoxSettings(boxSettingsDTO, tyConfiguration.getAccessToken().convertFromDTO()); return result.getState() == 1; } /** * 注册天宇平台 */ @Override public void registerMessage() { AccessTokenReceiver tyToken = tyConfiguration.getAccessToken(); RegisterCommand registerMessage = new RegisterCommand(tyToken.getCompanyId(), tyToken.getAccessToken().getBytes()); this.sendMessage(tyConfiguration.getIpPort(), registerMessage); } /** * 发送消息 */ public void sendMessage(String key, BaseCommand msg) { try { ChannelFuture future = TyNettyTcpClient.channels.get(key).getChannelFuture(); Channel channel = future.channel(); if (channel.isActive()) { InetSocketAddress ipSocket = (InetSocketAddress) channel.remoteAddress(); String host = ipSocket.getHostString(); int port = ipSocket.getPort(); channel.writeAndFlush(msg); // 发送编码后的数据 log.debug("向天宇服务器【{}:{}】发送数据,命令码:{}", host, port, String.format("0x%02X", msg.getCmdCode() & 0xFF)); } else { log.error("与天宇服务器链接断开,无法发送数据!"); } } catch (Exception e) { log.error("发送消息异常:{}", e.getMessage()); } } /** * 云台控制基于角度 */ @Override public void angleControl(AngleControlDto angleControlDto) { AngleControlCommand controlAngleCommand = new AngleControlCommand(angleControlDto); this.sendMessage(tyConfiguration.getIpPort(), controlAngleCommand); } /** * 云台绝对值控制(基于角度) */ @Override public void absAngleControl(AbsAngleControlDto absAngleControlDto) { AbsAngleControlCommand absAngleControlCommand = new AbsAngleControlCommand(absAngleControlDto); this.sendMessage(tyConfiguration.getIpPort(), absAngleControlCommand); } /** * 云台转动(基于速度) */ @Override public void speedControl(SpeedControlDto speedControlDto) { SpeedControlCommand speedControlCommand = new SpeedControlCommand(speedControlDto); this.sendMessage(tyConfiguration.getIpPort(), speedControlCommand); } /** * 拍照 */ @Override public void capturePic(CapturePicDto capturePicDto) { CapturePicCommand capturePicCommand = new CapturePicCommand(capturePicDto); this.sendMessage(tyConfiguration.getIpPort(), capturePicCommand); } /** * 录像 */ @Override public void record(RecordDto recordDto) { BaseCommand baseCommand; if (recordDto.getIsRecord()) { baseCommand = new RecordStartCommand(recordDto); } else { baseCommand = new RecordStopCommand(recordDto); } this.sendMessage(tyConfiguration.getIpPort(), baseCommand); } /** * 获取无人机状态 */ @Override public UavState getUavState(String boxSn) { return UavStateCache.getUavState(boxSn); } /** * 获取无人机遥测数据 */ @Override public TelemetryData getUavTelemetryData(String boxSn) { return UavTelemetryDataCache.getUavTelemetryData(boxSn); } /** * 获取无人机遥测数据 */ @Override public SignalInfo getSignalInfo(String boxSn) { return UavSignalInfoCache.getUavSignalInfo(boxSn); } @Override public void processMessage(String key, BaseCommand tyCommand) { byte cmdCode = tyCommand.getCmdCode(); switch (cmdCode) { case 0x01: // 处理心跳消息 RegisterReplyCommand registerReplyCommand = (RegisterReplyCommand) tyCommand; log.info("收到注册消息-->处理注册消息{}", registerReplyCommand.getSuccess()); if (registerReplyCommand.getSuccess() != 1) { // 注册失败,重新注册 log.info("注册失败,重新注册"); registerMessage(); } break; case 0x02: // 处理注册消息 HeartbeatReplyCommand heartbeatReplyCommand = (HeartbeatReplyCommand) tyCommand; log.debug("收到心跳消息-->处理心跳消息{}", heartbeatReplyCommand.getTimestamp()); break; case 0x03: // 处理订阅消息 break; case 0x04: // 处理取消订阅消息 break; case (byte) 0xA8: // 处理无人机状态消息 log.debug("收到无人机状态消息-->无人机状态消息"); UavStateCommand uavStateCommand = (UavStateCommand) tyCommand; UavState uavState = UavStateConverter.convertProtoToEntity(uavStateCommand.getUavState()); UavStateCache.putUavState(uavState); break; case (byte) 0xA9: // 处理无人机遥测消息 log.debug("收到无人机遥测消息-->无人机遥测消息"); UavTelemetryDataCommand uavTelemetryDataCommand = (UavTelemetryDataCommand) tyCommand; TelemetryData telemetryData = UavTelemetryDataConverter.convertProtoToEntity(uavTelemetryDataCommand.getTelemetryData()); UavTelemetryDataCache.putUavTelemetryData(telemetryData); break; case (byte) 0x0C: // 处理无人机信道质量数据 log.debug("收到无人机信道质量数据消息-->无人机信道质量数据消息"); SignalInfoCommand signalInfoCommand = (SignalInfoCommand) tyCommand; SignalInfo signalInfo = UavSignalInfoConverter.convertProtoToEntity(signalInfoCommand.getSignalInfo()); UavSignalInfoCache.putUavSignalInfoCache(signalInfo); break; case (byte) 0xD1: // 处理无人机 if (tyCommand instanceof UavReadyNotificationCommand) { UavReadyNotificationCommand droneReadyNotificationCommand = (UavReadyNotificationCommand) tyCommand; if (droneReadyNotificationCommand.getActionCode() == (byte) 0x42) { UavInitInfoCommand uavInitCommand = new UavInitInfoCommand(droneReadyNotificationCommand.getBoxSn()); this.sendMessage(tyConfiguration.getIpPort(), uavInitCommand); log.info("收到无人机初始化详情-回复防止再次发送"); } } if (tyCommand instanceof CapturePicReplyCommand) { CapturePicReplyCommand capturePicReplyCommand = (CapturePicReplyCommand) tyCommand; if (capturePicReplyCommand.getActionCode() == (byte) 0x23) { log.info("收到无人机拍照回复:{} 错误码:{}", String.format("0x%02X", capturePicReplyCommand.getResult() & 0xFF), capturePicReplyCommand.getErrorCode()); } } if (tyCommand instanceof RecordStartReplyCommand) { RecordStartReplyCommand recordStartReplyCommand = (RecordStartReplyCommand) tyCommand; if (recordStartReplyCommand.getActionCode() == (byte) 0x24) { log.info("收到无人机开始录像回复:{} 错误码:{}", String.format("0x%02X", recordStartReplyCommand.getResult() & 0xFF), recordStartReplyCommand.getErrorCode()); } } if (tyCommand instanceof RecordStopReplyCommand) { RecordStopReplyCommand recordStopReplyCommand = (RecordStopReplyCommand) tyCommand; if (recordStopReplyCommand.getActionCode() == (byte) 0x25) { log.info("收到无人机停止录像回复:{} 错误码:{}", String.format("0x%02X", recordStopReplyCommand.getResult() & 0xFF), recordStopReplyCommand.getErrorCode()); } } break; default: // 处理其他消息 log.debug("收到其他消息-->其他消息"); } } @Scheduled(fixedRate = 3000) public void sendHeartBeat() { long timestamp = System.currentTimeMillis(); log.debug("定时向天宇发送⼼跳,时间戳{}", timestamp); HeartbeatCommand heartbeatMessage = new HeartbeatCommand(timestamp); this.sendMessage(tyConfiguration.getIpPort(), heartbeatMessage); } }