diff --git a/HealthMonitor.Model/Config/ServiceConfig.cs b/HealthMonitor.Model/Config/ServiceConfig.cs index 0febe59..ac40e72 100644 --- a/HealthMonitor.Model/Config/ServiceConfig.cs +++ b/HealthMonitor.Model/Config/ServiceConfig.cs @@ -10,17 +10,9 @@ public string EtcdServerAddress { get; set; } = default!; public string IotWebApiUrl { get; set; } = default!; - ///// - ///// Kafka服务地址 - ///// - //public string MqServerAddress { get; set; } - ///// - ///// 服务守护消息kafka服务地址 - ///// - //public string ServiceGuardMqAddress { get; set; } - ///// - ///// 服务守护消息主题 - ///// - //public string ServiceGuardMqTopic { get; set; } + + public string IotAuth { get; set; } = default!; + + public string IotCore { get; set; } = default!; } } diff --git a/HealthMonitor.Model/Service/Mapper/PregnancyCommonHeartRateModel.cs b/HealthMonitor.Model/Service/Mapper/PregnancyCommonHeartRateModel.cs new file mode 100644 index 0000000..fec844e --- /dev/null +++ b/HealthMonitor.Model/Service/Mapper/PregnancyCommonHeartRateModel.cs @@ -0,0 +1,79 @@ +using Newtonsoft.Json; +using SqlSugar; +using SqlSugar.TDengine; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HealthMonitor.Model.Service.Mapper +{ + [STableAttribute(STableName = "stb_hm_pregnancy_common_heart_rate")] + public class PregnancyCommonHeartRateModel + { + [JsonProperty("ts")] + [SqlSugar.SugarColumn(IsPrimaryKey = true, ColumnName = "ts", SqlParameterDbType = typeof(DateTime19))] + public DateTime Timestamp { get; set; } + + + [JsonProperty("person_id")] + [SqlSugar.SugarColumn(ColumnName = "person_id")] + public string PersonId { get; set; } = default!; + + [JsonProperty("device_key")] + [SqlSugar.SugarColumn(ColumnName = "device_key")] + public string DeviceKey { get; set; } = default!; + + [JsonProperty("serialno")] + [SqlSugar.SugarColumn(ColumnName = "serialno")] + public string SerialNumber { get; set; } = default!; + + + [JsonProperty("mode")] + [SqlSugar.SugarColumn(ColumnName = "mode")] + public float Mode { get; set; } + + [JsonProperty("percentage")] + [SqlSugar.SugarColumn(ColumnName = "percentage")] + public int Percentage { get; set; } + + [JsonProperty("max_value")] + [SqlSugar.SugarColumn(ColumnName = "max_value")] + public int MaxValue { get; set; } + + [JsonProperty("min_value")] + [SqlSugar.SugarColumn(ColumnName = "min_value")] + public int MinValue { get; set; } + + + [JsonProperty("original_max_value")] + [SqlSugar.SugarColumn(ColumnName = "original_max_value")] + public int OriginalMaxValue { get; set; } + + [JsonProperty("original_min_value")] + [SqlSugar.SugarColumn(ColumnName = "original_min_value")] + public int OriginalMinValue { get; set; } + + [JsonProperty("create_time")] + [SqlSugar.SugarColumn(ColumnName = "create_time")] + public DateTime CreateTime { get; set; } + + [JsonProperty("stat_start_time")] + [SqlSugar.SugarColumn(ColumnName = "stat_start_time")] + public DateTime StatStartTime { get; set; } + + + [JsonProperty("stat_end_time")] + [SqlSugar.SugarColumn(ColumnName = "stat_end_time")] + public DateTime StatEndTime { get; set; } + + [JsonProperty("remark")] + [SqlSugar.SugarColumn(ColumnName = "remark")] + public string Remark { get; set; } = default!; + + [JsonProperty("serial_tail_no")] + [SqlSugar.SugarColumn(IsIgnore = true, ColumnName = "serial_tail_no")] + public string SerialTailNumber { get; set; } = default!; + } +} diff --git a/HealthMonitor.Service/Biz/IotApiService.cs b/HealthMonitor.Service/Biz/IotApiService.cs new file mode 100644 index 0000000..6803934 --- /dev/null +++ b/HealthMonitor.Service/Biz/IotApiService.cs @@ -0,0 +1,328 @@ +using HealthMonitor.Common.helper; +using HealthMonitor.Model.Config; +using HealthMonitor.Service.Resolver; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using HealthMonitor.Model.Service; +using TelpoDataService.Util.Entities.GpsCard; +using TelpoDataService.Util; +using TelpoDataService.Util.Clients; +using TelpoDataService.Util.Models; +using TelpoDataService.Util.QueryObjects; +using HealthMonitor.Service.Cache; +using HealthMonitor.Model.Cache; +using Etcdserverpb; + +namespace HealthMonitor.Service.Biz +{ + public class IotApiService + { + private readonly ServiceConfig _configService; + private readonly ILogger _logger; + private readonly PersonCacheManager _personCacheMgr; + private readonly DeviceCacheManager _deviceCacheMgr; + + + private readonly HttpHelper _httpHelper = default!; + + private readonly GpsCardAccessorClient _gpsPersonApiClient; + + public IotApiService(ILogger logger, HttpHelper httpHelper, DeviceCacheManager deviceCacheMgr, GpsCardAccessorClient gpsPersonApiClient, IOptions optConfigService, PersonCacheManager personCacheMgr) + { + _configService = optConfigService.Value; + _httpHelper=httpHelper; + _logger = logger; + _personCacheMgr = personCacheMgr; + _gpsPersonApiClient = gpsPersonApiClient; + _deviceCacheMgr = deviceCacheMgr; + } + + #region 平台下发血压标定参数 + /// + /// 平台下发血压标定参数 + /// + /// + /// + public async Task SetBloodPressCalibrationConfigAsync(BloodPressCalibrationConfigModel bpsCalibrationConfig) + { + +#if DEBUG + var flag = true; +#else + //systolicCalibrationValue = 0, //收缩压标定值,值为0 表示不生效 + //diastolicCalibrationValue 0, //舒张压标定值,值为0表示不生效 + //systolicIncValue = 0, //收缩压显示增量,值为0 表示不生效 + //diastolicIncValue = 0 //舒张压显示增量,值为0 表示不生效 + + var flag = false; + try + { + var url = $"{_configService.IotWebApiUrl}Command/SetBloodPressCalibrationConfig"; + List> headers = new() + { + new KeyValuePair("AuthKey", "key1") + }; + var res = await _httpHelper.HttpToPostAsync(url, bpsCalibrationConfig, headers).ConfigureAwait(false); + _logger.LogInformation($"向{bpsCalibrationConfig.Imei}下发增量值数据:{JsonConvert.SerializeObject(bpsCalibrationConfig)},响应:{res}"); + var resJToken = JsonConvert.DeserializeObject(res ?? string.Empty) as JToken; + flag= resJToken?["message"]?.ToString().Equals("ok") ?? false; + + } + catch (Exception ex) + { + _logger.LogError($"{nameof(SetBloodPressCalibrationConfigAsync)} 下发血压增量值异常:{ex.Message}, {ex.StackTrace}"); + + } + + +#endif + + return flag; + + + } + + + public async Task SetBloodPressCalibrationConfig2Async(BloodPressCalibrationConfigModel bpsCalibrationConfig) + { + BloodPressCalibrationConfigModelReponse response = new BloodPressCalibrationConfigModelReponse(); + response.Flag = false; + response.Message = string.Empty; +#if DEBUG + //var flag = true; + response.Flag=true; +#else + //systolicCalibrationValue = 0, //收缩压标定值,值为0 表示不生效 + //diastolicCalibrationValue 0, //舒张压标定值,值为0表示不生效 + //systolicIncValue = 0, //收缩压显示增量,值为0 表示不生效 + //diastolicIncValue = 0 //舒张压显示增量,值为0 表示不生效 + + // var flag = false; + try + { + var url = $"{_configService.IotWebApiUrl}Command/SetBloodPressCalibrationConfig"; + List> headers = new() + { + new KeyValuePair("AuthKey", "key1") + }; + var res = await _httpHelper.HttpToPostAsync(url, bpsCalibrationConfig, headers).ConfigureAwait(false); + _logger.LogInformation($"向{bpsCalibrationConfig.Imei}下发增量值数据:{JsonConvert.SerializeObject(bpsCalibrationConfig)},响应:{res}"); + var resJToken = JsonConvert.DeserializeObject(res ?? string.Empty) as JToken; + //response.Flag= resJToken?["message"]?.ToString().Equals("ok") ?? false; + response.Flag = Convert.ToBoolean(resJToken?["succeed"]?.ToString()); + if (!response.Flag) + { + response.Message = resJToken?["message"]?.ToString()!; + } + } + catch (Exception ex) + { + _logger.LogError($"{nameof(SetBloodPressCalibrationConfigAsync)} 下发血压增量值异常:{ex.Message}, {ex.StackTrace}"); + + } + + +#endif + + return response; + } + + public async Task UpdatePersonRemarksAsync(string imei, int systolicRefValue, int diastolicRefValue, int systolicIncValue, int diastolicIncValue, string remarks = "is_blood_press") + { + var flag = false; + try + { + + // 保证实时性,先更新缓存,再更新数据库 + var personCache = await _personCacheMgr.GetDeviceGpsPersonCacheObjectBySerialNoAsync(new Guid().ToString(), imei).ConfigureAwait(false); + + if (personCache == null) + { + _logger.LogInformation($"{imei} -- Person remarks数据异常,检查缓存和数据库"); + } + else + { + var newRemarkData = new + { + imei, + time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), + commandValue = new + { + systolicCalibrationValue = systolicRefValue, //收缩压标定值,值为0 表示不生效 + diastolicCalibrationValue = diastolicRefValue, //舒张压标定值,值为0表示不生效 + systolicIncValue, //收缩压显示增量,值为0 表示不生效 + diastolicIncValue //舒张压显示增量,值为0 表示不生效 + } + }; + var newRemarkStr = $"{remarks}:{JsonConvert.SerializeObject(newRemarkData)}|"; + + personCache["person"]!["remarks"] = newRemarkStr; + bool cacheFlag = await _personCacheMgr.UpdateDeviceGpsPersonCacheObjectBySerialNoAsync(personCache, imei); + if (cacheFlag) + { + GeneralParam condition = new() + { + Filters = new List { + new QueryFilterCondition { + Key=nameof(GpsDevice.Serialno), + Value=imei, + Operator= QueryOperatorEnum.Equal, + ValueType=QueryValueTypeEnum.String + } + }, + OrderBys = new List { new OrderByCondition { Key = "serialno", IsDesc = true } } + + }; + _logger.LogInformation($"{imei} 更新缓存{nameof(UpdatePersonRemarksAsync)}成功,{JsonConvert.SerializeObject(personCache)}"); + // 读取数据库 + var person = await _gpsPersonApiClient.GetFirstAsync(condition, new RequestHeader() { RequestId = $"{imei}" }).ConfigureAwait(false); + // 更新字段 + person!.Remarks = newRemarkStr; + await _gpsPersonApiClient.UpdateAsync(person, new RequestHeader() { RequestId = $"{imei}" }).ConfigureAwait(false); + _logger.LogInformation($"{imei} 更新Person remarks字段|{person.Remarks}"); + + } + else + { + _logger.LogInformation($"{imei} 更新缓存和数据库{nameof(UpdatePersonRemarksAsync)}失败,{JsonConvert.SerializeObject(personCache)}"); + } + flag = cacheFlag; + } + // else if (string.IsNullOrWhiteSpace(personCache["person"]!["remarks"]!.ToString())) + //else if (personCache?["person"]!["remarks"]!.ToString()!=null) + //{ + // var newRemarkData = new + // { + // imei, + // time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), + // commandValue = new + // { + // systolicCalibrationValue = systolicRefValue, //收缩压标定值,值为0 表示不生效 + // diastolicCalibrationValue = diastolicRefValue, //舒张压标定值,值为0表示不生效 + // systolicIncValue, //收缩压显示增量,值为0 表示不生效 + // diastolicIncValue //舒张压显示增量,值为0 表示不生效 + // } + // }; + // var newRemarkStr = $"{remarks}:{JsonConvert.SerializeObject(newRemarkData)}|"; + + // personCache["person"]!["remarks"] = newRemarkStr; + // bool cacheFlag = await _personCacheMgr.UpdateDeviceGpsPersonCacheObjectBySerialNoAsync(personCache, imei); + // if (cacheFlag) + // { + // GeneralParam condition = new() + // { + // Filters = new List { + // new QueryFilterCondition { + // Key=nameof(GpsDevice.Serialno), + // Value=imei, + // Operator= QueryOperatorEnum.Equal, + // ValueType=QueryValueTypeEnum.String + // } + // }, + // OrderBys = new List { new OrderByCondition { Key = "serialno", IsDesc = true } } + + // }; + // _logger.LogInformation($"{imei} 更新缓存{nameof(UpdatePersonRemarksAsync)}成功,{JsonConvert.SerializeObject(personCache)}"); + // // 读取数据库 + // var person = await _gpsPersonApiClient.GetFirstAsync(condition, new RequestHeader() { RequestId = $"{imei}" }).ConfigureAwait(false); + // // 更新字段 + // person!.Remarks = newRemarkStr; + // await _gpsPersonApiClient.UpdateAsync(person, new RequestHeader() { RequestId = $"{imei}" }).ConfigureAwait(false); + // _logger.LogInformation($"{imei} 更新Person remarks字段|{person.Remarks}"); + + // } + // else + // { + // _logger.LogInformation($"{imei} 更新缓存和数据库{nameof(UpdatePersonRemarksAsync)}失败,{JsonConvert.SerializeObject(personCache)}"); + // } + // flag = cacheFlag; + //} + } + catch (Exception ex) + { + _logger.LogError($"{nameof(UpdatePersonRemarksAsync)} {imei}--更新个人信息异常:{ex.Message}, {ex.StackTrace}"); + } + return flag; + } + + #endregion + + #region 平台下发胎心监测参数 + public async Task SetFetalHeartRateConfig(string serialno, int modeStatus=0, int maxValue=0, int minValue = 0) + { + 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 + var getTokenUrl = $"{_configService.IotAuth}/getAccessToken2"; + var tokenReq = new + { + manufactorId= "7c7c38cb-d045-41d8-b3d0-fcaaa84a8f02", + imei= serialno + }; + var resToken = await _httpHelper.HttpToPostAsync(getTokenUrl, tokenReq).ConfigureAwait(false); + var tokenAuth= JsonConvert.DeserializeObject(resToken ?? string.Empty) as JToken; + var tokenAuthData = tokenAuth?["data"]?.ToString()??string.Empty; + if (tokenAuthData == null) + { + return false; + } + #endregion + + #region 发送到B端 + List> headers = new() + { + new KeyValuePair("TelpoManufactorId", tokenAuthData) + }; + var data = new + { + imeis = new string[] { serialno }, + enabled = (int)watchConfig["fetalParamters"]!["enabled"]!, + triggerHighFreqHigh = maxValue == 0 ? (int)watchConfig["fetalParamters"]!["triggerHighFreqHigh"]!:maxValue, + triggerLowFreqLow = minValue == 0 ? (int)watchConfig["fetalParamters"]!["triggerHighFreqLow"]! : minValue, + highFreqSampleTimes = (int)watchConfig["fetalParamters"]!["highFreqSampleTimes"]!, + highFreqSampleInterval = (int)watchConfig["fetalParamters"]!["highFreqSampleInterval"]!, + stopHighFreqSampleCount = (int)watchConfig["fetalParamters"]!["stopHighFreqSampleCount"]!, + mode = modeStatus, + edoc = watchConfig["fetalParamters"]!["EDOC"]!, + vibrateEnabled = (int)watchConfig["fetalParamters"]!["vibrateEnabled"]!, + lcdEnabled= (int)watchConfig["fetalParamters"]!["lcdEnabled"]! + }; + var setUrl = $"{_configService.IotCore}/api/v1/open/OpenIot/SetFetalConfig"; + var res = await _httpHelper.HttpToPostAsync(setUrl, data, headers).ConfigureAwait(false); + var resJToken = JsonConvert.DeserializeObject(res ?? string.Empty) as JToken; + return resJToken?["message"]?.ToString().Equals("ok") ?? false; + //response.Flag = resJToken?["message"]?.ToString().Equals("ok") ?? false; + //response.Flag = Convert.ToBoolean(resJToken?["succeed"]?.ToString()); + //if (!response.Flag) + //{ + // response.Message = resJToken?["message"]?.ToString()!; + //} + #endregion + } + catch (Exception ex) + { + _logger.LogError($"{nameof(SetFetalHeartRateConfig)} 下发胎心检测参数异常:{ex.Message}, {ex.StackTrace}"); + return false; + } + } + #endregion + + } +} diff --git a/HealthMonitor.Service/Biz/IotWebApiService.cs b/HealthMonitor.Service/Biz/IotWebApiService.cs deleted file mode 100644 index dbbe453..0000000 --- a/HealthMonitor.Service/Biz/IotWebApiService.cs +++ /dev/null @@ -1,626 +0,0 @@ -using HealthMonitor.Common.helper; -using HealthMonitor.Model.Config; -using HealthMonitor.Service.Resolver; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Newtonsoft.Json.Linq; -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using HealthMonitor.Model.Service; -using TelpoDataService.Util.Entities.GpsCard; -using TelpoDataService.Util; -using TelpoDataService.Util.Clients; -using TelpoDataService.Util.Models; -using TelpoDataService.Util.QueryObjects; -using HealthMonitor.Service.Cache; -using HealthMonitor.Model.Cache; - -namespace HealthMonitor.Service.Biz -{ - public class IotWebApiService - { - private readonly ServiceConfig _configService; - private readonly ILogger _logger; - private readonly PersonCacheManager _personCacheMgr; - - private readonly HttpHelper _httpHelper = default!; - - private readonly GpsCardAccessorClient _gpsPersonApiClient; - - public IotWebApiService(ILogger logger, HttpHelper httpHelper, GpsCardAccessorClient gpsPersonApiClient, IOptions optConfigService, PersonCacheManager personCacheMgr) - { - _configService = optConfigService.Value; - _httpHelper=httpHelper; - _logger = logger; - _personCacheMgr = personCacheMgr; - _gpsPersonApiClient = gpsPersonApiClient; - } - /// - /// 平台下发血压标定参数 - /// - /// - /// - public async Task SetBloodPressCalibrationConfigAsync(BloodPressCalibrationConfigModel bpsCalibrationConfig) - { - -#if DEBUG - var flag = true; -#else - //systolicCalibrationValue = 0, //收缩压标定值,值为0 表示不生效 - //diastolicCalibrationValue 0, //舒张压标定值,值为0表示不生效 - //systolicIncValue = 0, //收缩压显示增量,值为0 表示不生效 - //diastolicIncValue = 0 //舒张压显示增量,值为0 表示不生效 - - var flag = false; - try - { - var url = $"{_configService.IotWebApiUrl}Command/SetBloodPressCalibrationConfig"; - List> headers = new() - { - new KeyValuePair("AuthKey", "key1") - }; - var res = await _httpHelper.HttpToPostAsync(url, bpsCalibrationConfig, headers).ConfigureAwait(false); - _logger.LogInformation($"向{bpsCalibrationConfig.Imei}下发增量值数据:{JsonConvert.SerializeObject(bpsCalibrationConfig)},响应:{res}"); - var resJToken = JsonConvert.DeserializeObject(res ?? string.Empty) as JToken; - flag= resJToken?["message"]?.ToString().Equals("ok") ?? false; - - } - catch (Exception ex) - { - _logger.LogError($"{nameof(SetBloodPressCalibrationConfigAsync)} 下发血压增量值异常:{ex.Message}, {ex.StackTrace}"); - - } - - -#endif - - return flag; - - - } - - - public async Task SetBloodPressCalibrationConfig2Async(BloodPressCalibrationConfigModel bpsCalibrationConfig) - { - BloodPressCalibrationConfigModelReponse response = new BloodPressCalibrationConfigModelReponse(); - response.Flag = false; - response.Message = string.Empty; -#if DEBUG - //var flag = true; - response.Flag=true; -#else - //systolicCalibrationValue = 0, //收缩压标定值,值为0 表示不生效 - //diastolicCalibrationValue 0, //舒张压标定值,值为0表示不生效 - //systolicIncValue = 0, //收缩压显示增量,值为0 表示不生效 - //diastolicIncValue = 0 //舒张压显示增量,值为0 表示不生效 - - // var flag = false; - try - { - var url = $"{_configService.IotWebApiUrl}Command/SetBloodPressCalibrationConfig"; - List> headers = new() - { - new KeyValuePair("AuthKey", "key1") - }; - var res = await _httpHelper.HttpToPostAsync(url, bpsCalibrationConfig, headers).ConfigureAwait(false); - _logger.LogInformation($"向{bpsCalibrationConfig.Imei}下发增量值数据:{JsonConvert.SerializeObject(bpsCalibrationConfig)},响应:{res}"); - var resJToken = JsonConvert.DeserializeObject(res ?? string.Empty) as JToken; - //response.Flag= resJToken?["message"]?.ToString().Equals("ok") ?? false; - response.Flag = Convert.ToBoolean(resJToken?["succeed"]?.ToString()); - if (!response.Flag) - { - response.Message = resJToken?["message"]?.ToString()!; - } - } - catch (Exception ex) - { - _logger.LogError($"{nameof(SetBloodPressCalibrationConfigAsync)} 下发血压增量值异常:{ex.Message}, {ex.StackTrace}"); - - } - - -#endif - - return response; - } - /** 取消 - /// - /// 更新 gps_person remark和缓存 - /// - /// - /// - /// - /// - public async Task UpdatePersonRemarksAsync(string imei,int systolicRefValue,int diastolicRefValue) - { - var flag = false; - try - { - GeneralParam condition = new () - { - Filters = new List { - new QueryFilterCondition { - Key=nameof(GpsDevice.Serialno), - Value=imei, - Operator= QueryOperatorEnum.Equal, - ValueType=QueryValueTypeEnum.String - } - }, - OrderBys = new List { new OrderByCondition { Key = "serialno", IsDesc = true } } - - }; - var person = await _gpsPersonApiClient.GetFirstAsync(condition, new RequestHeader() { RequestId = $"{imei}" }).ConfigureAwait(false); - //// 若remark为空,更新person remark字段 - //if (string.IsNullOrWhiteSpace(person?.Remarks)) - //{ - // var newRemarkData = new - // { - // imei, - // time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), - // commandValue = new - // { - // systolicCalibrationValue = systolicRefValue, //收缩压标定值,值为0 表示不生效 - // diastolicCalibrationValue = diastolicRefValue, //舒张压标定值,值为0表示不生效 - // systolicIncValue = 0, //收缩压显示增量,值为0 表示不生效 - // diastolicIncValue = 0 //舒张压显示增量,值为0 表示不生效 - // } - // }; - // person!.Remarks = $"is_blood_press:{JsonConvert.SerializeObject(newRemarkData)}|"; - // await _gpsPersonApiClient.UpdateAsync(person, new RequestHeader() { RequestId = $"{imei}" }).ConfigureAwait(false); - // _logger.LogInformation($"更新Person remarks字段|{person.Remarks}"); - - // // 更新缓存 - // var url = $"{_configService.IotWebApiUrl}Device/UpdatePersonInfoCache?imei={imei}"; - // List> headers = new() - // { - // new KeyValuePair("AuthKey", "key1") - // }; - // var res = await _httpHelper.HttpToGetAsync(url, headers).ConfigureAwait(false); - // _logger.LogInformation($"{imei} 更新缓存{nameof(UpdatePersonRemarksAsync)},响应:{res}"); - // var resJToken = JsonConvert.DeserializeObject(res ?? string.Empty) as JToken; - // flag = resJToken?["message"]?.ToString().Equals("ok") ?? false; - //} - - var newRemarkData = new - { - imei, - time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), - commandValue = new - { - systolicCalibrationValue = systolicRefValue, //收缩压标定值,值为0 表示不生效 - diastolicCalibrationValue = diastolicRefValue, //舒张压标定值,值为0表示不生效 - systolicIncValue = 0, //收缩压显示增量,值为0 表示不生效 - diastolicIncValue = 0 //舒张压显示增量,值为0 表示不生效 - } - }; - person!.Remarks = $"is_blood_press:{JsonConvert.SerializeObject(newRemarkData)}|"; - await _gpsPersonApiClient.UpdateAsync(person, new RequestHeader() { RequestId = $"{imei}" }).ConfigureAwait(false); - _logger.LogInformation($"更新Person remarks字段|{person.Remarks}"); - - // 更新缓存 - var url = $"{_configService.IotWebApiUrl}Device/UpdatePersonInfoCache?imei={imei}"; - List> headers = new() - { - new KeyValuePair("AuthKey", "key1") - }; - var res = await _httpHelper.HttpToGetAsync(url, headers).ConfigureAwait(false); - _logger.LogInformation($"{imei} 更新缓存{nameof(UpdatePersonRemarksAsync)},响应:{res}"); - var resJToken = JsonConvert.DeserializeObject(res ?? string.Empty) as JToken; - flag = resJToken?["message"]?.ToString().Equals("ok") ?? false; - } - catch (Exception ex) - { - _logger.LogError($"{nameof(UpdatePersonRemarksAsync)} 更新个人信息异常:{ex.Message}, {ex.StackTrace}"); - } - return flag; - } - */ - - ///// - ///// 初次开通更新 gps_person remark和对应的缓存 - ///// - ///// - ///// - ///// - ///// - ///// - ///// - //public async Task UpdatePersonRemarksAsync0(string imei, int systolicRefValue, int diastolicRefValue,int systolicIncValue,int diastolicIncValue) - //{ - // var flag = false; - // try - // { - // GeneralParam condition = new() - // { - // Filters = new List { - // new QueryFilterCondition { - // Key=nameof(GpsDevice.Serialno), - // Value=imei, - // Operator= QueryOperatorEnum.Equal, - // ValueType=QueryValueTypeEnum.String - // } - // }, - // OrderBys = new List { new OrderByCondition { Key = "serialno", IsDesc = true } } - - // }; - // var person = await _gpsPersonApiClient.GetFirstAsync(condition, new RequestHeader() { RequestId = $"{imei}" }).ConfigureAwait(false); - // // 若remark为空,更新person remark字段 - // if (string.IsNullOrWhiteSpace(person?.Remarks)) - // { - // var newRemarkData = new - // { - // imei, - // time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), - // commandValue = new - // { - // systolicCalibrationValue = systolicRefValue, //收缩压标定值,值为0 表示不生效 - // diastolicCalibrationValue = diastolicRefValue, //舒张压标定值,值为0表示不生效 - // systolicIncValue, //收缩压显示增量,值为0 表示不生效 - // diastolicIncValue //舒张压显示增量,值为0 表示不生效 - // } - // }; - // person!.Remarks = $"is_blood_press:{JsonConvert.SerializeObject(newRemarkData)}|"; - // await _gpsPersonApiClient.UpdateAsync(person, new RequestHeader() { RequestId = $"{imei}" }).ConfigureAwait(false); - // _logger.LogInformation($"更新Person remarks字段|{person.Remarks}"); - - // // 更新缓存 - // var personCache = await _personCacheMgr.GetDeviceGpsPersonCacheObjectBySerialNoAsync(new Guid().ToString(), imei).ConfigureAwait(false); - - // if (personCache != null) - // { - - // //personCache.Person.Remarks = person!.Remarks; - // personCache["person"]!["remarks"] = person!.Remarks; - // bool cacheFlag= await _personCacheMgr.UpdateDeviceGpsPersonCacheObjectBySerialNoAsync(personCache, imei); - - // // flag = true; - // if (cacheFlag) - // { - // flag = true; - // _logger.LogInformation($"{imei} 更新缓存{nameof(UpdatePersonRemarksAsync)}成功,{JsonConvert.SerializeObject(personCache)}"); - // } - // else - // { - // flag = false; - // _logger.LogInformation($"{imei} 更新缓存{nameof(UpdatePersonRemarksAsync)}失败,{JsonConvert.SerializeObject(personCache)}"); - // } - // } - - - // //var url = $"{_configService.IotWebApiUrl}Device/UpdatePersonInfoCache?imei={imei}"; - // //List> headers = new() - // //{ - // // new KeyValuePair("AuthKey", "key1") - // //}; - // //var res = await _httpHelper.HttpToGetAsync(url, headers).ConfigureAwait(false); - // //_logger.LogInformation($"{imei} 更新缓存{nameof(UpdatePersonRemarksAsync)},响应:{res}"); - // //var resJToken = JsonConvert.DeserializeObject(res ?? string.Empty) as JToken; - // //flag = resJToken?["message"]?.ToString().Equals("ok") ?? false; - // } - // } - // catch (Exception ex) - // { - // _logger.LogError($"{nameof(UpdatePersonRemarksAsync)} 更新个人信息异常:{ex.Message}, {ex.StackTrace}"); - // } - // return flag; - //} - /** - /// - /// 更新 gps_person remark缓存和数据库 - /// - /// - /// - /// - /// - /// - /// 是否初始化,即清空remakers - /// - public async Task UpdatePersonRemarksAsync(string imei, int systolicRefValue, int diastolicRefValue, int systolicIncValue, int diastolicIncValue, bool isInitRemakers=false) - { - var flag = false; - try - { - - // 保证实时性,先更新缓存,再更新数据库 - var personCache = await _personCacheMgr.GetDeviceGpsPersonCacheObjectBySerialNoAsync(new Guid().ToString(), imei).ConfigureAwait(false); - - if (personCache == null) - { - _logger.LogInformation($"{imei} -- Person remarks数据异常,检查缓存和数据库"); - } - else if (string.IsNullOrWhiteSpace(personCache["person"]!["remarks"]!.ToString())) - { - var newRemarkData = new - { - imei, - time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), - commandValue = new - { - systolicCalibrationValue = systolicRefValue, //收缩压标定值,值为0 表示不生效 - diastolicCalibrationValue = diastolicRefValue, //舒张压标定值,值为0表示不生效 - systolicIncValue, //收缩压显示增量,值为0 表示不生效 - diastolicIncValue //舒张压显示增量,值为0 表示不生效 - } - }; - var newRemarkStr = isInitRemakers ? string.Empty:$"is_blood_press:{JsonConvert.SerializeObject(newRemarkData)}|"; - personCache["person"]!["remarks"] = newRemarkStr; - bool cacheFlag = await _personCacheMgr.UpdateDeviceGpsPersonCacheObjectBySerialNoAsync(personCache, imei); - if (cacheFlag) - { - GeneralParam condition = new() - { - Filters = new List { - new QueryFilterCondition { - Key=nameof(GpsDevice.Serialno), - Value=imei, - Operator= QueryOperatorEnum.Equal, - ValueType=QueryValueTypeEnum.String - } - }, - OrderBys = new List { new OrderByCondition { Key = "serialno", IsDesc = true } } - - }; - _logger.LogInformation($"{imei} 更新缓存{nameof(UpdatePersonRemarksAsync)}成功,{JsonConvert.SerializeObject(personCache)}"); - // 读取数据库 - var person = await _gpsPersonApiClient.GetFirstAsync(condition, new RequestHeader() { RequestId = $"{imei}" }).ConfigureAwait(false); - // 更新字段 - person!.Remarks = newRemarkStr; - await _gpsPersonApiClient.UpdateAsync(person, new RequestHeader() { RequestId = $"{imei}" }).ConfigureAwait(false); - _logger.LogInformation($"{imei} 更新Person remarks字段|{person.Remarks}"); - - } - else - { - _logger.LogInformation($"{imei} 更新缓存和数据库{nameof(UpdatePersonRemarksAsync)}失败,{JsonConvert.SerializeObject(personCache)}"); - } - flag = cacheFlag; - } - } - catch (Exception ex) - { - _logger.LogError($"{nameof(UpdatePersonRemarksAsync)} {imei}--更新个人信息异常:{ex.Message}, {ex.StackTrace}"); - } - return flag; - } - */ - /// - ///// 更新 gps_person remark缓存和数据库 - ///// - ///// - ///// - ///// - ///// - ///// - ///// - ///// - //public async Task UpdatePersonRemarksAsync(string imei, int systolicRefValue, int diastolicRefValue, int systolicIncValue, int diastolicIncValue, string remarks= "is_blood_press") - //{ - // var flag = false; - // try - // { - - // // 保证实时性,先更新缓存,再更新数据库 - // var personCache = await _personCacheMgr.GetDeviceGpsPersonCacheObjectBySerialNoAsync(new Guid().ToString(), imei).ConfigureAwait(false); - - // if (personCache == null) - // { - // _logger.LogInformation($"{imei} -- Person remarks数据异常,检查缓存和数据库"); - // } - // else if (string.IsNullOrWhiteSpace(personCache["person"]!["remarks"]!.ToString())) - // { - // var newRemarkData = new - // { - // imei, - // time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), - // commandValue = new - // { - // systolicCalibrationValue = systolicRefValue, //收缩压标定值,值为0 表示不生效 - // diastolicCalibrationValue = diastolicRefValue, //舒张压标定值,值为0表示不生效 - // systolicIncValue, //收缩压显示增量,值为0 表示不生效 - // diastolicIncValue //舒张压显示增量,值为0 表示不生效 - // } - // }; - // var newRemarkStr = $"{remarks}:{JsonConvert.SerializeObject(newRemarkData)}|"; - - // personCache["person"]!["remarks"] = newRemarkStr; - // bool cacheFlag = await _personCacheMgr.UpdateDeviceGpsPersonCacheObjectBySerialNoAsync(personCache, imei); - // if (cacheFlag) - // { - // GeneralParam condition = new() - // { - // Filters = new List { - // new QueryFilterCondition { - // Key=nameof(GpsDevice.Serialno), - // Value=imei, - // Operator= QueryOperatorEnum.Equal, - // ValueType=QueryValueTypeEnum.String - // } - // }, - // OrderBys = new List { new OrderByCondition { Key = "serialno", IsDesc = true } } - - // }; - // _logger.LogInformation($"{imei} 更新缓存{nameof(UpdatePersonRemarksAsync)}成功,{JsonConvert.SerializeObject(personCache)}"); - // // 读取数据库 - // var person = await _gpsPersonApiClient.GetFirstAsync(condition, new RequestHeader() { RequestId = $"{imei}" }).ConfigureAwait(false); - // // 更新字段 - // person!.Remarks = newRemarkStr; - // await _gpsPersonApiClient.UpdateAsync(person, new RequestHeader() { RequestId = $"{imei}" }).ConfigureAwait(false); - // _logger.LogInformation($"{imei} 更新Person remarks字段|{person.Remarks}"); - - // } - // else - // { - // _logger.LogInformation($"{imei} 更新缓存和数据库{nameof(UpdatePersonRemarksAsync)}失败,{JsonConvert.SerializeObject(personCache)}"); - // } - // flag = cacheFlag; - // } - // } - // catch (Exception ex) - // { - // _logger.LogError($"{nameof(UpdatePersonRemarksAsync)} {imei}--更新个人信息异常:{ex.Message}, {ex.StackTrace}"); - // } - // return flag; - //} - - - - /// 更新 gps_person remark缓存和数据库 - /// - /// - /// - /// - /// - /// - /// - /// - public async Task UpdatePersonRemarksAsync(string imei, int systolicRefValue, int diastolicRefValue, int systolicIncValue, int diastolicIncValue, string remarks = "is_blood_press") - { - var flag = false; - try - { - - // 保证实时性,先更新缓存,再更新数据库 - var personCache = await _personCacheMgr.GetDeviceGpsPersonCacheObjectBySerialNoAsync(new Guid().ToString(), imei).ConfigureAwait(false); - - if (personCache == null) - { - _logger.LogInformation($"{imei} -- Person remarks数据异常,检查缓存和数据库"); - } - else - { - var newRemarkData = new - { - imei, - time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), - commandValue = new - { - systolicCalibrationValue = systolicRefValue, //收缩压标定值,值为0 表示不生效 - diastolicCalibrationValue = diastolicRefValue, //舒张压标定值,值为0表示不生效 - systolicIncValue, //收缩压显示增量,值为0 表示不生效 - diastolicIncValue //舒张压显示增量,值为0 表示不生效 - } - }; - var newRemarkStr = $"{remarks}:{JsonConvert.SerializeObject(newRemarkData)}|"; - - personCache["person"]!["remarks"] = newRemarkStr; - bool cacheFlag = await _personCacheMgr.UpdateDeviceGpsPersonCacheObjectBySerialNoAsync(personCache, imei); - if (cacheFlag) - { - GeneralParam condition = new() - { - Filters = new List { - new QueryFilterCondition { - Key=nameof(GpsDevice.Serialno), - Value=imei, - Operator= QueryOperatorEnum.Equal, - ValueType=QueryValueTypeEnum.String - } - }, - OrderBys = new List { new OrderByCondition { Key = "serialno", IsDesc = true } } - - }; - _logger.LogInformation($"{imei} 更新缓存{nameof(UpdatePersonRemarksAsync)}成功,{JsonConvert.SerializeObject(personCache)}"); - // 读取数据库 - var person = await _gpsPersonApiClient.GetFirstAsync(condition, new RequestHeader() { RequestId = $"{imei}" }).ConfigureAwait(false); - // 更新字段 - person!.Remarks = newRemarkStr; - await _gpsPersonApiClient.UpdateAsync(person, new RequestHeader() { RequestId = $"{imei}" }).ConfigureAwait(false); - _logger.LogInformation($"{imei} 更新Person remarks字段|{person.Remarks}"); - - } - else - { - _logger.LogInformation($"{imei} 更新缓存和数据库{nameof(UpdatePersonRemarksAsync)}失败,{JsonConvert.SerializeObject(personCache)}"); - } - flag = cacheFlag; - } - // else if (string.IsNullOrWhiteSpace(personCache["person"]!["remarks"]!.ToString())) - //else if (personCache?["person"]!["remarks"]!.ToString()!=null) - //{ - // var newRemarkData = new - // { - // imei, - // time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), - // commandValue = new - // { - // systolicCalibrationValue = systolicRefValue, //收缩压标定值,值为0 表示不生效 - // diastolicCalibrationValue = diastolicRefValue, //舒张压标定值,值为0表示不生效 - // systolicIncValue, //收缩压显示增量,值为0 表示不生效 - // diastolicIncValue //舒张压显示增量,值为0 表示不生效 - // } - // }; - // var newRemarkStr = $"{remarks}:{JsonConvert.SerializeObject(newRemarkData)}|"; - - // personCache["person"]!["remarks"] = newRemarkStr; - // bool cacheFlag = await _personCacheMgr.UpdateDeviceGpsPersonCacheObjectBySerialNoAsync(personCache, imei); - // if (cacheFlag) - // { - // GeneralParam condition = new() - // { - // Filters = new List { - // new QueryFilterCondition { - // Key=nameof(GpsDevice.Serialno), - // Value=imei, - // Operator= QueryOperatorEnum.Equal, - // ValueType=QueryValueTypeEnum.String - // } - // }, - // OrderBys = new List { new OrderByCondition { Key = "serialno", IsDesc = true } } - - // }; - // _logger.LogInformation($"{imei} 更新缓存{nameof(UpdatePersonRemarksAsync)}成功,{JsonConvert.SerializeObject(personCache)}"); - // // 读取数据库 - // var person = await _gpsPersonApiClient.GetFirstAsync(condition, new RequestHeader() { RequestId = $"{imei}" }).ConfigureAwait(false); - // // 更新字段 - // person!.Remarks = newRemarkStr; - // await _gpsPersonApiClient.UpdateAsync(person, new RequestHeader() { RequestId = $"{imei}" }).ConfigureAwait(false); - // _logger.LogInformation($"{imei} 更新Person remarks字段|{person.Remarks}"); - - // } - // else - // { - // _logger.LogInformation($"{imei} 更新缓存和数据库{nameof(UpdatePersonRemarksAsync)}失败,{JsonConvert.SerializeObject(personCache)}"); - // } - // flag = cacheFlag; - //} - } - catch (Exception ex) - { - _logger.LogError($"{nameof(UpdatePersonRemarksAsync)} {imei}--更新个人信息异常:{ex.Message}, {ex.StackTrace}"); - } - return flag; - } - - /** 取消 - public async Task UpdatePersonInfoCacheAsync(string imei) - { - var flag = false; - try - { - var url = $"{_configService.IotWebApiUrl}Device/UpdatePersonInfoCache?imei={imei}"; - List> headers = new() - { - new KeyValuePair("AuthKey", "key1") - }; - var res = await _httpHelper.HttpToGetAsync(url, headers).ConfigureAwait(false); - _logger.LogInformation($"{imei} 更新缓存{nameof(UpdatePersonInfoCacheAsync)},响应:{res}"); - var resJToken = JsonConvert.DeserializeObject(res ?? string.Empty) as JToken; - flag = resJToken?["message"]?.ToString().Equals("ok") ?? false; - } - catch (Exception ex) - { - _logger.LogError($"{nameof(UpdatePersonInfoCacheAsync)} 更新缓存异常:{ex.Message}, {ex.StackTrace}"); - - } - return flag; - - - } - */ - - } -} diff --git a/HealthMonitor.Service/Biz/db/TDengineService.cs b/HealthMonitor.Service/Biz/db/TDengineService.cs index e39bee1..c3ffcec 100644 --- a/HealthMonitor.Service/Biz/db/TDengineService.cs +++ b/HealthMonitor.Service/Biz/db/TDengineService.cs @@ -637,6 +637,7 @@ namespace HealthMonitor.Service.Biz.db } #region SqlSugarClient + /** public async Task InsertFetalHeartRateAsync() { var tableName = typeof(FetalHeartRateModel) @@ -680,61 +681,9 @@ namespace HealthMonitor.Service.Biz.db .OrderByDescending(x => x.Timestamp).FirstAsync(); return first; } - public void InsertFetalHeartRate2() - { - //var insrtSql = ""; - //_clientSqlSugar.Ado.ExecuteCommand(insrtSql); - // 通过反射获取STableAttribute的STableName值 - var tableName = typeof(FetalHeartRateModel) - .GetCustomAttribute()? - .STableName; - - if (tableName == null) - { - throw new InvalidOperationException("STableAttribute not found on FetalHeartRateModel class."); - } - - _clientSqlSugar.Ado.ExecuteCommand($"create table IF NOT EXISTS hm_fhr_00 using {tableName} tags('00')"); - - //_clientSqlSugar.Ado.ExecuteCommand($"create table IF NOT EXISTS hm_fhr_00 using `stb_hm_fetal_heart_rate_test` tags('00')"); - _clientSqlSugar.Insertable(new FetalHeartRateModel() - { - Timestamp = DateTime.Now, - CreateTime = DateTime.Now, - FetalHeartRate = 90, - FetalHeartRateId = Guid.NewGuid().ToString("D"), - IsDisplay = false, - Method = 1, - PersonId = Guid.NewGuid().ToString("D"), - MessageId = Guid.NewGuid().ToString("D"), - SerialNumber = Guid.NewGuid().ToString("D"), - DeviceKey = Guid.NewGuid().ToString("D"), - SerialTailNumber = "00", - LastUpdate = DateTime.Now, - }).AS("hm_fhr_00").ExecuteCommand(); - - - //List rows = new(); - - //rows.Add(new FetalHeartRateModel() { - // Timestamp = new DateTime(2024, 1, 1), - // CreateTime = DateTime.Now, - // FetalHeartRate = 90, - // FetalHeartRateId = Guid.NewGuid().ToString("D"), - // IsDisplay = false, - // Method = 1, - // PersonId = Guid.NewGuid().ToString("D"), - // MessageId = Guid.NewGuid().ToString("D"), - // SerialNumber = Guid.NewGuid().ToString("D"), - // DeviceKey = Guid.NewGuid().ToString("D"), - // SerialTailNumber = "00", - // LastUpdate = DateTime.Now, - - //}); - - //_clientSqlSugar.Insertable(rows).AS("hm_fhr_00").ExecuteCommand(); - } + */ + /// /// 插入记录 /// @@ -808,5 +757,192 @@ namespace HealthMonitor.Service.Biz.db return res; } #endregion + + #region 胎心算法 + /// + /// 获取孕妇心率众数 + /// + /// + /// + /// + public async Task GetPregnancyHeartRateModeAsync(string serialNo,int days=7) + { + var tableName = typeof(PregnancyHeartRateModel) + .GetCustomAttribute()? + .STableName; + + var res = await _clientSqlSugar + .Queryable() + .AS(tableName) + .Where(i=>i.SerialNumber.Equals(serialNo)) + .Where(i => i.Timestamp > DateTime.Now.AddDays(-days)) + //.OrderByDescending(i => i.PregnancyHeartRate) + .Select(i =>i.PregnancyHeartRate) + .ToListAsync(); + // 心率数据量必须30个以上才进行计算 + if (res.Count < 30) return 0; + + // 计算众数 + var mode = res.GroupBy(n => n) + .OrderByDescending(g => g.Count()) + .First() + .Key; + + Console.WriteLine("众数是: " + mode); + + // 如果有多个众数的情况 + var maxCount = res.GroupBy(n => n) + .Max(g => g.Count()); + + var modes = res.GroupBy(n => n) + .Where(g => g.Count() == maxCount) + .Select(g => g.Key) + .ToList(); + // 多个众数,选择最接近平均数或中位数的众数 + if (modes.Count>1) + { + // 计算平均值 + double average = res.Average(); + Console.WriteLine("平均值是: " + average); + + // 计算中位数 + double median; + int count = res.Count; + var sortedRes = res.OrderBy(n => n).ToList(); + if (count % 2 == 0) + { + // 偶数个元素,取中间两个数的平均值 + median = (sortedRes[count / 2 - 1] + sortedRes[count / 2]) / 2.0; + } + else + { + // 奇数个元素,取中间的数 + median = sortedRes[count / 2]; + } + Console.WriteLine("中位数是: " + median); + + // 找出最接近平均值的众数 + //var closestToAverage = modes.OrderBy(m => Math.Abs(m - average)).First(); + //Console.WriteLine("最接近平均值的众数是: " + closestToAverage); + + // 找出最接近中位数的众数 + var closestToMedian = modes.OrderBy(m => Math.Abs(m - median)).First(); + Console.WriteLine("最接近中位数的众数是: " + closestToMedian); + mode = closestToMedian; + } + + return mode; + } + /// + /// 计算个人一般心率 + /// + /// + /// + /// + /// + public async Task InitPregnancyCommonHeartRateModeAsync(string serialNo, int days = 7,int percentage=90) + { + var tableName = typeof(PregnancyHeartRateModel) + .GetCustomAttribute()? + .STableName; + + var collection = await _clientSqlSugar + .Queryable() + .AS(tableName) + .Where(i => i.SerialNumber.Equals(serialNo)) + .Where(i => i.Timestamp > DateTime.Now.AddDays(-days)) + .OrderByDescending(i => i.Timestamp) + .ToArrayAsync(); + + var res = collection + .Select(i => i.PregnancyHeartRate).ToList(); + // 心率数据量必须30个以上才进行计算 + if (res.Count < 30) + { + _logger.LogInformation($"{serialNo} 心率数据不足,无法计算其众数"); + return null; + } + + #region 计算众数 + var mode = res.GroupBy(n => n) + .OrderByDescending(g => g.Count()) + .First() + .Key; + + Console.WriteLine("众数是: " + mode); + + // 如果有多个众数的情况 + var maxCount = res.GroupBy(n => n) + .Max(g => g.Count()); + + var modes = res.GroupBy(n => n) + .Where(g => g.Count() == maxCount) + .Select(g => g.Key) + .ToList(); + // 多个众数,选择最接近平均数或中位数的众数 + if (modes.Count > 1) + { + // 计算平均值 + double average = res.Average(); + Console.WriteLine("平均值是: " + average); + + // 计算中位数 + double median; + int count = res.Count; + var sortedRes = res.OrderBy(n => n).ToList(); + if (count % 2 == 0) + { + // 偶数个元素,取中间两个数的平均值 + median = (sortedRes[count / 2 - 1] + sortedRes[count / 2]) / 2.0; + } + else + { + // 奇数个元素,取中间的数 + median = sortedRes[count / 2]; + } + Console.WriteLine("中位数是: " + median); + + // 找出最接近平均值的众数 + //var closestToAverage = modes.OrderBy(m => Math.Abs(m - average)).First(); + //Console.WriteLine("最接近平均值的众数是: " + closestToAverage); + + // 找出最接近中位数的众数 + var closestToMedian = modes.OrderBy(m => Math.Abs(m - median)).First(); + Console.WriteLine("最接近中位数的众数是: " + closestToMedian); + mode = closestToMedian; + } + #endregion + + // 计算需要的数量 + int requiredCount = (int)(res.Count * 0.8); + + // 从原始数据集中获取最接近众数的元素 + var closestToModeData = res.OrderBy(n => Math.Abs(n - mode)) + .Take(requiredCount) + .ToList(); + + // 输出新数据集 + Console.WriteLine("新数据集: " + string.Join(", ", closestToModeData)); + Console.WriteLine("新数据集的数量: " + closestToModeData.Count); + + return new PregnancyCommonHeartRateModel() + { + Timestamp = DateTime.Now, + PersonId = collection.First().DeviceKey, + DeviceKey = collection.First().DeviceKey, + SerialNumber = collection.First().SerialNumber, + Mode = mode, + Percentage= percentage, + MaxValue= closestToModeData.Max(), + MinValue= closestToModeData.Min(), + OriginalMaxValue=res.Max(), + OriginalMinValue= res.Min(), + CreateTime = DateTime.Now, + StatStartTime = collection.OrderBy(i=>i.Timestamp).Select(i=>i.Timestamp).First(), + StatEndTime= collection.OrderBy(i => i.Timestamp).Select(i => i.Timestamp).Last(), + }; + + } + #endregion } } diff --git a/HealthMonitor.Service/Cache/DeviceCacheManager.cs b/HealthMonitor.Service/Cache/DeviceCacheManager.cs new file mode 100644 index 0000000..d7b34b7 --- /dev/null +++ b/HealthMonitor.Service/Cache/DeviceCacheManager.cs @@ -0,0 +1,52 @@ +using Microsoft.Extensions.Logging; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HealthMonitor.Service.Cache +{ + public class DeviceCacheManager + { + private readonly ILogger _logger; + private const string CACHE_KEY_GPSDEVICE_WATCH_CONFIG = "#GPSDEVICE_WATCH_CONFIG_HASH"; + + + public DeviceCacheManager(ILogger logger) + { + _logger = logger; + } + + + /// + /// + /// + /// + /// + /// 业务码 + /// 0067 胎心启动配置 + /// + /// + public async Task GetGpsDeviceWatchConfigCacheObjectBySerialNoAsync(string sn, string bizCode) + { + if (string.IsNullOrWhiteSpace(sn)) return null; + + try + { + var config = await RedisHelperDb7.HGetAsync(CACHE_KEY_GPSDEVICE_WATCH_CONFIG, $"{sn}_{bizCode}").ConfigureAwait(false); + + if (config == null) return null; + return (JObject)JsonConvert.DeserializeObject(config)!; + } + catch (Exception ex) + { + _logger.LogWarning($"Redis DB7发生异常:{ex.Message}, {ex.StackTrace}"); + } + + return null; + } + } +} diff --git a/HealthMonitor.Service/Resolver/BloodpressResolver.cs b/HealthMonitor.Service/Resolver/BloodpressResolver.cs index d987746..0720e16 100644 --- a/HealthMonitor.Service/Resolver/BloodpressResolver.cs +++ b/HealthMonitor.Service/Resolver/BloodpressResolver.cs @@ -42,7 +42,7 @@ namespace HealthMonitor.Service.Resolver private readonly HttpHelper _httpHelper = default!; private readonly GpsCardAccessorClient _gpsPersonApiClient; - private readonly IotWebApiService _serviceIotWebApi; + private readonly IotApiService _serviceIotWebApi; private readonly AsyncLocal _messageId = new(); private readonly AsyncLocal _msgData = new(); @@ -54,7 +54,7 @@ namespace HealthMonitor.Service.Resolver BloodPressReferenceValueCacheManager bpRefValCacheManager, PersonCacheManager personCacheMgr, HttpHelper httpHelper, GpsCardAccessorClient gpsPersonApiClient, - IotWebApiService iotWebApiService, + IotApiService iotWebApiService, EtcdService serviceEtcd, IOptions optionBoodPressResolver, ILogger logger) diff --git a/HealthMonitor.Service/Resolver/Factory/ResolverFactory.cs b/HealthMonitor.Service/Resolver/Factory/ResolverFactory.cs index 50290aa..3aa2bbf 100644 --- a/HealthMonitor.Service/Resolver/Factory/ResolverFactory.cs +++ b/HealthMonitor.Service/Resolver/Factory/ResolverFactory.cs @@ -55,7 +55,6 @@ namespace HealthMonitor.Service.Resolver.Factory MessageId = msg.MessageId, Topic = msg.Topic, DetailData = msg.Body, - }; } } diff --git a/HealthMonitor.Service/Resolver/PregnancyHeartRateResolver.cs b/HealthMonitor.Service/Resolver/PregnancyHeartRateResolver.cs new file mode 100644 index 0000000..183e5b0 --- /dev/null +++ b/HealthMonitor.Service/Resolver/PregnancyHeartRateResolver.cs @@ -0,0 +1,134 @@ +using HealthMonitor.Common; +using HealthMonitor.Common.helper; +using HealthMonitor.Service.Etcd; +using HealthMonitor.Service.Resolver.Interface; +using HealthMonitor.Service.Sub; +using HealthMonitor.Service.Sub.Topic.Model; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TelpoDataService.Util.Entities.GpsLocationHistory; + +namespace HealthMonitor.Service.Resolver +{ + public class PregnancyHeartRateResolver : IResolver + { + private readonly ILogger _logger; + private readonly AsyncLocal _messageId = new(); + private readonly AsyncLocal _msgData = new(); + private readonly HttpHelper _httpHelper = default!; + private readonly EtcdService _serviceEtcd; + + + public PregnancyHeartRateResolver(ILogger logger, HttpHelper httpHelper, EtcdService serviceEtcd) + { + _logger = logger; + _httpHelper = httpHelper; + _serviceEtcd = serviceEtcd; + } + + 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() + { + //throw new NotImplementedException(); + var messageId = _messageId.Value; + var phr = _msgData.Value!; + #region 定时下发触发器 + var key = $"health_moniter/schedule_push/pregnancy_heart_rate/imei/{phr.Serialno}"; + var schedule_push = await _serviceEtcd.GetValAsync(key).ConfigureAwait(false); + + if (string.IsNullOrWhiteSpace(schedule_push)) + { + // 注册首次下推 +#if DEBUG + // await _serviceEtcd.PutValAsync(key, result, 60*1, false).ConfigureAwait(false); + + var interval = 0; + // 获取当前时间 + DateTime now = DateTime.Now; + + // 计算距离下一个$interval天后的8点的时间间隔 + DateTime nextRunTime = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute + 1, 58).AddDays(interval); + TimeSpan timeUntilNextRun = nextRunTime - now; + + // 如果当前时间已经超过了8点,将等待到明天后的8点 + if (timeUntilNextRun < TimeSpan.Zero) + { + timeUntilNextRun = timeUntilNextRun.Add(TimeSpan.FromMinutes(1)); + nextRunTime += timeUntilNextRun; + } + var ttl = (long)timeUntilNextRun.TotalSeconds; + var data = new + { + imei = phr.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); + +#else + + var interval = 0; + // 获取当前时间 + DateTime now = DateTime.Now; + var rand=new Random(); + var pushSec = rand.Next(59); + int pushMin= int.TryParse(phr.Serialno.AsSpan(phr.Serialno.Length - 1), out pushMin) ? pushMin : 10; + // 计算距离下一个$interval天后的8点的时间间隔 + DateTime nextRunTime = new DateTime(now.Year, now.Month, now.Day, 18, 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 = phr.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); +#endif + + } + + #endregion + } + + + + } +} diff --git a/HealthMonitor.Service/Sub/MsgQueueManager.cs b/HealthMonitor.Service/Sub/MsgQueueManager.cs index 6939450..de5ff06 100644 --- a/HealthMonitor.Service/Sub/MsgQueueManager.cs +++ b/HealthMonitor.Service/Sub/MsgQueueManager.cs @@ -15,15 +15,19 @@ namespace HealthMonitor.Service.Sub { private readonly ILogger _logger; private readonly BloodpressResolver _resolverBloodpress; + private readonly PregnancyHeartRateResolver _resolverPregnacyHeartRate; //private const string BP = nameof(TopicHmBloodPress).ToLower(); - public MsgQueueManager(ILogger logger, BloodpressResolver resolverBloodpress) + public MsgQueueManager(ILogger logger, + BloodpressResolver resolverBloodpress, + PregnancyHeartRateResolver pregnacyHeartRateResolver) { _logger = logger; _resolverBloodpress = resolverBloodpress; + _resolverPregnacyHeartRate = pregnacyHeartRateResolver; } //public IResolver? GetMsgResolver() @@ -55,6 +59,12 @@ namespace HealthMonitor.Service.Sub _resolverBloodpress.SetResolveInfo(msg); return _resolverBloodpress; } + + if (msg.Topic.Equals(nameof(TopicHmPregnancyHeartRate).ToLower())) + { + _resolverPregnacyHeartRate.SetResolveInfo(msg); + return _resolverPregnacyHeartRate; + } return null; diff --git a/HealthMonitor.Service/Sub/TDengineDataSubcribe.cs b/HealthMonitor.Service/Sub/TDengineDataSubcribe.cs index c5b3db4..91c1814 100644 --- a/HealthMonitor.Service/Sub/TDengineDataSubcribe.cs +++ b/HealthMonitor.Service/Sub/TDengineDataSubcribe.cs @@ -20,6 +20,7 @@ using System.Threading.Tasks; using TDengineDriver; using TDengineTMQ; using TelpoDataService.Util.Entities.GpsLocationHistory; +using static Microsoft.EntityFrameworkCore.DbLoggerCategory.Database; namespace HealthMonitor.Service.Sub { @@ -69,40 +70,80 @@ namespace HealthMonitor.Service.Sub DoReceive(conn); } - public void DoReceive(IntPtr Connection) + public void DoReceive(IntPtr connection) { - #region topichmbpstats 订阅 + #region topic 订阅 // string topic = "topichmbpstats"; - string topic = nameof(TopicHmBloodPress).ToLower(); - TopicHmBloodPress fields = new(); - PropertyInfo[] props = fields.GetType().GetProperties(); - // 获取 fields - string attributes = ""; - foreach (PropertyInfo prop in props) + //string bloodPressTopic = nameof(TopicHmBloodPress).ToLower(); + //TopicHmBloodPress fields = new(); + //PropertyInfo[] props = fields.GetType().GetProperties(); + //// 获取 fields + //string attributes = ""; + //foreach (PropertyInfo prop in props) + //{ + // JsonPropertyAttribute attr = prop.GetCustomAttribute()!; + // if (attr != null) + // { + // attributes += attr.PropertyName + ","; + // } + //} + //attributes = attributes.TrimEnd(','); + + ////创建 topichmbpstats + //IntPtr res = TDengine.Query(Connection, $"create topic if not exists {bloodPressTopic} as select {attributes} from health_monitor.stb_hm_bloodpress"); + + ////创建 topichmpregnancyheartrate + //var pregnancyHeartRateTopic = nameof(TopicHmPregnancyHeartRate).ToLower(); + //var pregnancyHeartateAttributes = typeof(TopicHmPregnancyHeartRate).GetType().GetProperties().Select(prop => prop.GetCustomAttribute()); + //var pregnancyHeartateAttributesStr = string.Join(", ", pregnancyHeartateAttributes); + //res = TDengine.Query(Connection, $"create topic if not exists {pregnancyHeartRateTopic} as select {pregnancyHeartateAttributesStr} from {_configTDengineService.DB}.stb_hm_pregnancy_heart_rate"); + + //if (TDengine.ErrorNo(res) != 0) + //{ + // _logger.LogError($"create topic failed, reason:{TDengine.Error(res)}"); + // throw new Exception($"create topic failed, reason:{TDengine.Error(res)}"); + //} + + // 获取字段属性 + string GetAttributes(Type type) { - JsonPropertyAttribute attr = prop.GetCustomAttribute()!; - if (attr != null) + var props = type.GetProperties(); + var attributeNames = props + .Select(prop => prop.GetCustomAttribute()?.PropertyName) + .Where(attr => !string.IsNullOrEmpty(attr)); + + return string.Join(",", attributeNames); + } + + // 创建 topic + void CreateTopic(IntPtr conn, string topicName, string attributes, string tableName) + { + string query = $"create topic if not exists {topicName} as select {attributes} from {tableName}"; + IntPtr res = TDengine.Query(conn, query); + + if (TDengine.ErrorNo(res) != 0) { - attributes += attr.PropertyName + ","; + string error = TDengine.Error(res); + _logger.LogError($"Create topic {topicName} failed, reason: {error}"); + throw new Exception($"Create topic {topicName} failed, reason: {error}"); } } - attributes = attributes.TrimEnd(','); - //创建 topichmbpstats - IntPtr res = TDengine.Query(Connection, $"create topic if not exists {topic} as select {attributes} from health_monitor.stb_hm_bloodpress"); + // 血压 topic + string bloodPressTopic = nameof(TopicHmBloodPress).ToLower(); + string bloodPressAttributes = GetAttributes(typeof(TopicHmBloodPress)); + CreateTopic(connection, bloodPressTopic, bloodPressAttributes, $"{_configTDengineService.DB}.stb_hm_bloodpress"); + + // 孕期心率 topic + string pregnancyHeartRateTopic = nameof(TopicHmPregnancyHeartRate).ToLower(); + string pregnancyHeartRateAttributes = GetAttributes(typeof(TopicHmPregnancyHeartRate)); + CreateTopic(connection, pregnancyHeartRateTopic, pregnancyHeartRateAttributes, $"{_configTDengineService.DB}.stb_hm_pregnancy_heart_rate"); + - //创建 topichmfetalheartrate - //var fetalHeartRateTopic = "topichmfetalheartrate"; - //var fetalHeartRateFields = "ts,fetal_heart_rate_id,message_id,person_id,serialno,fetal_heart_rate,create_time,method,last_update,is_display,device_key"; - //res = TDengine.Query(Connection, $"create topic if not exists {fetalHeartRateTopic} as select {fetalHeartRateFields} from health_monitor.stb_hm_fetal_heart_rate_test"); #endregion - if (TDengine.ErrorNo(res) != 0) - { - _logger.LogError($"create topic failed, reason:{TDengine.Error(res)}"); - throw new Exception($"create topic failed, reason:{TDengine.Error(res)}"); - } + var cfg = new ConsumerConfig { GourpId = "group_1", @@ -112,12 +153,13 @@ namespace HealthMonitor.Service.Sub TDConnectIp = _configTDengineService.Host, }; // create consumer - var consumer = new ConsumerBuilder(cfg) - .Build(); + var consumer = new ConsumerBuilder(cfg).Build(); + var topics = new string[] { bloodPressTopic, pregnancyHeartRateTopic }; + // subscribe - consumer.Subscribe(topic); - + consumer.Subscribe(topics); + while (!_tokenSource!.IsCancellationRequested) { var consumeRes = consumer.Consume(300); @@ -154,14 +196,11 @@ namespace HealthMonitor.Service.Sub } } consumer.Commit(consumeRes); - - //_logger.LogInformation("监听中...."); - // Console.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff},监听中...."); } // close consumer after use.Otherwise will lead memory leak. consumer.Close(); - TDengine.Close(Connection); + TDengine.Close(connection); } public void ParsePackage(ReceiveMessageModel model) diff --git a/HealthMonitor.Service/Sub/Topic/Model/TopicHmPregnancyHeartRate.cs b/HealthMonitor.Service/Sub/Topic/Model/TopicHmPregnancyHeartRate.cs new file mode 100644 index 0000000..d254425 --- /dev/null +++ b/HealthMonitor.Service/Sub/Topic/Model/TopicHmPregnancyHeartRate.cs @@ -0,0 +1,44 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HealthMonitor.Service.Sub.Topic.Model +{ + public class TopicHmPregnancyHeartRate + { + [JsonProperty("ts")] + public long Ts { get; set; } = default!; + [JsonProperty("pregnancy_heart_rate_id")] + public string PregnancyHeartRateId { get; set; } = default!; + + [JsonProperty("message_id")] + public string MessageId { get; set; } = default!; + + [JsonProperty("person_id")] + public string PersonId { get; set; } = default!; + + [JsonProperty("serialno")] + public string Serialno { get; set; } = default!; + + [JsonProperty("pregnancy_heart_rate")] + public int PregnancyHeartRate { get; set; } + + [JsonProperty("last_update")] + public long LastUpdate { get; set; } + + [JsonProperty("create_time")] + public long CreateTime { get; set; } + + [JsonProperty("method")] + public int Method { get; set; } + + [JsonProperty("is_display")] + public bool IsDisplay { get; set; } + + [JsonProperty("device_key")] + public string DeviceKey { get; set; } = default!; + } +} diff --git a/HealthMonitor.WebApi/Controllers/HealthMonitor/HmBloodPressConfigManualCalibrationController.cs b/HealthMonitor.WebApi/Controllers/HealthMonitor/HmBloodPressConfigManualCalibrationController.cs index 0535a23..b94c54d 100644 --- a/HealthMonitor.WebApi/Controllers/HealthMonitor/HmBloodPressConfigManualCalibrationController.cs +++ b/HealthMonitor.WebApi/Controllers/HealthMonitor/HmBloodPressConfigManualCalibrationController.cs @@ -46,7 +46,7 @@ namespace HealthMonitor.WebApi.Controllers.HealthMonitor private readonly TDengineService _serviceTDengine; private readonly HttpHelper _httpHelper = default!; - private readonly IotWebApiService _serviceIotWebApi; + private readonly IotApiService _serviceIotWebApi; private readonly GpsCardAccessorClient _deviceApiClient; private readonly GpsCardAccessorClient _gpsPersonApiClient; @@ -58,7 +58,7 @@ namespace HealthMonitor.WebApi.Controllers.HealthMonitor GpsCardAccessorClient gpsPersonApiClient, GpsCardAccessorClient deviceApiClient, ILogger logger, - IotWebApiService iotWebApiService + IotApiService iotWebApiService ) { diff --git a/HealthMonitor.WebApi/Controllers/HealthMonitor/HmBloodPressController.cs b/HealthMonitor.WebApi/Controllers/HealthMonitor/HmBloodPressController.cs index de805ee..affcb1e 100644 --- a/HealthMonitor.WebApi/Controllers/HealthMonitor/HmBloodPressController.cs +++ b/HealthMonitor.WebApi/Controllers/HealthMonitor/HmBloodPressController.cs @@ -97,7 +97,24 @@ namespace HealthMonitor.WebApi.Controllers.HealthMonitor //await _serviceTDengine.InsertAsync("hm_fhr", test); //var first = _serviceTDengine.GetFirst(); - var first = await _serviceTDengine.GetBySerialNoAsync("864144050568123"); + var test2 = new PregnancyHeartRateModel() + { + Timestamp = DateTime.Now, + CreateTime = DateTime.Now, + PregnancyHeartRate = 120, + PregnancyHeartRateId= Guid.NewGuid().ToString("D"), + IsDisplay = false, + Method = 1, + PersonId = Guid.NewGuid().ToString("D"), + MessageId = Guid.NewGuid().ToString("D"), + SerialNumber = "864144050568123", + DeviceKey = Guid.NewGuid().ToString("D"), + SerialTailNumber = "23", + LastUpdate = DateTime.Now, + }; + await _serviceTDengine.InsertAsync("hm_phr", test2); + + var first = await _serviceTDengine.GetBySerialNoAsync("864144050568123"); return Ok(first); } } diff --git a/HealthMonitor.WebApi/Program.cs b/HealthMonitor.WebApi/Program.cs index 27d2bf7..b7c072a 100644 --- a/HealthMonitor.WebApi/Program.cs +++ b/HealthMonitor.WebApi/Program.cs @@ -93,7 +93,7 @@ namespace HealthMonitor.WebApi var serverVersion = ServerVersion.AutoDetect(mySqlCon); options.UseMySql(mySqlCon, serverVersion) .UseLoggerFactory(loggerFactory); - }, poolSize: 64); ; + }, poolSize: 64); builder.Services .AddScoped(sp => @@ -172,6 +172,7 @@ namespace HealthMonitor.WebApi #region Cache builder.Services .AddSingleton() + .AddSingleton() .AddSingleton(); #endregion @@ -189,11 +190,12 @@ namespace HealthMonitor.WebApi builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); + builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services .AddSingleton() - .AddSingleton() + .AddSingleton() .AddSingleton() .AddHostedService(); #endregion diff --git a/HealthMonitor.WebApi/Worker.cs b/HealthMonitor.WebApi/Worker.cs index 0bfcc94..5f58ada 100644 --- a/HealthMonitor.WebApi/Worker.cs +++ b/HealthMonitor.WebApi/Worker.cs @@ -33,19 +33,19 @@ namespace HealthMonitor.WebApi private readonly TDengineService _serviceTDengine; private readonly EtcdService _serviceEtcd; private readonly HttpHelper _httpHelper = default!; - private readonly IotWebApiService _serviceIotWebApi; + private readonly IotApiService _serviceIotApi; private readonly BoodPressResolverConfig _configBoodPressResolver; private readonly BloodPressReferenceValueCacheManager _bpRefValCacheManager; private readonly PersonCacheManager _personCacheMgr; private CancellationTokenSource _tokenSource = default!; - public Worker(ILogger logger, IServiceProvider services, PersonCacheManager personCacheMgr, BloodPressReferenceValueCacheManager bpRefValCacheManager, IotWebApiService iotWebApiService, IOptions optionBoodPressResolver, PackageProcess processor, TDengineDataSubcribe tdEngineDataSubcribe, TDengineService serviceDengine, HttpHelper httpHelper, EtcdService serviceEtcd) + public Worker(ILogger logger, IServiceProvider services, PersonCacheManager personCacheMgr, BloodPressReferenceValueCacheManager bpRefValCacheManager, IotApiService IotApiService, IOptions optionBoodPressResolver, PackageProcess processor, TDengineDataSubcribe tdEngineDataSubcribe, TDengineService serviceDengine, HttpHelper httpHelper, EtcdService serviceEtcd) { _logger = logger; _tdEngineDataSubcribe = tdEngineDataSubcribe; _services = services; - _serviceIotWebApi = iotWebApiService; + _serviceIotApi = IotApiService; _processor = processor; _serviceEtcd = serviceEtcd; _serviceTDengine = serviceDengine; @@ -116,283 +116,382 @@ namespace HealthMonitor.WebApi case "Delete": // TTL到了重新计算TTL,下发 - Console.BackgroundColor = ConsoleColor.Green; - Console.WriteLine($"--- {e.Type}--{e.Kv.Key.ToStringUtf8()}--{e.Kv.Value.ToStringUtf8()}---{DateTime.Now}"); + //Console.BackgroundColor = ConsoleColor.Green; + //Console.WriteLine($"--- {e.Type}--{e.Kv.Key.ToStringUtf8()}--{e.Kv.Value.ToStringUtf8()}---{DateTime.Now}"); // var key = $"health_moniter/schedule_push/imei/{bp.Serialno}"; var key = e.Kv.Key.ToStringUtf8(); - var imeiDel = key.Split('/')[3]; + var imeiDel = key.Split('/')[^1]; var schedule_push = await _serviceEtcd.GetValAsync(key).ConfigureAwait(false); if (string.IsNullOrWhiteSpace(schedule_push)) { - int systolicInc; - int diastolicInc; + if (key.Contains("pregnancy_heart_rate")) + { + // 处理孕妇业务,计算一般心率并下发 + var commonPHR= await _serviceTDengine.InitPregnancyCommonHeartRateModeAsync(imeiDel); + // 设置胎心监测参数 - int systolicRefValue; - int diastolicRefValue; + if (commonPHR == null) + { + // 建模中 + var flag= await _serviceIotApi.SetFetalHeartRateConfig(imeiDel); + _logger.LogInformation($"{imeiDel} 建模建模中"); + } + else + { + // 建模完成 + var flag = await _serviceIotApi.SetFetalHeartRateConfig(imeiDel,1,commonPHR.MaxValue,commonPHR.MinValue); + _logger.LogInformation($"{imeiDel} 建模完成"); + // 保存到TDengine数据库 + await _serviceTDengine.InsertAsync("hm_pchr", commonPHR); + _logger.LogInformation($"保存TDengine完成"); + } - decimal systolicAvg; - decimal diastolicAvg; + #region 注册定时下发 + var startTime = DateTime.Now; + // 注册下次下推 + var endTime = DateTime.Now; - int systolicMax = 0; - int diastolicMax = 0; +#if DEBUG - // 统计时间 - //DateTime endTime = DateTime.Now; //测试 - DateTime statStartTime = DateTime.Now; + //long ttl = (long)((60 * 1000-(endTime-startTime).TotalMilliseconds)/1000); + //await _serviceEtcd.PutValAsync(key, imeiDel,ttl, false).ConfigureAwait(false); - // 最小值 - int systolicMin = 0; - int diastolicMin = 0; + var interval = 0; + // 获取当前时间 + DateTime now = DateTime.Now; - // 偏移参数 - var avgOffset = 0.25M; - var systolicAvgOffset = avgOffset; - var diastolicAvgOffset = avgOffset; + // 计算距离下一个$interval天后的8点的时间间隔 + DateTime nextRunTime = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute + 2, 0).AddDays(interval); + TimeSpan timeUntilNextRun = nextRunTime - now; - // 最后一次下发值 - int lastPushSystolicInc = 0; - int lastPushDiastolicInc = 0; + // 如果当前时间已经超过了8点,将等待到明天后的8点 + if (timeUntilNextRun < TimeSpan.Zero) + { + timeUntilNextRun = timeUntilNextRun.Add(TimeSpan.FromMinutes(1)); + nextRunTime += timeUntilNextRun; + } + + //long ttl = timeUntilNextRun.Milliseconds/1000; + long ttl = (long)((timeUntilNextRun.TotalMilliseconds - (endTime - startTime).TotalMilliseconds) / 1000); + var data = new + { + imei = imeiDel, + 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); - var startTime = DateTime.Now; - // 下发增量值 - #region 统计定时下发增量值 - //var last = await _serviceTDengine.GetLastAsync("stb_hm_bloodpress_stats_inc", $"serialno='{imeiDel}' order by last_update desc"); - //var ts = last?[0]; - // 最后一条血压数据 - var condition = $"serialno='{imeiDel}' order by last_update desc"; - var field = "last_row(*)"; - var lastHmBpResponse = await _serviceTDengine.ExecuteSelectRestResponseAsync("stb_hm_bloodpress", condition, field); - var lastHmBpParser = JsonConvert.DeserializeObject>(lastHmBpResponse!); - var lastHmBp = lastHmBpParser?.Select().FirstOrDefault(); - //if (lastHmBpParser?.Select()?.ToList().Count < 2) - //{ - // _logger.LogInformation($"{imeiDel} -- {nameof(Worker)} --{nameof(WatchEvents)} -- 血压数据条目不足"); - // break; - //} +#else + // 每$interval天,晚上8点 + var interval = 1; + // 获取当前时间 + DateTime now = DateTime.Now; + var rand = new Random(); - // 7 天有效数据 - if (lastHmBp?.Timestamp.AddDays(7) > DateTime.Now) + var pushSec = rand.Next(59); + int pushMin = int.TryParse(imeiDel.AsSpan(imeiDel.Length - 1), out pushMin) ? pushMin : 10; + // 计算距离下一个$interval天后的8点的时间间隔 + DateTime nextRunTime = new DateTime(now.Year, now.Month, now.Day, 18, pushMin, pushSec).AddDays(interval); + TimeSpan timeUntilNextRun = nextRunTime - now; + + // 如果当前时间已经超过了8点,将等待到明天后的8点 + if (timeUntilNextRun < TimeSpan.Zero) + { + timeUntilNextRun = timeUntilNextRun.Add(TimeSpan.FromDays(1)); + nextRunTime += timeUntilNextRun; + } + + // var ttl = timeUntilNextRun.TotalMilliseconds; + long ttl = (long)((timeUntilNextRun.TotalMilliseconds-(endTime-startTime).TotalMilliseconds)/1000); + var data = new + { + imei = imeiDel, + 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); +#endif + #endregion + } + else { - // 计算增量值 - condition = $"serialno='{imeiDel}' order by ts desc"; - var lastPushResponse = await _serviceTDengine.ExecuteSelectRestResponseAsync("stb_hm_bp_push_ref_inc_value", condition, field); - if (lastPushResponse == null) + // 处理血压业务 + int systolicInc; + int diastolicInc; + + int systolicRefValue; + int diastolicRefValue; + + decimal systolicAvg; + decimal diastolicAvg; + + int systolicMax = 0; + int diastolicMax = 0; + + // 统计时间 + //DateTime endTime = DateTime.Now; //测试 + DateTime statStartTime = DateTime.Now; + + + // 最小值 + int systolicMin = 0; + int diastolicMin = 0; + + // 偏移参数 + var avgOffset = 0.25M; + var systolicAvgOffset = avgOffset; + var diastolicAvgOffset = avgOffset; + + // 最后一次下发值 + int lastPushSystolicInc = 0; + int lastPushDiastolicInc = 0; + + + var startTime = DateTime.Now; + // 下发增量值 + #region 统计定时下发增量值 + //var last = await _serviceTDengine.GetLastAsync("stb_hm_bloodpress_stats_inc", $"serialno='{imeiDel}' order by last_update desc"); + //var ts = last?[0]; + + // 最后一条血压数据 + var condition = $"serialno='{imeiDel}' order by last_update desc"; + var field = "last_row(*)"; + var lastHmBpResponse = await _serviceTDengine.ExecuteSelectRestResponseAsync("stb_hm_bloodpress", condition, field); + var lastHmBpParser = JsonConvert.DeserializeObject>(lastHmBpResponse!); + var lastHmBp = lastHmBpParser?.Select().FirstOrDefault(); + //if (lastHmBpParser?.Select()?.ToList().Count < 2) + //{ + // _logger.LogInformation($"{imeiDel} -- {nameof(Worker)} --{nameof(WatchEvents)} -- 血压数据条目不足"); + // break; + //} + + // 7 天有效数据 + if (lastHmBp?.Timestamp.AddDays(7) > DateTime.Now) { - _logger.LogInformation($"{imeiDel}--没有下发记录"); - break; - } - var lastPushParser = JsonConvert.DeserializeObject>(lastPushResponse); - var lastPush = lastPushParser!.Select().FirstOrDefault(); - // 有下推记录 - if (lastPush != null) - { - systolicRefValue = lastPush!.SystolicRefValue; - diastolicRefValue = lastPush!.DiastolicRefValue; - lastPushSystolicInc = lastPush!.SystolicIncValue; - lastPushDiastolicInc = lastPush!.DiastolicIncValue; - condition = $"ts between '{lastPush?.Timestamp:yyyy-MM-dd HH:mm:ss.fff}' and '{startTime:yyyy-MM-dd HH:mm:ss.fff}' " + - $"and serialno='{imeiDel}' " + - $"and is_display = true"; - // 使用最近一次的下推时间作为统计的开始时间 - statStartTime = lastPush!.Timestamp; - } - // 没有下推记录(历史遗留数据),没有初始的测量值产生的平均值(测量值=平均值) - else - { - #region 获取个人信息 - - var person = await _personCacheMgr.GetDeviceGpsPersonCacheBySerialNoAsync(Guid.NewGuid().ToString(), imeiDel).ConfigureAwait(false); - //验证这个信息是否存在 - if (person == null || person?.Person.BornDate == null) + // 计算增量值 + condition = $"serialno='{imeiDel}' order by ts desc"; + var lastPushResponse = await _serviceTDengine.ExecuteSelectRestResponseAsync("stb_hm_bp_push_ref_inc_value", condition, field); + if (lastPushResponse == null) { - _logger.LogWarning($"{nameof(Worker)}--{imeiDel} 验证个人信息,找不到个人信息,跳过此消息"); + _logger.LogInformation($"{imeiDel}--没有下发记录"); break; } - // 验证年龄是否在范围 (2 - 120) - var age = SafeType.SafeInt(DateTime.Today.Year - person?.Person.BornDate!.Value.Year!); - if (age < 2 || age > 120) + var lastPushParser = JsonConvert.DeserializeObject>(lastPushResponse); + var lastPush = lastPushParser!.Select().FirstOrDefault(); + // 有下推记录 + if (lastPush != null) { - _logger.LogWarning($"{nameof(Worker)}--{imeiDel} 验证年龄,不在范围 (2 - 120)岁,跳过此消息"); - break; + systolicRefValue = lastPush!.SystolicRefValue; + diastolicRefValue = lastPush!.DiastolicRefValue; + lastPushSystolicInc = lastPush!.SystolicIncValue; + lastPushDiastolicInc = lastPush!.DiastolicIncValue; + condition = $"ts between '{lastPush?.Timestamp:yyyy-MM-dd HH:mm:ss.fff}' and '{startTime:yyyy-MM-dd HH:mm:ss.fff}' " + + $"and serialno='{imeiDel}' " + + $"and is_display = true"; + // 使用最近一次的下推时间作为统计的开始时间 + statStartTime = lastPush!.Timestamp; } + // 没有下推记录(历史遗留数据),没有初始的测量值产生的平均值(测量值=平均值) + else + { + #region 获取个人信息 - var gender = person?.Person.Gender == true ? 1 : 2; - var isHypertension = SafeType.SafeBool(person?.Person.Ishypertension!); - var height = SafeType.SafeDouble(person?.Person.Height!); - var weight = SafeType.SafeDouble(person?.Person.Weight!); - - #endregion - - #region 初始化常规血压标定值标定值 - var bpRef = await _bpRefValCacheManager.GetBloodPressReferenceValueAsync(age, gender, isHypertension); - //systolicRefValue = bpRef!.Systolic;//? - //diastolicRefValue = bpRef!.Diastolic;//? - #endregion - - systolicRefValue = bpRef!.Systolic; - diastolicRefValue = bpRef!.Diastolic; - lastPushSystolicInc = 0; - lastPushDiastolicInc = 0; - condition = $"ts <= '{startTime:yyyy-MM-dd HH:mm:ss.fff}' " + - $"and serialno='{imeiDel}' " + - $"and is_display = true"; - } + var person = await _personCacheMgr.GetDeviceGpsPersonCacheBySerialNoAsync(Guid.NewGuid().ToString(), imeiDel).ConfigureAwait(false); + //验证这个信息是否存在 + if (person == null || person?.Person.BornDate == null) + { + _logger.LogWarning($"{nameof(Worker)}--{imeiDel} 验证个人信息,找不到个人信息,跳过此消息"); + break; + } + // 验证年龄是否在范围 (2 - 120) + var age = SafeType.SafeInt(DateTime.Today.Year - person?.Person.BornDate!.Value.Year!); + if (age < 2 || age > 120) + { + _logger.LogWarning($"{nameof(Worker)}--{imeiDel} 验证年龄,不在范围 (2 - 120)岁,跳过此消息"); + break; + } + var gender = person?.Person.Gender == true ? 1 : 2; + var isHypertension = SafeType.SafeBool(person?.Person.Ishypertension!); + var height = SafeType.SafeDouble(person?.Person.Height!); + var weight = SafeType.SafeDouble(person?.Person.Weight!); + #endregion - var hmBpResponse = await _serviceTDengine.ExecuteSelectRestResponseAsync("stb_hm_bloodpress", condition); - var hmBpParser = JsonConvert.DeserializeObject>(hmBpResponse!); - var hmBp = hmBpParser?.Select(); - //if (hmBp?.ToList().Count < 2) - // 1. 判断数据样本数量 - if (hmBpParser!.Rows < 5) - { - _logger.LogInformation($"{imeiDel} -- {nameof(Worker)} --{nameof(WatchEvents)} -- 统计定时下发,计算增量值的数据条目不足:{hmBpParser!.Rows} < 5"); - _logger.LogInformation($"{imeiDel} -- {nameof(Worker)} --{nameof(WatchEvents)} 没有足够的数据样本,不会定时下发"); - break; - } - // 没有下推记录重新计算统计时间 - if (lastPush == null) - { - var firstHmBp = hmBpParser?.Select(i => i).OrderBy(i => i.Timestamp).FirstOrDefault(); - statStartTime = firstHmBp!.Timestamp; - } + #region 初始化常规血压标定值标定值 + var bpRef = await _bpRefValCacheManager.GetBloodPressReferenceValueAsync(age, gender, isHypertension); + //systolicRefValue = bpRef!.Systolic;//? + //diastolicRefValue = bpRef!.Diastolic;//? + #endregion - // NewMethod(systolicRefValue, hmBpParser); + systolicRefValue = bpRef!.Systolic; + diastolicRefValue = bpRef!.Diastolic; + lastPushSystolicInc = 0; + lastPushDiastolicInc = 0; + condition = $"ts <= '{startTime:yyyy-MM-dd HH:mm:ss.fff}' " + + $"and serialno='{imeiDel}' " + + $"and is_display = true"; + } - // 最大值 - //systolicMax = (int)hmBpParser?.Select(i => i.SystolicValue).Max()!; - //diastolicMax = (int)hmBpParser?.Select(i => i.DiastolicValue).Max()!; - //// 最小值 - //systolicMin = (int)hmBpParser?.Select(i => i.SystolicValue).Min()!; - //diastolicMin = (int)hmBpParser?.Select(i => i.DiastolicValue).Min()!; - //systolicAvg = (int)(hmBpParser?.AverageAfterRemovingOneMinMaxRef(i => i.SystolicValue, SafeType.SafeInt(systolicRefValue!)))!; - //diastolicAvg = (int)(hmBpParser?.AverageAfterRemovingOneMinMaxRef(i => i.DiastolicValue, SafeType.SafeInt(diastolicRefValue!)))!; - var avgs = _serviceTDengine.AverageAfterRemovingOneMinMaxRef(hmBpParser!); - systolicAvg = avgs[0]; - diastolicAvg = avgs[1]; + var hmBpResponse = await _serviceTDengine.ExecuteSelectRestResponseAsync("stb_hm_bloodpress", condition); + var hmBpParser = JsonConvert.DeserializeObject>(hmBpResponse!); + var hmBp = hmBpParser?.Select(); + //if (hmBp?.ToList().Count < 2) + // 1. 判断数据样本数量 + if (hmBpParser!.Rows < 5) + { + _logger.LogInformation($"{imeiDel} -- {nameof(Worker)} --{nameof(WatchEvents)} -- 统计定时下发,计算增量值的数据条目不足:{hmBpParser!.Rows} < 5"); + _logger.LogInformation($"{imeiDel} -- {nameof(Worker)} --{nameof(WatchEvents)} 没有足够的数据样本,不会定时下发"); + break; + } + // 没有下推记录重新计算统计时间 + if (lastPush == null) + { + var firstHmBp = hmBpParser?.Select(i => i).OrderBy(i => i.Timestamp).FirstOrDefault(); + statStartTime = firstHmBp!.Timestamp; + } + // NewMethod(systolicRefValue, hmBpParser); - // 2. 判断能否计算增量值 - if (systolicAvg.Equals(0)) - { - _logger.LogInformation($"{imeiDel}--{nameof(Worker)}--计算平均值" + - $"\n currentSystolicAvg:{systolicAvg} -- lastPushSystolicInc:{lastPushSystolicInc}" + - $"\n currentDiastolicInc:{diastolicAvg} -- lastPushDiastolicInc:{lastPushDiastolicInc}"); - _logger.LogInformation($"{imeiDel}--{nameof(Worker)} 没有足够的数据样本计算平均值,不会定时下发"); - break; - } - // 除最大值和最小值后的平均值与标定值差值少于4后(当天计算出该结果则也不产生增量调整),就不再进行增量值调整了。 - if (systolicRefValue - systolicAvg < 4) - { - _logger.LogInformation($"diastolic 舒张压 {imeiDel}除最大值和最小值后的平均值:{diastolicAvg}与标定值:{diastolicRefValue}\n systolic 收缩压 {imeiDel}除最大值和最小值后的平均值:{systolicAvg}与标定值:{systolicRefValue}的差值(标定值-平均值)少于4后,systolic 收缩压 不再进行增量值调整"); - break; - } + // 最大值 + //systolicMax = (int)hmBpParser?.Select(i => i.SystolicValue).Max()!; + //diastolicMax = (int)hmBpParser?.Select(i => i.DiastolicValue).Max()!; + //// 最小值 + //systolicMin = (int)hmBpParser?.Select(i => i.SystolicValue).Min()!; + //diastolicMin = (int)hmBpParser?.Select(i => i.DiastolicValue).Min()!; - if (diastolicRefValue - diastolicAvg < 4) - { - _logger.LogInformation($"systolic 收缩压 {imeiDel}除最大值和最小值后的平均值:{systolicAvg}与标定值:{systolicRefValue}\n diastolic 舒张压 {imeiDel}除最大值和最小值后的平均值:{diastolicAvg}与标定值:{diastolicRefValue}的差值(标定值-平均值)少于4后,diastolic 舒张压 不再进行增量值调整"); - break; - } + //systolicAvg = (int)(hmBpParser?.AverageAfterRemovingOneMinMaxRef(i => i.SystolicValue, SafeType.SafeInt(systolicRefValue!)))!; + //diastolicAvg = (int)(hmBpParser?.AverageAfterRemovingOneMinMaxRef(i => i.DiastolicValue, SafeType.SafeInt(diastolicRefValue!)))!; - // 增量值=(标定值-平均值)* 0.25 - var currentSystolicInc = (int)((systolicRefValue - systolicAvg) * systolicAvgOffset)!; - var currentDiastolicInc = (int)((diastolicRefValue - diastolicAvg) * diastolicAvgOffset)!; + var avgs = _serviceTDengine.AverageAfterRemovingOneMinMaxRef(hmBpParser!); + systolicAvg = avgs[0]; + diastolicAvg = avgs[1]; - // 累计增量 - systolicInc = currentSystolicInc + lastPushSystolicInc; - diastolicInc = currentDiastolicInc + lastPushDiastolicInc; + // 2. 判断能否计算增量值 + if (systolicAvg.Equals(0)) + { + _logger.LogInformation($"{imeiDel}--{nameof(Worker)}--计算平均值" + + $"\n currentSystolicAvg:{systolicAvg} -- lastPushSystolicInc:{lastPushSystolicInc}" + + $"\n currentDiastolicInc:{diastolicAvg} -- lastPushDiastolicInc:{lastPushDiastolicInc}"); + _logger.LogInformation($"{imeiDel}--{nameof(Worker)} 没有足够的数据样本计算平均值,不会定时下发"); + break; + } + // 除最大值和最小值后的平均值与标定值差值少于4后(当天计算出该结果则也不产生增量调整),就不再进行增量值调整了。 + if (systolicRefValue - systolicAvg < 4) + { + _logger.LogInformation($"diastolic 舒张压 {imeiDel}除最大值和最小值后的平均值:{diastolicAvg}与标定值:{diastolicRefValue}\n systolic 收缩压 {imeiDel}除最大值和最小值后的平均值:{systolicAvg}与标定值:{systolicRefValue}的差值(标定值-平均值)少于4后,systolic 收缩压 不再进行增量值调整"); + break; + } - _logger.LogInformation($"{imeiDel}--{nameof(Worker)}--计算增量值" + - $"\n {imeiDel} -- systolicAvg:{systolicAvg}-- systolicInc:{systolicInc}-- currentSystolicInc:{currentSystolicInc} -- lastPushSystolicInc:{lastPushSystolicInc}" + - $"\n {imeiDel} -- diastolicAvg:{diastolicAvg}-- diastolicInc:{diastolicInc} --currentDiastolicInc:{currentDiastolicInc} -- lastPushDiastolicInc:{lastPushDiastolicInc}"); - _logger.LogInformation($"{imeiDel}--{nameof(Worker)}-- 定时校准,发给设备的绝对增量值=(上次绝对增量值+新数据的增量值)"); + if (diastolicRefValue - diastolicAvg < 4) + { + _logger.LogInformation($"systolic 收缩压 {imeiDel}除最大值和最小值后的平均值:{systolicAvg}与标定值:{systolicRefValue}\n diastolic 舒张压 {imeiDel}除最大值和最小值后的平均值:{diastolicAvg}与标定值:{diastolicRefValue}的差值(标定值-平均值)少于4后,diastolic 舒张压 不再进行增量值调整"); + break; + } + // 增量值=(标定值-平均值)* 0.25 + var currentSystolicInc = (int)((systolicRefValue - systolicAvg) * systolicAvgOffset)!; + var currentDiastolicInc = (int)((diastolicRefValue - diastolicAvg) * diastolicAvgOffset)!; - _logger.LogInformation($"{nameof(Worker)} 开启血压标定值下发: {_configBoodPressResolver.EnableBPRefPush}"); - if (_configBoodPressResolver.EnableBPRefPush) - // if (false) // 临时关闭 - { - BloodPressCalibrationConfigModel bpIncData = new() - { - Imei = imeiDel, - SystolicRefValue = SafeType.SafeInt(((int)systolicRefValue!)), //收缩压标定值,值为0 表示不生效 - DiastolicRefValue = SafeType.SafeInt(((int)diastolicRefValue!)), //舒张压标定值,值为0表示不生效 - SystolicIncValue = SafeType.SafeInt(((int)systolicInc!)), //收缩压显示增量,值为0 表示不生效 - DiastolicIncValue = SafeType.SafeInt(((int)diastolicInc!)) //舒张压显示增量,值为0 表示不生效 - }; - //var pushedBP = await _serviceIotWebApi.SetBloodPressCalibrationConfigAsync(bpIncData).ConfigureAwait(false); - var response = await _serviceIotWebApi.SetBloodPressCalibrationConfig2Async(bpIncData).ConfigureAwait(false); - var pushedBP = response.Flag; - if (pushedBP) + // 累计增量 + systolicInc = currentSystolicInc + lastPushSystolicInc; + diastolicInc = currentDiastolicInc + lastPushDiastolicInc; + + _logger.LogInformation($"{imeiDel}--{nameof(Worker)}--计算增量值" + + $"\n {imeiDel} -- systolicAvg:{systolicAvg}-- systolicInc:{systolicInc}-- currentSystolicInc:{currentSystolicInc} -- lastPushSystolicInc:{lastPushSystolicInc}" + + $"\n {imeiDel} -- diastolicAvg:{diastolicAvg}-- diastolicInc:{diastolicInc} --currentDiastolicInc:{currentDiastolicInc} -- lastPushDiastolicInc:{lastPushDiastolicInc}"); + _logger.LogInformation($"{imeiDel}--{nameof(Worker)}-- 定时校准,发给设备的绝对增量值=(上次绝对增量值+新数据的增量值)"); + + + _logger.LogInformation($"{nameof(Worker)} 开启血压标定值下发: {_configBoodPressResolver.EnableBPRefPush}"); + if (_configBoodPressResolver.EnableBPRefPush) + // if (false) // 临时关闭 { - #region 保存下推记录 stb_hm_bp_push_ref_inc_value - var sql = $"INSERT INTO health_monitor.hm_bp_push_ref_inc_value_{imeiDel.Substring(imeiDel.Length - 2)} " + - $"USING health_monitor.stb_hm_bp_push_ref_inc_value " + - $"TAGS ('{imeiDel.Substring(imeiDel.Length - 2)}') " + - $"VALUES(" + - $"'{startTime:yyyy-MM-dd HH:mm:ss.fff}'," + - $"'{imeiDel}'," + - $"{bpIncData.SystolicRefValue}," + - $"{bpIncData.DiastolicRefValue}," + - $"{bpIncData.SystolicIncValue}," + - $"{bpIncData.DiastolicIncValue}," + - $"{false}," + - $"{systolicAvg}," + - $"{diastolicAvg}," + - $"{systolicAvgOffset}," + - $"{diastolicAvgOffset}," + - $"'{statStartTime:yyyy-MM-dd HH:mm:ss.fff}'," + - $"'{startTime:yyyy-MM-dd HH:mm:ss.fff}'" + - $")"; - _serviceTDengine.ExecuteInsertSQL(sql); - #endregion + BloodPressCalibrationConfigModel bpIncData = new() + { - #region 注册定时下发 - // 注册下次下推 - var endTime = DateTime.Now; + Imei = imeiDel, + SystolicRefValue = SafeType.SafeInt(((int)systolicRefValue!)), //收缩压标定值,值为0 表示不生效 + DiastolicRefValue = SafeType.SafeInt(((int)diastolicRefValue!)), //舒张压标定值,值为0表示不生效 + SystolicIncValue = SafeType.SafeInt(((int)systolicInc!)), //收缩压显示增量,值为0 表示不生效 + DiastolicIncValue = SafeType.SafeInt(((int)diastolicInc!)) //舒张压显示增量,值为0 表示不生效 + }; + //var pushedBP = await _serviceIotApi.SetBloodPressCalibrationConfigAsync(bpIncData).ConfigureAwait(false); + var response = await _serviceIotApi.SetBloodPressCalibrationConfig2Async(bpIncData).ConfigureAwait(false); + var pushedBP = response.Flag; + if (pushedBP) + { + #region 保存下推记录 stb_hm_bp_push_ref_inc_value + var sql = $"INSERT INTO health_monitor.hm_bp_push_ref_inc_value_{imeiDel.Substring(imeiDel.Length - 2)} " + + $"USING health_monitor.stb_hm_bp_push_ref_inc_value " + + $"TAGS ('{imeiDel.Substring(imeiDel.Length - 2)}') " + + $"VALUES(" + + $"'{startTime:yyyy-MM-dd HH:mm:ss.fff}'," + + $"'{imeiDel}'," + + $"{bpIncData.SystolicRefValue}," + + $"{bpIncData.DiastolicRefValue}," + + $"{bpIncData.SystolicIncValue}," + + $"{bpIncData.DiastolicIncValue}," + + $"{false}," + + $"{systolicAvg}," + + $"{diastolicAvg}," + + $"{systolicAvgOffset}," + + $"{diastolicAvgOffset}," + + $"'{statStartTime:yyyy-MM-dd HH:mm:ss.fff}'," + + $"'{startTime:yyyy-MM-dd HH:mm:ss.fff}'" + + $")"; + _serviceTDengine.ExecuteInsertSQL(sql); + #endregion + + #region 注册定时下发 + // 注册下次下推 + var endTime = DateTime.Now; #if DEBUG - //long ttl = (long)((60 * 1000-(endTime-startTime).TotalMilliseconds)/1000); - //await _serviceEtcd.PutValAsync(key, imeiDel,ttl, false).ConfigureAwait(false); + //long ttl = (long)((60 * 1000-(endTime-startTime).TotalMilliseconds)/1000); + //await _serviceEtcd.PutValAsync(key, imeiDel,ttl, false).ConfigureAwait(false); - var interval = 0; - // 获取当前时间 - DateTime now = DateTime.Now; + var interval = 0; + // 获取当前时间 + DateTime now = DateTime.Now; - // 计算距离下一个$interval天后的8点的时间间隔 - DateTime nextRunTime = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute + 2, 0).AddDays(interval); - TimeSpan timeUntilNextRun = nextRunTime - now; + // 计算距离下一个$interval天后的8点的时间间隔 + DateTime nextRunTime = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute + 2, 0).AddDays(interval); + TimeSpan timeUntilNextRun = nextRunTime - now; - // 如果当前时间已经超过了8点,将等待到明天后的8点 - if (timeUntilNextRun < TimeSpan.Zero) - { - timeUntilNextRun = timeUntilNextRun.Add(TimeSpan.FromMinutes(1)); - nextRunTime += timeUntilNextRun; - } + // 如果当前时间已经超过了8点,将等待到明天后的8点 + if (timeUntilNextRun < TimeSpan.Zero) + { + timeUntilNextRun = timeUntilNextRun.Add(TimeSpan.FromMinutes(1)); + nextRunTime += timeUntilNextRun; + } - // var ttl = timeUntilNextRun.TotalMilliseconds; - long ttl = (long)((timeUntilNextRun.TotalMilliseconds - (endTime - startTime).TotalMilliseconds) / 1000); - var data = new - { - imei = imeiDel, - 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); + // var ttl = timeUntilNextRun.TotalMilliseconds; + long ttl = (long)((timeUntilNextRun.TotalMilliseconds - (endTime - startTime).TotalMilliseconds) / 1000); + var data = new + { + imei = imeiDel, + create_time = now.ToString("yyyy-MM-dd HH:mm:ss"), + ttl, + next_run_time = nextRunTime.ToString("yyyy-MM-dd HH:mm:ss") + }; + var result = JsonConvert.SerializeObject(data); - await _serviceEtcd.PutValAsync(key, result, ttl, false).ConfigureAwait(false); + await _serviceEtcd.PutValAsync(key, result, ttl, false).ConfigureAwait(false); #else @@ -424,24 +523,24 @@ namespace HealthMonitor.WebApi var result = JsonConvert.SerializeObject(data); await _serviceEtcd.PutValAsync(key, result, ttl, false).ConfigureAwait(false); #endif - #endregion + #endregion - } - else - { - _logger.LogInformation($"错误响应,没有下推数据:{response.Message}"); + } + else + { + _logger.LogInformation($"错误响应,没有下推数据:{response.Message}"); + } } } - } - else - { - _logger.LogInformation($"向{imeiDel}统计数据已经失效"); - } - #endregion + else + { + _logger.LogInformation($"向{imeiDel}统计数据已经失效"); + } + #endregion + } } - break; } } @@ -454,62 +553,6 @@ namespace HealthMonitor.WebApi }); } - /** - protected override Task ExecuteAsync(CancellationToken stoppingToken) - { - TaskFactory factory = new(_tokenSource.Token); - factory.StartNew(async () => - { - if (_tokenSource.IsCancellationRequested) - _logger.LogWarning("Worker exit"); - - _logger.LogInformation("------ResolveAsync"); - while (!_tokenSource.IsCancellationRequested) - { - - await _processor.ResolveAsync().ConfigureAwait(false); - } - - }, TaskCreationOptions.LongRunning); - - factory.StartNew(() => - { - _logger.LogInformation("------_tdEngineDataSubcribe"); - while (!_tokenSource.IsCancellationRequested) - { - _tdEngineDataSubcribe.BeginListen(_tokenSource.Token); - } - }, TaskCreationOptions.LongRunning); - - Task.Run(() => - _serviceEtcd.WacthKeysWithPrefixResponseAsync($"health_moniter/schedule_push", WatchEvents) - , stoppingToken); - return Task.Delay(1000, _tokenSource.Token); - - } - **/ - - /** - private void WatchEvents(WatchEvent[] response) - { - foreach (WatchEvent e1 in response) - { - // Console.WriteLine($"{nameof(WatchEventsAsync)} --- {e1.Key}:{e1.Value}:{e1.Type}"); - - switch (e1.Type.ToString()) - { - //case "Put": - // // 获取时间点计算TTL - // break; - - case "Delete": - // TTL到了重新计算TTL,下发 - Console.WriteLine($"--- {e1.Key}:{e1.Value}:{e1.Type}"); - break; - } - } - } - */ } diff --git a/HealthMonitor.WebApi/appsettings.Development.json b/HealthMonitor.WebApi/appsettings.Development.json index 8a14514..9bc2665 100644 --- a/HealthMonitor.WebApi/appsettings.Development.json +++ b/HealthMonitor.WebApi/appsettings.Development.json @@ -27,7 +27,9 @@ "ServiceConfig": { "TelpoDataUrl": "https://id.gdssjl.com/data/", "EtcdServerAddress": "http://192.168.2.121:2379", - "IotWebApiUrl": "http://id.gdssjl.com/webapi/api/" + "IotWebApiUrl": "http://id.gdssjl.com/webapi/api/", + "IotAuth": "http://id.ssjlai.com/auth/identityController", + "IotCore": "https://id.ssjlai.com/gateway/core/api/v1/open/OpenIot" }, "BoodPressResolverConfig": { "EnableBPRefPush": true diff --git a/HealthMonitor.WebApi/appsettings.production.json b/HealthMonitor.WebApi/appsettings.production.json index b0dd66a..88c3dac 100644 --- a/HealthMonitor.WebApi/appsettings.production.json +++ b/HealthMonitor.WebApi/appsettings.production.json @@ -24,7 +24,9 @@ "ServiceConfig": { "TelpoDataUrl": "https://ai.gdssjl.com/data/", "EtcdServerAddress": "http://172.19.42.40:2379", - "IotWebApiUrl": "http://ai.gdssjl.com/webapi/api/" + "IotWebApiUrl": "http://ai.gdssjl.com/webapi/api/", + "IotAuth": "http://ai.ssjlai.com/auth/identityController", + "IotCore": "https://ai.ssjlai.com/gateway/core/api/v1/open/OpenIot" }, "BoodPressResolverConfig": { "EnableBPRefPush": true diff --git a/HealthMonitor.WebApi/appsettings.test.json b/HealthMonitor.WebApi/appsettings.test.json index 9fdc349..06be6f4 100644 --- a/HealthMonitor.WebApi/appsettings.test.json +++ b/HealthMonitor.WebApi/appsettings.test.json @@ -32,7 +32,9 @@ "ServiceConfig": { "TelpoDataUrl": "https://id.gdssjl.com/data/", "EtcdServerAddress": "http://172.19.42.44:2379", - "IotWebApiUrl": "http://id.gdssjl.com/webapi/api/" + "IotWebApiUrl": "http://id.gdssjl.com/webapi/api/", + "IotAuth": "http://id.ssjlai.com/auth/identityController", + "IotCore": "https://id.ssjlai.com/gateway/core/api/v1/open/OpenIot" }, "BoodPressResolverConfig": { "EnableBPRefPush": true