1、增加健康检查功能

This commit is contained in:
weidong 2025-02-16 09:49:55 +08:00
parent 67a3cec36e
commit a2a660099c
12 changed files with 407 additions and 1 deletions

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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<EhmConfig> {
}

View File

@ -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<Ehm> {
}

View File

@ -56,6 +56,8 @@ public class GnssTrxMsg {
// 这里的收发都是服务端统计的终端收发详细统计在msg_trx表里 // 这里的收发都是服务端统计的终端收发详细统计在msg_trx表里
@ExcelProperty("B562") @ExcelProperty("B562")
Integer b562bytes; Integer b562bytes;
@ExcelProperty("B562Count")
Integer b562count;
@ExcelProperty("D3XX") @ExcelProperty("D3XX")
Integer d3xxbytes; Integer d3xxbytes;
@ -69,4 +71,6 @@ public class GnssTrxMsg {
Integer floatnum; Integer floatnum;
@ExcelProperty("备注") @ExcelProperty("备注")
String remark; String remark;
@ExcelProperty("JumpCount")
Integer jumpcount;
} }

107
sec-beidou-ehm/pom.xml Normal file
View File

@ -0,0 +1,107 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.imdroid</groupId>
<artifactId>security-monitor</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>sec-beidou-ehm</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version><!--$NO-MVN-MAN-VER$ -->
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>com.imdroid</groupId>
<artifactId>sec-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.imdroid</groupId>
<artifactId>sec-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>central</id>
<name>ali-mirror</name>
<url>https://maven.aliyun.com/repository/central</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</project>

View File

@ -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);
}
}

View File

@ -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<EhmConfig> 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<GnssStatusJoin> deviceList= statusMapper.queryDeployed();
Iterator<GnssStatusJoin> 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<WarningMsg> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("deviceid",ehm.getDeviceid());
queryWrapper.le("createtime",now.minusDays(ehm.getOfflinestatdays()));
queryWrapper.eq("code",WarningCfg.TYPE_DEVICE_OFF_LINE);
List<WarningMsg> 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<GnssCalcData> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("deviceid", ehm.getDeviceid());
queryWrapper.le("createtime", ehm.getCreatetime().minusHours(ehm.getCalcstathours()));
List<GnssCalcData> 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<GnssTrxMsg> queryWrapper1 = new QueryWrapper<>();
queryWrapper1.eq("deviceid",ehm.getDeviceid());
queryWrapper1.le("createtime", ehm.getCreatetime().minusHours(ehm.getCalcstathours()));
List<GnssTrxMsg> 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);
}
}

View File

@ -145,6 +145,7 @@ public class SingleLineGNSSCalcService implements GNSSDataCalcService {
if(groupCalc.getVer() == 3 && focusCalculator.isJump()){ if(groupCalc.getVer() == 3 && focusCalculator.isJump()){
logger.info("{}发生周跳",deviceId); logger.info("{}发生周跳",deviceId);
hardResetDevice(deviceId); hardResetDevice(deviceId);
device.setJumpCount(device.getJumpCount()+1);
} }
} }

View File

@ -67,6 +67,7 @@ public class D3F2StopIndicationMessageExecutor implements Executor<D3F2StopIndic
gnssTrxMsg.setTenantid(device.getTenantId()); gnssTrxMsg.setTenantid(device.getTenantId());
gnssTrxMsg.setD3xxbytes(device.getD3xxbytes()); gnssTrxMsg.setD3xxbytes(device.getD3xxbytes());
gnssTrxMsg.setB562bytes(device.getD341bytes()); gnssTrxMsg.setB562bytes(device.getD341bytes());
gnssTrxMsg.setB562count(device.getD341Count());
gnssTrxMsg.setSatelliteinuse(device.getSatelitesInUse()); gnssTrxMsg.setSatelliteinuse(device.getSatelitesInUse());
gnssTrxMsg.setFixnum(device.getFixedNum()); gnssTrxMsg.setFixnum(device.getFixedNum());
gnssTrxMsg.setFloatnum(device.getFloatNum()); gnssTrxMsg.setFloatnum(device.getFloatNum());

View File

@ -54,6 +54,7 @@ public class Device {
int d341In42Count = 0; int d341In42Count = 0;
int satelitesInUse = 0;//平均卫星数 int satelitesInUse = 0;//平均卫星数
int sataStatCount = 0; int sataStatCount = 0;
int jumpCount = 0;
Double latitude; Double latitude;
Double longitude; Double longitude;
@ -143,6 +144,7 @@ public class Device {
satelitesInUse = 0; satelitesInUse = 0;
fixedNum = 0; fixedNum = 0;
floatNum = 0; floatNum = 0;
jumpCount = 0;
} }
public void clearD342Stat(){ public void clearD342Stat(){

View File

@ -215,9 +215,11 @@ CREATE TABLE IF NOT EXISTS `gnsstrxmsg` (
`uart2unknown` int DEFAULT NULL, `uart2unknown` int DEFAULT NULL,
`b562bytes` int DEFAULT NULL, `b562bytes` int DEFAULT NULL,
`d3xxbytes` int DEFAULT NULL, `d3xxbytes` int DEFAULT NULL,
`b562count` int DEFAULT NULL,
`satelliteinuse` int DEFAULT 0, `satelliteinuse` int DEFAULT 0,
`fixnum` int DEFAULT NULL, `fixnum` int DEFAULT NULL,
`floatnum` int DEFAULT NULL, `floatnum` int DEFAULT NULL,
`jumpcount` int DEFAULT NULL,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
@ -338,3 +340,30 @@ CREATE TABLE IF NOT EXISTS `gnssdevicesinglerecords` (
KEY `idx_deviceid_createtime` (`deviceid`,`createtime`), KEY `idx_deviceid_createtime` (`deviceid`,`createtime`),
KEY `idx_createtime` (`createtime`) KEY `idx_createtime` (`createtime`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT='GNSS单次解算记录表'; ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT='GNSS单次解算记录表';
CREATE TABLE IF NOT EXISTS `ehm` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`tenantid` int DEFAULT 0,
`deviceid` varchar(64) NOT NULL COMMENT '设备ID',
`createtime` datetime(3) NOT NULL COMMENT '创建时间',
`offlinestatdays` smallint DEFAULT NULL COMMENT '离线统计周期',
`offlinecount` int DEFAULT NULL COMMENT '离线统计周期内的离线次数',
`offlineminutes` int DEFAULT NULL COMMENT '离线统计周期内的离线时长',
`calcstathours` int DEFAULT NULL COMMENT '数据分析周期',
`stdeve` float DEFAULT NULL COMMENT '标准差',
`stdevn` float DEFAULT NULL COMMENT '标准差',
`stdevu` float DEFAULT NULL COMMENT '标准差',
`fixrate` float DEFAULT NULL COMMENT '固定率',
`validrate` float DEFAULT NULL COMMENT '有效解比例',
`jumpcount` int DEFAULT NULL COMMENT '周跳次数',
PRIMARY KEY (`id`),
KEY `idx_deviceid_createtime` (`deviceid`,`createtime`),
KEY `idx_createtime` (`createtime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `ehmconfig` (
`updatetime` datetime(3) NOT NULL COMMENT '更新时间',
`offlinestatdays` smallint DEFAULT NULL COMMENT '离线统计周期',
`calcstathours` int DEFAULT NULL COMMENT '数据分析周期',
PRIMARY KEY (`updatetime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;