Commit ca064c78 by 真的三个金鑫

UOM 上报

parent 4223c03b
......@@ -37,6 +37,14 @@
</dependencyManagement>
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.35</version>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
......
package com.dji.sample.manage.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.RandomUtil;
import com.dji.sample.component.websocket.model.BizCodeEnum;
import com.dji.sample.component.websocket.service.IWebSocketMessageService;
import com.dji.sample.manage.model.dto.DeviceDTO;
......@@ -10,6 +13,8 @@ import com.dji.sample.manage.service.IDeviceDictionaryService;
import com.dji.sample.manage.service.IDevicePayloadService;
import com.dji.sample.manage.service.IDeviceRedisService;
import com.dji.sample.manage.service.IDeviceService;
import com.dji.sample.uom.UOMDroneFlightRecordDTO;
import com.dji.sample.uom.UOMRecordService;
import com.dji.sdk.cloudapi.device.*;
import com.dji.sdk.cloudapi.device.api.AbstractDeviceService;
import com.dji.sdk.cloudapi.tsa.DeviceIconUrl;
......@@ -27,7 +32,9 @@ import org.springframework.messaging.MessageHeaders;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
......@@ -56,6 +63,8 @@ public class SDKDeviceService extends AbstractDeviceService {
@Autowired
private IDevicePayloadService devicePayloadService;
@Autowired
private UOMRecordService uomRecordService;
@Override
public TopicStatusResponse<MqttReply> updateTopoOnline(TopicStatusRequest<UpdateTopo> request, MessageHeaders headers) {
......@@ -177,7 +186,56 @@ public class SDKDeviceService extends AbstractDeviceService {
DeviceDTO device = deviceOpt.get();
deviceRedisService.setDeviceOnline(device);
deviceRedisService.setDeviceOsd(from, request.getData());
new Thread(() -> {
try {
UOMDroneFlightRecordDTO uomDroneFlightRecordDTO = new UOMDroneFlightRecordDTO();
// Set basic information
uomDroneFlightRecordDTO.setOrderID(String.format("%s-%s-%s",
device.getDeviceSn(),
DateUtil.format(new Date(), "yyyyMMdd"),
RandomUtil.randomString(8)));
uomDroneFlightRecordDTO.setSn(device.getDeviceSn());
uomDroneFlightRecordDTO.setFlightStatus("Land");
uomDroneFlightRecordDTO.setManufacturerID("914403007954257495");
uomDroneFlightRecordDTO.setUasID("UAS-DEFAULT");
// Set timestamp
uomDroneFlightRecordDTO.setTimeStamp(
DateUtil.format(DateUtil.date(request.getTimestamp()), "yyyyMMddHHmmss"));
// Set device model
uomDroneFlightRecordDTO.setUasModel(device.getType().name());
// Set coordinates
uomDroneFlightRecordDTO.setCoordinate(1);
uomDroneFlightRecordDTO.setLongitude(
(long) (NumberUtil.round(request.getData().getLongitude(), 7, RoundingMode.DOWN).doubleValue() * 10000000));
uomDroneFlightRecordDTO.setLatitude(
(long) (NumberUtil.round(request.getData().getLatitude(), 7, RoundingMode.DOWN).doubleValue() * 10000000));
// Set altitude and height
uomDroneFlightRecordDTO.setHeightType(1);
uomDroneFlightRecordDTO.setHeight(
(int) (NumberUtil.round(request.getData().getElevation(), 1, RoundingMode.DOWN).doubleValue() * 10));
uomDroneFlightRecordDTO.setAltitude(
(int) (request.getData().getHeight().doubleValue() * 10));
// Set speed values
uomDroneFlightRecordDTO.setVS(
(int) (NumberUtil.round(request.getData().getVerticalSpeed(), 1, RoundingMode.DOWN).doubleValue() * 10));
uomDroneFlightRecordDTO.setGS(
(int) (NumberUtil.round(request.getData().getHorizontalSpeed(), 1, RoundingMode.DOWN).doubleValue() * 10));
// Set course
uomDroneFlightRecordDTO.setCourse(-999);
// Send record
uomRecordService.sendRecord(uomDroneFlightRecordDTO);
} catch (Exception e) {
log.error("Error while sending drone flight record", e);
}
}).start();
deviceService.pushOsdDataToWeb(device.getWorkspaceId(), BizCodeEnum.DEVICE_OSD, from, request.getData());
}
......
package com.dji.sample.uom;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
public class SM3Util {
private static final String ENCODING = "UTF-8";
/**
* 加密
*
* @param src 明文
* @param key 密钥
* @return
* @throws Exception
*/
public static String encrypt(String src, String key) throws Exception {
return ByteUtils.toHexString(getEncryptByKey(src, key));
}
/**
* SM3加密方式之: 根据自定义密钥进行加密,返回加密后长度为32位的16进制字符串
*
* @param src 源数据
* @param key 密钥
* @return
* @throws Exception
*/
public static byte[] getEncryptByKey(String src, String key) throws Exception {
byte[] srcByte = src.getBytes(ENCODING);
byte[] keyByte = key.getBytes(ENCODING);
KeyParameter keyParameter = new KeyParameter(keyByte);
SM3Digest sm3 = new SM3Digest();
HMac hMac = new HMac(sm3);
hMac.init(keyParameter);
hMac.update(srcByte, 0, srcByte.length);
byte[] result = new byte[hMac.getMacSize()];
hMac.doFinal(result, 0);
return result;
}
}
package com.dji.sample.uom;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class SendUOMDTO {
private String appID;
private List<UOMDroneFlightRecordDTO> paths = new ArrayList<>();
}
package com.dji.sample.uom;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@ConfigurationProperties(prefix = "uom")
@Component
@Data
public class UOMConfiguration {
private Integer source;
private String platform;
private String programVersion;
private String url;
private String appID;
private String appKey;
}
package com.dji.sample.uom;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 无人机飞行数据记录实体
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class UOMDroneFlightRecordDTO {
/**
* 飞行记录编号
* 格式:厂商SN(8位)-起飞日期(YYYYMMDD)-8位随机码
* 示例:1581F5FHD25G100C1SDN-20240320-owvGyLqe
*
* <p>
* 厂商的无人机生产序列号(sn)-8位起飞日期(YYYYMMDD)-8位随机码(数字或字母均可)
* 如:1581F5FHD25G100C1SDN-20240320-owvGyLqe
* </p>
*/
private String orderID;
/**
* 无人机序列号(生产序列号)
*
* <p>
* 厂商的无人机生产序列号
* </p>
*/
private String sn;
/**
* 飞行状态
* TakeOff:起飞轨迹点
* Inflight:飞行中轨迹点
* Land:降落轨迹点
*
* <p>
* TakeOff:代表当前架次飞行的首个轨迹点
* Inflight:代表当前架次飞行中除首尾以外的其它轨迹点
* Land:代表当前架次飞行的最后一个轨迹点
* </p>
*/
private String flightStatus;
/**
* 厂商统一社会信用代码
*
* <p>
* 生产厂商的统一社会信用代码
* </p>
*/
private String manufacturerID;
/**
* 无人驾驶航空器实名登记号
* 默认值:"UAS-DEFAULT"
*
* <p>
* 若无登记号,推送默认值
* “UAS-DEFAULT"
* </p>
*/
private String uasID;
/**
* 当前时间(yyyyMMddHHmmss格式)
* 示例:20240124095001
*
* <p>
* 格式"yyyyMMddHHmmss",例:20240124095001
* </p>
*/
private String timeStamp;
/**
* 产品型号(字母/数字/符号组合)
*
* <p>
* 字母、数字与符号的组合
* </p>
*/
private String uasModel;
/**
* 坐标系类型
* 1: WGS-84
* 2: CGCS2000
* 3: GLONASS-PZ90
*
* <p>
* 1:代表WGS-84
* 2:代表CGCS2000
* 3:代表GLONASS-PZ90
* </p>
*/
private Integer coordinate;
/**
* 经度(单位:度)
* 传输值=实际值×10^7
*
* <p>
* 单位:度(°)
* 精确到小数点后7位,乘10的7次方后传输
* </p>
*/
private Long longitude;
/**
* 纬度(单位:度)
* 传输值=实际值×10^7
*
* <p>
* 单位:度(°)
* 精确到小数点后7位,乘10的7次方后传输
* </p>
*/
private Long latitude;
/**
* 真高类型
* 1: 相对于起飞点
* 2: 相对于当前位置
*
* <p>
* 1.相对于起飞点的真高
* 2.相对于当前位置的真高
* </p>
*/
private Integer heightType;
/**
* 真高(单位:米)
* 传输值=实际值×10
*
* <p>
* 单位:米(m)
* 精确到小数点后1位,乘10以后传输
* </p>
*/
private Integer height;
/**
* 海拔高度(单位:米)
* 传输值=实际值×10
*
* <p>
* 单位:米(m)
* 精确到小数点后1位,乘10以后传输
* </p>
*/
private Integer altitude;
/**
* 垂直飞行速度(m/s)
* 传输值=实际值×10
* <p>
* 单位:米每秒(m/s)
* 精确到小数点后1位,乘10后传输
* </p>
*/
private Integer VS;
/**
* 水平飞行速度(m/s)
* 传输值=实际值×10
*
* <p>
* 单位:米每秒(m/s)
* 精确到小数点后1位,乘10后传输
* </p>
*/
private Integer GS;
/**
* 航迹角(0-360度)
* 默认值:-999(不具备测算能力时)
* 传输值=实际值×10
*
* <p>
* 无人驾驶航空器当前时刻所在位置真北方向顺时针量至地速方向的夹角,范围(0度,360度]。
* 暂不具备航迹角测算能力的型号产品,应报送默认值“-999”精确到小数点后1位,乘10后传输
* </p>
*/
private Integer course;
}
\ No newline at end of file
package com.dji.sample.uom;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UOMRecordService {
@Autowired
private UOMConfiguration uomConfiguration;
/*
* {
"appID":"104807e9161a4804b35d",
"paths":[
{
"orderID":"ZTU25VA2204FSUHXT-20240204-17070329",
"sn":"ZTU25VA2204FSUHXT",
"flightStatus":"Land",
"manufacturerID":"91310106575864243X",
"uasID":"xxxxxxx",
"timeStamp":"20240124095001",
"uasModel":"ZT-25",
"coordinate":1,
"longitude":1154458272,
"latitude":401929176,
"heightType":1,
"height":130,
"altitude":130,
"VS":30,
"GS":118,
"course":680,
}
]
}
* */
public String sendRecord(UOMDroneFlightRecordDTO uomDroneFlightRecordDTO) throws Exception {
HttpRequest post = HttpUtil.createPost(uomConfiguration.getUrl());
post.header("source", String.valueOf(uomConfiguration.getSource()));
post.header("platform", uomConfiguration.getPlatform());
post.header("programVersion", uomConfiguration.getProgramVersion());
SendUOMDTO sendUOMDTO = new SendUOMDTO();
sendUOMDTO.setAppID(uomConfiguration.getAppID());
List<UOMDroneFlightRecordDTO> paths = sendUOMDTO.getPaths();
paths.add(uomDroneFlightRecordDTO);
sendUOMDTO.setPaths(paths);
String encrypt = SM3Util.encrypt(JSONUtil.toJsonStr(sendUOMDTO), uomConfiguration.getAppKey());
post.body(encrypt);
return post.execute().body();
}
}
......@@ -174,4 +174,22 @@ livestream:
# Webrtc: Only supports using whip standard
whip:
url: Please enter the rtmp access address. # Example:http://192.168.1.1:1985/rtc/v1/whip/?app=live&stream=
\ No newline at end of file
url: Please enter the rtmp access address. # Example:http://192.168.1.1:1985/rtc/v1/whip/?app=live&stream=
uom:
# 数据源 Integer
# 1:无人机系统直报的数据
# 2:无人机制造商自建的无人机运行服务系统代报的数据
# 3:无人机机体上加装的单独数据模块代报的数据
# 4:采集设备采集代报的广播数据
source: 2
# 识别信息报送平台
# 报送平台的名称,如“DJI FLY”
platform: "GEO FLY"
# 报送程序版本
# 程序版本号,以第一次完成报送对接记为“version1.0”,每次升级报送程序累加版本号后缀
programVersion: "version1.0"
# 上报平台 API 地址 https://uom.receive.caacic.cn/addFlightRoute
url: https://218.189.32.212:8080/addFlightRoute
appID: GEOSYS
appKey: geosys_uas
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