From 5bee6f681f4df86e6461dfbba34eb058e83441fe Mon Sep 17 00:00:00 2001 From: H Vs Date: Mon, 20 Nov 2023 16:47:08 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=89=8B=E5=8A=A8=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E8=A1=80=E5=8E=8B=E5=A2=9E=E9=87=8F=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HealthMonitor.Model/Config/ServiceConfig.cs | 2 + .../BloodPressCalibrationConfigModel.cs | 26 ++ HealthMonitor.Service/Biz/IotWebApiService.cs | 170 ++++++++ .../Controllers/Api/ApiResponse.cs | 74 ++++ ...dPressConfigManualCalibrationController.cs | 388 ++++++++++++------ HealthMonitor.WebApi/Program.cs | 2 + .../appsettings.Development.json | 3 +- .../appsettings.production.json | 4 +- HealthMonitor.WebApi/appsettings.test.json | 3 +- 9 files changed, 537 insertions(+), 135 deletions(-) create mode 100644 HealthMonitor.Model/Service/BloodPressCalibrationConfigModel.cs create mode 100644 HealthMonitor.Service/Biz/IotWebApiService.cs create mode 100644 HealthMonitor.WebApi/Controllers/Api/ApiResponse.cs diff --git a/HealthMonitor.Model/Config/ServiceConfig.cs b/HealthMonitor.Model/Config/ServiceConfig.cs index a815163..0febe59 100644 --- a/HealthMonitor.Model/Config/ServiceConfig.cs +++ b/HealthMonitor.Model/Config/ServiceConfig.cs @@ -8,6 +8,8 @@ public string TelpoDataUrl { get; set; } = default!; public string EtcdServerAddress { get; set; } = default!; + + public string IotWebApiUrl { get; set; } = default!; ///// ///// Kafka服务地址 ///// diff --git a/HealthMonitor.Model/Service/BloodPressCalibrationConfigModel.cs b/HealthMonitor.Model/Service/BloodPressCalibrationConfigModel.cs new file mode 100644 index 0000000..4ddac1b --- /dev/null +++ b/HealthMonitor.Model/Service/BloodPressCalibrationConfigModel.cs @@ -0,0 +1,26 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HealthMonitor.Model.Service +{ + public class BloodPressCalibrationConfigModel + { + [JsonProperty("imei")] + public string Imei { get; set; } = default!; + [JsonProperty("systolicCalibrationValue")] + public int SystolicRefValue { get; set; } + + [JsonProperty("diastolicCalibrationValue")] + public int DiastolicRefValue { get; set; } + + [JsonProperty("systolicIncValue")] + public int SystolicIncValue { get; set; } + + [JsonProperty("diastolicIncValue")] + public int DiastolicIncValue { get; set; } + } +} diff --git a/HealthMonitor.Service/Biz/IotWebApiService.cs b/HealthMonitor.Service/Biz/IotWebApiService.cs new file mode 100644 index 0000000..bb19bb6 --- /dev/null +++ b/HealthMonitor.Service/Biz/IotWebApiService.cs @@ -0,0 +1,170 @@ +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; + +namespace HealthMonitor.Service.Biz +{ + public class IotWebApiService + { + private readonly ServiceConfig _configService; + private readonly ILogger _logger; + + + private readonly HttpHelper _httpHelper = default!; + + private readonly GpsCardAccessorClient _gpsPersonApiClient; + + public IotWebApiService(ILogger logger, HttpHelper httpHelper, GpsCardAccessorClient gpsPersonApiClient, IOptions optConfigService) + { + _configService = optConfigService.Value; + _httpHelper=httpHelper; + _logger = logger; + _gpsPersonApiClient = gpsPersonApiClient; + } + + public async Task SetBloodPressCalibrationConfigAsync(BloodPressCalibrationConfigModel bpsCalibrationConfig) + { + +#if DEBUG + var flag = true; +#else + //systolicCalibrationValue = 0, //收缩压标定值,值为0 表示不生效 + //diastolicCalibrationValue 0, //舒张压标定值,值为0表示不生效 + //systolicIncValue = 0, //收缩压显示增量,值为0 表示不生效 + //diastolicIncValue = 0 //舒张压显示增量,值为0 表示不生效 + + var flag = false; + try + { + var url = $"{_configService.IotWebApiUrl}Command/SetBloodPressCalibrationConfig"; + List> headers = new() + { + new KeyValuePair("AuthKey", "key1") + }; + var res = await _httpHelper.HttpToPostAsync(url, bpsCalibrationConfig, headers).ConfigureAwait(false); + _logger.LogInformation($"向{bpsCalibrationConfig.Imei}下发增量值数据:{JsonConvert.SerializeObject(bpsCalibrationConfig)},响应:{res}"); + var resJToken = JsonConvert.DeserializeObject(res ?? string.Empty) as JToken; + flag= resJToken?["message"]?.ToString().Equals("ok") ?? false; + + } + catch (Exception ex) + { + _logger.LogError($"{nameof(SetBloodPressCalibrationConfigAsync)} 下发血压增量值异常:{ex.Message}, {ex.StackTrace}"); + + } + + +#endif + + return flag; + + + } + + public async Task UpdatePersonInfoCacheAsync(string imei) + { + var flag = false; + try + { + var url = $"{_configService.IotWebApiUrl}Device/UpdatePersonInfoCache?imei={imei}"; + List> headers = new() + { + new KeyValuePair("AuthKey", "key1") + }; + var res = await _httpHelper.HttpToGetAsync(url, headers).ConfigureAwait(false); + _logger.LogInformation($"{imei} 更新缓存{nameof(UpdatePersonInfoCacheAsync)},响应:{res}"); + var resJToken = JsonConvert.DeserializeObject(res ?? string.Empty) as JToken; + flag = resJToken?["message"]?.ToString().Equals("ok") ?? false; + } + catch (Exception ex) + { + _logger.LogError($"{nameof(UpdatePersonInfoCacheAsync)} 更新缓存异常:{ex.Message}, {ex.StackTrace}"); + + } + return flag; + + + } + + /// + /// 更新 gps_person remark和缓存 + /// + /// + /// + /// + /// + public async Task UpdatePersonRemarksAsync(string imei,int systolicRefValue,int diastolicRefValue) + { + var flag = false; + try + { + GeneralParam condition = new () + { + Filters = new List { + new QueryFilterCondition { + Key=nameof(GpsDevice.Serialno), + Value=imei, + Operator= QueryOperatorEnum.Equal, + ValueType=QueryValueTypeEnum.String + } + }, + OrderBys = new List { new OrderByCondition { Key = "serialno", IsDesc = true } } + + }; + var person = await _gpsPersonApiClient.GetFirstAsync(condition, new RequestHeader() { RequestId = $"{imei}" }).ConfigureAwait(false); + // 若remark为空,更新person remark字段 + if (string.IsNullOrWhiteSpace(person?.Remarks)) + { + var newRemarkData = new + { + imei, + time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), + commandValue = new + { + systolicCalibrationValue = systolicRefValue, //收缩压标定值,值为0 表示不生效 + diastolicCalibrationValue = diastolicRefValue, //舒张压标定值,值为0表示不生效 + systolicIncValue = 0, //收缩压显示增量,值为0 表示不生效 + diastolicIncValue = 0 //舒张压显示增量,值为0 表示不生效 + } + }; + person!.Remarks = $"is_blood_press:{JsonConvert.SerializeObject(newRemarkData)}|"; + await _gpsPersonApiClient.UpdateAsync(person, new RequestHeader() { RequestId = $"{imei}" }).ConfigureAwait(false); + _logger.LogInformation($"更新Person remarks字段|{person.Remarks}"); + + // 更新缓存 + var url = $"{_configService.IotWebApiUrl}Device/UpdatePersonInfoCache?imei={imei}"; + List> headers = new() + { + new KeyValuePair("AuthKey", "key1") + }; + var res = await _httpHelper.HttpToGetAsync(url, headers).ConfigureAwait(false); + _logger.LogInformation($"{imei} 更新缓存{nameof(UpdatePersonInfoCacheAsync)},响应:{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; + + + } + } +} diff --git a/HealthMonitor.WebApi/Controllers/Api/ApiResponse.cs b/HealthMonitor.WebApi/Controllers/Api/ApiResponse.cs new file mode 100644 index 0000000..ba477b4 --- /dev/null +++ b/HealthMonitor.WebApi/Controllers/Api/ApiResponse.cs @@ -0,0 +1,74 @@ +using Newtonsoft.Json.Serialization; +using Newtonsoft.Json; + +namespace HealthMonitor.WebApi.Controllers.Api +{ + public class ApiResponse + { + public string Timestamp { get; set; } = default!; + + public T Data { get; set; } = default!; + + public Result Result { get; set; } = default!; + + //public bool Succeeded { get; set; } + // public string Message { get; set; } = String.Empty; + + + public static ApiResponse Fail(int code, string errorMessage) => new() + { + //MsgType = msgType, + //Signature = signature, + Timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + Result = new() + { + Status = "failed", + Code = code, + Message = errorMessage, + }, + + }; + + //public static ApiResponse Success(string msgType,string signature,T data) => new() + //{ + // MsgType= msgType, + // Signature = signature, + // Timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + // Data = data, + // Result = new() + // { + // Status = "succeed", + // Code = 200, + // Message = "请求成功!", + // }, + //}; + public static ApiResponse Success(T data) => new() + { + Timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), + Data = data, + Result = new() + { + Status = "succeed", + Code = 200, + Message = "请求成功!", + }, + }; + public string ToJsonString() + { + var settings = new JsonSerializerSettings + { + DateFormatString = "yyyy-MM-dd HH:mm:ss.fff", // 设置日期格式 + ContractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy() } + }; + return JsonConvert.SerializeObject(this, settings); + } + } + + + public class Result + { + public string Status { get; set; } = default!; + public int Code { get; set; } + public string Message { get; set; } = default!; + } +} diff --git a/HealthMonitor.WebApi/Controllers/HealthMonitor/HmBloodPressConfigManualCalibrationController.cs b/HealthMonitor.WebApi/Controllers/HealthMonitor/HmBloodPressConfigManualCalibrationController.cs index d7bc380..71bf9f9 100644 --- a/HealthMonitor.WebApi/Controllers/HealthMonitor/HmBloodPressConfigManualCalibrationController.cs +++ b/HealthMonitor.WebApi/Controllers/HealthMonitor/HmBloodPressConfigManualCalibrationController.cs @@ -19,9 +19,17 @@ using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Metadata.Internal; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using TelpoDataService.Util.Entities.GpsCard; +using TelpoDataService.Util.Clients; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using TelpoDataService.Util; +using TelpoDataService.Util.Models; +using TelpoDataService.Util.QueryObjects; +using HealthMonitor.WebApi.Controllers.Api; +using HealthMonitor.Service.Biz; +using HealthMonitor.Model.Service; namespace HealthMonitor.WebApi.Controllers.HealthMonitor { @@ -36,113 +44,275 @@ namespace HealthMonitor.WebApi.Controllers.HealthMonitor private readonly TDengineService _serviceTDengine; private readonly HttpHelper _httpHelper = default!; + private readonly IotWebApiService _serviceIotWebApi; + + private readonly GpsCardAccessorClient _deviceApiClient; + private readonly GpsCardAccessorClient _gpsPersonApiClient; + public HmBloodPressConfigManualCalibrationController ( TDengineService serviceDengine, PersonCacheManager personCacheMgr, HttpHelper httpHelper, - - ILogger logger + GpsCardAccessorClient gpsPersonApiClient, + GpsCardAccessorClient deviceApiClient, + ILogger logger, + IotWebApiService iotWebApiService ) { - + + _serviceTDengine = serviceDengine; _logger = logger; + _httpHelper = httpHelper; + _gpsPersonApiClient = gpsPersonApiClient; + _deviceApiClient = deviceApiClient; _personCacheMgr = personCacheMgr; + _serviceIotWebApi = iotWebApiService; } [HttpPost] - public async Task Put([FromBody] BloodPressManualCalibration model, [FromHeader] string requestId) + public async Task> Put([FromBody] BloodPressManualCalibration model, [FromHeader] string requestId) { - /** - 没有血压数据时增量值为0 - */ + #region 设备合法性 +#if DEBUG +#else + var param = new GeneralParam + { + Filters = new List + { + new QueryFilterCondition + { + Key=nameof(GpsDevice.Serialno), + Value=model.Imei, + ValueType=QueryValueTypeEnum.String, + Operator=QueryOperatorEnum.Equal + } + } + }; - // 保存新的标定值 - // 使用新的标定值计算新的增量值 + var device = await _deviceApiClient.GetFirstAsync(param, new RequestHeader { RequestId = requestId }).ConfigureAwait(false); + if (device == null) + { + _logger.LogError($"非法设备:{model.Imei}"); + return ApiResponse.Fail(500, $"非法设备:{model.Imei}"); + } +#endif + +#endregion + + #region 重置设备 + if (model.ManualSystolicRefValue.Equals(0) && model.ManualDiastolicRefValue.Equals(0)) + { + return await IotSetBloodPressCalibrationConfigResponseAsync(model.Imei, 0, 0, 0, 0).ConfigureAwait(false); + + //return ApiResponse.Success(new + //{ + // imei = model.Imei, + // systolicCalibrationValue = 0, //收缩压标定值,值为0 表示不生效 + // diastolicCalibrationValue = 0, //舒张压标定值,值为0表示不生效 + // systolicIncValue = 0, //收缩压显示增量,值为0 表示不生效 + // diastolicIncValue = 0 //舒张压显示增量,值为0 表示不生效 + //}); + } + + #endregion + + #region 数据合法性 + if (model.ManualSystolicRefValue.Equals(0) || model.ManualDiastolicRefValue.Equals(0)) + { + return ApiResponse.Fail(501, $"数据非法,{JsonConvert.SerializeObject(model)}"); + } + #endregion + + #region 计算增量值 var imei = model.Imei; // 计算增量值 - var systolicRefValue = model.ManualSystolicRefValue;//? - var diastolicRefValue = model.ManualDiastolicRefValue;//? - // 没有血压数据时增量值为0 - var systolicInc = 0; - var diastolicInc = 0; + int systolicRefValue = model.ManualSystolicRefValue;//? + int diastolicRefValue = model.ManualDiastolicRefValue;//? + // 没有血压数据时增量值为0 + int systolicInc; + int diastolicInc; + int systolicAvg; + int diastolicAvg; //int duration = 7; long duration = 7 * 24 * 3600 * 1000; TimeSpan ts = TimeSpan.FromMilliseconds(duration); DateTime endTime = DateTime.Now; //测试 DateTime startTime = endTime - ts; + var lastPush = await _serviceTDengine.GetLastAsync("stb_hm_bp_push_ref_inc_value", $"serialno='{imei}' order by ts desc"); + + // A.没有下推记录 + if (lastPush?.Count == 0 || lastPush == null) + { + #region 初始化remarks + // 读数据库,remarks为空就写commandValue,更新缓存 + var resFlag = await _serviceIotWebApi.UpdatePersonRemarksAsync(imei, systolicRefValue, diastolicRefValue).ConfigureAwait(false); + if (resFlag) + { + _logger.LogInformation($"更新gps_person remarks和缓存"); + } + else + { + _logger.LogInformation($"更新gps_person remarks和缓存失败"); + } + #endregion + + int count = await _serviceTDengine.GetCount("stb_hm_bloodpress", $"serialno='{imei}' "); + // A.1 没有下推记录,没有测量记录,下推增量值 0 + if (count.Equals(0)) + { + _logger.LogInformation("A.1 没有下推记录,没有测量记录,下推增量值 0"); + return await IotSetBloodPressCalibrationConfigResponseAsync(model.Imei, systolicRefValue, diastolicRefValue, 0, 0).ConfigureAwait(false); + } + // A.2 没有下推记录,测量记录,正常计算增量值 + else + { + // 平均值: 计算去除最大值 MAX和最小值 MIN 和异常值 ABN 的平均值 + systolicAvg = await _serviceTDengine.GetAvgExceptMaxMinValueAsync("systolic_value", "stb_hm_bloodpress", $"ts>='{startTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and ts <='{endTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and serialno='{imei}' and systolic_value < {systolicRefValue} "); + diastolicAvg = await _serviceTDengine.GetAvgExceptMaxMinValueAsync("diastolic_value", "stb_hm_bloodpress", $"ts>='{startTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and ts <='{endTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and serialno='{imei}' and diastolic_value < {diastolicRefValue}"); + // 数据异常,不修改增量值 + if (systolicAvg.Equals(0) || diastolicAvg.Equals(0)) + { + _logger.LogInformation(" A.2 没有下推记录,有测量记录,正常计算增量值 ,平均值为0, 增量值将按0下发"); + return await IotSetBloodPressCalibrationConfigResponseAsync(model.Imei, systolicRefValue, diastolicRefValue, 0, 0).ConfigureAwait(false); + } + // 数据正常 + else + { + // 偏移参数 + var avgOffset = 0.25M; + var systolicAvgOffset = avgOffset; + var diastolicAvgOffset = avgOffset; - var last = await _serviceTDengine.GetLastAsync("stb_hm_bp_push_ref_inc_value", $"serialno='{imei}' order by ts desc"); - if (last?.Count != 0) - { - if (DateTime.TryParse(last?[0]!.ToString(), out DateTime newTs)) - { - startTime = newTs; + + // 增量值=(标定值-平均值)* 0.25 + systolicInc = systolicAvg.Equals(0M) ? 0 : (int)((systolicRefValue - systolicAvg) * systolicAvgOffset)!; + diastolicInc = diastolicAvg.Equals(0M) ? 0 : (int)((diastolicRefValue - diastolicAvg) * diastolicAvgOffset)!; + _logger.LogInformation(" A.2 没有下推记录,有测量记录,正常计算增量值 ,增量值将正常下发"); + return await IotSetBloodPressCalibrationConfigResponseAsync(imei, systolicRefValue, diastolicRefValue, systolicInc, diastolicInc).ConfigureAwait(false); + } } } - // 读数据库,remark为空就写commandValue,更新缓存 + // B.有下推记录(更改过个人信息) else { - #region 初始化remark - var dataServiceBaseUrl = $"https://id.ssjlai.com/data"; - var DataServicePersionGet = $"{dataServiceBaseUrl}/api/GpsCard/GpsPerson/GetFirst"; - List> Dataheaders = new() - { - new KeyValuePair("requestId", $"{imei}") - }; - var dataPersion = new + // B.1. 设备已经被重新设置 + if ( + (int)lastPush![2] == 0 + && (int)lastPush![3] == 0 + && (int)lastPush![4] == 0 + && (int)lastPush![5] == 0 + ) { - filters = new List() { new { key = "serialno", value = $"{imei}", valueType = "string", @operator = "Equal" } }, - orderBys = new List() { new { key = "serialno", isDesc = true } } - }; - var resPersion = await _httpHelper.HttpToPostAsync(DataServicePersionGet, dataPersion, Dataheaders).ConfigureAwait(false); - var resObj = JsonConvert.DeserializeObject(resPersion!) as JToken; - var remark = resObj?["remarks"]?.ToString(); - - // 修改数据库 - if (string.IsNullOrWhiteSpace(remark)) - { - var newRemarkData = new + + // 转换时间 + _ = DateTime.TryParse(lastPush?[0]!.ToString(), out DateTime newTs); + endTime = DateTime.Now;//newTs; + startTime = newTs;//DateTime.Now; + + int count = await _serviceTDengine.GetCount("stb_hm_bloodpress", $"ts>='{startTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and ts <='{endTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and serialno='{imei}' "); + // B.1.1 设备已经被重新设置, 从重置的ts 到 now 没有测量数据,inc=0 + if (count.Equals(0)) { - imei, - time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), - commandValue = new + _logger.LogWarning("B.1.1 设备已经被重新设置, 从重置的ts 到 now 没有测量数据,inc=0"); + return await IotSetBloodPressCalibrationConfigResponseAsync(model.Imei, systolicRefValue, diastolicRefValue, 0, 0).ConfigureAwait(false); + } + // B.1.2 设备已经被重新设置, 从重置的ts 到 now 有测量数据 + else + { + // 平均值: 计算去除最大值 MAX和最小值 MIN 和异常值 ABN 的平均值 + systolicAvg = await _serviceTDengine.GetAvgExceptMaxMinValueAsync("systolic_value", "stb_hm_bloodpress", $"ts>='{startTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and ts <='{endTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and serialno='{imei}' and systolic_value < {systolicRefValue} "); + diastolicAvg = await _serviceTDengine.GetAvgExceptMaxMinValueAsync("diastolic_value", "stb_hm_bloodpress", $"ts>='{startTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and ts <='{endTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and serialno='{imei}' and diastolic_value < {diastolicRefValue}"); + + // 数据异常,不修改增量值 + if (systolicAvg.Equals(0) || diastolicAvg.Equals(0)) { - systolicCalibrationValue = systolicRefValue, //收缩压标定值,值为0 表示不生效 - diastolicCalibrationValue = diastolicRefValue, //舒张压标定值,值为0表示不生效 - systolicIncValue = 0, //收缩压显示增量,值为0 表示不生效 - diastolicIncValue = 0 //舒张压显示增量,值为0 表示不生效 + _logger.LogWarning("B.1.2 设备已经被重新设置, 从重置的ts 到 now 有测量数据,平均值为0,增量值将按0下发"); + return await IotSetBloodPressCalibrationConfigResponseAsync(model.Imei, systolicRefValue, diastolicRefValue, 0, 0).ConfigureAwait(false); + } - }; - resObj!["remarks"] = $"is_blood_press:{JsonConvert.SerializeObject(newRemarkData)}|"; - var DataServicePersionUpdate = $"{dataServiceBaseUrl}/api/GpsCard/GpsPerson/Update"; - var resUpdate = await _httpHelper.HttpToPostAsync(DataServicePersionUpdate, resObj, Dataheaders).ConfigureAwait(false); - _logger.LogInformation($"更新Person数据库|{resUpdate}"); - - //更新缓存 - List> headersCache = new() + // 数据正常 + else + { + // 偏移参数 + var avgOffset = 0.25M; + var systolicAvgOffset = avgOffset; + var diastolicAvgOffset = avgOffset; + // 增量值=(标定值-平均值)* 0.25 + systolicInc = systolicAvg.Equals(0M) ? 0 : (int)((systolicRefValue - systolicAvg) * systolicAvgOffset)!; + diastolicInc = diastolicAvg.Equals(0M) ? 0 : (int)((diastolicRefValue - diastolicAvg) * diastolicAvgOffset)!; + _logger.LogInformation("B.1.2 设备已经被重新设置, 从重置的ts 到 now 有测量数据 ,增量值将正常下发"); + return await IotSetBloodPressCalibrationConfigResponseAsync(imei, systolicRefValue, diastolicRefValue, systolicInc, diastolicInc).ConfigureAwait(false); + } + + } + + } + // B.2. 曾经下推过断言有测量记录 + else + { + // 转换时间 + _ = DateTime.TryParse(lastPush?[0]!.ToString(), out DateTime newTs); + endTime = DateTime.Now; + startTime = newTs; + + // 平均值: 计算去除最大值 MAX和最小值 MIN 和异常值 ABN 的平均值 + systolicAvg = await _serviceTDengine.GetAvgExceptMaxMinValueAsync("systolic_value", "stb_hm_bloodpress", $"ts>='{startTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and ts <='{endTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and serialno='{imei}' and systolic_value < {systolicRefValue} "); + diastolicAvg = await _serviceTDengine.GetAvgExceptMaxMinValueAsync("diastolic_value", "stb_hm_bloodpress", $"ts>='{startTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and ts <='{endTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and serialno='{imei}' and diastolic_value < {diastolicRefValue}"); + + // B.2.1 数据异常,将按最后一次测量值的offeset下发 + if (systolicAvg.Equals(0) || diastolicAvg.Equals(0)) + { + _logger.LogInformation("B.2.1 曾经下推过断言有测量记录,数据异常,平均值为0,增量值将按0下发"); + return await IotSetBloodPressCalibrationConfigResponseAsync(model.Imei, systolicRefValue, diastolicRefValue, 0, 0).ConfigureAwait(false); + + } + // B.2.2 数据正常,按正常计算 + else { - new KeyValuePair("AuthKey", "key1") - }; + // 偏移参数 + var avgOffset = 0.25M; + var systolicAvgOffset = avgOffset; + var diastolicAvgOffset = avgOffset; - var cacheUrl = $"http://id.ssjlai.com/webapi/api/Device/UpdatePersonInfoCache?imei={imei}"; - var updateCache = await _httpHelper.HttpToGetAsync(cacheUrl, headersCache); - _logger.LogInformation($"更新Person缓存|{updateCache}"); + + // 增量值=(标定值-平均值)* 0.25 + systolicInc = systolicAvg.Equals(0M) ? 0 : (int)((systolicRefValue - systolicAvg) * systolicAvgOffset)!; + diastolicInc = diastolicAvg.Equals(0M) ? 0 : (int)((diastolicRefValue - diastolicAvg) * diastolicAvgOffset)!; + _logger.LogInformation("B.2.2 曾经下推过断言有测量记录,数据正常,按正常计算 ,增量值将正常下发"); + return await IotSetBloodPressCalibrationConfigResponseAsync(imei, systolicRefValue, diastolicRefValue, systolicInc, diastolicInc).ConfigureAwait(false); + } } + } - #endregion + /**if (lastPush?.Count == 0) + { + #region 初始化remarks + var resFlag = await _serviceIotWebApi.UpdatePersonRemarksAsync(imei, systolicRefValue, diastolicRefValue).ConfigureAwait(false); + if (resFlag) + { + _logger.LogInformation($"更新gps_person remarks和缓存"); + } + #endregion + } + else + { + if (DateTime.TryParse(lastPush?[0]!.ToString(), out DateTime newTs)) + { + startTime = newTs; + } } @@ -150,7 +320,7 @@ namespace HealthMonitor.WebApi.Controllers.HealthMonitor //var total = await _serviceTDengine.GetCount("stb_hm_bloodpress", $"serialno='{imei}' order by ts desc"); //if (total >= 4) - if(lastBP?.Count !=0 ) + if (lastBP?.Count != 0) { //var systolicAggregate = await _serviceTDengine.GetAggregateValueAsync("systolic_value", "stb_hm_bloodpress", $"ts>='{startTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and ts <='{endTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and serialno='{imei}'"); //var diastolicAggregate = await _serviceTDengine.GetAggregateValueAsync("diastolic_value", "stb_hm_bloodpress", $"ts>='{startTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and ts <='{endTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and serialno='{imei}'"); @@ -165,17 +335,18 @@ namespace HealthMonitor.WebApi.Controllers.HealthMonitor //var diastolicMin = diastolicAggregate.Min; - // 计算去除最大值和最小值和异常值的平均值 + // 平均值: 计算去除最大值 MAX和最小值 MIN 和异常值 ABN 的平均值 var systolicAvg = await _serviceTDengine.GetAvgExceptMaxMinValueAsync("systolic_value", "stb_hm_bloodpress", $"ts>='{startTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and ts <='{endTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and serialno='{imei}' and systolic_value < {systolicRefValue} "); var diastolicAvg = await _serviceTDengine.GetAvgExceptMaxMinValueAsync("diastolic_value", "stb_hm_bloodpress", $"ts>='{startTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and ts <='{endTime:yyyy-MM-ddTHH:mm:ss.fffZ}' and serialno='{imei}' and diastolic_value < {diastolicRefValue}"); if (systolicAvg.Equals(0) || diastolicAvg.Equals(0)) { - _logger.LogWarning("平均值为0不保存"); + _logger.LogWarning("平均值为0,下发增量值按0处理"); + //return ApiResponse.Fail(501, "平均值为0不处理"); + return await IotSetBloodPressCalibrationConfigResponseAsync(imei, systolicRefValue, diastolicRefValue, 0, 0).ConfigureAwait(false); } // 偏移参数 var avgOffset = 0.25M; - var systolicAvgOffset = avgOffset; var diastolicAvgOffset = avgOffset; @@ -185,37 +356,26 @@ namespace HealthMonitor.WebApi.Controllers.HealthMonitor diastolicInc = diastolicAvg.Equals(0M) ? 0 : (int)((diastolicRefValue - diastolicAvg) * diastolicAvgOffset)!; } - - var bpData = new - { - imei = imei, - //systolicCalibrationValue = last?[5], //收缩压标定值,值为0 表示不生效 - //diastolicCalibrationValue = last?[12], //舒张压标定值,值为0表示不生效 - //systolicIncValue = last?[10], //收缩压显示增量,值为0 表示不生效 - //diastolicIncValue = last?[17] //舒张压显示增量,值为0 表示不生效 - - systolicCalibrationValue = systolicRefValue, //收缩压标定值,值为0 表示不生效 - diastolicCalibrationValue = diastolicRefValue, //舒张压标定值,值为0表示不生效 - systolicIncValue = systolicInc, //收缩压显示增量,值为0 表示不生效 - diastolicIncValue = diastolicInc //舒张压显示增量,值为0 表示不生效 - }; - var str = JsonConvert.SerializeObject(bpData); - var url = $"http://id.ssjlai.com/webapi/api/Command/SetBloodPressCalibrationConfig"; - List> headers = new() + + return await IotSetBloodPressCalibrationConfigResponseAsync(imei, systolicRefValue, diastolicRefValue, systolicInc, diastolicInc).ConfigureAwait(false); + */ + #endregion + } + + private async Task> IotSetBloodPressCalibrationConfigResponseAsync(string imei, int systolicRefValue, int diastolicRefValue, int systolicInc, int diastolicInc) + { + BloodPressCalibrationConfigModel bpIncData = new() { - new KeyValuePair("AuthKey", "key1") - }; -#if DEBUG - var flag = true; -#else - var res = await _httpHelper.HttpToPostAsync(url, bpData, headers).ConfigureAwait(false); - _logger.LogInformation($"向{imei}下发增量值数据:{str},响应:{res}"); - var resJToken = JsonConvert.DeserializeObject(res ?? string.Empty) as JToken; - var flag = resJToken?["message"]?.ToString().Equals("ok") ?? false; -#endif - object? response; - if (flag) + Imei = imei, + SystolicRefValue = systolicRefValue, //收缩压标定值,值为0 表示不生效 + DiastolicRefValue = diastolicRefValue, //舒张压标定值,值为0表示不生效 + SystolicIncValue = systolicInc, //收缩压显示增量,值为0 表示不生效 + DiastolicIncValue = diastolicInc //舒张压显示增量,值为0 表示不生效 + }; + // 下发 IOT 增量值 + var flagIot = await _serviceIotWebApi.SetBloodPressCalibrationConfigAsync(bpIncData).ConfigureAwait(false); + if (flagIot) { #region 保存下推记录 stb_hm_bp_push_ref_inc_value var sql = $"INSERT INTO health_monitor.hm_bp_push_ref_inc_value_{imei.Substring(imei.Length - 2)} " + @@ -234,48 +394,12 @@ namespace HealthMonitor.WebApi.Controllers.HealthMonitor #endregion // 返回结果 - response = new - { - //Timestamp= DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), - data = new - { - imei = model.Imei, - systolicCalibrationValue = systolicRefValue, //收缩压标定值,值为0 表示不生效 - diastolicCalibrationValue = diastolicRefValue, //舒张压标定值,值为0表示不生效 - systolicIncValue = systolicInc, //收缩压显示增量,值为0 表示不生效 - diastolicIncValue = diastolicInc //舒张压显示增量,值为0 表示不生效 - }, - result = new - { - status = "succeed", - code = 200, - message = "请求成功!" - } - }; + return ApiResponse.Success(bpIncData); } else { - // 返回结果 - response = new - { - //Timestamp= DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), - data = new - { - imei = model.Imei, - systolicCalibrationValue = -1, //收缩压标定值,值为0 表示不生效 - diastolicCalibrationValue = -1, //舒张压标定值,值为0表示不生效 - systolicIncValue = -1, //收缩压显示增量,值为0 表示不生效 - diastolicIncValue = -1 //舒张压显示增量,值为0 表示不生效 - }, - result = new - { - status = "failed", - code = 500, - message = "业务出错!下发指令失败" - } - }; + return ApiResponse.Fail(500, "业务出错!下发指令失败"); } - return Ok(response); } } } diff --git a/HealthMonitor.WebApi/Program.cs b/HealthMonitor.WebApi/Program.cs index 3f91541..e056578 100644 --- a/HealthMonitor.WebApi/Program.cs +++ b/HealthMonitor.WebApi/Program.cs @@ -33,6 +33,7 @@ using Microsoft.Extensions.Http; using Microsoft.Extensions.DependencyInjection.Extensions; using HealthMonitor.Service.Etcd; using HealthMonitor.WebApi.Middleware; +using HealthMonitor.Service.Biz; namespace HealthMonitor.WebApi { @@ -191,6 +192,7 @@ namespace HealthMonitor.WebApi builder.Services .AddSingleton() + .AddSingleton() .AddSingleton() .AddHostedService(); #endregion diff --git a/HealthMonitor.WebApi/appsettings.Development.json b/HealthMonitor.WebApi/appsettings.Development.json index 18fa44e..d4141d7 100644 --- a/HealthMonitor.WebApi/appsettings.Development.json +++ b/HealthMonitor.WebApi/appsettings.Development.json @@ -26,7 +26,8 @@ }, "ServiceConfig": { "TelpoDataUrl": "https://id.ssjlai.com/data/", - "EtcdServerAddress": "http://192.168.2.121:2379" + "EtcdServerAddress": "http://192.168.2.121:2379", + "IotWebApiUrl": "http://id.ssjlai.com/webapi/api/" }, "ConnectionStrings": { //"GpsCard_Connection_String": "server=172.16.192.26;port=3304;database=user_operation_platform;uid=root;pwd=telpo#1234;CharSet=utf8;MinimumPoolSize=10;MaximumPoolSize=1000;SslMode=none", diff --git a/HealthMonitor.WebApi/appsettings.production.json b/HealthMonitor.WebApi/appsettings.production.json index dbe55f0..b93b4f0 100644 --- a/HealthMonitor.WebApi/appsettings.production.json +++ b/HealthMonitor.WebApi/appsettings.production.json @@ -22,7 +22,9 @@ "IdleTimeout": 20000 }, "ServiceConfig": { - "TelpoDataUrl": "https://ai.ssjlai.com/data/" + "TelpoDataUrl": "https://ai.ssjlai.com/data/", + "EtcdServerAddress": "http://172.19.42.44:2379", + "IotWebApiUrl": "http://ai.ssjlai.com/webapi/api/" }, "ConnectionStrings": { "GpsCard_Connection_String": "server=rm-uf6j529mu0v6g0btp.mysql.rds.aliyuncs.com;port=3305;database=gps_card;uid=root;pwd=telpo#1234;CharSet=utf8;MinimumPoolSize=10;MaximumPoolSize=1000;SslMode=none", diff --git a/HealthMonitor.WebApi/appsettings.test.json b/HealthMonitor.WebApi/appsettings.test.json index 66a4576..52df8f0 100644 --- a/HealthMonitor.WebApi/appsettings.test.json +++ b/HealthMonitor.WebApi/appsettings.test.json @@ -31,7 +31,8 @@ }, "ServiceConfig": { "TelpoDataUrl": "https://id.ssjlai.com/data/", - "EtcdServerAddress": "http://172.19.42.44:2379" + "EtcdServerAddress": "http://172.19.42.44:2379", + "IotWebApiUrl": "http://id.ssjlai.com/webapi/api/" }, "ConnectionStrings": { // 测试环境内网