#region << 版 本 注 释 >> /*-------------------------------------------------------------------- * 版权所有 (c) 2025 WenJY 保留所有权利。 * CLR版本:4.0.30319.42000 * 机器名称:Mr.Wen's MacBook Pro * 命名空间:Sln.Iot.Business * 唯一标识:7C26094C-5352-4997-866A-FA618F2E5D27 * * 创建者:WenJY * 电子邮箱: * 创建时间:2025-04-11 15:47:06 * 版本:V1.0.0 * 描述: * *-------------------------------------------------------------------- * 修改人: * 时间: * 修改说明: * * 版本:V1.0.0 *--------------------------------------------------------------------*/ #endregion << 版 本 注 释 >> using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Linq.Expressions; using System.Text; using Dm.util; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Sln.Iot.Business.@base; using Sln.Iot.Common; using Sln.Iot.Config; using Sln.Iot.Model.dao; using Sln.Iot.Model.dto; using Sln.Iot.Repository.service; using Sln.Iot.Serilog; using Sln.Iot.Socket; using Sln.Iot.Socket.Adapter; using TouchSocket.Core; using TouchSocket.Sockets; namespace Sln.Iot.Business { /// /// 物联网环境:温度、湿度、照度、噪音、振动 /// public class IotEnvBusiness:BaseBusiness { private readonly IRecordIotEnvInstantService? _service; private readonly IBaseAlarmRuleService _alarmRuleService; private readonly WebSocketBusiness _webSocket; private readonly TcpServer _tcpServer; private readonly IBaseMonitorInfoService _monitorInfoService; public IotEnvBusiness(SerilogHelper logger, AppConfig appConfig, StringChange stringChange, IRecordIotEnvInstantService? service, IBaseAlarmRuleService alarmRuleService, WebSocketBusiness webSocket, TcpServer tcpServer , IBaseMonitorInfoService monitorInfoService) : base(logger, appConfig, stringChange) { _service = service; _alarmRuleService = alarmRuleService; _webSocket = webSocket; _tcpServer = tcpServer; _monitorInfoService = monitorInfoService; } public override FilterResult BufferAnalysis(ISocketClient client, BufferRequestInfo requestInfo, int bodyLength) { ByteBlock byteBlock = new ByteBlock(requestInfo.Body); if (byteBlock.CanReadLen < 1) { return FilterResult.Cache; } int pos = byteBlock.Pos; try { List result = new List(); var amount = requestInfo.BufferLength / bodyLength; _logger.Info($"收到{amount}个物联网环境数据,开始循环解析......"); for (int i = 0; i < amount; i++) { RecordIotEnvInstant iotEnvInstant = new RecordIotEnvInstant(); #region 表号解析 Add By Wenjy 2024-04-18 // byteBlock.Read(out byte[] b_MeterID, 2); // var MeterID_1 = "00" + Convert.ToInt32(b_MeterID[0]).ToString(); // MeterID_1 = MeterID_1.Substring(MeterID_1.Length - 2, 2); // var MeterID_2 = "00" + Convert.ToInt32(b_MeterID[1]).ToString(); // MeterID_2 = MeterID_2.Substring(MeterID_2.Length - 2, 2); // var equipId = requestInfo.ColletEquipCode + "_" + MeterID_1 + MeterID_2; #endregion #region 表号解析 byteBlock.Read(out byte[] b_MeterID, 2); var decParts = b_MeterID.Select(b => $"{b:D2}").ToArray(); var equipId = $"{requestInfo.ColletEquipCode}_{decParts[0]}{decParts[1]}"; #endregion iotEnvInstant.monitorId = equipId; #region 物联网参数解析 Edit By Wenjy 2025-05-07 修改 Nan 值过滤 do { byteBlock.Read(out byte[] b_UA_flag, 2); base._stringChange.ConvertBytesToUInt16(b_UA_flag, out uint flag); switch (flag) { case CommParams.TTempreture: //温度 byteBlock.Read(out byte[] tempreture, 4); base._stringChange.SwapBytes(ref tempreture); float f_tempreture = BitConverter.ToSingle(tempreture, 0); ValueIsNan(ref f_tempreture); iotEnvInstant.temperature = (decimal) f_tempreture; break; case CommParams.Humidity: //湿度 byteBlock.Read(out byte[] humidity, 4); base._stringChange.SwapBytes(ref humidity); float f_humidity = BitConverter.ToSingle(humidity, 0); ValueIsNan(ref f_humidity); iotEnvInstant.humidity = (decimal) f_humidity; break; case CommParams.Noise: //噪音 byteBlock.Read(out byte[] noise, 4); base._stringChange.SwapBytes(ref noise); float f_noise = BitConverter.ToSingle(noise, 0); ValueIsNan(ref f_noise); iotEnvInstant.noise = (decimal) f_noise; break; case CommParams.VibrationSpeed: //振动-速度 byteBlock.Read(out byte[] vibrationSpeed, 4); base._stringChange.SwapBytes(ref vibrationSpeed); float f_vibrationSpeed = BitConverter.ToSingle(vibrationSpeed, 0); ValueIsNan(ref f_vibrationSpeed); iotEnvInstant.vibrationSpeed = (decimal) f_vibrationSpeed; break; case CommParams.VibrationDisplacement: //振动-位移 byteBlock.Read(out byte[] vibrationDisplacement, 4); base._stringChange.SwapBytes(ref vibrationDisplacement); float f_vibrationDisplacement = BitConverter.ToSingle(vibrationDisplacement, 0); ValueIsNan(ref f_vibrationDisplacement); iotEnvInstant.vibrationDisplacement = (decimal)f_vibrationDisplacement; break; case CommParams.VibrationAcceleration: //振动-加速度 byteBlock.Read(out byte[] vibrationAcceleration, 4); base._stringChange.SwapBytes(ref vibrationAcceleration); float f_vibrationAcceleration = BitConverter.ToSingle(vibrationAcceleration, 0); ValueIsNan(ref f_vibrationAcceleration); iotEnvInstant.vibrationAcceleration = (decimal)f_vibrationAcceleration; break; case CommParams.VibrationTemp: //振动-温度 byteBlock.Read(out byte[] vibrationTemp, 4); base._stringChange.SwapBytes(ref vibrationTemp); float f_vibrationTemp = BitConverter.ToSingle(vibrationTemp, 0); ValueIsNan(ref f_vibrationTemp); iotEnvInstant.vibrationTemp = (decimal)f_vibrationTemp; break; case CommParams.CJSJ: byteBlock.Read(out byte[] b_CJSJ, 6); string strDateTime = "20" + b_CJSJ[5].ToString("x2") + "-" + b_CJSJ[4].ToString("x2") + "-" + b_CJSJ[3].ToString("x2") + " " + b_CJSJ[2].ToString("x2") + ":" + b_CJSJ[1].ToString("x2") + ":" + b_CJSJ[0].ToString("x2"); iotEnvInstant.collectTime = Convert.ToDateTime(strDateTime); break; } } while (byteBlock.Pos % bodyLength != 0); #endregion iotEnvInstant.recordTime = DateTime.Now; var serializeObject = JsonConvert.SerializeObject(iotEnvInstant); _logger.Info($"第{i+1}个物联网表{iotEnvInstant.monitorId}解析完成:{serializeObject}"); result.Add(iotEnvInstant); } if (result.Count > 0) { //是否开启 FF 异常值过滤 if (_appConfig.virtualFlag) { ParamVerification(ref result); } SendData(result); var inRes = _service.SplitInsert(result,out List insertIds); _logger.Info($"{amount}个物联网数据解析处理完成,保存{result.Count}个物联网数据,保存{(inRes ? "成功" : "失败")}"); ParamAlarmFilter(result); } else { _logger.Info($"{amount}个物联网数据解析处理完成,没有需要保存的数据"); } return FilterResult.Success; } catch (Exception e) { base._logger.Error($"物联网数据解析异常:{e.Message}"); } return FilterResult.Cache; } /// /// 回复指令 /// /// /// public override void ResponseHandle(ISocketClient client, byte[] buffer) { ResponsePack sendResponsePackInfo = new ResponsePack() { m_MessageType = 0xB5 }; base.GetMessagePack(ref sendResponsePackInfo, buffer); base.SendMessageAsync(client,sendResponsePackInfo); } /// /// FF FF参数过滤 /// /// /// private void ParamVerification(ref List iotEnvInstants) { if (iotEnvInstants == null) { throw new ArgumentNullException($"过滤参数方法异常,传入参数为空"); } for (int i = iotEnvInstants.Count - 1; i >= 0; i--) { var item = iotEnvInstants[i]; if (item.temperature == _appConfig.virtualValue) { _logger.Info($"MonitorId:{item.monitorId},温度值为 FF FF FF FF,已启用过滤不保存该表数据"); iotEnvInstants.RemoveAt(i); continue; } if (item.humidity == _appConfig.virtualValue) { _logger.Info($"MonitorId:{item.monitorId},湿度值为 FF FF FF FF,已启用过滤不保存该表数据"); iotEnvInstants.RemoveAt(i); continue; } if (item.noise == _appConfig.virtualValue) { _logger.Info($"MonitorId:{item.monitorId},噪音值为 FF FF FF FF,已启用过滤不保存该表数据"); iotEnvInstants.RemoveAt(i); continue; } if (item.vibrationSpeed == _appConfig.virtualValue) { _logger.Info($"MonitorId:{item.monitorId},振动速度值为 FF FF FF FF,已启用过滤不保存该表数据"); iotEnvInstants.RemoveAt(i); continue; } if (item.vibrationDisplacement == _appConfig.virtualValue) { _logger.Info($"MonitorId:{item.monitorId},振动位移值为 FF FF FF FF,已启用过滤不保存该表数据"); iotEnvInstants.RemoveAt(i); continue; } if (item.vibrationAcceleration == _appConfig.virtualValue) { _logger.Info($"MonitorId:{item.monitorId},振动加速度值为 FF FF FF FF,已启用过滤不保存该表数据"); iotEnvInstants.RemoveAt(i); continue; } if (item.vibrationTemp == _appConfig.virtualValue) { _logger.Info($"MonitorId:{item.monitorId},振动温度值为 FF FF FF FF,已启用过滤不保存该表数据"); iotEnvInstants.RemoveAt(i); continue; } } } /// /// /// /// public void SendData(List iotEnvInstants) { lock (string.Empty) { foreach (var iotEnvInstant in iotEnvInstants) { Thread.Sleep(200); var monitorInfo = _monitorInfoService.Query(x => x.monitorId == iotEnvInstant.monitorId).FirstOrDefault(); StringBuilder sb = new StringBuilder(); if (monitorInfo != null) { sb.Append(iotEnvInstant.monitorId); sb.Append("-"); sb.Append(monitorInfo.monitorType); if (monitorInfo.monitorType == 5 || monitorInfo.monitorType == 6) { sb.Append("-"); sb.Append(iotEnvInstant.temperature); } if (monitorInfo.monitorType == 6) { sb.Append("-"); sb.Append(iotEnvInstant.humidity); } if (monitorInfo.monitorType == 7) { sb.Append("-"); sb.Append(iotEnvInstant.noise); } if (monitorInfo.monitorType == 8) { sb.Append("-"); sb.Append(iotEnvInstant.illuminance); } if (monitorInfo.monitorType == 10) { sb.Append("-"); sb.Append(iotEnvInstant.vibrationSpeed); sb.Append("-"); sb.Append(iotEnvInstant.vibrationAcceleration); sb.Append("-"); sb.Append(iotEnvInstant.vibrationDisplacement); sb.Append("-"); sb.Append(iotEnvInstant.vibrationTemp); } sb.Append(";"); } //string str = $"{iotEnvInstant.monitorId}-{iotEnvInstant.temperature}-{iotEnvInstant.humidity}-{iotEnvInstant.noise}-{iotEnvInstant.illuminance}-{iotEnvInstant.vibrationSpeed}-{iotEnvInstant.vibrationAcceleration}-{iotEnvInstant.vibrationDisplacement}-{iotEnvInstant.vibrationTemp}"; string str = sb.ToString(); byte[] bytes = StringToBytesUsingASCII(str); _tcpServer.SendDataToRecevieDevice(bytes); } } } public static byte[] StringToBytesUsingASCII(string input) { if (input == null) { throw new ArgumentNullException(nameof(input), "输入字符串不能为 null。"); } // 使用 ASCII 编码将字符串转换为字节数组 return Encoding.ASCII.GetBytes(input); } /// /// 报警参数过滤 /// /// private void ParamAlarmFilter(List iotEnvInstants) { if (iotEnvInstants == null) { throw new ArgumentNullException(nameof(iotEnvInstants), "报警参数过滤异常,传入参数为空"); } // 预编译比较委托(避免循环内重复编译) static Func CreateComparer(int triggerRule) { ParameterExpression x = Expression.Parameter(typeof(decimal), "x"); ParameterExpression y = Expression.Parameter(typeof(decimal), "y"); BinaryExpression comparison = triggerRule == 0 ? Expression.GreaterThan(x, y) : Expression.LessThan(x, y); return Expression.Lambda>(comparison, x, y).Compile(); } var fieldAccessors = new Dictionary> { { 0, item => item.temperature }, { 1, item => item.humidity }, { 2, item => item.vibrationSpeed }, { 3, item => item.vibrationDisplacement }, { 4, item => item.vibrationAcceleration }, { 5, item => item.vibrationTemp }, { 6, item => item.noise }, { 7, item => item.illuminance } }; foreach (var item in iotEnvInstants) { var alarmRules = _alarmRuleService.Query(x => x.monitorId == item.monitorId); List ruleRes = new List(); List alarmContents = new List(); foreach (var rule in alarmRules) { decimal paramValue = fieldAccessors.TryGetValue(rule.monitorField, out var accessor) ? accessor(item) : 0; var comparer = CreateComparer(rule.triggerRule); if (comparer(paramValue, rule.triggerValue)) { ruleRes.Add(rule); alarmContents.Add($"{item.monitorId}传感器数据在{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}触发{rule.ruleName}异常告警,告警规则:{(rule.triggerRule == 0 ? "大于" : "小于") },阈值:{rule.triggerValue},详细信息:{rule.cause}"); } } MonitorAlarmDto monitorAlarmDto = new MonitorAlarmDto() { monitorId = item.monitorId, isFlag = ruleRes.Count() > 0 ? 1 : 0, deviceParam = item, alarmRules = ruleRes, alarmContents = alarmContents, recordTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() }; string str = JsonConvert.SerializeObject(monitorAlarmDto); _logger.Alarm($"传感器数据推送:{str}"); _webSocket.PushMsg(str); } } } }