环境:idea
语言:java
框架:springboot
难点:区分静置和行驶
分析:
//todo 如果车辆在静置状态,但是速度和方向角都有值,这种情况怎么屏蔽,看坐标是否发生变化?
// 接上:如果这种情况下坐标为0,则应该怎么判断?不判断?认为是静置?认为是运动?设备处理:坐标为0,则速度、方向角直接变为0
// 如果坐标不为0,则需要看有效坐标的行驶距离,没有行驶,则还是认为是静置,防止飘动,但是怎么判断坐标的行驶距离呢?
// 接上:看上一个状态的坐标与本次状态的坐标的小数点第三位是否发生变化?或者变化值在2以内,就认为是静置的?
//本程序没有处理
思路:
获取设备给过来的实时数据
摘出坐标、速度、方向角(设备提供)
获取设备历史最新的状态记录
如果状态记录为空,则将设备状态插入(默认静置)
如果状态记录不为空,则判断速度和方向角,如果都不为0,则肯定是运行状态
状态一致则判断设备报警状态是否一致,报警不一致就发送报警消息
状态不一致则更新原设备状态(结束原设备状态),插入新的设备状态,判断设备报警状态是否一致,不一致则发送报警消息
速度和方向角有不为0的情况,还需要看是不是一段时间内都为0或者很低的速度,才可以判断是否为静置(比如超过3分钟速度都是在5以内,则认为是静置)
获取设备当前时间往前约定的静置时间内所有设备数据,计算出平均速度
平均速度低于5,则状态是静置的,如果不是低于5,则还是运行状态(不可能是离线状态,因为是设备推送过来的实时数据)
状态一致则判断设备报警状态是否一致,报警不一致就发送报警消息
状态不一致则更新原设备状态(结束原设备状态),插入新的设备状态,判断设备报警状态是否一致,不一致则发送报警消息
部分代码参考:
/**
* 处理设备的状态
* @param pointValue GPS设备传输的数据
*/
private void dealDevState(PointValue pointValue) {
//设备ID
String deviceId = pointValue.getDeviceId();
//根据ID获取设备对象
Device device = deviceClient.selectById(deviceId).getData();
//设备当前的状态
DeviceState deviceState = deviceStateService.selectByDevId(deviceId);
//设备的配置信息,包含设备的离线时间、静置时间、高低温阈值等配置数据
DeviceCfg deviceCfg = deviceCfgService.selectByDevId(deviceId);
//设备最新的有效坐标,这里是防止当前传过来的GPS设备数据没有坐标
DeviceCoordinate deviceCoordinate = deviceCoordinateService.selectByDevId(deviceId);
//设备的GPS数据
List<PointValue> pointValues = pointValue.getChildren();
//将list转换map
Map<Integer, Object> pointValueMap = pointValues.stream().collect(Collectors.toMap(PointValue::getPointOrderNum, Function.identity(), (n1, n2) -> n1, TreeMap::new));
//设备组织ID
((PointValue) pointValueMap.get(0)).setDeptId(device.getDeptId());
//报警代码
String normalCode = "00000";
//系统时间
Date sysDate = new Date();
if (null == deviceState) {
//执行插入 新设备,没有设备状态记录
deviceState = new DeviceState();
deviceState.setDeviceId(deviceId);
deviceState.setState(2); //新设备,默认就是静置的
deviceState.setStartTime(sysDate); //这里没有采用设备时间,是采用的服务器收到的时间
//合成设备的温度、湿度等数据
deviceState.formatDeviceInfo(pointValueMap);
//合成设备的最新的有效坐标,并获取设备的地址
deviceState.formatDevAddr(pointValueMap, deviceCoordinate);
//合成设备的报警信息
deviceState.formatAlarmInfo(deviceCfg);
try {
//插入设备状态
deviceStateService.add(deviceState);
if (!deviceState.getAlarmCode().equals(normalCode)) {
//todo 这里如果有报警,还需要推送报警
this.sendAlarmMsg(deviceState,device);
}
} catch (Exception ex) {
ex.printStackTrace();
log.error(ex.getMessage());
}
} else {
String angle = ((PointValue) pointValueMap.get(6)).getValue();
String speed = ((PointValue) pointValueMap.get(7)).getValue();
float fSpeed = Float.valueOf(speed);
float fAngle = Float.valueOf(angle);
int nowState = deviceState.getState();
int newState = 1; //默认为是运动的
if (fSpeed > 0 && fAngle > 0) {
//速度和方向角不为0的情况下,就认为是运动的
this.dealDevState(nowState,newState,deviceId,deviceState,pointValueMap,deviceCfg,normalCode,sysDate,deviceCoordinate,device);
}else{
//速度为0或者方向角为0,还需要看是不是一段时间内都为0或者很低的速度,才可以判断是否为静置
int disMinute = 3; //默认为3分钟
if((null != deviceCfg) && (deviceCfg.getStaticMinute() > 0)){
disMinute = deviceCfg.getStaticMinute();
}
Date date = ((PointValue) pointValueMap.get(0)).getCreateTime();
int size = pointValueMap.size();
if(null == date){
date = pointValue.getOriginTime();
}
//往前倒推的时间
Date oldDate = DateUtil.offsetMinute(date,-Math.abs(disMinute));
//根据设备ID,获取设备从当前时间往前一段时间内的所有设备数据,求出这个时间内的速度平均值,来衡量是否为静置状态
List<PointValue> pointValues01 = this.getHisPointValue(deviceId,DataConvertor.getStrDate03(oldDate),DataConvertor.getStrDate03(date));
List<PointValue> pointValues01Sort = pointValues01.stream().sorted(Comparator.comparing(PointValue::getOriginTime)).collect(Collectors.toList());
double avgSpeed = this.getAvgSpeed(pointValues01Sort,size);
if(avgSpeed < 5){ //规定时间里面,行驶速度低于5,就认为是静置的
newState = 2; //认为是静置的
}else{
newState = 1; //认为是运动的
}
this.dealDevState(nowState,newState,deviceId,deviceState,pointValueMap,deviceCfg,normalCode,sysDate,deviceCoordinate,device);
}
}
}
/**
* 获取速度的平均值
* @param pointValues
* @param size
*/
private double getAvgSpeed(List<PointValue> pointValues,int size){
List<PointValue> pointValueList = null;
double avgSpeed = 0;
int count = 0;
double dSpeed = 0;
for (int i = 0; i < pointValues.size(); i++) {
if (i % size == 0) {
pointValueList = new ArrayList<>();
}
pointValueList.add(pointValues.get(i));
if ((i + 1) % size == 0) {
//将list转换map
Map<Integer, Object> pointValueMap = pointValueList.stream().collect(Collectors.toMap(PointValue::getPointOrderNum, Function.identity(),(n1, n2) -> n1, TreeMap::new));
String sSpeed = ((PointValue)pointValueMap.get(7)).getValue();
dSpeed = dSpeed + Double.parseDouble(sSpeed);
count++;
}
}
if(count > 0){
avgSpeed =(dSpeed / count);
}
return avgSpeed;
}
/**
* 存储设备状态
* @param nowState 设备上一条状态
* @param newState 当前状态
* @param deviceId 设备ID
* @param deviceState 设备状态对象
* @param pointValueMap 设备传递过来的GPS数据
* @param deviceCfg 设备配置信息
* @param normalCode 正常代码
* @param sysDate 当前时间
* @param deviceCoordinate 设备上一条有效GPS坐标
* @param device 设备对象
*/
private void dealDevState(int nowState,int newState,String deviceId,DeviceState deviceState,Map<Integer, Object> pointValueMap,
DeviceCfg deviceCfg,String normalCode,Date sysDate,DeviceCoordinate deviceCoordinate,Device device){
if (nowState == newState) {
//原来就是运动状态,需要判断是否报警
//如果状态一致,判断报警状态是否一致
DeviceState deviceState01 = new DeviceState();
deviceState01.setDeviceId(deviceId);
deviceState01.setState(newState);
deviceState01.setStartTime(deviceState.getStartTime());
deviceState01.formatDeviceInfo(pointValueMap);
deviceState01.formatAlarmInfo(deviceCfg);
if(!deviceState01.getAlarmCode().equals(normalCode)) {
//有报警
if (!deviceState.getAlarmCode().equals(deviceState01.getAlarmCode())) {
// 报警代码不一致,把状态开始时间还获取过来纳入到新的状态里面,同时结束当前状态,插入新的状态
deviceState.setEndTime(sysDate);
deviceStateService.update(deviceState);
deviceState01.formatDevAddr(pointValueMap,deviceCoordinate);
deviceStateService.add(deviceState01);
//todo 这里还需要做报警代码推送
this.sendAlarmMsg(deviceState01,device);
} else {
//状态一致,报警代码一致
// 不做任何处理
}
}
} else{
//状态发生变化
deviceState.setEndTime(sysDate);
deviceStateService.update(deviceState);
DeviceState deviceState1 = new DeviceState();
deviceState1.setDeviceId(deviceId);
deviceState1.setState(newState);
deviceState1.setStartTime(sysDate);
deviceState1.formatDeviceInfo(pointValueMap);
deviceState1.formatDevAddr(pointValueMap, deviceCoordinate);
deviceState1.formatAlarmInfo(deviceCfg);
deviceStateService.add(deviceState1);
if (!deviceState1.getAlarmCode().equals(normalCode)) {
//有报警
if (!deviceState.getAlarmCode().equals(deviceState1.getAlarmCode())) {
//todo 这里如果报警代码不一致,还需要做报警代码推送
this.sendAlarmMsg(deviceState1,device);
}
}
}
}