/*
|
* 【机场1】从 dock2 原类 com.ard.sample.manage.service.impl.DeviceOSDServiceImpl 复制/独立适配(DJI Dock 1 / M30)。
|
* 与 dock2 原类同服务共存;本文件内的适配差异以「// 机场1:」内联注释标出。
|
*/
|
package com.ard.sample.dock1.manage.service.impl;
|
|
import com.ard.common.core.redis.RedisConst;
|
import com.ard.common.core.redis.RedisOpsUtils;
|
import com.ard.sample.component.mqtt.model.CommonTopicReceiver;
|
|
import com.ard.sample.component.websocket.config.ConcurrentWebSocketSession;
|
import com.ard.sample.component.websocket.enums.MessageType;
|
import com.ard.sample.component.websocket.handler.DockWebSocketHandler;
|
import com.ard.sample.component.websocket.model.BizCodeEnum;
|
import com.ard.sample.component.websocket.model.CustomWebSocketMessage;
|
import com.ard.sample.manage.model.dto.DeviceDTO;
|
import com.ard.sample.manage.model.dto.TelemetryDTO;
|
import com.ard.sample.manage.model.dto.TelemetryDeviceDTO;
|
import com.ard.sample.manage.model.enums.DeviceDomainEnum;
|
import com.ard.sample.manage.model.receiver.OsdSubDeviceReceiver;
|
// 机场1:使用带 M30 专属字段的子类解析飞行器 OSD(仍兼容共享层类型)。
|
import com.ard.sample.dock1.manage.model.receiver.Dock1OsdSubDeviceReceiver;
|
import com.ard.sample.manage.service.IDeviceService;
|
// 机场1:轨迹缓存必须与共享任务进度(FlightTaskServiceImpl 的 type="1" 写入)使用同一个服务实例,
|
// 否则 type="0" 的轨迹点写进 dock1 独立缓存、而 type="1" 的任务状态写在共享缓存,两处永远无法配对。
|
// 这里复用共享层 IWaylineTrajectoryService,不修改共享层实现。
|
import com.ard.sample.manage.service.IWaylineTrajectoryService;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.stereotype.Service;
|
|
import java.util.Collection;
|
import com.ard.sample.manage.service.impl.AbstractTSAService;
|
import com.ard.sample.manage.service.impl.DeviceOSDServiceImpl;
|
|
/**
|
* @author sean
|
* @version 0.3
|
* @date 2022/2/21
|
*/
|
@Service
|
@Slf4j
|
public class Dock1DeviceOSDServiceImpl extends AbstractTSAService {
|
|
@Autowired
|
private IDeviceService _deviceService;
|
|
@Autowired
|
private IWaylineTrajectoryService _waylineTrajectoryService;
|
|
@Autowired
|
private DockWebSocketHandler _dockWebSocketHandler;
|
|
protected Dock1DeviceOSDServiceImpl(@Autowired @Qualifier("dock1DockOSDServiceImpl") AbstractTSAService tsaService) {
|
super(tsaService);
|
}
|
|
@Override
|
public void pushTelemetryData(Collection<ConcurrentWebSocketSession> sessions,
|
CustomWebSocketMessage<TelemetryDTO> message, Object osdData) {
|
if (osdData instanceof OsdSubDeviceReceiver) {
|
OsdSubDeviceReceiver data = (OsdSubDeviceReceiver) osdData;
|
TelemetryDTO telemetry = message.getData();
|
telemetry.setHost(TelemetryDeviceDTO.builder()
|
.latitude(data.getLatitude())
|
.longitude(data.getLongitude())
|
.altitude(data.getElevation())
|
.attitudeHead(data.getAttitudeHead())
|
.elevation(data.getElevation())
|
.horizontalSpeed(data.getHorizontalSpeed())
|
.verticalSpeed(data.getVerticalSpeed())
|
.build());
|
|
this.sendMessageService.sendBatch(sessions, message);
|
}
|
}
|
@Override
|
public void handleOSD(CommonTopicReceiver receiver, DeviceDTO device,
|
Collection<ConcurrentWebSocketSession> webSessions,
|
CustomWebSocketMessage<TelemetryDTO> wsMessage) {
|
if (DeviceDomainEnum.SUB_DEVICE.getVal() == device.getDomain()) {
|
wsMessage.setBizCode(BizCodeEnum.DEVICE_OSD.getCode());
|
|
// 机场1:M30/M30T 的 OSD 比共享类多 9 个字段,用 dock1 子类承接。
|
// 机场1:Dock1 的飞行器 OSD 中 payloads 本身就是数组,convertValue 已经完成解析;
|
// 共享层按 device.payloadsList(扁平 key)二次覆盖的逻辑不适用于 dock1,
|
// 且该列表当前恒为 null,会在每条 OSD 上触发 NPE 并打印误导性告警,故 dock1 链直接跳过。
|
// 容错:单个字段类型异常(如固件把 rid_state 上报成布尔)不应丢弃整帧 OSD,
|
// 解析失败时降级为共享接收器,保证状态、遥测、轨迹链路继续工作。
|
OsdSubDeviceReceiver data;
|
try {
|
data = mapper.convertValue(receiver.getData(), Dock1OsdSubDeviceReceiver.class);
|
} catch (IllegalArgumentException e) {
|
log.warn("机场1 飞行器 OSD 解析失败,降级为共享接收器:{}", e.getMessage());
|
data = mapper.convertValue(receiver.getData(), OsdSubDeviceReceiver.class);
|
}
|
//data.setChildDeviceSn(device.getDeviceSn());
|
String dockOsd = "";
|
receiver.setType(MessageType.STATUS.getType()+"-aircraft");
|
// receiver.setData(data);
|
try {
|
dockOsd=mapper.writeValueAsString(receiver);
|
JsonNode jsonNode = mapper.readTree(dockOsd);
|
//在JSON的data下插入childDeviceSn,飞行器的sn
|
if(jsonNode.get("data") instanceof ObjectNode){
|
ObjectNode objectNode = (ObjectNode) jsonNode.get("data");
|
objectNode.put("childDeviceSn", device.getDeviceSn());
|
}
|
if(jsonNode.has("data")){
|
|
if(jsonNode.get("data").has("mode_code")) {
|
Long code = jsonNode.get("data").get("mode_code").asLong();
|
if ("0,1,2,3,4,5,8,9,10,11,13,14".contains(code.toString())) {
|
_deviceService.updateWorkType(device.getDeviceSn(), code);
|
RedisOpsUtils.set(RedisConst.OSD_STATUS_PREFIX + device.getDeviceSn(), code);
|
}
|
}
|
}
|
dockOsd=mapper.writeValueAsString(jsonNode);
|
} catch (NullPointerException | JsonProcessingException e) {
|
log.warn("Please remount the payload, or restart the drone. Otherwise the data of the payload will not be received.");
|
}
|
|
RedisOpsUtils.setWithExpire(RedisConst.OSD_PREFIX + device.getDeviceSn(), data, RedisConst.DEVICE_ALIVE_SECOND);
|
wsMessage.getData().setHost(data);
|
|
// 发送给websocket客户端
|
_dockWebSocketHandler.sendMessageToSubscribers(device.getDeviceSn(), MessageType.STATUS.getType(), dockOsd, "");
|
|
// 将飞行器的OSD数据dockOsd入库;device.getDeviceSn()为飞行器sn,这里要机场的sn,试试receiver.getGateway();
|
_waylineTrajectoryService.setList(receiver.getGateway(),"0", dockOsd);
|
|
sendMessageService.sendBatch(webSessions, wsMessage);
|
this.pushTelemetryData(data, device.getDeviceSn());
|
}
|
tsaService.handleOSD(receiver, device, webSessions, wsMessage);
|
}
|
}
|