Commit ba5b1b18 by gdj

增加自动断点续飞功能。

parent c95e40fd
......@@ -45,6 +45,10 @@ public final class RedisConst {
public static final String WAYLINE_JOB_PAUSED_PREFIX = "wayline_job_paused" + DELIMITER;
public static final String WAYLINE_JOB_BREAK_POINT_PREFIX = "wayline_job_break_point" + DELIMITER;
public static final Integer WAYLINE_JOB_BREAK_POINT_ALIVE_SECOND = 60 * 60 * 24;
public static final String OSD_PREFIX = "osd" + DELIMITER;
public static final String MEDIA_FILE_PREFIX = "media_file" + DELIMITER;
......
......@@ -89,4 +89,9 @@ public class WaylineJobDTO {
private String orgId;
/**
* 断点
*/
private FlighttaskBreakPoint breakPoint;
}
package com.dji.sample.wayline.model.param;
import com.dji.sdk.cloudapi.wayline.FlighttaskBreakPoint;
import lombok.Data;
/**
* @author guan
*/
@Data
public class BreakPointWaylineJobEvent {
private String taskId;
private FlighttaskBreakPoint breakPointInfo;
public BreakPointWaylineJobEvent(String taskId, FlighttaskBreakPoint breakPointInfo) {
this.taskId = taskId;
this.breakPointInfo = breakPointInfo;
}
}
package com.dji.sample.wayline.model.param;
import com.dji.sdk.cloudapi.wayline.FlighttaskBreakPoint;
import com.dji.sdk.cloudapi.wayline.OutOfControlActionEnum;
import com.dji.sdk.cloudapi.wayline.TaskTypeEnum;
import com.dji.sdk.cloudapi.wayline.WaylineTypeEnum;
......@@ -51,4 +52,14 @@ public class CreateJobParam {
private String orgId;
/**
* 断点
*/
private FlighttaskBreakPoint breakPoint;
/**
* 自动断点续飞 0 不续飞 1 续飞
*/
private Integer breakPointResumeFlight;
}
......@@ -6,6 +6,7 @@ import com.dji.sample.wayline.model.dto.WaylineJobDTO;
import com.dji.sample.wayline.model.param.CreateInFlightJobParam;
import com.dji.sample.wayline.model.param.CreateJobParam;
import com.dji.sample.wayline.model.param.UpdateJobParam;
import com.dji.sdk.cloudapi.wayline.FlighttaskBreakPoint;
import com.dji.sdk.common.HttpResultResponse;
import java.sql.SQLException;
......@@ -95,4 +96,6 @@ public interface IFlightTaskService {
void publishCancelInFlightTask(String workspaceId, String dockSn);
HttpResultResponse publishTimeFlightTask(String taskId, FlighttaskBreakPoint breakPoint);
}
......@@ -60,6 +60,8 @@ public interface IWaylineJobService extends IService<WaylineJobEntity> {
*/
Optional<WaylineJobDTO> getJobByJobId(String workspaceId, String jobId);
WaylineJobEntity getJobEntityByJobId(String jobId);
/**
* Update job data.
* @param dto
......
......@@ -97,4 +97,12 @@ public interface IWaylineRedisService {
Double getConditionalWaylineJobTime(ConditionalWaylineJobKey jobKey);
Boolean removePrepareConditionalWaylineJob(ConditionalWaylineJobKey jobKey);
// 增加 自动断点续飞
void setBreakPointWaylineJobDockSn(String jobId, String dockSn);
// 获取是否有断点续飞
String getBreakPointWaylineJobDockSn(String jobId);
// 删除 自动断点续飞
Boolean delBreakPointWaylineJobDockSn(String jobId);
}
......@@ -15,15 +15,14 @@ import com.dji.sample.media.service.IMediaRedisService;
import com.dji.sample.wayline.model.dto.ConditionalWaylineJobKey;
import com.dji.sample.wayline.model.dto.WaylineJobDTO;
import com.dji.sample.wayline.model.dto.WaylineTaskConditionDTO;
import com.dji.sample.wayline.model.entity.WaylineJobEntity;
import com.dji.sample.wayline.model.enums.WaylineErrorCodeEnum;
import com.dji.sample.wayline.model.enums.WaylineJobStatusEnum;
import com.dji.sample.wayline.model.param.BreakPointWaylineJobEvent;
import com.dji.sample.wayline.model.param.CreateInFlightJobParam;
import com.dji.sample.wayline.model.param.CreateJobParam;
import com.dji.sample.wayline.model.param.UpdateJobParam;
import com.dji.sample.wayline.service.IFlightTaskService;
import com.dji.sample.wayline.service.IWaylineFileService;
import com.dji.sample.wayline.service.IWaylineJobService;
import com.dji.sample.wayline.service.IWaylineRedisService;
import com.dji.sample.wayline.service.*;
import com.dji.sdk.cloudapi.device.*;
import com.dji.sdk.cloudapi.media.UploadFlighttaskMediaPrioritize;
import com.dji.sdk.cloudapi.media.api.AbstractMediaService;
......@@ -38,6 +37,7 @@ import com.dji.sdk.mqtt.events.TopicEventsResponse;
import com.dji.sdk.mqtt.services.ServicesReplyData;
import com.dji.sdk.mqtt.services.TopicServicesResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpStatus;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -47,12 +47,15 @@ import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.context.event.EventListener;
import java.net.URL;
import java.sql.SQLException;
import java.time.*;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
......@@ -252,6 +255,12 @@ public class FlightTaskServiceImpl extends AbstractWaylineService implements IFl
throw new SQLException("Failed to create wayline job.");
}
WaylineJobDTO waylineJob = waylineJobOpt.get();
/**
* 起始飞行断点
*/
if (param.getBreakPoint() != null) {
waylineJob.setBreakPoint(param.getBreakPoint());
}
// If it is a conditional task type, add conditions to the job parameters.
addConditions(waylineJob, param, beginTime, endTime);
......@@ -264,6 +273,90 @@ public class FlightTaskServiceImpl extends AbstractWaylineService implements IFl
return HttpResultResponse.success();
}
@SneakyThrows
@EventListener
public HttpResultResponse publishTimeFlightTask(BreakPointWaylineJobEvent event) {
String taskId = event.getTaskId();
FlighttaskBreakPoint breakPoint = event.getBreakPointInfo();
return this.publishTimeFlightTask(taskId, breakPoint);
}
@SneakyThrows
@Override
public HttpResultResponse publishTimeFlightTask(String taskId, FlighttaskBreakPoint breakPoint) {
// 查询任务详情
WaylineJobEntity jobEntity = waylineJobService.getJobEntityByJobId(taskId);
// token
CustomClaim customClaim = new CustomClaim();
customClaim.setWorkspaceId(jobEntity.getWorkspaceId());
customClaim.setUsername(jobEntity.getUsername());
customClaim.setOrgId(jobEntity.getOrgId());
// 创建 开始和结束时间是 20-40分钟 电量90 条件任务
CreateJobParam param = new CreateJobParam();
// 任务信息
param.setOrgId(jobEntity.getOrgId());
String breakPointTaskName = getBreakPointTaskName(jobEntity.getName());
param.setName(breakPointTaskName);
param.setFileId(jobEntity.getFileId());
param.setDockSn(jobEntity.getDockSn());
param.setWaylineType(WaylineTypeEnum.find(jobEntity.getWaylineType()));
param.setRthAltitude(jobEntity.getRthAltitude());
param.setOutOfControlAction(OutOfControlActionEnum.find(jobEntity.getOutOfControlAction()));
// 断点
param.setBreakPoint(breakPoint);
// 条件信息
param.setTaskType(TaskTypeEnum.CONDITIONAL);
param.setMinBatteryCapacity(90);
ZoneId zone = ZoneId.systemDefault();
// 当前时间加20分钟
ZonedDateTime now = ZonedDateTime.now(zone);
ZonedDateTime plus30Min = now.plusMinutes(20);
long timestampPlus30Min = plus30Min.toInstant().getEpochSecond();
// 20分钟之后当天0点(如果跨天就是第二天0点)
LocalDateTime targetDate = plus30Min.toLocalDate().atStartOfDay();
long timestampMidnight = targetDate.atZone(zone).toInstant().getEpochSecond();
List<Long> taskDays = new ArrayList<>();
taskDays.add(timestampMidnight);
param.setTaskDays(taskDays);
List<List<Long>> taskPeriods = new ArrayList<>();
List<Long> tempPeriod = new ArrayList<>();
tempPeriod.add(timestampPlus30Min);
// 结束时间 再加20分钟
tempPeriod.add(timestampPlus30Min + 20 * 60);
taskPeriods.add(tempPeriod);
param.setTaskPeriods(taskPeriods);
// 自动断点续飞
param.setBreakPointResumeFlight(1);
// minStorageCapacity 存储容量
return this.publishFlightTask(param, customClaim);
}
public static String getBreakPointTaskName(String name) {
if (name == null || name.isEmpty()) {
return name;
}
// 设置 断点续飞任务名称规则 -x
Pattern pattern = Pattern.compile("^(.*?)-(\\d+)$");
Matcher matcher = pattern.matcher(name);
if (matcher.matches()) {
String prefix = matcher.group(1);
int num = Integer.parseInt(matcher.group(2));
return prefix + "-" + (num + 1);
} else {
return name + "-1";
}
}
public HttpResultResponse publishOneFlightTask(WaylineJobDTO waylineJob) throws SQLException {
boolean isOnline = deviceRedisService.checkDeviceOnline(waylineJob.getDockSn());
......@@ -346,6 +439,10 @@ public class FlightTaskServiceImpl extends AbstractWaylineService implements IFl
if (waylineJob.getSimulateMission() != null) {
flightTask.setSimulateMission(waylineJob.getSimulateMission());
}
// 设置航线任务断点
if (waylineJob.getBreakPoint() != null) {
flightTask.setBreakPoint(waylineJob.getBreakPoint());
}
if (TaskTypeEnum.CONDITIONAL == waylineJob.getTaskType()) {
if (Objects.isNull(waylineJob.getConditions())) {
......
......@@ -11,9 +11,8 @@ import com.dji.sample.media.model.MediaFileCountDTO;
import com.dji.sample.media.service.IMediaRedisService;
import com.dji.sample.wayline.model.dto.WaylineJobDTO;
import com.dji.sample.wayline.model.enums.WaylineJobStatusEnum;
import com.dji.sample.wayline.service.IWaylineFileService;
import com.dji.sample.wayline.service.IWaylineJobService;
import com.dji.sample.wayline.service.IWaylineRedisService;
import com.dji.sample.wayline.model.param.BreakPointWaylineJobEvent;
import com.dji.sample.wayline.service.*;
import com.dji.sdk.cloudapi.wayline.*;
import com.dji.sdk.cloudapi.wayline.api.AbstractWaylineService;
import com.dji.sdk.mqtt.MqttReply;
......@@ -22,12 +21,15 @@ import com.dji.sdk.mqtt.events.TopicEventsRequest;
import com.dji.sdk.mqtt.events.TopicEventsResponse;
import com.dji.sdk.mqtt.requests.TopicRequestsRequest;
import com.dji.sdk.mqtt.requests.TopicRequestsResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.messaging.MessageHeaders;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import java.net.URL;
import java.sql.SQLException;
......@@ -62,6 +64,12 @@ public class SDKWaylineService extends AbstractWaylineService {
@Autowired
private IWaylineFileService waylineFileService;
@Autowired
private ApplicationEventPublisher eventPublisher;
@Autowired
private ObjectMapper mapper;
@Override
public TopicEventsResponse<MqttReply> deviceExitHomingNotify(TopicEventsRequest<DeviceExitHomingNotify> request, MessageHeaders headers) {
return super.deviceExitHomingNotify(request, headers);
......@@ -81,6 +89,29 @@ public class SDKWaylineService extends AbstractWaylineService {
log.error("Task progress ===> Error: " + eventsReceiver.getResult());
}
// 单独记录 任务的状态
// 如果是没电或者其他情况 任务中止 处理任务状态
// 记录断点信息 中断
ProgressExtBreakPoint breakPoint = output.getExt().getBreakPoint();
if (breakPoint != null) {
FlighttaskBreakReasonEnum breakReason = breakPoint.getBreakReason();
// 判断当前是否自动断点续传任务
String taskId = response.getBid();
String dockSn = waylineRedisService.getBreakPointWaylineJobDockSn(taskId);
if (StringUtils.hasText(dockSn)) {
// 转换断点
FlighttaskBreakPoint breakPointInfo = mapper.convertValue(breakPoint, FlighttaskBreakPoint.class);
// 假如断点是 低电量
if (breakReason == FlighttaskBreakReasonEnum.LOW_BATTERY_RTH) {
// 删除redis记录
waylineRedisService.delBreakPointWaylineJobDockSn(taskId);
// 自动创建一个30分钟之后的任务
eventPublisher.publishEvent(new BreakPointWaylineJobEvent(taskId, breakPointInfo));
}
}
}
Optional<DeviceDTO> deviceOpt = deviceRedisService.getDeviceOnline(response.getGateway());
if (deviceOpt.isEmpty()) {
return new TopicEventsResponse<>();
......
......@@ -129,6 +129,11 @@ public class WaylineJobServiceImpl extends ServiceImpl<IWaylineJobMapper, Waylin
.mediaCount(0)
.build();
// 断点续飞存redis
if (param.getBreakPointResumeFlight() != null && param.getBreakPointResumeFlight() == 1) {
waylineRedisService.setBreakPointWaylineJobDockSn(jobId, param.getDockSn());
}
return insertWaylineJob(jobEntity);
}
......@@ -184,6 +189,14 @@ public class WaylineJobServiceImpl extends ServiceImpl<IWaylineJobMapper, Waylin
}
@Override
public WaylineJobEntity getJobEntityByJobId(String jobId) {
WaylineJobEntity jobEntity = mapper.selectOne(
new LambdaQueryWrapper<WaylineJobEntity>()
.eq(WaylineJobEntity::getJobId, jobId));
return jobEntity;
}
@Override
public Boolean updateJob(WaylineJobDTO dto) {
return mapper.update(this.dto2Entity(dto),
new LambdaUpdateWrapper<WaylineJobEntity>()
......
......@@ -109,4 +109,22 @@ public class WaylineRedisServiceImpl implements IWaylineRedisService {
public Boolean removePrepareConditionalWaylineJob(ConditionalWaylineJobKey jobKey) {
return RedisOpsUtils.zRemove(RedisConst.WAYLINE_JOB_CONDITION_PREPARE, jobKey.getKey());
}
// 增加 自动断点续飞
@Override
public void setBreakPointWaylineJobDockSn(String jobId, String dockSn) {
RedisOpsUtils.setWithExpire(RedisConst.WAYLINE_JOB_BREAK_POINT_PREFIX + jobId, dockSn, RedisConst.WAYLINE_JOB_BREAK_POINT_ALIVE_SECOND);
}
// 获取是否有断点续飞
@Override
public String getBreakPointWaylineJobDockSn(String jobId) {
return (String) RedisOpsUtils.get(RedisConst.WAYLINE_JOB_BREAK_POINT_PREFIX + jobId);
}
// 删除 自动断点续飞
@Override
public Boolean delBreakPointWaylineJobDockSn(String jobId) {
return RedisOpsUtils.del(RedisConst.WAYLINE_JOB_BREAK_POINT_PREFIX + jobId);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment