@@ -10,17 +10,9 @@ | |||||
public string EtcdServerAddress { get; set; } = default!; | public string EtcdServerAddress { get; set; } = default!; | ||||
public string IotWebApiUrl { get; set; } = default!; | public string IotWebApiUrl { get; set; } = default!; | ||||
///// <summary> | |||||
///// Kafka服务地址 | |||||
///// </summary> | |||||
//public string MqServerAddress { get; set; } | |||||
///// <summary> | |||||
///// 服务守护消息kafka服务地址 | |||||
///// </summary> | |||||
//public string ServiceGuardMqAddress { get; set; } | |||||
///// <summary> | |||||
///// 服务守护消息主题 | |||||
///// </summary> | |||||
//public string ServiceGuardMqTopic { get; set; } | |||||
public string IotAuth { get; set; } = default!; | |||||
public string IotCore { get; set; } = default!; | |||||
} | } | ||||
} | } |
@@ -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!; | |||||
} | |||||
} |
@@ -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<IotApiService> _logger; | |||||
private readonly PersonCacheManager _personCacheMgr; | |||||
private readonly DeviceCacheManager _deviceCacheMgr; | |||||
private readonly HttpHelper _httpHelper = default!; | |||||
private readonly GpsCardAccessorClient<GpsPerson> _gpsPersonApiClient; | |||||
public IotApiService(ILogger<IotApiService> logger, HttpHelper httpHelper, DeviceCacheManager deviceCacheMgr, GpsCardAccessorClient<GpsPerson> gpsPersonApiClient, IOptions<ServiceConfig> optConfigService, PersonCacheManager personCacheMgr) | |||||
{ | |||||
_configService = optConfigService.Value; | |||||
_httpHelper=httpHelper; | |||||
_logger = logger; | |||||
_personCacheMgr = personCacheMgr; | |||||
_gpsPersonApiClient = gpsPersonApiClient; | |||||
_deviceCacheMgr = deviceCacheMgr; | |||||
} | |||||
#region 平台下发血压标定参数 | |||||
/// <summary> | |||||
/// 平台下发血压标定参数 | |||||
/// </summary> | |||||
/// <param name="bpsCalibrationConfig"></param> | |||||
/// <returns></returns> | |||||
public async Task<bool> 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<KeyValuePair<string, string>> headers = new() | |||||
{ | |||||
new KeyValuePair<string, string>("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<BloodPressCalibrationConfigModelReponse> 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<KeyValuePair<string, string>> headers = new() | |||||
{ | |||||
new KeyValuePair<string, string>("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<bool> 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<QueryFilterCondition> { | |||||
new QueryFilterCondition { | |||||
Key=nameof(GpsDevice.Serialno), | |||||
Value=imei, | |||||
Operator= QueryOperatorEnum.Equal, | |||||
ValueType=QueryValueTypeEnum.String | |||||
} | |||||
}, | |||||
OrderBys = new List<OrderByCondition> { 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<QueryFilterCondition> { | |||||
// new QueryFilterCondition { | |||||
// Key=nameof(GpsDevice.Serialno), | |||||
// Value=imei, | |||||
// Operator= QueryOperatorEnum.Equal, | |||||
// ValueType=QueryValueTypeEnum.String | |||||
// } | |||||
// }, | |||||
// OrderBys = new List<OrderByCondition> { 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<bool> 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<KeyValuePair<string, string>> headers = new() | |||||
{ | |||||
new KeyValuePair<string, string>("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 | |||||
} | |||||
} |
@@ -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<IotWebApiService> _logger; | |||||
private readonly PersonCacheManager _personCacheMgr; | |||||
private readonly HttpHelper _httpHelper = default!; | |||||
private readonly GpsCardAccessorClient<GpsPerson> _gpsPersonApiClient; | |||||
public IotWebApiService(ILogger<IotWebApiService> logger, HttpHelper httpHelper, GpsCardAccessorClient<GpsPerson> gpsPersonApiClient, IOptions<ServiceConfig> optConfigService, PersonCacheManager personCacheMgr) | |||||
{ | |||||
_configService = optConfigService.Value; | |||||
_httpHelper=httpHelper; | |||||
_logger = logger; | |||||
_personCacheMgr = personCacheMgr; | |||||
_gpsPersonApiClient = gpsPersonApiClient; | |||||
} | |||||
/// <summary> | |||||
/// 平台下发血压标定参数 | |||||
/// </summary> | |||||
/// <param name="bpsCalibrationConfig"></param> | |||||
/// <returns></returns> | |||||
public async Task<bool> 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<KeyValuePair<string, string>> headers = new() | |||||
{ | |||||
new KeyValuePair<string, string>("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<BloodPressCalibrationConfigModelReponse> 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<KeyValuePair<string, string>> headers = new() | |||||
{ | |||||
new KeyValuePair<string, string>("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; | |||||
} | |||||
/** 取消 | |||||
/// <summary> | |||||
/// 更新 gps_person remark和缓存 | |||||
/// </summary> | |||||
/// <param name="imei"></param> | |||||
/// <param name="systolicRefValue"></param> | |||||
/// <param name="diastolicRefValue"></param> | |||||
/// <returns></returns> | |||||
public async Task<bool> UpdatePersonRemarksAsync(string imei,int systolicRefValue,int diastolicRefValue) | |||||
{ | |||||
var flag = false; | |||||
try | |||||
{ | |||||
GeneralParam condition = new () | |||||
{ | |||||
Filters = new List<QueryFilterCondition> { | |||||
new QueryFilterCondition { | |||||
Key=nameof(GpsDevice.Serialno), | |||||
Value=imei, | |||||
Operator= QueryOperatorEnum.Equal, | |||||
ValueType=QueryValueTypeEnum.String | |||||
} | |||||
}, | |||||
OrderBys = new List<OrderByCondition> { 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<KeyValuePair<string, string>> headers = new() | |||||
// { | |||||
// new KeyValuePair<string, string>("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<KeyValuePair<string, string>> headers = new() | |||||
{ | |||||
new KeyValuePair<string, string>("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; | |||||
} | |||||
*/ | |||||
///// <summary> | |||||
///// 初次开通更新 gps_person remark和对应的缓存 | |||||
///// </summary> | |||||
///// <param name="imei"></param> | |||||
///// <param name="systolicRefValue"></param> | |||||
///// <param name="diastolicRefValue"></param> | |||||
///// <param name="systolicIncValue"></param> | |||||
///// <param name="diastolicIncValue"></param> | |||||
///// <returns></returns> | |||||
//public async Task<bool> UpdatePersonRemarksAsync0(string imei, int systolicRefValue, int diastolicRefValue,int systolicIncValue,int diastolicIncValue) | |||||
//{ | |||||
// var flag = false; | |||||
// try | |||||
// { | |||||
// GeneralParam condition = new() | |||||
// { | |||||
// Filters = new List<QueryFilterCondition> { | |||||
// new QueryFilterCondition { | |||||
// Key=nameof(GpsDevice.Serialno), | |||||
// Value=imei, | |||||
// Operator= QueryOperatorEnum.Equal, | |||||
// ValueType=QueryValueTypeEnum.String | |||||
// } | |||||
// }, | |||||
// OrderBys = new List<OrderByCondition> { 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<KeyValuePair<string, string>> headers = new() | |||||
// //{ | |||||
// // new KeyValuePair<string, string>("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; | |||||
//} | |||||
/** | |||||
/// <summary> | |||||
/// 更新 gps_person remark缓存和数据库 | |||||
/// </summary> | |||||
/// <param name="imei"></param> | |||||
/// <param name="systolicRefValue"></param> | |||||
/// <param name="diastolicRefValue"></param> | |||||
/// <param name="systolicIncValue"></param> | |||||
/// <param name="diastolicIncValue"></param> | |||||
/// <param name="isInitRemakers">是否初始化,即清空remakers</param> | |||||
/// <returns></returns> | |||||
public async Task<bool> 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<QueryFilterCondition> { | |||||
new QueryFilterCondition { | |||||
Key=nameof(GpsDevice.Serialno), | |||||
Value=imei, | |||||
Operator= QueryOperatorEnum.Equal, | |||||
ValueType=QueryValueTypeEnum.String | |||||
} | |||||
}, | |||||
OrderBys = new List<OrderByCondition> { 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; | |||||
} | |||||
*/ | |||||
/// <summary> | |||||
///// 更新 gps_person remark缓存和数据库 | |||||
///// </summary> | |||||
///// <param name="imei"></param> | |||||
///// <param name="systolicRefValue"></param> | |||||
///// <param name="diastolicRefValue"></param> | |||||
///// <param name="systolicIncValue"></param> | |||||
///// <param name="diastolicIncValue"></param> | |||||
///// <param name="remarks"></param> | |||||
///// <returns></returns> | |||||
//public async Task<bool> 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<QueryFilterCondition> { | |||||
// new QueryFilterCondition { | |||||
// Key=nameof(GpsDevice.Serialno), | |||||
// Value=imei, | |||||
// Operator= QueryOperatorEnum.Equal, | |||||
// ValueType=QueryValueTypeEnum.String | |||||
// } | |||||
// }, | |||||
// OrderBys = new List<OrderByCondition> { 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缓存和数据库 | |||||
/// </summary> | |||||
/// <param name="imei"></param> | |||||
/// <param name="systolicRefValue"></param> | |||||
/// <param name="diastolicRefValue"></param> | |||||
/// <param name="systolicIncValue"></param> | |||||
/// <param name="diastolicIncValue"></param> | |||||
/// <param name="remarks"></param> | |||||
/// <returns></returns> | |||||
public async Task<bool> 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<QueryFilterCondition> { | |||||
new QueryFilterCondition { | |||||
Key=nameof(GpsDevice.Serialno), | |||||
Value=imei, | |||||
Operator= QueryOperatorEnum.Equal, | |||||
ValueType=QueryValueTypeEnum.String | |||||
} | |||||
}, | |||||
OrderBys = new List<OrderByCondition> { 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<QueryFilterCondition> { | |||||
// new QueryFilterCondition { | |||||
// Key=nameof(GpsDevice.Serialno), | |||||
// Value=imei, | |||||
// Operator= QueryOperatorEnum.Equal, | |||||
// ValueType=QueryValueTypeEnum.String | |||||
// } | |||||
// }, | |||||
// OrderBys = new List<OrderByCondition> { 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<bool> UpdatePersonInfoCacheAsync(string imei) | |||||
{ | |||||
var flag = false; | |||||
try | |||||
{ | |||||
var url = $"{_configService.IotWebApiUrl}Device/UpdatePersonInfoCache?imei={imei}"; | |||||
List<KeyValuePair<string, string>> headers = new() | |||||
{ | |||||
new KeyValuePair<string, string>("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; | |||||
} | |||||
*/ | |||||
} | |||||
} |
@@ -637,6 +637,7 @@ namespace HealthMonitor.Service.Biz.db | |||||
} | } | ||||
#region SqlSugarClient | #region SqlSugarClient | ||||
/** | |||||
public async Task InsertFetalHeartRateAsync() | public async Task InsertFetalHeartRateAsync() | ||||
{ | { | ||||
var tableName = typeof(FetalHeartRateModel) | var tableName = typeof(FetalHeartRateModel) | ||||
@@ -680,61 +681,9 @@ namespace HealthMonitor.Service.Biz.db | |||||
.OrderByDescending(x => x.Timestamp).FirstAsync(); | .OrderByDescending(x => x.Timestamp).FirstAsync(); | ||||
return first; | return first; | ||||
} | } | ||||
public void InsertFetalHeartRate2() | |||||
{ | |||||
//var insrtSql = ""; | |||||
//_clientSqlSugar.Ado.ExecuteCommand(insrtSql); | |||||
// 通过反射获取STableAttribute的STableName值 | |||||
var tableName = typeof(FetalHeartRateModel) | |||||
.GetCustomAttribute<STableAttribute>()? | |||||
.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<FetalHeartRateModel> 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(); | |||||
} | |||||
*/ | |||||
/// <summary> | /// <summary> | ||||
/// 插入记录 | /// 插入记录 | ||||
/// </summary> | /// </summary> | ||||
@@ -808,5 +757,192 @@ namespace HealthMonitor.Service.Biz.db | |||||
return res; | return res; | ||||
} | } | ||||
#endregion | #endregion | ||||
#region 胎心算法 | |||||
/// <summary> | |||||
/// 获取孕妇心率众数 | |||||
/// </summary> | |||||
/// <param name="serialNo"></param> | |||||
/// <param name="days"></param> | |||||
/// <returns></returns> | |||||
public async Task<int> GetPregnancyHeartRateModeAsync(string serialNo,int days=7) | |||||
{ | |||||
var tableName = typeof(PregnancyHeartRateModel) | |||||
.GetCustomAttribute<STableAttribute>()? | |||||
.STableName; | |||||
var res = await _clientSqlSugar | |||||
.Queryable<PregnancyHeartRateModel>() | |||||
.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; | |||||
} | |||||
/// <summary> | |||||
/// 计算个人一般心率 | |||||
/// </summary> | |||||
/// <param name="serialNo"></param> | |||||
/// <param name="days"></param> | |||||
/// <param name="percentage"></param> | |||||
/// <returns></returns> | |||||
public async Task<PregnancyCommonHeartRateModel?> InitPregnancyCommonHeartRateModeAsync(string serialNo, int days = 7,int percentage=90) | |||||
{ | |||||
var tableName = typeof(PregnancyHeartRateModel) | |||||
.GetCustomAttribute<STableAttribute>()? | |||||
.STableName; | |||||
var collection = await _clientSqlSugar | |||||
.Queryable<PregnancyHeartRateModel>() | |||||
.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 | |||||
} | } | ||||
} | } |
@@ -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<DeviceCacheManager> _logger; | |||||
private const string CACHE_KEY_GPSDEVICE_WATCH_CONFIG = "#GPSDEVICE_WATCH_CONFIG_HASH"; | |||||
public DeviceCacheManager(ILogger<DeviceCacheManager> logger) | |||||
{ | |||||
_logger = logger; | |||||
} | |||||
/// <summary> | |||||
/// | |||||
/// </summary> | |||||
/// <param name="sn"></param> | |||||
/// <param name="bizCode"> | |||||
/// 业务码 | |||||
/// 0067 胎心启动配置 | |||||
/// </param> | |||||
/// <returns></returns> | |||||
public async Task<JObject?> 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; | |||||
} | |||||
} | |||||
} |
@@ -42,7 +42,7 @@ namespace HealthMonitor.Service.Resolver | |||||
private readonly HttpHelper _httpHelper = default!; | private readonly HttpHelper _httpHelper = default!; | ||||
private readonly GpsCardAccessorClient<GpsPerson> _gpsPersonApiClient; | private readonly GpsCardAccessorClient<GpsPerson> _gpsPersonApiClient; | ||||
private readonly IotWebApiService _serviceIotWebApi; | |||||
private readonly IotApiService _serviceIotWebApi; | |||||
private readonly AsyncLocal<string> _messageId = new(); | private readonly AsyncLocal<string> _messageId = new(); | ||||
private readonly AsyncLocal<HisGpsBloodPress> _msgData = new(); | private readonly AsyncLocal<HisGpsBloodPress> _msgData = new(); | ||||
@@ -54,7 +54,7 @@ namespace HealthMonitor.Service.Resolver | |||||
BloodPressReferenceValueCacheManager bpRefValCacheManager, | BloodPressReferenceValueCacheManager bpRefValCacheManager, | ||||
PersonCacheManager personCacheMgr, HttpHelper httpHelper, | PersonCacheManager personCacheMgr, HttpHelper httpHelper, | ||||
GpsCardAccessorClient<GpsPerson> gpsPersonApiClient, | GpsCardAccessorClient<GpsPerson> gpsPersonApiClient, | ||||
IotWebApiService iotWebApiService, | |||||
IotApiService iotWebApiService, | |||||
EtcdService serviceEtcd, | EtcdService serviceEtcd, | ||||
IOptions<BoodPressResolverConfig> optionBoodPressResolver, | IOptions<BoodPressResolverConfig> optionBoodPressResolver, | ||||
ILogger<BloodpressResolver> logger) | ILogger<BloodpressResolver> logger) | ||||
@@ -55,7 +55,6 @@ namespace HealthMonitor.Service.Resolver.Factory | |||||
MessageId = msg.MessageId, | MessageId = msg.MessageId, | ||||
Topic = msg.Topic, | Topic = msg.Topic, | ||||
DetailData = msg.Body, | DetailData = msg.Body, | ||||
}; | }; | ||||
} | } | ||||
} | } | ||||
@@ -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<PregnancyHeartRateResolver> _logger; | |||||
private readonly AsyncLocal<string> _messageId = new(); | |||||
private readonly AsyncLocal<HisGpsHeartRate> _msgData = new(); | |||||
private readonly HttpHelper _httpHelper = default!; | |||||
private readonly EtcdService _serviceEtcd; | |||||
public PregnancyHeartRateResolver(ILogger<PregnancyHeartRateResolver> logger, HttpHelper httpHelper, EtcdService serviceEtcd) | |||||
{ | |||||
_logger = logger; | |||||
_httpHelper = httpHelper; | |||||
_serviceEtcd = serviceEtcd; | |||||
} | |||||
public void SetResolveInfo(PackageMsgModel msg) | |||||
{ | |||||
var topicHmPregnancyHeartRate = JsonConvert.DeserializeObject<TopicHmPregnancyHeartRate>(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 | |||||
} | |||||
} | |||||
} |
@@ -15,15 +15,19 @@ namespace HealthMonitor.Service.Sub | |||||
{ | { | ||||
private readonly ILogger<MsgQueueManager> _logger; | private readonly ILogger<MsgQueueManager> _logger; | ||||
private readonly BloodpressResolver _resolverBloodpress; | private readonly BloodpressResolver _resolverBloodpress; | ||||
private readonly PregnancyHeartRateResolver _resolverPregnacyHeartRate; | |||||
//private const string BP = nameof(TopicHmBloodPress).ToLower(); | //private const string BP = nameof(TopicHmBloodPress).ToLower(); | ||||
public MsgQueueManager(ILogger<MsgQueueManager> logger, BloodpressResolver resolverBloodpress) | |||||
public MsgQueueManager(ILogger<MsgQueueManager> logger, | |||||
BloodpressResolver resolverBloodpress, | |||||
PregnancyHeartRateResolver pregnacyHeartRateResolver) | |||||
{ | { | ||||
_logger = logger; | _logger = logger; | ||||
_resolverBloodpress = resolverBloodpress; | _resolverBloodpress = resolverBloodpress; | ||||
_resolverPregnacyHeartRate = pregnacyHeartRateResolver; | |||||
} | } | ||||
//public IResolver? GetMsgResolver() | //public IResolver? GetMsgResolver() | ||||
@@ -55,6 +59,12 @@ namespace HealthMonitor.Service.Sub | |||||
_resolverBloodpress.SetResolveInfo(msg); | _resolverBloodpress.SetResolveInfo(msg); | ||||
return _resolverBloodpress; | return _resolverBloodpress; | ||||
} | } | ||||
if (msg.Topic.Equals(nameof(TopicHmPregnancyHeartRate).ToLower())) | |||||
{ | |||||
_resolverPregnacyHeartRate.SetResolveInfo(msg); | |||||
return _resolverPregnacyHeartRate; | |||||
} | |||||
return null; | return null; | ||||
@@ -20,6 +20,7 @@ using System.Threading.Tasks; | |||||
using TDengineDriver; | using TDengineDriver; | ||||
using TDengineTMQ; | using TDengineTMQ; | ||||
using TelpoDataService.Util.Entities.GpsLocationHistory; | using TelpoDataService.Util.Entities.GpsLocationHistory; | ||||
using static Microsoft.EntityFrameworkCore.DbLoggerCategory.Database; | |||||
namespace HealthMonitor.Service.Sub | namespace HealthMonitor.Service.Sub | ||||
{ | { | ||||
@@ -69,40 +70,80 @@ namespace HealthMonitor.Service.Sub | |||||
DoReceive(conn); | DoReceive(conn); | ||||
} | } | ||||
public void DoReceive(IntPtr Connection) | |||||
public void DoReceive(IntPtr connection) | |||||
{ | { | ||||
#region topichmbpstats 订阅 | |||||
#region topic 订阅 | |||||
// string topic = "topichmbpstats"; | // 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<JsonPropertyAttribute>()!; | |||||
// 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<JsonPropertyAttribute>()); | |||||
//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<JsonPropertyAttribute>()!; | |||||
if (attr != null) | |||||
var props = type.GetProperties(); | |||||
var attributeNames = props | |||||
.Select(prop => prop.GetCustomAttribute<JsonPropertyAttribute>()?.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 | #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 | var cfg = new ConsumerConfig | ||||
{ | { | ||||
GourpId = "group_1", | GourpId = "group_1", | ||||
@@ -112,12 +153,13 @@ namespace HealthMonitor.Service.Sub | |||||
TDConnectIp = _configTDengineService.Host, | TDConnectIp = _configTDengineService.Host, | ||||
}; | }; | ||||
// create consumer | // create consumer | ||||
var consumer = new ConsumerBuilder(cfg) | |||||
.Build(); | |||||
var consumer = new ConsumerBuilder(cfg).Build(); | |||||
var topics = new string[] { bloodPressTopic, pregnancyHeartRateTopic }; | |||||
// subscribe | // subscribe | ||||
consumer.Subscribe(topic); | |||||
consumer.Subscribe(topics); | |||||
while (!_tokenSource!.IsCancellationRequested) | while (!_tokenSource!.IsCancellationRequested) | ||||
{ | { | ||||
var consumeRes = consumer.Consume(300); | var consumeRes = consumer.Consume(300); | ||||
@@ -154,14 +196,11 @@ namespace HealthMonitor.Service.Sub | |||||
} | } | ||||
} | } | ||||
consumer.Commit(consumeRes); | 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. | // close consumer after use.Otherwise will lead memory leak. | ||||
consumer.Close(); | consumer.Close(); | ||||
TDengine.Close(Connection); | |||||
TDengine.Close(connection); | |||||
} | } | ||||
public void ParsePackage(ReceiveMessageModel model) | public void ParsePackage(ReceiveMessageModel model) | ||||
@@ -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!; | |||||
} | |||||
} |
@@ -46,7 +46,7 @@ namespace HealthMonitor.WebApi.Controllers.HealthMonitor | |||||
private readonly TDengineService _serviceTDengine; | private readonly TDengineService _serviceTDengine; | ||||
private readonly HttpHelper _httpHelper = default!; | private readonly HttpHelper _httpHelper = default!; | ||||
private readonly IotWebApiService _serviceIotWebApi; | |||||
private readonly IotApiService _serviceIotWebApi; | |||||
private readonly GpsCardAccessorClient<GpsDevice> _deviceApiClient; | private readonly GpsCardAccessorClient<GpsDevice> _deviceApiClient; | ||||
private readonly GpsCardAccessorClient<GpsPerson> _gpsPersonApiClient; | private readonly GpsCardAccessorClient<GpsPerson> _gpsPersonApiClient; | ||||
@@ -58,7 +58,7 @@ namespace HealthMonitor.WebApi.Controllers.HealthMonitor | |||||
GpsCardAccessorClient<GpsPerson> gpsPersonApiClient, | GpsCardAccessorClient<GpsPerson> gpsPersonApiClient, | ||||
GpsCardAccessorClient<GpsDevice> deviceApiClient, | GpsCardAccessorClient<GpsDevice> deviceApiClient, | ||||
ILogger<HmBloodPressConfigManualCalibrationController> logger, | ILogger<HmBloodPressConfigManualCalibrationController> logger, | ||||
IotWebApiService iotWebApiService | |||||
IotApiService iotWebApiService | |||||
) | ) | ||||
{ | { | ||||
@@ -97,7 +97,24 @@ namespace HealthMonitor.WebApi.Controllers.HealthMonitor | |||||
//await _serviceTDengine.InsertAsync<FetalHeartRateModel>("hm_fhr", test); | //await _serviceTDengine.InsertAsync<FetalHeartRateModel>("hm_fhr", test); | ||||
//var first = _serviceTDengine.GetFirst(); | //var first = _serviceTDengine.GetFirst(); | ||||
var first = await _serviceTDengine.GetBySerialNoAsync<FetalHeartRateModel>("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<PregnancyHeartRateModel>("hm_phr", test2); | |||||
var first = await _serviceTDengine.GetBySerialNoAsync<PregnancyHeartRateModel>("864144050568123"); | |||||
return Ok(first); | return Ok(first); | ||||
} | } | ||||
} | } | ||||
@@ -93,7 +93,7 @@ namespace HealthMonitor.WebApi | |||||
var serverVersion = ServerVersion.AutoDetect(mySqlCon); | var serverVersion = ServerVersion.AutoDetect(mySqlCon); | ||||
options.UseMySql(mySqlCon, serverVersion) | options.UseMySql(mySqlCon, serverVersion) | ||||
.UseLoggerFactory(loggerFactory); | .UseLoggerFactory(loggerFactory); | ||||
}, poolSize: 64); ; | |||||
}, poolSize: 64); | |||||
builder.Services | builder.Services | ||||
.AddScoped<IGpsCardDataAccessor, EfCoreDataAccessor>(sp => | .AddScoped<IGpsCardDataAccessor, EfCoreDataAccessor>(sp => | ||||
@@ -172,6 +172,7 @@ namespace HealthMonitor.WebApi | |||||
#region Cache | #region Cache | ||||
builder.Services | builder.Services | ||||
.AddSingleton<PersonCacheManager>() | .AddSingleton<PersonCacheManager>() | ||||
.AddSingleton<DeviceCacheManager>() | |||||
.AddSingleton<BloodPressReferenceValueCacheManager>(); | .AddSingleton<BloodPressReferenceValueCacheManager>(); | ||||
#endregion | #endregion | ||||
@@ -189,11 +190,12 @@ namespace HealthMonitor.WebApi | |||||
builder.Services.AddSingleton<MsgQueueManager>(); | builder.Services.AddSingleton<MsgQueueManager>(); | ||||
builder.Services.AddSingleton<IResolverFactory, ResolverFactory>(); | builder.Services.AddSingleton<IResolverFactory, ResolverFactory>(); | ||||
builder.Services.AddSingleton<BloodpressResolver>(); | builder.Services.AddSingleton<BloodpressResolver>(); | ||||
builder.Services.AddSingleton<PregnancyHeartRateResolver>(); | |||||
builder.Services.AddSingleton<PackageProcess>(); | builder.Services.AddSingleton<PackageProcess>(); | ||||
builder.Services | builder.Services | ||||
.AddSingleton<TDengineDataSubcribe>() | .AddSingleton<TDengineDataSubcribe>() | ||||
.AddSingleton<IotWebApiService>() | |||||
.AddSingleton<IotApiService>() | |||||
.AddSingleton<EtcdService>() | .AddSingleton<EtcdService>() | ||||
.AddHostedService<Worker>(); | .AddHostedService<Worker>(); | ||||
#endregion | #endregion | ||||
@@ -33,19 +33,19 @@ namespace HealthMonitor.WebApi | |||||
private readonly TDengineService _serviceTDengine; | private readonly TDengineService _serviceTDengine; | ||||
private readonly EtcdService _serviceEtcd; | private readonly EtcdService _serviceEtcd; | ||||
private readonly HttpHelper _httpHelper = default!; | private readonly HttpHelper _httpHelper = default!; | ||||
private readonly IotWebApiService _serviceIotWebApi; | |||||
private readonly IotApiService _serviceIotApi; | |||||
private readonly BoodPressResolverConfig _configBoodPressResolver; | private readonly BoodPressResolverConfig _configBoodPressResolver; | ||||
private readonly BloodPressReferenceValueCacheManager _bpRefValCacheManager; | private readonly BloodPressReferenceValueCacheManager _bpRefValCacheManager; | ||||
private readonly PersonCacheManager _personCacheMgr; | private readonly PersonCacheManager _personCacheMgr; | ||||
private CancellationTokenSource _tokenSource = default!; | private CancellationTokenSource _tokenSource = default!; | ||||
public Worker(ILogger<Worker> logger, IServiceProvider services, PersonCacheManager personCacheMgr, BloodPressReferenceValueCacheManager bpRefValCacheManager, IotWebApiService iotWebApiService, IOptions<BoodPressResolverConfig> optionBoodPressResolver, PackageProcess processor, TDengineDataSubcribe tdEngineDataSubcribe, TDengineService serviceDengine, HttpHelper httpHelper, EtcdService serviceEtcd) | |||||
public Worker(ILogger<Worker> logger, IServiceProvider services, PersonCacheManager personCacheMgr, BloodPressReferenceValueCacheManager bpRefValCacheManager, IotApiService IotApiService, IOptions<BoodPressResolverConfig> optionBoodPressResolver, PackageProcess processor, TDengineDataSubcribe tdEngineDataSubcribe, TDengineService serviceDengine, HttpHelper httpHelper, EtcdService serviceEtcd) | |||||
{ | { | ||||
_logger = logger; | _logger = logger; | ||||
_tdEngineDataSubcribe = tdEngineDataSubcribe; | _tdEngineDataSubcribe = tdEngineDataSubcribe; | ||||
_services = services; | _services = services; | ||||
_serviceIotWebApi = iotWebApiService; | |||||
_serviceIotApi = IotApiService; | |||||
_processor = processor; | _processor = processor; | ||||
_serviceEtcd = serviceEtcd; | _serviceEtcd = serviceEtcd; | ||||
_serviceTDengine = serviceDengine; | _serviceTDengine = serviceDengine; | ||||
@@ -116,283 +116,382 @@ namespace HealthMonitor.WebApi | |||||
case "Delete": | case "Delete": | ||||
// TTL到了重新计算TTL,下发 | // 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 = $"health_moniter/schedule_push/imei/{bp.Serialno}"; | ||||
var key = e.Kv.Key.ToStringUtf8(); | 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); | var schedule_push = await _serviceEtcd.GetValAsync(key).ConfigureAwait(false); | ||||
if (string.IsNullOrWhiteSpace(schedule_push)) | 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<PregnancyCommonHeartRateModel>("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<ParseTDengineRestResponse<BloodPressureModel>>(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<ParseTDengineRestResponse<BloodPressureModel>>(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<ParseTDengineRestResponse<BloodPressurePushRefIncModel>>(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; | break; | ||||
} | } | ||||
// 验证年龄是否在范围 (2 - 120) | |||||
var age = SafeType.SafeInt(DateTime.Today.Year - person?.Person.BornDate!.Value.Year!); | |||||
if (age < 2 || age > 120) | |||||
var lastPushParser = JsonConvert.DeserializeObject<ParseTDengineRestResponse<BloodPressurePushRefIncModel>>(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<ParseTDengineRestResponse<BloodPressureModel>>(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<ParseTDengineRestResponse<BloodPressureModel>>(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 | #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 | #else | ||||
@@ -424,24 +523,24 @@ namespace HealthMonitor.WebApi | |||||
var result = JsonConvert.SerializeObject(data); | var result = JsonConvert.SerializeObject(data); | ||||
await _serviceEtcd.PutValAsync(key, result, ttl, false).ConfigureAwait(false); | await _serviceEtcd.PutValAsync(key, result, ttl, false).ConfigureAwait(false); | ||||
#endif | #endif | ||||
#endregion | |||||
#endregion | |||||
} | |||||
else | |||||
{ | |||||
_logger.LogInformation($"错误响应,没有下推数据:{response.Message}"); | |||||
} | |||||
else | |||||
{ | |||||
_logger.LogInformation($"错误响应,没有下推数据:{response.Message}"); | |||||
} | |||||
} | } | ||||
} | } | ||||
} | |||||
else | |||||
{ | |||||
_logger.LogInformation($"向{imeiDel}统计数据已经失效"); | |||||
} | |||||
#endregion | |||||
else | |||||
{ | |||||
_logger.LogInformation($"向{imeiDel}统计数据已经失效"); | |||||
} | |||||
#endregion | |||||
} | |||||
} | } | ||||
break; | 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; | |||||
} | |||||
} | |||||
} | |||||
*/ | |||||
} | } | ||||
@@ -27,7 +27,9 @@ | |||||
"ServiceConfig": { | "ServiceConfig": { | ||||
"TelpoDataUrl": "https://id.gdssjl.com/data/", | "TelpoDataUrl": "https://id.gdssjl.com/data/", | ||||
"EtcdServerAddress": "http://192.168.2.121:2379", | "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": { | "BoodPressResolverConfig": { | ||||
"EnableBPRefPush": true | "EnableBPRefPush": true | ||||
@@ -24,7 +24,9 @@ | |||||
"ServiceConfig": { | "ServiceConfig": { | ||||
"TelpoDataUrl": "https://ai.gdssjl.com/data/", | "TelpoDataUrl": "https://ai.gdssjl.com/data/", | ||||
"EtcdServerAddress": "http://172.19.42.40:2379", | "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": { | "BoodPressResolverConfig": { | ||||
"EnableBPRefPush": true | "EnableBPRefPush": true | ||||
@@ -32,7 +32,9 @@ | |||||
"ServiceConfig": { | "ServiceConfig": { | ||||
"TelpoDataUrl": "https://id.gdssjl.com/data/", | "TelpoDataUrl": "https://id.gdssjl.com/data/", | ||||
"EtcdServerAddress": "http://172.19.42.44:2379", | "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": { | "BoodPressResolverConfig": { | ||||
"EnableBPRefPush": true | "EnableBPRefPush": true | ||||