远程调试
远程调试只对机场生效,远程调试可以分为命令(cmd)和任务(job),命令是机场能立即回复的行为,任务是需要持续动作的行为。
命令(cmd) | 任务(job) |
---|---|
调试模式开启/关闭 | 机场重启 |
补光灯开启/关闭 | 飞行器开机/关机 |
4G图传功能开启/关闭 | 一键起飞自检 |
一键返航 | 飞行器数据格式化 |
机场数据格式化 | |
打开/关闭舱盖 | |
推杆展开/闭合 | |
充电打开/关闭 |
*所有的调试都是通过访问 /devices/{sn}/jobs/{service_identifier} *
@Override
public HttpResultResponse controlDockDebug(String sn, RemoteDebugMethodEnum controlMethodEnum, RemoteDebugParam param) {
// 获取对应调试方法的枚举
DebugMethodEnum methodEnum = controlMethodEnum.getDebugMethodEnum();
// 检查执行该命令的条件
RemoteDebugHandler data = checkDebugCondition(sn, param, controlMethodEnum);
// 判断执行命令设备是否上线
boolean isExist = deviceRedisService.checkDeviceOnline(sn);
if (!isExist) {
return HttpResultResponse.error("The dock is offline.");
}
TopicServicesResponse response;
switch (controlMethodEnum) {
// 一键返航
case RETURN_HOME:
response = abstractWaylineService.returnHome(SDKManager.getDeviceSDK(sn));
break;
// 取消一键返航
case RETURN_HOME_CANCEL:
response = abstractWaylineService.returnHomeCancel(SDKManager.getDeviceSDK(sn));
break;
default:
// 其他命令根据不同的debugMethod 进行远程调用
response = abstractDebugService.remoteDebug(SDKManager.getDeviceSDK(sn), methodEnum,
Objects.nonNull(methodEnum.getClazz()) ? mapper.convertValue(data, methodEnum.getClazz()) : null);
}
ServicesReplyData serviceReply = (ServicesReplyData) response.getData();
if (!serviceReply.getResult().isSuccess()) {
return HttpResultResponse.error(serviceReply.getResult());
}
return HttpResultResponse.success();
}
public TopicServicesResponse<ServicesReplyData<RemoteDebugResponse>> remoteDebug(GatewayManager gateway, DebugMethodEnum methodEnum, BaseModel request) {
try {
List<Class> clazz = new ArrayList<>();
List<Object> args = new ArrayList<>();
clazz.add(GatewayManager.class);
args.add(gateway);
if (Objects.nonNull(request)) {
clazz.add(request.getClass());
args.add(request);
}
AbstractDebugService abstractDebugService = SpringBeanUtils.getBean(this.getClass());
// 根据方法名获取方法
Method method = abstractDebugService.getClass().getDeclaredMethod(Common.convertSnake(methodEnum.getMethod()), clazz.toArray(Class[]::new));
// abstractDebugService 执行对应方法
return (TopicServicesResponse<ServicesReplyData<RemoteDebugResponse>>) method.invoke(abstractDebugService, args.toArray());
} catch (NoSuchMethodException | IllegalAccessException e) {
throw new CloudSDKException(e);
} catch (InvocationTargetException e) {
throw new CloudSDKException(e.getTargetException());
}
}
任务类的进度上报
job类型的调试指令,如机场重启,机场会通过thing/product/{gateway_sn}/events主题持续上报云端,
最终路由会进入EventsRouter中
@Bean
public IntegrationFlow eventsMethodRouterFlow() {
return IntegrationFlows
.from(ChannelName.INBOUND_EVENTS)
.transform(Message.class, source -> {
try {
TopicEventsRequest data = Common.getObjectMapper().readValue((byte[]) source.getPayload(), TopicEventsRequest.class);
// 对应消息主题
String topic = String.valueOf(source.getHeaders().get(MqttHeaders.RECEIVED_TOPIC));
return data.setFrom(topic.substring((THING_MODEL_PRE + PRODUCT).length(), topic.indexOf(EVENTS_SUF)))
.setData(Common.getObjectMapper().convertValue(data.getData(), EventsMethodEnum.find(data.getMethod()).getClassType()));
} catch (IOException e) {
throw new CloudSDKException(e);
}
}, null)
.<TopicEventsRequest, EventsMethodEnum>route(
// 不同的命令走不同的通道
response -> EventsMethodEnum.find(response.getMethod()),
mapping -> Arrays.stream(EventsMethodEnum.values()).forEach(
methodEnum -> mapping.channelMapping(methodEnum, methodEnum.getChannelName())))
.get();
}
机场重启会进入ChannelName.INBOUND_EVENTS_CONTROL_PROGRESS中进行处理
@ServiceActivator(inputChannel = ChannelName.INBOUND_EVENTS_CONTROL_PROGRESS, outputChannel = ChannelName.OUTBOUND_EVENTS)
public TopicEventsResponse<MqttReply> remoteDebugProgress(TopicEventsRequest<EventsDataRequest<RemoteDebugProgress>> request, MessageHeaders headers) {
throw new UnsupportedOperationException("remoteDebugProgress not implemented");
}
@Override
public TopicEventsResponse<MqttReply> remoteDebugProgress(TopicEventsRequest<EventsDataRequest<RemoteDebugProgress>> request, MessageHeaders headers) {
// 获取网关
String sn = request.getGateway();
// 上报消息转换为另外一个实体
EventsReceiver<RemoteDebugProgress> eventsReceiver = new EventsReceiver<RemoteDebugProgress>()
.setOutput(request.getData().getOutput()).setResult(request.getData().getResult());
eventsReceiver.setBid(request.getBid());
eventsReceiver.setSn(sn);
log.info("SN: {}, {} ===> Control progress: {}", sn, request.getMethod(), eventsReceiver.getOutput().getProgress());
if (!eventsReceiver.getResult().isSuccess()) {
log.error("SN: {}, {} ===> Error: {}", sn, request.getMethod(), eventsReceiver.getResult());
}
// 设备当前是否在线
Optional<DeviceDTO> deviceOpt = deviceRedisService.getDeviceOnline(sn);
if (deviceOpt.isEmpty()) {
throw new RuntimeException("The device is offline.");
}
DeviceDTO device = deviceOpt.get();
// websocket 推送消息对应的任务进度
webSocketMessageService.sendBatch(device.getWorkspaceId(), UserTypeEnum.WEB.getVal(),
request.getMethod(), eventsReceiver);
return new TopicEventsResponse<MqttReply>().setData(MqttReply.success());
}