package com.dji.sample.control.service.impl;
|
|
import com.dji.sample.component.mqtt.config.MqttPropertyConfiguration;
|
import com.dji.sample.component.mqtt.model.EventsReceiver;
|
import com.dji.sample.component.mqtt.model.MapKeyConst;
|
import com.dji.sample.component.redis.RedisConst;
|
import com.dji.sample.component.redis.RedisOpsUtils;
|
import com.dji.sample.component.websocket.service.IWebSocketMessageService;
|
import com.dji.sample.control.model.dto.JwtAclDTO;
|
import com.dji.sample.control.model.enums.DroneAuthorityEnum;
|
import com.dji.sample.control.model.enums.MqttAclAccessEnum;
|
import com.dji.sample.control.model.param.DrcConnectParam;
|
import com.dji.sample.control.model.param.DrcModeParam;
|
import com.dji.sample.control.model.param.DroneControlParam;
|
import com.dji.sample.control.model.param.HeartBeatParam;
|
import com.dji.sample.control.service.IControlService;
|
import com.dji.sample.control.service.IDrcService;
|
import com.dji.sample.manage.model.dto.DeviceDTO;
|
import com.dji.sample.manage.service.IDeviceRedisService;
|
import com.dji.sample.manage.service.IDeviceService;
|
import com.dji.sample.wayline.model.enums.WaylineJobStatusEnum;
|
import com.dji.sample.wayline.model.enums.WaylineTaskStatusEnum;
|
import com.dji.sample.wayline.model.param.UpdateJobParam;
|
import com.dji.sample.wayline.service.IFlightTaskService;
|
import com.dji.sample.wayline.service.IWaylineJobService;
|
import com.dji.sample.wayline.service.IWaylineRedisService;
|
import com.dji.sdk.cloudapi.control.*;
|
import com.dji.sdk.cloudapi.control.api.AbstractControlService;
|
import com.dji.sdk.cloudapi.device.DockModeCodeEnum;
|
import com.dji.sdk.cloudapi.device.OsdDockDrone;
|
import com.dji.sdk.cloudapi.wayline.FlighttaskProgress;
|
import com.dji.sdk.common.HttpResultResponse;
|
import com.dji.sdk.common.SDKManager;
|
import com.dji.sdk.mqtt.TopicConst;
|
import com.dji.sdk.mqtt.services.ServicesReplyData;
|
import com.dji.sdk.mqtt.services.TopicServicesResponse;
|
import com.fasterxml.jackson.core.type.TypeReference;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Service;
|
import org.springframework.util.StringUtils;
|
|
import java.util.Collections;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Optional;
|
|
/**
|
* @author sean
|
* @version 1.3
|
* @date 2023/1/11
|
*/
|
@Service
|
@Slf4j
|
public class DrcServiceImpl implements IDrcService {
|
|
@Autowired
|
private ObjectMapper objectMapper;
|
|
@Autowired
|
private IWaylineJobService waylineJobService;
|
|
@Autowired
|
private IFlightTaskService flighttaskService;
|
|
@Autowired
|
private IDeviceService deviceService;
|
|
@Autowired
|
private ObjectMapper mapper;
|
|
@Autowired
|
private IWebSocketMessageService webSocketMessageService;
|
|
@Autowired
|
private IControlService controlService;
|
|
@Autowired
|
private IDeviceRedisService deviceRedisService;
|
|
@Autowired
|
private IWaylineRedisService waylineRedisService;
|
|
@Autowired
|
private AbstractControlService abstractControlService;
|
|
@Override
|
public void setDrcModeInRedis(String dockSn, String clientId) {
|
RedisOpsUtils.setWithExpire(RedisConst.DRC_PREFIX + dockSn, clientId, RedisConst.DRC_MODE_ALIVE_SECOND);
|
}
|
|
@Override
|
public String getDrcModeInRedis(String dockSn) {
|
return (String) RedisOpsUtils.get(RedisConst.DRC_PREFIX + dockSn);
|
}
|
|
@Override
|
public Boolean delDrcModeInRedis(String dockSn) {
|
return RedisOpsUtils.del(RedisConst.DRC_PREFIX + dockSn);
|
}
|
|
@Override
|
public DrcModeMqttBroker userDrcAuth(String workspaceId, String userId, String username, DrcConnectParam param) {
|
|
// refresh token
|
String clientId = param.getClientId();
|
// first time
|
if (!StringUtils.hasText(clientId) || !RedisOpsUtils.checkExist(RedisConst.MQTT_ACL_PREFIX + clientId)) {
|
clientId = userId + "-" + System.currentTimeMillis();
|
RedisOpsUtils.hashSet(RedisConst.MQTT_ACL_PREFIX + clientId, "", MqttAclAccessEnum.ALL.getValue());
|
}
|
|
String key = RedisConst.MQTT_ACL_PREFIX + clientId;
|
|
try {
|
RedisOpsUtils.expireKey(key, RedisConst.DRC_MODE_ALIVE_SECOND);
|
|
return MqttPropertyConfiguration.getMqttBrokerWithDrc(
|
clientId, username, param.getExpireSec(), Collections.emptyMap());
|
} catch (RuntimeException e) {
|
RedisOpsUtils.del(key);
|
throw e;
|
}
|
}
|
|
private void checkDrcModeCondition(String workspaceId, String dockSn) {
|
Optional<EventsReceiver<FlighttaskProgress>> runningOpt = waylineRedisService.getRunningWaylineJob(dockSn);
|
if (runningOpt.isPresent() && WaylineJobStatusEnum.IN_PROGRESS == waylineJobService.getWaylineState(dockSn)) {
|
flighttaskService.updateJobStatus(workspaceId, runningOpt.get().getBid(),
|
UpdateJobParam.builder().status(WaylineTaskStatusEnum.PAUSE).build());
|
}
|
|
DockModeCodeEnum dockMode = deviceService.getDockMode(dockSn);
|
Optional<DeviceDTO> dockOpt = deviceRedisService.getDeviceOnline(dockSn);
|
if (dockOpt.isPresent() && (DockModeCodeEnum.IDLE == dockMode || DockModeCodeEnum.WORKING == dockMode)) {
|
Optional<OsdDockDrone> deviceOsd = deviceRedisService.getDeviceOsd(dockOpt.get().getChildDeviceSn(), OsdDockDrone.class);
|
if (deviceOsd.isEmpty() || deviceOsd.get().getElevation() <= 0) {
|
throw new RuntimeException("The drone is not in the sky and cannot enter command flight mode.");
|
}
|
} else {
|
throw new RuntimeException("The current state of the dock does not support entering command flight mode.");
|
}
|
|
HttpResultResponse result = controlService.seizeAuthority(dockSn, DroneAuthorityEnum.FLIGHT, null);
|
if (HttpResultResponse.CODE_SUCCESS != result.getCode()) {
|
throw new IllegalArgumentException(result.getMessage());
|
}
|
|
}
|
|
@Override
|
public JwtAclDTO deviceDrcEnter(DrcModeParam param) {
|
String topic = TopicConst.THING_MODEL_PRE + TopicConst.PRODUCT + param.getDockSn() + TopicConst.DRC;
|
String pubTopic = topic + TopicConst.DOWN;
|
String subTopic = topic + TopicConst.UP;
|
|
|
TopicServicesResponse<ServicesReplyData> reply = abstractControlService.drcModeEnter(
|
SDKManager.getDeviceSDK(param.getDockSn()),
|
new DrcModeEnterRequest()
|
.setMqttBroker(MqttPropertyConfiguration.getMqttBrokerWithDrc(param.getDockSn() + "-" + System.currentTimeMillis(),
|
// RedisConst.DRC_MODE_ALIVE_SECOND.longValue()))
|
param.getExpireSec()))
|
.setHsiFrequency(param.getDeviceInfo().getHsiFrequency()).setOsdFrequency(param.getDeviceInfo().getOsdFrequency()));
|
|
if (!reply.getData().getResult().isSuccess()) {
|
throw new RuntimeException("SN: " + param.getDockSn() + "; Error:" + reply.getData().getResult() +
|
"; Failed to enter command flight control mode, please try again later!");
|
}
|
|
// refreshAcl(param.getDockSn(), param.getClientId(), pubTopic, subTopic);
|
return JwtAclDTO.builder().sub(List.of(subTopic)).pub(List.of(pubTopic)).build();
|
}
|
|
private void refreshAcl(String dockSn, String clientId, String pubTopic, String subTopic) {
|
this.setDrcModeInRedis(dockSn, clientId);
|
|
// assign acl,Match by clientId. https://www.emqx.io/docs/zh/v4.4/advanced/acl-redis.html
|
// scheme: HSET mqtt_acl:[clientid] [topic] [access]
|
String key = RedisConst.MQTT_ACL_PREFIX + clientId;
|
RedisOpsUtils.hashSet(key, pubTopic, MqttAclAccessEnum.PUB.getValue());
|
RedisOpsUtils.hashSet(key, subTopic, MqttAclAccessEnum.SUB.getValue());
|
RedisOpsUtils.expireKey(key, RedisConst.DRC_MODE_ALIVE_SECOND);
|
}
|
|
@Override
|
public void deviceDrcExit( DrcModeParam param) {
|
// if (!deviceService.checkDockDrcMode(param.getDockSn())) {
|
// throw new RuntimeException("The dock is not in flight control mode.");
|
// }
|
TopicServicesResponse<ServicesReplyData> reply =
|
abstractControlService.drcModeExit(SDKManager.getDeviceSDK(param.getDockSn()));
|
if (!reply.getData().getResult().isSuccess()) {
|
throw new RuntimeException("SN: " + param.getDockSn() + "; Error:" +
|
reply.getData().getResult() + "; Failed to exit command flight control mode, please try again later!");
|
}
|
|
}
|
|
@Override
|
public void droneControl(String sn, DroneControlParam param) {
|
abstractControlService.droneControlDown( SDKManager.getDeviceSDK(sn),
|
mapper.convertValue(param, DroneControlRequest.class));
|
}
|
|
@Override
|
public void droneEmergencyStop(String sn) {
|
abstractControlService.droneEmergencyStopDown( SDKManager.getDeviceSDK(sn));
|
}
|
|
@Override
|
public void heartBeat(String sn, HeartBeatParam param) {
|
abstractControlService.heartBeatDown( SDKManager.getDeviceSDK(sn),
|
mapper.convertValue(param, HeartBeatRequest.class));
|
}
|
|
}
|