From fea15e6708926d0a1444297d76f6e01c7e18d20a Mon Sep 17 00:00:00 2001 From: weidong Date: Fri, 22 Dec 2023 16:12:38 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E8=87=AA=E5=8A=A8=E8=A1=A5=E4=BC=A0?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- readme | 20 ++++++ .../imdroid/secapi/client/BeidouClient.java | 30 ++++++++- .../com/imdroid/secapi/dto/GnssStatus.java | 1 + .../sideslope/calc/GNSSCalcService.java | 44 ------------- .../calc/MultiLineGNSSCalcService.java | 42 +++++++++++- .../calc/SingleLineGNSSCalcService.java | 4 +- .../D31xConfigAckMessageExecutor.java | 2 +- .../D3F0SelfCheckMessageExecutor.java | 15 ++++- .../D3F2StopIndicationMessageExecutor.java | 17 +++-- .../sideslope/service/DataPersistService.java | 5 +- .../service/DataPersistServiceImpl.java | 14 +++- .../beidou/controller/APIController.java | 64 +++++++++++++++++-- .../resources/templates/page/gnss_status.html | 2 + 13 files changed, 191 insertions(+), 69 deletions(-) create mode 100644 readme delete mode 100644 sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/calc/GNSSCalcService.java diff --git a/readme b/readme new file mode 100644 index 00000000..2016ac55 --- /dev/null +++ b/readme @@ -0,0 +1,20 @@ +2023-12 +核心功能:基站转发、测站解算、结果推送、断点续传 +待实现和优化的功能: +1、自动断点续传: +1)增加一个断点续传任务表。当设备上线时检查上次的状态,如果是掉线,则向设备发补传数据指令,并添加一条新的断点续传任务,包括设备号、时间段 +2)收到最后一条补传消息,则将任务设置为已完成 + +2、推送任务: +1)按项目号、推送参数ID将在线设备信息打包成若干个List +2)根据推送参数ID生成相应的推送对象,含协议、地址、端口、推送格式,传入设备List +3)推送对象推送设备最近的解算记录 + +3、私有化部署UI优化: +1)首页:显示地图和在线/掉线/告警统计,告警信息实时滚动 +2)告警:告警信息、告警设置 +3)设备状态:温湿度、延迟仅开发者可见 +3)配置:组参数配置、解算参数(仅开发者可见)、推送参数、设备参数(可导出excel表)、命令行(仅开发者可见) +4)设备消息(仅开发者可见) +5)数据分析:解算结果,可导出excel表 +6)用户设置:用户名、手机号、权限(管理员、普通),内置开发者用户。管理员可以增删改查,普通用户只能查 diff --git a/sec-api/src/main/java/com/imdroid/secapi/client/BeidouClient.java b/sec-api/src/main/java/com/imdroid/secapi/client/BeidouClient.java index f9b4985b..6d471b3f 100644 --- a/sec-api/src/main/java/com/imdroid/secapi/client/BeidouClient.java +++ b/sec-api/src/main/java/com/imdroid/secapi/client/BeidouClient.java @@ -4,15 +4,39 @@ import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; +import java.time.LocalDateTime; + @FeignClient(name="BeidouClient",url = "http://localhost:9901/api") public interface BeidouClient { @PostMapping("/config_ack") - String onConfigAck(@RequestParam(name = "deviceId") String deviceId, @RequestParam(name = "configAck") String configAck); + String onConfigAck(@RequestParam(name = "deviceId") String deviceId, + @RequestParam(name = "tenantId") Integer tenantId, + @RequestParam(name = "configAck") String configAck); + + @PostMapping("/device_online") + String onLine(@RequestParam(name = "deviceId") String deviceId, + @RequestParam(name = "tenantId") Integer tenantId, + @RequestParam(name = "lastOnlineTime") LocalDateTime lastOnlineTime); @PostMapping("/device_active") - String onDeviceActive(@RequestParam(name = "deviceId") String deviceId); + String onDeviceActive(@RequestParam(name = "deviceId") String deviceId, + @RequestParam(name = "tenantId") Integer tenantId); @PostMapping("/device_stop") - String onDeviceStop(@RequestParam(name = "deviceId") String deviceId); + String onDeviceStop(@RequestParam(name = "deviceId") String deviceId, + @RequestParam(name = "tenantId") Integer tenantId); + + @PostMapping("/gnss_upload") + String onGnssUpload(@RequestParam(name = "deviceId") String deviceId, + @RequestParam(name = "tenantId") Integer tenantId, + @RequestParam(name = "uploadTime") LocalDateTime uploadTime); + + @PostMapping("/gnss_upload_pause") + String onGnssUploadPause(@RequestParam(name = "deviceId") String deviceId, + @RequestParam(name = "tenantId") Integer tenantId); + + @PostMapping("/gnss_upload_complete") + String onGnssUploadComplete(@RequestParam(name = "deviceId") String deviceId, + @RequestParam(name = "tenantId") Integer tenantId); } diff --git a/sec-api/src/main/java/com/imdroid/secapi/dto/GnssStatus.java b/sec-api/src/main/java/com/imdroid/secapi/dto/GnssStatus.java index 9a0af313..baa50b8a 100644 --- a/sec-api/src/main/java/com/imdroid/secapi/dto/GnssStatus.java +++ b/sec-api/src/main/java/com/imdroid/secapi/dto/GnssStatus.java @@ -19,6 +19,7 @@ public class GnssStatus { public static final short STATE_OFFLINE = 0; public static final short STATE_ACTIVE = 1; public static final short STATE_IDLE = 2; + public static final short STATE_UPLOADING = 3; @TableId(value = "id", type = IdType.AUTO) Long id; diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/calc/GNSSCalcService.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/calc/GNSSCalcService.java deleted file mode 100644 index 8ed29b02..00000000 --- a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/calc/GNSSCalcService.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.imdroid.sideslope.calc; - -import com.imdroid.sideslope.bd.Tilt; -import com.imdroid.sideslope.message.D341LocationMessage; - -import java.time.LocalDateTime; - -/** - * @author Layton - * @date 2023/2/4 19:18 - */ -public interface GNSSCalcService { - - /** - * 计算单条GNSS数据 - * - * @param message GNSS数据 - * @param completeWhenIdle 是否根据空闲时间判断本轮结束 - * @return x,y,z三轴数据 - */ - double[] calcSingle(D341LocationMessage message, boolean completeWhenIdle); - - /** - * 单轮解算结束,计算平滑值 - */ - void calSingleDone(String deviceId, Integer tenantId, LocalDateTime resultTime); - - /** - * 根据GNSS数据的中间结果,计算出最终结果 - * - * @param deviceId 设备id - * @return x,y,z三轴数据 - */ - //double[] calcResult(String deviceId,double[] b562Xyz, double[] tiltXyz); - - /** - * 根据GNSS数据的中间结果,计算Tilt的平均值 - * @param deviceId 设备id - * @return Tilt - */ - Tilt calcAvgTilt(String deviceId); - - //void cleanTiltByDeviceId(String deviceId); -} diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/calc/MultiLineGNSSCalcService.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/calc/MultiLineGNSSCalcService.java index 394434f9..fd16913d 100644 --- a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/calc/MultiLineGNSSCalcService.java +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/calc/MultiLineGNSSCalcService.java @@ -1,10 +1,13 @@ package com.imdroid.sideslope.calc; +import com.imdroid.secapi.client.BeidouClient; import com.imdroid.secapi.dto.FwdRecord; import com.imdroid.secapi.dto.FwdRecordMapper; +import com.imdroid.secapi.dto.GnssStatus; import com.imdroid.sideslope.message.BaseMessage; import com.imdroid.sideslope.message.D341LocationMessage; import com.imdroid.sideslope.message.D342LocationMessage; +import com.imdroid.sideslope.service.DataPersistService; import com.imdroid.sideslope.service.GNSSDeviceLocationRecordService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,11 +27,15 @@ public class MultiLineGNSSCalcService { @Autowired SingleLineGNSSCalcService calcService; @Autowired - private GNSSDeviceLocationRecordService dataPersistService; + private GNSSDeviceLocationRecordService locationPersistService; @Autowired GNSSCalcFilterService gnssCalcFilterService; @Autowired private FwdRecordMapper fwdRecordMapper; + @Autowired + private BeidouClient beidouClient; + @Autowired + DataPersistService dataPersistService; public void calc(D342LocationMessage d342Message){ // 如果时间跨度大于1分钟,或者不含d341,则计算平滑值 @@ -41,6 +48,14 @@ public class MultiLineGNSSCalcService { // 如果序号为0,则创建一条转发记录表 if(d342Message.getSeq() == 0 && d342Message.getProjectId()!=null){ createFwdReord(d342Message); + // 产生继续补传通知 + beidouClient.onGnssUpload(deviceId,d342Message.getTenantId(), msgTime); + GnssStatus gnssStatus = dataPersistService.getDeviceState(deviceId); + if(gnssStatus!=null){ + gnssStatus.setUpdatetime(LocalDateTime.now()); + gnssStatus.setState(GnssStatus.STATE_UPLOADING); + dataPersistService.updateDeviceState(gnssStatus); + } } if(lastDate != null){ @@ -63,12 +78,25 @@ public class MultiLineGNSSCalcService { calcService.calSingleDone(deviceId, d342Message.getTenantId(),lastDate); } } - deviceMap.put(deviceId, msgTime); + // 处理每个B562 for(BaseMessage message: d342Message.getMessageList()){ D341LocationMessage d341Message = (D341LocationMessage)message; calcService.calcSingle(d341Message, false); - dataPersistService.saveRawData(d341Message); + locationPersistService.saveRawData(d341Message); + } + + // 记录最新补传数据的时间 + if(d341Count>0) deviceMap.put(deviceId, msgTime); + else{ + // 补传完成 + deviceMap.remove(deviceId); + beidouClient.onGnssUploadComplete(deviceId,d342Message.getTenantId()); + GnssStatus gnssStatus = dataPersistService.getDeviceState(deviceId); + if(gnssStatus!=null){ + gnssStatus.setState(GnssStatus.STATE_IDLE); + dataPersistService.updateDeviceState(gnssStatus); + } } } @@ -85,4 +113,12 @@ public class MultiLineGNSSCalcService { fwdRecord.setDevicenum((short) 1); fwdRecordMap.put(deviceId, fwdRecord); } + + /** + * 周期结束通知 + * @param deviceId 设备id + */ + public LocalDateTime getUploadTime(String deviceId){ + return deviceMap.get(deviceId); + } } diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/calc/SingleLineGNSSCalcService.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/calc/SingleLineGNSSCalcService.java index 708ab4b1..c4ad4cc1 100644 --- a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/calc/SingleLineGNSSCalcService.java +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/calc/SingleLineGNSSCalcService.java @@ -3,19 +3,16 @@ package com.imdroid.sideslope.calc; import com.imdroid.secapi.dto.GnssCalcData; import com.imdroid.sideslope.bd.*; import com.imdroid.sideslope.message.D341LocationMessage; -import com.imdroid.sideslope.sal.*; import com.imdroid.sideslope.service.WarningService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import javax.annotation.Resource; import java.time.LocalDateTime; import java.util.Arrays; import java.util.Map; import java.util.concurrent.*; - /** * @author Layton * @date 2023/2/4 19:22 @@ -76,6 +73,7 @@ public class SingleLineGNSSCalcService implements GNSSCalcService { @Override public void calSingleDone(String deviceId, Integer tenantId, LocalDateTime resultTime) { FocusCalculator1 focusCalculator = calculatorMap.get(deviceId); + if(focusCalculator == null) return; // 1.检查b562有效数,如果过少,产生告警 warningService.checkB562Num(deviceId, tenantId, focusCalculator.getB562Stat()); diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/executor/D31xConfigAckMessageExecutor.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/executor/D31xConfigAckMessageExecutor.java index 0c3fb6f6..89ab97b9 100644 --- a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/executor/D31xConfigAckMessageExecutor.java +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/executor/D31xConfigAckMessageExecutor.java @@ -28,7 +28,7 @@ public class D31xConfigAckMessageExecutor implements Executor { + GnssStatus lastGnssStatus = dataPersistService.getDeviceState(message.getId()); + if(lastGnssStatus!=null && lastGnssStatus.getState() == GnssStatus.STATE_OFFLINE){ + beidouClient.onLine(lastGnssStatus.getDeviceid(), lastGnssStatus.getTenantid(), lastGnssStatus.getUpdatetime()); + } + else{ + // 通知beidou服务设备上线 + beidouClient.onDeviceActive(message.getId(), device.getTenantId()); + } dataPersistService.saveDeviceState(message); }); - // 通知beidou服务设备上线 - beidouClient.onDeviceActive(message.getId()); - // 存储最新设备状态信息到数据库中 + + return null; } + @Override public Class getMessageType() { return D3F0SelfCheckMessage.class; diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/executor/D3F2StopIndicationMessageExecutor.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/executor/D3F2StopIndicationMessageExecutor.java index dd3c440d..1151a682 100644 --- a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/executor/D3F2StopIndicationMessageExecutor.java +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/executor/D3F2StopIndicationMessageExecutor.java @@ -1,6 +1,7 @@ package com.imdroid.sideslope.executor; import com.imdroid.secapi.client.BeidouClient; +import com.imdroid.sideslope.calc.MultiLineGNSSCalcService; import com.imdroid.sideslope.message.D3F2StopIndicationMessage; import com.imdroid.sideslope.sal.Device; import com.imdroid.sideslope.sal.DeviceService; @@ -10,6 +11,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.annotation.Resource; +import java.time.LocalDateTime; /** * 停止指示消息处理器 @@ -26,22 +28,29 @@ public class D3F2StopIndicationMessageExecutor implements Executor { - dataPersistService.saveDeviceTrxStat(message); + dataPersistService.saveDeviceTrxStat(message, (uploadTime!=null)); }); // 通知beidou服务设备休眠 - beidouClient.onDeviceStop(message.getId()); - + beidouClient.onDeviceStop(deviceId,device.getTenantId()); + if(uploadTime!=null){ + beidouClient.onGnssUpload(deviceId,device.getTenantId(),uploadTime); + } return null; } diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/DataPersistService.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/DataPersistService.java index b8869ef7..96b2e39e 100644 --- a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/DataPersistService.java +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/DataPersistService.java @@ -1,5 +1,6 @@ package com.imdroid.sideslope.service; +import com.imdroid.secapi.dto.GnssStatus; import com.imdroid.sideslope.message.D3F0SelfCheckMessage; import com.imdroid.sideslope.message.D3F2StopIndicationMessage; @@ -13,8 +14,10 @@ import com.imdroid.sideslope.message.D3F2StopIndicationMessage; */ public interface DataPersistService { + GnssStatus getDeviceState(String deviceId); + void updateDeviceState(GnssStatus gnssStatus); void saveDeviceState(D3F0SelfCheckMessage d3F0SelfCheckMessage); - void saveDeviceTrxStat(D3F2StopIndicationMessage d3F2StopIndicationMessage); + void saveDeviceTrxStat(D3F2StopIndicationMessage d3F2StopIndicationMessage,boolean isUploading); } diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/DataPersistServiceImpl.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/DataPersistServiceImpl.java index 94779961..4e68b593 100644 --- a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/DataPersistServiceImpl.java +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/DataPersistServiceImpl.java @@ -28,6 +28,16 @@ public class DataPersistServiceImpl implements DataPersistService { @Autowired WarningService warningService; + @Override + public GnssStatus getDeviceState(String deviceId) + { + return deviceStateRepository.getByDeviceId(deviceId); + } + + @Override + public void updateDeviceState(GnssStatus gnssStatus){ + deviceStateRepository.updateById(gnssStatus); + } @Override public void saveDeviceState(D3F0SelfCheckMessage message) { try { @@ -72,7 +82,7 @@ public class DataPersistServiceImpl implements DataPersistService { } @Override - public void saveDeviceTrxStat(D3F2StopIndicationMessage message) { + public void saveDeviceTrxStat(D3F2StopIndicationMessage message, boolean isUploading) { try { // 添加到trxmsg里 GnssTrxMsg trxMsg = message.getTrxMsg(); @@ -90,7 +100,7 @@ public class DataPersistServiceImpl implements DataPersistService { deviceState.setRxbytes(rxbytes); deviceState.setD3xxbytes(d3xxbytes); deviceState.setB562bytes(b562bytes);*/ - deviceState.setState(GnssStatus.STATE_IDLE); + deviceState.setState(isUploading?GnssStatus.STATE_UPLOADING:GnssStatus.STATE_IDLE); deviceStateRepository.updateById(deviceState); } } catch (Exception e) { diff --git a/sec-beidou/src/main/java/com/imdroid/beidou/controller/APIController.java b/sec-beidou/src/main/java/com/imdroid/beidou/controller/APIController.java index d1ff9844..5b9c42ce 100644 --- a/sec-beidou/src/main/java/com/imdroid/beidou/controller/APIController.java +++ b/sec-beidou/src/main/java/com/imdroid/beidou/controller/APIController.java @@ -22,11 +22,13 @@ public class APIController extends BasicController{ GnssGroupMapper groupMapper; @Autowired GnssMsgMapper msgMapper; + @Autowired + GnssStatusMapper gnssStatusMapper; /****** config ack *******/ @PostMapping(value = "/api/config_ack") @ResponseBody - public String onConfigAck(String deviceId, String configAck) { + public String onConfigAck(String deviceId, Integer tenantId, String configAck) { GnssDevice device = deviceMapper.queryByDeviceId(deviceId); if(device == null) return null; @@ -41,7 +43,7 @@ public class APIController extends BasicController{ } // 保存 - saveMsg(deviceId, device.getTenantid(),msgType, configAck); + saveMsg(deviceId, tenantId,msgType, configAck); // 命令行显示 String rxInfo = "RX "+ dateFormat.format(System.currentTimeMillis())+ @@ -59,10 +61,40 @@ public class APIController extends BasicController{ return null; } + /****** device active *******/ + @PostMapping(value = "/api/device_online") + @ResponseBody + public String onLine(String deviceId, Integer tenantId, LocalDateTime lastOnlineTime) { + + onDeviceActive(deviceId,tenantId); + + // 检查上次是否离线,如果是则启动补传 + LocalDateTime now = LocalDateTime.now(); + Short len = 15; + String uploadCmd = "D31A" + HexUtil.Short2HexString(len) + + HexUtil.Int2HexString(Integer.parseInt(deviceId)) + + "0F" + + HexUtil.Byte2HexString((byte) (lastOnlineTime.getYear() - 2000)) + + HexUtil.Byte2HexString((byte) (lastOnlineTime.getMonthValue())) + + HexUtil.Byte2HexString((byte) (lastOnlineTime.getDayOfMonth())) + + HexUtil.Byte2HexString((byte) (lastOnlineTime.getHour())) + + HexUtil.Byte2HexString((byte) (lastOnlineTime.getMinute())) + + HexUtil.Byte2HexString((byte) (now.getYear() - 2000)) + + HexUtil.Byte2HexString((byte) (now.getMonthValue())) + + HexUtil.Byte2HexString((byte) (now.getDayOfMonth())) + + HexUtil.Byte2HexString((byte) (now.getHour())) + + HexUtil.Byte2HexString((byte) (now.getMinute())); + rtcmClient.config(deviceId, uploadCmd); + // 保存 + saveMsg(deviceId, tenantId,0xD31A, uploadCmd); + + return null; + } + /****** device active *******/ @PostMapping(value = "/api/device_active") @ResponseBody - public String onDeviceActive(String deviceId) { + public String onDeviceActive(String deviceId, Integer tenantId) { // 检查有没有待配置的参数 GnssDevice device = deviceMapper.queryByDeviceId(deviceId); @@ -73,7 +105,7 @@ public class APIController extends BasicController{ if(config != null){ rtcmClient.config(deviceId, config); // 保存 - saveMsg(deviceId, device.getTenantid(),0xd311, config); + saveMsg(deviceId, tenantId,0xd311, config); } } } @@ -84,11 +116,33 @@ public class APIController extends BasicController{ /****** device stop *******/ @PostMapping(value = "/api/device_stop") @ResponseBody - public String onDeviceStop(String deviceId) { + public String onDeviceStop(String deviceId, Integer tenantId) { return null; } + /****** gnss upload *******/ + @PostMapping(value = "/api/gnss_upload") + @ResponseBody + public String onGnssUpload(String deviceId, Integer tenantId,LocalDateTime uploadTime) { + saveMsg(deviceId, tenantId,0xd342, "gnss data upload from "+uploadTime); + return null; + } + + @PostMapping(value = "/api/gnss_upload_pause") + @ResponseBody + public String onGnssUploadPause(String deviceId, Integer tenantId) { + saveMsg(deviceId, tenantId,0xd342, "gnss data upload pause"); + return null; + } + + @PostMapping(value = "/api/gnss_upload_complete") + @ResponseBody + public String onGnssUploadComplete(String deviceId, Integer tenantId) { + saveMsg(deviceId, tenantId,0xd342, "gnss data upload completely"); + return null; + } + void saveMsg(String deviceId, int tenantId, int msgType, String content){ GnssMsg gnssMsg = new GnssMsg(); gnssMsg.setCreatetime(LocalDateTime.now()); diff --git a/sec-beidou/src/main/resources/templates/page/gnss_status.html b/sec-beidou/src/main/resources/templates/page/gnss_status.html index a517c8df..06f29a6e 100644 --- a/sec-beidou/src/main/resources/templates/page/gnss_status.html +++ b/sec-beidou/src/main/resources/templates/page/gnss_status.html @@ -133,6 +133,8 @@ 掉线 {{# } else if(d.state == 1){ }} 工作 + {{# } else if(d.state == 3){ }} + 补传 {{# } else { }} 休眠 {{# } }}