/* * 【机场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 sessions, CustomWebSocketMessage 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 webSessions, CustomWebSocketMessage 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); } }