Browse Source

延后10s计算

datasub12_fetal_heart_rate_0
H Vs 6 months ago
parent
commit
04d86c80df
2 changed files with 438 additions and 253 deletions
  1. +255
    -253
      HealthMonitor.Service/Resolver/PregnancyHeartRateResolver.cs
  2. +183
    -0
      HealthMonitor.WebApi/Worker.cs

+ 255
- 253
HealthMonitor.Service/Resolver/PregnancyHeartRateResolver.cs View File

@@ -102,313 +102,315 @@ namespace HealthMonitor.Service.Resolver
var messageId = _messageId.Value;
var heartRate = _msgData.Value!;

var watchConfig = await _deviceCacheMgr.GetGpsDeviceWatchConfigCacheObjectBySerialNoAsync(heartRate.Serialno, "0067");
var isFetalHeartEnable = watchConfig != null && (int)watchConfig["enabled"]! == 1;

if (isFetalHeartEnable)
{
//_logger.LogInformation($"{heartRate.Serialno} 计算胎心胎动启动");
#region 定时下发触发器(定时建模)
var key = $"health_monitor/schedule_push/pregnancy_heart_rate/imei/{heartRate.Serialno}";
var schedule_push = await _serviceEtcd.GetValAsync(key).ConfigureAwait(false);

if (string.IsNullOrWhiteSpace(schedule_push))
{
// 注册首次下推
var interval = 0;
// 获取当前时间
DateTime now = DateTime.Now;
var rand = new Random();
var pushSec = rand.Next(59);
int pushMin = int.TryParse(heartRate.Serialno.AsSpan(heartRate.Serialno.Length - 1), out pushMin) ? pushMin : 10;
// 计算距离下一个$interval天后的8点的时间间隔
DateTime nextRunTime = new DateTime(now.Year, now.Month, now.Day, 6, pushMin, pushSec).AddDays(interval);
TimeSpan timeUntilNextRun = nextRunTime - now;

if (timeUntilNextRun < TimeSpan.Zero)
{
timeUntilNextRun = timeUntilNextRun.Add(TimeSpan.FromDays(1));
nextRunTime += TimeSpan.FromDays(1);
}

var ttl = (long)timeUntilNextRun.TotalSeconds;
var data = new
{
imei = heartRate.Serialno,
create_time = now.ToString("yyyy-MM-dd HH:mm:ss"),
ttl,
next_run_time = nextRunTime.ToString("yyyy-MM-dd HH:mm:ss")
};
var result = JsonConvert.SerializeObject(data);
await _serviceEtcd.PutValAsync(key, result, ttl, false).ConfigureAwait(false);
try
{

}
var watchConfig = await _deviceCacheMgr.GetGpsDeviceWatchConfigCacheObjectBySerialNoAsync(heartRate.Serialno, "0067");
var isFetalHeartEnable = watchConfig != null && (int)watchConfig["enabled"]! == 1;

#endregion
//_logger.LogInformation($"{heartRate.Serialno} 触发定时建模");

// 高频心率采样间隔 highFreqSampleInterval = highFreqSampleInterval+5,增加5秒兼容
var highFreqSampleInterval = (int)watchConfig!["highFreqSampleInterval"]! + 5;
// 触发高频监测的心率上限值
var triggerHighFreqHigh = (int)watchConfig["triggerHighFreqHigh"]!;
// 触发高频监测的心率下限值
var triggerHighFreqLow = (int)watchConfig["triggerHighFreqLow"]!;
//停止高频心率采样心率连续正常次数
var stopHighFreqSampleCount = (int)watchConfig["stopHighFreqSampleCount"]!;
// 高频心率采集时长 0 为持续采集,非零为高频心率的采集时长
var highFreqSampleTimes = (int)watchConfig["highFreqSampleTimes"]!;
// 告警上限阀值
var upperAlarmThreshold = (int)watchConfig["upperAlarmThreshold"]!;
// 告警下限阀值
var lowerAlarmThreshold = (int)watchConfig["lowerAlarmThreshold"]!;
// EDOC
var edoc = DateTimeUtil.ToDateTime(watchConfig!["EDOC"]!.ToString());
// interval (分钟) 固定15分钟
var intervalFHR = 15;//int)watchConfig["interval"]!;


var phr = await _serviceTDengine.GetBySerialNoAsync<PregnancyHeartRateModel>(heartRate.Serialno, 7);
if (phr.Count >= 30)
if (isFetalHeartEnable)
{
#region 定时计算胎动数据触发器两小时间隔开始
var fetalMovementKey = $"health_monitor/schedule_push/cal_fetal_movement/imei/{heartRate.Serialno}";
///// 计算 0 点秒数
var fetalMovementLastUpdate = (DateTime)heartRate.LastUpdate!;
DateTime fmScheduleNow = DateTime.Now;
// 小于两小时
if (fmScheduleNow > fetalMovementLastUpdate && (fmScheduleNow - fetalMovementLastUpdate).TotalHours <= 2)
//_logger.LogInformation($"{heartRate.Serialno} 计算胎心胎动启动");
#region 定时下发触发器(定时建模)
var key = $"health_monitor/schedule_push/pregnancy_heart_rate/imei/{heartRate.Serialno}";
var schedule_push = await _serviceEtcd.GetValAsync(key).ConfigureAwait(false);

if (string.IsNullOrWhiteSpace(schedule_push))
{
// 注册首次下推
var interval = 0;
// 获取当前时间
DateTime now = DateTime.Now;
var rand = new Random();
var pushSec = rand.Next(59);
int pushMin = int.TryParse(heartRate.Serialno.AsSpan(heartRate.Serialno.Length - 1), out pushMin) ? pushMin : 10;
// 计算距离下一个$interval天后的8点的时间间隔
DateTime nextRunTime = new DateTime(now.Year, now.Month, now.Day, 6, pushMin, pushSec).AddDays(interval);
TimeSpan timeUntilNextRun = nextRunTime - now;

var scheduleHourDiff = SCHEDULE_HOUR
.Where(h => h > fetalMovementLastUpdate.Hour)
.OrderBy(h => h - fetalMovementLastUpdate.Hour)
.FirstOrDefault() - fetalMovementLastUpdate.Hour;
var scheduleTime = fetalMovementLastUpdate.AddHours(scheduleHourDiff);
if (timeUntilNextRun < TimeSpan.Zero)
{
timeUntilNextRun = timeUntilNextRun.Add(TimeSpan.FromDays(1));
nextRunTime += TimeSpan.FromDays(1);
}

DateTime nextRunTime = new(scheduleTime.Year, scheduleTime.Month, scheduleTime.Day, scheduleTime.Hour, pushMin, pushSec);
TimeSpan timeUntilNextRun = nextRunTime - fmScheduleNow;
var ttl = (long)timeUntilNextRun.TotalSeconds;
var data = new
{
imei = heartRate.Serialno,
create_time = now.ToString("yyyy-MM-dd HH:mm:ss"),
ttl,
next_run_time = nextRunTime.ToString("yyyy-MM-dd HH:mm:ss")
};
var result = JsonConvert.SerializeObject(data);
await _serviceEtcd.PutValAsync(key, result, ttl, false).ConfigureAwait(false);

await SetIntervalTriggerAsync(fetalMovementKey, heartRate.Serialno, ttl);
}
#endregion

#region 计算胎心数据(按心率时间LastUpdate)
var commonPHR = await _serviceTDengine.GetLastAsync<PregnancyCommonHeartRateModel>(heartRate.Serialno);
if (commonPHR == null)
#endregion
//_logger.LogInformation($"{heartRate.Serialno} 触发定时建模");

// 高频心率采样间隔 highFreqSampleInterval = highFreqSampleInterval+5,增加5秒兼容
var highFreqSampleInterval = (int)watchConfig!["highFreqSampleInterval"]! + 5;
// 触发高频监测的心率上限值
var triggerHighFreqHigh = (int)watchConfig["triggerHighFreqHigh"]!;
// 触发高频监测的心率下限值
var triggerHighFreqLow = (int)watchConfig["triggerHighFreqLow"]!;
//停止高频心率采样心率连续正常次数
var stopHighFreqSampleCount = (int)watchConfig["stopHighFreqSampleCount"]!;
// 高频心率采集时长 0 为持续采集,非零为高频心率的采集时长
var highFreqSampleTimes = (int)watchConfig["highFreqSampleTimes"]!;
// 告警上限阀值
var upperAlarmThreshold = (int)watchConfig["upperAlarmThreshold"]!;
// 告警下限阀值
var lowerAlarmThreshold = (int)watchConfig["lowerAlarmThreshold"]!;
// EDOC
var edoc = DateTimeUtil.ToDateTime(watchConfig!["EDOC"]!.ToString());
// interval (分钟) 固定15分钟
var intervalFHR = 15;//int)watchConfig["interval"]!;



var phr = await _serviceTDengine.GetBySerialNoAsync<PregnancyHeartRateModel>(heartRate.Serialno, 7);
if (phr.Count >= 30)
{
// 处理孕妇业务,计算一般心率并下发
commonPHR = await _serviceTDengine.InitPregnancyCommonHeartRateModeAsync(heartRate.Serialno, highFreqSampleInterval: highFreqSampleInterval);
// 建模完成
var flag = await _serviceIotApi.SetFetalConfig(heartRate.Serialno, 1, commonPHR!.MaxValue, commonPHR!.MinValue);
_logger.LogInformation($"{heartRate.Serialno} 记录数量足够,建模完成");
// 保存到TDengine数据库
await _serviceTDengine.InsertAsync<PregnancyCommonHeartRateModel>("hm_pchr", commonPHR!);
_logger.LogInformation($"保存TDengine完成");
}
// 获取最近的两个记录,并计算它们的 LastUpdate 时间差
var firstTwoPhr = phr.OrderByDescending(i => i.LastUpdate).Take(2).Select(i => i.LastUpdate).ToList();
var timeDiff = firstTwoPhr[0] - firstTwoPhr[1];

// 如果需要,将时间差转换为秒
var timeDiffInSeconds = timeDiff.TotalSeconds;
#region 定时计算胎动数据触发器两小时间隔开始
var fetalMovementKey = $"health_monitor/schedule_push/cal_fetal_movement/imei/{heartRate.Serialno}";
///// 计算 0 点秒数
var fetalMovementLastUpdate = (DateTime)heartRate.LastUpdate!;
DateTime fmScheduleNow = DateTime.Now;
// 小于两小时
if (fmScheduleNow > fetalMovementLastUpdate && (fmScheduleNow - fetalMovementLastUpdate).TotalHours <= 2)
{
var rand = new Random();
var pushSec = rand.Next(59);
int pushMin = int.TryParse(heartRate.Serialno.AsSpan(heartRate.Serialno.Length - 1), out pushMin) ? pushMin : 10;

// 高频统计结束时间
var FreqStatsEnd = DateTime.Now;
var scheduleHourDiff = SCHEDULE_HOUR
.Where(h => h > fetalMovementLastUpdate.Hour)
.OrderBy(h => h - fetalMovementLastUpdate.Hour)
.FirstOrDefault() - fetalMovementLastUpdate.Hour;
var scheduleTime = fetalMovementLastUpdate.AddHours(scheduleHourDiff);

DateTime nextRunTime = new(scheduleTime.Year, scheduleTime.Month, scheduleTime.Day, scheduleTime.Hour, pushMin, pushSec);
TimeSpan timeUntilNextRun = nextRunTime - fmScheduleNow;
var ttl = (long)timeUntilNextRun.TotalSeconds;

// 高频心率启动
if (timeDiffInSeconds <= highFreqSampleInterval)
{
await SetIntervalTriggerAsync(fetalMovementKey, heartRate.Serialno, ttl);
}
#endregion

var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno);
if (phrFreqstatus == null)
#region 计算胎心数据(按心率时间LastUpdate)
var commonPHR = await _serviceTDengine.GetLastAsync<PregnancyCommonHeartRateModel>(heartRate.Serialno);
if (commonPHR == null)
{
/// 设置高频状态
_logger.LogInformation($"{heartRate.Serialno} 进入高频心率启动状态 timeDiffInSeconds {timeDiffInSeconds},highFreqSampleInterval:{highFreqSampleInterval}");
// 设置高频状态
_logger.LogInformation($"{heartRate.Serialno} phr.Count {phr.Count}");
var freqFirstPhr = phr.OrderByDescending(i => i.LastUpdate).First();
await _deviceCacheMgr.SetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno, freqFirstPhr);
_logger.LogInformation($"{heartRate.Serialno} 设置高频状态");
phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno);
// 处理孕妇业务,计算一般心率并下发
commonPHR = await _serviceTDengine.InitPregnancyCommonHeartRateModeAsync(heartRate.Serialno, highFreqSampleInterval: highFreqSampleInterval);
// 建模完成
var flag = await _serviceIotApi.SetFetalConfig(heartRate.Serialno, 1, commonPHR!.MaxValue, commonPHR!.MinValue);
_logger.LogInformation($"{heartRate.Serialno} 记录数量足够,建模完成");
// 保存到TDengine数据库
await _serviceTDengine.InsertAsync<PregnancyCommonHeartRateModel>("hm_pchr", commonPHR!);
_logger.LogInformation($"保存TDengine完成");
}
/// phr PregnancyHeartRate 连续连续正常次数个值都是正常(大于等于triggerHighFreqLow,少于等于triggerHighFreqHig),
/// 取连续正常次数正常值的平均值,推送到api/v1/open/OpenIot/SetFetalHeartRateConfig
#region 检查是否连续12个心率值都是正常的
// 获取最近连续正常次数个心率记录
_logger.LogInformation($"{heartRate.Serialno} 设置 stopHighFreqSampleCount {stopHighFreqSampleCount}");

var lastPhr = phr.OrderByDescending(i => i.LastUpdate).Take(stopHighFreqSampleCount).ToList();
_logger.LogInformation($"{heartRate.Serialno} 设置 lastPhr {lastPhr.Count}");
_logger.LogInformation($"{heartRate.Serialno} 设置 triggerHighFreqLow {triggerHighFreqLow}");
_logger.LogInformation($"{heartRate.Serialno} 设置 triggerHighFreqHigh {triggerHighFreqHigh}");
// 检查是否连续12个值都是正常的
if (lastPhr.All(i => i.PregnancyHeartRate >= triggerHighFreqLow && i.PregnancyHeartRate <= triggerHighFreqHigh))

// 获取最近的两个记录,并计算它们的 LastUpdate 时间差
var firstTwoPhr = phr.OrderByDescending(i => i.LastUpdate).Take(2).Select(i => i.LastUpdate).ToList();
var timeDiff = firstTwoPhr[0] - firstTwoPhr[1];

// 如果需要,将时间差转换为秒
var timeDiffInSeconds = timeDiff.TotalSeconds;

// 高频统计结束时间
var FreqStatsEnd = DateTime.Now;


// 高频心率启动
if (timeDiffInSeconds <= highFreqSampleInterval)
{
var avgPhr = lastPhr.Select(i => i.PregnancyHeartRate).Average();
// 计算一般心率得到胎心系数
//await SaveAndPushFreqFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, avgPhr, DateTimeUtil.ConvertToTimeStamp(DateTime.Now).ToString());
// 高频数据不建模
FreqStatsEnd = (DateTime)heartRate.LastUpdate!;
_logger.LogInformation($"{heartRate.Serialno} 高频状态已经持续{(FreqStatsEnd - phrFreqstatus!.LastUpdate).TotalSeconds} 秒,连续 {stopHighFreqSampleCount} 次采样心率正常,将下发指令");

var freqSaveAndPushFetalHeartRate = await _deviceCacheMgr.GetBizIntervalAsync(heartRate.Serialno, "SaveAndPushFetalHeartRate");
// 高频不停,15分钟内只下发一条
if (string.IsNullOrEmpty(freqSaveAndPushFetalHeartRate))

var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno);
if (phrFreqstatus == null)
{
await SaveAndPushFetalHeartRateAsync(heartRate, commonPHR, upperAlarmThreshold, lowerAlarmThreshold, avgPhr, DateTimeUtil.ConvertToTimeStamp(phrFreqstatus!.LastUpdate).ToString(), phrFreqstatus!.LastUpdate, FreqStatsEnd);
// 删除高频状态的首条记录
await _deviceCacheMgr.DelPregnancyHeartRateFreqStatusAsync(heartRate.Serialno);
// 设置15分的SaveAndPushFetalHeartRate业务间隔
await _deviceCacheMgr.SetBizIntervalAsync(heartRate.Serialno, "SaveAndPushFetalHeartRate");
_logger.LogInformation($"{heartRate.Serialno} 连续 {stopHighFreqSampleCount} 次采样心率正常,结束高频心率状态, timeDiffInSeconds {timeDiffInSeconds},highFreqSampleInterval:{highFreqSampleInterval},高频状态持续{((DateTime)heartRate.LastUpdate - phrFreqstatus!.LastUpdate).TotalSeconds} 秒");
/// 设置高频状态
_logger.LogInformation($"{heartRate.Serialno} 进入高频心率启动状态 timeDiffInSeconds {timeDiffInSeconds},highFreqSampleInterval:{highFreqSampleInterval}");
// 设置高频状态
_logger.LogInformation($"{heartRate.Serialno} phr.Count {phr.Count}");
var freqFirstPhr = phr.OrderByDescending(i => i.LastUpdate).First();
await _deviceCacheMgr.SetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno, freqFirstPhr);
_logger.LogInformation($"{heartRate.Serialno} 设置高频状态");
phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno);
}
else
/// phr PregnancyHeartRate 连续连续正常次数个值都是正常(大于等于triggerHighFreqLow,少于等于triggerHighFreqHig),
/// 取连续正常次数正常值的平均值,推送到api/v1/open/OpenIot/SetFetalHeartRateConfig
#region 检查是否连续12个心率值都是正常的
// 获取最近连续正常次数个心率记录
_logger.LogInformation($"{heartRate.Serialno} 设置 stopHighFreqSampleCount {stopHighFreqSampleCount}");

var lastPhr = phr.OrderByDescending(i => i.LastUpdate).Take(stopHighFreqSampleCount).ToList();

_logger.LogInformation($"{heartRate.Serialno} 设置 lastPhr {lastPhr.Count}");
_logger.LogInformation($"{heartRate.Serialno} 设置 triggerHighFreqLow {triggerHighFreqLow}");
_logger.LogInformation($"{heartRate.Serialno} 设置 triggerHighFreqHigh {triggerHighFreqHigh}");
// 检查是否连续12个值都是正常的
if (lastPhr.All(i => i.PregnancyHeartRate >= triggerHighFreqLow && i.PregnancyHeartRate <= triggerHighFreqHigh))
{
_logger.LogWarning($"{heartRate.Serialno} 连续 {stopHighFreqSampleCount} 次采样心率正常,设备端应该结束高频状态,但设备端没有结束高频,平台高频15分钟内已经下发过指令");
}

}
else
{
_logger.LogInformation($"{heartRate.Serialno} 处于高频状态...");
}
#endregion
}
// 高频心率结束或平常心率
else
{
var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno);
// 高频心率结束
if (phrFreqstatus != null)
{
/// 在highFreqSampleTimes=0一直异常(大于等于triggerHighFreqLow,少于等于triggerHighFreqHig),
/// 取所有值的平均值,推送胎心数据到api/v1/open/OpenIot/SetFetalHeartRateConfig
if (highFreqSampleTimes == 0)
{
var avgPhr = phr.OrderByDescending(i => i.LastUpdate)
.Where(i => i.LastUpdate >= phrFreqstatus?.LastUpdate)
.Skip(1) // 去除首条
.Where(i => i.PregnancyHeartRate < triggerHighFreqLow || i.PregnancyHeartRate > triggerHighFreqHigh)
.Select(i => i.PregnancyHeartRate).Average();
// 推送胎心数据到 api/v1/open/OpenIot/SetFetalHeartRateConfig
var avgPhr = lastPhr.Select(i => i.PregnancyHeartRate).Average();
// 计算一般心率得到胎心系数
//await SaveAndPushFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, avgPhr);
//await SaveAndPushFreqFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, avgPhr, DateTimeUtil.ConvertToTimeStamp(DateTime.Now).ToString());
// 高频数据不建模
FreqStatsEnd = firstTwoPhr[1];
_logger.LogInformation($"{heartRate.Serialno} 高频状态已经持续{(FreqStatsEnd - phrFreqstatus!.LastUpdate).TotalSeconds} 秒,highFreqSampleTimes={highFreqSampleTimes}秒,即将结束高频状态,将下发指令");
FreqStatsEnd = (DateTime)heartRate.LastUpdate!;
_logger.LogInformation($"{heartRate.Serialno} 高频状态已经持续{(FreqStatsEnd - phrFreqstatus!.LastUpdate).TotalSeconds} 秒,连续 {stopHighFreqSampleCount} 次采样心率正常,将下发指令");

//await SaveAndPushFreqFetalHeartRateAsync(heartRate, commonPHR, upperAlarmThreshold, lowerAlarmThreshold, avgPhr, DateTimeUtil.ConvertToTimeStamp(phrFreqstatus!.LastUpdate).ToString());
await SaveAndPushFetalHeartRateAsync(heartRate, commonPHR, upperAlarmThreshold, lowerAlarmThreshold, avgPhr, DateTimeUtil.ConvertToTimeStamp(phrFreqstatus!.LastUpdate).ToString(), phrFreqstatus!.LastUpdate, FreqStatsEnd);
var freqSaveAndPushFetalHeartRate = await _deviceCacheMgr.GetBizIntervalAsync(heartRate.Serialno, "SaveAndPushFetalHeartRate");
// 高频不停,15分钟内只下发一条
if (string.IsNullOrEmpty(freqSaveAndPushFetalHeartRate))
{
await SaveAndPushFetalHeartRateAsync(heartRate, commonPHR, upperAlarmThreshold, lowerAlarmThreshold, avgPhr, DateTimeUtil.ConvertToTimeStamp(phrFreqstatus!.LastUpdate).ToString(), phrFreqstatus!.LastUpdate, FreqStatsEnd);
// 删除高频状态的首条记录
await _deviceCacheMgr.DelPregnancyHeartRateFreqStatusAsync(heartRate.Serialno);
// 设置15分的SaveAndPushFetalHeartRate业务间隔
await _deviceCacheMgr.SetBizIntervalAsync(heartRate.Serialno, "SaveAndPushFetalHeartRate");
_logger.LogInformation($"{heartRate.Serialno} 连续 {stopHighFreqSampleCount} 次采样心率正常,结束高频心率状态, timeDiffInSeconds {timeDiffInSeconds},highFreqSampleInterval:{highFreqSampleInterval},高频状态持续{((DateTime)heartRate.LastUpdate - phrFreqstatus!.LastUpdate).TotalSeconds} 秒");
}
else
{
_logger.LogWarning($"{heartRate.Serialno} 连续 {stopHighFreqSampleCount} 次采样心率正常,设备端应该结束高频状态,但设备端没有结束高频,平台高频15分钟内已经下发过指令");
}

}

/// 在highFreqSampleTimes>0一直异常(大于等于triggerHighFreqLow,少于等于triggerHighFreqHig),
/// 取所有值的平均值,推送胎心数据到api/v1/open/OpenIot/SetFetalHeartRateConfig
if (highFreqSampleTimes > 0 && heartRate.LastUpdate >= (phrFreqstatus?.LastUpdate.AddSeconds(highFreqSampleTimes)))
else
{

// 获取高频心率数据个数
var filterPhr = phr
.Where(i => i.LastUpdate >= phrFreqstatus?.LastUpdate)
.Skip(1)
.ToList();

//var freqCollection = new List<PregnancyHeartRateModel>();
//PregnancyHeartRateModel? previousItem = null;

//foreach (var item in filterPhr)
//{
// if (previousItem != null)
// {
// var timeNextDiff = (previousItem!.LastUpdate - item.LastUpdate).TotalSeconds;
// if (timeNextDiff <= highFreqSampleInterval)
// {
// freqCollection.Add(item);
// }
// }
// previousItem = item;
//}
_logger.LogInformation($"{heartRate.Serialno} {phrFreqstatus?.LastUpdate.ToString("yyyy-MM-dd HH:mm:ss")}--{firstTwoPhr[1].ToString("yyyy-MM-dd HH:mm:ss")} 产生高频心率数量 {filterPhr.Count} 条");

// 高频心率数据大于等于stopHighFreqSampleCount/12个才计算胎心数据
if (filterPhr.Count >= stopHighFreqSampleCount)
_logger.LogInformation($"{heartRate.Serialno} 处于高频状态...");
}
#endregion
}
// 高频心率结束或平常心率
else
{
var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno);
// 高频心率结束
if (phrFreqstatus != null)
{
/// 在highFreqSampleTimes=0一直异常(大于等于triggerHighFreqLow,少于等于triggerHighFreqHig),
/// 取所有值的平均值,推送胎心数据到api/v1/open/OpenIot/SetFetalHeartRateConfig
if (highFreqSampleTimes == 0)
{
var avgPhr = filterPhr
.OrderByDescending(i => i.LastUpdate)
.Take(stopHighFreqSampleCount) // 计算最后12条
//.Where(i => i.PregnancyHeartRate < triggerHighFreqLow || i.PregnancyHeartRate > triggerHighFreqHigh)
.Select(i => i.PregnancyHeartRate).Average();
var avgPhr = phr.OrderByDescending(i => i.LastUpdate)
.Where(i => i.LastUpdate >= phrFreqstatus?.LastUpdate)
.Skip(1) // 去除首条
.Where(i => i.PregnancyHeartRate < triggerHighFreqLow || i.PregnancyHeartRate > triggerHighFreqHigh)
.Select(i => i.PregnancyHeartRate).Average();
// 推送胎心数据到 api/v1/open/OpenIot/SetFetalHeartRateConfig
// 计算一般心率得到胎心系数
// 高频数据不建模
FreqStatsEnd = firstTwoPhr[1];
_logger.LogInformation($"{heartRate.Serialno} 高频状态已经持续{(FreqStatsEnd - phrFreqstatus!.LastUpdate).TotalSeconds} 秒,超过约定的 {highFreqSampleTimes} 秒,即将结束高频状态,将下发指令");
_logger.LogInformation($"{heartRate.Serialno} 高频状态已经持续{(FreqStatsEnd - phrFreqstatus!.LastUpdate).TotalSeconds} 秒,highFreqSampleTimes={highFreqSampleTimes}秒,即将结束高频状态,将下发指令");

//await SaveAndPushFreqFetalHeartRateAsync(heartRate, commonPHR, upperAlarmThreshold, lowerAlarmThreshold, avgPhr, DateTimeUtil.ConvertToTimeStamp(phrFreqstatus!.LastUpdate).ToString());
await SaveAndPushFetalHeartRateAsync(heartRate, commonPHR, upperAlarmThreshold, lowerAlarmThreshold, avgPhr, DateTimeUtil.ConvertToTimeStamp(phrFreqstatus!.LastUpdate).ToString(), phrFreqstatus!.LastUpdate, FreqStatsEnd);

}

/// 在highFreqSampleTimes>0一直异常(大于等于triggerHighFreqLow,少于等于triggerHighFreqHig),
/// 取所有值的平均值,推送胎心数据到api/v1/open/OpenIot/SetFetalHeartRateConfig
if (highFreqSampleTimes > 0 && heartRate.LastUpdate >= (phrFreqstatus?.LastUpdate.AddSeconds(highFreqSampleTimes)))
{


// 获取高频心率数据个数
var filterPhr = phr
.Where(i => i.LastUpdate >= phrFreqstatus?.LastUpdate)
.Skip(1)
.ToList();

//var freqCollection = new List<PregnancyHeartRateModel>();
//PregnancyHeartRateModel? previousItem = null;

//foreach (var item in filterPhr)
//{
// if (previousItem != null)
// {
// var timeNextDiff = (previousItem!.LastUpdate - item.LastUpdate).TotalSeconds;
// if (timeNextDiff <= highFreqSampleInterval)
// {
// freqCollection.Add(item);
// }
// }
// previousItem = item;
//}

_logger.LogInformation($"{heartRate.Serialno} {phrFreqstatus?.LastUpdate.ToString("yyyy-MM-dd HH:mm:ss")}--{firstTwoPhr[1].ToString("yyyy-MM-dd HH:mm:ss")} 产生高频心率数量 {filterPhr.Count} 条");

// 高频心率数据大于等于stopHighFreqSampleCount/12个才计算胎心数据
if (filterPhr.Count >= stopHighFreqSampleCount)
{
var avgPhr = filterPhr
.OrderByDescending(i => i.LastUpdate)
.Take(stopHighFreqSampleCount) // 计算最后12条
//.Where(i => i.PregnancyHeartRate < triggerHighFreqLow || i.PregnancyHeartRate > triggerHighFreqHigh)
.Select(i => i.PregnancyHeartRate).Average();

// 高频数据不建模
FreqStatsEnd = firstTwoPhr[1];
_logger.LogInformation($"{heartRate.Serialno} 高频状态已经持续{(FreqStatsEnd - phrFreqstatus!.LastUpdate).TotalSeconds} 秒,超过约定的 {highFreqSampleTimes} 秒,即将结束高频状态,将下发指令");

await SaveAndPushFetalHeartRateAsync(heartRate, commonPHR, upperAlarmThreshold, lowerAlarmThreshold, avgPhr, DateTimeUtil.ConvertToTimeStamp(phrFreqstatus!.LastUpdate).ToString(), phrFreqstatus!.LastUpdate, FreqStatsEnd);

}
else
{
_logger.LogInformation($"{heartRate.Serialno} 高频心率的数据不足{stopHighFreqSampleCount}条,不进行胎心计算");

}
}
//不满足持续10分钟highFreqSampleTimes
else
{
_logger.LogInformation($"{heartRate.Serialno} 高频心率的数据不足{stopHighFreqSampleCount}条,不进行胎心计算");
_logger.LogInformation($"{heartRate.Serialno} 高频持续时间不足{highFreqSampleTimes},只持续{(firstTwoPhr[1] - phrFreqstatus!.LastUpdate).TotalSeconds} 秒");
}

// 删除高频状态的首条记录
await _deviceCacheMgr.DelPregnancyHeartRateFreqStatusAsync(heartRate.Serialno);

_logger.LogInformation($"{heartRate.Serialno} 超时结束高频心率状态 timeDiffInSeconds {timeDiffInSeconds},highFreqSampleInterval:{highFreqSampleInterval},高频状态持续{(firstTwoPhr[1] - phrFreqstatus!.LastUpdate).TotalSeconds} 秒");

// 计算本次平常心率的胎心数据
//await CalculateNormalFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, intervalFHR, commonPHR);
// 使用延后计算
var fhrScheduleKey = $"health_monitor/schedule_push/cal_fetal_heart_rate/imei/{heartRate.Serialno}";
var fhrScheduleTTL = 10;
await SetIntervalTriggerAsync(fhrScheduleKey, heartRate.Serialno, fhrScheduleTTL);
}
//不满足持续10分钟highFreqSampleTimes
// 平常心率
else
{
_logger.LogInformation($"{heartRate.Serialno} 高频持续时间不足{highFreqSampleTimes},只持续{(firstTwoPhr[1] - phrFreqstatus!.LastUpdate).TotalSeconds} 秒");
// 计算本次平常心率的胎心数据
//await CalculateNormalFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, intervalFHR, commonPHR);
// 使用延后计算
var fhrScheduleKey = $"health_monitor/schedule_push/cal_fetal_heart_rate/imei/{heartRate.Serialno}";
var fhrScheduleTTL = 10;
await SetIntervalTriggerAsync(fhrScheduleKey, heartRate.Serialno, fhrScheduleTTL);
}

// 删除高频状态的首条记录
await _deviceCacheMgr.DelPregnancyHeartRateFreqStatusAsync(heartRate.Serialno);

_logger.LogInformation($"{heartRate.Serialno} 超时结束高频心率状态 timeDiffInSeconds {timeDiffInSeconds},highFreqSampleInterval:{highFreqSampleInterval},高频状态持续{(firstTwoPhr[1] - phrFreqstatus!.LastUpdate).TotalSeconds} 秒");

// 计算本次平常心率的胎心数据
await CalculateNormalFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, intervalFHR, commonPHR);

}
// 平常心率
else
{
// 计算本次平常心率的胎心数据
await CalculateNormalFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, intervalFHR, commonPHR);
}
}

#endregion
}
else
{
_logger.LogInformation($"{heartRate.Serialno} 记录不足30条,建模中");
#endregion
}
else
{
_logger.LogInformation($"{heartRate.Serialno} 记录不足30条,建模中");
}
}

}

//try
//{



}
catch (Exception ex)
{

//}
//catch (Exception ex)
//{

// _logger.LogError($"{heartRate.Serialno} 处理孕妇心率数据异常 \n{ex.Message}\n{ex.StackTrace}");
//}
_logger.LogError($"{heartRate.Serialno} 处理孕妇心率数据异常 \n{ex.Message}\n{ex.StackTrace}");
}

}
/// <summary>


+ 183
- 0
HealthMonitor.WebApi/Worker.cs View File

@@ -337,6 +337,38 @@ namespace HealthMonitor.WebApi
}
*/

var watchConfig = await _deviceCacheMgr.GetGpsDeviceWatchConfigCacheObjectBySerialNoAsync(imeiDel, "0067");
_logger.LogInformation($"触发平常心率计算胎心,设备配置{JsonConvert.SerializeObject(watchConfig)}");
var isFetalHeartEnable = watchConfig != null && (int)watchConfig["enabled"]! == 1;

if (isFetalHeartEnable)
{
// 告警上限阀值
var upperAlarmThreshold = (int)watchConfig!["upperAlarmThreshold"]!;
// 告警下限阀值
var lowerAlarmThreshold = (int)watchConfig["lowerAlarmThreshold"]!;

var commonPHR = await _serviceTDengine.GetLastAsync<PregnancyCommonHeartRateModel>(imeiDel);

// 最后一条孕妇心率
var phr= await _serviceTDengine.GetLastAsync<PregnancyHeartRateModel>(imeiDel);

HisGpsHeartRate heartRate = new()
{
CreateTime = phr.CreateTime,
DeviceKey = phr.DeviceKey,
HeartRate = phr.PregnancyHeartRate,
HeartRateId = phr.PregnancyHeartRateId,
IsDisplay = phr.IsDisplay ? 1 : 0,
MessageId = phr.MessageId,
LastUpdate = phr.LastUpdate,
Method = phr.Method,
PersonId = phr.PersonId,
Serialno = phr.SerialNumber
};
var intervalFHR = 15;
await CalculateNormalFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, intervalFHR, commonPHR);
}
}

//health_monitor/schedule_push/cal_fetal_movement/imei/
@@ -930,6 +962,157 @@ namespace HealthMonitor.WebApi
return timeRanges.Any(range => now >= range.Start && now <= range.End);
}

private async Task CalculateNormalFetalHeartRateAsync(HisGpsHeartRate heartRate, int upperAlarmThreshold, int lowerAlarmThreshold, int intervalFHR, PregnancyCommonHeartRateModel? commonPHR)
{
// 上15分钟的数据
// 获取当前时间
DateTime nowInterval = (DateTime)heartRate.LastUpdate!;

// 计算last_update到上一间隔的分钟数
int minutesToSubtract = nowInterval.Minute % intervalFHR;

// 计算上一间隔的时间
DateTime previousInterval = nowInterval.AddMinutes(-minutesToSubtract).AddSeconds(-nowInterval.Second).AddMilliseconds(-nowInterval.Millisecond);

// 使用 last_update 上一刻
var sampleTimeFHR = DateTimeUtil.ConvertToTimeStamp(previousInterval).ToString();

// 计算last_update到下一间隔的分钟数
int minutesToAdd = intervalFHR - (nowInterval.Minute % intervalFHR);
if (minutesToAdd == intervalFHR)
{
minutesToAdd = 0; // 如果已经是间隔,则不需要增加分钟
}

// 计算下一间隔的时间
DateTime nextInterval = nowInterval.AddMinutes(minutesToAdd)
.AddSeconds(-nowInterval.Second)
.AddMilliseconds(-nowInterval.Millisecond);


var daysPhr = await _serviceTDengine.GetBySerialNoAsync<PregnancyHeartRateModel>(heartRate.Serialno, 7);

var normalPhrStatStartTime = nextInterval.AddMinutes(-intervalFHR);

var normalPhrStatEndTime = nextInterval;

_logger.LogInformation($"{heartRate.Serialno} 计算胎心数据, 周期:{normalPhrStatStartTime}-{normalPhrStatEndTime} ");
var filteredPhr = daysPhr
// 使用 last_update 下一刻
.Where(i => i.LastUpdate <= normalPhrStatEndTime && i.LastUpdate >= normalPhrStatStartTime)
.ToList();
if (filteredPhr.Count == 0)
{
_logger.LogWarning($"{heartRate.Serialno} 周期:{normalPhrStatStartTime}-{normalPhrStatEndTime} 孕妇心率数据不足,{filteredPhr.Count}条记录");
return;
}
var phrValue = filteredPhr.Count == 1
? filteredPhr.First().PregnancyHeartRate
: filteredPhr.Average(i => i.PregnancyHeartRate);

//await SaveAndPushFreqFetalHeartRateAsync(heartRate, commonPHR!, upperAlarmThreshold, lowerAlarmThreshold, phrValue, sampleTimeFHR);
await SaveAndPushFetalHeartRateAsync(heartRate, commonPHR!, upperAlarmThreshold, lowerAlarmThreshold, phrValue, sampleTimeFHR, normalPhrStatStartTime, normalPhrStatEndTime);
}

private async Task SaveAndPushFetalHeartRateAsync(HisGpsHeartRate heartRate, PregnancyCommonHeartRateModel commonPHR, int upperAlarmThreshold, int lowerAlarmThreshold, double phrValue, string sampleTime, DateTime statStartTime, DateTime statEndTime)
{
// 计算胎心=孕妇心率*系数
var fetalHeartRate = SafeType.SafeInt(phrValue * commonPHR?.StatModeAvgFprCoefficient!);
//fetalHeartRate = fetalHeartRate > 220 ? 220 : fetalHeartRate; // 胎心的最大值调整为220,超过都按该值220输出
if (fetalHeartRate >= 220)
{
// 先使用最小系数计算
var statMaxValueFprCoefficient = commonPHR?.StatMaxValueFprCoefficient!;
var statMinValueFprCoefficient = commonPHR?.StatMinValueFprCoefficient!;
var coefficient = statMaxValueFprCoefficient < statMinValueFprCoefficient ? statMaxValueFprCoefficient : statMinValueFprCoefficient;
fetalHeartRate = SafeType.SafeInt(phrValue * coefficient);
if (fetalHeartRate < 220)
{
_logger.LogWarning($"{heartRate.Serialno} 使用极值系数 {coefficient} ,建模数据可能出现异常,请检查");
}
else
{
fetalHeartRate = 220;
_logger.LogWarning($"{heartRate.Serialno} 使用所有系数都不能放映实际,建模数据可能出现异常,请检查");
}
}

var isAbnormal = fetalHeartRate > upperAlarmThreshold ? 1 : (fetalHeartRate < lowerAlarmThreshold ? 2 : 0);
var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno);
if (phrFreqstatus == null) isAbnormal = 0;

//if (!isFreq)
//{
// statStartTime = heartRate.LastUpdate;
//
//}
// 保存到 数据服务 MySQL 数据库
HisGpsFetalHeartRate gpsFetalHeartRate = new()
{
FetalHeartRateId = Guid.NewGuid().ToString("D"),
PersonId = commonPHR!.PersonId,
Serialno = heartRate.Serialno,
HeartRate = fetalHeartRate,
SampleTime = sampleTime.Length > 10 ? sampleTime.Substring(0, 10) : sampleTime,
IsAbnormal = isAbnormal,
StatStartTime = statStartTime,
StatEndTime = statEndTime,//commonPHR.StatEndTime,
CreateTime = DateTime.Now,
Method = 1,
IsDisplay = 1,
DeviceKey = commonPHR!.DeviceKey
};
await _hisFetalHeartApiClient.AddAsync(gpsFetalHeartRate).ConfigureAwait(false);

// 推送到api/v1/open/OpenIot/SetFetalHeartRateConfig
await _serviceIotApi.SetFetalHeartRateConfig(heartRate.Serialno, fetalHeartRate, sampleTime, isAbnormal);


var device = await _deviceCacheMgr.GetDeviceBySerialNoAsync(heartRate.Serialno).ConfigureAwait(false);
var fhrMsgId = $"{heartRate.Serialno}-{sampleTime}-{Guid.NewGuid().ToString("D")[^3..]}";
var fhrMsgTime = DateTimeUtil.GetDateTimeFromUnixTimeMilliseconds(long.Parse(sampleTime.Length < 13 ? sampleTime.PadRight(13, '0') : sampleTime)).ToString("yyyy-MM-dd HH:mm:ss");
// 胎心数据推送到第三方
var topic = "topic.push.third";
var fhrThridMsg = new
{
messageId = fhrMsgId,
topic = topic,
time = fhrMsgTime,
data = new
{
imei = heartRate.Serialno,
value = fetalHeartRate,
isAbnormal,
type = "fetalHeart"
}
};
await _serviceMqProcess.ProcessIMEIEventMessageAsync(fhrMsgId, topic, 31, fhrThridMsg).ConfigureAwait(false);

// 胎心数据推送到微信
if (isAbnormal != 0)
{

topic = "topic.push.wx";
var fhrMsg = new
{
messageId = fhrMsgId,
topic = topic,
time = fhrMsgTime,
data = new
{
deviceId = device?.DeviceId,
imei = heartRate.Serialno,
alarmTypeId = 12,
alarmDeviceName = heartRate.Serialno,
alarmRemarks = JsonConvert.SerializeObject(new { fetalHeartValue = fetalHeartRate, isAbnormal = isAbnormal }),
address = string.Empty,
deviceKey = device?.DeviceId
}
};
await _serviceMqProcess.ProcessIMEIEventMessageAsync(fhrMsgId, topic, fhrMsg).ConfigureAwait(false);

}
}

}
}

Loading…
Cancel
Save