|
|
@@ -165,7 +165,7 @@ namespace HealthMonitor.Service.Resolver |
|
|
|
// interval (分钟) |
|
|
|
var intervalFHR = (int)watchConfig["interval"]!; |
|
|
|
|
|
|
|
var fetalHeartRateIsAbnormal = 0; |
|
|
|
|
|
|
|
|
|
|
|
var phr = await _serviceTDengine.GetBySerialNoAsync<PregnancyHeartRateModel>(heartRate.Serialno, 7); |
|
|
|
if (phr.Count >= 30) |
|
|
@@ -196,7 +196,7 @@ namespace HealthMonitor.Service.Resolver |
|
|
|
} |
|
|
|
#endregion |
|
|
|
|
|
|
|
#region 计算胎心和胎动数据 |
|
|
|
#region 计算胎心数据(按心率时间LastUpdate) |
|
|
|
var commonPHR = await _serviceTDengine.GetLastAsync<PregnancyCommonHeartRateModel>(heartRate.Serialno); |
|
|
|
if (commonPHR == null) |
|
|
|
{ |
|
|
@@ -209,8 +209,7 @@ namespace HealthMonitor.Service.Resolver |
|
|
|
await _serviceTDengine.InsertAsync<PregnancyCommonHeartRateModel>("hm_pchr", commonPHR!); |
|
|
|
_logger.LogInformation($"保存TDengine完成"); |
|
|
|
} |
|
|
|
#region 计算胎心数据(按心率时间LastUpdate) |
|
|
|
|
|
|
|
|
|
|
|
// 获取最近的两个记录,并计算它们的 LastUpdate 时间差 |
|
|
|
var firstTwoPhr = phr.OrderByDescending(i => i.LastUpdate).Take(2).Select(i => i.LastUpdate).ToList(); |
|
|
|
var timeDiff = firstTwoPhr[0] - firstTwoPhr[1]; |
|
|
@@ -220,6 +219,8 @@ namespace HealthMonitor.Service.Resolver |
|
|
|
|
|
|
|
// 高频统计结束时间 |
|
|
|
var FreqStatsEnd = DateTime.Now; |
|
|
|
|
|
|
|
|
|
|
|
// 高频心率启动 |
|
|
|
if (timeDiffInSeconds <= highFreqSampleInterval) |
|
|
|
{ |
|
|
@@ -249,7 +250,8 @@ namespace HealthMonitor.Service.Resolver |
|
|
|
// 高频数据不建模 |
|
|
|
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 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); |
|
|
|
|
|
|
|
// 删除高频状态的首条记录 |
|
|
|
await _deviceCacheMgr.DelPregnancyHeartRateFreqStatusAsync(heartRate.Serialno); |
|
|
@@ -259,10 +261,11 @@ namespace HealthMonitor.Service.Resolver |
|
|
|
} |
|
|
|
#endregion |
|
|
|
} |
|
|
|
// 高频心率结束或正常心率 |
|
|
|
// 高频心率结束或平常心率 |
|
|
|
else |
|
|
|
{ |
|
|
|
var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno); |
|
|
|
// 高频心率结束 |
|
|
|
if (phrFreqstatus != null) |
|
|
|
{ |
|
|
|
/// 在highFreqSampleTimes=0一直异常(大于等于triggerHighFreqLow,少于等于triggerHighFreqHig), |
|
|
@@ -282,7 +285,8 @@ namespace HealthMonitor.Service.Resolver |
|
|
|
FreqStatsEnd = firstTwoPhr[1]; |
|
|
|
_logger.LogInformation($"{heartRate.Serialno} 高频状态已经持续{(FreqStatsEnd - phrFreqstatus!.LastUpdate).TotalSeconds} 秒,highFreqSampleTimes={highFreqSampleTimes}秒,即将结束高频状态,将下发指令"); |
|
|
|
|
|
|
|
await SaveAndPushFreqFetalHeartRateAsync(heartRate, commonPHR, upperAlarmThreshold, lowerAlarmThreshold, avgPhr, DateTimeUtil.ConvertToTimeStamp(phrFreqstatus!.LastUpdate).ToString()); |
|
|
|
//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); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
@@ -290,279 +294,77 @@ namespace HealthMonitor.Service.Resolver |
|
|
|
/// 取所有值的平均值,推送胎心数据到api/v1/open/OpenIot/SetFetalHeartRateConfig |
|
|
|
if (highFreqSampleTimes > 0 && heartRate.LastUpdate >= (phrFreqstatus?.LastUpdate.AddSeconds(highFreqSampleTimes))) |
|
|
|
{ |
|
|
|
var filterPhr = phr |
|
|
|
.Where(i => i.LastUpdate >= phrFreqstatus?.LastUpdate); |
|
|
|
|
|
|
|
var avgPhr = filterPhr |
|
|
|
.OrderByDescending(i => i.LastUpdate) |
|
|
|
.Skip(1) // 去除首条 |
|
|
|
.Take(12) // 计算最后12条 |
|
|
|
//.Where(i => i.PregnancyHeartRate < triggerHighFreqLow || i.PregnancyHeartRate > triggerHighFreqHigh) |
|
|
|
.Select(i => i.PregnancyHeartRate).Average(); |
|
|
|
// 推送胎心数据到 api/v1/open/OpenIot/SetFetalHeartRateConfig |
|
|
|
// 计算一般心率得到胎心系数 |
|
|
|
//await SaveAndPushFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, avgPhr); |
|
|
|
//await SaveAndPushFreqFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, avgPhr, DateTimeUtil.ConvertToTimeStamp(DateTime.Now).ToString()); |
|
|
|
//await SaveAndPushFreqFetalHeartRateAsync(heartRate, commonPHR, upperAlarmThreshold, lowerAlarmThreshold, avgPhr, DateTimeUtil.ConvertToTimeStamp(DateTime.Now).ToString()); |
|
|
|
// 高频数据不建模 |
|
|
|
FreqStatsEnd = firstTwoPhr[1]; |
|
|
|
_logger.LogInformation($"{heartRate.Serialno} 高频状态已经持续{(FreqStatsEnd - phrFreqstatus!.LastUpdate).TotalSeconds} 秒,超过约定的 {highFreqSampleTimes} 秒,即将结束高频状态,将下发指令"); |
|
|
|
|
|
|
|
await SaveAndPushFreqFetalHeartRateAsync(heartRate, commonPHR, upperAlarmThreshold, lowerAlarmThreshold, avgPhr, DateTimeUtil.ConvertToTimeStamp(phrFreqstatus!.LastUpdate).ToString()); |
|
|
|
} |
|
|
|
|
|
|
|
// 删除高频状态的首条记录 |
|
|
|
await _deviceCacheMgr.DelPregnancyHeartRateFreqStatusAsync(heartRate.Serialno); |
|
|
|
|
|
|
|
_logger.LogInformation($"{heartRate.Serialno} 超时结束高频心率状态 timeDiffInSeconds {timeDiffInSeconds},highFreqSampleInterval:{highFreqSampleInterval},高频状态持续{(firstTwoPhr[1] - phrFreqstatus!.LastUpdate).TotalSeconds} 秒"); |
|
|
|
} |
|
|
|
// 正常心率 |
|
|
|
else |
|
|
|
{ |
|
|
|
|
|
|
|
// 上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; |
|
|
|
|
|
|
|
var normalPhrStatEndTime = nextInterval.AddMinutes(-intervalFHR); |
|
|
|
|
|
|
|
_logger.LogInformation($"{heartRate.Serialno} 计算胎心数据, 周期:{normalPhrStatStartTime}-{normalPhrStatEndTime} "); |
|
|
|
var filteredPhr = daysPhr |
|
|
|
// 使用 last_update 下一刻 |
|
|
|
.Where(i => i.LastUpdate <= normalPhrStatStartTime && i.LastUpdate >= normalPhrStatEndTime) |
|
|
|
.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); |
|
|
|
|
|
|
|
var fetalHeartRate = SafeType.SafeInt(phrValue * commonPHR?.StatModeAvgFprCoefficient!); |
|
|
|
|
|
|
|
|
|
|
|
fetalHeartRateIsAbnormal = fetalHeartRate > upperAlarmThreshold ? 1 : (fetalHeartRate < lowerAlarmThreshold ? 2 : 0); |
|
|
|
fetalHeartRateIsAbnormal = 0;// 不是高频数据,按正常值 |
|
|
|
/* HisGpsFetalHeartRate gpsFetalHeartRate = new() |
|
|
|
{ |
|
|
|
FetalHeartRateId = Guid.NewGuid().ToString("D"), |
|
|
|
PersonId = commonPHR!.PersonId, |
|
|
|
Serialno = heartRate.Serialno, |
|
|
|
HeartRate = fetalHeartRate, |
|
|
|
SampleTime = sampleTimeFHR.Length > 10 ? sampleTimeFHR.Substring(0, 10) : sampleTimeFHR, |
|
|
|
IsAbnormal = fetalHeartRateIsAbnormal, |
|
|
|
StatStartTime = filteredPhr.OrderBy(i => i.LastUpdate).First().LastUpdate, |
|
|
|
StatEndTime = filteredPhr.OrderBy(i => i.LastUpdate).Last().LastUpdate, |
|
|
|
CreateTime = DateTime.Now, |
|
|
|
Method = 1, |
|
|
|
IsDisplay = 1, |
|
|
|
DeviceKey = commonPHR!.DeviceKey |
|
|
|
}; |
|
|
|
// 保存到 数据服务 MySQL 数据库 |
|
|
|
await _hisFetalHeartApiClient.AddAsync(gpsFetalHeartRate).ConfigureAwait(false); |
|
|
|
|
|
|
|
// 推送到api/v1/open/OpenIot/SetFetalHeartRateConfig |
|
|
|
await _serviceIotApi.SetFetalHeartRateConfig(heartRate.Serialno, fetalHeartRate, sampleTimeFHR, fetalHeartRateIsAbnormal); |
|
|
|
|
|
|
|
// 推送送微信 |
|
|
|
if (fetalHeartRateIsAbnormal != 0) |
|
|
|
{ |
|
|
|
var device = await _deviceCacheMgr.GetDeviceBySerialNoAsync(heartRate.Serialno).ConfigureAwait(false); |
|
|
|
var fhrMsgId = $"{heartRate.Serialno}-{sampleTimeFHR}-{Guid.NewGuid().ToString("D")[^3..]}"; |
|
|
|
var topic = "topic.push.wx"; |
|
|
|
var fhrMsg = new |
|
|
|
{ |
|
|
|
messageId = fhrMsgId, |
|
|
|
topic = topic, |
|
|
|
time = DateTimeUtil.GetDateTimeFromUnixTimeMilliseconds(long.Parse(sampleTimeFHR.Length < 13 ? sampleTimeFHR.PadRight(13, '0') : sampleTimeFHR)).ToString("yyyy-MM-dd HH:mm:ss"), |
|
|
|
data = new |
|
|
|
{ |
|
|
|
deviceId = device?.DeviceId, |
|
|
|
imei = heartRate.Serialno, |
|
|
|
alarmTypeId = 12, |
|
|
|
alarmDeviceName = heartRate.Serialno, |
|
|
|
alarmRemarks = JsonConvert.SerializeObject(new { fetalHeartValue = fetalHeartRate, isAbnormal = fetalHeartRateIsAbnormal }), |
|
|
|
address = string.Empty, |
|
|
|
deviceKey = device?.DeviceId |
|
|
|
} |
|
|
|
}; |
|
|
|
await _serviceMqProcess.ProcessIMEIEventMessageAsync(fhrMsgId, topic, fhrMsg).ConfigureAwait(false); |
|
|
|
} |
|
|
|
|
|
|
|
*/ |
|
|
|
await SaveAndPushFreqFetalHeartRateAsync(heartRate, commonPHR!, upperAlarmThreshold, lowerAlarmThreshold, phrValue, sampleTimeFHR, false); |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#endregion |
|
|
|
|
|
|
|
#region 计算胎动数据(按心率时间LastUpdate) |
|
|
|
/** |
|
|
|
_logger.LogInformation($"{heartRate.Serialno} 计算胎动数据 "); |
|
|
|
|
|
|
|
var fetalMovementNow = (DateTime)heartRate.LastUpdate!; |
|
|
|
|
|
|
|
var midNight = new DateTime(fetalMovementNow.Year, fetalMovementNow.Month, fetalMovementNow.Day, 0, 0, 0); |
|
|
|
|
|
|
|
TimeSpan fetalMovementTS = fetalMovementNow - midNight; |
|
|
|
|
|
|
|
// 当天每隔2小时的段数,取整数部分 |
|
|
|
int segmentCountFM = (int)(fetalMovementTS.TotalHours / 2); |
|
|
|
|
|
|
|
for (int i = 0; i < segmentCountFM; i++) |
|
|
|
{ |
|
|
|
// 每两小时 |
|
|
|
var fetalMovementSampleTime = DateTimeUtil.ConvertToTimeStamp(midNight.AddHours(2 * i)).ToString()[..10]; |
|
|
|
|
|
|
|
// 统计开始时间 |
|
|
|
var statStartTime = midNight.AddHours(2 * i); |
|
|
|
// 统计结束时间 |
|
|
|
var statEndTime = midNight.AddHours(2 * (i+1)); |
|
|
|
|
|
|
|
var isFetalMovementExisted = await _deviceCacheMgr.FetalMovementIsExistedAsync(heartRate.Serialno, fetalMovementSampleTime); |
|
|
|
_logger.LogInformation($"{heartRate.Serialno} 胎动记录{isFetalMovementExisted},数据采样时间:{fetalMovementSampleTime}|{midNight.AddHours(2 * i).ToString("yyyy-MM-dd HH:mm:ss")}, 周期:{statStartTime}-{statEndTime} 开始"); |
|
|
|
|
|
|
|
if (!isFetalMovementExisted) |
|
|
|
{ |
|
|
|
/// 开始计算 |
|
|
|
var phrRange = phr.Where(i => i.LastUpdate >= statStartTime && i.LastUpdate<= statEndTime) |
|
|
|
.OrderByDescending(i => i.LastUpdate) |
|
|
|
.Select(i => i.LastUpdate) |
|
|
|
.ToList(); |
|
|
|
// 判断是否有持续佩戴 |
|
|
|
if (phrRange.Count >= 2) |
|
|
|
{ |
|
|
|
var duringMins = Math.Abs((phrRange.First()- statStartTime).TotalMinutes); |
|
|
|
//在餐后时间段(8:00~10:00,12:00~14:00,18:00~20:00,22:00~24:00)取中间值。其他时间段取正常起始值 |
|
|
|
bool isInTimeRanges = IsLastUpdateInTimeRanges(fetalMovementNow); |
|
|
|
|
|
|
|
int pregnancyWeeks = (DateTime.Now - edoc.AddDays(-280)).Days / 7; |
|
|
|
if (pregnancyWeeks >= 12 && pregnancyWeeks <= 50) |
|
|
|
|
|
|
|
// 获取高频心率数据个数 |
|
|
|
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 fetalMovementMap = _mgrFetalMovementNormalValueRangeCache.GetFetalMovements(); |
|
|
|
|
|
|
|
var fetalMovementMapValue = isInTimeRanges ? fetalMovementMap |
|
|
|
.Where(i => |
|
|
|
i.PregnancyPeriod![0] <= pregnancyWeeks && |
|
|
|
i.PregnancyPeriod[1] >= pregnancyWeeks) |
|
|
|
.Select(i => i.MedianMovement) |
|
|
|
.FirstOrDefault() |
|
|
|
: |
|
|
|
fetalMovementMap |
|
|
|
.Where(i => |
|
|
|
i.PregnancyPeriod![0] <= pregnancyWeeks && |
|
|
|
i.PregnancyPeriod[1] >= pregnancyWeeks) |
|
|
|
.Select(i => i.InitialMovement) |
|
|
|
.FirstOrDefault() |
|
|
|
; |
|
|
|
|
|
|
|
var fetalMovementValue = (fetalMovementMapValue * duringMins * 2) / 120; |
|
|
|
// 四舍五入 |
|
|
|
var fetalMovement = (int)Math.Round(fetalMovementValue, 0, MidpointRounding.AwayFromZero); |
|
|
|
// _logger.LogInformation($"{heartRate.Serialno} segmentCountFMIndex: {i} -- fetalMovementSampleTime:{fetalMovementSampleTime}|{midNight.AddHours(2 * i).ToString("yyyy-MM-dd HH:mm:ss")} -- statStartTime: {statStartTime} -- statEndTime: {statEndTime}-- isFetalMovementExisted: {isFetalMovementExisted} "); |
|
|
|
|
|
|
|
_logger.LogInformation($"{heartRate.Serialno} 胎动数据采样时间:{fetalMovementSampleTime}|{midNight.AddHours(2 * i).ToString("yyyy-MM-dd HH:mm:ss")}, 采样周期:{statStartTime}-{statEndTime}, 原始胎动值:{fetalMovementMapValue}, 佩戴时间 :{duringMins}|{statStartTime}-{phrRange.First()}, 胎动计算值:{fetalMovementValue}, 胎动最终值:{fetalMovement} 已完成."); |
|
|
|
|
|
|
|
// 获取胎心数据状态与胎动数据状态一致 |
|
|
|
var feltalMovementIsAbnormal = fetalHeartRateIsAbnormal; |
|
|
|
//var feltalMovementIsAbnormal = 0; |
|
|
|
// 推送到api/v1/open/OpenIot/SetFetalMovementConfig |
|
|
|
|
|
|
|
await _serviceIotApi.SetFetalMovementConfig(heartRate.Serialno, fetalMovement, fetalMovementSampleTime, feltalMovementIsAbnormal); |
|
|
|
|
|
|
|
// 保存到MySQL数据库 |
|
|
|
HisGpsFetalMovement fm = new() |
|
|
|
{ |
|
|
|
FetalMovementId = Guid.NewGuid().ToString("D"), |
|
|
|
PersonId = commonPHR!.PersonId, |
|
|
|
Serialno = heartRate.Serialno, |
|
|
|
CreateTime = DateTime.Now, |
|
|
|
IsAbnormal = feltalMovementIsAbnormal, |
|
|
|
FetalMovementValue = fetalMovement, |
|
|
|
SampleTime = fetalMovementSampleTime, |
|
|
|
Method = 1, |
|
|
|
IsDisplay = 1, |
|
|
|
DeviceKey = commonPHR!.DeviceKey |
|
|
|
}; |
|
|
|
await _hisFetalMovementApiClient.AddAsync(fm).ConfigureAwait(false); |
|
|
|
|
|
|
|
// 发送到微信 |
|
|
|
if (feltalMovementIsAbnormal != 0) |
|
|
|
{ |
|
|
|
var device = await _deviceCacheMgr.GetDeviceBySerialNoAsync(heartRate.Serialno).ConfigureAwait(false); |
|
|
|
var fmMsgId = $"{heartRate.Serialno}-{fetalMovementSampleTime}-{Guid.NewGuid().ToString("D")[^3..]}"; |
|
|
|
var topic = "topic.push.wx"; |
|
|
|
var fmMsg = new |
|
|
|
{ |
|
|
|
messageId = Guid.NewGuid().ToString("D"), |
|
|
|
topic = topic, |
|
|
|
time = DateTimeUtil.GetDateTimeFromUnixTimeMilliseconds(long.Parse(fetalMovementSampleTime.Length < 13 ? fetalMovementSampleTime.PadRight(13, '0') : fetalMovementSampleTime)).ToString("yyyy-MM-dd HH:mm:ss"), |
|
|
|
data = new |
|
|
|
{ |
|
|
|
deviceId = device?.DeviceId, |
|
|
|
imei = heartRate.Serialno, |
|
|
|
alarmTypeId = 12, |
|
|
|
alarmDeviceName = heartRate.Serialno, |
|
|
|
alarmRemarks = JsonConvert.SerializeObject(new { fetalMovementValue = fetalMovement, isAbnormal = feltalMovementIsAbnormal }), |
|
|
|
address = string.Empty, |
|
|
|
deviceKey = device?.DeviceId |
|
|
|
} |
|
|
|
}; |
|
|
|
await _serviceMqProcess.ProcessIMEIEventMessageAsync(fmMsgId, topic, fmMsg).ConfigureAwait(false); |
|
|
|
} |
|
|
|
// 设置入库缓存记录 |
|
|
|
await _deviceCacheMgr.SetFetalMovementAsync(heartRate.Serialno, fetalMovementSampleTime,fm); |
|
|
|
|
|
|
|
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 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); |
|
|
|
|
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
_logger.LogWarning($"{heartRate.Serialno} 孕周 {pregnancyWeeks},超出胎动计算范围"); |
|
|
|
_logger.LogInformation($"{heartRate.Serialno} 高频心率的数据不足{stopHighFreqSampleCount}条,不进行胎心计算"); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
//不满足持续10分钟highFreqSampleTimes |
|
|
|
else |
|
|
|
{ |
|
|
|
_logger.LogInformation($"{heartRate.Serialno} 胎动记录{isFetalMovementExisted},数据采样时间:{fetalMovementSampleTime}|{midNight.AddHours(2 * i).ToString("yyyy-MM-dd HH:mm:ss")}, 周期:{statStartTime}-{statEndTime} 不足两条,不能判断是否持续佩戴"); |
|
|
|
|
|
|
|
_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); |
|
|
|
|
|
|
|
} |
|
|
|
// 平常心率 |
|
|
|
else |
|
|
|
{ |
|
|
|
_logger.LogInformation($"{heartRate.Serialno} 胎动记录{isFetalMovementExisted},数据采样时间:{fetalMovementSampleTime}|{midNight.AddHours(2 * i).ToString("yyyy-MM-dd HH:mm:ss")}, 周期:{statStartTime}-{statEndTime} 已处理"); |
|
|
|
// 计算本次平常心率的胎心数据 |
|
|
|
await CalculateNormalFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, intervalFHR, commonPHR); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
*/ |
|
|
|
#endregion |
|
|
|
|
|
|
|
#endregion |
|
|
|
} |
|
|
@@ -588,68 +390,83 @@ namespace HealthMonitor.Service.Resolver |
|
|
|
//} |
|
|
|
|
|
|
|
} |
|
|
|
/// <summary> |
|
|
|
/// 平常心率计算胎心数据 |
|
|
|
/// </summary> |
|
|
|
/// <param name="heartRate"></param> |
|
|
|
/// <param name="upperAlarmThreshold"></param> |
|
|
|
/// <param name="lowerAlarmThreshold"></param> |
|
|
|
/// <param name="intervalFHR"></param> |
|
|
|
/// <param name="commonPHR"></param> |
|
|
|
/// <returns></returns> |
|
|
|
private async Task CalculateNormalFetalHeartRateAsync(HisGpsHeartRate heartRate, int upperAlarmThreshold, int lowerAlarmThreshold, int intervalFHR, PregnancyCommonHeartRateModel? commonPHR) |
|
|
|
{ |
|
|
|
// 上15分钟的数据 |
|
|
|
// 获取当前时间 |
|
|
|
DateTime nowInterval = (DateTime)heartRate.LastUpdate!; |
|
|
|
|
|
|
|
//private async Task SaveAndPushFetalHeartRateAsync(HisGpsHeartRate heartRate, int upperAlarmThreshold, int lowerAlarmThreshold, double avgPhr) |
|
|
|
//{ |
|
|
|
// var commonPHR = await _serviceTDengine.InitPregnancyCommonHeartRateModeAsync(heartRate.Serialno); |
|
|
|
// if (commonPHR != null) |
|
|
|
// { |
|
|
|
// // 保存到TDengine数据库 |
|
|
|
// await _serviceTDengine.InsertAsync<PregnancyCommonHeartRateModel>("hm_pchr", commonPHR); |
|
|
|
// // 计算胎心=孕妇心率*系数 |
|
|
|
// var fetalHeartRate = SafeType.SafeInt(avgPhr * commonPHR?.StatModeAvgFprCoefficient!); |
|
|
|
// var sampleTime = DateTimeUtil.ConvertToTimeStamp(DateTime.Now).ToString(); |
|
|
|
// var isAbnormal = fetalHeartRate > upperAlarmThreshold ? 1 : (fetalHeartRate < lowerAlarmThreshold ? 2 : 0); |
|
|
|
|
|
|
|
// // 保存到 数据服务 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 = commonPHR.StatStartTime, |
|
|
|
// 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 deviceId = device?.DeviceId; |
|
|
|
// var msg = new |
|
|
|
// { |
|
|
|
// messageId = "", |
|
|
|
// topic = "topic.push.wx", |
|
|
|
// time="" |
|
|
|
// }; |
|
|
|
// } |
|
|
|
//} |
|
|
|
// 计算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; |
|
|
|
|
|
|
|
var normalPhrStatEndTime = nextInterval.AddMinutes(-intervalFHR); |
|
|
|
|
|
|
|
_logger.LogInformation($"{heartRate.Serialno} 计算胎心数据, 周期:{normalPhrStatStartTime}-{normalPhrStatEndTime} "); |
|
|
|
var filteredPhr = daysPhr |
|
|
|
// 使用 last_update 下一刻 |
|
|
|
.Where(i => i.LastUpdate <= normalPhrStatStartTime && i.LastUpdate >= normalPhrStatEndTime) |
|
|
|
.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); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary> |
|
|
|
/// |
|
|
|
/// |
|
|
|
/// </summary> |
|
|
|
/// <param name="heartRate"></param> |
|
|
|
/// <param name="commonPHR"></param> |
|
|
|
/// <param name="upperAlarmThreshold"></param> |
|
|
|
/// <param name="lowerAlarmThreshold"></param> |
|
|
|
/// <param name="phr"></param> |
|
|
|
/// <param name="sampleTime">使用高频心率的首条last_update</param> |
|
|
|
/// <param name="isFreq"></param> |
|
|
|
/// <param name="phrValue"></param> |
|
|
|
/// <param name="sampleTime"></param> |
|
|
|
/// <param name="statStartTime"></param> |
|
|
|
/// <param name="statEndTime"></param> |
|
|
|
/// <returns></returns> |
|
|
|
private async Task SaveAndPushFreqFetalHeartRateAsync(HisGpsHeartRate heartRate, PregnancyCommonHeartRateModel commonPHR, int upperAlarmThreshold, int lowerAlarmThreshold, double phr,string sampleTime,bool isFreq = true) |
|
|
|
private async Task SaveAndPushFetalHeartRateAsync(HisGpsHeartRate heartRate, PregnancyCommonHeartRateModel commonPHR, int upperAlarmThreshold, int lowerAlarmThreshold, double phrValue, string sampleTime,DateTime statStartTime, DateTime statEndTime) |
|
|
|
{ |
|
|
|
// 计算胎心=孕妇心率*系数 |
|
|
|
var fetalHeartRate = SafeType.SafeInt(phr * commonPHR?.StatModeAvgFprCoefficient!); |
|
|
|
var fetalHeartRate = SafeType.SafeInt(phrValue * commonPHR?.StatModeAvgFprCoefficient!); |
|
|
|
//fetalHeartRate = fetalHeartRate > 220 ? 220 : fetalHeartRate; // 胎心的最大值调整为220,超过都按该值220输出 |
|
|
|
if (fetalHeartRate >= 220) |
|
|
|
{ |
|
|
@@ -657,22 +474,27 @@ namespace HealthMonitor.Service.Resolver |
|
|
|
var statMaxValueFprCoefficient = commonPHR?.StatMaxValueFprCoefficient!; |
|
|
|
var statMinValueFprCoefficient = commonPHR?.StatMinValueFprCoefficient!; |
|
|
|
var coefficient = statMaxValueFprCoefficient < statMinValueFprCoefficient ? statMaxValueFprCoefficient : statMinValueFprCoefficient; |
|
|
|
fetalHeartRate = SafeType.SafeInt(phr * coefficient); |
|
|
|
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); |
|
|
|
if (!isFreq) isAbnormal = 0; |
|
|
|
var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno); |
|
|
|
if (phrFreqstatus == null) isAbnormal = 0; |
|
|
|
|
|
|
|
//if (!isFreq) |
|
|
|
//{ |
|
|
|
// statStartTime = heartRate.LastUpdate; |
|
|
|
// |
|
|
|
//} |
|
|
|
// 保存到 数据服务 MySQL 数据库 |
|
|
|
HisGpsFetalHeartRate gpsFetalHeartRate = new() |
|
|
|
{ |
|
|
@@ -682,8 +504,8 @@ namespace HealthMonitor.Service.Resolver |
|
|
|
HeartRate = fetalHeartRate, |
|
|
|
SampleTime = sampleTime.Length > 10 ? sampleTime.Substring(0, 10) : sampleTime, |
|
|
|
IsAbnormal = isAbnormal, |
|
|
|
StatStartTime = commonPHR.StatStartTime, |
|
|
|
StatEndTime = commonPHR.StatEndTime, |
|
|
|
StatStartTime = statStartTime, |
|
|
|
StatEndTime = statEndTime,//commonPHR.StatEndTime, |
|
|
|
CreateTime = DateTime.Now, |
|
|
|
Method = 1, |
|
|
|
IsDisplay = 1, |
|
|
@@ -705,14 +527,15 @@ namespace HealthMonitor.Service.Resolver |
|
|
|
messageId = fhrMsgId, |
|
|
|
topic = topic, |
|
|
|
time = fhrMsgTime, |
|
|
|
data=new { |
|
|
|
data = new |
|
|
|
{ |
|
|
|
imei = heartRate.Serialno, |
|
|
|
value= fetalHeartRate, |
|
|
|
value = fetalHeartRate, |
|
|
|
isAbnormal, |
|
|
|
type= "fetalHeart" |
|
|
|
type = "fetalHeart" |
|
|
|
} |
|
|
|
}; |
|
|
|
await _serviceMqProcess.ProcessIMEIEventMessageAsync(fhrMsgId, topic, 31,fhrThridMsg).ConfigureAwait(false); |
|
|
|
await _serviceMqProcess.ProcessIMEIEventMessageAsync(fhrMsgId, topic, 31, fhrThridMsg).ConfigureAwait(false); |
|
|
|
|
|
|
|
// 胎心数据推送到微信 |
|
|
|
if (isAbnormal != 0) |
|
|
@@ -739,6 +562,7 @@ namespace HealthMonitor.Service.Resolver |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private async Task SetIntervalTriggerAsync(string key,string imei, long interval) |
|
|
|
{ |
|
|
|
// var key = $"health_monitor/schedule_push/{type}/imei/{imei}"; |
|
|
@@ -758,21 +582,6 @@ namespace HealthMonitor.Service.Resolver |
|
|
|
await _serviceEtcd.PutValAsync(key, result, interval, false).ConfigureAwait(false); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public static bool IsLastUpdateInTimeRanges(DateTime lastUpdate) |
|
|
|
{ |
|
|
|
var now = lastUpdate.TimeOfDay; |
|
|
|
|
|
|
|
var timeRanges = new List<(TimeSpan Start, TimeSpan End)> |
|
|
|
{ |
|
|
|
// 8:00~10:00,12:00~14:00,18:00~20:00,22:00~24:00 |
|
|
|
(new TimeSpan(8, 0, 0), new TimeSpan(10, 0, 0)), |
|
|
|
(new TimeSpan(12, 0, 0), new TimeSpan(14, 0, 0)), |
|
|
|
(new TimeSpan(18, 0, 0), new TimeSpan(20, 0, 0)), |
|
|
|
(new TimeSpan(22, 0, 0), new TimeSpan(24, 0, 0)) |
|
|
|
}; |
|
|
|
|
|
|
|
return timeRanges.Any(range => now >= range.Start && now <= range.End); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |