refactor - 去掉DI,添加业务类,完善PLC连接

master
SoulStar 2 months ago
parent 871523b1e7
commit 18f73cd51a

@ -0,0 +1,82 @@
using HslCommunication;
using Sln.Iot.PLC;
using Sln.Iot.Repository;
using Sln.Iot.Repository.dao;
using Sln.Iot.Repository.service;
using Sln.Iot.Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Sln.Iot.Business
{
public class RFID01Business
{
private Timer _timer;
private readonly PLCConnect _plc;
private readonly SerilogHelper _log;
public RFID01Business()
{
_timer = new Timer(TimerCallback, null, 0, 2000);
}
/// <summary>
/// RFID01上料提升机数据处理流程业务刷新
/// </summary>
/// <param name="state"></param>
public void TimerCallback(object? state)
{
// 定时任务逻辑
//读取信号
OperateResult<short> signalRes = _plc.ReadInt16(_plc.DeltaInstance3, "D500");
//成功验证
if (signalRes.IsSuccess)
{
short signalValue = signalRes.Content;
//如果有读取信号
if (signalValue == 1001)
{
//读取托盘码和产品码
OperateResult<byte[]> trayBytesResult = _plc.ReadBytes(_plc.DeltaInstance3, "D5000", 20);
OperateResult<byte[]> pordBytesResult = _plc.ReadBytes(_plc.DeltaInstance3, "D8000", 120);
//成功验证
if (trayBytesResult.IsSuccess && pordBytesResult.IsSuccess)
{
//转换托盘吗
string traycode = Encoding.ASCII.GetString(trayBytesResult.Content);
byte[] prodBytes = trayBytesResult.Content;
string[] prodcode = new string[6];
//分割转换产品码
for (int i = 0; i < 5; i++)
{
prodcode[i] = Encoding.ASCII.GetString(prodBytes[(i * 20)..(i * 20 + 20)]);
}
//sql更新
bool res = TrayBindingService.Instance.TrayBindingRefresh(traycode, prodcode);
if (!res)
{
_log.Error("上料提升机数据处理流程异常");
}
//写入完成信号
res = _plc.PlcWrite(_plc.DeltaInstance3, "D500", 1002, DataTypeEnum.UInt16).IsSuccess;
if (!res)
{
_log.Error("上料提升机写入完成信号异常");
}
}
//流程完成
}
}
else
{
_log.Error("上料提升机读取信号异常");
}
}
}
}

@ -0,0 +1,49 @@
using HslCommunication;
using Sln.Iot.PLC;
using Sln.Iot.Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Sln.Iot.Business
{
public class RFID02Business
{
private Timer _timer;
private readonly PLCConnect _plc;
private readonly SerilogHelper _log;
public RFID02Business()
{
_timer = new Timer(TimerCallback, null, 0, 5000);
}
/// <summary>
/// RFID02上料提升机数据处理流程业务刷新
/// </summary>
/// <param name="state"></param>
public void TimerCallback(object? state)
{
// 定时任务逻辑
OperateResult<short> signalRes = _plc.ReadInt16(_plc.DeltaInstance1, "D500");
if (signalRes.IsSuccess)
{
short signalValue = signalRes.Content;
if(signalValue == 1001)
{
OperateResult<byte[]> trayBytesResult = _plc.ReadBytes(_plc.DeltaInstance1, "D5000", 10);
OperateResult<byte[]> pordBytesResult = _plc.ReadBytes(_plc.DeltaInstance1, "D8000", 60);
if(trayBytesResult.IsSuccess && pordBytesResult.IsSuccess)
{
string traycode = "abcdefg";
string prodcode = "1234567890";
}
}
}
}
}
}

@ -12,9 +12,16 @@
<ItemGroup>
<ProjectReference Include="..\Sln.Iot.Common\Sln.Iot.Common.csproj" />
<ProjectReference Include="..\Sln.Iot.PLC\Sln.Iot.PLC.csproj" />
<ProjectReference Include="..\Sln.Iot.Repository\Sln.Iot.Repository.csproj" />
<ProjectReference Include="..\Sln.Iot.Serilog\Sln.Iot.Serilog.csproj" />
<ProjectReference Include="..\Sln.Iot.Socket\Sln.Iot.Socket.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="HslCommunication">
<HintPath>..\DLL\HslCommunication.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

@ -68,6 +68,11 @@ public class CFXHelper
}
}
/// <summary>
/// 请求接收处理
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
private CFXEnvelope Endpoint_OnRequestReceived(CFXEnvelope request)
{
CFXMessage response = null;
@ -102,7 +107,6 @@ public class CFXHelper
/// <param name="env"></param>
public void PublishEvent(CFXEnvelope env)
{
try
{
if (_endpoint == null)

@ -22,8 +22,7 @@
*--------------------------------------------------------------------*/
#endregion << 版 本 注 释 >>
using System.Collections.Generic;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
namespace Sln.Iot.Config
@ -35,11 +34,7 @@ namespace Sln.Iot.Config
/// </summary>
public string logPath { get; set; }
/// <summary>
/// Sql连接配置
/// </summary>
public List<SqlConfig> sqlConfig { get; set; }
public List<PLCConfig> PLCConfig { get; set; }
public AppConfig Value => this;
}

@ -0,0 +1,33 @@
using Microsoft.Extensions.Configuration;
namespace Sln.Iot.Config
{
public class AppConfigSetting
{
private static AppConfig? _config;
/// <summary>
/// 加载配置文件并解析为 AppConfig 对象。
/// </summary>
public static AppConfig Load()
{
if (_config != null)
return _config; // 已经加载过就直接返回(模拟单例)
var configBuilder = new ConfigurationBuilder()
.SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
IConfiguration configuration = configBuilder.Build();
_config = configuration.GetSection("AppConfig").Get<AppConfig>();
if (_config == null)
{
throw new InvalidOperationException("无法从 appsettings.json 加载 AppConfig 配置。");
}
return _config;
}
}
}

@ -7,7 +7,9 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.10" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.10" />
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.10" />
</ItemGroup>
</Project>

@ -25,26 +25,21 @@
namespace Sln.Iot.Config
{
public class SqlConfig
public class PLCConfig
{
/// <summary>
/// Sql 配置ID实体通过该ID关联数据源
/// PLCIP地址
/// </summary>
public string configId { get; set; }
public string IPAddress { get; set; }
/// <summary>
/// 数据库类型MySql-0;SqlServer-1;Sqlite-2;Oracle-3
/// PLC端口号
/// </summary>
public int dbType { get; set; }
public string Port { get; set; }
/// <summary>
/// 是否启用true-是false-否
/// 站号
/// </summary>
public bool isFlag{get;set;}
/// <summary>
/// 连接字符串
/// </summary>
public string connStr { get; set; }
public int StationNo { get; set; }
}
}

@ -6,13 +6,18 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Compile Remove="dao\**" />
<EmbeddedResource Remove="dao\**" />
<None Remove="dao\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SqlSugarCore" Version="5.1.4.193" />
</ItemGroup>
<ItemGroup>
<Folder Include="api\" />
<Folder Include="dao\" />
</ItemGroup>
</Project>

@ -1,26 +1,64 @@
using HslCommunication;
using HslCommunication.Profinet.Delta;
using Microsoft.Extensions.DependencyInjection;
using Serilog;
using Sln.Iot.Serilog;
using System;
using System.Drawing;
namespace Sln.Iot.PLC
{
public class PLCConnect
{
private SerilogHelper? LogHelper;
private static readonly Lazy<PLCConnect> lazy = new Lazy<PLCConnect>(() => new PLCConnect());
public static DeltaSerialOverTcp DeltaInstance1;
public static PLCConnect Instance
{
get
{
return lazy.Value;
}
}
private readonly SerilogHelper _log = SerilogHelper.Instance;
/// <summary>
/// PLC1 192.168.1.21
/// </summary>
public DeltaSerialOverTcp DeltaInstance1;
/// <summary>
/// PLC2 192.168.1.22
/// </summary>
public DeltaSerialOverTcp DeltaInstance2;
/// <summary>
/// PLC3 192.168.1.23
/// </summary>
public DeltaSerialOverTcp DeltaInstance3;
/// <summary>
/// PLC4 192.168.1.24
/// </summary>
public DeltaSerialOverTcp DeltaInstance4;
/// <summary>
/// 锁对象1
/// </summary>
private static readonly object locker1 = new object();
public PLCConnect(SerilogHelper serilogHelper)
public async void InitConnect()
{
LogHelper = serilogHelper;
DeltaInstance1 = CreateDeltaConnect("127.0.0.1", 502, 1, serilogHelper);
List<Task<DeltaSerialOverTcp>> tasks = new List<Task<DeltaSerialOverTcp>>
{
CreateDeltaConnect("192.168.1.21", 502, 1),
CreateDeltaConnect("192.168.1.22", 502, 1),
CreateDeltaConnect("192.168.1.23", 502, 1),
CreateDeltaConnect("192.168.1.24", 502, 1)
};
DeltaInstance1 = tasks[0].GetAwaiter().GetResult();
DeltaInstance2 = tasks[1].GetAwaiter().GetResult();
DeltaInstance3 = tasks[2].GetAwaiter().GetResult();
DeltaInstance4 = tasks[3].GetAwaiter().GetResult();
}
/// <summary>
@ -29,31 +67,43 @@ namespace Sln.Iot.PLC
/// <param name="ip"></param>
/// <param name="port"></param>
/// <param name="stationNo"></param>
/// <param name="log"></param>
/// <returns></returns>
public static DeltaSerialOverTcp CreateDeltaConnect(string ip, int port, byte stationNo, SerilogHelper log)
public async Task<DeltaSerialOverTcp> CreateDeltaConnect(string ip, int port, byte stationNo)
{
DeltaSerialOverTcp plc = new DeltaSerialOverTcp(ip, port, stationNo);
try
{
var res = plc.ConnectServer();
OperateResult res = new OperateResult();
res.IsSuccess = true;
int count = 0;
do
{
if (res.IsSuccess == false)
{
count++;
_log.Error($"PLC[{ip}]连接失败,正在进行第[{count}]次重连...");
}
res = await plc.ConnectServerAsync();
}
while (!res.IsSuccess);
}
catch (Exception ex)
{
log.Error($"连接PLC[{ip}]失败", ex);
_log.Error($"连接PLC[{ip}]失败", ex);
}
return plc;
}
/// <summary>
/// PLC2写入数据
/// PLC写入数据
/// </summary>
/// <param name="address">地址</param>
/// <param name="value">值</param>
/// <param name="type">数据类型</param>
/// <returns></returns>
public static OperateResult PlcWrite(string address, object value, DataTypeEnum type)
public OperateResult PlcWrite(DeltaSerialOverTcp connect, string address, object value, DataTypeEnum type)
{
var result = new OperateResult() { IsSuccess = false };
@ -62,37 +112,37 @@ namespace Sln.Iot.PLC
switch (type)
{
case DataTypeEnum.Bool:
result = DeltaInstance1.Write(address, Convert.ToBoolean(value));
result = connect.Write(address, Convert.ToBoolean(value));
break;
case DataTypeEnum.Byte:
result = DeltaInstance1.Write(address, Convert.ToByte(value));
result = connect.Write(address, Convert.ToByte(value));
break;
case DataTypeEnum.Int16:
result = DeltaInstance1.Write(address, Convert.ToInt16(value));
result = connect.Write(address, Convert.ToInt16(value));
break;
case DataTypeEnum.UInt16:
result = DeltaInstance1.Write(address, Convert.ToUInt16(value));
result = connect.Write(address, Convert.ToUInt16(value));
break;
case DataTypeEnum.Int32:
result = DeltaInstance1.Write(address, Convert.ToInt32(value));
result = connect.Write(address, Convert.ToInt32(value));
break;
case DataTypeEnum.UInt32:
result = DeltaInstance1.Write(address, Convert.ToUInt32(value));
result = connect.Write(address, Convert.ToUInt32(value));
break;
case DataTypeEnum.Int64:
result = DeltaInstance1.Write(address, Convert.ToInt64(value));
result = connect.Write(address, Convert.ToInt64(value));
break;
case DataTypeEnum.UInt64:
result = DeltaInstance1.Write(address, Convert.ToUInt64(value));
result = connect.Write(address, Convert.ToUInt64(value));
break;
case DataTypeEnum.Float:
result = DeltaInstance1.Write(address, Convert.ToSingle(value));
result = connect.Write(address, Convert.ToSingle(value));
break;
case DataTypeEnum.Double:
result = DeltaInstance1.Write(address, Convert.ToDouble(value));
result = connect.Write(address, Convert.ToDouble(value));
break;
case DataTypeEnum.String:
result = DeltaInstance1.Write(address, Convert.ToString(value));
result = connect.Write(address, Convert.ToString(value));
break;
default:
throw new ArgumentException($"Unsupported data type: {type}");
@ -107,11 +157,11 @@ namespace Sln.Iot.PLC
/// <param name="address"></param>
/// <param name="data"></param>
/// <returns></returns>
public static OperateResult PlcWriteBytes(string address, byte[] data)
public OperateResult PlcWriteBytes(DeltaSerialOverTcp connect, string address, byte[] data)
{
lock (locker1)
{
var res = DeltaInstance1.Write(address, data);
var res = connect.Write(address, data);
return res;
}
}
@ -120,11 +170,11 @@ namespace Sln.Iot.PLC
/// 读取int32
/// </summary>
/// <returns></returns>
public OperateResult<int> ReadInt32(string address)
public OperateResult<int> ReadInt32(DeltaSerialOverTcp connect, string address)
{
lock (locker1)
{
var res = DeltaInstance1.ReadInt32(address);
var res = connect.ReadInt32(address);
return res;
}
}
@ -133,11 +183,11 @@ namespace Sln.Iot.PLC
/// 读取int16
/// </summary>
/// <returns></returns>
public OperateResult<short> ReadInt16(string address)
public OperateResult<short> ReadInt16(DeltaSerialOverTcp connect, string address)
{
lock (locker1)
{
var res = DeltaInstance1.ReadInt16(address);
var res = connect.ReadInt16(address);
return res;
}
}
@ -147,11 +197,11 @@ namespace Sln.Iot.PLC
/// </summary>
/// <param name="address"></param>
/// <returns></returns>
public OperateResult<float> ReadFloat(string address)
public OperateResult<float> ReadFloat(DeltaSerialOverTcp connect, string address)
{
lock (locker1)
{
var res = DeltaInstance1.ReadFloat(address);
var res = connect.ReadFloat(address);
return res;
}
}
@ -161,11 +211,11 @@ namespace Sln.Iot.PLC
/// </summary>
/// <param name="address"></param>
/// <returns></returns>
public OperateResult<bool> ReadBool(string address)
public OperateResult<bool> ReadBool(DeltaSerialOverTcp connect, string address)
{
lock (locker1)
{
var res = DeltaInstance1.ReadBool(address);
var res = connect.ReadBool(address);
return res;
}
}
@ -176,15 +226,15 @@ namespace Sln.Iot.PLC
/// <param name="address"></param>
/// <param name="length"></param>
/// <returns></returns>
public static OperateResult<byte[]> ReadByte2(string address, ushort length)
public OperateResult<byte[]> ReadBytes(DeltaSerialOverTcp connect, string address, ushort length)
{
lock (locker1)
{
var res = DeltaInstance1.Read(address, length);
var res = connect.Read(address, length);
return res;
}
}
}
}

@ -12,6 +12,7 @@
<ItemGroup>
<ProjectReference Include="..\Sln.Iot.Config\Sln.Iot.Config.csproj" />
<ProjectReference Include="..\Sln.Iot.Serilog\Sln.Iot.Serilog.csproj" />
</ItemGroup>
</Project>

@ -11,8 +11,6 @@ namespace Sln.Iot.Repository
{
/// <summary>
/// SQLite同步方法帮助类
/// 作者:追逐时光者
/// 创建时间2023年11月30日
/// </summary>
/// <typeparam name="T"></typeparam>
public class SQLiteHelper<T> where T : new()

@ -8,10 +8,13 @@ using System.Threading.Tasks;
namespace Sln.Iot.Repository.dao
{
/// <summary>
/// 数据中转表
/// 托盘绑定实体类
/// </summary>
public class TrayRfidBinding
{
/// <summary>
/// 主键
/// </summary>
[PrimaryKey]
public string GUID { get; set; }

@ -1,4 +1,7 @@
using System;
using Sln.Iot.Repository.dao;
using Sln.Iot.Serilog;
using SQLitePCL;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -6,8 +9,57 @@ using System.Threading.Tasks;
namespace Sln.Iot.Repository.service
{
/// <summary>
/// 托盘绑定服务类
/// </summary>
public class TrayBindingService
{
private static readonly Lazy<TrayBindingService> lazy = new Lazy<TrayBindingService>(() => new TrayBindingService());
public static TrayBindingService Instance
{
get
{
return lazy.Value;
}
}
private SQLiteHelper<TrayRfidBinding> _helper = SQLiteHelper<TrayRfidBinding>.Instance;
private SerilogHelper _log = SerilogHelper.Instance;
/// <summary>
/// 托盘二维码重新绑定
/// </summary>
/// <param name="trayCode"></param>
/// <param name="prodCode"></param>
/// <returns></returns>
public bool TrayBindingRefresh(string trayCode, string[] prodCode)
{
try
{
//先删除原来的
_helper.DeleteRange(trayCode);
//再绑定(插入)新的
var entities = new List<TrayRfidBinding>();
foreach (string code in prodCode)
{
TrayRfidBinding entity = new TrayRfidBinding()
{
GUID = Guid.NewGuid().ToString("N"),
TrayCode = trayCode,
ProductionCode = code
};
entities.Add(entity);
}
_helper.InsertRange(entities);
return true;
}
catch(Exception ex)
{
_log.Error("托盘二维码重新绑定错误", ex);
return false;
}
}
}
}

@ -33,13 +33,11 @@ namespace Sln.Iot.Serilog
{
public static class SerilogExtensions
{
public static void UseSerilogExtensions(this IServiceProvider service)
public static void UseSerilogExtensions()
{
//启用Serilog中间件
#region 通过配置文件读取日志存放位置
var appConfig = service.GetService<AppConfig>();
var appConfig = AppConfigSetting.Load();
var logPath = Path.Combine(appConfig.logPath, "Logs");
#endregion

@ -30,6 +30,16 @@ namespace Sln.Iot.Serilog
{
public class SerilogHelper
{
private static readonly Lazy<SerilogHelper> lazy = new Lazy<SerilogHelper>(() => new SerilogHelper());
public static SerilogHelper Instance
{
get
{
return lazy.Value;
}
}
private readonly ILogger? Info_logger = Log.ForContext("Module", "Info");
private readonly ILogger? Iot_logger = Log.ForContext("Module", "Iot");
private readonly ILogger? Error_logger = Log.ForContext("Module", "Error");

@ -49,6 +49,7 @@ namespace Sln.Iot.Test
},
};
var ress = SQLiteHelper<TrayRfidBinding>.Instance.InsertRange(testDatas);
var res = SQLiteHelper<TrayRfidBinding>.Instance.DeleteRange("Tray001");
Assert.Equal(5, res.Count);

@ -2,6 +2,7 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Sln.Iot.Config;
using Sln.Iot.PLC;
using Sln.Iot.Repository;
using Sln.Iot.Serilog;
using TouchSocket.Sockets;
@ -9,66 +10,24 @@ using TouchSocket.Sockets;
namespace Sln.Iot
{
/// <summary>
///
/// 程序主入口
/// </summary>
internal class Program
public class Program
{
public static IServiceProvider? ServiceProvider = null;
static async Task Main(string[] args)
{
var services = new ServiceCollection();
ConfigureServices(services);
ServiceProvider = services.BuildServiceProvider();
ServiceProvider.UseSerilogExtensions();
//Serilog中间件
SerilogExtensions.UseSerilogExtensions();
//日志实例
var log = SerilogHelper.Instance;
//配置文件加载
var appConfig = AppConfigSetting.Load();
PLCConnect.Instance.InitConnect();
var appConfig = ServiceProvider.GetService<AppConfig>();
var log = ServiceProvider.GetService<SerilogHelper>();
log.Info($"系统启动成功,日志存放位置:{appConfig.logPath}");
await Task.Delay(-1);
}
private static void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<AppConfig>(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<AppConfig>();
return ap;
});
//services.AddSingleton<TcpClient>(provider =>
//{
// TcpClient tcpClient = new TcpClient();
// tcpClient.Setup(new TouchSocketConfig()
// .SetRemoteIPHost("127.0.0.1:6000")
// .ConfigureContainer(a =>
// {
// a.AddConsoleLogger();
// }));
// tcpClient.Connect();
// return tcpClient;
//});
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()
.WithSingletonLifetime());
services.AddSingleton(typeof(SerilogHelper));
}
}
}

@ -12,13 +12,14 @@
<ProjectReference Include="..\Sln.Iot.Business\Sln.Iot.Business.csproj" />
<ProjectReference Include="..\Sln.Iot.Common\Sln.Iot.Common.csproj" />
<ProjectReference Include="..\Sln.Iot.Config\Sln.Iot.Config.csproj" />
<ProjectReference Include="..\Sln.Iot.PLC\Sln.Iot.PLC.csproj" />
<ProjectReference Include="..\Sln.Iot.Repository\Sln.Iot.Repository.csproj" />
<ProjectReference Include="..\Sln.Iot.Serilog\Sln.Iot.Serilog.csproj" />
<ProjectReference Include="..\Sln.Iot.Socket\Sln.Iot.Socket.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.5" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.10" />
<PackageReference Include="Scrutor" Version="6.0.1" />
</ItemGroup>

@ -1,6 +1,6 @@
{
"AppConfig": {
"logPath": "\\\\Mac\\Home\\Public\\WorkSpace\\Mesnac\\项目资料\\IOT物联网数据采集\\日志信息",
"logPath": "D:\\log",
"listernPort": 6000,
"virtualFlag": true,
"virtualValue": 9999999,

Loading…
Cancel
Save