using Etcdserverpb; using Google.Protobuf.WellKnownTypes; using HealthMonitor.Common; using HealthMonitor.Common.helper; using HealthMonitor.Model.Service.Mapper; using HealthMonitor.Service.Biz; using HealthMonitor.Service.Biz.db; using HealthMonitor.Service.Cache; using HealthMonitor.Service.Etcd; using HealthMonitor.Service.MessageQueue; using HealthMonitor.Service.Resolver.Interface; using HealthMonitor.Service.Sub; using HealthMonitor.Service.Sub.Topic.Model; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; using TelpoDataService.Util.Clients; using TelpoDataService.Util.Entities.GpsCard; using TelpoDataService.Util.Entities.GpsLocationHistory; using TelpoDataService.Util.Models; using TelpoDataService.Util.QueryObjects; namespace HealthMonitor.Service.Resolver { public class PregnancyHeartRateResolver : IResolver { private readonly ILogger _logger; private readonly TDengineService _serviceTDengine; private readonly DeviceCacheManager _deviceCacheMgr; private readonly IotApiService _serviceIotApi; private readonly AsyncLocal _messageId = new(); private readonly AsyncLocal _msgData = new(); private readonly HttpHelper _httpHelper = default!; private readonly EtcdService _serviceEtcd; private readonly GpsLocationHistoryAccessorClient _hisFetalHeartApiClient; private readonly GpsLocationHistoryAccessorClient _hisFetalMovementApiClient; private readonly FetalMovementNormalValueRangeCacheManager _mgrFetalMovementNormalValueRangeCache; private readonly MqProcessLogic _serviceMqProcess; private static int[] SCHEDULE_HOUR = new int[] { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24 }; public PregnancyHeartRateResolver(ILogger logger, HttpHelper httpHelper, EtcdService serviceEtcd, DeviceCacheManager deviceCacheMgr, MqProcessLogic serviceMqProcess, IotApiService iotApiService, TDengineService serviceDengine, FetalMovementNormalValueRangeCacheManager fetalMovementNormalValueRangeCacheMgr, GpsLocationHistoryAccessorClient hisFetalHeartApiClient, GpsLocationHistoryAccessorClient hisFetalMovementApiClient ) { _logger = logger; _httpHelper = httpHelper; _serviceEtcd = serviceEtcd; _serviceTDengine = serviceDengine; _deviceCacheMgr = deviceCacheMgr; _serviceIotApi = iotApiService; _serviceMqProcess= serviceMqProcess; _hisFetalHeartApiClient = hisFetalHeartApiClient; _hisFetalMovementApiClient = hisFetalMovementApiClient; _mgrFetalMovementNormalValueRangeCache = fetalMovementNormalValueRangeCacheMgr; } public void SetResolveInfo(PackageMsgModel msg) { var topicHmPregnancyHeartRate = JsonConvert.DeserializeObject(msg.DetailData.ToString()!); _messageId.Value = msg.MessageId; _msgData.Value = new HisGpsHeartRate() { HeartRateId = topicHmPregnancyHeartRate!.PregnancyHeartRateId, MessageId = topicHmPregnancyHeartRate!.MessageId, Serialno = topicHmPregnancyHeartRate!.Serialno, HeartRate= topicHmPregnancyHeartRate.PregnancyHeartRate, LastUpdate = DateTimeUtil.GetDateTimeFromUnixTimeMilliseconds(SafeType.SafeInt64(topicHmPregnancyHeartRate.LastUpdate) / 1000000), CreateTime = DateTimeUtil.GetDateTimeFromUnixTimeMilliseconds(SafeType.SafeInt64(topicHmPregnancyHeartRate.CreateTime) / 1000000), Method = topicHmPregnancyHeartRate!.Method, IsDisplay = topicHmPregnancyHeartRate!.IsDisplay ? 1 : 0 }; } public override string ToString() { return $"{nameof(PregnancyHeartRateResolver)}[{_messageId.Value}]"; } public async Task ExecuteMessageAsync() { var messageId = _messageId.Value; var heartRate = _msgData.Value!; var watchConfig = await _deviceCacheMgr.GetGpsDeviceWatchConfigCacheObjectBySerialNoAsync(heartRate.Serialno, "0067"); var isFetalHeartEnable = watchConfig != null && (int)watchConfig["enabled"]! == 1; if (isFetalHeartEnable) { #region 定时下发触发器(定时建模) var key = $"health_monitor/schedule_push/pregnancy_heart_rate/imei/{heartRate.Serialno}"; var schedule_push = await _serviceEtcd.GetValAsync(key).ConfigureAwait(false); if (string.IsNullOrWhiteSpace(schedule_push)) { // 注册首次下推 var interval = 0; // 获取当前时间 DateTime now = DateTime.Now; var rand = new Random(); var pushSec = rand.Next(59); int pushMin = int.TryParse(heartRate.Serialno.AsSpan(heartRate.Serialno.Length - 1), out pushMin) ? pushMin : 10; // 计算距离下一个$interval天后的8点的时间间隔 DateTime nextRunTime = new DateTime(now.Year, now.Month, now.Day, 6, pushMin, pushSec).AddDays(interval); TimeSpan timeUntilNextRun = nextRunTime - now; if (timeUntilNextRun < TimeSpan.Zero) { timeUntilNextRun = timeUntilNextRun.Add(TimeSpan.FromDays(1)); nextRunTime += TimeSpan.FromDays(1); } var ttl = (long)timeUntilNextRun.TotalSeconds; var data = new { imei = heartRate.Serialno, create_time = now.ToString("yyyy-MM-dd HH:mm:ss"), ttl, next_run_time = nextRunTime.ToString("yyyy-MM-dd HH:mm:ss") }; var result = JsonConvert.SerializeObject(data); await _serviceEtcd.PutValAsync(key, result, ttl, false).ConfigureAwait(false); } #endregion // 高频心率采样间隔 highFreqSampleInterval = highFreqSampleInterval+5,增加5秒兼容 var highFreqSampleInterval = (int)watchConfig!["highFreqSampleInterval"]! + 5; // 触发高频监测的心率上限值 var triggerHighFreqHigh = (int)watchConfig["triggerHighFreqHigh"]!; // 触发高频监测的心率下限值 var triggerHighFreqLow = (int)watchConfig["triggerHighFreqLow"]!; //停止高频心率采样心率连续正常次数 var stopHighFreqSampleCount = (int)watchConfig["stopHighFreqSampleCount"]!; // 高频心率采集时长 0 为持续采集,非零为高频心率的采集时长 var highFreqSampleTimes = (int)watchConfig["highFreqSampleTimes"]!; // 告警上限阀值 var upperAlarmThreshold = (int)watchConfig["upperAlarmThreshold"]!; // 告警下限阀值 var lowerAlarmThreshold = (int)watchConfig["lowerAlarmThreshold"]!; // EDOC var edoc = DateTimeUtil.ToDateTime(watchConfig!["EDOC"]!.ToString()); // interval (分钟) var intervalFHR = (int)watchConfig["interval"]!; var phr = await _serviceTDengine.GetBySerialNoAsync(heartRate.Serialno, 7); if (phr.Count >= 30) { #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 计算胎心数据(按心率时间LastUpdate) var commonPHR = await _serviceTDengine.GetLastAsync(heartRate.Serialno); if (commonPHR == null) { // 处理孕妇业务,计算一般心率并下发 commonPHR = await _serviceTDengine.InitPregnancyCommonHeartRateModeAsync(heartRate.Serialno, highFreqSampleInterval: highFreqSampleInterval); // 建模完成 var flag = await _serviceIotApi.SetFetalConfig(heartRate.Serialno, 1, commonPHR!.MaxValue, commonPHR!.MinValue); _logger.LogInformation($"{heartRate.Serialno} 记录数量足够,建模完成"); // 保存到TDengine数据库 await _serviceTDengine.InsertAsync("hm_pchr", commonPHR!); _logger.LogInformation($"保存TDengine完成"); } // 获取最近的两个记录,并计算它们的 LastUpdate 时间差 var firstTwoPhr = phr.OrderByDescending(i => i.LastUpdate).Take(2).Select(i => i.LastUpdate).ToList(); var timeDiff = firstTwoPhr[0] - firstTwoPhr[1]; // 如果需要,将时间差转换为秒 var timeDiffInSeconds = timeDiff.TotalSeconds; // 高频统计结束时间 var FreqStatsEnd = DateTime.Now; // 高频心率启动 if (timeDiffInSeconds <= highFreqSampleInterval) { var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno); if (phrFreqstatus == null) { /// 设置高频状态 _logger.LogInformation($"{heartRate.Serialno} 进入高频心率启动状态 timeDiffInSeconds {timeDiffInSeconds},highFreqSampleInterval:{highFreqSampleInterval}"); // 设置高频状态 var freqFirstPhr = phr.OrderByDescending(i => i.LastUpdate).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.LastUpdate).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()); // 高频数据不建模 FreqStatsEnd = (DateTime)heartRate.LastUpdate!; _logger.LogInformation($"{heartRate.Serialno} 高频状态已经持续{(FreqStatsEnd - phrFreqstatus!.LastUpdate).TotalSeconds} 秒,连续 {stopHighFreqSampleCount} 次采样心率正常,将下发指令"); //await SaveAndPushFreqFetalHeartRateAsync(heartRate, commonPHR, upperAlarmThreshold, lowerAlarmThreshold, avgPhr, DateTimeUtil.ConvertToTimeStamp(phrFreqstatus!.LastUpdate).ToString()); await SaveAndPushFetalHeartRateAsync(heartRate, commonPHR, upperAlarmThreshold, lowerAlarmThreshold, avgPhr, DateTimeUtil.ConvertToTimeStamp(phrFreqstatus!.LastUpdate).ToString(), phrFreqstatus!.LastUpdate, FreqStatsEnd); // 删除高频状态的首条记录 await _deviceCacheMgr.DelPregnancyHeartRateFreqStatusAsync(heartRate.Serialno); _logger.LogInformation($"{heartRate.Serialno} 连续正常结束高频心率状态, timeDiffInSeconds {timeDiffInSeconds},highFreqSampleInterval:{highFreqSampleInterval},高频状态持续{((DateTime)heartRate.LastUpdate - phrFreqstatus!.LastUpdate).TotalSeconds} 秒"); } #endregion } // 高频心率结束或平常心率 else { var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno); // 高频心率结束 if (phrFreqstatus != null) { /// 在highFreqSampleTimes=0一直异常(大于等于triggerHighFreqLow,少于等于triggerHighFreqHig), /// 取所有值的平均值,推送胎心数据到api/v1/open/OpenIot/SetFetalHeartRateConfig if (highFreqSampleTimes == 0) { var avgPhr = phr.OrderByDescending(i => i.LastUpdate) .Where(i => i.LastUpdate >= phrFreqstatus?.LastUpdate) .Skip(1) // 去除首条 .Where(i => i.PregnancyHeartRate < triggerHighFreqLow || i.PregnancyHeartRate > triggerHighFreqHigh) .Select(i => i.PregnancyHeartRate).Average(); // 推送胎心数据到 api/v1/open/OpenIot/SetFetalHeartRateConfig // 计算一般心率得到胎心系数 //await SaveAndPushFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, avgPhr); //await SaveAndPushFreqFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, avgPhr, DateTimeUtil.ConvertToTimeStamp(DateTime.Now).ToString()); // 高频数据不建模 FreqStatsEnd = firstTwoPhr[1]; _logger.LogInformation($"{heartRate.Serialno} 高频状态已经持续{(FreqStatsEnd - phrFreqstatus!.LastUpdate).TotalSeconds} 秒,highFreqSampleTimes={highFreqSampleTimes}秒,即将结束高频状态,将下发指令"); //await SaveAndPushFreqFetalHeartRateAsync(heartRate, commonPHR, upperAlarmThreshold, lowerAlarmThreshold, avgPhr, DateTimeUtil.ConvertToTimeStamp(phrFreqstatus!.LastUpdate).ToString()); await SaveAndPushFetalHeartRateAsync(heartRate, commonPHR, upperAlarmThreshold, lowerAlarmThreshold, avgPhr, DateTimeUtil.ConvertToTimeStamp(phrFreqstatus!.LastUpdate).ToString(), phrFreqstatus!.LastUpdate, FreqStatsEnd); } /// 在highFreqSampleTimes>0一直异常(大于等于triggerHighFreqLow,少于等于triggerHighFreqHig), /// 取所有值的平均值,推送胎心数据到api/v1/open/OpenIot/SetFetalHeartRateConfig if (highFreqSampleTimes > 0 && heartRate.LastUpdate >= (phrFreqstatus?.LastUpdate.AddSeconds(highFreqSampleTimes))) { // 获取高频心率数据个数 var filterPhr = phr .Where(i => i.LastUpdate >= phrFreqstatus?.LastUpdate) .Skip(1) .ToList(); //var freqCollection = new List(); //PregnancyHeartRateModel? previousItem = null; //foreach (var item in filterPhr) //{ // if (previousItem != null) // { // var timeNextDiff = (previousItem!.LastUpdate - item.LastUpdate).TotalSeconds; // if (timeNextDiff <= highFreqSampleInterval) // { // freqCollection.Add(item); // } // } // previousItem = item; //} _logger.LogInformation($"{heartRate.Serialno} {phrFreqstatus?.LastUpdate.ToString("yyyy-MM-dd HH:mm:ss")}--{firstTwoPhr[1].ToString("yyyy-MM-dd HH:mm:ss")} 产生高频心率数量 {filterPhr.Count} 条"); // 高频心率数据大于等于stopHighFreqSampleCount/12个才计算胎心数据 if (filterPhr.Count >= stopHighFreqSampleCount) { var avgPhr = filterPhr .OrderByDescending(i => i.LastUpdate) .Take(stopHighFreqSampleCount) // 计算最后12条 //.Where(i => i.PregnancyHeartRate < triggerHighFreqLow || i.PregnancyHeartRate > triggerHighFreqHigh) .Select(i => i.PregnancyHeartRate).Average(); // 高频数据不建模 FreqStatsEnd = firstTwoPhr[1]; _logger.LogInformation($"{heartRate.Serialno} 高频状态已经持续{(FreqStatsEnd - phrFreqstatus!.LastUpdate).TotalSeconds} 秒,超过约定的 {highFreqSampleTimes} 秒,即将结束高频状态,将下发指令"); //await 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.LogInformation($"{heartRate.Serialno} 高频心率的数据不足{stopHighFreqSampleCount}条,不进行胎心计算"); } } //不满足持续10分钟highFreqSampleTimes else { _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 { // 计算本次平常心率的胎心数据 await CalculateNormalFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, intervalFHR, commonPHR); } } #endregion } else { _logger.LogInformation($"{heartRate.Serialno} 记录不足30条,建模中"); } } //try //{ //} //catch (Exception ex) //{ // _logger.LogError($"{heartRate.Serialno} 处理孕妇心率数据异常 \n{ex.Message}\n{ex.StackTrace}"); //} } /// /// 平常心率计算胎心数据 /// /// /// /// /// /// /// private async Task CalculateNormalFetalHeartRateAsync(HisGpsHeartRate heartRate, int upperAlarmThreshold, int lowerAlarmThreshold, int intervalFHR, PregnancyCommonHeartRateModel? commonPHR) { // 上15分钟的数据 // 获取当前时间 DateTime nowInterval = (DateTime)heartRate.LastUpdate!; // 计算last_update到上一间隔的分钟数 int minutesToSubtract = nowInterval.Minute % intervalFHR; // 计算上一间隔的时间 DateTime previousInterval = nowInterval.AddMinutes(-minutesToSubtract).AddSeconds(-nowInterval.Second).AddMilliseconds(-nowInterval.Millisecond); // 使用 last_update 上一刻 var sampleTimeFHR = DateTimeUtil.ConvertToTimeStamp(previousInterval).ToString(); // 计算last_update到下一间隔的分钟数 int minutesToAdd = intervalFHR - (nowInterval.Minute % intervalFHR); if (minutesToAdd == intervalFHR) { minutesToAdd = 0; // 如果已经是间隔,则不需要增加分钟 } // 计算下一间隔的时间 DateTime nextInterval = nowInterval.AddMinutes(minutesToAdd) .AddSeconds(-nowInterval.Second) .AddMilliseconds(-nowInterval.Millisecond); var daysPhr = await _serviceTDengine.GetBySerialNoAsync(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); } /// /// /// /// /// /// /// /// /// /// /// /// private async Task SaveAndPushFetalHeartRateAsync(HisGpsHeartRate heartRate, PregnancyCommonHeartRateModel commonPHR, int upperAlarmThreshold, int lowerAlarmThreshold, double phrValue, string sampleTime,DateTime statStartTime, DateTime statEndTime) { // 计算胎心=孕妇心率*系数 var fetalHeartRate = SafeType.SafeInt(phrValue * commonPHR?.StatModeAvgFprCoefficient!); //fetalHeartRate = fetalHeartRate > 220 ? 220 : fetalHeartRate; // 胎心的最大值调整为220,超过都按该值220输出 if (fetalHeartRate >= 220) { // 先使用最小系数计算 var statMaxValueFprCoefficient = commonPHR?.StatMaxValueFprCoefficient!; var statMinValueFprCoefficient = commonPHR?.StatMinValueFprCoefficient!; var coefficient = statMaxValueFprCoefficient < statMinValueFprCoefficient ? statMaxValueFprCoefficient : statMinValueFprCoefficient; fetalHeartRate = SafeType.SafeInt(phrValue * coefficient); if (fetalHeartRate < 220) { _logger.LogWarning($"{heartRate.Serialno} 使用极值系数 {coefficient} ,建模数据可能出现异常,请检查"); } else { fetalHeartRate = 220; _logger.LogWarning($"{heartRate.Serialno} 使用所有系数都不能放映实际,建模数据可能出现异常,请检查"); } } var isAbnormal = fetalHeartRate > upperAlarmThreshold ? 1 : (fetalHeartRate < lowerAlarmThreshold ? 2 : 0); var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno); if (phrFreqstatus == null) isAbnormal = 0; //if (!isFreq) //{ // statStartTime = heartRate.LastUpdate; // //} // 保存到 数据服务 MySQL 数据库 HisGpsFetalHeartRate gpsFetalHeartRate = new() { FetalHeartRateId = Guid.NewGuid().ToString("D"), PersonId = commonPHR!.PersonId, Serialno = heartRate.Serialno, HeartRate = fetalHeartRate, SampleTime = sampleTime.Length > 10 ? sampleTime.Substring(0, 10) : sampleTime, IsAbnormal = isAbnormal, StatStartTime = statStartTime, StatEndTime = statEndTime,//commonPHR.StatEndTime, CreateTime = DateTime.Now, Method = 1, IsDisplay = 1, DeviceKey = commonPHR!.DeviceKey }; await _hisFetalHeartApiClient.AddAsync(gpsFetalHeartRate).ConfigureAwait(false); // 推送到api/v1/open/OpenIot/SetFetalHeartRateConfig await _serviceIotApi.SetFetalHeartRateConfig(heartRate.Serialno, fetalHeartRate, sampleTime, isAbnormal); var device = await _deviceCacheMgr.GetDeviceBySerialNoAsync(heartRate.Serialno).ConfigureAwait(false); var fhrMsgId = $"{heartRate.Serialno}-{sampleTime}-{Guid.NewGuid().ToString("D")[^3..]}"; var fhrMsgTime = DateTimeUtil.GetDateTimeFromUnixTimeMilliseconds(long.Parse(sampleTime.Length < 13 ? sampleTime.PadRight(13, '0') : sampleTime)).ToString("yyyy-MM-dd HH:mm:ss"); // 胎心数据推送到第三方 var topic = "topic.push.third"; var fhrThridMsg = new { messageId = fhrMsgId, topic = topic, time = fhrMsgTime, data = new { imei = heartRate.Serialno, value = fetalHeartRate, isAbnormal, type = "fetalHeart" } }; await _serviceMqProcess.ProcessIMEIEventMessageAsync(fhrMsgId, topic, 31, fhrThridMsg).ConfigureAwait(false); // 胎心数据推送到微信 if (isAbnormal != 0) { topic = "topic.push.wx"; var fhrMsg = new { messageId = fhrMsgId, topic = topic, time = fhrMsgTime, data = new { deviceId = device?.DeviceId, imei = heartRate.Serialno, alarmTypeId = 12, alarmDeviceName = heartRate.Serialno, alarmRemarks = JsonConvert.SerializeObject(new { fetalHeartValue = fetalHeartRate, isAbnormal = isAbnormal }), address = string.Empty, deviceKey = device?.DeviceId } }; await _serviceMqProcess.ProcessIMEIEventMessageAsync(fhrMsgId, topic, fhrMsg).ConfigureAwait(false); } } 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); } } } }