Commit 0e53f7c2 by 汪志阳

fix:起床清醒时间判断

parent 7e54fc62
......@@ -12,6 +12,7 @@ import com.makeit.global.annotation.AuthIgnore;
import com.makeit.global.aspect.tenant.TenantIdIgnore;
import com.makeit.service.platform.device.PlatDeviceService;
import com.makeit.service.platform.elder.*;
import com.makeit.vo.platform.elder.wakeUpAnalysisVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -151,5 +152,14 @@ public class PlatElderSleepController {
huiNengService.bodyAlarm("1712384736845950978","219A04X1856F6D8",jsonObject);
return ApiResponseUtils.success();
}
@ApiOperation("起床测试")
@GetMapping("getup")
@AuthIgnore
@TenantIdIgnore
public ApiResponseEntity<List<wakeUpAnalysisVO>> elderGetUpAnalysisTask(@RequestParam Integer month,
@RequestParam Integer day) {
return ApiResponseUtils.success(platElderBreatheAnalysisService.elderGetUpAnalysisTask(month, day));
}
}
......@@ -2,6 +2,7 @@ package com.makeit.service.platform.elder;
import com.baomidou.mybatisplus.extension.service.IService;
import com.makeit.entity.platform.elder.PlatElderBreatheAnalysis;
import com.makeit.vo.platform.elder.wakeUpAnalysisVO;
import java.util.List;
......@@ -16,4 +17,6 @@ import java.util.List;
public interface PlatElderBreatheAnalysisService extends IService<PlatElderBreatheAnalysis> {
List<PlatElderBreatheAnalysis> elderHeartRespiratoryAnalysisTask(Integer month, Integer day);
List<wakeUpAnalysisVO> elderGetUpAnalysisTask(Integer month, Integer day);
}
......@@ -13,6 +13,7 @@ import com.makeit.entity.platform.device.PlatDevice;
import com.makeit.entity.platform.elder.PlatElder;
import com.makeit.entity.platform.elder.PlatElderBreatheAnalysis;
import com.makeit.entity.platform.elder.PlatElderBreatheDayStat;
import com.makeit.entity.platform.elder.PlatElderSleep;
import com.makeit.entity.saas.analysis.SaasDiseaseEvaluateReport;
import com.makeit.entity.saas.analysis.SaasDiseaseModel;
import com.makeit.entity.saas.analysis.SaasSleepAnalysisModel;
......@@ -23,10 +24,7 @@ import com.makeit.module.iot.vo.DeviceOperationLogEntity;
import com.makeit.module.iot.vo.analysis.DiseaseReportVO;
import com.makeit.module.iot.vo.analysis.EvaluateReportVO;
import com.makeit.module.iot.vo.breathe.DeviceInfoContentBreathe;
import com.makeit.service.platform.elder.PlatElderBreatheAnalysisService;
import com.makeit.service.platform.elder.PlatElderBreatheDayStatService;
import com.makeit.service.platform.elder.PlatElderRealTimeService;
import com.makeit.service.platform.elder.PlatElderService;
import com.makeit.service.platform.elder.*;
import com.makeit.service.saas.SaasDiseaseEvaluateReportService;
import com.makeit.service.saas.SaasDiseaseModelService;
import com.makeit.service.saas.SaasDiseaseReportService;
......@@ -34,6 +32,7 @@ import com.makeit.service.saas.SaasSleepAnalysisModelService;
import com.makeit.utils.data.convert.JsonUtil;
import com.makeit.utils.data.convert.StreamUtil;
import com.makeit.utils.time.LocalDateTimeUtils;
import com.makeit.vo.platform.elder.wakeUpAnalysisVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
......@@ -47,9 +46,11 @@ import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
/**
......@@ -84,6 +85,8 @@ public class PlatElderBreatheAnalysisServiceImpl extends ServiceImpl<PlatElderBr
private PlatElderBreatheAnalysisService platElderBreatheAnalysisService;
@Autowired
private PlatElderRealTimeService platElderRealTimeService;
@Autowired
private PlatElderSleepService platElderSleepService;
private static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
......@@ -183,7 +186,7 @@ public class PlatElderBreatheAnalysisServiceImpl extends ServiceImpl<PlatElderBr
}
if (firstStopSecond != 0 && (timestamp - firstStopSecond) / 1000 >= breatheDuration) {
// 避免每10s生成一次统计的方式,切换状态后重新计算
if(!existBrStop.get()) {
if (!existBrStop.get()) {
log.info("第一次呼吸暂停持续时间满足:{}:now:{}", breatheDuration, longToTime(timestamp));
brStopCount.getAndIncrement();
existBrStop.set(true);
......@@ -271,12 +274,12 @@ public class PlatElderBreatheAnalysisServiceImpl extends ServiceImpl<PlatElderBr
}
hrFastSecond.set(0);
existHrFast.set(false);
}else {
} else {
hrSlowSecond.set(0);
existHrSlow.set(false);
hrFastSecond.set(0);
existHrFast.set(false);
log.info("心率正常:{},min:{},max:{},的时间:{}", hr, heartThresholdMin,heartThresholdMax, longToTime(timestamp));
log.info("心率正常:{},min:{},max:{},的时间:{}", hr, heartThresholdMin, heartThresholdMax, longToTime(timestamp));
}
});
......@@ -394,7 +397,7 @@ public class PlatElderBreatheAnalysisServiceImpl extends ServiceImpl<PlatElderBr
@Override
@Transactional(rollbackFor = Exception.class)
public List<PlatElderBreatheAnalysis> elderHeartRespiratoryAnalysisTask(Integer month,Integer day) {
public List<PlatElderBreatheAnalysis> elderHeartRespiratoryAnalysisTask(Integer month, Integer day) {
// 12-06,12-18 12-07、 12-12(70分)
LocalDate nowDate = LocalDate.now();
if (month != null && day != null) {
......@@ -442,14 +445,6 @@ public class PlatElderBreatheAnalysisServiceImpl extends ServiceImpl<PlatElderBr
return result;
}
public Long getDurationRange(String startTime, String endTime) {
LocalDateTime target = LocalDateTime.parse(startTime, DEFAULT_FORMATTER);
// 获取当前日期,此处为了保证后续结果固定,注掉自动获取当前日期,指定固定日期
// LocalDate today = LocalDate.now();
LocalDateTime source = LocalDateTime.parse(endTime, DEFAULT_FORMATTER);
return Duration.between(target, source).toHours() + 1;
}
public static String formatLongTime(long time) {
return DEFAULT_FORMATTER.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneId.systemDefault()));
}
......@@ -466,5 +461,210 @@ public class PlatElderBreatheAnalysisServiceImpl extends ServiceImpl<PlatElderBr
return list;
}
@Override
public List<wakeUpAnalysisVO> elderGetUpAnalysisTask(Integer month, Integer day) {
LocalDate nowDate = LocalDate.now();
if (month != null && day != null) {
nowDate = LocalDate.of(2023, month, day);
}
LocalDate yesDate = nowDate.minusDays(1);
List<PlatElder> elderList = platElderService.list(new QueryWrapper<PlatElder>().lambda()
.isNotNull(PlatElder::getBedId).eq(PlatElder::getId,"1712648603580764161"));
List<wakeUpAnalysisVO> result = new ArrayList<>();
if (CollectionUtils.isEmpty(elderList)) {
return result;
}
List<String> elderIdList = StreamUtil.map(elderList, BaseEntity::getId);
SaasSleepAnalysisModel analysisModel = saasSleepAnalysisModelService.getOne(new QueryWrapper<SaasSleepAnalysisModel>().lambda()
.orderByDesc(BaseEntity::getCreateBy)
.last("limit 1"));
LocalDateTime yesStart = LocalDateTimeUtils.getDayStart(yesDate);
Map<String, List<PlatElderSleep>> sleepMap = StreamUtil.groupBy(platElderSleepService.list(Wrappers.<PlatElderSleep>lambdaQuery().eq(PlatElderSleep::getHappenDate, String.valueOf(yesDate))
.in(PlatElderSleep::getElderId, elderIdList)), PlatElderSleep::getElderId);
for (PlatElder platElder : elderList) {
PlatDevice platDevice = platElderRealTimeService.getBreathDevice(platElder.getId(), null);
if (platDevice == null) {
continue;
}
List<PlatElderSleep> sleepList = sleepMap.get(platElder.getId());
List<String> dayHourRange = getLastDayHourRange(yesStart);
List<LocalDateTime> leaveOverTime = new ArrayList<>();
List<LocalDateTime> wakeUpList = new ArrayList<>();
boolean isOffBed = false;
for (String hourRange : dayHourRange) {
String[] hourRangeArray = hourRange.split("~");
List<DeviceOperationLogEntity> deviceOperationLogEntities = productDeviceService.getDeviceLogByTimeRange(
platDevice.getOriDeviceId(), "reportProperty", 5000, hourRangeArray[0], hourRangeArray[1]);
if (CollectionUtils.isEmpty(deviceOperationLogEntities)) {
continue;
}
List<DeviceInfoContentBreathe> deviceInfoContentBreatheList = deviceOperationLogEntities.stream()
.filter(deviceOperationLogEntity -> deviceOperationLogEntity.getType().contains("reportProperty"))
.map(deviceOperationLogEntity -> {
DeviceInfoContentBreathe deviceInfoContentBreathe = JsonUtil.toObj((String) deviceOperationLogEntity.getContent(), DeviceInfoContentBreathe.class);
assert deviceInfoContentBreathe != null;
deviceInfoContentBreathe.setReportTime(formatLongTime(deviceInfoContentBreathe.getTimestamp()));
return deviceInfoContentBreathe;
}).collect(Collectors.toList());
Map<String, List<DeviceInfoContentBreathe>> minuteMap = StreamUtil.groupBy(deviceInfoContentBreatheList, DeviceInfoContentBreathe::getReportTime);
deviceOperationLogEntities.clear();
// 人离床大于(0.5)小时
double leaveHourThreshold = Double.parseDouble(analysisModel.getRiseLeaveThreshold());
// 或者每分钟大于30秒体动值 大于(50)
int actionThreshold = Integer.parseInt(analysisModel.getRiseActionThreshold());
// 每分钟大于30秒体动值 大于(50) 持续 (10)min
int actionDurationThreshold = Integer.parseInt(analysisModel.getRiseActionDuration());
// 且在 (2) 小时内无再次入睡
int riseRepeatThreshold = Integer.parseInt(analysisModel.getRiseRepeatThreshold());
Long firstOffBedTime = 0L;
TreeMap<LocalDateTime, Integer> minuteToActionCountMap = new TreeMap<>();
for (Map.Entry<String, List<DeviceInfoContentBreathe>> entry : minuteMap.entrySet()) {
List<DeviceInfoContentBreathe> perMinDeviceInfoList = entry.getValue();
if (CollUtil.isEmpty(perMinDeviceInfoList)) {
continue;
}
int totalActionCount = 0;
int perMinInfoSize = perMinDeviceInfoList.size();
for (int i = 0; i < perMinDeviceInfoList.size(); i++) {
DeviceInfoContentBreathe deviceInfo = perMinDeviceInfoList.get(i);
DeviceInfoContentBreathe.Properties deviceProperties = deviceInfo.getProperties();
// 0无人,1有人
Integer hasPerson = deviceProperties.getPerson();
Long timestamp = deviceInfo.getTimestamp();
if (1 == hasPerson) {
isOffBed = false;
firstOffBedTime = 0L;
// 体动值大于阈值
if (deviceProperties.getBodymove() > actionThreshold) {
totalActionCount++;
}
} else {
if (!isOffBed) {
firstOffBedTime = timestamp;
isOffBed = true;
continue;
}
if (firstOffBedTime != 0L && (timestamp - firstOffBedTime) / 1000 >= (long) leaveHourThreshold * 60 * 60) {
logger.info("离床时间大于:{}小时,第一次离床时间:{},当前时间:{}", leaveHourThreshold, longToTime(firstOffBedTime), longToTime(timestamp));
leaveOverTime.add(longToTime(timestamp));
}
}
if (i == perMinInfoSize - 1 && totalActionCount >= perMinInfoSize / 2) {
LocalDateTime reportTime = parse(deviceInfo.getReportTime());
minuteToActionCountMap.put(reportTime, totalActionCount);
}
}
}
wakeUpList = getWakeUpTimes(minuteToActionCountMap, sleepList, actionDurationThreshold, riseRepeatThreshold);
}
wakeUpAnalysisVO wakeUpAnalysisVO = new wakeUpAnalysisVO();
wakeUpAnalysisVO.setElderId(platElder.getId());
wakeUpAnalysisVO.setName(platElder.getName());
wakeUpAnalysisVO.setWakeUpList(wakeUpList);
wakeUpAnalysisVO.setLeaveOverTimeList(leaveOverTime);
result.add(wakeUpAnalysisVO);
}
return result;
}
private List<LocalDateTime> getActionDurationTime(Map<String, List<DeviceInfoContentBreathe>> map, int actionDurationThreshold,
int actionThreshold, List<PlatElderSleep> sleepList, int riseRepeatThreshold) {
List<LocalDateTime> result = new ArrayList<>();
int totalActionCount = 0;
TreeMap<LocalDateTime, Integer> minuteToActionCountMap = new TreeMap<>();
for (Map.Entry<String, List<DeviceInfoContentBreathe>> entry : map.entrySet()) {
List<DeviceInfoContentBreathe> perMinDeviceInfoList = entry.getValue();
if (CollUtil.isEmpty(perMinDeviceInfoList)) {
continue;
}
int perMinInfoSize = perMinDeviceInfoList.size();
for (int i = 0; i < perMinInfoSize; i++) {
DeviceInfoContentBreathe deviceInfo = perMinDeviceInfoList.get(i);
DeviceInfoContentBreathe.Properties deviceProperties = deviceInfo.getProperties();
// 0无人,1有人
Integer hasPerson = deviceProperties.getPerson();
if (1 == hasPerson) {
// 体动值大于阈值
if (deviceProperties.getBodymove() > actionThreshold) {
totalActionCount++;
}
}
if (i == perMinInfoSize - 1 && totalActionCount >= perMinInfoSize / 2) {
LocalDateTime reportTime = parse(deviceInfo.getReportTime());
minuteToActionCountMap.put(reportTime, totalActionCount);
}
}
}
if (CollUtil.isEmpty(minuteToActionCountMap)) {
return result;
}
result = getWakeUpTimes(minuteToActionCountMap, sleepList, actionDurationThreshold, riseRepeatThreshold);
return result;
}
/**
* 获取满足(每分钟大于30秒体动值大于(50),持续10min且在(2)小时内无再次入睡
* @param minuteToActionCountMap
* @return
*/
private List<LocalDateTime> getWakeUpTimes(TreeMap<LocalDateTime, Integer> minuteToActionCountMap, List<PlatElderSleep> elderSleeps,
int actionDurationThreshold, int riseRepeatThreshold) {
List<LocalDateTime> result = new ArrayList<>();
AtomicReference<LocalDateTime> startTime = new AtomicReference<>(LocalDateTime.MAX);
minuteToActionCountMap.forEach((k, v) -> {
int count = 0;
if (startTime.get().isEqual(LocalDateTime.MAX)) {
startTime.set(k);
}
for (int i = 1; i < actionDurationThreshold + 1; i++) {
if (minuteToActionCountMap.containsKey(k.plusMinutes(i))) {
count++;
}
if (count >= actionDurationThreshold / 2) {
if (k.compareTo(startTime.get()) != 1) {
result.add(k);
} else {
startTime.set(k);
}
}
}
if (!minuteToActionCountMap.containsKey(k.plusMinutes(1))) {
startTime.set(LocalDateTime.MAX);
}
});
if (CollUtil.isEmpty(result) || CollUtil.isEmpty(elderSleeps)) {
return result;
}
List<LocalDateTime> errorTime = new ArrayList<>();
// (2)小时内无再次入睡
for (LocalDateTime wakeUpTime : result) {
elderSleeps.stream().filter(f -> Duration.between(wakeUpTime, f.getStartSleep()).toHours() < riseRepeatThreshold)
.findFirst().ifPresent(platElderSleep -> errorTime.add(parse(platElderSleep.getStartSleep().toString())));
}
if (CollUtil.isNotEmpty(errorTime)) {
log.info("清醒时间和再次入睡:{}相隔太短{}", riseRepeatThreshold, errorTime);
result.removeAll(errorTime);
}
return result;
}
private LocalDateTime parse(String time) {
return LocalDateTime.parse(time, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
}
}
......@@ -89,11 +89,6 @@ public class PlatElderSleepServiceImpl extends ServiceImpl<PlatElderSleepMapper,
public List<PlatElderSleepAnalysis> elderSleepSleepAnalysisTask(Integer month,Integer day) {
List<String> dayHourRangeList = getLastDayHourRange(month,day);
// Calendar calendar = Calendar.getInstance();
// calendar.setTime(new Date());
// calendar.add(Calendar.DAY_OF_MONTH, -1);
// Date previousDate = calendar.getTime();
// String currentDate = DateUtil.format(previousDate, DatePattern.NORM_DATE_PATTERN);
String currentDate = LocalDate.now().minusDays(1).toString();
if(month != null && day != null){
currentDate = LocalDate.of(2023, month, day).minusDays(1).toString();
......@@ -155,6 +150,7 @@ public class PlatElderSleepServiceImpl extends ServiceImpl<PlatElderSleepMapper,
.filter(deviceOperationLogEntity -> deviceOperationLogEntity.getType().contains("reportProperty"))
.map(deviceOperationLogEntity -> {
DeviceInfoContentBreathe deviceInfoContentBreathe = JsonUtil.toObj((String) deviceOperationLogEntity.getContent(), DeviceInfoContentBreathe.class);
assert deviceInfoContentBreathe != null;
deviceInfoContentBreathe.setReportTime(formatLongTime(deviceInfoContentBreathe.getTimestamp()));
return deviceInfoContentBreathe;
})
......
package com.makeit.vo.platform.elder;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
/**
* @author wangzy
* @description
* @createDate 2023-12-29-14:48
*/
@Data
public class wakeUpAnalysisVO {
private List<LocalDateTime> wakeUpList;
private List<LocalDateTime> leaveOverTimeList;
private String elderId;
private String name;
}
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 sign in to comment