Bläddra i källkod

心率足够30条,立即胎心建模

datasub12_fetal_heart_rate_0
H Vs 4 månader sedan
förälder
incheckning
9e6931d678
1 ändrade filer med 355 tillägg och 545 borttagningar
  1. +355
    -545
      HealthMonitor.Service/Resolver/PregnancyHeartRateResolver.cs

+ 355
- 545
HealthMonitor.Service/Resolver/PregnancyHeartRateResolver.cs Visa fil

@@ -130,202 +130,400 @@ namespace HealthMonitor.Service.Resolver
var phr = await _serviceTDengine.GetBySerialNoAsync<PregnancyHeartRateModel>(heartRate.Serialno, 7);
if (phr.Count >= 30)
{
/**
#region 计算胎心和胎动数据
var commonPHR = await _serviceTDengine.GetLastAsync<PregnancyCommonHeartRateModel>(heartRate.Serialno);
if (commonPHR != null)
if (commonPHR == null)
{
var lastUpdateNow = (DateTime)heartRate.LastUpdate!;
var midNight = new DateTime(lastUpdateNow.Year, lastUpdateNow.Month, lastUpdateNow.Day, 0, 0, 0);
#region 计算胎心数据
_logger.LogInformation($"{heartRate.Serialno} 计算胎心数据 ");
// 处理孕妇业务,计算一般心率并下发
commonPHR = await _serviceTDengine.InitPregnancyCommonHeartRateModeAsync(heartRate.Serialno);
// 建模完成
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完成");
}
#region 计算胎心数据(按心率时间LastUpdate)

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

TimeSpan fhrTS = fhrNow - midNight;
// 当天每隔intervalFHR 分钟的段数,取整数部分
int segmentCountFHR = (int)(fhrTS.TotalMinutes / intervalFHR);
for (int i = 0; i < segmentCountFHR; i++)
{
// 每intervalFHR * i分钟
var fhrSampleTime = DateTimeUtil.ConvertToTimeStamp(midNight.AddMinutes(intervalFHR * i)).ToString()[..10];
// 如果需要,将时间差转换为秒
var timeDiffInSeconds = timeDiff.TotalSeconds;

// 统计开始时间
var statStartTimeFHR = midNight.AddMinutes(intervalFHR * i);
// 统计结束时间
var statEndTimeFHR = midNight.AddMinutes(intervalFHR * (i + 1));
// 高频心率启动
if (timeDiffInSeconds <= highFreqSampleInterval)
{

var isFHRExisted =await _mgrFetalHeartRateCache.FetalHeartRateIsExistedAsync(heartRate.Serialno, fhrSampleTime);
_logger.LogInformation($"{heartRate.Serialno} 胎心数据采样时间:{fhrSampleTime}|{midNight.AddMinutes(intervalFHR * i).ToString("yyyy-MM-dd HH:mm:ss")}, 采样周期:{statStartTimeFHR}-{statEndTimeFHR},isFHRExisted:{isFHRExisted} ");
var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno);
if (phrFreqstatus == null)
{
/// 设置高频状态
_logger.LogInformation($"进入高频心率启动状态 timeDiffInSeconds {timeDiffInSeconds},highFreqSampleInterval:{highFreqSampleInterval}");
// 设置高频状态
var freqFirstPhr = phr.OrderByDescending(i => i.Timestamp).First();
await _deviceCacheMgr.SetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno, freqFirstPhr);
//phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno);
}
/// phr PregnancyHeartRate 连续连续正常次数个值都是正常(大于等于triggerHighFreqLow,少于等于triggerHighFreqHig),
/// 取连续正常次数正常值的平均值,推送到api/v1/open/OpenIot/SetFetalHeartRateConfig
#region 检查是否连续12个值都是正常的
// 获取最近连续正常次数个心率记录
var lastPhr = phr.OrderByDescending(i => i.Timestamp).Take(stopHighFreqSampleCount).ToList();

// 检查是否连续12个值都是正常的
if (lastPhr.All(i => i.PregnancyHeartRate >= triggerHighFreqLow && i.PregnancyHeartRate <= triggerHighFreqHigh))
{
var avgPhr = lastPhr.Select(i => i.PregnancyHeartRate).Average();
// 计算一般心率得到胎心系数
await SaveAndPushFreqFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, avgPhr, DateTimeUtil.ConvertToTimeStamp(DateTime.Now).ToString());

if (!isFHRExisted)
}
#endregion
}
// 高频心率结束或正常心率
else
{
var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno);
if (phrFreqstatus != null)
{
/// 在highFreqSampleTimes=0一直异常(大于等于triggerHighFreqLow,少于等于triggerHighFreqHig),
/// 取所有值的平均值,推送胎心数据到api/v1/open/OpenIot/SetFetalHeartRateConfig
if (highFreqSampleTimes == 0)
{
// 开始计算 ,每intervalFHR分钟计算一个
var phrRange = phr.Where(i => i.LastUpdate >= statStartTimeFHR && i.LastUpdate <= statEndTimeFHR)
.OrderByDescending(i => i.LastUpdate)
.ToList();

// 胎心数据每intervalFHR分钟计算1个值,采集的数据多于1个取平均值再*胎心系数。
var phrValue = phrRange.Count == 1
? phrRange.First().PregnancyHeartRate
: phrRange.Average(i => i.PregnancyHeartRate);
// 当天的系数,没有的就实时计算
var fprCoefficient = 0f;

//if (commonPHR.CreateTime.Year == lastUpdateNow.Year &&
// commonPHR.CreateTime.Month == lastUpdateNow.Month &&
// commonPHR.CreateTime.Day == lastUpdateNow.Day
// )
//{
// fprCoefficient = (float)commonPHR?.StatModeAvgFprCoefficient!;
//}
//else
//{
// //var daysDiff = 7 - (DateTime.Now.Day - lastUpdateNow.Day);
// //var realtimePCHR = await _serviceTDengine.InitPregnancyCommonHeartRateModeAsync(heartRate.Serialno, daysDiff);
// //fprCoefficient = realtimePCHR!.StatModeAvgFprCoefficient;
// var pchr = await _serviceTDengine.GetBySerialNoAsync<PregnancyCommonHeartRateModel>(heartRate.Serialno);
// var dayPCHR = pchr.Where(i => i.CreateTime.Year == lastUpdateNow.Year && i.CreateTime.Month == lastUpdateNow.Month && i.CreateTime.Day == i.CreateTime.Day);
// fprCoefficient=dayPCHR.First().StatModeAvgFprCoefficient;
//}

fprCoefficient = (float)commonPHR?.StatModeAvgFprCoefficient!;

var fetalHeartRate = SafeType.SafeInt(phrValue * fprCoefficient);

var 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 = fhrSampleTime.Length > 10 ? fhrSampleTime.Substring(0, 10) : fhrSampleTime,
IsAbnormal = fetalHeartRateIsAbnormal,
StatStartTime = phrRange.OrderBy(i => i.LastUpdate).First().LastUpdate,
StatEndTime = phrRange.OrderBy(i => i.LastUpdate).Last().LastUpdate,
CreateTime = DateTime.Now,
Method = 1,
IsDisplay = 1,
DeviceKey = commonPHR!.DeviceKey
};
// 保存到 数据服务 MySQL 数据库
await _hisFetalHeartApiClient.AddAsync(gpsFetalHeartRate).ConfigureAwait(false);
var avgPhr = phr.OrderByDescending(i => i.Timestamp)
.Where(i => i.Timestamp >= phrFreqstatus?.Timestamp)
.Skip(1) // 去除首条
.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());

// 推送到api/v1/open/OpenIot/SetFetalHeartRateConfig
await _serviceIotApi.SetFetalHeartRateConfig(heartRate.Serialno, fetalHeartRate, fhrSampleTime, fetalHeartRateIsAbnormal);
}

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

var avgPhr = phr
.Where(i => i.Timestamp >= phrFreqstatus?.Timestamp)
.Skip(1) // 去除首条
.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 _mgrFetalHeartRateCache.SetFetalHeartRateAsync(heartRate.Serialno, fhrSampleTime);
}

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

/// 设置高频状态
_logger.LogInformation($"结束高频心率状态 timeDiffInSeconds {timeDiffInSeconds},highFreqSampleInterval:{highFreqSampleInterval}");
}
// 正常心率
else
{

#endregion
// 上15分钟的数据
// 获取当前时间
DateTime nowInterval = (DateTime)heartRate.LastUpdate!;

#region 计算胎动数据
_logger.LogInformation($"{heartRate.Serialno} 计算胎动数据 ");
// 计算last_update到上一刻钟的分钟数
int minutesToSubtract = nowInterval.Minute % intervalFHR;

var fmNow = lastUpdateNow;
// 计算上一刻钟的时间
DateTime previousInterval = nowInterval.AddMinutes(-minutesToSubtract).AddSeconds(-nowInterval.Second).AddMilliseconds(-nowInterval.Millisecond);

TimeSpan fmTS = fmNow - midNight;
// 使用 last_update 上一刻
var sampleTimeFHR = DateTimeUtil.ConvertToTimeStamp(previousInterval).ToString();

// 当天每隔2小时的段数,取整数部分
int segmentCountFM = (int)(fmTS.TotalHours / 2);
// 计算last_update到下一刻钟的分钟数
int minutesToAdd = intervalFHR - (nowInterval.Minute % intervalFHR);
if (minutesToAdd == intervalFHR)
{
minutesToAdd = 0; // 如果已经是刻钟,则不需要增加分钟
}

for (int i = 0; i < segmentCountFM; i++)
{
// 每两小时
var fetalMovementSampleTime = DateTimeUtil.ConvertToTimeStamp(midNight.AddHours(2 * i)).ToString()[..10];
// 计算下一刻钟的时间
DateTime nextInterval = nowInterval.AddMinutes(minutesToAdd)
.AddSeconds(-nowInterval.Second)
.AddMilliseconds(-nowInterval.Millisecond);

// 统计开始时间
var statStartTime = midNight.AddHours(2 * i);
// 统计结束时间
var statEndTime = midNight.AddHours(2 * (i + 1));

//var isFetalMovementExist = await _hisFetalMovementApiClient.GetFirstAsync(param, heartRate.Serialno[^2..], null, new RequestHeader { RequestId = Guid.NewGuid().ToString("D") });
var isFetalMovementExisted = await _mgrFetalMovement.FetalMovementIsExistedAsync(heartRate.Serialno, fetalMovementSampleTime);
var daysPhr = await _serviceTDengine.GetBySerialNoAsync<PregnancyHeartRateModel>(heartRate.Serialno, 7);

if (!isFetalMovementExisted)
{
/// 开始计算
var phrRange = phr.Where(i => i.LastUpdate >= statStartTime && i.LastUpdate <= statEndTime)
.OrderByDescending(i => i.LastUpdate)
.Select(i => i.LastUpdate)
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!);

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(fmNow);

int pregnancyWeeks = (DateTime.Now - edoc.AddDays(-280)).Days / 7;
if (pregnancyWeeks >= 12 && pregnancyWeeks <= 50)
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
{
var fetalMovementMap = _mgrFetalMovementNormalValueRangeCache.GetFetalMovements();
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);
}
}
}

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()
;
#endregion

var fetalMovementValue = (fetalMovementMapValue * duringMins * 2) / 120;
#region 计算胎动数据(按心率时间LastUpdate)
/**
_logger.LogInformation($"{heartRate.Serialno} 计算胎动数据 ");

var fetalMovementNow = (DateTime)heartRate.LastUpdate!;

// 四舍五入
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} ");
var midNight = new DateTime(fetalMovementNow.Year, fetalMovementNow.Month, fetalMovementNow.Day, 0, 0, 0);

_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}");
TimeSpan fetalMovementTS = fetalMovementNow - midNight;

// 获取胎心数据状态与胎动数据状态一致
//var feltalMovementIsAbnormal = fetalHeartRateIsAbnormal;
var feltalMovementIsAbnormal = 0;
// 推送到api/v1/open/OpenIot/SetFetalMovementConfig
// 当天每隔2小时的段数,取整数部分
int segmentCountFM = (int)(fetalMovementTS.TotalHours / 2);

await _serviceIotApi.SetFetalMovementConfig(heartRate.Serialno, fetalMovement, fetalMovementSampleTime, feltalMovementIsAbnormal);
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);

// 保存到MySQL数据库
HisGpsFetalMovement fm = new()
int pregnancyWeeks = (DateTime.Now - edoc.AddDays(-280)).Days / 7;
if (pregnancyWeeks >= 12 && pregnancyWeeks <= 50)
{
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
{
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
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 _hisFetalMovementApiClient.AddAsync(fm).ConfigureAwait(false);

// 设置入库缓存记录
await _mgrFetalMovement.SetFetalMovementAsync(heartRate.Serialno, fetalMovementSampleTime);
await _serviceMqProcess.ProcessIMEIEventMessageAsync(fmMsgId, topic, fmMsg).ConfigureAwait(false);
}
// 设置入库缓存记录
await _deviceCacheMgr.SetFetalMovementAsync(heartRate.Serialno, fetalMovementSampleTime,fm);
}
else
{
_logger.LogWarning($"{heartRate.Serialno} 孕周 {pregnancyWeeks},超出胎动计算范围");
}
}
else
{
_logger.LogInformation($"{heartRate.Serialno} 胎动记录{isFetalMovementExisted},数据采样时间:{fetalMovementSampleTime}|{midNight.AddHours(2 * i).ToString("yyyy-MM-dd HH:mm:ss")}, 周期:{statStartTime}-{statEndTime} 不足两条,不能判断是否持续佩戴");

}
}
#endregion
else
{
_logger.LogInformation($"{heartRate.Serialno} 胎动记录{isFetalMovementExisted},数据采样时间:{fetalMovementSampleTime}|{midNight.AddHours(2 * i).ToString("yyyy-MM-dd HH:mm:ss")}, 周期:{statStartTime}-{statEndTime} 已处理");
}

}
*/
#endregion

#endregion

#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 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;

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

#region 定时计算胎心数据触发器 {interval} 秒后
//var fetalKey = $"health_monitor/schedule_push/cal_fetal_heart_rate/imei/{heartRate.Serialno}";
//await SetIntervalTriggerAsync(fetalKey, heartRate.Serialno, 60 * 15);
#endregion

#region 定时计算胎心数据触发器下一刻钟后
//// 获取当前时间
//DateTime nowInterval = DateTime.Now;

//// 计算下一个15分钟的刻钟
//int minutesToAdd = 15 - (nowInterval.Minute % 15);
//if (minutesToAdd == 15)
//{
// minutesToAdd = 0; // 如果已经是刻钟,则不需要增加分钟
//}
//// 计算下一刻钟的时间
//DateTime nextInterval = nowInterval.AddMinutes(minutesToAdd)
// .AddSeconds(-nowInterval.Second)
// .AddMilliseconds(-nowInterval.Millisecond);

//// 计算时间差
//TimeSpan timeDifference = nextInterval - nowInterval;

//var fetalKey = $"health_monitor/schedule_push/cal_fetal_heart_rate/imei/{heartRate.Serialno}";
//await SetIntervalTriggerAsync(fetalKey, heartRate.Serialno, (long)timeDifference.TotalSeconds);
#endregion

#region 高频心率计算

@@ -422,397 +620,12 @@ namespace HealthMonitor.Service.Resolver
//}

#endregion

#region 计算胎心和胎动数据
var commonPHR = await _serviceTDengine.GetLastAsync<PregnancyCommonHeartRateModel>(heartRate.Serialno);
if (commonPHR != null)
{

#region 计算胎心数据

// 获取最近的两个记录,并计算它们的 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;

// 高频心率启动
if (timeDiffInSeconds <= highFreqSampleInterval)
{

var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno);
if (phrFreqstatus == null)
{
/// 设置高频状态
_logger.LogInformation($"进入高频心率启动状态 timeDiffInSeconds {timeDiffInSeconds},highFreqSampleInterval:{highFreqSampleInterval}");
// 设置高频状态
var freqFirstPhr = phr.OrderByDescending(i => i.Timestamp).First();
await _deviceCacheMgr.SetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno, freqFirstPhr);
//phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno);
}
/// phr PregnancyHeartRate 连续连续正常次数个值都是正常(大于等于triggerHighFreqLow,少于等于triggerHighFreqHig),
/// 取连续正常次数正常值的平均值,推送到api/v1/open/OpenIot/SetFetalHeartRateConfig
#region 检查是否连续12个值都是正常的
// 获取最近连续正常次数个心率记录
var lastPhr = phr.OrderByDescending(i => i.Timestamp).Take(stopHighFreqSampleCount).ToList();

// 检查是否连续12个值都是正常的
if (lastPhr.All(i => i.PregnancyHeartRate >= triggerHighFreqLow && i.PregnancyHeartRate <= triggerHighFreqHigh))
{
var avgPhr = lastPhr.Select(i => i.PregnancyHeartRate).Average();
// 计算一般心率得到胎心系数
await SaveAndPushFreqFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, avgPhr, DateTimeUtil.ConvertToTimeStamp(DateTime.Now).ToString());

}
#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.Timestamp)
.Where(i => i.Timestamp >= phrFreqstatus?.Timestamp)
.Skip(1) // 去除首条
.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());

}

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

var avgPhr = phr
.Where(i => i.Timestamp >= phrFreqstatus?.Timestamp)
.Skip(1) // 去除首条
.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 _deviceCacheMgr.DelPregnancyHeartRateFreqStatusAsync(heartRate.Serialno);

/// 设置高频状态
_logger.LogInformation($"结束高频心率状态 timeDiffInSeconds {timeDiffInSeconds},highFreqSampleInterval:{highFreqSampleInterval}");
}
// 正常心率
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);
}


}
}

#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 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);
}
else
{
_logger.LogWarning($"{heartRate.Serialno} 孕周 {pregnancyWeeks},超出胎动计算范围");
}
}
else
{
_logger.LogInformation($"{heartRate.Serialno} 胎动记录{isFetalMovementExisted},数据采样时间:{fetalMovementSampleTime}|{midNight.AddHours(2 * i).ToString("yyyy-MM-dd HH:mm:ss")}, 周期:{statStartTime}-{statEndTime} 不足两条,不能判断是否持续佩戴");

}
}
else
{
_logger.LogInformation($"{heartRate.Serialno} 胎动记录{isFetalMovementExisted},数据采样时间:{fetalMovementSampleTime}|{midNight.AddHours(2 * i).ToString("yyyy-MM-dd HH:mm:ss")}, 周期:{statStartTime}-{statEndTime} 已处理");
}

}
*/
#endregion
}
#endregion



#region 定时计算胎心数据触发器 {interval} 秒后
//var fetalKey = $"health_monitor/schedule_push/cal_fetal_heart_rate/imei/{heartRate.Serialno}";
//await SetIntervalTriggerAsync(fetalKey, heartRate.Serialno, 60 * 15);
#endregion

#region 定时计算胎心数据触发器下一刻钟后
//// 获取当前时间
//DateTime nowInterval = DateTime.Now;

//// 计算下一个15分钟的刻钟
//int minutesToAdd = 15 - (nowInterval.Minute % 15);
//if (minutesToAdd == 15)
//{
// minutesToAdd = 0; // 如果已经是刻钟,则不需要增加分钟
//}
//// 计算下一刻钟的时间
//DateTime nextInterval = nowInterval.AddMinutes(minutesToAdd)
// .AddSeconds(-nowInterval.Second)
// .AddMilliseconds(-nowInterval.Millisecond);

//// 计算时间差
//TimeSpan timeDifference = nextInterval - nowInterval;

//var fetalKey = $"health_monitor/schedule_push/cal_fetal_heart_rate/imei/{heartRate.Serialno}";
//await SetIntervalTriggerAsync(fetalKey, heartRate.Serialno, (long)timeDifference.TotalSeconds);
#endregion

#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 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;

await SetIntervalTriggerAsync(fetalMovementKey, heartRate.Serialno, ttl);
}
#endregion
}
else
{
// 建模中
//var flag = await _serviceIotApi.SetFetalConfig(heartRate.Serialno);
_logger.LogInformation($"{heartRate.Serialno} 记录不足30条,建模中");
}

#region 定时下发触发器(定时建模)
@@ -884,11 +697,8 @@ namespace HealthMonitor.Service.Resolver
}

#endregion

}



}

private async Task SaveAndPushFetalHeartRateAsync(HisGpsHeartRate heartRate, int upperAlarmThreshold, int lowerAlarmThreshold, double avgPhr)


Laddar…
Avbryt
Spara