diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000..e4d2e26
Binary files /dev/null and b/.DS_Store differ
diff --git a/.idea/.idea.Sln.Iot/.idea/.gitignore b/.idea/.idea.Sln.Iot/.idea/.gitignore
new file mode 100644
index 0000000..c8996d7
--- /dev/null
+++ b/.idea/.idea.Sln.Iot/.idea/.gitignore
@@ -0,0 +1,13 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Rider ignored files
+/contentModel.xml
+/projectSettingsUpdater.xml
+/.idea.Sln.Iot.iml
+/modules.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/.idea.Sln.Iot/.idea/encodings.xml b/.idea/.idea.Sln.Iot/.idea/encodings.xml
new file mode 100644
index 0000000..df87cf9
--- /dev/null
+++ b/.idea/.idea.Sln.Iot/.idea/encodings.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.Sln.Iot/.idea/indexLayout.xml b/.idea/.idea.Sln.Iot/.idea/indexLayout.xml
new file mode 100644
index 0000000..7b08163
--- /dev/null
+++ b/.idea/.idea.Sln.Iot/.idea/indexLayout.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Sln.Iot.Business/CheckTimeBusiness.cs b/Sln.Iot.Business/CheckTimeBusiness.cs
new file mode 100644
index 0000000..097323b
--- /dev/null
+++ b/Sln.Iot.Business/CheckTimeBusiness.cs
@@ -0,0 +1,76 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Business
+* 唯一标识:8BCBBC2D-F2EB-45A3-9DBA-24217C772093
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-05-07 13:44:30
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using System;
+using Sln.Iot.Business.@base;
+using Sln.Iot.Common;
+using Sln.Iot.Config;
+using Sln.Iot.Model.dto;
+using Sln.Iot.Serilog;
+using Sln.Iot.Socket.Adapter;
+using TouchSocket.Core;
+using TouchSocket.Sockets;
+
+namespace Sln.Iot.Business
+{
+ ///
+ /// 校时指令
+ ///
+ public class CheckTimeBusiness:BaseBusiness
+ {
+ public CheckTimeBusiness(SerilogHelper logger, AppConfig appConfig, StringChange stringChange) : base(logger, appConfig, stringChange)
+ {
+ }
+
+ public override FilterResult BufferAnalysis(ISocketClient client, BufferRequestInfo requestInfo, int bodyLength)
+ {
+ ResponsePack sendResponsePackInfo = new ResponsePack()
+ {
+ m_MessageType = 0x08,
+ m_PackLen = new byte[] {0x00, 0x06}
+ };
+ base.GetMessagePack(ref sendResponsePackInfo,requestInfo.buffer);
+ DateTime currentTime = DateTime.Now;
+ byte[] timeBuffer = new byte[]
+ {
+ base._stringChange.HexStrTorbytes(currentTime.ToString("ss"))[0],
+ base._stringChange.HexStrTorbytes(currentTime.ToString("mm"))[0],
+ base._stringChange.HexStrTorbytes(currentTime.ToString("HH"))[0],
+ base._stringChange.HexStrTorbytes(currentTime.ToString("dd"))[0],
+ base._stringChange.HexStrTorbytes(currentTime.ToString("MM"))[0],
+ base._stringChange.HexStrTorbytes(currentTime.ToString("yy"))[0],
+ };
+
+ base.SendMessageAsync(client, sendResponsePackInfo,timeBuffer);
+
+ return FilterResult.Success;
+ }
+
+ public override void ResponseHandle(ISocketClient client, byte[] buffer)
+ {
+ //校时指令通过业务数据返回
+ }
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Business/ElectricBusiness.cs b/Sln.Iot.Business/ElectricBusiness.cs
new file mode 100644
index 0000000..0812c0a
--- /dev/null
+++ b/Sln.Iot.Business/ElectricBusiness.cs
@@ -0,0 +1,299 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Business
+* 唯一标识:F35152F4-9983-4881-AB1C-F9561EFAF534
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-05-20 10:30:12
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+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.Adapter;
+using TouchSocket.Core;
+using TouchSocket.Sockets;
+
+namespace Sln.Iot.Business
+{
+ ///
+ /// 电能数据
+ ///
+ public class ElectricBusiness:BaseBusiness
+ {
+
+ private Dictionary _lastCollectTimeDict = new Dictionary();
+
+ private readonly IRecordDnbInstantService? _service;
+
+
+ public ElectricBusiness(SerilogHelper logger, AppConfig appConfig, StringChange stringChange, IRecordDnbInstantService? service) : base(logger, appConfig, stringChange)
+ {
+ _service = service;
+ }
+
+ 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++)
+ {
+ RecordDnbInstant dnbInstant = new RecordDnbInstant();
+
+ #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
+
+ dnbInstant.monitorId = equipId;
+
+ do
+ {
+ byteBlock.Read(out byte[] b_UA_flag, 2);
+ base._stringChange.ConvertBytesToUInt16(b_UA_flag, out uint flag);
+ switch (flag)
+ {
+ case CommParams.AU: //A项电压
+ byteBlock.Read(out byte[] b_UA, 4);
+ base._stringChange.SwapBytes(ref b_UA);
+ float f_UA = BitConverter.ToSingle(b_UA, 0);
+
+ ValueIsNan(ref f_UA);
+
+ dnbInstant.vA = (decimal) f_UA;
+ break;
+
+ case CommParams.BU: //B项电压
+ byteBlock.Read(out byte[] b_UB, 4);
+ base._stringChange.SwapBytes(ref b_UB);
+ float f_UB = BitConverter.ToSingle(b_UB, 0);
+
+ ValueIsNan(ref f_UB);
+
+ dnbInstant.vB = (decimal) f_UB;
+ break;
+ case CommParams.CU: //C项电压
+ byteBlock.Read(out byte[] b_UC, 4);
+ base._stringChange.SwapBytes(ref b_UC);
+ float f_UC = BitConverter.ToSingle(b_UC, 0);
+
+ ValueIsNan(ref f_UC);
+
+ dnbInstant.vC = (decimal) f_UC;
+ break;
+ case CommParams.AI: //A项电流
+ byteBlock.Read(out byte[] b_IA, 4);
+ base._stringChange.SwapBytes(ref b_IA);
+ float f_IA = BitConverter.ToSingle(b_IA, 0);
+
+ ValueIsNan(ref f_IA);
+
+ dnbInstant.iA = (decimal) f_IA;
+ break;
+ case CommParams.BI: //B项电流
+ byteBlock.Read(out byte[] b_IB, 4);
+ base._stringChange.SwapBytes(ref b_IB);
+ float f_IB = BitConverter.ToSingle(b_IB, 0);
+
+ ValueIsNan(ref f_IB);
+
+ dnbInstant.iB = (decimal) f_IB;
+ break;
+ case CommParams.CI: //C项电流
+ byteBlock.Read(out byte[] b_IC, 4);
+ base._stringChange.SwapBytes(ref b_IC);
+ float f_IC = BitConverter.ToSingle(b_IC, 0);
+
+ ValueIsNan(ref f_IC);
+
+ dnbInstant.iC = (decimal) f_IC;
+ break;
+ case CommParams.GLYS: //功率因数
+ byteBlock.Read(out byte[] b_GLYS, 4);
+ base._stringChange.SwapBytes(ref b_GLYS);
+ float f_GLYS = BitConverter.ToSingle(b_GLYS, 0);
+
+ ValueIsNan(ref f_GLYS);
+
+ dnbInstant.powerFactor = (decimal) f_GLYS;
+ break;
+ case CommParams.YGGL: //有功功率
+ byteBlock.Read(out byte[] b_YGGL, 4);
+ base._stringChange.SwapBytes(ref b_YGGL);
+ float f_YGGL = BitConverter.ToSingle(b_YGGL, 0);
+
+ ValueIsNan(ref f_YGGL);
+
+ dnbInstant.activePower = Convert.ToDecimal(f_YGGL / 1000);
+ break;
+ case CommParams.WGGL: //无功功率
+ byteBlock.Read(out byte[] b_WGGL, 4);
+ base._stringChange.SwapBytes(ref b_WGGL);
+ float f_WGGL = BitConverter.ToSingle(b_WGGL, 0);
+
+ ValueIsNan(ref f_WGGL);
+
+ dnbInstant.reactivePower = (decimal) f_WGGL;
+ break;
+ case CommParams.ZXYGZ: //正向有功
+ byteBlock.Read(out byte[] b_ZXYGZ, 4);
+ base._stringChange.SwapBytes(ref b_ZXYGZ);
+ float f_ZXYGZ = BitConverter.ToSingle(b_ZXYGZ, 0);
+
+ ValueIsNan(ref f_ZXYGZ);
+
+ dnbInstant.positiveActive = (decimal) f_ZXYGZ;
+ 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");
+ dnbInstant.collectTime = Convert.ToDateTime(strDateTime);
+ break;
+ }
+
+ } while (byteBlock.Pos % bodyLength != 0);
+
+ dnbInstant.recordTime = DateTime.Now;
+
+ var serializeObject = JsonConvert.SerializeObject(dnbInstant);
+
+ _logger.Info($"第{i+1}个电表{dnbInstant.monitorId}解析完成:{serializeObject}");
+
+ DateTime? lastCollectTime = GetLastCollectTime(dnbInstant.monitorId);
+ if (lastCollectTime != null && DateTime.Now -lastCollectTime < TimeSpan.FromMinutes(_appConfig.electricTimeInterval))
+ {
+ //时间间隔小于采集间隔,不保存
+ continue;
+ }
+
+ // 如果字典中已有该键,则更新;否则新增
+ _lastCollectTimeDict[dnbInstant.monitorId] = DateTime.Now;
+
+ result.Add(dnbInstant);
+ }
+
+ if (result.Count > 0)
+ {
+ //是否开启 FF 异常值过滤
+ if (_appConfig.virtualFlag)
+ {
+ ParamVerification(ref result);
+ }
+
+ var inRes = _service.SplitInsert(result,out List insertIds);
+ _logger.Info($"{result.Count}个电表数据解析处理完成,数据保存{(inRes ? "成功" : "失败")}");
+ }
+ else
+ {
+ _logger.Info($"{amount}个电表数据解析处理完成,没有需要保存的数据");
+ }
+ return FilterResult.Success;
+ }
+ catch (Exception e)
+ {
+ base._logger.Error($"电能数据解析异常:{e.Message}");
+ }
+
+ return FilterResult.Cache;
+ }
+
+ ///
+ /// FF FF参数过滤
+ ///
+ ///
+ ///
+ private void ParamVerification(ref List dnbInstants)
+ {
+ if (dnbInstants == null)
+ {
+ throw new ArgumentNullException($"过滤参数方法异常,传入参数为空");
+ }
+
+ for (int i = dnbInstants.Count - 1; i >= 0; i--)
+ {
+ var item = dnbInstants[i];
+
+ if (item.positiveActive == _appConfig.virtualValue)
+ {
+ _logger.Info($"MonitorId:{item.monitorId},正向有功为 FF FF FF FF,已启用过滤不保存该表数据");
+ dnbInstants.RemoveAt(i);
+ continue;
+ }
+ }
+ }
+
+ private DateTime? GetLastCollectTime(string key)
+ {
+ // 检查键是否存在
+ if (_lastCollectTimeDict.TryGetValue(key, out DateTime collectTime))
+ {
+ return collectTime;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ ///
+ /// 应答处理
+ ///
+ ///
+ ///
+ public override void ResponseHandle(ISocketClient client, byte[] buffer)
+ {
+ ResponsePack sendResponsePackInfo = new ResponsePack()
+ {
+ m_MessageType = 0xB3
+ };
+ base.GetMessagePack(ref sendResponsePackInfo, buffer);
+
+ base.SendMessageAsync(client,sendResponsePackInfo);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Business/FluidBusiness.cs b/Sln.Iot.Business/FluidBusiness.cs
new file mode 100644
index 0000000..d0974a2
--- /dev/null
+++ b/Sln.Iot.Business/FluidBusiness.cs
@@ -0,0 +1,276 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Business
+* 唯一标识:D5F7092D-7C5C-42B9-A373-1332CFD77169
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-05-20 14:45:41
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+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.Adapter;
+using TouchSocket.Core;
+using TouchSocket.Sockets;
+
+namespace Sln.Iot.Business
+{
+ public class FluidBusiness:BaseBusiness
+ {
+ private Dictionary _lastCollectTimeDict = new Dictionary();
+
+ private readonly IRecordFluidInstantService? _service;
+
+ public FluidBusiness(SerilogHelper logger, AppConfig appConfig, StringChange stringChange, IRecordFluidInstantService? service) : base(logger, appConfig, stringChange)
+ {
+ _service = service;
+ }
+
+ 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++)
+ {
+ RecordFluidInstant fluidInstant = new RecordFluidInstant();
+
+ #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
+
+ fluidInstant.monitorId = equipId;
+
+ do
+ {
+ byteBlock.Read(out byte[] b_UA_flag, 2);
+ base._stringChange.ConvertBytesToUInt16(b_UA_flag, out uint flag);
+ switch (flag)
+ {
+ case CommParams.Press: //压力值
+ byteBlock.Read(out byte[] b_Press, 4);
+ base._stringChange.SwapBytes(ref b_Press);
+ float f_Press = BitConverter.ToSingle(b_Press, 0);
+
+ ValueIsNan(ref f_Press);
+
+ fluidInstant.press = (decimal)f_Press;
+ break;
+ case CommParams.STemperature: //温度值
+ byteBlock.Read(out byte[] b_Temperature, 4);
+ base._stringChange.SwapBytes(ref b_Temperature);
+ float f_Temperature = BitConverter.ToSingle(b_Temperature, 0);
+
+ ValueIsNan(ref f_Temperature);
+
+ fluidInstant.temperature = (decimal)f_Temperature;
+ break;
+ case CommParams.Frequency: //频率值
+ byteBlock.Read(out byte[] b_Frequency, 4);
+ base._stringChange.SwapBytes(ref b_Frequency);
+ float f_Frequency = BitConverter.ToSingle(b_Frequency, 0);
+
+ ValueIsNan(ref f_Frequency);
+
+ fluidInstant.frequency = (decimal)f_Frequency;
+ break;
+
+ case CommParams.Density: //密度值
+ byteBlock.Read(out byte[] b_Density, 4);
+ base._stringChange.SwapBytes(ref b_Density);
+ float f_Density = BitConverter.ToSingle(b_Density, 0);
+
+ ValueIsNan(ref f_Density);
+
+ fluidInstant.density = (decimal)f_Density;
+ break;
+
+ case CommParams.FluxInstantValue: //瞬时流值
+ byteBlock.Read(out byte[] b_FluxInstantValue, 4);
+ base._stringChange.SwapBytes(ref b_FluxInstantValue);
+ float f_FluxInstantValue = BitConverter.ToSingle(b_FluxInstantValue, 0);
+
+ ValueIsNan(ref f_FluxInstantValue);
+
+ fluidInstant.instantFlow = (decimal)f_FluxInstantValue;
+ break;
+ case CommParams.FluxEyeableTotalValue: //累计流量值
+ byteBlock.Read(out byte[] b_FluxEyeableTotalValue, 4);
+ base._stringChange.SwapBytes(ref b_FluxEyeableTotalValue);
+ float f_FluxEyeableTotalValue = BitConverter.ToSingle(b_FluxEyeableTotalValue, 0);
+
+ ValueIsNan(ref f_FluxEyeableTotalValue);
+
+ fluidInstant.totalFlow = (decimal)f_FluxEyeableTotalValue;
+ break;
+ case CommParams.HeatInstantValue: //瞬时热量
+ byteBlock.Read(out byte[] b_HeatInstantValue, 4);
+ base._stringChange.SwapBytes(ref b_HeatInstantValue);
+ float f_HeatInstantValue = BitConverter.ToSingle(b_HeatInstantValue, 0);
+
+ ValueIsNan(ref f_HeatInstantValue);
+
+ fluidInstant.instantHeat = (decimal)f_HeatInstantValue;
+ break;
+ case CommParams.HeatToftalValue: //累计热量值
+ byteBlock.Read(out byte[] b_HeatToftalValue, 4);
+ base._stringChange.SwapBytes(ref b_HeatToftalValue);
+ float f_HeatToftalValue = BitConverter.ToSingle(b_HeatToftalValue, 0);
+
+ ValueIsNan(ref f_HeatToftalValue);
+
+ fluidInstant.totalHeat = (decimal)f_HeatToftalValue;
+ 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");
+ fluidInstant.collectTime = Convert.ToDateTime(strDateTime);
+ break;
+ }
+
+ } while (byteBlock.Pos % bodyLength != 0);
+
+ fluidInstant.recordTime = DateTime.Now;
+
+ var serializeObject = JsonConvert.SerializeObject(fluidInstant);
+
+ _logger.Info($"第{i+1}个流体仪表{fluidInstant.monitorId}解析完成:{serializeObject}");
+
+ DateTime? lastCollectTime = GetLastCollectTime(fluidInstant.monitorId);
+ if (lastCollectTime != null && DateTime.Now -lastCollectTime < TimeSpan.FromMinutes(_appConfig.fluidTimeInterval))
+ {
+ //时间间隔小于采集间隔,不保存
+ continue;
+ }
+
+ // 如果字典中已有该键,则更新;否则新增
+ _lastCollectTimeDict[fluidInstant.monitorId] = DateTime.Now;
+
+ result.Add(fluidInstant);
+ }
+
+ if (result.Count > 0)
+ {
+ //是否开启 FF 异常值过滤
+ if (_appConfig.virtualFlag)
+ {
+ ParamVerification(ref result);
+ }
+
+ var inRes = _service.SplitInsert(result,out List insertIds);
+ _logger.Info($"{result.Count}个流体数据解析处理完成,数据保存{(inRes ? "成功" : "失败")}");
+ }
+ else
+ {
+ _logger.Info($"{amount}个流体数据解析处理完成,没有需要保存的数据");
+ }
+ return FilterResult.Success;
+ }
+ catch (Exception e)
+ {
+ base._logger.Error($"流体数据解析异常:{e.Message}");
+ }
+
+ return FilterResult.Cache;
+ }
+
+ ///
+ /// FF FF参数过滤
+ ///
+ ///
+ ///
+ private void ParamVerification(ref List fluidInstants)
+ {
+ if (fluidInstants == null)
+ {
+ throw new ArgumentNullException($"过滤参数方法异常,传入参数为空");
+ }
+
+ for (int i = fluidInstants.Count - 1; i >= 0; i--)
+ {
+ var item = fluidInstants[i];
+
+ if (item.totalFlow == _appConfig.virtualValue)
+ {
+ _logger.Info($"MonitorId:{item.monitorId},累计流量为 FF FF FF FF,已启用过滤不保存该表数据");
+ fluidInstants.RemoveAt(i);
+ continue;
+ }
+ }
+ }
+
+ private DateTime? GetLastCollectTime(string key)
+ {
+ // 检查键是否存在
+ if (_lastCollectTimeDict.TryGetValue(key, out DateTime collectTime))
+ {
+ return collectTime;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ ///
+ /// 应答处理
+ ///
+ ///
+ ///
+ public override void ResponseHandle(ISocketClient client, byte[] buffer)
+ {
+ ResponsePack sendResponsePackInfo = new ResponsePack()
+ {
+ m_MessageType = 0xB4
+ };
+ base.GetMessagePack(ref sendResponsePackInfo, buffer);
+ base.SendMessageAsync(client, sendResponsePackInfo);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Business/HeartBusiness.cs b/Sln.Iot.Business/HeartBusiness.cs
new file mode 100644
index 0000000..696fbd2
--- /dev/null
+++ b/Sln.Iot.Business/HeartBusiness.cs
@@ -0,0 +1,79 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Business
+* 唯一标识:AF7CD4B2-87AF-4F91-BECA-13779B05170C
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-04-11 16:04:07
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using Sln.Iot.Business.@base;
+using Sln.Iot.Common;
+using Sln.Iot.Config;
+using Sln.Iot.Model.dto;
+using Sln.Iot.Serilog;
+using Sln.Iot.Socket.Adapter;
+using TouchSocket.Core;
+using TouchSocket.Sockets;
+
+namespace Sln.Iot.Business
+{
+ ///
+ /// 心跳指令
+ ///
+ public class HeartBusiness:BaseBusiness
+ {
+ public HeartBusiness(SerilogHelper logger, AppConfig appConfig,StringChange stringChange) : base(logger, appConfig,stringChange)
+ {
+ }
+
+ public override FilterResult BufferAnalysis(ISocketClient client, BufferRequestInfo requestInfo, int bodyLength)
+ {
+ //心跳没有业务逻辑处理
+ return FilterResult.Success;
+ }
+
+ ///
+ /// 应答处理
+ ///
+ ///
+ ///
+ public override void ResponseHandle(ISocketClient client, byte[] buffer)
+ {
+
+ ResponsePack sendResponsePackInfo = new ResponsePack()
+ {
+ m_MessageType = 0xA4
+ };
+ base.GetMessagePack(ref sendResponsePackInfo,buffer);
+
+ //ByteBlock byteBlock = new ByteBlock(requestInfo.Body);
+ //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;
+
+ //Console.WriteLine($"心跳:::::{}");
+
+ base.SendMessageAsync(client, sendResponsePackInfo);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Business/IotEnvBusiness.cs b/Sln.Iot.Business/IotEnvBusiness.cs
new file mode 100644
index 0000000..06c62d4
--- /dev/null
+++ b/Sln.Iot.Business/IotEnvBusiness.cs
@@ -0,0 +1,309 @@
+#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.Linq;
+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.Adapter;
+using TouchSocket.Core;
+using TouchSocket.Sockets;
+
+namespace Sln.Iot.Business
+{
+ ///
+ /// 物联网环境:温度、湿度、照度、噪音、振动
+ ///
+ public class IotEnvBusiness:BaseBusiness
+ {
+ private readonly IRecordIotEnvInstantService? _service;
+
+ public IotEnvBusiness(SerilogHelper logger, AppConfig appConfig, StringChange stringChange, IRecordIotEnvInstantService? service) : base(logger, appConfig, stringChange)
+ {
+ _service = service;
+ }
+
+ 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: //振动-位移
+ bodyLength = 58;
+ 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);
+ }
+
+ var inRes = _service.SplitInsert(result,out List insertIds);
+
+ _logger.Info($"{amount}个物联网数据解析处理完成,保存{result.Count}个物联网数据,保存{(inRes ? "成功" : "失败")}");
+ }
+ 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;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Business/LoginBusiness.cs b/Sln.Iot.Business/LoginBusiness.cs
new file mode 100644
index 0000000..b6a7bbd
--- /dev/null
+++ b/Sln.Iot.Business/LoginBusiness.cs
@@ -0,0 +1,98 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Business
+* 唯一标识:71034873-2FF6-4081-AC87-DFCCCCCF51F2
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-04-11 16:03:28
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using System;
+using Microsoft.Extensions.Logging;
+using Sln.Iot.Business.@base;
+using Sln.Iot.Common;
+using Sln.Iot.Config;
+using Sln.Iot.Model.dto;
+using Sln.Iot.Serilog;
+using Sln.Iot.Socket.Adapter;
+using TouchSocket.Core;
+using TouchSocket.Sockets;
+
+namespace Sln.Iot.Business
+{
+ ///
+ /// 登录指令
+ ///
+ public class LoginBusiness:BaseBusiness
+ {
+ public LoginBusiness(SerilogHelper logger, AppConfig appConfig,StringChange stringChange) : base(logger, appConfig,stringChange)
+ {
+ }
+
+ ///
+ /// 指令解析
+ ///
+ ///
+ ///
+ ///
+ ///
+ public override FilterResult BufferAnalysis(ISocketClient client, BufferRequestInfo requestInfo, int bodyLength)
+ {
+ var flag = "";
+ byte[] bDeviceType = new byte[1];
+ byte[] bDeviceID = new byte[2];
+ Array.Copy(requestInfo.buffer, 1, bDeviceType, 0, 1);
+ Array.Copy(requestInfo.buffer, 2, bDeviceID, 0, 2);
+
+ flag = base._stringChange.ConverToString(bDeviceType);
+ flag += base._stringChange.ConverToString(bDeviceID);
+
+ string clientIdStr = flag.ToString();
+
+ if (clientIdStr.Contains("45"))
+ {
+ if (client.Id != clientIdStr)
+ {
+ client.ResetId(clientIdStr);
+
+ //更新客户端状态
+ }
+ }
+
+ return FilterResult.Success;
+
+ }
+
+ ///
+ /// 应答处理
+ ///
+ ///
+ ///
+ public override void ResponseHandle(ISocketClient client, byte[] buffer)
+ {
+ ResponsePack sendResponsePackInfo = new ResponsePack()
+ {
+ m_MessageType = 0xA1
+ };
+ base.GetMessagePack(ref sendResponsePackInfo,buffer);
+
+ base.SendMessageAsync(client, sendResponsePackInfo);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Business/Sln.Iot.Business.csproj b/Sln.Iot.Business/Sln.Iot.Business.csproj
new file mode 100644
index 0000000..a1e49db
--- /dev/null
+++ b/Sln.Iot.Business/Sln.Iot.Business.csproj
@@ -0,0 +1,17 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Sln.Iot.Business/base/BaseBusiness.cs b/Sln.Iot.Business/base/BaseBusiness.cs
new file mode 100644
index 0000000..dcdc18c
--- /dev/null
+++ b/Sln.Iot.Business/base/BaseBusiness.cs
@@ -0,0 +1,151 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Business.base
+* 唯一标识:AA8CCDD9-6D6B-47B7-8309-5C9D41FFC822
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-04-11 15:04:43
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using Sln.Iot.Common;
+using Sln.Iot.Config;
+using Sln.Iot.Model.dto;
+using Sln.Iot.Serilog;
+using Sln.Iot.Socket.Adapter;
+using TouchSocket.Core;
+using TouchSocket.Sockets;
+
+namespace Sln.Iot.Business.@base
+{
+ public abstract class BaseBusiness
+ {
+ public SerilogHelper _logger;
+
+ public AppConfig _appConfig;
+
+ public StringChange _stringChange;
+
+ public BaseBusiness(SerilogHelper logger,AppConfig appConfig,StringChange stringChange)
+ {
+ _logger = logger;
+ _appConfig = appConfig;
+ _stringChange = stringChange;
+ }
+
+ ///
+ /// 指令解析方法
+ ///
+ ///
+ ///
+ public abstract FilterResult BufferAnalysis(ISocketClient client,BufferRequestInfo requestInfo,int bodyLength);
+
+ ///
+ /// 应答响应
+ ///
+ ///
+ ///
+ public abstract void ResponseHandle(ISocketClient client, byte[] buffer);
+
+ ///
+ /// 封装回复指令
+ ///
+ ///
+ ///
+ public void GetMessagePack(ref ResponsePack SendMessagePackInfo,byte[] buffer)
+ {
+ SendMessagePackInfo.m_EnergyType = buffer[1];
+ Array.Copy(buffer, 2, SendMessagePackInfo.m_Meteraddr, 0, 2);
+ Array.Copy(buffer, 4, SendMessagePackInfo.m_Msta, 0, 2);
+ SendMessagePackInfo.m_StartFlag = buffer[6];
+ }
+
+ ///
+ /// 发送接收成功指令
+ ///
+ ///
+ ///
+ ///
+ public bool SendMessageAsync(ISocketClient client, ResponsePack pMessagePack,byte[] buffer = null)
+ {
+ ushort num = 0;
+ try
+ {
+ byte[] SendBuffer = new byte[12];
+
+ if (buffer != null)
+ {
+ SendBuffer = new byte[12 + buffer.Length];
+ }
+ SendBuffer[num] = pMessagePack.m_BeginChar;
+ num = (ushort)(num + 1);
+ SendBuffer[num] = pMessagePack.m_EnergyType;
+ num = (ushort)(num + 1);
+ Array.Copy(pMessagePack.m_Meteraddr, 0, SendBuffer, num, pMessagePack.m_Meteraddr.Length);
+ num = (ushort)(num + 2);
+ Array.Copy(pMessagePack.m_Msta, 0, SendBuffer, num, pMessagePack.m_Msta.Length);
+ num = (ushort)(num + 2);
+ SendBuffer[num] = pMessagePack.m_StartFlag;
+ num = (ushort)(num + 1);
+ SendBuffer[num] = pMessagePack.m_MessageType;
+ num = (ushort)(num + 1);
+ Array.Copy(pMessagePack.m_PackLen, 0, SendBuffer, num, pMessagePack.m_PackLen.Length);
+ num = (ushort)(num + 2);
+
+ if (buffer != null)
+ {
+ Array.Copy(buffer, 0, SendBuffer, num, buffer.Length);
+ num = (ushort)(num + buffer.Length);
+ }
+
+ pMessagePack.m_Verify = _stringChange.CalculateVerifyToArray(SendBuffer, SendBuffer.Length - 1)[0];
+ SendBuffer[num] = pMessagePack.m_Verify;
+ num = (ushort)(num + 1);
+ SendBuffer[num] = pMessagePack.m_EndChar;
+ _logger.Info($"向客户端:{client.Id};地址:{client.GetIPPort()};发送终端消息:{_stringChange.bytesToHexStr(SendBuffer, SendBuffer.Length)}");
+
+ client.SendAsync(SendBuffer);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ _logger.Error($"SendMessageToClient异常:{ex.Message}");
+ return false;
+ }
+ }
+
+ ///
+ /// Nan 值处理
+ ///
+ ///
+ public void ValueIsNan(ref float value)
+ {
+ if (double.IsNaN(value))
+ {
+ if (_appConfig.virtualFlag)
+ {
+ value = _appConfig.virtualValue;
+ }
+ else
+ {
+ value = 0;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Common/Class1.cs b/Sln.Iot.Common/Class1.cs
new file mode 100644
index 0000000..6644cec
--- /dev/null
+++ b/Sln.Iot.Common/Class1.cs
@@ -0,0 +1,5 @@
+namespace Sln.Iot.Common;
+
+public class Class1
+{
+}
\ No newline at end of file
diff --git a/Sln.Iot.Common/Sln.Iot.Common.csproj b/Sln.Iot.Common/Sln.Iot.Common.csproj
new file mode 100644
index 0000000..9af301d
--- /dev/null
+++ b/Sln.Iot.Common/Sln.Iot.Common.csproj
@@ -0,0 +1,13 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/Sln.Iot.Common/StringChange.cs b/Sln.Iot.Common/StringChange.cs
new file mode 100644
index 0000000..962a0b9
--- /dev/null
+++ b/Sln.Iot.Common/StringChange.cs
@@ -0,0 +1,320 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Common
+* 唯一标识:78FCCE90-A4C0-4DCC-AB23-7C21EC7ECE05
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-04-11 15:06:46
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using System;
+using System.Drawing;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Sln.Iot.Common
+{
+ public class StringChange
+ {
+ ///
+ /// 将字符串强制转换成int,转换失败则返回0
+ ///
+ ///
+ ///
+ public int ParseToInt(string str)
+ {
+ int returnInt = 0;
+ if (str == null || str.Trim().Length < 1)
+ {
+ return returnInt;
+ }
+ if (int.TryParse(str, out returnInt))
+ {
+ return returnInt;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ ///
+ /// char数组转Array
+ ///
+ ///
+ ///
+ ///
+ public string CharArrayToString(char[] cha, int len)
+ {
+ string str = "";
+ for (int i = 0; i < len; i++)
+ {
+ str += string.Format("{0}", cha[i]);
+ }
+
+ return str;
+ }
+
+
+
+ public byte[] HexStrTorbytes(string strHex)//e.g. " 01 01" ---> { 0x01, 0x01}
+ {
+ strHex = strHex.Replace(" ", "");
+ if ((strHex.Length % 2) != 0)
+ strHex += " ";
+ byte[] returnBytes = new byte[strHex.Length / 2];
+ for (int i = 0; i < returnBytes.Length; i++)
+ returnBytes[i] = Convert.ToByte(strHex.Substring(i * 2, 2), 16);
+ return returnBytes;
+ }
+
+ public string StringToHexString(string s, Encoding encode)
+ {
+ byte[] b = encode.GetBytes(s); //按照指定编码将string编程字节数组
+ string result = string.Empty;
+ for (int i = 0; i < b.Length; i++) //逐字节变为16进制字符,以%隔开
+ {
+ result += "%" + Convert.ToString(b[i], 16);
+ }
+ return result;
+ }
+
+ public string HexStringToString(string hs, Encoding encode)
+ {
+ //以%分割字符串,并去掉空字符
+ string[] chars = hs.Split(new char[] { '%' }, StringSplitOptions.RemoveEmptyEntries);
+ byte[] b = new byte[chars.Length];
+ //逐个字符变为16进制字节数据
+ for (int i = 0; i < chars.Length; i++)
+ {
+ b[i] = Convert.ToByte(chars[i], 16);
+ }
+ //按照指定编码将字节数组变为字符串
+ return encode.GetString(b);
+ }
+
+ public byte[] Swap16Bytes(byte[] OldU16)
+ {
+ byte[] ReturnBytes = new byte[2];
+ ReturnBytes[1] = OldU16[0];
+ ReturnBytes[0] = OldU16[1];
+ return ReturnBytes;
+ }
+
+
+ /// 64Base码
+ /// 保存路径
+ /// 文件名称
+ ///
+ public bool Base64ToImage(string strbase64, string path, string filename)
+ {
+ bool Flag = false;
+ try
+ {
+ //base64编码的文本 转为 图片
+ //图片名称
+ byte[] arr = Convert.FromBase64String(strbase64);//将指定的字符串(它将二进制数据编码为 Base64 数字)转换为等效的 8 位无符号整数数组。
+ using (MemoryStream ms = new MemoryStream(arr))
+ {
+ Bitmap bmp = new Bitmap(ms);//加载图像
+ if (!Directory.Exists(path))//判断保存目录是否存在
+ {
+ Directory.CreateDirectory(path);
+ }
+ bmp.Save((path + "\\" + filename + ".png"), System.Drawing.Imaging.ImageFormat.Png);//将图片以JPEG格式保存在指定目录(可以选择其他图片格式)
+ ms.Close();//关闭流并释放
+ if (File.Exists(path + "\\" + filename + ".png"))//判断是否存在
+ {
+ Flag = true;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine("图片保存失败:" + ex.Message);
+ }
+ return Flag;
+ }
+
+ ///
+ /// 获取时间戳
+ ///
+ ///
+ public long GetTimeStamp()
+ {
+ TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
+ return Convert.ToInt64(ts.TotalSeconds);
+ }
+
+ public byte[] ConvertFloatToINt(byte[] floatBytes)
+ {
+ byte[] intBytes = new byte[floatBytes.Length / 2];
+ for (int i = 0; i < intBytes.Length; i++)
+ {
+ intBytes[i] = floatBytes[i * 2];
+ }
+ return intBytes;
+ }
+
+ //CRC异或校验
+ public byte CalculateVerify(byte[] pMessage, int iLength)
+ {
+ UInt16 i;
+ byte iVerify = 0;
+
+ iVerify = pMessage[0];
+ for (i = 1; i < iLength; i++)
+ {
+ iVerify = (byte)(iVerify ^ pMessage[i]);
+ }
+ return iVerify;
+ }
+
+ public int HexStringToNegative(string strNumber)
+ {
+
+ int iNegate = 0;
+ int iNumber = Convert.ToInt32(strNumber, 16);
+ if (iNumber > 127)
+ {
+ int iComplement = iNumber - 1;
+ string strNegate = string.Empty;
+ char[] binchar = Convert.ToString(iComplement, 2).PadLeft(8, '0').ToArray();
+ foreach (char ch in binchar)
+ {
+ if (Convert.ToInt32(ch) == 48)
+ {
+ strNegate += "1";
+ }
+ else
+ {
+ strNegate += "0";
+ }
+ }
+ iNegate = -Convert.ToInt32(strNegate, 2);
+ }
+ return iNegate;
+ }
+
+
+ ///
+ /// Byte[] 转 uint16
+ ///
+ ///
+ ///
+ ///
+ public void ConvertBytesToUInt16(byte[] buffer,out uint falg)
+ {
+ if (buffer == null || buffer.Length < 2)
+ {
+ throw new ArgumentException("Input array length must be at least 2.");
+ }
+
+ var input = buffer.Reverse().ToArray();
+
+ falg = (uint) ((input[1] << 8) | input[0]);
+ }
+
+ ///
+ /// Byte[] 移位转换
+ ///
+ ///
+ ///
+ public void SwapBytes(ref byte[] input)
+ {
+ if (input == null || input.Length % 2 != 0)
+ {
+ throw new ArgumentException("Input array length must be a multiple of 2.");
+ }
+
+ byte[] result = new byte[input.Length];
+
+ for (int j = 0; j < input.Length; j += 2)
+ {
+ ushort swapped = (ushort)((input[j + 1] << 8) | input[j]);
+ result[j] = (byte)(swapped >> 8);
+ result[j + 1] = (byte)swapped;
+ }
+ input = result;
+ }
+
+ ///
+ /// Byte[] 转string
+ ///
+ ///
+ ///
+ public string ConverToString(byte[] data)
+ {
+ string str;
+ StringBuilder stb = new StringBuilder();
+ for (int i = 0; i < data.Length; i++)
+ {
+ if ((int)data[i] > 15)
+ {
+ stb.Append(Convert.ToString(data[i], 16).ToUpper()); //添加字符串
+ }
+ else //如果是小于0F需要加个零
+ {
+ stb.Append("0" + Convert.ToString(data[i], 16).ToUpper());
+ }
+ }
+ str = stb.ToString();
+ return str;
+ }
+
+ ///
+ /// Byte[] 转 Hex
+ ///
+ ///
+ ///
+ ///
+ public string bytesToHexStr(byte[] bytes, int iLen)
+ {
+ StringBuilder sb = new StringBuilder();
+ if (bytes != null)
+ {
+ for (int i = 0; i < iLen; i++)
+ {
+ sb.Append(bytes[i].ToString("X2"));
+ }
+ }
+ return sb.ToString();
+ }
+
+ ///
+ /// 校验计算
+ ///
+ ///
+ ///
+ ///
+ public byte[] CalculateVerifyToArray(byte[] pMessage, int iLength)
+ {
+ UInt16 i;
+ int iVerify = 0;
+
+ iVerify = pMessage[0];
+ for (i = 0; i < iLength - 1; i++)
+ {
+ iVerify = iVerify + pMessage[i + 1];
+ }
+ return BitConverter.GetBytes(Convert.ToUInt16(iVerify));
+ }
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Config/AppConfig.cs b/Sln.Iot.Config/AppConfig.cs
new file mode 100644
index 0000000..3ea6d25
--- /dev/null
+++ b/Sln.Iot.Config/AppConfig.cs
@@ -0,0 +1,75 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Config
+* 唯一标识:132376EA-435B-4340-B8F3-44D61AAE1E99
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-04-11 10:54:31
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using System.Collections.Generic;
+using Microsoft.Extensions.Options;
+
+namespace Sln.Iot.Config
+{
+ public class AppConfig: IOptions
+ {
+ ///
+ /// 日志文件路径
+ ///
+ public string logPath { get; set; }
+
+ ///
+ /// 监听端口
+ ///
+ public int listernPort { get; set; }
+
+ ///
+ /// 虚拟值,用于过滤FFFFFF
+ ///
+ public long virtualValue { get; set; }
+
+ ///
+ /// 是否启用虚拟值
+ ///
+ public bool virtualFlag { get; set; }
+
+ ///
+ /// 电力数据采集间隔
+ ///
+ public int electricTimeInterval { get; set; }
+
+ ///
+ /// 流体数据采集间隔
+ ///
+ public int fluidTimeInterval { get; set; }
+
+ ///
+ /// Sql连接配置
+ ///
+ public List sqlConfig { get; set; }
+
+ ///
+ /// Redis配置
+ ///
+ public string redisConfig { get; set; }
+
+ public AppConfig Value => this;
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Config/Sln.Iot.Config.csproj b/Sln.Iot.Config/Sln.Iot.Config.csproj
new file mode 100644
index 0000000..2a5999f
--- /dev/null
+++ b/Sln.Iot.Config/Sln.Iot.Config.csproj
@@ -0,0 +1,13 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/Sln.Iot.Config/SqlConfig.cs b/Sln.Iot.Config/SqlConfig.cs
new file mode 100644
index 0000000..33ba963
--- /dev/null
+++ b/Sln.Iot.Config/SqlConfig.cs
@@ -0,0 +1,50 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Config
+* 唯一标识:E59D09B8-4750-4486-BB59-5983CD7FB394
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-04-11 13:40:21
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+namespace Sln.Iot.Config
+{
+ public class SqlConfig
+ {
+ ///
+ /// Sql 配置ID,实体通过该ID关联数据源
+ ///
+ public string configId { get; set; }
+
+ ///
+ /// 数据库类型,MySql-0;SqlServer-1;Sqlite-2;Oracle-3
+ ///
+ public int dbType { get; set; }
+
+ ///
+ /// 是否启用:true-是;false-否
+ ///
+ public bool isFlag{get;set;}
+
+ ///
+ /// 连接字符串
+ ///
+ public string connStr { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Model/Class1.cs b/Sln.Iot.Model/Class1.cs
new file mode 100644
index 0000000..636c8d9
--- /dev/null
+++ b/Sln.Iot.Model/Class1.cs
@@ -0,0 +1,5 @@
+namespace Sln.Iot.Model;
+
+public class Class1
+{
+}
\ No newline at end of file
diff --git a/Sln.Iot.Model/Sln.Iot.Model.csproj b/Sln.Iot.Model/Sln.Iot.Model.csproj
new file mode 100644
index 0000000..9c85367
--- /dev/null
+++ b/Sln.Iot.Model/Sln.Iot.Model.csproj
@@ -0,0 +1,13 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/Sln.Iot.Model/dao/BaseMonitorInfo.cs b/Sln.Iot.Model/dao/BaseMonitorInfo.cs
new file mode 100644
index 0000000..41ce6e3
--- /dev/null
+++ b/Sln.Iot.Model/dao/BaseMonitorInfo.cs
@@ -0,0 +1,209 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Model.dao
+* 唯一标识:74702D18-55B3-4AA3-91EB-E02ADC9AEBC8
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-04-11 13:23:39
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using System;
+using SqlSugar;
+
+namespace Sln.Iot.Model.dao
+{
+ ///
+ ///计量设备信息
+ ///
+ [SugarTable("ems_base_monitor_info"), TenantAttribute("tao_iot")]
+ public partial class BaseMonitorInfo
+ {
+ public BaseMonitorInfo(){
+
+
+ }
+ ///
+ /// Desc:自增标识
+ /// Default:
+ /// Nullable:False
+ ///
+ [SugarColumn(IsPrimaryKey=true,IsIdentity=true,ColumnName="obj_id")]
+ public int objid {get;set;}
+
+ ///
+ /// Desc:父级编号
+ /// Default:
+ /// Nullable:True
+ ///
+ [SugarColumn(ColumnName="parent_id")]
+ public int? parentId {get;set;}
+
+ ///
+ /// Desc:计量设备编号
+ /// Default:
+ /// Nullable:False
+ ///
+ [SugarColumn(IsPrimaryKey=true,ColumnName="monitor_code")]
+ public string monitorId {get;set;}
+
+ ///
+ /// Desc:计量设备名称
+ /// Default:
+ /// Nullable:True
+ ///
+ [SugarColumn(ColumnName="monitor_name")]
+ public string monitorName {get;set;}
+
+ ///
+ /// Desc:计量设备位置
+ /// Default:
+ /// Nullable:True
+ ///
+ [SugarColumn(ColumnName="monitor_addr")]
+ public string monitorAddr {get;set;}
+
+ ///
+ /// Desc:计量设备类型
+ /// Default:
+ /// Nullable:True
+ ///
+ [SugarColumn(ColumnName="monitor_type")]
+ public int? monitorType {get;set;}
+
+ ///
+ /// Desc:计量设备状态
+ /// Default:0
+ /// Nullable:True
+ ///
+ [SugarColumn(ColumnName="monitor_status")]
+ public int? monitorStatus {get;set;}
+
+ ///
+ /// Desc:采集设备编号
+ /// Default:
+ /// Nullable:True
+ ///
+ [SugarColumn(ColumnName="collect_device_id")]
+ public string collectDeviceId {get;set;}
+
+ ///
+ /// Desc:祖级列表
+ /// Default:
+ /// Nullable:True
+ ///
+ [SugarColumn(ColumnName="ancestors")]
+ public string ancestors {get;set;}
+
+ ///
+ /// Desc:等级
+ /// Default:
+ /// Nullable:True
+ ///
+ [SugarColumn(ColumnName="grade")]
+ public int? grade {get;set;}
+
+ ///
+ /// Desc:传感器仪表
+ /// Default:
+ /// Nullable:True
+ ///
+ [SugarColumn(ColumnName="meter_type_id")]
+ public string meterTypeId {get;set;}
+
+ ///
+ /// Desc:修正值
+ /// Default:
+ /// Nullable:True
+ ///
+ [SugarColumn(ColumnName="correct_value")]
+ public decimal? correctValue {get;set;}
+
+ ///
+ /// Desc:PT值
+ /// Default:
+ /// Nullable:True
+ ///
+ [SugarColumn(ColumnName="pt")]
+ public int? pt {get;set;}
+
+ ///
+ /// Desc:CT值
+ /// Default:
+ /// Nullable:True
+ ///
+ [SugarColumn(ColumnName="ct")]
+ public int? ct {get;set;}
+
+ ///
+ /// Desc:是否虚拟
+ /// Default:false
+ /// Nullable:True
+ ///
+ [SugarColumn(ColumnName="is_ammeter")]
+ public string isAmmeter {get;set;}
+
+ ///
+ /// Desc:通断复位
+ /// Default:
+ /// Nullable:True
+ ///
+ [SugarColumn(ColumnName="is_key_monitor")]
+ public int? isKeyMonitor {get;set;}
+
+ ///
+ /// Desc:是否断路
+ /// Default:
+ /// Nullable:True
+ ///
+ [SugarColumn(ColumnName="is_circuit")]
+ public int? isCircuit {get;set;}
+
+ ///
+ /// Desc:创建人
+ /// Default:
+ /// Nullable:True
+ ///
+ [SugarColumn(ColumnName="create_by")]
+ public string createBy {get;set;}
+
+ ///
+ /// Desc:创建时间
+ /// Default:CURRENT_TIMESTAMP
+ /// Nullable:True
+ ///
+ [SugarColumn(ColumnName="create_time")]
+ public DateTime? createTime {get;set;}
+
+ ///
+ /// Desc:更新人
+ /// Default:
+ /// Nullable:True
+ ///
+ [SugarColumn(ColumnName="update_by")]
+ public string updateBy {get;set;}
+
+ ///
+ /// Desc:更新时间
+ /// Default:
+ /// Nullable:True
+ ///
+ [SugarColumn(ColumnName="update_time")]
+ public DateTime? updateTime {get;set;}
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Model/dao/RecordDnbInstant.cs b/Sln.Iot.Model/dao/RecordDnbInstant.cs
new file mode 100644
index 0000000..860563e
--- /dev/null
+++ b/Sln.Iot.Model/dao/RecordDnbInstant.cs
@@ -0,0 +1,132 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Model.dao
+* 唯一标识:B1423370-1BD2-4199-AEDC-80C06296A9BC
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-05-20 10:57:48
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using System;
+using SqlSugar;
+
+namespace Sln.Iot.Model.dao
+{
+ ///
+ /// 电实时数据
+ ///
+ [SplitTable(SplitType.Day)]
+ [SugarTable("record_dnb_instant_{year}{month}{day}"), TenantAttribute("tao_iot")]
+ public class RecordDnbInstant
+ {
+ ///
+ /// 编号
+ ///
+ [SugarColumn(ColumnName="objid" ,IsPrimaryKey = true )]
+ public long objid { get; set; }
+ ///
+ /// 计量设备编号
+ ///
+ [SugarColumn(ColumnName="monitor_id" )]
+ public string monitorId { get; set; }
+
+ ///
+ /// A项电压
+ ///
+ [SugarColumn(ColumnName="va" )]
+ public decimal? vA { get; set; }
+
+ ///
+ /// B项电压
+ ///
+ [SugarColumn(ColumnName="vb" )]
+ public decimal? vB { get; set; }
+
+ ///
+ /// C项电压
+ ///
+ [SugarColumn(ColumnName="vc" )]
+ public decimal? vC { get; set; }
+
+ ///
+ /// A项电流
+ ///
+ [SugarColumn(ColumnName="ia" )]
+ public decimal? iA { get; set; }
+
+ ///
+ /// B项电流
+ ///
+ [SugarColumn(ColumnName="ib" )]
+ public decimal? iB { get; set; }
+
+ ///
+ /// C项电流
+ ///
+ [SugarColumn(ColumnName="ic" )]
+ public decimal? iC { get; set; }
+
+ ///
+ /// 功率因数
+ ///
+ [SugarColumn(ColumnName="glys" )]
+ public decimal? powerFactor { get; set; }
+
+ ///
+ /// 正向有功
+ ///
+ [SugarColumn(ColumnName="zxyg" )]
+ public decimal? positiveActive { get; set; }
+
+ ///
+ /// 有功功率
+ ///
+ [SugarColumn(ColumnName="active_power" )]
+ public decimal? activePower { get; set; }
+
+ ///
+ /// 无功功率
+ ///
+ [SugarColumn(ColumnName="reactive_power" )]
+ public decimal? reactivePower { get; set; }
+
+ ///
+ /// 采集方式
+ /// 默认值: 0
+ ///
+ [SugarColumn(ColumnName="collect_type" )]
+ public int collectType
+ {
+ get { return 1;}
+ }
+
+ ///
+ /// 采集时间
+ ///
+ [SugarColumn(ColumnName="collect_time" )]
+ public DateTime? collectTime { get; set; }
+
+ ///
+ /// 记录时间
+ ///
+ [SplitField]
+ [SugarColumn(ColumnName="record_time" )]
+ public DateTime? recordTime { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Model/dao/RecordFluidInstant.cs b/Sln.Iot.Model/dao/RecordFluidInstant.cs
new file mode 100644
index 0000000..0e08d9a
--- /dev/null
+++ b/Sln.Iot.Model/dao/RecordFluidInstant.cs
@@ -0,0 +1,121 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Model.dao
+* 唯一标识:CB52EBBD-0D7F-498D-B2D0-B9926F06F5AF
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-05-20 14:40:03
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using System;
+using SqlSugar;
+
+namespace Sln.Iot.Model.dao
+{
+ ///
+ /// 流体实时数据
+ ///
+ [SplitTable(SplitType.Day)]
+ [SugarTable("record_fluid_instant_{year}{month}{day}"), Tenant("tao_iot")]
+ public class RecordFluidInstant
+ {
+ ///
+ /// 自增标识
+ ///
+ [SugarColumn(ColumnName="objid" ,IsPrimaryKey = true )]
+ public long objid { get; set; }
+
+ ///
+ /// 计量设备编号
+ ///
+ [SugarColumn(ColumnName="monitor_id" )]
+ public string monitorId { get; set; }
+
+ ///
+ /// 温度值
+ ///
+ [SugarColumn(ColumnName="temperature" )]
+ public decimal? temperature{get;set;}
+
+ ///
+ /// 压力值
+ ///
+ [SugarColumn(ColumnName="press" )]
+ public decimal? press{get;set;}
+
+ ///
+ /// 频率值
+ ///
+ [SugarColumn(ColumnName="frequency" )]
+ public decimal? frequency{get;set;}
+
+ ///
+ /// 密度值
+ ///
+ [SugarColumn(ColumnName="density" )]
+ public decimal? density{get;set;}
+
+ ///
+ /// 瞬时热量
+ ///
+ [SugarColumn(ColumnName="instant_heat" )]
+ public decimal? instantHeat { get; set; }
+
+ ///
+ /// 累计热量
+ ///
+ [SugarColumn(ColumnName="total_heat" )]
+ public decimal? totalHeat { get; set; }
+
+ ///
+ /// 瞬时流量
+ ///
+ [SugarColumn(ColumnName="instant_flow" )]
+ public decimal? instantFlow { get; set; }
+
+ ///
+ /// 累计流量
+ ///
+ [SugarColumn(ColumnName="total_flow" )]
+ public decimal? totalFlow { get; set; }
+
+ ///
+ /// 采集方式
+ /// 默认值: 0
+ ///
+ [SugarColumn(ColumnName="collect_type" )]
+ public int collectType
+ {
+ get { return 1;}
+ }
+
+ ///
+ /// 采集时间
+ ///
+ [SugarColumn(ColumnName="collect_time" )]
+ public DateTime? collectTime { get; set; }
+
+ ///
+ /// 记录时间
+ ///
+ [SplitField]
+ [SugarColumn(ColumnName="record_time" )]
+ public DateTime? recordTime { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Model/dao/RecordIotEnvInstant.cs b/Sln.Iot.Model/dao/RecordIotEnvInstant.cs
new file mode 100644
index 0000000..8958735
--- /dev/null
+++ b/Sln.Iot.Model/dao/RecordIotEnvInstant.cs
@@ -0,0 +1,116 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Model.dao
+* 唯一标识:2946BBED-E772-4BC4-953F-F4B9834C27F6
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-04-11 15:20:56
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using System;
+using SqlSugar;
+
+namespace Sln.Iot.Model.dao
+{
+ [SplitTable(SplitType.Day)]
+ [SugarTable("record_iotenv_instant_{year}{month}{day}"), TenantAttribute("tao_iot")]
+ public class RecordIotEnvInstant
+ {
+ ///
+ /// 编号 ,IsIdentity = true
+ ///
+ [SugarColumn(ColumnName="objid" ,IsPrimaryKey = true )]
+ public long objid { get; set; }
+
+ ///
+ /// 计量设备编号
+ ///
+ [SugarColumn(ColumnName="monitorId" )]
+ public string monitorId { get; set; }
+
+ ///
+ /// 温度
+ ///
+ [SugarColumn(ColumnName="temperature" )]
+ public decimal temperature { get; set; }
+
+ ///
+ /// 湿度
+ ///
+ [SugarColumn(ColumnName="humidity" )]
+ public decimal humidity { get; set; }
+
+ ///
+ /// 照度
+ ///
+ [SugarColumn(ColumnName="illuminance" )]
+ public decimal illuminance { get; set; }
+
+ ///
+ /// 噪音
+ ///
+ [SugarColumn(ColumnName="noise" )]
+ public decimal noise { get; set; }
+
+ ///
+ /// 气体浓度
+ ///
+ [SugarColumn(ColumnName="concentration" )]
+ public decimal concentration { get; set; }
+
+ ///
+ /// 振动-速度
+ ///
+ [SugarColumn(ColumnName = "vibration_speed")]
+ public decimal VibrationSpeed { get; set; }
+
+
+ ///
+ /// 振动-位移
+ ///
+ [SugarColumn(ColumnName = "vibration_displacement")]
+ public decimal VibrationDisplacement { get; set; }
+
+ ///
+ /// 振动-加速度
+ ///
+ [SugarColumn(ColumnName = "vibration_acceleration")]
+ public decimal VibrationAcceleration { get; set; }
+
+ ///
+ /// 振动-温度
+ ///
+ [SugarColumn(ColumnName = "vibration_temp")]
+ public decimal VibrationTemp { get; set; }
+
+
+ ///
+ /// 采集时间
+ ///
+ [SugarColumn(ColumnName="collectTime" )]
+ public DateTime? collectTime { get; set; }
+
+ ///
+ /// 记录时间
+ ///
+ [SplitField]
+ [SugarColumn(ColumnName="recodeTime" )]
+ public DateTime? recordTime { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Model/dto/CommParams.cs b/Sln.Iot.Model/dto/CommParams.cs
new file mode 100644
index 0000000..94a81a3
--- /dev/null
+++ b/Sln.Iot.Model/dto/CommParams.cs
@@ -0,0 +1,100 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Model.dto
+* 唯一标识:CA8D9816-589C-4E15-96FD-CA864799054D
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-04-11 15:10:04
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+namespace Sln.Iot.Model.dto
+{
+ public struct CommParams
+ {
+ ///
+ /// 温度
+ ///
+ public const uint TTempreture = 0x8E50;
+
+ ///
+ /// 湿度
+ ///
+ public const uint Humidity = 0x8E52;
+
+
+ ///
+ /// 噪音
+ ///
+ public const uint Noise = 0x8E53;
+
+ ///
+ /// 振动-速度
+ ///
+ public const uint VibrationSpeed = 0x8E54;
+
+ ///
+ /// 振动-位移
+ ///
+ public const uint VibrationDisplacement = 0x8E55;
+
+ ///
+ /// 振动-加速度
+ ///
+ public const uint VibrationAcceleration = 0x8E56;
+
+ ///
+ /// 振动-温度
+ ///
+ public const uint VibrationTemp = 0x8E57;
+
+ ///
+ /// 采集时间
+ ///
+ public const uint CJSJ = 0x8030;
+
+ #region 电能数据结构体
+
+ public const uint AI = 0x8E21;
+ public const uint BI = 0x8E22;
+ public const uint CI = 0x8E23;
+ public const uint AU = 0x8E11;
+ public const uint BU = 0x8E12;
+ public const uint CU = 0x8E13;
+ public const uint GLYS = 0xB650;
+ public const uint ZXYGZ = 0x9010;
+ public const uint ZXWG = 0x9030;
+ public const uint YGGL = 0xB651;
+ public const uint WGGL = 0xB652;
+
+ #endregion
+
+ #region 流体数据结构体
+
+ public const uint Press = 0x9B00;
+ public const uint STemperature = 0x9B01;
+ public const uint Frequency = 0x9B02;
+ public const uint FluxInstantValue = 0x9B03;
+ public const uint FluxEyeableTotalValue = 0x9B05;
+ public const uint HeatInstantValue = 0x9B06;
+ public const uint HeatToftalValue = 0x9B07;
+ public const uint Density = 0x9B0E;
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Model/dto/ResponsePack.cs b/Sln.Iot.Model/dto/ResponsePack.cs
new file mode 100644
index 0000000..5cd6156
--- /dev/null
+++ b/Sln.Iot.Model/dto/ResponsePack.cs
@@ -0,0 +1,40 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Model.dto
+* 唯一标识:CE889E7E-08A9-4043-A157-32CB2773E568
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-04-11 15:08:47
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+namespace Sln.Iot.Model.dto
+{
+ public class ResponsePack
+ {
+ public byte m_BeginChar = 0x68; //帧头
+ public byte m_EnergyType; //能源类型
+ public byte[] m_Meteraddr = new byte[2];//地址
+ public byte[] m_Msta = new byte[2]; //命令序列号
+ public byte m_StartFlag; //起始符
+ public byte m_MessageType; //控制码
+ public byte[] m_PackLen = new byte[2]; //数据长度
+ public byte m_Verify;
+ public byte m_EndChar = 0x16; //尾盘
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Model/dto/TagInfo.cs b/Sln.Iot.Model/dto/TagInfo.cs
new file mode 100644
index 0000000..93d12da
--- /dev/null
+++ b/Sln.Iot.Model/dto/TagInfo.cs
@@ -0,0 +1,42 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Model.dto
+* 唯一标识:CF7EE865-8FD7-4B6E-BD69-B86E09886CB6
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-04-11 15:10:36
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using System;
+
+namespace Sln.Iot.Model.dto
+{
+ public class TagInfo
+ {
+ public byte[] PC = new byte[2];
+ public int Count { get; set; }
+ public int RSSI{ get; set; }
+ public int Antana{ get; set; }
+ public byte[] EPC{ get; set; }
+ public byte[] Data{ get; set; }
+ public string PCstring = (string) null;
+ public string EPCstring = (string) null;
+ public DateTime Time{ get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Repository/Class1.cs b/Sln.Iot.Repository/Class1.cs
new file mode 100644
index 0000000..e063971
--- /dev/null
+++ b/Sln.Iot.Repository/Class1.cs
@@ -0,0 +1,5 @@
+namespace Sln.Iot.Repository;
+
+public class Class1
+{
+}
\ No newline at end of file
diff --git a/Sln.Iot.Repository/Repository.cs b/Sln.Iot.Repository/Repository.cs
new file mode 100644
index 0000000..80a6ea4
--- /dev/null
+++ b/Sln.Iot.Repository/Repository.cs
@@ -0,0 +1,44 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Repository
+* 唯一标识:130152CF-25A2-4CF6-BF55-FF62811E139D
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-04-11 13:24:59
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using SqlSugar;
+
+namespace Sln.Iot.Repository
+{
+ public class Repository : SimpleClient where T : class, new()
+ {
+ public ITenant itenant = null;//多租户事务、GetConnection、IsAnyConnection等功能
+
+ public Repository(ISqlSugarClient db)
+ {
+ itenant = db.AsTenant();//用来处理事务
+ base.Context = db.AsTenant().GetConnectionScopeWithAttr();//获取子Db
+
+ //如果不想通过注入多个仓储
+ //用到ChangeRepository或者Db.GetMyRepository需要看标题4写法
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Repository/Sln.Iot.Repository.csproj b/Sln.Iot.Repository/Sln.Iot.Repository.csproj
new file mode 100644
index 0000000..a10b9ab
--- /dev/null
+++ b/Sln.Iot.Repository/Sln.Iot.Repository.csproj
@@ -0,0 +1,18 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Sln.Iot.Repository/SqlsugarSetup.cs b/Sln.Iot.Repository/SqlsugarSetup.cs
new file mode 100644
index 0000000..c2b560f
--- /dev/null
+++ b/Sln.Iot.Repository/SqlsugarSetup.cs
@@ -0,0 +1,73 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Repository
+* 唯一标识:EBCC8183-D907-4049-B036-0C5BA2284E22
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-04-11 13:39:23
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using System.Collections.Generic;
+using Microsoft.Extensions.DependencyInjection;
+using Sln.Iot.Config;
+using SqlSugar;
+
+namespace Sln.Iot.Repository
+{
+ public static class SqlsugarSetup
+ {
+ ///
+ /// 注册SqlSugar
+ ///
+ ///
+ public static void AddSqlSugarSetup(this IServiceCollection services)
+ {
+ services.AddSingleton(x =>
+ {
+ var appConfig = x.GetService();
+
+ var connectConfigList = new List();
+ if (appConfig.sqlConfig != null)
+ {
+ foreach (var item in appConfig.sqlConfig)
+ {
+ if (item.isFlag)
+ {
+ var config = new ConnectionConfig()
+ {
+ ConfigId = item.configId,
+ DbType = (DbType)item.dbType,
+ ConnectionString = item.connStr,
+ InitKeyType = InitKeyType.Attribute,
+ IsAutoCloseConnection = true,
+ };
+ connectConfigList.Add(config);
+ }
+ }
+ }
+ SqlSugarScope Db = new SqlSugarScope(connectConfigList, db =>
+ {
+ db.Aop.OnLogExecuting = (sql, pars) => { };
+ });
+
+ return Db;
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Repository/service/.DS_Store b/Sln.Iot.Repository/service/.DS_Store
new file mode 100644
index 0000000..b71960d
Binary files /dev/null and b/Sln.Iot.Repository/service/.DS_Store differ
diff --git a/Sln.Iot.Repository/service/IBaseMonitorInfoService.cs b/Sln.Iot.Repository/service/IBaseMonitorInfoService.cs
new file mode 100644
index 0000000..8b292ed
--- /dev/null
+++ b/Sln.Iot.Repository/service/IBaseMonitorInfoService.cs
@@ -0,0 +1,35 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Repository.service
+* 唯一标识:9B119436-8BE4-4693-9D28-F971874E03CB
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-04-11 13:27:35
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using Sln.Iot.Model.dao;
+using Sln.Iot.Repository.service.@base;
+
+namespace Sln.Iot.Repository.service
+{
+ public interface IBaseMonitorInfoService : IBaseService
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Repository/service/IRecordDnbInstantService.cs b/Sln.Iot.Repository/service/IRecordDnbInstantService.cs
new file mode 100644
index 0000000..06932fd
--- /dev/null
+++ b/Sln.Iot.Repository/service/IRecordDnbInstantService.cs
@@ -0,0 +1,42 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Repository.service
+* 唯一标识:D397E4B7-48E1-4BF3-8906-B11F96EE8B42
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-05-20 11:26:07
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using System.Collections.Generic;
+using Sln.Iot.Model.dao;
+using Sln.Iot.Repository.service.@base;
+
+namespace Sln.Iot.Repository.service
+{
+ public interface IRecordDnbInstantService:IBaseService
+ {
+ ///
+ /// 分表保存
+ ///
+ ///
+ ///
+ ///
+ bool SplitInsert(List list,out List insertIds);
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Repository/service/IRecordFluidInstantService.cs b/Sln.Iot.Repository/service/IRecordFluidInstantService.cs
new file mode 100644
index 0000000..06ed4b0
--- /dev/null
+++ b/Sln.Iot.Repository/service/IRecordFluidInstantService.cs
@@ -0,0 +1,42 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Repository.service
+* 唯一标识:6403A242-FF9C-4942-B02B-8680BBD7ACBD
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-05-20 14:46:25
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using System.Collections.Generic;
+using Sln.Iot.Model.dao;
+using Sln.Iot.Repository.service.@base;
+
+namespace Sln.Iot.Repository.service
+{
+ public interface IRecordFluidInstantService:IBaseService
+ {
+ ///
+ /// 分表保存
+ ///
+ ///
+ ///
+ ///
+ bool SplitInsert(List list,out List insertIds);
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Repository/service/IRecordIotEnvInstantService.cs b/Sln.Iot.Repository/service/IRecordIotEnvInstantService.cs
new file mode 100644
index 0000000..f9f7cd2
--- /dev/null
+++ b/Sln.Iot.Repository/service/IRecordIotEnvInstantService.cs
@@ -0,0 +1,42 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Repository.service
+* 唯一标识:44931288-195F-4560-B9D8-9EA8A511FE8A
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-04-11 15:44:29
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using System.Collections.Generic;
+using Sln.Iot.Model.dao;
+using Sln.Iot.Repository.service.@base;
+
+namespace Sln.Iot.Repository.service
+{
+ public interface IRecordIotEnvInstantService:IBaseService
+ {
+ ///
+ /// 分表保存
+ ///
+ ///
+ ///
+ ///
+ bool SplitInsert(List list,out List insertIds);
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Repository/service/Impl/BaseMonitorInfoServiceImpl.cs b/Sln.Iot.Repository/service/Impl/BaseMonitorInfoServiceImpl.cs
new file mode 100644
index 0000000..33c5365
--- /dev/null
+++ b/Sln.Iot.Repository/service/Impl/BaseMonitorInfoServiceImpl.cs
@@ -0,0 +1,37 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Repository.service.Impl
+* 唯一标识:625A971B-5BA8-4E05-9AE1-DC6D8E3D6051
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-04-11 13:28:02
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using Sln.Iot.Model.dao;
+using Sln.Iot.Repository.service.@base;
+
+namespace Sln.Iot.Repository.service.Impl
+{
+ public class BaseMonitorInfoServiceImpl : BaseServiceImpl, IBaseMonitorInfoService
+ {
+ public BaseMonitorInfoServiceImpl(Repository repository):base(repository)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Repository/service/Impl/RecordDnbInstantServiceImpl.cs b/Sln.Iot.Repository/service/Impl/RecordDnbInstantServiceImpl.cs
new file mode 100644
index 0000000..e49b220
--- /dev/null
+++ b/Sln.Iot.Repository/service/Impl/RecordDnbInstantServiceImpl.cs
@@ -0,0 +1,73 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Repository.service.Impl
+* 唯一标识:EF060FA7-6D52-478C-84FF-F26EEC206685
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-05-20 11:26:53
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using System;
+using System.Collections.Generic;
+using Sln.Iot.Model.dao;
+using Sln.Iot.Repository.service.@base;
+
+namespace Sln.Iot.Repository.service.Impl
+{
+ public class RecordDnbInstantServiceImpl: BaseServiceImpl, IRecordDnbInstantService
+ {
+ public RecordDnbInstantServiceImpl(Repository rep) : base(rep)
+ {
+ }
+
+ ///
+ /// 分表保存
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public bool SplitInsert(List list,out List insertIds)
+ {
+ if (list == null)
+ {
+ throw new ArgumentNullException($"参数为空");
+ }
+ try
+ {
+
+ // _rep.AsTenant().BeginTran();
+
+ var sqlSugarClient = _rep.Context;
+ //加载指定分表策略
+ //sqlSugarClient.CurrentConnectionConfig.ConfigureExternalServices.SplitTableService = new MonitorIdToSplitService();
+ insertIds = sqlSugarClient.Insertable(list).SplitTable().ExecuteReturnSnowflakeIdList();
+
+ // _rep.AsTenant().CommitTran();
+ return true;
+ }
+ catch (Exception ex)
+ {
+ // _rep.AsTenant().RollbackTran();
+ throw new InvalidOperationException($"电能数据分表保存异常:{ex.Message}");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Repository/service/Impl/RecordFluidInstantServiceImpl.cs b/Sln.Iot.Repository/service/Impl/RecordFluidInstantServiceImpl.cs
new file mode 100644
index 0000000..e3bdcb8
--- /dev/null
+++ b/Sln.Iot.Repository/service/Impl/RecordFluidInstantServiceImpl.cs
@@ -0,0 +1,73 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Repository.service.Impl
+* 唯一标识:72B88660-5410-4016-9E12-B1E11841AB4B
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-05-20 14:47:03
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using System;
+using System.Collections.Generic;
+using Sln.Iot.Model.dao;
+using Sln.Iot.Repository.service.@base;
+
+namespace Sln.Iot.Repository.service.Impl
+{
+ public class RecordFluidInstantServiceImpl: BaseServiceImpl, IRecordFluidInstantService
+ {
+ public RecordFluidInstantServiceImpl(Repository rep) : base(rep)
+ {
+ }
+
+ ///
+ /// 分表保存
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public bool SplitInsert(List list,out List insertIds)
+ {
+ if (list == null)
+ {
+ throw new ArgumentNullException($"参数为空");
+ }
+ try
+ {
+
+ // _rep.AsTenant().BeginTran();
+
+ var sqlSugarClient = _rep.Context;
+ //加载指定分表策略
+ //sqlSugarClient.CurrentConnectionConfig.ConfigureExternalServices.SplitTableService = new MonitorIdToSplitService();
+ insertIds = sqlSugarClient.Insertable(list).SplitTable().ExecuteReturnSnowflakeIdList();
+
+ // _rep.AsTenant().CommitTran();
+ return true;
+ }
+ catch (Exception ex)
+ {
+ // _rep.AsTenant().RollbackTran();
+ throw new InvalidOperationException($"流体数据分表保存异常:{ex.Message}");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Repository/service/Impl/RecordIotEnvInstantServiceImpl.cs b/Sln.Iot.Repository/service/Impl/RecordIotEnvInstantServiceImpl.cs
new file mode 100644
index 0000000..46a527c
--- /dev/null
+++ b/Sln.Iot.Repository/service/Impl/RecordIotEnvInstantServiceImpl.cs
@@ -0,0 +1,74 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Repository.service.Impl
+* 唯一标识:C914F6F6-C7CC-4DDC-B061-C89A15419EF0
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-04-11 15:44:49
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using System;
+using System.Collections.Generic;
+using Sln.Iot.Model.dao;
+using Sln.Iot.Repository.service.@base;
+using Sln.Iot.Repository.service.split;
+
+namespace Sln.Iot.Repository.service.Impl
+{
+ public class RecordIotEnvInstantServiceImpl: BaseServiceImpl, IRecordIotEnvInstantService
+ {
+ public RecordIotEnvInstantServiceImpl(Repository rep) : base(rep)
+ {
+ }
+
+ ///
+ /// 分表保存
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public bool SplitInsert(List list,out List insertIds)
+ {
+ if (list == null)
+ {
+ throw new ArgumentNullException($"参数为空");
+ }
+ try
+ {
+
+ // _rep.AsTenant().BeginTran();
+
+ var sqlSugarClient = _rep.Context;
+ //加载指定分表策略
+ //sqlSugarClient.CurrentConnectionConfig.ConfigureExternalServices.SplitTableService = new MonitorIdToSplitService();
+ insertIds = sqlSugarClient.Insertable(list).SplitTable().ExecuteReturnSnowflakeIdList();
+
+ // _rep.AsTenant().CommitTran();
+ return true;
+ }
+ catch (Exception ex)
+ {
+ // _rep.AsTenant().RollbackTran();
+ throw new InvalidOperationException($"物联网数据分表保存异常:{ex.Message}");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Repository/service/base/BaseServiceImpl.cs b/Sln.Iot.Repository/service/base/BaseServiceImpl.cs
new file mode 100644
index 0000000..2874397
--- /dev/null
+++ b/Sln.Iot.Repository/service/base/BaseServiceImpl.cs
@@ -0,0 +1,359 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Repository.service.base
+* 唯一标识:AAD164C5-C115-422B-B57B-E9669385D083
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-04-11 13:26:34
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+using SqlSugar;
+
+namespace Sln.Iot.Repository.service.@base
+{
+ public class BaseServiceImpl : IBaseService where T : class, new()
+ {
+ public readonly Repository _rep;
+
+ public BaseServiceImpl(Repository rep)
+ {
+ _rep = rep;
+ }
+
+ ///
+ /// 添加实体信息
+ ///
+ ///
+ ///
+ ///
+ ///
+ public bool Insert(T model)
+ {
+ if (model == null)
+ {
+ throw new ArgumentNullException($"添加实体信息异常:实体参数为空");
+ }
+
+ try
+ {
+ return _rep.CopyNew().Insert(model);
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException($"添加实体信息异常:{ex.Message}");
+ }
+
+ }
+
+ ///
+ /// 批量添加实体集合
+ ///
+ ///
+ ///
+ ///
+ ///
+ public bool Insert(List lisT)
+ {
+ if (lisT == null)
+ {
+ throw new ArgumentNullException($"批量添加实体集合异常:实体集合参数为空");
+ }
+ try
+ {
+
+ // _rep.AsTenant().BeginTran();
+ var info = _rep.CopyNew().InsertRange(lisT);
+ // _rep.AsTenant().CommitTran();
+ return true;
+ }
+ catch (Exception ex)
+ {
+ // _rep.AsTenant().RollbackTran();
+ throw new InvalidOperationException($"批量添加实体集合异常:{ex.Message}");
+ }
+ }
+
+ ///
+ /// 根据id 删除信息
+ ///
+ ///
+ ///
+ ///
+ public bool DeleteById(object id)
+ {
+ if (id == null)
+ {
+ throw new ArgumentNullException($"根据id删除信息异常:Id参数为空");
+ }
+ try
+ {
+ return _rep.DeleteById(id);
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException($"根据id删除信息异常:{ex.Message}");
+ }
+ }
+
+ ///
+ /// 根据实体删除信息
+ ///
+ ///
+ ///
+ ///
+ ///
+ public bool Delete(T model)
+ {
+ if (model == null)
+ {
+ throw new ArgumentNullException($"根据实体删除信息异常:实体参数为空");
+ }
+ try
+ {
+ return _rep.DeleteById(model);
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException($"根据实体删除信息异常:{ex.Message}");
+ }
+ }
+
+ ///
+ /// 根据实体集合批量删除信息
+ ///
+ ///
+ ///
+ ///
+ public bool Deletes(List entitys)
+ {
+ if (entitys == null)
+ {
+ throw new ArgumentNullException($"根据实体集合批量删除信息异常:实体集合参数为空");
+ }
+ try
+ {
+ return _rep.Delete(entitys);
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException($"根据实体集合批量删除信息异常:{ex.Message}");
+ }
+ }
+
+ ///
+ /// 根据实体更新信息
+ ///
+ ///
+ ///
+ ///
+ public bool Update(T model)
+ {
+ if (model == null)
+ {
+ throw new ArgumentNullException($"根据实体更新信息异常:实体参数为空");
+ }
+ try
+ {
+ return _rep.Update(model);
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException($"根据实体更新信息异常:{ex.Message}");
+ }
+ }
+
+ ///
+ /// 批量更新实体集合信息
+ ///
+ ///
+ ///
+ ///
+ public bool Update(List entitys)
+ {
+ if (entitys == null)
+ {
+ throw new ArgumentNullException($"批量更新实体集合信息异常:实体集合参数为空");
+ }
+
+ try
+ {
+ return _rep.UpdateRange(entitys);
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException($"批量更新实体集合信息异常:{ex.Message}");
+ }
+ }
+
+ ///
+ /// 根据Where条件更新实体信息
+ ///
+ ///
+ ///
+ ///
+ public bool Update(T entity, string strWhere)
+ {
+ if (entity == null)
+ {
+ throw new ArgumentNullException($"根据Where条件更新实体信息异常:实体参数为空");
+ }
+
+ if (string.IsNullOrEmpty(strWhere))
+ {
+ throw new ArgumentNullException($"根据Where条件更新实体信息异常:Where参数为空");
+ }
+
+ try
+ {
+ return _rep.AsUpdateable(entity).Where(strWhere).ExecuteCommandHasChange();
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException($"根据Where条件更新实体信息异常:{ex.Message}");
+ }
+ }
+
+ ///
+ /// 根据实体更新指定列
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public bool Update(T entity, List lstColumns = null, List lstIgnoreColumns = null, string strWhere = "")
+ {
+ try
+ {
+ IUpdateable up = _rep.AsUpdateable(entity);
+ if (lstIgnoreColumns != null && lstIgnoreColumns.Count > 0)
+ {
+ up = up.IgnoreColumns(lstIgnoreColumns.ToArray());
+ }
+ if (lstColumns != null && lstColumns.Count > 0)
+ {
+ up = up.UpdateColumns(lstColumns.ToArray());
+ }
+ if (!string.IsNullOrEmpty(strWhere))
+ {
+ up = up.Where(strWhere);
+ }
+ return up.ExecuteCommandHasChange();
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException($"根据实体更新指定列异常:{ex.Message}");
+ }
+ }
+
+ ///
+ /// 查询所有信息
+ ///
+ ///
+ ///
+ public List Query()
+ {
+ try
+ {
+ return _rep.GetList();
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException($"查询所有信息异常:{ex.Message}");
+ }
+ }
+
+ ///
+ /// 根据Id查询实体
+ ///
+ ///
+ ///
+ ///
+ public T Query(object objId)
+ {
+ if (objId == null)
+ {
+ throw new ArgumentNullException($"根据Id查询实体信息异常:Id参数为空");
+ }
+ try
+ {
+ return _rep.GetById(objId);
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException($"根据Id查询实体信息异常:{ex.Message}");
+ }
+ }
+
+ ///
+ /// 根据表达式查询
+ ///
+ ///
+ ///
+ ///
+ public List Query(Expression> whereExpression)
+ {
+ if (whereExpression == null)
+ {
+ throw new ArgumentNullException($"根据表达式查询实体信息异常:表达式参数为空");
+ }
+ try
+ {
+ return _rep.GetList(whereExpression);
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException($"根据表达式查询实体信息异常:{ex.Message}");
+ }
+ }
+
+ ///
+ /// 根据表达式排序查询
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public List Query(Expression> whereExpression, Expression> orderByExpression, bool isAsc = true)
+ {
+ if (whereExpression == null)
+ {
+ throw new ArgumentNullException($"根据表达式排序查询信息异常:条件表达式参数为空");
+ }
+
+ if (orderByExpression == null)
+ {
+ throw new ArgumentNullException($"根据表达式排序查询信息异常:排序表达式参数为空");
+ }
+
+ try
+ {
+ return _rep.AsQueryable().OrderByIF(orderByExpression != null, orderByExpression, isAsc ? OrderByType.Asc : OrderByType.Desc).WhereIF(whereExpression != null, whereExpression).ToList();
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException($"根据表达式排序查询信息异常:{ex.Message}");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Repository/service/base/IBaseService.cs b/Sln.Iot.Repository/service/base/IBaseService.cs
new file mode 100644
index 0000000..ce2664a
--- /dev/null
+++ b/Sln.Iot.Repository/service/base/IBaseService.cs
@@ -0,0 +1,130 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Repository.service.base
+* 唯一标识:4F2637EA-9206-45C6-92B8-E2CDBA5A1B22
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-04-11 13:26:02
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+
+namespace Sln.Iot.Repository.service.@base
+{
+ public interface IBaseService where T : class
+ {
+ ///
+ /// 添加实体信息
+ ///
+ ///
+ ///
+ bool Insert(T model);
+
+ ///
+ /// 批量添加实体集合
+ ///
+ ///
+ ///
+ bool Insert(List lisT);
+
+ ///
+ /// 根据id 删除信息
+ ///
+ ///
+ ///
+ bool DeleteById(object id);
+
+ ///
+ /// 根据实体删除信息
+ ///
+ ///
+ ///
+ bool Delete(T model);
+
+ ///
+ /// 根据实体集合批量删除信息
+ ///
+ ///
+ ///
+ bool Deletes(List entitys);
+
+ ///
+ /// 根据实体更新信息
+ ///
+ ///
+ ///
+ bool Update(T model);
+
+ ///
+ /// 批量更新实体集合信息
+ ///
+ ///
+ ///
+ bool Update(List entitys);
+
+ ///
+ /// 根据Where条件更新实体信息
+ ///
+ ///
+ ///
+ ///
+ bool Update(T entity, string strWhere);
+
+ ///
+ /// 根据实体更新指定列
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ bool Update(T entity, List lstColumns = null, List lstIgnoreColumns = null, string strWhere = "");
+
+ ///
+ /// 查询所有信息
+ ///
+ ///
+ List Query();
+
+ ///
+ /// 根据Id查询实体
+ ///
+ ///
+ ///
+ T Query(object objId);
+
+ ///
+ /// 根据表达式查询
+ ///
+ ///
+ ///
+ List Query(Expression> whereExpression);
+
+ ///
+ /// 根据表达式排序查询
+ ///
+ /// 查询条件
+ /// 排序条件
+ /// 是否正序
+ ///
+ List Query(Expression> whereExpression, Expression> orderByExpression, bool isAsc = true);
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Repository/service/split/MonitorIdToSplitService.cs b/Sln.Iot.Repository/service/split/MonitorIdToSplitService.cs
new file mode 100644
index 0000000..fbe1db9
--- /dev/null
+++ b/Sln.Iot.Repository/service/split/MonitorIdToSplitService.cs
@@ -0,0 +1,97 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Repository.service.split
+* 唯一标识:2D1DE17A-79B9-48D8-BB98-60E89BEC711A
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-04-27 10:10:14
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using SqlSugar;
+
+namespace Sln.Iot.Repository.service.split
+{
+ ///
+ /// 自定义分表策略:根据传感器 ID 进行分表
+ ///
+ public class MonitorIdToSplitService:ISplitTableService
+ {
+ ///
+ /// 返回数据库中所有分表
+ ///
+ ///
+ ///
+ ///
+ ///
+ public List GetAllTables(ISqlSugarClient db, EntityInfo EntityInfo, List tableInfos)
+ {
+ List result = new List();
+ foreach (var item in tableInfos)
+ {
+ if (item.Name.Contains("record_iotenv_instant")) //区分标识如果不用正则符复杂一些,防止找错表
+ {
+ SplitTableInfo data = new SplitTableInfo()
+ {
+ TableName = item.Name //要用item.name不要写错了
+ };
+ result.Add(data);
+ }
+ }
+ return result.OrderBy(it=>it.TableName).ToList();//打断点看一下有没有查出所有分表
+ }
+
+ ///
+ /// 获取分表字段的值
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public object GetFieldValue(ISqlSugarClient db, EntityInfo entityInfo, SplitType splitType, object entityValue)
+ {
+ var splitColumn = entityInfo.Columns.FirstOrDefault(it => it.PropertyInfo.GetCustomAttribute() != null);
+ var value = splitColumn.PropertyInfo.GetValue(entityValue, null);
+ return value;
+ }
+ ///
+ /// 默认表名
+ ///
+ ///
+ ///
+ ///
+ public string GetTableName(ISqlSugarClient db, EntityInfo entityInfo)
+ {
+ return entityInfo.DbTableName;
+ }
+
+ public string GetTableName(ISqlSugarClient db, EntityInfo entityInfo, SplitType type)
+ {
+ return entityInfo.DbTableName;//目前模式少不需要分类(自带的有 日、周、月、季、年等进行区分)
+ }
+
+ public string GetTableName(ISqlSugarClient db, EntityInfo entityInfo, SplitType splitType, object fieldValue)
+ {
+ return entityInfo.DbTableName + "_"+fieldValue; //根据值按首字母
+ }
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Serilog/Class1.cs b/Sln.Iot.Serilog/Class1.cs
new file mode 100644
index 0000000..4416261
--- /dev/null
+++ b/Sln.Iot.Serilog/Class1.cs
@@ -0,0 +1,5 @@
+namespace Sln.Iot.Serilog;
+
+public class Class1
+{
+}
\ No newline at end of file
diff --git a/Sln.Iot.Serilog/SerilogExtensions.cs b/Sln.Iot.Serilog/SerilogExtensions.cs
new file mode 100644
index 0000000..48ca446
--- /dev/null
+++ b/Sln.Iot.Serilog/SerilogExtensions.cs
@@ -0,0 +1,65 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Serilog
+* 唯一标识:77C04261-6831-4763-A6E1-C6B2B66D4DD9
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-04-11 11:12:30
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using System;
+using System.IO;
+using Microsoft.Extensions.DependencyInjection;
+using Serilog;
+using Sln.Iot.Config;
+
+namespace Sln.Iot.Serilog
+{
+ public static class SerilogExtensions
+ {
+ public static void UseSerilogExtensions(this IServiceProvider service)
+ {
+ //启用Serilog中间件
+
+
+ #region 通过配置文件读取日志存放位置
+ var appConfig = service.GetService();
+ var logPath = Path.Combine(appConfig.logPath, "Logs");
+ #endregion
+
+ Log.Logger = new LoggerConfiguration().MinimumLevel.Information().WriteTo.Console()
+ .WriteTo.Logger(lc => lc
+ .Filter.ByIncludingOnly(logEvent => logEvent.Properties.ContainsKey("Module") && logEvent.Properties["Module"].ToString().Contains("Info"))
+ .WriteTo.File(Path.Combine($"{logPath}/Info/", "Info.log"), rollingInterval: RollingInterval.Day))
+ .WriteTo.Logger(lc => lc
+ .Filter.ByIncludingOnly(logEvent => logEvent.Properties.ContainsKey("Module") && logEvent.Properties["Module"].ToString().Contains("Plc"))
+ .WriteTo.File(Path.Combine($"{logPath}/Plc/", "Plc.log"), rollingInterval: RollingInterval.Day))
+ .WriteTo.Logger(lc => lc
+ .Filter.ByIncludingOnly(logEvent => logEvent.Properties.ContainsKey("Module") && logEvent.Properties["Module"].ToString().Contains("Camera"))
+ .WriteTo.File(Path.Combine($"{logPath}/Camera/", "Camera.log"), rollingInterval: RollingInterval.Day))
+ .WriteTo.Logger(lc => lc
+ .Filter.ByIncludingOnly(logEvent => logEvent.Properties.ContainsKey("Module") && logEvent.Properties["Module"].ToString().Contains("Error"))
+ .WriteTo.File(Path.Combine($"{logPath}/Error/", "Error.log"), rollingInterval: RollingInterval.Day))
+ .CreateLogger();
+
+
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Serilog/SerilogHelper.cs b/Sln.Iot.Serilog/SerilogHelper.cs
new file mode 100644
index 0000000..7a00349
--- /dev/null
+++ b/Sln.Iot.Serilog/SerilogHelper.cs
@@ -0,0 +1,105 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Serilog
+* 唯一标识:15731D3E-0D48-41B6-B77B-A4CC592B4939
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-04-11 11:09:14
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using System;
+using Serilog;
+
+namespace Sln.Iot.Serilog
+{
+ public class SerilogHelper
+ {
+ private readonly ILogger? Info_logger = Log.ForContext("Module", "Info");
+ private readonly ILogger? Plc_logger = Log.ForContext("Module", "Plc");
+ private readonly ILogger? Error_logger = Log.ForContext("Module", "Error");
+ private readonly ILogger? Camera_logger = Log.ForContext("Module", "Camera");
+
+ ///
+ /// Info日志
+ ///
+ ///
+ public void Info(string msg)
+ {
+ if (Info_logger != null)
+ {
+ this.Info_logger.Information(msg);
+ }
+ }
+
+ ///
+ /// Plc日志
+ ///
+ ///
+ public void Plc(string msg)
+ {
+ if (Plc_logger != null)
+ {
+ this.Plc_logger.Information(msg);
+ }
+ }
+
+ ///
+ /// 相机日志
+ ///
+ ///
+ public void Camera(string msg)
+ {
+ if (Camera_logger != null)
+ {
+ this.Camera_logger.Information(msg);
+ }
+ }
+
+ ///
+ /// Error日志
+ ///
+ ///
+ ///
+ public void Error(string msg, Exception ex = null)
+ {
+ if (!string.IsNullOrEmpty(msg) && ex == null)
+ {
+ this.Error_logger.Information("【附加信息】 : {0}
", new object[] { msg });
+ }
+ else if (!string.IsNullOrEmpty(msg) && ex != null)
+ {
+ string errorMsg = BeautyErrorMsg(ex);
+ this.Error_logger.Information("【附加信息】 : {0}
{1}", new object[] { msg, errorMsg });
+ }
+ else if (string.IsNullOrEmpty(msg) && ex != null)
+ {
+ string errorMsg = BeautyErrorMsg(ex);
+ this.Error_logger.Information(errorMsg);
+ }
+ }
+
+ private string BeautyErrorMsg(Exception ex)
+ {
+ string errorMsg = string.Format("【异常类型】:{0}
【异常信息】:{1}
【堆栈调用】:{2}", new object[] { ex.GetType().Name, ex.Message, ex.StackTrace });
+ errorMsg = errorMsg.Replace("\r\n", "
");
+ errorMsg = errorMsg.Replace("位置", "位置");
+ return errorMsg;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Serilog/Sln.Iot.Serilog.csproj b/Sln.Iot.Serilog/Sln.Iot.Serilog.csproj
new file mode 100644
index 0000000..b540308
--- /dev/null
+++ b/Sln.Iot.Serilog/Sln.Iot.Serilog.csproj
@@ -0,0 +1,18 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Sln.Iot.Socket/Adapter/BufferRequestInfo.cs b/Sln.Iot.Socket/Adapter/BufferRequestInfo.cs
new file mode 100644
index 0000000..2993e0b
--- /dev/null
+++ b/Sln.Iot.Socket/Adapter/BufferRequestInfo.cs
@@ -0,0 +1,72 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Socket.Adapter
+* 唯一标识:8A1D4D97-E419-4A49-B921-7FF76B190F45
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-04-11 13:55:38
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using TouchSocket.Core;
+
+namespace Sln.Iot.Socket.Adapter
+{
+ public class BufferRequestInfo: IRequestInfo
+ {
+ ///
+ /// 帧头 0x68 1个字
+ ///
+ public byte[] header { get; internal set; }
+
+ ///
+ /// 采集设备编号,由采集器类型(1个字)、采集器地址(2个字)组成
+ ///
+ public string ColletEquipCode { get; internal set; }
+
+ ///
+ /// 自定义属性,DataType
+ ///
+ public byte DataType { get; internal set; }
+
+ ///
+ /// Buffer长度
+ ///
+ public int BufferLength { get; internal set; }
+
+ ///
+ /// 内容体
+ ///
+ public byte[] Body { get; internal set; }
+
+ ///
+ /// 校验位 1个字:从帧头到数据累加CS校验
+ ///
+ public byte CheckBit { get; internal set; }
+
+ ///
+ /// 帧尾 0x16 1个字
+ ///
+ public byte[] Tail { get; internal set; }
+
+ ///
+ /// 原始Buffer
+ ///
+ public ByteBlock buffer { get; internal set; }
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Socket/Adapter/CustomDataHandlingAdapter.cs b/Sln.Iot.Socket/Adapter/CustomDataHandlingAdapter.cs
new file mode 100644
index 0000000..a08238c
--- /dev/null
+++ b/Sln.Iot.Socket/Adapter/CustomDataHandlingAdapter.cs
@@ -0,0 +1,117 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Socket.Adapter
+* 唯一标识:50003A25-42CE-44A7-9940-FFDE3BD0A52A
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-04-11 13:56:24
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using System;
+using System.Text;
+using TouchSocket.Core;
+
+namespace Sln.Iot.Socket.Adapter
+{
+ public class CustomDataHandlingAdapter:CustomDataHandlingAdapter
+ {
+ protected override FilterResult Filter(in ByteBlock byteBlock, bool beCached, ref BufferRequestInfo request, ref int tempCapacity)
+ {
+ CacheTimeoutEnable = true;
+ CacheTimeout = new TimeSpan(0, 0, 0, 0, 5000);
+ int pos = byteBlock.Pos;
+ try
+ {
+ if (byteBlock.CanReadLen < 5)
+ {
+ return FilterResult.Cache;
+ }
+
+ byteBlock.Read(out byte[] header, 1);
+
+ byteBlock.Read(out byte[] deviceType, 1);
+
+ byteBlock.Read(out byte[] deviceId, 2);
+
+ string DeviceType = Encoding.ASCII.GetString(deviceType);
+ string collectEquipCode = DeviceType + this.ConverToString(deviceId);
+
+ byteBlock.Pos += 3;
+
+ byteBlock.Read(out byte[] dataType, 1);
+
+ byteBlock.Read(out byte[] lengthByte, 2);
+
+ string hexString = BitConverter.ToString(lengthByte).Replace("-", "");
+ int bodyLength = Convert.ToInt32(hexString, 16);
+
+ if (bodyLength > byteBlock.CanReadLen)
+ {
+ byteBlock.Pos = pos; //body数据不足。回退游标
+ return FilterResult.Cache;
+ }
+ else
+ {
+ byteBlock.Read(out byte[] body, bodyLength);
+ byteBlock.Read(out byte[] check, 1);
+ byteBlock.Read(out byte[] tail, 1);
+
+ request = new BufferRequestInfo()
+ {
+ header = header,
+ ColletEquipCode = collectEquipCode,
+ DataType = dataType[0],
+ BufferLength = bodyLength,
+ Body = body,
+ CheckBit = check[0],
+ Tail = tail,
+ buffer = byteBlock
+ };
+
+ return FilterResult.Success;
+ }
+ }catch (Exception ex)
+ {
+ Logger.Error("FilterResult"+ex.Message);
+ byteBlock.Pos = pos; //body数据不足。回退游标
+ return FilterResult.Cache;
+ }
+
+ }
+
+ private string ConverToString(byte[] data)
+ {
+ string str;
+ StringBuilder stb = new StringBuilder();
+ for (int i = 0; i < data.Length; i++)
+ {
+ if ((int)data[i] > 15)
+ {
+ stb.Append(Convert.ToString(data[i], 16).ToUpper()); //添加字符串
+ }
+ else //如果是小于0F需要加个零
+ {
+ stb.Append("0" + Convert.ToString(data[i], 16).ToUpper());
+ }
+ }
+ str = stb.ToString();
+ return str;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.Socket/Class1.cs b/Sln.Iot.Socket/Class1.cs
new file mode 100644
index 0000000..3660e6e
--- /dev/null
+++ b/Sln.Iot.Socket/Class1.cs
@@ -0,0 +1,5 @@
+namespace Sln.Iot.Socket;
+
+public class Class1
+{
+}
\ No newline at end of file
diff --git a/Sln.Iot.Socket/Sln.Iot.Socket.csproj b/Sln.Iot.Socket/Sln.Iot.Socket.csproj
new file mode 100644
index 0000000..0990bfc
--- /dev/null
+++ b/Sln.Iot.Socket/Sln.Iot.Socket.csproj
@@ -0,0 +1,17 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Sln.Iot.Socket/TcpServer.cs b/Sln.Iot.Socket/TcpServer.cs
new file mode 100644
index 0000000..87e3e2a
--- /dev/null
+++ b/Sln.Iot.Socket/TcpServer.cs
@@ -0,0 +1,127 @@
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2025 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:Mr.Wen's MacBook Pro
+* 命名空间:Sln.Iot.Socket
+* 唯一标识:6D821766-EAFA-4C51-A757-8786E77645AC
+*
+* 创建者:WenJY
+* 电子邮箱:
+* 创建时间:2025-04-11 13:51:11
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+using System;
+using Sln.Iot.Serilog;
+using Sln.Iot.Socket.Adapter;
+using TouchSocket.Core;
+using TouchSocket.Sockets;
+
+namespace Sln.Iot.Socket
+{
+ public class TcpServer
+ {
+ private readonly SerilogHelper _logger;
+ private readonly TcpService _service;
+
+ public TcpServer(SerilogHelper logger, TcpService service)
+ {
+ _logger = logger;
+ _service = service;
+ }
+
+ ///
+ /// 接收客户端指令委托
+ ///
+ public delegate void ReceivedClientBuffer(byte[] buffer);
+ public event ReceivedClientBuffer? ReceivedClientBufferEvent;
+
+ public delegate void RefreshClientInfo(TcpService tcpService);
+ public event RefreshClientInfo? RefreshClientInfoEvent;
+
+ [Obsolete("Obsolete")]
+ public delegate void ReceivedBufferRequestInfo(SocketClient client,BufferRequestInfo requestInfo);
+ public event ReceivedBufferRequestInfo ReceivedBufferRequestInfoEvent;
+
+ public void Init(int serverPort)
+ {
+ try
+ {
+ _service.Connecting = (client, e) => {
+ _logger.Info($"客户端{client.IP}正在接入服务");
+ return EasyTask.CompletedTask;
+ };
+ _service.Connected = (client, e) => {
+ _logger.Info($"客户端{client.IP}接入服务成功");
+ RefreshClientInfoEvent?.Invoke(_service);
+ return EasyTask.CompletedTask;
+ };
+ _service.Disconnected = (client, e) => {
+ _logger.Info($"客户端{client.IP}断开连接");
+ RefreshClientInfoEvent?.Invoke(_service);
+ return EasyTask.CompletedTask;
+ };
+ _service.Received = (client, e) =>
+ {
+ if (e.RequestInfo is BufferRequestInfo request)
+ {
+ string msg = $"收到客户端:{client.Id};指令====>>>>Header:{BitConverter.ToString(request.header).Replace("-", "")};DataType:{request.DataType.ToString("X2")};BufferLength:{request.BufferLength};Body:{BitConverter.ToString(request.Body).Replace("-", "")};CheckBit:{request.CheckBit.ToString("X2")};Tail:{BitConverter.ToString(request.Tail).Replace("-", "")};";
+
+ _logger.Info($"{msg}");
+
+ ReceivedBufferRequestInfoEvent?.Invoke(client,request);
+
+
+ }
+
+ return EasyTask.CompletedTask;
+ };
+
+ _service.Setup(new TouchSocketConfig()//载入配置
+ .SetListenIPHosts(new IPHost[] { new IPHost($"0.0.0.0:{serverPort}") })
+ .SetTcpDataHandlingAdapter(() => new CustomDataHandlingAdapter())
+ .ConfigureContainer(a =>//容器的配置顺序应该在最前面
+ {
+
+ a.AddConsoleLogger();
+ })
+ .ConfigurePlugins(a =>
+ {
+ //自定义插件
+ }));
+ _service.Start();
+ _logger.Info($"TcpServer启动成功,监听端口:{serverPort}");
+ }
+ catch (Exception ex)
+ {
+ //throw new InvalidOperationException($"TcpServer启动异常:{ex.Message}");
+ _logger.Error($"TcpServer启动异常:{ex.Message}");
+ }
+
+ }
+
+ ///
+ /// 向所有客户端发送心跳
+ ///
+ public void SendHeartBeat()
+ {
+ var clients = _service.SocketClients.GetClients();
+ foreach (var item in clients)
+ {
+ _service.Send(item.Id,"heartbeat");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot.sln b/Sln.Iot.sln
new file mode 100644
index 0000000..c7f584f
--- /dev/null
+++ b/Sln.Iot.sln
@@ -0,0 +1,67 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.9.34714.143
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sln.Iot", "Sln.Iot\Sln.Iot.csproj", "{2140AD68-D4CE-44EC-B9D3-20D18EB59F9D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sln.Iot.Business", "Sln.Iot.Business\Sln.Iot.Business.csproj", "{F59EB67D-66FD-43B9-B6CC-46BF25202C21}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sln.Iot.Config", "Sln.Iot.Config\Sln.Iot.Config.csproj", "{2E10DED8-5F53-4ED9-892F-B0007B85806E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sln.Iot.Common", "Sln.Iot.Common\Sln.Iot.Common.csproj", "{899D8A81-D3E3-4599-8A8C-D60280A777F3}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sln.Iot.Model", "Sln.Iot.Model\Sln.Iot.Model.csproj", "{503E7EAE-6323-4CE2-AAE4-C6A7CBDFC4B2}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sln.Iot.Repository", "Sln.Iot.Repository\Sln.Iot.Repository.csproj", "{DA193E49-8B4A-4C8D-B44E-844E22983DA8}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sln.Iot.Serilog", "Sln.Iot.Serilog\Sln.Iot.Serilog.csproj", "{A9CCC9F6-BE1C-4B73-AFBF-83D363D7F64F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sln.Iot.Socket", "Sln.Iot.Socket\Sln.Iot.Socket.csproj", "{5B7C6367-7B41-48A6-9A71-2F191CE14000}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {2140AD68-D4CE-44EC-B9D3-20D18EB59F9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2140AD68-D4CE-44EC-B9D3-20D18EB59F9D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2140AD68-D4CE-44EC-B9D3-20D18EB59F9D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2140AD68-D4CE-44EC-B9D3-20D18EB59F9D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F59EB67D-66FD-43B9-B6CC-46BF25202C21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F59EB67D-66FD-43B9-B6CC-46BF25202C21}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F59EB67D-66FD-43B9-B6CC-46BF25202C21}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F59EB67D-66FD-43B9-B6CC-46BF25202C21}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2E10DED8-5F53-4ED9-892F-B0007B85806E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2E10DED8-5F53-4ED9-892F-B0007B85806E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2E10DED8-5F53-4ED9-892F-B0007B85806E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2E10DED8-5F53-4ED9-892F-B0007B85806E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {899D8A81-D3E3-4599-8A8C-D60280A777F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {899D8A81-D3E3-4599-8A8C-D60280A777F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {899D8A81-D3E3-4599-8A8C-D60280A777F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {899D8A81-D3E3-4599-8A8C-D60280A777F3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {503E7EAE-6323-4CE2-AAE4-C6A7CBDFC4B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {503E7EAE-6323-4CE2-AAE4-C6A7CBDFC4B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {503E7EAE-6323-4CE2-AAE4-C6A7CBDFC4B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {503E7EAE-6323-4CE2-AAE4-C6A7CBDFC4B2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DA193E49-8B4A-4C8D-B44E-844E22983DA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DA193E49-8B4A-4C8D-B44E-844E22983DA8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DA193E49-8B4A-4C8D-B44E-844E22983DA8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DA193E49-8B4A-4C8D-B44E-844E22983DA8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A9CCC9F6-BE1C-4B73-AFBF-83D363D7F64F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A9CCC9F6-BE1C-4B73-AFBF-83D363D7F64F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A9CCC9F6-BE1C-4B73-AFBF-83D363D7F64F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A9CCC9F6-BE1C-4B73-AFBF-83D363D7F64F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5B7C6367-7B41-48A6-9A71-2F191CE14000}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5B7C6367-7B41-48A6-9A71-2F191CE14000}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5B7C6367-7B41-48A6-9A71-2F191CE14000}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5B7C6367-7B41-48A6-9A71-2F191CE14000}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {47F07B24-817F-4612-9BD3-D8AD5F4B31C3}
+ EndGlobalSection
+EndGlobal
diff --git a/Sln.Iot/Program.cs b/Sln.Iot/Program.cs
new file mode 100644
index 0000000..c34cc9e
--- /dev/null
+++ b/Sln.Iot/Program.cs
@@ -0,0 +1,108 @@
+using System.Reflection;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Sln.Iot.Business;
+using Sln.Iot.Business.@base;
+using Sln.Iot.Config;
+using Sln.Iot.Repository;
+using Sln.Iot.Serilog;
+using Sln.Iot.Socket;
+using TouchSocket.Sockets;
+
+namespace Sln.Iot
+{
+ internal class Program
+ {
+ public static IServiceProvider? ServiceProvider = null;
+
+ static async Task Main(string[] args)
+ {
+ var services = new ServiceCollection();
+ ConfigureServices(services);
+ ServiceProvider = services.BuildServiceProvider();
+ ServiceProvider.UseSerilogExtensions();
+
+ var appConfig = ServiceProvider.GetService();
+ var log = ServiceProvider.GetService();
+ log.Info($"系统启动成功,日志存放位置:{appConfig.logPath}");
+
+ var _server = ServiceProvider.GetService();
+ _server.Init(appConfig.listernPort);
+
+ _server.ReceivedBufferRequestInfoEvent += (client, info) =>
+ {
+ bool isRet = false;
+ BaseBusiness _business = null;
+ int bodyLength = 0;
+ switch (info.DataType)
+ {
+ case 0x08: //校时指令
+ _business = ServiceProvider.GetService();
+ break;
+ case 0x21: //登录指令
+ _business = ServiceProvider.GetService();
+ break;
+ case 0x24: //心跳指令
+ _business = ServiceProvider.GetService();
+ break;
+ case 0x83: //电能指令
+ bodyLength = 70;
+ _business = ServiceProvider.GetService();
+ break;
+ case 0x84: //水
+ bodyLength = 58;
+ _business = ServiceProvider.GetService();
+ break;
+ case 0x85: //物联网环境
+ bodyLength = info.BufferLength;
+ _business = ServiceProvider.GetService();
+ break;
+ default:
+ break;
+ }
+
+ if (_business != null)
+ {
+ Parallel.Invoke(
+ () => _business.ResponseHandle(client, info.buffer),
+ () => _business.BufferAnalysis(client, info, bodyLength)
+ );
+ }
+ };
+
+ await Task.Delay(-1);
+ }
+
+ private static void ConfigureServices(IServiceCollection services)
+ {
+ services.AddSingleton(provider =>
+ {
+ var configurationBuilder = new ConfigurationBuilder()
+ .SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
+ .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
+ IConfiguration configuration = configurationBuilder.Build();
+ var ap = configuration.GetSection("AppConfig").Get();
+ return ap;
+ });
+
+ Assembly[] assemblies =
+ {
+ Assembly.LoadFrom("Sln.Iot.Repository.dll"),
+ Assembly.LoadFrom("Sln.Iot.Socket.dll"),
+ Assembly.LoadFrom("Sln.Iot.Common.dll"),
+ Assembly.LoadFrom("Sln.Iot.Business.dll"),
+ };
+
+ services.Scan(scan => scan.FromAssemblies(assemblies)
+ .AddClasses()
+ .AsImplementedInterfaces()
+ .AsSelf()
+ .WithTransientLifetime());
+
+ services.AddSingleton(typeof(SerilogHelper));
+ services.AddSingleton(typeof(TcpService));
+
+ services.AddSqlSugarSetup();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Sln.Iot/Sln.Iot.csproj b/Sln.Iot/Sln.Iot.csproj
new file mode 100644
index 0000000..ee5f903
--- /dev/null
+++ b/Sln.Iot/Sln.Iot.csproj
@@ -0,0 +1,32 @@
+
+
+
+ Exe
+ net6.0
+ enable
+ enable
+ zh-Hans
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
diff --git a/Sln.Iot/appsettings.json b/Sln.Iot/appsettings.json
new file mode 100644
index 0000000..fa27537
--- /dev/null
+++ b/Sln.Iot/appsettings.json
@@ -0,0 +1,19 @@
+{
+ "AppConfig": {
+ "logPath": "\\\\Mac\\Home\\Public\\WorkSpace\\Mesnac\\项目资料\\IOT物联网数据采集\\日志信息",
+ "listernPort": 7001,
+ "virtualFlag": true,
+ "virtualValue": 9999999,
+ "electricTimeInterval": 1, //电力数据采集间隔,小于间隔数据不保存,单位:分钟
+ "fluidTimeInterval": 1, //流体数据采集间隔,小于间隔数据不保存,单位:分钟
+ "SqlConfig": [
+ {
+ "configId": "tao_iot", //tao:青岛胶东机场简称
+ "dbType": 0, //tidb按照 mysql 去连接
+ "isFlag": true,
+ //"connStr": "server=127.0.0.1;Port=4000;Database=tao_iot;Uid=root;" //Pwd=haiwei@123;
+ "connStr": "server=1.13.177.47;Port=3306;Database=tao_iot;Uid=root;Pwd=Haiwei123456;"
+ }
+ ],
+ }
+}
diff --git a/Sln.Iot/readme.md b/Sln.Iot/readme.md
new file mode 100644
index 0000000..823928f
--- /dev/null
+++ b/Sln.Iot/readme.md
@@ -0,0 +1,210 @@
+**RKKC1604-N2型动力环境监控一体机.上行通讯协议**
+
+**1.终端主动发送登录指令(0x21/0xA1)**
+
+终端发起有效登录指令后,上位机软件才能对终端发送的数据进行解析和存库。
+
+| 类别 | 数据内容 | 数据长度 | 备注 |
+| --- | --- | --- | --- |
+| 帧开始 | 0x68 | 1个字节 | |
+| 采集器类型 | 0x45 | 1个字节 | 0x45-采集终端类型 |
+| 采集器地址 | 0x0001~0x9999 | 2个字节 | 高位在前低位在后,BCD码形式 |
+| 命令序列号 | | 2个字节 | 高位在前低位在后,命令帧的序列号 |
+| 起始符 | 0x68 | 1个字节 | |
+| 控制码 | 0x21 | 1个字节 | 登录指令标识码 |
+| 数据长度 | 0x00 0x03 | 2个字节 | 固定为0x00,0x03 |
+| 数据域 | 0x12 0x34 0x56 | 3个字节 | 固定为 0x12 0x34 0x56 |
+| 校验码 | CS | 1个字节 | 从帧开始到数据域最后一位的数据累加CS校验 |
+| 结束符 | 0x16 | 1个字节 | 1个字节 |
+
+举例:
+
+终端发送指令:
+
+68 45 01 02 00 BF 68 21 00 03 12 34 56 97 16
+
+上位机返回指令:
+
+68 45 01 02 00 BF 68 A1 00 00 78 16
+
+**2.上位机对采集终端设备校时指令(0x08/0x88)**
+
+为保证现场采集设备与服务器之间的时间同步,采集终端登录服务器成功后服务器需要对采集设备进行校时。在后续正常工作时,为纠正设备之间的时间偏差,建议每隔一段时间(比如8个小时)对现场终端进行一次校时。
+
+| 类别 | 数据内容 | 数据长度 | 备注 |
+| --- | --- | --- | --- |
+| 帧开始 | 0x68 | 1个字节 | |
+| 采集器类型 | 0x45 | 1个字节 | 0x45-采集终端类型 |
+| 采集器地址 | 0x0001~0x9999 | 2个字节 | 高位在前低位在后,BCD码形式 |
+| 命令序列号 | | 2个字节 | 高位在前低位在后,命令帧的序列号 |
+| 起始符 | 0x68 | 1个字节 | |
+| 控制码 | 0x08 | 1个字节 | 设置终端参数标识码 |
+| 数据长度 | 0x00 0x0D | 2个字节 | 固定为0x00,0x0D |
+| 数据域 | 0x00 | 1个字节 | 固定为0x00 |
+| | 0x00 | 1个字节 | 固定为0x00 |
+| | 0x31 0x32 0x33 | 3个字节 | 密码,固定为0x31 0x32 0x33 |
+| | 0x80 0x30 | 2个字节 | 时间标识码,固定为0x80 0x30 |
+| | 秒-分-时-日-月-年 | 6个字节 | 具体时间:秒-分-时-日-月-年 |
+| 校验码 | CS | 1个字节 | 从帧开始到数据长度数据累加CS校验 |
+| 结束符 | 0x16 | 1个字节 | 1个字节 |
+
+举例:
+
+上位机发送指令:
+
+68 45 01 02 40 00 68 08 00 0D 00 00 31 32 33 80 30 22 39 14 16 09 15 56 16
+
+终端返回指令:
+
+68 45 01 02 40 00 68 88 00 04 00 80 30 00 94 16
+
+**3.终端主动发送心跳指令(0x24/0xA4)**
+
+通过心跳指令判断采集设备与上位机直接的通讯连接状态,采集设备通过定时发送心跳指令,在有效时间内若得到上位机的响应,则判断出终端与上位机之间处于有效连接中,否则若在有效时间捏没有得到上位机的响应,则判断出终端没有连接上上位机,终端则发起登录上位机服务器的流程和指令。
+
+| 类别 | 数据内容 | 数据长度 | 备注 |
+| --- | --- | --- | --- |
+| 帧开始 | 0x68 | 1个字节 | |
+| 采集器类型 | 0x45 | 1个字节 | 0x45-采集终端类型 |
+| 采集器地址 | 0x0001~0x9999 | 2个字节 | 高位在前低位在后,BCD码形式 |
+| 命令序列号 | | 2个字节 | 高位在前低位在后,命令帧的序列号 |
+| 起始符 | 0x68 | 1个字节 | |
+| 控制码 | 0x24 | 1个字节 | 心跳指令标识码 |
+| 数据长度 | | 2个字节 | 固定为0x00,0x00 |
+| 校验码 | CS | 1个字节 | 从帧开始到数据长度数据累加CS校验 |
+| 结束符 | 0x16 | 1个字节 | 1个字节 |
+
+举例:
+
+终端发送指令:
+
+68 45 00 01 00 01 68 24 00 00 3B 16
+
+上位机返回指令:
+
+68 45 00 01 00 01 68 A4 00 00 BB 16
+
+**4.终端主动上传实时数据指令**
+
+采集设备根据设定的时间间隔,定时对现场仪表进行数据采集,并将采集到的数据综合处理后主动上传到上位机平台。
+
+| 类别 | 数据内容 | 数据长度 | 备注 |
+| --- | --- | --- | --- |
+| 帧开始 | 0x68 | 1个字节 | |
+| 采集器类型 | 0x45 | 1个字节 | 0x45-采集终端类型 |
+| 采集器地址 | 0x0001~0x9999 | 2个字节 | 高位在前低位在后,BCD码形式 |
+| 命令序列号 | | 2个字节 | 高位在前低位在后,命令帧的序列号 |
+| 起始符 | 0x68 | 1个字节 | |
+| 控制码 | 0x83/0x84/0x85/0x86/0x87 | 1个字节 | 0x83-电力;0x84-压缩空气、水;0x85-温湿度、照度;0x86-开关量IO状态;0x87-蒸汽 |
+| 数据长度 | N个仪表*1个仪表的长度 | 2个字节 | 1条仪表数据数据长度L
+0x83:L=2(表序号)+8*6(8项数据项)+8(采集时间) = 58个字节
+0x84:L=2(表序号)+8*6(8项数据项)+8(采集时间) = 58个字节
+0x85: L=2(表序号)+4*6(8项数据项)+8(采集时间) = 34个字节
+0x86: L=2(表序号)+16(16路IO输入)+8(采集时间) = 26个字节,N=1
+0x87:L=2(表序号)+8*6(8项数据项)+8(采集时间) = 58个字节 |
+| 数据域 | 0x00 | N*L个字节 | |
+| 校验码 | CS | 1个字节 | 从帧开始到数据长度数据累加CS校验 |
+| 结束符 | 0x16 | 1个字节 | 1个字节 |
+
+控制码:
+
+| 序号 | 终端主动发送数据控制码 | 上位机返回对应控制码 | 备注 |
+| --- | --- | --- | --- |
+| 1 | 0x83 | 0xB3 | |
+| 2 | 0x84 | 0xB4 | |
+| 3 | 0x85 | 0xB5 | |
+| 3 | 0x85 | 0xB6 | |
+
+电力采集数据域举例:
+
+
+
+举例:
+
+终端发生命令帧:
+
+68 45 00 01 01 FF 68 83 00 3A 01 00 8E 11 61 4E 4B 3C 8E 12 61 4E 4B 3C 8E 13 61 4E 4B 3C 8E 21 61 4E 4B 3C 8E 22 61 4E 4B 3C 8E 23 61 4E 4B 3C B6 50 3F 7C AC 08 90 10 61 4E 4B 3C 80 30 50 40 16 28 04 20 F5 16
+
+上位机返回:
+
+68 45 00 01 0A 3F 68 B3 00 00 12 16
+
+**5.终端主动上传历史数据指令**
+
+在采集设备与上位机有效连接的期间内,采集设备对存储在内部存储区内的历史数据进行批量上传工作。
+
+| 类别 | 数据内容 | 数据长度 | 备注 |
+| --- | --- | --- | --- |
+| 帧开始 | 0x68 | 1个字节 | |
+| 采集器类型 | 0x45 | 1个字节 | 0x45-采集终端类型 |
+| 采集器地址 | 0x0001~0x9999 | 2个字节 | 高位在前低位在后,BCD码形式 |
+| 命令序列号 | | 2个字节 | 高位在前低位在后,命令帧的序列号 |
+| 起始符 | 0x68 | 1个字节 | |
+| 控制码 | 0x83/0x84/0x85/0x86/0x87 | 1个字节 | 0x83-电力;0x84-压缩空气、水;0x85-温湿度、照度;0x86-开关量IO状态;0x87-蒸汽 |
+| 数据长度 | N个仪表*1个仪表的长度 | 2个字节 | 1条仪表数据数据长度L
+0x93:L=2(表序号)+8*6(8项数据项)+8(采集时间) = 58个字节
+0x94:L=2(表序号)+8*6(8项数据项)+8(采集时间) = 58个字节
+0x95: L=2(表序号)+4*6(4项数据项)+8(采集时间) = 34个字节
+0x96: L=2(表序号)+16(16路IO输入)+8(采集时间) = 26个字节,N=1
+0x97:L=2(表序号)+8*6(8项数据项)+8(采集时间) = 58个字节 |
+| 数据域 | 0x00 | N*L个字节 | |
+| 校验码 | CS | 1个字节 | 从帧开始到数据长度数据累加CS校验 |
+| 结束符 | 0x16 | 1个字节 | 1个字节 |
+
+控制码:
+
+| 序号 | 终端主动发送数据控制码 | 上位机返回对应控制码 | 备注 |
+| --- | --- | --- | --- |
+| 1 | 0x93 | 0xC3 | |
+| 2 | 0x94 | 0xC4 | |
+| 3 | 0x95 | 0xC5 | |
+| 4 | 0x96 | 0xC6 | |
+| 5 | 0x97 | 0xC7 | |
+
+电力采集数据域举例:
+
+
+
+举例:
+
+终端发生命令帧:
+
+68 45 00 01 01 FF 68 93 00 3A 01 00 8E 11 61 4E 4B 3C 8E 12 61 4E 4B 3C 8E 13 61 4E 4B 3C 8E 21 61 4E 4B 3C 8E 22 61 4E 4B 3C 8E 23 61 4E 4B 3C B6 50 3F 7C AC 08 90 10 61 4E 4B 3C 80 30 50 40 16 28 04 20 05 16
+
+上位机返回:
+
+68 45 00 01 0A 3F 68 C3 00 00 22 16
+
+# 附录:上传数据标识码(部分)
+
+| 标识符类型 | 说明 | 标识符类型 | 说明 |
+| --- | --- | --- | --- |
+| 0x8E11 | A相电压 | 0x9B00 | 仪表压力值 |
+| 0x8E12 | B相电压 | 0x9B01 | 仪表温度值 |
+| 0x8E13 | C相电压 | 0x9B02 | 仪表频率值 |
+| 0x8E21 | A相电流 | 0x9B03 | 仪表瞬时流值 |
+| 0x8E22 | B相电流 | 0x9B05 | 仪表累积流量值 |
+| 0x8E23 | C相电流 | 0x9B06 | 仪表瞬时热量 |
+| 0xB650 | 总功率因数 | 0x9B07 | 仪表累积热量值 |
+| 0x9010 | 正向有功总电能 | 0x9B0E | 仪表密度值 |
+| 0x8030 | 仪表数据采集时间 | | |
+
+| 标识符类型 | 说明 | 标识符类型 | 说明 |
+| --- | --- | --- | --- |
+| 0x8E50 | 温湿度.温度 | 0x8E51 | 照度.流明 |
+| 0x8E52 | 温湿度.湿度 | 0x8E53 | 噪声.分贝 |
+| 0x8E54 | 振动-速度 | 0x8E55 | 振动-位移 |
+| 0x8E56 | 振动-加速度 | 0x8E57 | 振动-温度 |
+| 0x8030 | 仪表数据采集时间 | | |
+
+指令样例:
+
+`温度指令:68 54 00 02 0E 7F 68 85 00 28 01 01 8E 50 70 A4 41 DD 8E 51 00 00 00 00 8E 52 00 00 00 00 8E 53 00 00 00 00 8E 54 00 00 00 00 80 30 06 47 04 03 09 24 25 16`
+
+`湿度指令:68 54 00 01 18 3F 68 85 00 28 01 01 8E 50 7A E1 41 FC 8E 51 00 00 00 00 8E 52 0A 3D 42 2E 8E 53 00 00 00 00 8E 54 00 00 00 00 80 30 34 47 04 03 09 24 39 16`
+
+`噪音指令:68 54 00 03 1B 3F 68 85 00 28 01 01 8E 50 00 00 00 00 8E 51 00 00 00 00 8E 52 00 00 00 00 8E 53 66 66 42 93 8E 54 00 00 00 00 80 30 36 53 09 14 03 25 AF 16`
+
+`电能指令:6845002104BF6883023011008E11199A43688E12333343678E13199A43688E21BA5E3FA98E2268733F718E23353F3FAEB651FF000000B65200000000B6504DD33F629010C6E14590803037520521052512008E11000043688E12199A43678E13199A43688E21000000008E22000000008E2300000000B651FF000000B65200000000B65000003F809010AF484605803043520521052513008E11E66643678E12199A43678E13199A43688E21353F3E5E8E2260423E658E239DB23E6FB651FF000000B65200000000B65016873F799010F33344BC803049520521052514008E11333343688E12199A43678E13199A43688E21000000008E22000000008E2300000000B651FF000000B65200000000B65000003F8090103266461C803054520521052515008E11000043688E12CCCD43668E13199A43688E21BA5E3F998E22AE143F978E2326E93FA1B651FF000000B65200000000B65081063F5590106F5C454B803000530521052516008E11000043688E12000043678E13199A43688E211EB83D858E2247AE3D618E23999A3D99B651FF000000B65200000000B650020C3F4B9010619A44F0803006530521052517008E11000043688E12E66643668E13333343688E21A1CB3E858E224FDF3E8D8E23FDF43E94B651FF000000B65200000000B65068733F5190101D1F44C7803011530521052518008E11199A43688E12CCCD43668E13000043688E21CED93EB78E223F7D3EB58E23CCCD3ECCB651FF000000B65200000000B6506C8B3F67901091EC44FD80301753052105257116`
+
+`流体指令:68450073197F688400E801009B00000000009B01000000009B02000000009B03000000009B0500003F809B06000000009B07000000009B0E00000000803019250521052502009B00000000009B01000000009B02000000009B03000000009B0500003F809B06000000009B07000000009B0E00000000803020250521052503009B00000000009B01000000009B02000000009B03000000009B05C00044219B06000000009B07000000009B0E00000000803021250521052504009B00000000009B01000000009B02000000009B03000000009B05000043BE9B06000000009B07000000009B0E0000000080302225052105254216`
\ No newline at end of file
diff --git a/Sln.Iot/sql.md b/Sln.Iot/sql.md
new file mode 100644
index 0000000..eec7363
--- /dev/null
+++ b/Sln.Iot/sql.md
@@ -0,0 +1,144 @@
+# Sql File 数据结构
+
+record_iotenv_instant:动力环境数据表
+
+```sql
+/*
+ Navicat Premium Data Transfer
+
+ Source Server : 127.0.0.1_4000
+ Source Server Type : MySQL
+ Source Server Version : 80011 (8.0.11-TiDB-v8.5.1)
+ Source Host : 127.0.0.1:4000
+ Source Schema : tao_iot
+
+ Target Server Type : MySQL
+ Target Server Version : 80011 (8.0.11-TiDB-v8.5.1)
+ File Encoding : 65001
+
+ Date: 20/05/2025 14:18:32
+*/
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for record_iotenv_instant
+-- ----------------------------
+DROP TABLE IF EXISTS `record_iotenv_instant`;
+CREATE TABLE `record_iotenv_instant` (
+ `objid` bigint NOT NULL AUTO_INCREMENT COMMENT '主键标识',
+ `monitorId` varchar(50) DEFAULT NULL COMMENT '计量设备编号',
+ `temperature` decimal(18,2) DEFAULT NULL COMMENT '温度',
+ `humidity` decimal(18,2) DEFAULT NULL COMMENT '湿度',
+ `illuminance` decimal(18,2) DEFAULT NULL COMMENT '照度',
+ `noise` decimal(18,2) DEFAULT NULL COMMENT '噪声',
+ `concentration` decimal(18,2) DEFAULT NULL COMMENT '硫化氢浓度',
+ `vibration_speed` decimal(18,2) DEFAULT NULL COMMENT '振动-速度(mm/s)',
+ `vibration_displacement` decimal(18,2) DEFAULT NULL COMMENT '振动-位移(um)',
+ `vibration_acceleration` decimal(18,2) DEFAULT NULL COMMENT '振动-加速度(g)',
+ `vibration_temp` decimal(18,2) DEFAULT NULL COMMENT '振动-温度(℃)',
+ `collectTime` datetime DEFAULT NULL COMMENT '采集时间',
+ `recodeTime` datetime DEFAULT NULL COMMENT '记录时间',
+ PRIMARY KEY (`objid`) /*T![clustered_index] CLUSTERED */
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin AUTO_INCREMENT=6687491 COMMENT='物联网数据';
+
+SET FOREIGN_KEY_CHECKS = 1;
+
+```
+
+record_dnb_instant:电能数据表
+
+```sql
+/*
+ Navicat Premium Data Transfer
+
+ Source Server : 127.0.0.1_4000
+ Source Server Type : MySQL
+ Source Server Version : 80011 (8.0.11-TiDB-v8.5.1)
+ Source Host : 127.0.0.1:4000
+ Source Schema : tao_iot
+
+ Target Server Type : MySQL
+ Target Server Version : 80011 (8.0.11-TiDB-v8.5.1)
+ File Encoding : 65001
+
+ Date: 20/05/2025 14:18:23
+*/
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for record_dnb_instant
+-- ----------------------------
+DROP TABLE IF EXISTS `record_dnb_instant`;
+CREATE TABLE `record_dnb_instant` (
+ `objid` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
+ `monitor_id` varchar(64) DEFAULT NULL COMMENT '计量设备编号',
+ `va` decimal(18,2) DEFAULT NULL COMMENT 'A项电压',
+ `vb` decimal(18,2) DEFAULT NULL COMMENT 'B项电压',
+ `vc` decimal(18,2) DEFAULT NULL COMMENT 'C项电压',
+ `ia` decimal(18,2) DEFAULT NULL COMMENT 'A项电流',
+ `ib` decimal(18,2) DEFAULT NULL COMMENT 'B项电流',
+ `ic` decimal(18,2) DEFAULT NULL COMMENT 'C项电流',
+ `glys` decimal(18,2) DEFAULT NULL COMMENT '功率因数',
+ `zxyg` decimal(18,2) DEFAULT NULL COMMENT '正向有功',
+ `active_power` decimal(18,2) DEFAULT NULL COMMENT '有功功率',
+ `reactive_power` decimal(18,2) DEFAULT NULL COMMENT '无功功率',
+ `collect_type` int DEFAULT '0' COMMENT '采集方式',
+ `collect_time` datetime DEFAULT NULL COMMENT '采集时间',
+ `record_time` datetime DEFAULT NULL COMMENT '记录时间',
+ PRIMARY KEY (`objid`) /*T![clustered_index] CLUSTERED */
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='电实时数据';
+
+SET FOREIGN_KEY_CHECKS = 1;
+
+```
+
+record_fluid_instant:流体实时数据
+
+```sql
+/*
+ Navicat Premium Data Transfer
+
+ Source Server : 127.0.0.1_4000
+ Source Server Type : MySQL
+ Source Server Version : 80011 (8.0.11-TiDB-v8.5.1)
+ Source Host : 127.0.0.1:4000
+ Source Schema : tao_iot
+
+ Target Server Type : MySQL
+ Target Server Version : 80011 (8.0.11-TiDB-v8.5.1)
+ File Encoding : 65001
+
+ Date: 20/05/2025 14:31:46
+*/
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for record_fluid_instant
+-- ----------------------------
+DROP TABLE IF EXISTS `record_fluid_instant`;
+CREATE TABLE `record_fluid_instant` (
+ `objid` bigint NOT NULL AUTO_INCREMENT COMMENT '自增标识',
+ `monitor_id` varchar(64) DEFAULT NULL COMMENT '计量设备编号',
+ `temperature` decimal(18,2) DEFAULT NULL COMMENT '温度值',
+ `press` decimal(18,2) DEFAULT NULL COMMENT '压力值',
+ `frequency` decimal(18,2) DEFAULT NULL COMMENT '频率值',
+ `density` decimal(18,2) DEFAULT NULL COMMENT '密度值',
+ `instant_heat` decimal(18,2) DEFAULT NULL COMMENT '瞬时热量',
+ `total_heat` decimal(18,2) DEFAULT NULL COMMENT '累计热量值',
+ `instant_flow` decimal(18,2) DEFAULT NULL COMMENT '瞬时流量',
+ `total_flow` decimal(18,2) DEFAULT NULL COMMENT '累计流量',
+ `collect_type` int DEFAULT '0' COMMENT '采集方式',
+ `collect_time` datetime DEFAULT NULL COMMENT '采集时间',
+ `record_time` datetime DEFAULT NULL COMMENT '记录时间',
+ PRIMARY KEY (`objid`) /*T![clustered_index] CLUSTERED */
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='流体实时数据';
+
+SET FOREIGN_KEY_CHECKS = 1;
+
+```
\ No newline at end of file