diff --git a/sec-api/src/main/java/com/imdroid/secapi/dto/Ehm.java b/sec-api/src/main/java/com/imdroid/secapi/dto/Ehm.java new file mode 100644 index 00000000..d5471a2f --- /dev/null +++ b/sec-api/src/main/java/com/imdroid/secapi/dto/Ehm.java @@ -0,0 +1,34 @@ +package com.imdroid.secapi.dto; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * GNSS设备配置数据 + * + * @author LiGang + */ +@Data +@TableName(value = "ehm") +public class Ehm { + @TableId(value = "id", type = IdType.AUTO) + private Long id; + private Integer tenantid; + private String deviceid; + private LocalDateTime createtime; + private Short offlinestatdays; + private Integer offlinecount; + private Integer offlineminutes; + private Integer calcstathours; + private Float stdeve; + private Float stdevn; + private Float stdevu; + private Float fixrate; + private Float validrate; + + private Integer jumpcount; +} diff --git a/sec-api/src/main/java/com/imdroid/secapi/dto/EhmConfig.java b/sec-api/src/main/java/com/imdroid/secapi/dto/EhmConfig.java new file mode 100644 index 00000000..6a7c205a --- /dev/null +++ b/sec-api/src/main/java/com/imdroid/secapi/dto/EhmConfig.java @@ -0,0 +1,19 @@ +package com.imdroid.secapi.dto; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * GNSS设备配置数据 + * + * @author LiGang + */ +@Data +@TableName(value = "ehm") +public class EhmConfig { + private LocalDateTime updatetime; + private Short offlinestatdays; + private Integer calcstathours; +} diff --git a/sec-api/src/main/java/com/imdroid/secapi/dto/EhmConfigMapper.java b/sec-api/src/main/java/com/imdroid/secapi/dto/EhmConfigMapper.java new file mode 100644 index 00000000..5aef32a5 --- /dev/null +++ b/sec-api/src/main/java/com/imdroid/secapi/dto/EhmConfigMapper.java @@ -0,0 +1,8 @@ +package com.imdroid.secapi.dto; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface EhmConfigMapper extends BaseMapper { +} diff --git a/sec-api/src/main/java/com/imdroid/secapi/dto/EhmMapper.java b/sec-api/src/main/java/com/imdroid/secapi/dto/EhmMapper.java new file mode 100644 index 00000000..edb9657a --- /dev/null +++ b/sec-api/src/main/java/com/imdroid/secapi/dto/EhmMapper.java @@ -0,0 +1,8 @@ +package com.imdroid.secapi.dto; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface EhmMapper extends BaseMapper { +} diff --git a/sec-api/src/main/java/com/imdroid/secapi/dto/GnssTrxMsg.java b/sec-api/src/main/java/com/imdroid/secapi/dto/GnssTrxMsg.java index 412bd15f..9fbbd415 100644 --- a/sec-api/src/main/java/com/imdroid/secapi/dto/GnssTrxMsg.java +++ b/sec-api/src/main/java/com/imdroid/secapi/dto/GnssTrxMsg.java @@ -56,6 +56,8 @@ public class GnssTrxMsg { // 这里的收发都是服务端统计的,终端收发详细统计在msg_trx表里 @ExcelProperty("B562") Integer b562bytes; + @ExcelProperty("B562Count") + Integer b562count; @ExcelProperty("D3XX") Integer d3xxbytes; @@ -69,4 +71,6 @@ public class GnssTrxMsg { Integer floatnum; @ExcelProperty("备注") String remark; + @ExcelProperty("JumpCount") + Integer jumpcount; } diff --git a/sec-beidou-ehm/pom.xml b/sec-beidou-ehm/pom.xml new file mode 100644 index 00000000..ccfcca28 --- /dev/null +++ b/sec-beidou-ehm/pom.xml @@ -0,0 +1,107 @@ + + + 4.0.0 + + com.imdroid + security-monitor + 1.0-SNAPSHOT + + + sec-beidou-ehm + + + 8 + 8 + UTF-8 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-devtools + true + + + + mysql + mysql-connector-java + 8.0.11 + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + + com.baomidou + mybatis-plus-boot-starter + 3.5.2 + + + + com.imdroid + sec-api + 1.0-SNAPSHOT + + + com.imdroid + sec-common + 1.0-SNAPSHOT + + + + org.projectlombok + lombok + true + + + + + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + + + + + + central + ali-mirror + https://maven.aliyun.com/repository/central + + true + + + true + + + + + \ No newline at end of file diff --git a/sec-beidou-ehm/src/main/java/com/imdroid/beidou_ehm/BeidouEhmApp.java b/sec-beidou-ehm/src/main/java/com/imdroid/beidou_ehm/BeidouEhmApp.java new file mode 100644 index 00000000..856c808a --- /dev/null +++ b/sec-beidou-ehm/src/main/java/com/imdroid/beidou_ehm/BeidouEhmApp.java @@ -0,0 +1,22 @@ +package com.imdroid.beidou_ehm; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.context.annotation.ComponentScan; + + +/** + * @author Layton + * @date 2023/1/31 20:33 + */ +@SpringBootApplication(scanBasePackages = {"com.imdroid"}) +@MapperScan({"com.imdroid.secapi","com.imdroid.beidou.entity"}) +@ComponentScan({"com.imdroid.*"}) +@EntityScan({"com.imdroid.*"}) +public class BeidouEhmApp { + public static void main(String[] args) { + SpringApplication.run(BeidouEhmApp.class, args); + } +} diff --git a/sec-beidou-ehm/src/main/java/com/imdroid/beidou_ehm/task/EhmTask.java b/sec-beidou-ehm/src/main/java/com/imdroid/beidou_ehm/task/EhmTask.java new file mode 100644 index 00000000..2dc0ff38 --- /dev/null +++ b/sec-beidou-ehm/src/main/java/com/imdroid/beidou_ehm/task/EhmTask.java @@ -0,0 +1,171 @@ +package com.imdroid.beidou_ehm.task; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.imdroid.secapi.dto.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.Iterator; +import java.util.List; + +@Component +@Configuration +@EnableScheduling +public class EhmTask{ + @Autowired + GnssStatusMapper statusMapper; + @Autowired + EhmMapper ehmMapper; + @Autowired + EhmConfigMapper ehmConfigMapper; + @Autowired + WarningMsgMapper warningMsgMapper; + @Autowired + GnssCalcDataMapper gnssCalcDataMapper; + @Autowired + GnssTrxMsgMapper gnssTrxMsgMapper; + /** + * 每半小时转发GNSS解算结果 + */ + @Scheduled(cron = "0 24 * * * ?") // 每30分钟执行一次 + private void check() { + // 获取健康检查配置 + List ehmConfigList = ehmConfigMapper.selectList(null); + EhmConfig ehmConfig; + if(ehmConfigList==null || ehmConfigList.size()==0){ + ehmConfig = new EhmConfig(); + ehmConfig.setUpdatetime(LocalDateTime.now()); + ehmConfig.setCalcstathours(24); + ehmConfig.setOfflinestatdays((short) 7); + ehmConfigMapper.update(ehmConfig,null); + } + else{ + ehmConfig = ehmConfigList.get(0); + } + // 获取所有已部署的设备 + List deviceList= statusMapper.queryDeployed(); + Iterator iterator = deviceList.iterator(); + while(iterator.hasNext()) { + GnssStatusJoin status=iterator.next(); + Ehm ehm = new Ehm(); + ehm.setDeviceid(status.getDeviceid()); + ehm.setTenantid(status.getTenantid()); + ehm.setCreatetime(LocalDateTime.now()); + ehm.setOfflinestatdays(ehmConfig.getOfflinestatdays()); + ehm.setCalcstathours(ehmConfig.getCalcstathours()); + + // 检查过去N天离线次数和时长 + checkOffline(ehm, status.getState()==GnssStatus.STATE_OFFLINE); + // 计算过去N小时标准差 + // 计算过去N小时有效解比例 + // 计算过去N小时固定解比例 + checkCalcResults(ehm); + ehmMapper.insert(ehm); + } + } + + private void checkOffline(Ehm ehm, boolean isOffline){ + LocalDateTime now = ehm.getCreatetime(); + // 从告警消息里查询离线记录 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("deviceid",ehm.getDeviceid()); + queryWrapper.le("createtime",now.minusDays(ehm.getOfflinestatdays())); + queryWrapper.eq("code",WarningCfg.TYPE_DEVICE_OFF_LINE); + List warningMsgList = warningMsgMapper.selectList(queryWrapper); + if(warningMsgList==null || warningMsgList.size()==0){ + if(isOffline){ + ehm.setOfflinecount(1); + ehm.setOfflineminutes(ehm.getOfflinestatdays()*24*60); + } + else{ + ehm.setOfflinecount(0); + ehm.setOfflineminutes(0); + } + } + else{ + ehm.setOfflinecount(warningMsgList.size()); + int offlineMinutes = 0; + LocalDateTime offlineEnd = null; + LocalDateTime offlineBegin = null; + for(WarningMsg warningMsg:warningMsgList){ + // 读下一条纪录时才计算上一条的时间差,因为cleartime有可能没有 + if(offlineEnd==null) offlineEnd=warningMsg.getCreatetime(); + if(offlineBegin!=null){ + Duration duration = Duration.between(offlineBegin,offlineEnd); + offlineMinutes+=duration.toMinutes(); + } + offlineBegin = warningMsg.getCreatetime(); + offlineEnd = warningMsg.getCleartime(); + } + if(offlineEnd==null) offlineEnd=now; + if(offlineBegin!=null){ + Duration duration = Duration.between(offlineBegin,offlineEnd); + offlineMinutes+=duration.toMinutes(); + } + ehm.setOfflineminutes(offlineMinutes); + } + } + + private void checkCalcResults(Ehm ehm){ + // 获取过去N小时的解算数据 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("deviceid", ehm.getDeviceid()); + queryWrapper.le("createtime", ehm.getCreatetime().minusHours(ehm.getCalcstathours())); + List gnssCalcDataList = gnssCalcDataMapper.selectList(queryWrapper); + // 计算过去N小时标准差,不含有效值 + // 计算过去N小时有效解比例 + double avgE = 0; + double avgN = 0; + double avgU = 0; + double sedevE = 0; + double sedevN = 0; + double sedevU = 0; + int validCount = 0; + for(GnssCalcData gnssCalcData:gnssCalcDataList){ + if(gnssCalcData.getEnabled()){ + avgE += gnssCalcData.getB562e(); + avgN += gnssCalcData.getB562n(); + avgU += gnssCalcData.getB562d(); + validCount++; + } + } + if(validCount>0){ + avgE = avgE/validCount; + avgN = avgN/validCount; + avgU = avgU/validCount; + for(GnssCalcData gnssCalcData:gnssCalcDataList){ + if(gnssCalcData.getEnabled()){ + sedevE += Math.pow(gnssCalcData.getB562e()-avgE,2); + sedevN += Math.pow(gnssCalcData.getB562n()-avgN,2); + sedevU += Math.pow(gnssCalcData.getB562d()-avgU,2); + } + } + ehm.setStdeve((float) (sedevE/validCount)); + ehm.setStdevn((float) (sedevN/validCount)); + ehm.setStdevu((float) (sedevU/validCount)); + ehm.setValidrate((float) (validCount/gnssCalcDataList.size())); + } + + + // 计算过去N小时固定解比例 + QueryWrapper queryWrapper1 = new QueryWrapper<>(); + queryWrapper1.eq("deviceid",ehm.getDeviceid()); + queryWrapper1.le("createtime", ehm.getCreatetime().minusHours(ehm.getCalcstathours())); + List gnssTrxMsgList = gnssTrxMsgMapper.selectList(queryWrapper1); + int fixCount = 0; + int d341Count = 0; + int jumpCount = 0; + for(GnssTrxMsg gnssTrxMsg:gnssTrxMsgList){ + fixCount += gnssTrxMsg.getFixnum(); + d341Count += gnssTrxMsg.getB562count(); + jumpCount += gnssTrxMsg.getJumpcount(); + } + if(d341Count>0) ehm.setFixrate((float) (fixCount/d341Count)); + ehm.setJumpcount(jumpCount); + } +} 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 e9f745a5..7e72baac 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 @@ -145,6 +145,7 @@ public class SingleLineGNSSCalcService implements GNSSDataCalcService { if(groupCalc.getVer() == 3 && focusCalculator.isJump()){ logger.info("{}发生周跳",deviceId); hardResetDevice(deviceId); + device.setJumpCount(device.getJumpCount()+1); } } 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 989aff20..180b9e52 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 @@ -67,6 +67,7 @@ public class D3F2StopIndicationMessageExecutor implements Executor