@@ -0,0 +1,46 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
namespace HealthMonitor.Model.Cache | |||||
{ | |||||
public class FetalMovementNormalValueRange | |||||
{ | |||||
/// <summary> | |||||
/// 孕周期 | |||||
/// </summary> | |||||
public int[] PregnancyPeriod { get; set; } | |||||
/// <summary> | |||||
/// 正常胎动(次/小时) | |||||
/// </summary> | |||||
public int[] NormalMovementRange { get; set; } | |||||
/// <summary> | |||||
/// 12小时胎动(次) | |||||
/// </summary> | |||||
public int[] TwelveHourMovementRange { get; set; } | |||||
/// <summary> | |||||
/// 胎动中间值(次/小时) | |||||
/// </summary> | |||||
public int MedianMovement { get; set; } | |||||
/// <summary> | |||||
/// 胎动起始值(次/小时) | |||||
/// </summary> | |||||
public int InitialMovement { get; set; } | |||||
/// <summary> | |||||
/// 备注 | |||||
/// </summary> | |||||
public string Remarks { get; set; } | |||||
public FetalMovementNormalValueRange(int[] pregnancyPeriod, int[] normalMovementRange, int[] twelveHourMovementRange, int medianMovement, int initialMovement, string remarks) | |||||
{ | |||||
PregnancyPeriod = pregnancyPeriod; | |||||
NormalMovementRange = normalMovementRange; | |||||
TwelveHourMovementRange = twelveHourMovementRange; | |||||
MedianMovement = medianMovement; | |||||
InitialMovement = initialMovement; | |||||
Remarks = remarks; | |||||
} | |||||
} | |||||
} |
@@ -254,7 +254,11 @@ namespace HealthMonitor.Service.Biz | |||||
#endregion | #endregion | ||||
#region 平台下发胎心监测参数 | #region 平台下发胎心监测参数 | ||||
/// <summary> | /// <summary> | ||||
/// 胎心设置 | /// 胎心设置 | ||||
/// </summary> | /// </summary> | ||||
@@ -328,8 +332,6 @@ namespace HealthMonitor.Service.Biz | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
/// <summary> | /// <summary> | ||||
/// 下发胎心数据 | /// 下发胎心数据 | ||||
/// </summary> | /// </summary> | ||||
@@ -340,7 +342,7 @@ namespace HealthMonitor.Service.Biz | |||||
/// <returns></returns> | /// <returns></returns> | ||||
public async Task<bool> SetFetalHeartRateConfig(string serialno, int fhr, string sampeTime, int isAbnormal) | public async Task<bool> SetFetalHeartRateConfig(string serialno, int fhr, string sampeTime, int isAbnormal) | ||||
{ | { | ||||
try | try | ||||
{ | { | ||||
#region 读取缓存 | #region 读取缓存 | ||||
@@ -369,8 +371,8 @@ namespace HealthMonitor.Service.Biz | |||||
_logger.LogInformation($" SetFetalHeartRateConfig Token TelpoManufactorId: {tokenAuthData}"); | _logger.LogInformation($" SetFetalHeartRateConfig Token TelpoManufactorId: {tokenAuthData}"); | ||||
var data = new | var data = new | ||||
{ | { | ||||
imei= serialno, | |||||
heartValue= fhr, | |||||
imei = serialno, | |||||
heartValue = fhr, | |||||
sampeTime, | sampeTime, | ||||
isAbnormal | isAbnormal | ||||
}; | }; | ||||
@@ -383,16 +385,70 @@ namespace HealthMonitor.Service.Biz | |||||
return resJToken?["message"]?.ToString().Equals("ok") ?? false; | return resJToken?["message"]?.ToString().Equals("ok") ?? false; | ||||
#endregion | #endregion | ||||
} | } | ||||
catch (Exception ex) | catch (Exception ex) | ||||
{ | { | ||||
_logger.LogError($"{nameof(SetFetalHeartRateConfig)} 下发胎心数据异常:{ex.Message}, {ex.StackTrace}"); | _logger.LogError($"{nameof(SetFetalHeartRateConfig)} 下发胎心数据异常:{ex.Message}, {ex.StackTrace}"); | ||||
return false; | return false; | ||||
} | } | ||||
} | |||||
public async Task<bool> SetFetalMovementConfig(string serialno,int fm, string sampeTime, int isAbnormal) | |||||
{ | |||||
try | |||||
{ | |||||
#region 读取缓存 | |||||
// db7.HashGet("TELPO#GPSDEVICE_WATCH_CONFIG_HASH","861281060086083_0067") | |||||
var watchConfig = await _deviceCacheMgr.GetGpsDeviceWatchConfigCacheObjectBySerialNoAsync(serialno, "0067"); | |||||
if (watchConfig == null) | |||||
{ | |||||
return false; | |||||
} | |||||
#endregion | |||||
#region 获取B端 Token | |||||
string tokenAuthData = await getAccessToken2(serialno).ConfigureAwait(false); | |||||
if (tokenAuthData == null) | |||||
{ | |||||
return false; | |||||
} | |||||
#endregion | |||||
#region 下发数据 | |||||
List<KeyValuePair<string, string>> headers = new() | |||||
{ | |||||
new KeyValuePair<string, string>("AccessToken", tokenAuthData) | |||||
}; | |||||
_logger.LogInformation($" SetFetalHeartRateConfig Token TelpoManufactorId: {tokenAuthData}"); | |||||
var data = new | |||||
{ | |||||
imei = serialno, | |||||
movementValue = fm, | |||||
sampeTime, | |||||
isAbnormal | |||||
}; | |||||
var setUrl = $"{_configService.IotCore}/SetFetalMovementConfig"; | |||||
_logger.LogInformation($"{setUrl} 请求 {JsonConvert.SerializeObject(JsonConvert.SerializeObject(data))}"); | |||||
var res = await _httpHelper.HttpToPostAsync(setUrl, data, headers).ConfigureAwait(false); | |||||
_logger.LogInformation($"{setUrl} 响应 {res}"); | |||||
var resJToken = JsonConvert.DeserializeObject(res ?? string.Empty) as JToken; | |||||
return resJToken?["message"]?.ToString().Equals("ok") ?? false; | |||||
#endregion | |||||
} | |||||
catch (Exception ex) | |||||
{ | |||||
_logger.LogError($"{nameof(SetFetalMovementConfig)} 下发胎动数据异常:{ex.Message}, {ex.StackTrace}"); | |||||
return false; | |||||
} | |||||
} | } | ||||
private async Task<string> getAccessToken2(string serialno) | private async Task<string> getAccessToken2(string serialno) | ||||
{ | { | ||||
var getTokenUrl = $"{_configService.IotAuth}/getAccessToken2"; | var getTokenUrl = $"{_configService.IotAuth}/getAccessToken2"; | ||||
@@ -973,17 +973,17 @@ namespace HealthMonitor.Service.Biz.db | |||||
return null; | return null; | ||||
} | } | ||||
long.TryParse(watchConfig["EDOC"]!.ToString(), out long edoc); | long.TryParse(watchConfig["EDOC"]!.ToString(), out long edoc); | ||||
// "EDOC": "1720860180652",EDOC -280 days =怀孕时间 | |||||
// "EDOC": "1720860180652",当前时间 - (EDOC - 280) days =怀孕时间 | |||||
edoc = edoc.ToString().Length == 10 ? edoc * 1000 : edoc; | |||||
int pregnancyWeek = (DateTime.Now-DateTimeUtil.GetDateTimeFromUnixTimeMilliseconds(edoc).AddDays(-280)).Days / 7; | int pregnancyWeek = (DateTime.Now-DateTimeUtil.GetDateTimeFromUnixTimeMilliseconds(edoc).AddDays(-280)).Days / 7; | ||||
_logger.LogInformation($"EDOC:{edoc},NOW:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")},SinceNOW:{DateTimeUtil.GetDateTimeFromUnixTimeMilliseconds(edoc).AddDays(-280).ToString("yyyy-MM-dd HH:mm:ss")},怀孕周数 {pregnancyWeek}"); | |||||
_logger.LogInformation($"IMEI {serialNo},EDOC:{edoc},NOW:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")},SinceNOW:{DateTimeUtil.GetDateTimeFromUnixTimeMilliseconds(edoc).AddDays(-280).ToString("yyyy-MM-dd HH:mm:ss")},怀孕周数 {pregnancyWeek}"); | |||||
var statMaxValueFprCoefficient = 0; | var statMaxValueFprCoefficient = 0; | ||||
var statMinValueFprCoefficient = 0; | var statMinValueFprCoefficient = 0; | ||||
var StatModeAvgFprCoefficient = 0; | var StatModeAvgFprCoefficient = 0; | ||||
// 20-40周之间 | |||||
if (pregnancyWeek >= 12 && pregnancyWeek <= 40) | |||||
// 20-45周之间 | |||||
if (pregnancyWeek >= 12 && pregnancyWeek <= 45) | |||||
{ | { | ||||
var map= fhrMap | var map= fhrMap | ||||
.Where(i => | .Where(i => | ||||
@@ -0,0 +1,33 @@ | |||||
using HealthMonitor.Model.Cache; | |||||
using Microsoft.Extensions.Logging; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
namespace HealthMonitor.Service.Cache | |||||
{ | |||||
public class FetalMovementNormalValueRangeCacheManager | |||||
{ | |||||
private readonly ILogger<FetalMovementNormalValueRange> _logger; | |||||
public FetalMovementNormalValueRangeCacheManager(ILogger<FetalMovementNormalValueRange> logger) | |||||
{ | |||||
_logger = logger; | |||||
} | |||||
public List<FetalMovementNormalValueRange> GetFetalMovements() | |||||
{ | |||||
return new List<FetalMovementNormalValueRange> | |||||
{ | |||||
new (new int[] {12, 20}, new int[] {1, 3}, new int[] {10, 30}, 2, 1, "初次感觉到胎动"), | |||||
new (new int[] {21, 24}, new int[] {2, 4}, new int[] {20, 40}, 3, 2, "胎动逐渐增强"), | |||||
new (new int[] {25, 28}, new int[] {3, 5}, new int[] {30, 50}, 4, 3, "胎动更加明显"), | |||||
new (new int[] {29, 32}, new int[] {6, 8}, new int[] {60, 80}, 7, 6, "胎动达到高峰"), | |||||
new (new int[] {33, 36}, new int[] {5, 7}, new int[] {50, 70}, 6, 5, "胎动频繁且有力"), | |||||
new (new int[] {37, 40}, new int[] {3, 5}, new int[] {30, 50}, 4, 3, "胎动可能因空间减少而减少"), | |||||
new (new int[] {41, 50}, new int[] {2, 4}, new int[] {20, 40}, 3, 2, "减少,但因人而异。胎儿入盆,空间受限") | |||||
}; | |||||
} | |||||
} | |||||
} |
@@ -15,13 +15,13 @@ namespace HealthMonitor.Service.Cache | |||||
{ | { | ||||
_logger = logger; | _logger = logger; | ||||
} | } | ||||
public List<FhrPhrMap> GetHeartRatesMap() | |||||
public List<FhrPhrMap> GetHeartRatesMap() | |||||
{ | { | ||||
return new List<FhrPhrMap> | return new List<FhrPhrMap> | ||||
{ | { | ||||
new FhrPhrMap(new int[] {12, 20}, new int[] {120, 170}, 162, new int[] {60, 100}, new int[] {50, 80}), | new FhrPhrMap(new int[] {12, 20}, new int[] {120, 170}, 162, new int[] {60, 100}, new int[] {50, 80}), | ||||
new FhrPhrMap(new int[] {21, 30}, new int[] {110, 160}, 147, new int[] {60, 100}, new int[] {40, 70}), | new FhrPhrMap(new int[] {21, 30}, new int[] {110, 160}, 147, new int[] {60, 100}, new int[] {40, 70}), | ||||
new FhrPhrMap(new int[] {31, 40}, new int[] {110, 160}, 139, new int[] {60, 100}, new int[] {40, 70}) | |||||
new FhrPhrMap(new int[] {31, 45}, new int[] {110, 160}, 139, new int[] {60, 100}, new int[] {40, 70}) | |||||
}; | }; | ||||
} | } | ||||
} | } | ||||
@@ -11,6 +11,7 @@ using HealthMonitor.Service.Sub.Topic.Model; | |||||
using Microsoft.EntityFrameworkCore.Metadata; | using Microsoft.EntityFrameworkCore.Metadata; | ||||
using Microsoft.Extensions.Logging; | using Microsoft.Extensions.Logging; | ||||
using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
using SqlSugar; | |||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Linq; | using System.Linq; | ||||
@@ -199,29 +200,69 @@ namespace HealthMonitor.Service.Resolver | |||||
#region 定时计算胎心数据触发器 {interval} 秒后 | #region 定时计算胎心数据触发器 {interval} 秒后 | ||||
var fetalKey = $"health_monitor/schedule_push/cal_fetal_heart_rate/imei/{heartRate.Serialno}"; | var fetalKey = $"health_monitor/schedule_push/cal_fetal_heart_rate/imei/{heartRate.Serialno}"; | ||||
var scheduleFetalPush = await _serviceEtcd.GetValAsync(fetalKey).ConfigureAwait(false); | |||||
if (string.IsNullOrWhiteSpace(scheduleFetalPush)) | |||||
await SetIntervalTriggerAsync(fetalKey, heartRate.Serialno, 60 * 15); | |||||
//var scheduleFetalPush = await _serviceEtcd.GetValAsync(fetalKey).ConfigureAwait(false); | |||||
//if (string.IsNullOrWhiteSpace(scheduleFetalPush)) | |||||
//{ | |||||
// //var fetalInterval = (int)watchConfig["interval"]!; | |||||
// var fetalInterval = 60 * 15; | |||||
// var fetalNow= DateTime.Now; | |||||
// var fetalTimeNextRun = fetalNow.Add(TimeSpan.FromSeconds(fetalInterval)); | |||||
// var fetalTTL = fetalInterval; | |||||
// var data = new | |||||
// { | |||||
// imei = heartRate.Serialno, | |||||
// create_time = fetalNow.ToString("yyyy-MM-dd HH:mm:ss"), | |||||
// fetalTTL, | |||||
// next_run_time = fetalTimeNextRun.ToString("yyyy-MM-dd HH:mm:ss") | |||||
// }; | |||||
// var result = JsonConvert.SerializeObject(data); | |||||
// await _serviceEtcd.PutValAsync(fetalKey, result, fetalTTL, false).ConfigureAwait(false); | |||||
//} | |||||
#endregion | |||||
#region 定时计算胎动数据触发器 0 点开始 | |||||
var fetalMovementKey = $"health_monitor/schedule_push/cal_fetal_movement/imei/{heartRate.Serialno}"; | |||||
/// 计算 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; | |||||
DateTime nextRunTime = new (now.Year, now.Month, now.Day, 0, pushMin, pushSec); | |||||
TimeSpan timeUntilNextRun = nextRunTime - now; | |||||
if (timeUntilNextRun < TimeSpan.Zero) | |||||
{ | { | ||||
//var fetalInterval = (int)watchConfig["interval"]!; | |||||
var fetalInterval = 60 * 15; | |||||
var fetalNow= DateTime.Now; | |||||
var fetalTimeNextRun = fetalNow.Add(TimeSpan.FromSeconds(fetalInterval)); | |||||
var fetalTTL = fetalInterval; | |||||
var data = new | |||||
{ | |||||
imei = heartRate.Serialno, | |||||
create_time = fetalNow.ToString("yyyy-MM-dd HH:mm:ss"), | |||||
fetalTTL, | |||||
next_run_time = fetalTimeNextRun.ToString("yyyy-MM-dd HH:mm:ss") | |||||
}; | |||||
var result = JsonConvert.SerializeObject(data); | |||||
await _serviceEtcd.PutValAsync(fetalKey, result, fetalTTL, false).ConfigureAwait(false); | |||||
timeUntilNextRun = timeUntilNextRun.Add(TimeSpan.FromDays(1)); | |||||
nextRunTime += timeUntilNextRun; | |||||
} | } | ||||
#endregion | |||||
} | |||||
var ttl = (long)timeUntilNextRun.TotalSeconds; | |||||
await SetIntervalTriggerAsync(fetalMovementKey, heartRate.Serialno, ttl); | |||||
//var scheduleFetalMovementPush = await _serviceEtcd.GetValAsync(fetalMovementKey).ConfigureAwait(false); | |||||
//if (string.IsNullOrWhiteSpace(scheduleFetalMovementPush)) | |||||
//{ | |||||
// var fetalMovementInterval = 60 * 15; | |||||
// var fetalMovementNow = DateTime.Now; | |||||
// var fetalMovementTimeNextRun = fetalMovementNow.Add(TimeSpan.FromSeconds(fetalMovementInterval)); | |||||
// var fetalMovementTTL = fetalMovementInterval; | |||||
// var data = new | |||||
// { | |||||
// imei = heartRate.Serialno, | |||||
// create_time = fetalMovementNow.ToString("yyyy-MM-dd HH:mm:ss"), | |||||
// fetalMovementTTL, | |||||
// next_run_time = fetalMovementTimeNextRun.ToString("yyyy-MM-dd HH:mm:ss") | |||||
// }; | |||||
// var result = JsonConvert.SerializeObject(data); | |||||
// await _serviceEtcd.PutValAsync(fetalKey, result, fetalMovementTTL, false).ConfigureAwait(false); | |||||
//} | |||||
#endregion | |||||
} | |||||
#region 定时下发触发器(定时建模) | #region 定时下发触发器(定时建模) | ||||
var key = $"health_monitor/schedule_push/pregnancy_heart_rate/imei/{heartRate.Serialno}"; | var key = $"health_monitor/schedule_push/pregnancy_heart_rate/imei/{heartRate.Serialno}"; | ||||
@@ -333,5 +374,25 @@ namespace HealthMonitor.Service.Resolver | |||||
await _serviceIotApi.SetFetalHeartRateConfig(heartRate.Serialno, fetalHeartRate, sampleTime, isAbnormal); | await _serviceIotApi.SetFetalHeartRateConfig(heartRate.Serialno, fetalHeartRate, sampleTime, isAbnormal); | ||||
} | } | ||||
} | } | ||||
private async Task SetIntervalTriggerAsync(string key,string imei, long interval) | |||||
{ | |||||
// var key = $"health_monitor/schedule_push/{type}/imei/{imei}"; | |||||
var schedulePush = await _serviceEtcd.GetValAsync(key).ConfigureAwait(false); | |||||
if (string.IsNullOrWhiteSpace(schedulePush)) | |||||
{ | |||||
var now = DateTime.Now; | |||||
var timeNextRun = now.Add(TimeSpan.FromSeconds(interval)); | |||||
var data = new | |||||
{ | |||||
imei, | |||||
create_time = now.ToString("yyyy-MM-dd HH:mm:ss"), | |||||
ttl = interval, | |||||
next_run_time = timeNextRun.ToString("yyyy-MM-dd HH:mm:ss") | |||||
}; | |||||
var result = JsonConvert.SerializeObject(data); | |||||
await _serviceEtcd.PutValAsync(key, result, interval, false).ConfigureAwait(false); | |||||
} | |||||
} | |||||
} | } | ||||
} | } |
@@ -174,6 +174,7 @@ namespace HealthMonitor.WebApi | |||||
.AddSingleton<PersonCacheManager>() | .AddSingleton<PersonCacheManager>() | ||||
.AddSingleton<DeviceCacheManager>() | .AddSingleton<DeviceCacheManager>() | ||||
.AddSingleton<FhrPhrMapCacheManager>() | .AddSingleton<FhrPhrMapCacheManager>() | ||||
.AddSingleton<FetalMovementNormalValueRangeCacheManager>() | |||||
.AddSingleton<BloodPressReferenceValueCacheManager>(); | .AddSingleton<BloodPressReferenceValueCacheManager>(); | ||||
#endregion | #endregion | ||||
@@ -4,6 +4,7 @@ using Google.Protobuf.WellKnownTypes; | |||||
using HealthMonitor.Common; | using HealthMonitor.Common; | ||||
using HealthMonitor.Common.helper; | using HealthMonitor.Common.helper; | ||||
using HealthMonitor.Core.Common.Extensions; | using HealthMonitor.Core.Common.Extensions; | ||||
using HealthMonitor.Core.Pipeline; | |||||
using HealthMonitor.Model.Config; | using HealthMonitor.Model.Config; | ||||
using HealthMonitor.Model.Service; | using HealthMonitor.Model.Service; | ||||
using HealthMonitor.Model.Service.Mapper; | using HealthMonitor.Model.Service.Mapper; | ||||
@@ -17,12 +18,16 @@ using Microsoft.EntityFrameworkCore.Metadata.Internal; | |||||
using Microsoft.Extensions.Options; | using Microsoft.Extensions.Options; | ||||
using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
using Newtonsoft.Json.Linq; | using Newtonsoft.Json.Linq; | ||||
using System; | |||||
using System.Reflection; | using System.Reflection; | ||||
using System.Threading.Channels; | using System.Threading.Channels; | ||||
using TDengineDriver; | using TDengineDriver; | ||||
using TDengineTMQ; | using TDengineTMQ; | ||||
using TelpoDataService.Util.Clients; | using TelpoDataService.Util.Clients; | ||||
using TelpoDataService.Util.Entities.GpsCard; | |||||
using TelpoDataService.Util.Entities.GpsLocationHistory; | using TelpoDataService.Util.Entities.GpsLocationHistory; | ||||
using TelpoDataService.Util.Models; | |||||
using TelpoDataService.Util.QueryObjects; | |||||
namespace HealthMonitor.WebApi | namespace HealthMonitor.WebApi | ||||
{ | { | ||||
@@ -40,6 +45,7 @@ namespace HealthMonitor.WebApi | |||||
private readonly BloodPressReferenceValueCacheManager _bpRefValCacheManager; | private readonly BloodPressReferenceValueCacheManager _bpRefValCacheManager; | ||||
private readonly PersonCacheManager _personCacheMgr; | private readonly PersonCacheManager _personCacheMgr; | ||||
private readonly DeviceCacheManager _deviceCacheMgr; | private readonly DeviceCacheManager _deviceCacheMgr; | ||||
private readonly FetalMovementNormalValueRangeCacheManager _mgrFetalMovementNormalValueRangeCache; | |||||
private readonly GpsLocationHistoryAccessorClient<HisGpsFetalHeartRate> _hisFetalHeartApiClient; | private readonly GpsLocationHistoryAccessorClient<HisGpsFetalHeartRate> _hisFetalHeartApiClient; | ||||
@@ -50,6 +56,7 @@ namespace HealthMonitor.WebApi | |||||
IOptions<BoodPressResolverConfig> optionBoodPressResolver, PackageProcess processor, | IOptions<BoodPressResolverConfig> optionBoodPressResolver, PackageProcess processor, | ||||
TDengineDataSubcribe tdEngineDataSubcribe, TDengineService serviceDengine, | TDengineDataSubcribe tdEngineDataSubcribe, TDengineService serviceDengine, | ||||
GpsLocationHistoryAccessorClient<HisGpsFetalHeartRate> hisFetalHeartApiClient, | GpsLocationHistoryAccessorClient<HisGpsFetalHeartRate> hisFetalHeartApiClient, | ||||
FetalMovementNormalValueRangeCacheManager fetalMovementNormalValueRangeCacheMgr, | |||||
HttpHelper httpHelper, EtcdService serviceEtcd, DeviceCacheManager deviceCacheMgr) | HttpHelper httpHelper, EtcdService serviceEtcd, DeviceCacheManager deviceCacheMgr) | ||||
{ | { | ||||
_logger = logger; | _logger = logger; | ||||
@@ -65,6 +72,7 @@ namespace HealthMonitor.WebApi | |||||
_personCacheMgr = personCacheMgr; | _personCacheMgr = personCacheMgr; | ||||
_deviceCacheMgr = deviceCacheMgr; | _deviceCacheMgr = deviceCacheMgr; | ||||
_hisFetalHeartApiClient = hisFetalHeartApiClient; | _hisFetalHeartApiClient = hisFetalHeartApiClient; | ||||
_mgrFetalMovementNormalValueRangeCache = fetalMovementNormalValueRangeCacheMgr; | |||||
} | } | ||||
public override Task StartAsync(CancellationToken cancellationToken) | public override Task StartAsync(CancellationToken cancellationToken) | ||||
@@ -286,28 +294,133 @@ namespace HealthMonitor.WebApi | |||||
#region 注册定时计算胎心数据触发器 {interval} 秒后 | #region 注册定时计算胎心数据触发器 {interval} 秒后 | ||||
//var fetalKey = $"health_monitor/schedule_push/cal_fetal_heart_rate/imei/{imeiDel}"; | //var fetalKey = $"health_monitor/schedule_push/cal_fetal_heart_rate/imei/{imeiDel}"; | ||||
var fetalKey = key; | |||||
var scheduleFetalPush = await _serviceEtcd.GetValAsync(fetalKey).ConfigureAwait(false); | |||||
if (string.IsNullOrWhiteSpace(scheduleFetalPush)) | |||||
//var fetalKey = key; | |||||
//var scheduleFetalPush = await _serviceEtcd.GetValAsync(fetalKey).ConfigureAwait(false); | |||||
//if (string.IsNullOrWhiteSpace(scheduleFetalPush)) | |||||
//{ | |||||
// // var fetalInterval = (int)watchConfig!["interval"]!; | |||||
// var fetalInterval = 60 * 15; | |||||
// var fetalNow = DateTime.Now; | |||||
// var fetalTimeNextRun = fetalNow.Add(TimeSpan.FromSeconds(fetalInterval)); | |||||
// var fetalTTL = fetalInterval; | |||||
// var data = new | |||||
// { | |||||
// imei = imeiDel, | |||||
// create_time = fetalNow.ToString("yyyy-MM-dd HH:mm:ss"), | |||||
// fetalTTL, | |||||
// next_run_time = fetalTimeNextRun.ToString("yyyy-MM-dd HH:mm:ss") | |||||
// }; | |||||
// var result = JsonConvert.SerializeObject(data); | |||||
// await _serviceEtcd.PutValAsync(fetalKey, result, fetalTTL, false).ConfigureAwait(false); | |||||
//} | |||||
await SetIntervalTriggerAsync(key, imeiDel, 60 * 15); | |||||
#endregion | |||||
} | |||||
} | |||||
} | |||||
//health_monitor/schedule_push/cal_fetal_movement/imei/ | |||||
else if (key.Contains("health_monitor/schedule_push/cal_fetal_movement/imei/")) | |||||
{ | |||||
// 计算胎动数据 | |||||
var watchConfig = await _deviceCacheMgr.GetGpsDeviceWatchConfigCacheObjectBySerialNoAsync(imeiDel, "0067"); | |||||
var isFetalHeartEnable = watchConfig != null && (int)watchConfig["enabled"]! == 1; | |||||
if (isFetalHeartEnable) | |||||
{ | |||||
// 检查胎心建模 | |||||
var fchr = await _serviceTDengine.GetLastAsync<PregnancyCommonHeartRateModel>(); | |||||
if (fchr != null) | |||||
{ | |||||
// 获取孕妇心率数据接近最近2小时的数据 | |||||
var phr = await _serviceTDengine.GetBySerialNoAsync<PregnancyHeartRateModel>(imeiDel, 1); | |||||
var now = DateTime.Now; | |||||
var ago2hrs = now.AddHours(-2); | |||||
var phrRange = phr.Where(i => i.LastUpdate >= ago2hrs) | |||||
.OrderByDescending(i => i.LastUpdate) | |||||
.Select(i => i.LastUpdate) | |||||
.ToList(); | |||||
if (phrRange.Count >= 2) | |||||
{ | { | ||||
// var fetalInterval = (int)watchConfig!["interval"]!; | |||||
var fetalInterval = 60 * 15; | |||||
var duringMins = (phrRange.First() - phrRange.Last()).TotalMinutes; | |||||
//在餐后时间段(8:00~10:00,12:00~14:00,18:00~20:00,22:00~24:00)取中间值。其他时间段取正常起始值 | |||||
bool isInTimeRanges = IsNowInTimeRanges(); | |||||
var fetalNow = DateTime.Now; | |||||
var fetalTimeNextRun = fetalNow.Add(TimeSpan.FromSeconds(fetalInterval)); | |||||
var fetalTTL = fetalInterval; | |||||
var data = new | |||||
long.TryParse(watchConfig!["EDOC"]!.ToString(), out long edoc); | |||||
int pregnancyWeeks = (DateTime.Now - DateTimeUtil.GetDateTimeFromUnixTimeMilliseconds(edoc).AddDays(-280)).Days / 7; | |||||
if (pregnancyWeeks >= 12 && pregnancyWeeks <= 50) | |||||
{ | { | ||||
imei = imeiDel, | |||||
create_time = fetalNow.ToString("yyyy-MM-dd HH:mm:ss"), | |||||
fetalTTL, | |||||
next_run_time = fetalTimeNextRun.ToString("yyyy-MM-dd HH:mm:ss") | |||||
}; | |||||
var result = JsonConvert.SerializeObject(data); | |||||
await _serviceEtcd.PutValAsync(fetalKey, result, fetalTTL, false).ConfigureAwait(false); | |||||
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); | |||||
var sampleTime = DateTimeUtil.ConvertToTimeStamp(DateTime.Now).ToString(); | |||||
// 告警上限阀值 | |||||
var upperAlarmThreshold = (int)watchConfig["upperAlarmThreshold"]!; | |||||
// 告警下限阀值 | |||||
var lowerAlarmThreshold = (int)watchConfig["lowerAlarmThreshold"]!; | |||||
GeneralParam param = new() | |||||
{ | |||||
Filters = new List<QueryFilterCondition> | |||||
{ | |||||
new () | |||||
{ | |||||
Key=nameof(HisGpsFetalHeartRate.Serialno), | |||||
Value=imeiDel, | |||||
ValueType=QueryValueTypeEnum.String, | |||||
Operator=QueryOperatorEnum.Equal | |||||
} | |||||
}, | |||||
OrderBys = new List<OrderByCondition> | |||||
{ | |||||
new() { | |||||
IsDesc=true, | |||||
Key=nameof(HisGpsFetalHeartRate.CreateTime) | |||||
} | |||||
} | |||||
}; | |||||
var frh = await _hisFetalHeartApiClient.GetFirstAsync(param, imeiDel.Substring(imeiDel.Length - 2), null, new RequestHeader { RequestId = Guid.NewGuid().ToString("D") }).ConfigureAwait(false); | |||||
if (frh != null) | |||||
{ | |||||
var fetalHeartRate = frh.HeartRate; | |||||
var isAbnormal = fetalHeartRate > upperAlarmThreshold ? 1 : (fetalHeartRate < lowerAlarmThreshold ? 2 : 0); | |||||
// 推送到api/v1/open/OpenIot/SetFetalMovementConfig | |||||
await _serviceIotApi.SetFetalMovementConfig(imeiDel, fetalMovement, sampleTime, isAbnormal); | |||||
// 保存到MySQL数据库 | |||||
} | |||||
} | |||||
} | } | ||||
#endregion | |||||
} | } | ||||
#region 定时计算胎动数据触发器 2小时后 | |||||
await SetIntervalTriggerAsync(key, imeiDel, 60 * 60 * 2); | |||||
#endregion | |||||
} | } | ||||
@@ -646,5 +759,41 @@ namespace HealthMonitor.WebApi | |||||
} | } | ||||
private async Task SetIntervalTriggerAsync(string key, string imei, long interval) | |||||
{ | |||||
// var key = $"health_monitor/schedule_push/{type}/imei/{imei}"; | |||||
var schedulePush = await _serviceEtcd.GetValAsync(key).ConfigureAwait(false); | |||||
if (string.IsNullOrWhiteSpace(schedulePush)) | |||||
{ | |||||
var now = DateTime.Now; | |||||
var timeNextRun = now.Add(TimeSpan.FromSeconds(interval)); | |||||
var data = new | |||||
{ | |||||
imei, | |||||
create_time = now.ToString("yyyy-MM-dd HH:mm:ss"), | |||||
ttl = interval, | |||||
next_run_time = timeNextRun.ToString("yyyy-MM-dd HH:mm:ss") | |||||
}; | |||||
var result = JsonConvert.SerializeObject(data); | |||||
await _serviceEtcd.PutValAsync(key, result, interval, false).ConfigureAwait(false); | |||||
} | |||||
} | |||||
public static bool IsNowInTimeRanges() | |||||
{ | |||||
var now = DateTime.Now.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); | |||||
} | |||||
} | } | ||||
} | } |