Compare commits

..

20 Commits
2.0.2 ... 2.0.5

Author SHA1 Message Date
Kimdiego2098
6f972aa515 2.0.5 2023-08-10 18:23:40 +08:00
Kimdiego2098
7407ba6313 去除不需要的模板 2023-08-10 16:28:52 +08:00
Kimdiego2098
1c79de207b 修改详情模板 2023-08-10 11:23:18 +08:00
Kimdiego2098
257c79db92 添加自定义详情模板 2023-08-10 10:35:19 +08:00
Kimdiego2098
9d1934a308 底层修改:如果连接端口断开,停止等待返回 2023-08-10 10:35:01 +08:00
Kimdiego2098
d70f959902 上传DTO添加 单位 参数 2023-08-10 09:09:09 +08:00
Kimdiego2098
e4d810222f 调整调试页面 2023-08-09 23:45:53 +08:00
Kimdiego2098
bc1af4ae07 添加单文件发布配置 2023-08-09 15:12:55 +08:00
Kimdiego2098
6e688ef43f 去除页面多余引号 2023-08-09 13:45:27 +08:00
Kimdiego2098
f0fe1b23dc 更新2.0.4 2023-08-09 13:00:10 +08:00
Kimdiego2098
aaf2006401 更新opcua写入 2023-08-09 12:43:05 +08:00
Kimdiego2098
b821e26935 更新opcua调试页面 2023-08-09 12:01:23 +08:00
Kimdiego2098
7ae4287157 更新opcua 2023-08-09 11:47:04 +08:00
Kimdiego2098
c6fcc38a65 修复中间变量导入错误 2023-08-09 09:00:49 +08:00
Kimdiego2098
ab2d5c8853 修正错误注释 2023-08-08 18:09:23 +08:00
Kimdiego2098
5e557ff0bc opcua添加初始化连接错误重试 2023-08-08 18:04:24 +08:00
Kimdiego2098
918ca449a1 更新readme 2023-08-08 16:14:06 +08:00
Kimdiego2098
8e73368008 优化大量设备线程重启的耗时 2023-08-08 14:02:00 +08:00
Kimdiego2098
f3c1faf672 2.0.3 2023-08-08 12:59:14 +08:00
Kimdiego2098
d6df04dd6a 底层部分方法更改 2023-08-08 12:31:42 +08:00
100 changed files with 662 additions and 299 deletions

5
.gitignore vendored
View File

@@ -360,4 +360,7 @@ MigrationBackup/
.ionide/ .ionide/
# Fody - auto-generated XML schema # Fody - auto-generated XML schema
FodyWeavers.xsd FodyWeavers.xsd
/framework/*Pro*

View File

@@ -5,12 +5,11 @@
**NetCore** 跨平台边缘采集网关(工业设备采集) **NetCore** 跨平台边缘采集网关(工业设备采集)
**ThingsGateway** 存储库同时提供 [**设备采集驱动**](https://www.nuget.org/profiles/KimDiego) **ThingsGateway** 存储库同时提供 [**设备采集驱动**](https://www.nuget.org/packages?q=Tags%3A%22ThingsGateway%22)
**ThingsGateway** 存储库同时提供 **基于Blazor的权限框架** 查看 [**ThingsGateway.Admin**](https://gitee.com/dotnetchina/ThingsGateway/blob/master/framework/ThingsGateway.Admin.sln) **ThingsGateway** 存储库同时提供 **基于Blazor的权限框架** 查看 [**ThingsGateway.Admin**](https://gitee.com/dotnetchina/ThingsGateway/blob/master/framework/ThingsGateway.Admin.sln)
## 文档 ## 文档
[ThingsGateway](https://diego2098.gitee.io/thingsgateway-docs/) 文档。 [ThingsGateway](https://diego2098.gitee.io/thingsgateway-docs/) 文档。

View File

@@ -81,6 +81,15 @@ dotnet_diagnostic.CA2208.severity = none
# IDE0057: 使用范围运算符 # IDE0057: 使用范围运算符
dotnet_diagnostic.IDE0057.severity = none dotnet_diagnostic.IDE0057.severity = none
# IDE0056: 使用索引运算符
dotnet_diagnostic.IDE0056.severity = none
# CA1830: 最好使用 StringBuilder 的强类型 Append 和 Insert 方法重载
dotnet_diagnostic.CA1830.severity = none
# CA1847: 将字符型文本用于单个字符查找
dotnet_diagnostic.CA1847.severity = none
[*.vb] [*.vb]
#### 命名样式 #### #### 命名样式 ####

View File

@@ -1,7 +1,7 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net6.0;net7.0</TargetFrameworks> <TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<Version>2.0.0.0</Version> <Version>2.0.5.0</Version>
<Authors>Diego</Authors> <Authors>Diego</Authors>
<Product>ThingsGateway</Product> <Product>ThingsGateway</Product>
<Copyright>© 2023-present Diego</Copyright> <Copyright>© 2023-present Diego</Copyright>

View File

@@ -19,7 +19,7 @@ using ThingsGateway.Admin.Core;
namespace ThingsGateway.Admin.Application; namespace ThingsGateway.Admin.Application;
/// <summary> /// <summary>
/// 后台登录控制器 /// 文件下载
/// </summary> /// </summary>
[ApiDescriptionSettings(CateGoryConst.ThingsGatewayAdmin, Order = 200)] [ApiDescriptionSettings(CateGoryConst.ThingsGatewayAdmin, Order = 200)]
[Route("file")] [Route("file")]

View File

@@ -46,7 +46,7 @@ namespace ThingsGateway.Admin.Application
[AllowAnonymous, NonUnify] [AllowAnonymous, NonUnify]
public async Task<int> SwaggerCheckUrlAsync() public async Task<int> SwaggerCheckUrlAsync()
{ {
var enable = (await _configService.GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_SWAGGERLOGIN_OPEN)).ConfigValue.ToBool(); var enable = (await _configService.GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_SWAGGERLOGIN_OPEN)).ConfigValue.ToBoolean();
return enable ? 401 : 200; return enable ? 401 : 200;
} }

View File

@@ -30,7 +30,7 @@
</member> </member>
<member name="T:ThingsGateway.Admin.Application.FileController"> <member name="T:ThingsGateway.Admin.Application.FileController">
<summary> <summary>
后台登录控制器 文件下载
</summary> </summary>
</member> </member>
<member name="M:ThingsGateway.Admin.Application.FileController.#ctor(ThingsGateway.Admin.Application.IFileService,ThingsGateway.Admin.Application.IOperateLogService,ThingsGateway.Admin.Application.IVisitLogService)"> <member name="M:ThingsGateway.Admin.Application.FileController.#ctor(ThingsGateway.Admin.Application.IFileService,ThingsGateway.Admin.Application.IOperateLogService,ThingsGateway.Admin.Application.IVisitLogService)">

View File

@@ -149,7 +149,7 @@ public class OpenApiAuthService : IOpenApiAuthService, ITransient
{ {
bool isSingle = false;//默认不开启单用户登录 bool isSingle = false;//默认不开启单用户登录
var singleConfig = await _configService.GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_SINGLE_OPEN);//获取系统单用户登录选项 var singleConfig = await _configService.GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_SINGLE_OPEN);//获取系统单用户登录选项
if (singleConfig != null) isSingle = singleConfig.ConfigValue.ToBool();//如果配置不为空则设置单用户登录选项为系统配置的值 if (singleConfig != null) isSingle = singleConfig.ConfigValue.ToBoolean();//如果配置不为空则设置单用户登录选项为系统配置的值
//判断是否单用户登录 //判断是否单用户登录
if (isSingle) if (isSingle)

View File

@@ -79,7 +79,7 @@ public class AuthService : IAuthService
if (sysBase != null)//如果有这个配置项 if (sysBase != null)//如果有这个配置项
{ {
if (sysBase.ConfigValue.ToBool())//如果需要验证码 if (sysBase.ConfigValue.ToBoolean())//如果需要验证码
{ {
//如果没填验证码,提示验证码不能为空 //如果没填验证码,提示验证码不能为空
if (input.ValidCode.IsNullOrEmpty() || input.ValidCodeReqNo == 0) throw Oops.Bah("验证码不能为空").StatusCode(410); if (input.ValidCode.IsNullOrEmpty() || input.ValidCodeReqNo == 0) throw Oops.Bah("验证码不能为空").StatusCode(410);
@@ -217,7 +217,7 @@ public class AuthService : IAuthService
bool isSingle = false;//默认不开启单用户登录 bool isSingle = false;//默认不开启单用户登录
var singleConfig = await _configService.GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_SINGLE_OPEN);//获取系统单用户登录选项 var singleConfig = await _configService.GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_SINGLE_OPEN);//获取系统单用户登录选项
if (singleConfig != null) isSingle = singleConfig.ConfigValue.ToBool();//如果配置不为空则设置单用户登录选项为系统配置的值 if (singleConfig != null) isSingle = singleConfig.ConfigValue.ToBoolean();//如果配置不为空则设置单用户登录选项为系统配置的值
if (isSingle)//判断是否单用户登录 if (isSingle)//判断是否单用户登录
{ {
await _noticeService.LogoutAsync(loginEvent.SysUser.Id, verificatInfos.Where(it => it.Device == loginEvent.Device.ToString()).ToList(), "该账号已在别处登录!");//通知其他用户下线 await _noticeService.LogoutAsync(loginEvent.SysUser.Id, verificatInfos.Where(it => it.Device == loginEvent.Device.ToString()).ToList(), "该账号已在别处登录!");//通知其他用户下线

View File

@@ -189,7 +189,7 @@
} }
else else
{ {
if (ItemColWithDTTemplate!=null) if (ItemColWithDTTemplate != null)
{ {
@ItemColWithDTTemplate(context) @ItemColWithDTTemplate(context)
} }
@@ -220,7 +220,7 @@
} }
} }
} }
</ItemColContent> </ItemColContent>
@@ -310,16 +310,24 @@
{ {
string value = DetailModelPairs[item.Value]; string value = DetailModelPairs[item.Value];
{ {
<tr @key="item.Text"> @if (Detailemplate != null)
<td class="text-start table-minwidth"> {
@item.Text @Detailemplate((item,value))
</td> }
<td class="text-start "> else
<div style="word-break:break-all; white-space:pre-wrap;"> {
@value <tr @key="item.Text">
</div> <td class="text-start table-minwidth">
</td> @item.Text
</tr> </td>
<td class="text-start ">
<div style="word-break:break-all; white-space:pre-wrap;">
@value
</div>
</td>
</tr>
}
} }
} }
} }

View File

@@ -72,12 +72,6 @@ public partial class AppDataTable<TItem, SearchItem, AddItem, EditItem> : IAppDa
[Parameter] [Parameter]
public bool Dense { get; set; } public bool Dense { get; set; }
/// <summary>
/// 获得/设置 明细行模板
/// </summary>
[Parameter]
public RenderFragment<TItem> DetailRowTemplate { get; set; }
/// <summary> /// <summary>
/// 编辑项委托 /// 编辑项委托
/// </summary> /// </summary>
@@ -89,6 +83,11 @@ public partial class AppDataTable<TItem, SearchItem, AddItem, EditItem> : IAppDa
/// </summary> /// </summary>
[Parameter] [Parameter]
public RenderFragment<EditItem> EditTemplate { get; set; } public RenderFragment<EditItem> EditTemplate { get; set; }
/// <summary>
/// 获得/设置 详情模板
/// </summary>
[Parameter]
public RenderFragment<(DataTableHeader<TItem>, string)> Detailemplate { get; set; }
/// <summary> /// <summary>
/// 表头过滤返回DataTableHeader列表传输参数已包含全部初始表头与表头标题 /// 表头过滤返回DataTableHeader列表传输参数已包含全部初始表头与表头标题

View File

@@ -133,7 +133,7 @@ public partial class Login
GetCaptchaInfo(); GetCaptchaInfo();
CONFIG_TITLE = (await App.GetService<IConfigService>().GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_TITLE))?.ConfigValue; CONFIG_TITLE = (await App.GetService<IConfigService>().GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_TITLE))?.ConfigValue;
CONFIG_REMARK = (await App.GetService<IConfigService>().GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_REMARK))?.ConfigValue; CONFIG_REMARK = (await App.GetService<IConfigService>().GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_REMARK))?.ConfigValue;
_showCaptcha = (await App.GetService<IConfigService>().GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_CAPTCHA_OPEN))?.ConfigValue?.ToBool() == true; _showCaptcha = (await App.GetService<IConfigService>().GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_CAPTCHA_OPEN))?.ConfigValue?.ToBoolean() == true;
Welcome = "欢迎使用" + CONFIG_TITLE + "!"; Welcome = "欢迎使用" + CONFIG_TITLE + "!";
await base.OnParametersSetAsync(); await base.OnParametersSetAsync();
} }

View File

@@ -43,11 +43,6 @@
表格紧凑 表格紧凑
</summary> </summary>
</member> </member>
<member name="P:ThingsGateway.Admin.Blazor.Core.AppDataTable`4.DetailRowTemplate">
<summary>
获得/设置 明细行模板
</summary>
</member>
<member name="P:ThingsGateway.Admin.Blazor.Core.AppDataTable`4.EditCallAsync"> <member name="P:ThingsGateway.Admin.Blazor.Core.AppDataTable`4.EditCallAsync">
<summary> <summary>
编辑项委托 编辑项委托
@@ -58,6 +53,11 @@
获得/设置 编辑模板 获得/设置 编辑模板
</summary> </summary>
</member> </member>
<member name="P:ThingsGateway.Admin.Blazor.Core.AppDataTable`4.Detailemplate">
<summary>
获得/设置 详情模板
</summary>
</member>
<member name="P:ThingsGateway.Admin.Blazor.Core.AppDataTable`4.FilterHeaders"> <member name="P:ThingsGateway.Admin.Blazor.Core.AppDataTable`4.FilterHeaders">
<summary> <summary>
表头过滤返回DataTableHeader列表传输参数已包含全部初始表头与表头标题 表头过滤返回DataTableHeader列表传输参数已包含全部初始表头与表头标题

View File

@@ -22,7 +22,7 @@ public class UserManager
/// <summary> /// <summary>
/// 是否超级管理员 /// 是否超级管理员
/// </summary> /// </summary>
public static bool IsSuperAdmin => (App.User?.FindFirst(ClaimConst.IsSuperAdmin)?.Value).ToBool(); public static bool IsSuperAdmin => (App.User?.FindFirst(ClaimConst.IsSuperAdmin)?.Value).ToBoolean();
/// <summary> /// <summary>
/// 当前用户账号 /// 当前用户账号

View File

@@ -330,7 +330,7 @@ public static class ObjectExtensions
/// 转换布尔值 /// 转换布尔值
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public static bool ToBool(this object value, bool defaultValue = false) => value?.ToString().ToUpper() switch public static bool ToBoolean(this object value, bool defaultValue = false) => value?.ToString().ToUpper() switch
{ {
"1" or "TRUE" => true, "1" or "TRUE" => true,
_ => defaultValue, _ => defaultValue,
@@ -356,10 +356,22 @@ public static class ObjectExtensions
{ {
return Double.IsNaN(d) ? defaultValue : (Decimal)d; return Double.IsNaN(d) ? defaultValue : (Decimal)d;
} }
var str = value.ToString(); var str = value?.ToString();
return str.IsNullOrEmpty() ? defaultValue : Decimal.TryParse(str, out var n) ? n : defaultValue; return str.IsNullOrEmpty() ? defaultValue : Decimal.TryParse(str, out var n) ? n : defaultValue;
} }
/// <summary>
/// ToDecimal
/// </summary>
/// <returns></returns>
public static double ToDouble(this object value, double defaultValue = 0)
{
if (value is Double d)
{
return Double.IsNaN(d) ? defaultValue : (Double)d;
}
var str = value?.ToString();
return str.IsNullOrEmpty() ? defaultValue : double.TryParse(str, out var n) ? n : defaultValue;
}
/// <summary> /// <summary>
/// JsonElement 转 Object /// JsonElement 转 Object

View File

@@ -97,7 +97,7 @@ public static class StringExtensions
/// 转换布尔值 /// 转换布尔值
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public static bool ToBool(this string value, bool defaultValue = false) => value?.ToUpper() switch public static bool ToBoolean(this string value, bool defaultValue = false) => value?.ToUpper() switch
{ {
"1" or "TRUE" => true, "1" or "TRUE" => true,
_ => defaultValue, _ => defaultValue,

View File

@@ -1026,7 +1026,7 @@
<param name="str"></param> <param name="str"></param>
<returns></returns> <returns></returns>
</member> </member>
<member name="M:ThingsGateway.Admin.Core.ObjectExtensions.ToBool(System.Object,System.Boolean)"> <member name="M:ThingsGateway.Admin.Core.ObjectExtensions.ToBoolean(System.Object,System.Boolean)">
<summary> <summary>
转换布尔值 转换布尔值
</summary> </summary>
@@ -1050,6 +1050,12 @@
</summary> </summary>
<returns></returns> <returns></returns>
</member> </member>
<member name="M:ThingsGateway.Admin.Core.ObjectExtensions.ToDouble(System.Object,System.Double)">
<summary>
ToDecimal
</summary>
<returns></returns>
</member>
<member name="M:ThingsGateway.Admin.Core.ObjectExtensions.ToObject(System.Text.Json.JsonElement)"> <member name="M:ThingsGateway.Admin.Core.ObjectExtensions.ToObject(System.Text.Json.JsonElement)">
<summary> <summary>
JsonElement 转 Object JsonElement 转 Object
@@ -1142,7 +1148,7 @@
<param name="input"></param> <param name="input"></param>
<returns></returns> <returns></returns>
</member> </member>
<member name="M:ThingsGateway.Admin.Core.StringExtensions.ToBool(System.String,System.Boolean)"> <member name="M:ThingsGateway.Admin.Core.StringExtensions.ToBoolean(System.String,System.Boolean)">
<summary> <summary>
转换布尔值 转换布尔值
</summary> </summary>

View File

@@ -21,7 +21,7 @@ using ThingsGateway.Application;
namespace ThingsGateway.ApiController; namespace ThingsGateway.ApiController;
/// <summary> /// <summary>
/// 后台登录控制器 /// 文件下载
/// </summary> /// </summary>
[ApiDescriptionSettings(CateGoryConst.ThingsGatewayAdmin, Order = 200)] [ApiDescriptionSettings(CateGoryConst.ThingsGatewayAdmin, Order = 200)]
[Route("gatewayFile")] [Route("gatewayFile")]

View File

@@ -26,7 +26,7 @@
</member> </member>
<member name="T:ThingsGateway.ApiController.FileController"> <member name="T:ThingsGateway.ApiController.FileController">
<summary> <summary>
后台登录控制器 文件下载
</summary> </summary>
</member> </member>
<member name="M:ThingsGateway.ApiController.FileController.#ctor(ThingsGateway.Application.IRpcLogService,ThingsGateway.Application.IBackendLogService,ThingsGateway.Application.ICollectDeviceService,ThingsGateway.Application.IUploadDeviceService,ThingsGateway.Application.IVariableService)"> <member name="M:ThingsGateway.ApiController.FileController.#ctor(ThingsGateway.Application.IRpcLogService,ThingsGateway.Application.IBackendLogService,ThingsGateway.Application.ICollectDeviceService,ThingsGateway.Application.IUploadDeviceService,ThingsGateway.Application.IVariableService)">

View File

@@ -31,7 +31,7 @@ public class DeviceVariable : MemoryVariable
public virtual long DeviceId { get; set; } public virtual long DeviceId { get; set; }
/// <summary> /// <summary>
/// 写入表达式 /// 单位
/// </summary> /// </summary>
[SugarColumn(ColumnName = "Unit", ColumnDescription = "单位", Length = 200, IsNullable = true)] [SugarColumn(ColumnName = "Unit", ColumnDescription = "单位", Length = 200, IsNullable = true)]
[DataTable(Order = 3, IsShow = true, Sortable = true)] [DataTable(Order = 3, IsShow = true, Sortable = true)]
@@ -59,12 +59,7 @@ public class DeviceVariable : MemoryVariable
[DataTable(Order = 3, IsShow = true, Sortable = true)] [DataTable(Order = 3, IsShow = true, Sortable = true)]
public string VariableAddress { get; set; } public string VariableAddress { get; set; }
/// <summary>
/// 写入表达式
/// </summary>
[SugarColumn(ColumnName = "WriteExpressions", ColumnDescription = "写入表达式", Length = 200, IsNullable = true)]
[DataTable(Order = 7, IsShow = true, Sortable = true)]
public string WriteExpressions { get; set; }
/// <summary> /// <summary>
/// 是否中间变量 /// 是否中间变量

View File

@@ -51,7 +51,12 @@ public class MemoryVariable : BaseEntity
[SugarColumn(ColumnName = "ReadExpressions", ColumnDescription = "读取表达式", Length = 200, IsNullable = true)] [SugarColumn(ColumnName = "ReadExpressions", ColumnDescription = "读取表达式", Length = 200, IsNullable = true)]
[DataTable(Order = 7, IsShow = true, Sortable = true, CellClass = " table-text-truncate ")] [DataTable(Order = 7, IsShow = true, Sortable = true, CellClass = " table-text-truncate ")]
public string ReadExpressions { get; set; } public string ReadExpressions { get; set; }
/// <summary>
/// 写入表达式
/// </summary>
[SugarColumn(ColumnName = "WriteExpressions", ColumnDescription = "写入表达式", Length = 200, IsNullable = true)]
[DataTable(Order = 7, IsShow = true, Sortable = true)]
public string WriteExpressions { get; set; }
/// <summary> /// <summary>
/// 是否中间变量 /// 是否中间变量
/// </summary> /// </summary>

View File

@@ -20,6 +20,8 @@ public class VariableData
public long Id { get; set; } public long Id { get; set; }
/// <inheritdoc cref="MemoryVariable.Name"/> /// <inheritdoc cref="MemoryVariable.Name"/>
public string Name { get; set; } public string Name { get; set; }
/// <inheritdoc cref="DeviceVariable.Unit"/>
public string Unit { get; set; }
/// <inheritdoc cref="MemoryVariable.Description"/> /// <inheritdoc cref="MemoryVariable.Description"/>
public string Description { get; set; } public string Description { get; set; }
/// <inheritdoc cref="DeviceVariableRunTime.DeviceName"/> /// <inheritdoc cref="DeviceVariableRunTime.DeviceName"/>
@@ -36,7 +38,7 @@ public class VariableData
public bool IsOnline { get; set; } public bool IsOnline { get; set; }
/// <inheritdoc cref="MemoryVariable.ReadExpressions"/> /// <inheritdoc cref="MemoryVariable.ReadExpressions"/>
public string ReadExpressions { get; set; } public string ReadExpressions { get; set; }
/// <inheritdoc cref="DeviceVariable.WriteExpressions"/> /// <inheritdoc cref="MemoryVariable.WriteExpressions"/>
public string WriteExpressions { get; set; } public string WriteExpressions { get; set; }
/// <inheritdoc cref="DeviceVariable.IntervalTime"/> /// <inheritdoc cref="DeviceVariable.IntervalTime"/>
public int IntervalTime { get; set; } public int IntervalTime { get; set; }

View File

@@ -17,8 +17,6 @@ using Newtonsoft.Json.Linq;
using ThingsGateway.Foundation; using ThingsGateway.Foundation;
using ThingsGateway.Foundation.Serial; using ThingsGateway.Foundation.Serial;
using TouchSocket.Core;
namespace ThingsGateway.Application; namespace ThingsGateway.Application;
/// <summary> /// <summary>
/// <para></para> /// <para></para>

View File

@@ -360,7 +360,7 @@
</member> </member>
<member name="P:ThingsGateway.Application.DeviceVariable.Unit"> <member name="P:ThingsGateway.Application.DeviceVariable.Unit">
<summary> <summary>
写入表达式 单位
</summary> </summary>
</member> </member>
<member name="P:ThingsGateway.Application.DeviceVariable.IntervalTime"> <member name="P:ThingsGateway.Application.DeviceVariable.IntervalTime">
@@ -378,11 +378,6 @@
变量地址,可能带有额外的信息,比如<see cref="T:ThingsGateway.Foundation.DataFormat"/> ,以;分割 变量地址,可能带有额外的信息,比如<see cref="T:ThingsGateway.Foundation.DataFormat"/> ,以;分割
</summary> </summary>
</member> </member>
<member name="P:ThingsGateway.Application.DeviceVariable.WriteExpressions">
<summary>
写入表达式
</summary>
</member>
<member name="P:ThingsGateway.Application.DeviceVariable.IsMemoryVariable"> <member name="P:ThingsGateway.Application.DeviceVariable.IsMemoryVariable">
<summary> <summary>
是否中间变量 是否中间变量
@@ -524,6 +519,11 @@
读取表达式 读取表达式
</summary> </summary>
</member> </member>
<member name="P:ThingsGateway.Application.MemoryVariable.WriteExpressions">
<summary>
写入表达式
</summary>
</member>
<member name="P:ThingsGateway.Application.MemoryVariable.IsMemoryVariable"> <member name="P:ThingsGateway.Application.MemoryVariable.IsMemoryVariable">
<summary> <summary>
是否中间变量 是否中间变量
@@ -1791,6 +1791,9 @@
<member name="P:ThingsGateway.Application.VariableData.Name"> <member name="P:ThingsGateway.Application.VariableData.Name">
<inheritdoc cref="P:ThingsGateway.Application.MemoryVariable.Name"/> <inheritdoc cref="P:ThingsGateway.Application.MemoryVariable.Name"/>
</member> </member>
<member name="P:ThingsGateway.Application.VariableData.Unit">
<inheritdoc cref="P:ThingsGateway.Application.DeviceVariable.Unit"/>
</member>
<member name="P:ThingsGateway.Application.VariableData.Description"> <member name="P:ThingsGateway.Application.VariableData.Description">
<inheritdoc cref="P:ThingsGateway.Application.MemoryVariable.Description"/> <inheritdoc cref="P:ThingsGateway.Application.MemoryVariable.Description"/>
</member> </member>
@@ -1816,7 +1819,7 @@
<inheritdoc cref="P:ThingsGateway.Application.MemoryVariable.ReadExpressions"/> <inheritdoc cref="P:ThingsGateway.Application.MemoryVariable.ReadExpressions"/>
</member> </member>
<member name="P:ThingsGateway.Application.VariableData.WriteExpressions"> <member name="P:ThingsGateway.Application.VariableData.WriteExpressions">
<inheritdoc cref="P:ThingsGateway.Application.DeviceVariable.WriteExpressions"/> <inheritdoc cref="P:ThingsGateway.Application.MemoryVariable.WriteExpressions"/>
</member> </member>
<member name="P:ThingsGateway.Application.VariableData.IntervalTime"> <member name="P:ThingsGateway.Application.VariableData.IntervalTime">
<inheritdoc cref="P:ThingsGateway.Application.DeviceVariable.IntervalTime"/> <inheritdoc cref="P:ThingsGateway.Application.DeviceVariable.IntervalTime"/>
@@ -3561,6 +3564,11 @@
开始采集 开始采集
</summary> </summary>
</member> </member>
<member name="M:ThingsGateway.Application.CollectDeviceThread.BeforeStopThreadAsync">
<summary>
停止采集前提前取消Token
</summary>
</member>
<member name="M:ThingsGateway.Application.CollectDeviceThread.StopThreadAsync"> <member name="M:ThingsGateway.Application.CollectDeviceThread.StopThreadAsync">
<summary> <summary>
停止采集 停止采集
@@ -3934,6 +3942,11 @@
开始上传 开始上传
</summary> </summary>
</member> </member>
<member name="M:ThingsGateway.Application.UploadDeviceThread.BeforeStopThreadAsync">
<summary>
停止采集前提前取消Token
</summary>
</member>
<member name="M:ThingsGateway.Application.UploadDeviceThread.StopThreadAsync"> <member name="M:ThingsGateway.Application.UploadDeviceThread.StopThreadAsync">
<summary> <summary>
停止上传 停止上传

View File

@@ -74,7 +74,7 @@ public class AlarmWorker : BackgroundService
public async Task<OperResult<SqlSugarClient>> GetAlarmDbAsync() public async Task<OperResult<SqlSugarClient>> GetAlarmDbAsync()
{ {
var ConfigService = ServiceHelper.Services.GetService<IConfigService>(); var ConfigService = ServiceHelper.Services.GetService<IConfigService>();
var alarmEnable = (await ConfigService.GetByConfigKeyAsync(ThingsGatewayConfigConst.ThingGateway_AlarmConfig_Base, ThingsGatewayConfigConst.Config_Alarm_Enable))?.ConfigValue?.ToBool(); var alarmEnable = (await ConfigService.GetByConfigKeyAsync(ThingsGatewayConfigConst.ThingGateway_AlarmConfig_Base, ThingsGatewayConfigConst.Config_Alarm_Enable))?.ConfigValue?.ToBoolean();
var alarmDbType = (await ConfigService.GetByConfigKeyAsync(ThingsGatewayConfigConst.ThingGateway_AlarmConfig_Base, ThingsGatewayConfigConst.Config_Alarm_DbType))?.ConfigValue; var alarmDbType = (await ConfigService.GetByConfigKeyAsync(ThingsGatewayConfigConst.ThingGateway_AlarmConfig_Base, ThingsGatewayConfigConst.Config_Alarm_DbType))?.ConfigValue;
var alarmConnstr = (await ConfigService.GetByConfigKeyAsync(ThingsGatewayConfigConst.ThingGateway_AlarmConfig_Base, ThingsGatewayConfigConst.Config_Alarm_ConnStr))?.ConfigValue; var alarmConnstr = (await ConfigService.GetByConfigKeyAsync(ThingsGatewayConfigConst.ThingGateway_AlarmConfig_Base, ThingsGatewayConfigConst.Config_Alarm_ConnStr))?.ConfigValue;
@@ -132,14 +132,14 @@ public class AlarmWorker : BackgroundService
limit = string.Empty; limit = string.Empty;
expressions = string.Empty; expressions = string.Empty;
text = string.Empty; text = string.Empty;
if (tag.BoolCloseAlarmEnable && tag.Value.ToBool() == false) if (tag.BoolCloseAlarmEnable && tag.Value.ToBoolean() == false)
{ {
limit = false.ToString(); limit = false.ToString();
expressions = tag.BoolCloseRestrainExpressions; expressions = tag.BoolCloseRestrainExpressions;
text = tag.BoolCloseAlarmText; text = tag.BoolCloseAlarmText;
return AlarmEnum.Close; return AlarmEnum.Close;
} }
if (tag.BoolOpenAlarmEnable && tag.Value.ToBool() == true) if (tag.BoolOpenAlarmEnable && tag.Value.ToBoolean() == true)
{ {
limit = true.ToString(); limit = true.ToString();
expressions = tag.BoolOpenRestrainExpressions; expressions = tag.BoolOpenRestrainExpressions;

View File

@@ -85,6 +85,29 @@ public class CollectDeviceThread : IAsyncDisposable
easyLock.Release(); easyLock.Release();
} }
} }
/// <summary>
/// 停止采集前提前取消Token
/// </summary>
public virtual async Task BeforeStopThreadAsync()
{
try
{
await easyLock.WaitAsync();
if (DeviceTask == null)
{
return;
}
foreach (var token in StoppingTokens)
{
token.Cancel();
}
}
finally
{
easyLock.Release();
}
}
/// <summary> /// <summary>
/// 停止采集 /// 停止采集
@@ -173,7 +196,10 @@ public class CollectDeviceThread : IAsyncDisposable
foreach (var device in CollectDeviceCores) foreach (var device in CollectDeviceCores)
{ {
try try
{//初始化成功才能执行 {
if (stoppingToken.IsCancellationRequested)
break;
//初始化成功才能执行
if (device.IsInitSuccess) if (device.IsInitSuccess)
{ {
//如果是共享通道类型,需要每次转换时切换适配器 //如果是共享通道类型,需要每次转换时切换适配器

View File

@@ -328,6 +328,18 @@ public class CollectDeviceWorker : BackgroundService
/// </summary> /// </summary>
private async Task RemoveAllDeviceThreadAsync() private async Task RemoveAllDeviceThreadAsync()
{ {
await CollectDeviceThreads.ParallelForEachAsync(async (deviceThread, token) =>
{
try
{
await deviceThread.BeforeStopThreadAsync();
}
catch (Exception ex)
{
_logger?.LogError(ex, deviceThread.ToString());
}
}, 10);
await CollectDeviceThreads.ParallelForEachAsync(async (deviceThread, token) => await CollectDeviceThreads.ParallelForEachAsync(async (deviceThread, token) =>
{ {
try try

View File

@@ -60,7 +60,7 @@ public class HistoryValueWorker : BackgroundService
public async Task<OperResult<SqlSugarClient>> GetHisDbAsync() public async Task<OperResult<SqlSugarClient>> GetHisDbAsync()
{ {
var ConfigService = ServiceHelper.Services.GetService<IConfigService>(); var ConfigService = ServiceHelper.Services.GetService<IConfigService>();
var hisEnable = (await ConfigService.GetByConfigKeyAsync(ThingsGatewayConfigConst.ThingGateway_HisConfig_Base, ThingsGatewayConfigConst.Config_His_Enable))?.ConfigValue?.ToBool(); var hisEnable = (await ConfigService.GetByConfigKeyAsync(ThingsGatewayConfigConst.ThingGateway_HisConfig_Base, ThingsGatewayConfigConst.Config_His_Enable))?.ConfigValue?.ToBoolean();
var hisDbType = (await ConfigService.GetByConfigKeyAsync(ThingsGatewayConfigConst.ThingGateway_HisConfig_Base, ThingsGatewayConfigConst.Config_His_DbType))?.ConfigValue; var hisDbType = (await ConfigService.GetByConfigKeyAsync(ThingsGatewayConfigConst.ThingGateway_HisConfig_Base, ThingsGatewayConfigConst.Config_His_DbType))?.ConfigValue;
var hisConnstr = (await ConfigService.GetByConfigKeyAsync(ThingsGatewayConfigConst.ThingGateway_HisConfig_Base, ThingsGatewayConfigConst.Config_His_ConnStr))?.ConfigValue; var hisConnstr = (await ConfigService.GetByConfigKeyAsync(ThingsGatewayConfigConst.ThingGateway_HisConfig_Base, ThingsGatewayConfigConst.Config_His_ConnStr))?.ConfigValue;
@@ -458,7 +458,7 @@ public class HistoryValueMapper : IRegister
{ {
if (src.Value?.ToString()?.IsBoolValue() == true) if (src.Value?.ToString()?.IsBoolValue() == true)
{ {
if (src.Value.ToBool()) if (src.Value.ToBoolean())
{ {
return 1; return 1;
} }

View File

@@ -74,6 +74,29 @@ public class UploadDeviceThread : IAsyncDisposable
easyLock.Release(); easyLock.Release();
} }
} }
/// <summary>
/// 停止采集前提前取消Token
/// </summary>
public virtual async Task BeforeStopThreadAsync()
{
try
{
await easyLock.WaitAsync();
if (DeviceTask == null)
{
return;
}
foreach (var token in StoppingTokens)
{
token.Cancel();
}
}
finally
{
easyLock.Release();
}
}
/// <summary> /// <summary>
/// 停止上传 /// 停止上传
@@ -152,7 +175,10 @@ public class UploadDeviceThread : IAsyncDisposable
foreach (var device in UploadDeviceCores) foreach (var device in UploadDeviceCores)
{ {
try try
{//初始化成功才能执行 {
if (stoppingToken.IsCancellationRequested)
break;
//初始化成功才能执行
if (device.IsInitSuccess) if (device.IsInitSuccess)
{ {

View File

@@ -239,6 +239,17 @@ public class UploadDeviceWorker : BackgroundService
/// </summary> /// </summary>
private async Task RemoveAllDeviceThreadAsync() private async Task RemoveAllDeviceThreadAsync()
{ {
await UploadDeviceThreads.ParallelForEachAsync(async (deviceThread, token) =>
{
try
{
await deviceThread.BeforeStopThreadAsync();
}
catch (Exception ex)
{
_logger?.LogError(ex, deviceThread.ToString());
}
}, 10);
await UploadDeviceThreads.ParallelForEachAsync(async (deviceThread, token) => await UploadDeviceThreads.ParallelForEachAsync(async (deviceThread, token) =>
{ {
try try

View File

@@ -102,44 +102,6 @@
} }
@foreach (var item in ImportPreviews)
{
<MSubheader Class="mt-2 font-weight-black">
@(
$"{item.Key},预计导入{item.Value.DataCount}条数据"
)
</MSubheader>
<MSubheader Class=@((item.Value.HasError?"mt-2 red--text":"mt-2 green--text"))>
@(
(item.Value.HasError ? "出现错误" : "验证成功")
)
</MSubheader>
<MVirtualScroll Context="item1" Height=300 OverscanCount=2 ItemSize="60" Items="item.Value.Results">
<ItemContent>
<MListItem>
<MListItemAction>
<MChip Class="ma-2">
@(
$"第{item1.row}行"
)
</MChip>
</MListItemAction>
<MListItemContent>
<MListItemTitle Class=@((item1.isSuccess?"green--text":"red--text"))>
<strong>@item1.resultString</strong>
</MListItemTitle>
</MListItemContent>
</MListItem>
<MDivider></MDivider>
</ItemContent>
</MVirtualScroll>
}
</div> </div>
<div class="mt-6"> <div class="mt-6">
<MButton Color="primary" Disabled=@ImportPreviews.Any(it=>it.Value.HasError) OnClick="()=>Step=3">下一步</MButton> <MButton Color="primary" Disabled=@ImportPreviews.Any(it=>it.Value.HasError) OnClick="()=>Step=3">下一步</MButton>

View File

@@ -78,8 +78,7 @@ public partial class SerialClientPage
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnInitialized() protected override void OnInitialized()
{ {
config?.Dispose(); config ??= new TouchSocketConfig();
config = new TouchSocketConfig();
var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace }; var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace };
LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace }); LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace });
config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));

View File

@@ -78,8 +78,7 @@ public partial class TcpClientPage
/// <returns></returns> /// <returns></returns>
public TcpClientEx GetTcpClient() public TcpClientEx GetTcpClient()
{ {
config?.Dispose(); config ??= new TouchSocketConfig();
config = new TouchSocketConfig();
var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace }; var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace };
LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace }); LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace });
config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));

View File

@@ -67,8 +67,7 @@ public partial class TcpServerPage
/// <returns></returns> /// <returns></returns>
public TcpService GetTcpServer() public TcpService GetTcpServer()
{ {
config?.Dispose(); config ??= new TouchSocketConfig();
config = new TouchSocketConfig();
var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace }; var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace };
LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace }); LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace });
config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));

View File

@@ -67,8 +67,7 @@ public partial class UdpSessionPage : IDisposable
/// <returns></returns> /// <returns></returns>
public UdpSession GetUdpSession() public UdpSession GetUdpSession()
{ {
config?.Dispose(); config ??= new TouchSocketConfig();
config = new TouchSocketConfig();
var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace }; var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace };
LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace }); LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace });
config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));

View File

@@ -62,6 +62,7 @@
<MTextField Dense Style="max-width:200px;" HideDetails=@("auto") Class="mx-2 my-1" @bind-Value="_collectDeviceGroupSearchName" <MTextField Dense Style="max-width:200px;" HideDetails=@("auto") Class="mx-2 my-1" @bind-Value="_collectDeviceGroupSearchName"
Outlined Label=@typeof(CollectDevice).GetDescription(nameof(CollectDevice.DeviceGroup)) /> Outlined Label=@typeof(CollectDevice).GetDescription(nameof(CollectDevice.DeviceGroup)) />
</MCardTitle> </MCardTitle>
<MTreeview Style=@($"height: calc(100vh - {BlazorResourceConst.DefaultHeight + 240}px; overflow-y:auto)") Dense TItem="string" TKey="string" ActiveChanged=@(async a=> <MTreeview Style=@($"height: calc(100vh - {BlazorResourceConst.DefaultHeight + 240}px; overflow-y:auto)") Dense TItem="string" TKey="string" ActiveChanged=@(async a=>
{ {
if(_collectDeviceGroup!=a.FirstOrDefault()) if(_collectDeviceGroup!=a.FirstOrDefault())

View File

@@ -199,7 +199,6 @@ public partial class DeviceStatusPage : IDisposable
// await MainLayout.StateHasChangedAsync(); // await MainLayout.StateHasChangedAsync();
// } // }
//} //}
private async Task RunTimerAsync() private async Task RunTimerAsync()
{ {
while (await _periodicTimer.WaitForNextTickAsync()) while (await _periodicTimer.WaitForNextTickAsync())

View File

@@ -180,8 +180,41 @@ else
} }
</ItemColTemplate> </ItemColTemplate>
<Detailemplate>
@{
switch (context.Item1.Value)
{
case nameof(DeviceVariable.DeviceId):
<tr @key="context.Item1.Text">
<td class="text-start table-minwidth">
@context.Item1.Text
</td>
<td class="text-start ">
<div style="word-break:break-all; white-space:pre-wrap;">
@(App.GetService<ICollectDeviceService>().GetNameById(context.Item2.ToLong()))
</div>
</td>
</tr>
break;
default:
<tr @key="context.Item1.Text">
<td class="text-start table-minwidth">
@context.Item1.Text
</td>
<td class="text-start ">
<div style="word-break:break-all; white-space:pre-wrap;">
@context.Item2
</div>
</td>
</tr>
break;
}
}
</Detailemplate>
</AppDataTable> </AppDataTable>
; ;
return renderFragment; return renderFragment;
} }

View File

@@ -61,6 +61,7 @@ else
</span> </span>
</LabelContent> </LabelContent>
</MTreeview> </MTreeview>
</MCard> </MCard>
</MCol> </MCol>
<MCol Md=10 Cols="12"> <MCol Md=10 Cols="12">
@@ -119,7 +120,38 @@ else
} }
</ItemColTemplate> </ItemColTemplate>
<Detailemplate>
@{
switch (context.Item1.Value)
{
case nameof(DeviceVariable.DeviceId):
<tr @key="context.Item1.Text">
<td class="text-start table-minwidth">
@context.Item1.Text
</td>
<td class="text-start ">
<div style="word-break:break-all; white-space:pre-wrap;">
@(App.GetService<ICollectDeviceService>().GetNameById(context.Item2.ToLong()))
</div>
</td>
</tr>
break;
default:
<tr @key="context.Item1.Text">
<td class="text-start table-minwidth">
@context.Item1.Text
</td>
<td class="text-start ">
<div style="word-break:break-all; white-space:pre-wrap;">
@context.Item2
</div>
</td>
</tr>
break;
}
}
</Detailemplate>
</AppDataTable> </AppDataTable>
; ;

View File

@@ -32,7 +32,7 @@
@layout MainLayout @layout MainLayout
<MRow NoGutters> <MRow NoGutters>
<MCol Md=@(IsShowTreeView?4:0)> <MCol Md=@(IsShowTreeView?3:0)>
<MCard Show=IsShowTreeView Style=@($"height: calc(100vh - {BlazorResourceConst.DefaultHeight}px);border-radius:0px;")> <MCard Show=IsShowTreeView Style=@($"height: calc(100vh - {BlazorResourceConst.DefaultHeight}px);border-radius:0px;")>
<MCardTitle> <MCardTitle>
<MTextField Dense Style="max-width:200px;" HideDetails=@("auto") Class="mx-2 my-1" @bind-Value="_searchName" Outlined Label=@typeof(CollectDevice).GetDescription(nameof(CollectDevice.PluginId)) /> <MTextField Dense Style="max-width:200px;" HideDetails=@("auto") Class="mx-2 my-1" @bind-Value="_searchName" Outlined Label=@typeof(CollectDevice).GetDescription(nameof(CollectDevice.PluginId)) />
@@ -62,7 +62,7 @@
</MTreeview> </MTreeview>
</MCard> </MCard>
</MCol> </MCol>
<MCol Md=@(IsShowTreeView?8:12)> <MCol Md=@(IsShowTreeView?9:12)>
<MCard Style=@($"height: calc(100vh - {BlazorResourceConst.DefaultHeight}px);border-radius:0px;")> <MCard Style=@($"height: calc(100vh - {BlazorResourceConst.DefaultHeight}px);border-radius:0px;")>
<MCard Class="mb-3 pa-2 text-h6" Elevation="0" Flat Rounded="false"> <MCard Class="mb-3 pa-2 text-h6" Elevation="0" Flat Rounded="false">
<MRow Align="AlignTypes.Center" Class="mt-1"> <MRow Align="AlignTypes.Center" Class="mt-1">

View File

@@ -130,7 +130,7 @@
<MCard Elevation="1" Class="ma-2"> <MCard Elevation="1" Class="ma-2">
<MCardSubtitle Class=@("text-h6")> <MCardSubtitle Class=@("text-h6")>
<div class="mt-1 d-flex align-center justify-space-between"> <div class="mt-1 d-flex align-center justify-space-between">
<span>"当前内存/磁盘信息</span> <span>当前内存/磁盘信息</span>
</div> </div>
</MCardSubtitle> </MCardSubtitle>
<MDivider></MDivider> <MDivider></MDivider>

View File

@@ -149,6 +149,7 @@
<MTextField Dense Outlined HideDetails="@("auto")" @bind-Value=@context.ReadExpressions /> <MTextField Dense Outlined HideDetails="@("auto")" @bind-Value=@context.ReadExpressions />
</MCol> </MCol>
<MCol Md=6 Cols=12 class="px-1"> <MCol Md=6 Cols=12 class="px-1">
<MSubheader Class="font-weight-black"> @(context.Description(x => x.WriteExpressions)) </MSubheader> <MSubheader Class="font-weight-black"> @(context.Description(x => x.WriteExpressions)) </MSubheader>

View File

@@ -96,7 +96,7 @@ public partial class MemoryVariablePage
Task<Dictionary<string, ImportPreviewOutputBase>> DeviceImportAsync(IBrowserFile file) Task<Dictionary<string, ImportPreviewOutputBase>> DeviceImportAsync(IBrowserFile file)
{ {
return VariableService.PreviewAsync(file); return VariableService.MemoryVariablePreviewAsync(file);
} }

View File

@@ -30,7 +30,7 @@ public abstract class ReadWriteDevicesSerialBase : ReadWriteDevicesClientBase
public ReadWriteDevicesSerialBase(SerialClient serialClient) public ReadWriteDevicesSerialBase(SerialClient serialClient)
{ {
SerialClient = serialClient; SerialClient = serialClient;
WaitingClientEx = SerialClient.GetWaitingClientEx(new()); WaitingClientEx = SerialClient.GetWaitingClientEx(new() { BreakTrigger = true });
SerialClient.Connecting -= Connecting; SerialClient.Connecting -= Connecting;
SerialClient.Connected -= Connected; SerialClient.Connected -= Connected;

View File

@@ -26,7 +26,7 @@ public abstract class ReadWriteDevicesTcpClientBase : ReadWriteDevicesClientBase
public ReadWriteDevicesTcpClientBase(TcpClientEx tcpClient) public ReadWriteDevicesTcpClientBase(TcpClientEx tcpClient)
{ {
TcpClientEx = tcpClient; TcpClientEx = tcpClient;
WaitingClientEx = TcpClientEx.GetWaitingClientEx(new()); WaitingClientEx = TcpClientEx.GetWaitingClientEx(new() { BreakTrigger = true });
TcpClientEx.Connecting -= Connecting; TcpClientEx.Connecting -= Connecting;
TcpClientEx.Connected -= Connected; TcpClientEx.Connected -= Connected;
TcpClientEx.Disconnecting -= Disconnecting; TcpClientEx.Disconnecting -= Disconnecting;

View File

@@ -24,10 +24,8 @@ public abstract class ReadWriteDevicesUdpBase : ReadWriteDevicesClientBase
/// <inheritdoc cref="ReadWriteDevicesUdpBase"/> /// <inheritdoc cref="ReadWriteDevicesUdpBase"/>
public ReadWriteDevicesUdpBase(UdpSession udpSession) public ReadWriteDevicesUdpBase(UdpSession udpSession)
{ {
UdpSession = udpSession; UdpSession = udpSession;
WaitingClientEx = UdpSession.GetWaitingClientEx(new()); WaitingClientEx = UdpSession.GetWaitingClientEx(new() { BreakTrigger = true });
SetDataAdapter(); SetDataAdapter();
} }
/// <summary> /// <summary>

View File

@@ -12,6 +12,8 @@
using ThingsGateway.Foundation.Serial;
namespace ThingsGateway.Foundation; namespace ThingsGateway.Foundation;
internal class WaitingClientEx<TClient> : DisposableObject, IWaitingClient<TClient> where TClient : IClient, IDefaultSender, ISender internal class WaitingClientEx<TClient> : DisposableObject, IWaitingClient<TClient> where TClient : IClient, IDefaultSender, ISender
@@ -52,6 +54,7 @@ internal class WaitingClientEx<TClient> : DisposableObject, IWaitingClient<TClie
{ {
this.Client = default; this.Client = default;
this.m_waitData.SafeDispose(); this.m_waitData.SafeDispose();
this.m_waitDataAsync.SafeDispose();
base.Dispose(disposing); base.Dispose(disposing);
} }
@@ -66,7 +69,11 @@ internal class WaitingClientEx<TClient> : DisposableObject, IWaitingClient<TClie
this.m_breaked = true; this.m_breaked = true;
this.Cancel(); this.Cancel();
} }
private void OnSerialClientDisconnected(ISerialClientBase client, DisconnectEventArgs e)
{
this.m_breaked = true;
this.Cancel();
}
private bool OnHandleRawBuffer(ByteBlock byteBlock) private bool OnHandleRawBuffer(ByteBlock byteBlock)
{ {
var responsedData = new ResponsedData(byteBlock.ToArray(), null, true); var responsedData = new ResponsedData(byteBlock.ToArray(), null, true);
@@ -121,7 +128,10 @@ internal class WaitingClientEx<TClient> : DisposableObject, IWaitingClient<TClie
{ {
tcpClient.Disconnected += this.OnDisconnected; tcpClient.Disconnected += this.OnDisconnected;
} }
if (this.WaitingOptions.BreakTrigger && this.Client is ISerialClientBase serialClient)
{
serialClient.Disconnected += this.OnSerialClientDisconnected;
}
if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter) if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter)
{ {
this.Client.OnHandleReceivedData += this.OnHandleReceivedData; this.Client.OnHandleReceivedData += this.OnHandleReceivedData;
@@ -179,7 +189,10 @@ internal class WaitingClientEx<TClient> : DisposableObject, IWaitingClient<TClie
{ {
tcpClient.Disconnected -= this.OnDisconnected; tcpClient.Disconnected -= this.OnDisconnected;
} }
if (this.WaitingOptions.BreakTrigger && this.Client is ISerialClientBase serialClient)
{
serialClient.Disconnected -= this.OnSerialClientDisconnected;
}
if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter) if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter)
{ {
this.Client.OnHandleReceivedData -= this.OnHandleReceivedData; this.Client.OnHandleReceivedData -= this.OnHandleReceivedData;
@@ -191,6 +204,8 @@ internal class WaitingClientEx<TClient> : DisposableObject, IWaitingClient<TClie
} }
} }
public ResponsedData SendThenResponse(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default) public ResponsedData SendThenResponse(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default)
{ {
return this.SendThenResponse(buffer, 0, buffer.Length, timeout, token); return this.SendThenResponse(buffer, 0, buffer.Length, timeout, token);
@@ -216,7 +231,10 @@ internal class WaitingClientEx<TClient> : DisposableObject, IWaitingClient<TClie
{ {
tcpClient.Disconnected += this.OnDisconnected; tcpClient.Disconnected += this.OnDisconnected;
} }
if (this.WaitingOptions.BreakTrigger && this.Client is ISerialClientBase serialClient)
{
serialClient.Disconnected += this.OnSerialClientDisconnected;
}
if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter) if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter)
{ {
this.Client.OnHandleReceivedData += this.OnHandleReceivedData; this.Client.OnHandleReceivedData += this.OnHandleReceivedData;
@@ -274,7 +292,10 @@ internal class WaitingClientEx<TClient> : DisposableObject, IWaitingClient<TClie
{ {
tcpClient.Disconnected -= this.OnDisconnected; tcpClient.Disconnected -= this.OnDisconnected;
} }
if (this.WaitingOptions.BreakTrigger && this.Client is ISerialClientBase serialClient)
{
serialClient.Disconnected -= this.OnSerialClientDisconnected;
}
if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter) if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter)
{ {
this.Client.OnHandleReceivedData -= this.OnHandleReceivedData; this.Client.OnHandleReceivedData -= this.OnHandleReceivedData;

View File

@@ -108,11 +108,8 @@ public abstract class ReadWriteDevicesTcpDataHandleAdapter<TRequest> : CustomDat
protected virtual FilterResult GetResponse(ByteBlock byteBlock, TRequest request, byte[] body, byte[] bytes) protected virtual FilterResult GetResponse(ByteBlock byteBlock, TRequest request, byte[] body, byte[] bytes)
{ {
var unpackbytes = UnpackResponse(request, request.SendBytes, body, bytes); var unpackbytes = UnpackResponse(request, request.SendBytes, body, bytes);
request.Message = unpackbytes.Message;
request.Content = unpackbytes.Content1;
request.ReceivedBytes = bytes; request.ReceivedBytes = bytes;
request.ResultCode = unpackbytes.ResultCode; switch (unpackbytes)
switch (unpackbytes.Content2)
{ {
case FilterResult.Cache: case FilterResult.Cache:
return FilterResult.Cache; return FilterResult.Cache;
@@ -121,15 +118,10 @@ public abstract class ReadWriteDevicesTcpDataHandleAdapter<TRequest> : CustomDat
case FilterResult.GoOn: case FilterResult.GoOn:
byteBlock.Pos = byteBlock.Len; byteBlock.Pos = byteBlock.Len;
return FilterResult.GoOn; return FilterResult.GoOn;
default:
byteBlock.Pos = byteBlock.Len;
return FilterResult.GoOn;
} }
//直接放弃
byteBlock.Pos = byteBlock.Len;
request.ReceivedBytes = bytes;
Logger?.Warning(unpackbytes.Message);
request.ResultCode = ResultCode.Error;
request.Message = unpackbytes.Message;
return FilterResult.GoOn;
} }
/// <summary> /// <summary>
/// 发送方法,会重新建立<see cref="Request"/> /// 发送方法,会重新建立<see cref="Request"/>
@@ -156,5 +148,5 @@ public abstract class ReadWriteDevicesTcpDataHandleAdapter<TRequest> : CustomDat
/// <summary> /// <summary>
/// 报文拆包 /// 报文拆包
/// </summary> /// </summary>
protected abstract OperResult<byte[], FilterResult> UnpackResponse(TRequest request, byte[] send, byte[] body, byte[] response); protected abstract FilterResult UnpackResponse(TRequest request, byte[] send, byte[] body, byte[] response);
} }

View File

@@ -38,6 +38,8 @@ public static class LoggerExtensions
{ {
logger.Log(TouchSocket.Core.LogLevel.Warning, null, msg, ex); logger.Log(TouchSocket.Core.LogLevel.Warning, null, msg, ex);
} }
/// <summary> /// <summary>
/// 输出警示日志 /// 输出警示日志
/// </summary> /// </summary>

View File

@@ -45,4 +45,9 @@ public class SerialProperty
/// </summary> /// </summary>
[Description("停止位")] [Description("停止位")]
public StopBits StopBits { get; set; } = StopBits.One; public StopBits StopBits { get; set; } = StopBits.One;
/// <inheritdoc/>
public override string ToString()
{
return $"{PortName}[{BaudRate},{DataBits},{StopBits},{Parity}]";
}
} }

View File

@@ -3,6 +3,11 @@
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net45;net6.0;net7.0</TargetFrameworks> <TargetFrameworks>net45;net6.0;net7.0</TargetFrameworks>
<OpenApiGenerateDocuments>false</OpenApiGenerateDocuments> <OpenApiGenerateDocuments>false</OpenApiGenerateDocuments>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageProjectUrl>https://diego2098.gitee.io/thingsgateway-docs/</PackageProjectUrl>
<PackageTags>ThingsGateway;Diego;dotNET China;Blazor;设备采集;边缘网关</PackageTags>
<PackageOutputPath>../nupkgs</PackageOutputPath>
<AssemblyOriginatorKeyFile>..\..\snks\ThingsGateway.snk</AssemblyOriginatorKeyFile> <AssemblyOriginatorKeyFile>..\..\snks\ThingsGateway.snk</AssemblyOriginatorKeyFile>
</PropertyGroup> </PropertyGroup>

View File

@@ -2288,6 +2288,9 @@
停止位 停止位
</summary> </summary>
</member> </member>
<member name="M:ThingsGateway.Foundation.Serial.SerialProperty.ToString">
<inheritdoc/>
</member>
<member name="T:ThingsGateway.Foundation.SerialPortExtensions"> <member name="T:ThingsGateway.Foundation.SerialPortExtensions">
<summary> <summary>
SocketExtension SocketExtension

View File

@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Foundataion\ThingsGateway.Foundation.Adapter.OPCUA\ThingsGateway.Foundation.Adapter.OPCUA.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>OPCUAClientDemo</name>
</assembly>
<members>
</members>
</doc>

View File

@@ -0,0 +1,26 @@
using ThingsGateway.Foundation.Adapter.OPCUA;
using TouchSocket.Core;
namespace ModbusDemo
{
internal class Program
{
static async Task Main(string[] args)
{
OPCUAClient oPCUAClient = new(new EasyLogger(a => Console.WriteLine(a)))
{
OPCNode = new()
{
OPCUrl = "opc.tcp://desktop-p5gb4iq:50001/StandardServer",
IsUseSecurity = true,
}
};
await oPCUAClient.ConnectAsync();
var testData1 = await oPCUAClient.ReadJTokenValueAsync(new[] { "ns=2;i=2897" });
await oPCUAClient.WriteNodeAsync("ns=2;i=2897", testData1.FirstOrDefault().Item3);
}
}
}

View File

@@ -1,7 +1,7 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net6.0;net7.0</TargetFrameworks> <TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<Version>2.0.0.0</Version> <Version>2.0.5.0</Version>
<Authors>Diego</Authors> <Authors>Diego</Authors>
<Product>ThingsGateway</Product> <Product>ThingsGateway</Product>
<Copyright>© 2023-present Diego</Copyright> <Copyright>© 2023-present Diego</Copyright>

View File

@@ -82,12 +82,12 @@ public class ModbusRtu : ReadWriteDevicesSerialBase
/// <inheritdoc/> /// <inheritdoc/>
public override void SetDataAdapter() public override void SetDataAdapter()
{ {
ModbusRtuDataHandleAdapter DataHandleAdapter = new() ModbusRtuDataHandleAdapter dataHandleAdapter = new()
{ {
Crc16CheckEnable = Crc16CheckEnable, Crc16CheckEnable = Crc16CheckEnable,
CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout) CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout)
}; };
SerialClient.SetDataHandlingAdapter(DataHandleAdapter); SerialClient.SetDataHandlingAdapter(dataHandleAdapter);
} }
/// <inheritdoc/> /// <inheritdoc/>

View File

@@ -10,7 +10,6 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion
using ThingsGateway.Foundation.Extension;
namespace ThingsGateway.Foundation.Adapter.Modbus; namespace ThingsGateway.Foundation.Adapter.Modbus;
@@ -41,43 +40,52 @@ public class ModbusRtuDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter<M
/// <inheritdoc/> /// <inheritdoc/>
protected override OperResult<byte[], FilterResult> UnpackResponse(ModbusRtuMessage request, byte[] send, byte[] body, byte[] response) protected override FilterResult UnpackResponse(ModbusRtuMessage request, byte[] send, byte[] body, byte[] response)
{ {
//理想状态检测 //理想状态检测
var result = ModbusHelper.GetModbusRtuData(send, response, Crc16CheckEnable); var result = ModbusHelper.GetModbusRtuData(send, response, Crc16CheckEnable);
if (result.IsSuccess) if (result.IsSuccess)
{ {
return OperResult.CreateSuccessResult(result.Content, FilterResult.Success); request.ResultCode = result.ResultCode;
request.Message = result.Message;
request.Content = result.Content;
return FilterResult.Success;
} }
else else
{ {
//如果返回错误,具体分析
var op = result.Copy<byte[], FilterResult>();
if (response.Length <= 1) if (response.Length <= 1)
{ {
request.ResultCode = result.ResultCode;
request.Message = result.Message;
request.Content = result.Content;
//如果长度不足,返回缓存 //如果长度不足,返回缓存
op.Content2 = FilterResult.Cache; return FilterResult.Cache;
return op;
} }
if (!(response[1] <= 0x10)) if (!(response[1] <= 0x10))
{ {
request.ResultCode = result.ResultCode;
request.Message = result.Message;
request.Content = result.Content;
//功能码不对,返回放弃 //功能码不对,返回放弃
op.Content2 = FilterResult.Success; return FilterResult.Success;
return op;
} }
else else
{ {
if ((response.Length > response[2] + 4)) if ((response.Length > response[2] + 4))
{ {
request.ResultCode = result.ResultCode;
request.Message = result.Message;
request.Content = result.Content;
//如果长度已经超了,说明这段报文已经不能继续解析了,直接返回放弃 //如果长度已经超了,说明这段报文已经不能继续解析了,直接返回放弃
op.Content2 = FilterResult.Success; return FilterResult.Success;
return op;
} }
else else
{ {
request.ResultCode = result.ResultCode;
request.Message = result.Message;
request.Content = result.Content;
//否则返回缓存 //否则返回缓存
op.Content2 = FilterResult.Cache; return FilterResult.Cache;
return op;
} }
} }
} }

View File

@@ -78,12 +78,12 @@ public class ModbusRtuOverTcp : ReadWriteDevicesTcpClientBase
/// <inheritdoc/> /// <inheritdoc/>
public override void SetDataAdapter() public override void SetDataAdapter()
{ {
ModbusRtuDataHandleAdapter DataHandleAdapter = new() ModbusRtuDataHandleAdapter dataHandleAdapter = new()
{ {
Crc16CheckEnable = Crc16CheckEnable, Crc16CheckEnable = Crc16CheckEnable,
CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout) CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout)
}; };
TcpClientEx.SetDataHandlingAdapter(DataHandleAdapter); TcpClientEx.SetDataHandlingAdapter(dataHandleAdapter);
} }
/// <inheritdoc/> /// <inheritdoc/>

View File

@@ -72,11 +72,14 @@ public class ModbusRtuOverUdp : ReadWriteDevicesUdpBase
/// <inheritdoc/> /// <inheritdoc/>
public override void SetDataAdapter() public override void SetDataAdapter()
{ {
ModbusRtuOverUdpDataHandleAdapter DataHandleAdapter = new() ModbusRtuOverUdpDataHandleAdapter dataHandleAdapter = new()
{ {
Crc16CheckEnable = Crc16CheckEnable, Crc16CheckEnable = Crc16CheckEnable,
}; };
UdpSession.SetDataHandlingAdapter(DataHandleAdapter); UdpSession.Config.SetUdpDataHandlingAdapter(() =>
{
return dataHandleAdapter;
});
} }
/// <inheritdoc/> /// <inheritdoc/>

View File

@@ -78,8 +78,8 @@ public class ModbusServer : ReadWriteDevicesTcpServerBase
/// <inheritdoc/> /// <inheritdoc/>
public override void SetDataAdapter(SocketClient client) public override void SetDataAdapter(SocketClient client)
{ {
ModbusServerDataHandleAdapter DataHandleAdapter = new(); ModbusServerDataHandleAdapter dataHandleAdapter = new();
client.SetDataHandlingAdapter(DataHandleAdapter); client.SetDataHandlingAdapter(dataHandleAdapter);
} }
/// <inheritdoc/> /// <inheritdoc/>

View File

@@ -10,7 +10,6 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion
using ThingsGateway.Foundation.Extension;
using ThingsGateway.Foundation.Extension.Generic; using ThingsGateway.Foundation.Extension.Generic;
namespace ThingsGateway.Foundation.Adapter.Modbus; namespace ThingsGateway.Foundation.Adapter.Modbus;
@@ -69,7 +68,7 @@ public class ModbusServerDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapte
} }
/// <inheritdoc/> /// <inheritdoc/>
protected override OperResult<byte[], FilterResult> UnpackResponse(ModbusServerMessage request, byte[] send, byte[] body, byte[] response) protected override FilterResult UnpackResponse(ModbusServerMessage request, byte[] send, byte[] body, byte[] response)
{ {
var result = GetModbusData(response.RemoveBegin(6)); var result = GetModbusData(response.RemoveBegin(6));
if (result.IsSuccess) if (result.IsSuccess)
@@ -119,14 +118,15 @@ public class ModbusServerDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapte
Length = ThingsGatewayBitConverter.ToByte(response, 11), Length = ThingsGatewayBitConverter.ToByte(response, 11),
}; };
} }
request.ResultCode = result.ResultCode;
return OperResult.CreateSuccessResult(request.Content, FilterResult.Success); request.Message = result.Message;
return FilterResult.Success;
} }
else else
{ {
var op = result.Copy<byte[], FilterResult>(); request.ResultCode = result.ResultCode;
op.Content2 = FilterResult.Cache; request.Message = result.Message;
return op; return FilterResult.Cache;
} }
} }
} }

View File

@@ -79,12 +79,12 @@ public class ModbusTcp : ReadWriteDevicesTcpClientBase
/// <inheritdoc/> /// <inheritdoc/>
public override void SetDataAdapter() public override void SetDataAdapter()
{ {
ModbusTcpDataHandleAdapter DataHandleAdapter = new() ModbusTcpDataHandleAdapter dataHandleAdapter = new()
{ {
IsCheckMessageId = IsCheckMessageId, IsCheckMessageId = IsCheckMessageId,
CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout) CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout)
}; };
TcpClientEx.SetDataHandlingAdapter(DataHandleAdapter); TcpClientEx.SetDataHandlingAdapter(dataHandleAdapter);
} }
/// <inheritdoc/> /// <inheritdoc/>

View File

@@ -50,35 +50,54 @@ public class ModbusTcpDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter<M
} }
/// <inheritdoc/> /// <inheritdoc/>
protected override OperResult<byte[], FilterResult> UnpackResponse(ModbusTcpMessage request, byte[] send, byte[] body, byte[] response) protected override FilterResult UnpackResponse(ModbusTcpMessage request, byte[] send, byte[] body, byte[] response)
{ {
//理想状态检测 //理想状态检测
var result = ModbusHelper.GetModbusData(send.RemoveBegin(6), response.RemoveBegin(6)); var result = ModbusHelper.GetModbusData(send.RemoveBegin(6), response.RemoveBegin(6));
if (result.IsSuccess) if (result.IsSuccess)
{ {
return OperResult.CreateSuccessResult(result.Content, FilterResult.Success); request.ResultCode = result.ResultCode;
request.Message = result.Message;
request.Content = result.Content;
return FilterResult.Success;
} }
else else
{ {
//如果返回错误,具体分析 //如果返回错误,具体分析
var op = result.Copy<byte[], FilterResult>(); var op = result.Copy<byte[], FilterResult>();
if (response.Length == 9)
{
if (response[7] >= 0x80)//错误码
{
request.ResultCode = result.ResultCode;
request.Message = result.Message;
request.Content = result.Content;
return FilterResult.Success;
}
}
if (response.Length < 10) if (response.Length < 10)
{ {
request.ResultCode = result.ResultCode;
request.Message = result.Message;
request.Content = result.Content;
return FilterResult.Cache;
//如果长度不足,返回缓存 //如果长度不足,返回缓存
op.Content2 = FilterResult.Cache;
return op;
} }
if ((response.Length > response[8] + 9)) if ((response.Length > response[8] + 9))
{ {
request.ResultCode = result.ResultCode;
request.Message = result.Message;
request.Content = result.Content;
return FilterResult.Success;
//如果长度已经超了,说明这段报文已经不能继续解析了,直接返回放弃 //如果长度已经超了,说明这段报文已经不能继续解析了,直接返回放弃
op.Content2 = FilterResult.Success;
return op;
} }
else else
{ {
request.ResultCode = result.ResultCode;
request.Message = result.Message;
request.Content = result.Content;
return FilterResult.Cache;
//否则返回缓存 //否则返回缓存
op.Content2 = FilterResult.Cache;
return op;
} }
} }

View File

@@ -75,11 +75,14 @@ public class ModbusUdp : ReadWriteDevicesUdpBase
/// <inheritdoc/> /// <inheritdoc/>
public override void SetDataAdapter() public override void SetDataAdapter()
{ {
ModbusUdpDataHandleAdapter DataHandleAdapter = new() ModbusUdpDataHandleAdapter dataHandleAdapter = new()
{ {
IsCheckMessageId = IsCheckMessageId IsCheckMessageId = IsCheckMessageId
}; };
UdpSession.SetDataHandlingAdapter(DataHandleAdapter); UdpSession.Config.SetUdpDataHandlingAdapter(() =>
{
return dataHandleAdapter;
});
} }
/// <inheritdoc/> /// <inheritdoc/>

View File

@@ -31,11 +31,6 @@ public static class JsonUtils
/// <summary> /// <summary>
/// 解析获取DataValue /// 解析获取DataValue
/// </summary> /// </summary>
/// <param name="Context"></param>
/// <param name="dataTypeId"></param>
/// <param name="builtInType"></param>
/// <param name="valueRank"></param>
/// <param name="json"></param>
/// <returns></returns> /// <returns></returns>
public static DataValue Decode( public static DataValue Decode(
IServiceMessageContext Context, IServiceMessageContext Context,
@@ -45,6 +40,7 @@ public static class JsonUtils
JToken json JToken json
) )
{ {
var data = DecoderObject(Context, dataTypeId, builtInType, valueRank, json); var data = DecoderObject(Context, dataTypeId, builtInType, valueRank, json);
var dataValue = new DataValue(new Variant(data)); var dataValue = new DataValue(new Variant(data));
return dataValue; return dataValue;
@@ -54,11 +50,6 @@ public static class JsonUtils
/// <summary> /// <summary>
/// 解析获取object /// 解析获取object
/// </summary> /// </summary>
/// <param name="Context"></param>
/// <param name="dataTypeId"></param>
/// <param name="builtInType"></param>
/// <param name="valueRank"></param>
/// <param name="json"></param>
/// <returns></returns> /// <returns></returns>
public static object DecoderObject( public static object DecoderObject(
IServiceMessageContext Context, IServiceMessageContext Context,
@@ -76,10 +67,9 @@ public static class JsonUtils
{ {
Value = new Value = new
{ {
TypeId = new { Id = dataTypeId.Identifier }, TypeId = new { Id = dataTypeId.Identifier, Namespace = dataTypeId.NamespaceIndex },
Body = json Body = json
} }
}.ToJson(); }.ToJson();
break; break;
case BuiltInType.Variant: case BuiltInType.Variant:

View File

@@ -14,6 +14,7 @@ using Newtonsoft.Json.Linq;
using Opc.Ua; using Opc.Ua;
using Opc.Ua.Client; using Opc.Ua.Client;
using Opc.Ua.Client.ComplexTypes;
using Opc.Ua.Configuration; using Opc.Ua.Configuration;
using System.Collections.Generic; using System.Collections.Generic;
@@ -454,13 +455,24 @@ public class OPCUAClient : DisposableObject
/// </summary> /// </summary>
public async Task ConnectAsync() public async Task ConnectAsync()
{ {
m_session = await ConnectAsync(OPCNode.OPCUrl); await ConnectAsync(OPCNode.OPCUrl);
} }
/// <summary> /// <summary>
/// 断开连接。 /// 断开连接。
/// </summary> /// </summary>
public void Disconnect() public void Disconnect()
{
PrivateDisconnect();
// disconnect any existing session.
if (m_session != null)
{
Log.Debug("断开连接");
m_session = null;
}
}
private void PrivateDisconnect()
{ {
// stop any reconnect operation. // stop any reconnect operation.
if (m_reConnectHandler != null) if (m_reConnectHandler != null)
@@ -468,15 +480,7 @@ public class OPCUAClient : DisposableObject
m_reConnectHandler.SafeDispose(); m_reConnectHandler.SafeDispose();
m_reConnectHandler = null; m_reConnectHandler = null;
} }
m_session?.Close(10000);
// disconnect any existing session.
if (m_session != null)
{
Log.Debug("断开连接");
m_session.Close(10000);
m_session = null;
}
} }
@@ -508,6 +512,10 @@ public class OPCUAClient : DisposableObject
AttributeId = Attributes.Value, AttributeId = Attributes.Value,
}; };
var node = (VariableNode)ReadNode(tag.ToString(), false); var node = (VariableNode)ReadNode(tag.ToString(), false);
//var expandedNodeId = NodeId.ToExpandedNodeId(node.DataType, m_session.NamespaceUris);
//var type = m_session.Factory.GetSystemType(expandedNodeId);
//var data = value.ToObject(type);
//var dataValue = new DataValue(new Variant(data));
var dataValue = JsonUtils.Decode( var dataValue = JsonUtils.Decode(
m_session.MessageContext, m_session.MessageContext,
node.DataType, node.DataType,
@@ -859,7 +867,7 @@ public class OPCUAClient : DisposableObject
/// <returns>The new session object.</returns> /// <returns>The new session object.</returns>
private async Task<ISession> ConnectAsync(string serverUrl) private async Task<ISession> ConnectAsync(string serverUrl)
{ {
Disconnect(); PrivateDisconnect();
if (m_configuration == null) if (m_configuration == null)
{ {
@@ -889,7 +897,7 @@ public class OPCUAClient : DisposableObject
60000, 60000,
userIdentity, userIdentity,
Array.Empty<string>()); Array.Empty<string>());
await new ComplexTypeSystem(m_session).Load(false, true).ConfigureAwait(false);
Log.Debug("连接成功"); Log.Debug("连接成功");
m_session.KeepAliveInterval = OPCNode.KeepAliveInterval == 0 ? 60000 : OPCNode.KeepAliveInterval; m_session.KeepAliveInterval = OPCNode.KeepAliveInterval == 0 ? 60000 : OPCNode.KeepAliveInterval;

View File

@@ -8,6 +8,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client" Version="1.4.371.96" /> <PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client" Version="1.4.371.96" />
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client.ComplexTypes" Version="1.4.371.96" />
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Server" Version="1.4.371.96" /> <PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Server" Version="1.4.371.96" />
</ItemGroup> </ItemGroup>

View File

@@ -161,22 +161,12 @@
<summary> <summary>
解析获取DataValue 解析获取DataValue
</summary> </summary>
<param name="Context"></param>
<param name="dataTypeId"></param>
<param name="builtInType"></param>
<param name="valueRank"></param>
<param name="json"></param>
<returns></returns> <returns></returns>
</member> </member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.JsonUtils.DecoderObject(Opc.Ua.IServiceMessageContext,Opc.Ua.NodeId,Opc.Ua.BuiltInType,System.Int32,Newtonsoft.Json.Linq.JToken)"> <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.JsonUtils.DecoderObject(Opc.Ua.IServiceMessageContext,Opc.Ua.NodeId,Opc.Ua.BuiltInType,System.Int32,Newtonsoft.Json.Linq.JToken)">
<summary> <summary>
解析获取object 解析获取object
</summary> </summary>
<param name="Context"></param>
<param name="dataTypeId"></param>
<param name="builtInType"></param>
<param name="valueRank"></param>
<param name="json"></param>
<returns></returns> <returns></returns>
</member> </member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.JsonUtils.DecodeRawData(Opc.Ua.JsonDecoder,Opc.Ua.BuiltInType,System.Int32,System.String)"> <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.JsonUtils.DecodeRawData(Opc.Ua.JsonDecoder,Opc.Ua.BuiltInType,System.Int32,System.String)">

View File

@@ -305,6 +305,8 @@ namespace ThingsGateway.Foundation.Adapter.Siemens
foreach (var item in commandResult.Content) foreach (var item in commandResult.Content)
{ {
ResponsedData result = await WaitingClientEx.SendThenResponseAsync(item, TimeOut, token); ResponsedData result = await WaitingClientEx.SendThenResponseAsync(item, TimeOut, token);
if (!((MessageBase)result.RequestInfo).IsSuccess)
return OperResult.CreateFailedResult<byte[]>(((MessageBase)result.RequestInfo));
bytes.Add(result); bytes.Add(result);
} }
return OperResult.CreateSuccessResult(bytes.ToArray()); return OperResult.CreateSuccessResult(bytes.ToArray());
@@ -338,7 +340,7 @@ namespace ThingsGateway.Foundation.Adapter.Siemens
if (commandResult.IsSuccess) if (commandResult.IsSuccess)
{ {
var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token); var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token);
return OperResult.CreateSuccessResult(result); return (MessageBase)result.RequestInfo;
} }
else else
{ {

View File

@@ -10,7 +10,6 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion
using ThingsGateway.Foundation.Extension;
namespace ThingsGateway.Foundation.Adapter.Siemens; namespace ThingsGateway.Foundation.Adapter.Siemens;
@@ -35,7 +34,7 @@ public class SiemensS7PLCDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapte
} }
/// <inheritdoc/> /// <inheritdoc/>
protected override OperResult<byte[], FilterResult> UnpackResponse(SiemensMessage request, byte[] send, byte[] body, byte[] response) protected override FilterResult UnpackResponse(SiemensMessage request, byte[] send, byte[] body, byte[] response)
{ {
var result = new OperResult<byte[]>(); var result = new OperResult<byte[]>();
if (response[2] * 256 + response[3] == 7) if (response[2] * 256 + response[3] == 7)
@@ -57,23 +56,29 @@ public class SiemensS7PLCDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapte
} }
if (result.IsSuccess) if (result.IsSuccess)
{ {
return OperResult.CreateSuccessResult(result.Content, FilterResult.Success); request.ResultCode = result.ResultCode;
request.Message = result.Message;
request.Content = result.Content;
return FilterResult.Success;
} }
else else
{ {
//如果返回错误,具体分析 //如果返回错误,具体分析
var op = result.Copy<byte[], FilterResult>();
if (response.Length < 21) if (response.Length < 21)
{ {
request.ResultCode = result.ResultCode;
request.Message = result.Message;
request.Content = result.Content;
//如果长度不足,返回缓存 //如果长度不足,返回缓存
op.Content2 = FilterResult.Cache; return FilterResult.Cache;
return op;
} }
else else
{ {
request.ResultCode = result.ResultCode;
request.Message = result.Message;
request.Content = result.Content;
//如果长度已经超了,说明这段报文已经不能继续解析了,直接返回放弃 //如果长度已经超了,说明这段报文已经不能继续解析了,直接返回放弃
op.Content2 = FilterResult.Success; return FilterResult.Success;
return op;
} }
} }
} }

View File

@@ -26,13 +26,13 @@
<DefalutDebugDriverPage Channel="ChannelEnum.SerialPort" @ref=defalutDebugDriverPage> <DefalutDebugDriverPage Channel="ChannelEnum.SerialPort" @ref=defalutDebugDriverPage>
<MCard Flat Elevation="0"> <MCard Flat Elevation="0">
<MRow Class="my-1" NoGutters Justify="JustifyTypes.SpaceBetween" Align="AlignTypes.Center"> <MRow Class="my-1" NoGutters Justify="JustifyTypes.SpaceBetween" Align="AlignTypes.Center">
<MCheckbox Class="mx-1" Label=@(_plc.Description(x => x.Crc16CheckEnable)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Crc16CheckEnable></MCheckbox> <MCheckbox Class="ma-1" Label=@(_plc.Description(x => x.Crc16CheckEnable)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Crc16CheckEnable></MCheckbox>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.FrameTime)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.FrameTime)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.CacheTimeout)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.CacheTimeout)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.Station)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Station></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.Station)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Station></MTextField>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.TimeOut)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.TimeOut)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
<MSelect Class="mx-1" Style="max-width:200px" @bind-Value="_plc.DataFormat" Outlined Label="@(_plc.Description(x => x.DataFormat))" <MSelect Class="ma-1" Style="max-width:200px" @bind-Value="_plc.DataFormat" Outlined Label="@(_plc.Description(x => x.DataFormat))"
Items=@(typeof(DataFormat).GetEnumList()) Items=@(typeof(DataFormat).GetEnumList())
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })" MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
ItemText=@((u) =>u.des) ItemText=@((u) =>u.des)
@@ -54,6 +54,7 @@
{ {
//载入配置 //载入配置
_plc = new ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu((SerialClient)defalutDebugDriverPage.SerialClientPage.GetSerialClient()); _plc = new ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu((SerialClient)defalutDebugDriverPage.SerialClientPage.GetSerialClient());
defalutDebugDriverPage.Plc = _plc;
} }
base.OnAfterRender(firstRender); base.OnAfterRender(firstRender);
} }

View File

@@ -25,13 +25,13 @@
<DefalutDebugDriverPage Channel="ChannelEnum.TcpClientEx" @ref=defalutDebugDriverPage> <DefalutDebugDriverPage Channel="ChannelEnum.TcpClientEx" @ref=defalutDebugDriverPage>
<MCard Flat Elevation="0"> <MCard Flat Elevation="0">
<MRow Class="my-1" NoGutters Justify="JustifyTypes.SpaceBetween" Align="AlignTypes.Center"> <MRow Class="my-1" NoGutters Justify="JustifyTypes.SpaceBetween" Align="AlignTypes.Center">
<MCheckbox Class="mx-1" Label=@(_plc.Description(x => x.Crc16CheckEnable)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Crc16CheckEnable></MCheckbox> <MCheckbox Class="ma-1" Label=@(_plc.Description(x => x.Crc16CheckEnable)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Crc16CheckEnable></MCheckbox>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.FrameTime)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.FrameTime)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.CacheTimeout)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.CacheTimeout)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.Station)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Station></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.Station)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Station></MTextField>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.TimeOut)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.TimeOut)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
<MSelect Class="mx-1" Style="max-width:200px" @bind-Value="_plc.DataFormat" Outlined Label="@(_plc.Description(x => x.DataFormat))" <MSelect Class="ma-1" Style="max-width:200px" @bind-Value="_plc.DataFormat" Outlined Label="@(_plc.Description(x => x.DataFormat))"
Items=@(typeof(DataFormat).GetEnumList()) Items=@(typeof(DataFormat).GetEnumList())
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })" MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
ItemText=@((u) =>u.des) ItemText=@((u) =>u.des)

View File

@@ -25,12 +25,12 @@
<DefalutDebugDriverPage Channel="ChannelEnum.UdpSession" @ref=defalutDebugDriverPage> <DefalutDebugDriverPage Channel="ChannelEnum.UdpSession" @ref=defalutDebugDriverPage>
<MCard Flat Elevation="0"> <MCard Flat Elevation="0">
<MRow Class="my-1" NoGutters Justify="JustifyTypes.SpaceBetween" Align="AlignTypes.Center"> <MRow Class="my-1" NoGutters Justify="JustifyTypes.SpaceBetween" Align="AlignTypes.Center">
<MCheckbox Class="mx-1" Label=@(_plc.Description(x => x.Crc16CheckEnable)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Crc16CheckEnable></MCheckbox> <MCheckbox Class="ma-1" Label=@(_plc.Description(x => x.Crc16CheckEnable)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Crc16CheckEnable></MCheckbox>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.FrameTime)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.FrameTime)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.Station)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Station></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.Station)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Station></MTextField>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.TimeOut)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.TimeOut)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
<MSelect Class="mx-1" Style="max-width:200px" @bind-Value="_plc.DataFormat" Outlined Label="@(_plc.Description(x => x.DataFormat))" <MSelect Class="ma-1" Style="max-width:200px" @bind-Value="_plc.DataFormat" Outlined Label="@(_plc.Description(x => x.DataFormat))"
Items=@(typeof(DataFormat).GetEnumList()) Items=@(typeof(DataFormat).GetEnumList())
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })" MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
ItemText=@((u) =>u.des) ItemText=@((u) =>u.des)

View File

@@ -193,7 +193,7 @@ public class ModbusServer : UpLoadBase
if (tag.Value == null) return OperResult.CreateSuccessResult(); if (tag.Value == null) return OperResult.CreateSuccessResult();
var enable = var enable =
GetPropertyValue(tag.Value, nameof(variablePropertys.VariableRpcEnable)).ToBool() GetPropertyValue(tag.Value, nameof(variablePropertys.VariableRpcEnable)).ToBoolean()
&& driverPropertys.DeviceRpcEnable; && driverPropertys.DeviceRpcEnable;
if (!enable) return new OperResult("不允许写入"); if (!enable) return new OperResult("不允许写入");
var type = GetPropertyValue(tag.Value, nameof(ModbusServerVariableProperty.ModbusType)); var type = GetPropertyValue(tag.Value, nameof(ModbusServerVariableProperty.ModbusType));

View File

@@ -25,11 +25,11 @@
<DefalutDebugDriverPage Channel="ChannelEnum.TcpServer" @ref=defalutDebugDriverPage> <DefalutDebugDriverPage Channel="ChannelEnum.TcpServer" @ref=defalutDebugDriverPage>
<MCard Flat Elevation="0"> <MCard Flat Elevation="0">
<MRow Class="my-1" NoGutters Justify="JustifyTypes.SpaceBetween" Align="AlignTypes.Center"> <MRow Class="my-1" NoGutters Justify="JustifyTypes.SpaceBetween" Align="AlignTypes.Center">
<MCheckbox Class="mx-1" Label=@(_plc.Description(x => x.MulStation)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.MulStation></MCheckbox> <MCheckbox Class="ma-1" Label=@(_plc.Description(x => x.MulStation)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.MulStation></MCheckbox>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.Station)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Station></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.Station)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Station></MTextField>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.TimeOut)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.TimeOut)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
<MSelect Class="mx-1" Style="max-width:200px" @bind-Value="_plc.DataFormat" Outlined Label="@(_plc.Description(x => x.DataFormat))" <MSelect Class="ma-1" Style="max-width:200px" @bind-Value="_plc.DataFormat" Outlined Label="@(_plc.Description(x => x.DataFormat))"
Items=@(typeof(DataFormat).GetEnumList()) Items=@(typeof(DataFormat).GetEnumList())
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })" MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
ItemText=@((u) =>u.des) ItemText=@((u) =>u.des)

View File

@@ -25,13 +25,13 @@
<DefalutDebugDriverPage Channel="ChannelEnum.TcpClientEx" @ref=defalutDebugDriverPage> <DefalutDebugDriverPage Channel="ChannelEnum.TcpClientEx" @ref=defalutDebugDriverPage>
<MCard Flat Elevation="0"> <MCard Flat Elevation="0">
<MRow Class="my-1" NoGutters Justify="JustifyTypes.SpaceBetween" Align="AlignTypes.Center"> <MRow Class="my-1" NoGutters Justify="JustifyTypes.SpaceBetween" Align="AlignTypes.Center">
<MCheckbox Class="mx-1" Label=@(_plc.Description(x => x.IsCheckMessageId)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.IsCheckMessageId></MCheckbox> <MCheckbox Class="ma-1" Label=@(_plc.Description(x => x.IsCheckMessageId)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.IsCheckMessageId></MCheckbox>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.FrameTime)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.FrameTime)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.CacheTimeout)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.CacheTimeout)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.Station)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Station></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.Station)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Station></MTextField>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.TimeOut)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.TimeOut)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
<MSelect Class="mx-1" Style="max-width:200px" @bind-Value="_plc.DataFormat" Outlined Label="@(_plc.Description(x => x.DataFormat))" <MSelect Class="ma-1" Style="max-width:200px" @bind-Value="_plc.DataFormat" Outlined Label="@(_plc.Description(x => x.DataFormat))"
Items=@(typeof(DataFormat).GetEnumList()) Items=@(typeof(DataFormat).GetEnumList())
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })" MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
ItemText=@((u) =>u.des) ItemText=@((u) =>u.des)

View File

@@ -25,12 +25,12 @@
<DefalutDebugDriverPage Channel="ChannelEnum.UdpSession" @ref=defalutDebugDriverPage> <DefalutDebugDriverPage Channel="ChannelEnum.UdpSession" @ref=defalutDebugDriverPage>
<MCard Flat Elevation="0"> <MCard Flat Elevation="0">
<MRow Class="my-1" NoGutters Justify="JustifyTypes.SpaceBetween" Align="AlignTypes.Center"> <MRow Class="my-1" NoGutters Justify="JustifyTypes.SpaceBetween" Align="AlignTypes.Center">
<MCheckbox Class="mx-1" Label=@(_plc.Description(x => x.IsCheckMessageId)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.IsCheckMessageId></MCheckbox> <MCheckbox Class="ma-1" Label=@(_plc.Description(x => x.IsCheckMessageId)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.IsCheckMessageId></MCheckbox>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.FrameTime)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.FrameTime)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.Station)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Station></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.Station)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Station></MTextField>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.TimeOut)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.TimeOut)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
<MSelect Class="mx-1" Style="max-width:200px" @bind-Value="_plc.DataFormat" Outlined Label="@(_plc.Description(x => x.DataFormat))" <MSelect Class="ma-1" Style="max-width:200px" @bind-Value="_plc.DataFormat" Outlined Label="@(_plc.Description(x => x.DataFormat))"
Items=@(typeof(DataFormat).GetEnumList()) Items=@(typeof(DataFormat).GetEnumList())
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })" MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
ItemText=@((u) =>u.des) ItemText=@((u) =>u.des)

View File

@@ -2,6 +2,7 @@
<PropertyGroup> <PropertyGroup>
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>--> <!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
<EnableDynamicLoading>true</EnableDynamicLoading>
</PropertyGroup> </PropertyGroup>
@@ -12,7 +13,9 @@
</Target> </Target>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\ThingsGateway.Blazor\ThingsGateway.Blazor.csproj" /> <ProjectReference Include="..\..\ThingsGateway.Blazor\ThingsGateway.Blazor.csproj" >
<IncludeAssets>Compile</IncludeAssets>
</ProjectReference>
<ProjectReference Include="..\Foundataion\ThingsGateway.Foundation.Adapter.Modbus\ThingsGateway.Foundation.Adapter.Modbus.csproj" /> <ProjectReference Include="..\Foundataion\ThingsGateway.Foundation.Adapter.Modbus\ThingsGateway.Foundation.Adapter.Modbus.csproj" />
</ItemGroup> </ItemGroup>

View File

@@ -335,7 +335,7 @@ public class IotSharpClient : UpLoadBase
if (tag != null) if (tag != null)
{ {
var rpcEnable = var rpcEnable =
GetPropertyValue(tag, nameof(variablePropertys.VariableRpcEnable)).ToBool() GetPropertyValue(tag, nameof(variablePropertys.VariableRpcEnable)).ToBoolean()
&& driverPropertys.DeviceRpcEnable; && driverPropertys.DeviceRpcEnable;
if (rpcEnable == true) if (rpcEnable == true)
{ {

View File

@@ -415,7 +415,7 @@ public class MqttClient : UpLoadBase
var tag = _uploadVariables.FirstOrDefault(a => a.Name == nv.Key); var tag = _uploadVariables.FirstOrDefault(a => a.Name == nv.Key);
if (tag != null) if (tag != null)
{ {
var rpcEnable = GetPropertyValue(tag, nameof(variablePropertys.VariableRpcEnable)).ToBool(); var rpcEnable = GetPropertyValue(tag, nameof(variablePropertys.VariableRpcEnable)).ToBoolean();
if (rpcEnable == true) if (rpcEnable == true)
{ {
var result = await _rpcCore.InvokeDeviceMethodAsync(ToString() + "-" + arg.ClientId, nv); var result = await _rpcCore.InvokeDeviceMethodAsync(ToString() + "-" + arg.ClientId, nv);

View File

@@ -270,7 +270,7 @@ public class MqttServer : UpLoadBase
var tag = _uploadVariables.FirstOrDefault(a => a.Name == nv.Key); var tag = _uploadVariables.FirstOrDefault(a => a.Name == nv.Key);
if (tag != null) if (tag != null)
{ {
var rpcEnable = GetPropertyValue(tag, nameof(variablePropertys.VariableRpcEnable)).ToBool(); var rpcEnable = GetPropertyValue(tag, nameof(variablePropertys.VariableRpcEnable)).ToBoolean();
if (rpcEnable == true) if (rpcEnable == true)
{ {
var result = await _rpcCore.InvokeDeviceMethodAsync(ToString() + "-" + IdWithName[arg.ClientId], nv); var result = await _rpcCore.InvokeDeviceMethodAsync(ToString() + "-" + IdWithName[arg.ClientId], nv);

View File

@@ -2,6 +2,7 @@
<PropertyGroup> <PropertyGroup>
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>--> <!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
<EnableDynamicLoading>true</EnableDynamicLoading>
</PropertyGroup> </PropertyGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent"> <Target Name="PostBuild" AfterTargets="PostBuildEvent">
@@ -9,7 +10,9 @@
</Target> </Target>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\ThingsGateway.Blazor\ThingsGateway.Blazor.csproj" /> <ProjectReference Include="..\..\ThingsGateway.Blazor\ThingsGateway.Blazor.csproj" >
<IncludeAssets>Compile</IncludeAssets>
</ProjectReference>
<ProjectReference Include="..\Foundataion\ThingsGateway.Foundation.Adapter.OPCDA\ThingsGateway.Foundation.Adapter.OPCDA.csproj" /> <ProjectReference Include="..\Foundataion\ThingsGateway.Foundation.Adapter.OPCDA\ThingsGateway.Foundation.Adapter.OPCDA.csproj" />
</ItemGroup> </ItemGroup>

View File

@@ -89,7 +89,7 @@ public partial class ImportVariable
var dataTypeId = (Opc.Ua.NodeId)(await PLC.ReadNoteAttributeAsync(a.NodeId.ToString(), Attributes.DataType)).Content.FirstOrDefault().Value; var dataTypeId = (Opc.Ua.NodeId)(await PLC.ReadNoteAttributeAsync(a.NodeId.ToString(), Attributes.DataType)).Content.FirstOrDefault().Value;
var dataType = Opc.Ua.TypeInfo.GetSystemType(dataTypeId, PLC.Session.Factory); var dataType = Opc.Ua.TypeInfo.GetSystemType(dataTypeId, PLC.Session.Factory);
var result = dataType != null ? Enum.TryParse<DataTypeEnum>(dataType.Name, out dataTypeEnum) : false; var result = dataType != null && Enum.TryParse<DataTypeEnum>(dataType.Name, out dataTypeEnum);
if (!result) if (!result)
{ {
dataTypeEnum = DataTypeEnum.Object; dataTypeEnum = DataTypeEnum.Object;

View File

@@ -36,6 +36,34 @@ namespace ThingsGateway.OPCUA;
/// </summary> /// </summary>
public class OPCUAClient : CollectBase public class OPCUAClient : CollectBase
{ {
readonly PeriodicTimer _periodicTimer = new(TimeSpan.FromSeconds(60));
/// <summary>
/// OPCUA客户端
/// </summary>
public OPCUAClient()
{
_ = RunTimerAsync();
}
private async Task RunTimerAsync()
{
while (await _periodicTimer.WaitForNextTickAsync())
{
if (PLC != null && PLC.Session == null)
{
try
{
await PLC.ConnectAsync();
}
catch (Exception ex)
{
LogMessage.Exception(ex);
}
}
}
}
internal CollectDeviceRunTime Device; internal CollectDeviceRunTime Device;
internal Foundation.Adapter.OPCUA.OPCUAClient PLC = null; internal Foundation.Adapter.OPCUA.OPCUAClient PLC = null;
@@ -73,7 +101,11 @@ public class OPCUAClient : CollectBase
} }
/// <inheritdoc/> /// <inheritdoc/>
public override bool IsConnected() => PLC.Connected; public override bool IsConnected()
{
return PLC.Connected;
}
/// <inheritdoc/> /// <inheritdoc/>
public override List<DeviceVariableSourceRead> LoadSourceRead(List<DeviceVariableRunTime> deviceVariables) public override List<DeviceVariableSourceRead> LoadSourceRead(List<DeviceVariableRunTime> deviceVariables)
@@ -99,7 +131,6 @@ public class OPCUAClient : CollectBase
/// <inheritdoc/> /// <inheritdoc/>
public override async Task<OperResult<byte[]>> ReadSourceAsync(DeviceVariableSourceRead deviceVariableSourceRead, CancellationToken token) public override async Task<OperResult<byte[]>> ReadSourceAsync(DeviceVariableSourceRead deviceVariableSourceRead, CancellationToken token)
{ {
await Task.CompletedTask;
var result = await PLC.ReadJTokenValueAsync(deviceVariableSourceRead.DeviceVariables.Select(a => a.VariableAddress).ToArray(), token); var result = await PLC.ReadJTokenValueAsync(deviceVariableSourceRead.DeviceVariables.Select(a => a.VariableAddress).ToArray(), token);
foreach (var data in result) foreach (var data in result)
{ {
@@ -163,6 +194,7 @@ public class OPCUAClient : CollectBase
/// <inheritdoc/> /// <inheritdoc/>
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
_periodicTimer?.Dispose();
if (PLC != null) if (PLC != null)
{ {
PLC.DataChangedHandler -= DataChangedHandler; PLC.DataChangedHandler -= DataChangedHandler;

View File

@@ -115,7 +115,7 @@ public partial class OPCUAClientDebugDriverPage
try try
{ {
var data = await _plc.ReadJTokenValueAsync(new string[] { defalutDebugDriverPage.Address }); var data = await _plc.ReadJTokenValueAsync(new string[] { defalutDebugDriverPage.Address });
defalutDebugDriverPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Debug, SysDateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + " - " + data.ToJson())); defalutDebugDriverPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Debug, SysDateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + " - " + (data[0].Item1 + ":" + data[0].Item3)));
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@@ -14,7 +14,9 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Foundataion\ThingsGateway.Foundation.Adapter.OPCUA\ThingsGateway.Foundation.Adapter.OPCUA.csproj" /> <ProjectReference Include="..\Foundataion\ThingsGateway.Foundation.Adapter.OPCUA\ThingsGateway.Foundation.Adapter.OPCUA.csproj" />
<ProjectReference Include="..\..\ThingsGateway.Blazor\ThingsGateway.Blazor.csproj" /> <ProjectReference Include="..\..\ThingsGateway.Blazor\ThingsGateway.Blazor.csproj" >
<IncludeAssets>Compile</IncludeAssets>
</ProjectReference>
</ItemGroup> </ItemGroup>

View File

@@ -33,6 +33,11 @@
OPCUA客户端 OPCUA客户端
</summary> </summary>
</member> </member>
<member name="M:ThingsGateway.OPCUA.OPCUAClient.#ctor">
<summary>
OPCUA客户端
</summary>
</member>
<member name="P:ThingsGateway.OPCUA.OPCUAClient.DriverDebugUIType"> <member name="P:ThingsGateway.OPCUA.OPCUAClient.DriverDebugUIType">
<inheritdoc/> <inheritdoc/>
</member> </member>

View File

@@ -12,7 +12,6 @@
global using ThingsGateway.Foundation.Adapter.Siemens; global using ThingsGateway.Foundation.Adapter.Siemens;
global using TouchSocket.Core;
global using TouchSocket.Sockets; global using TouchSocket.Sockets;

View File

@@ -25,11 +25,11 @@
<DefalutDebugDriverPage Channel="ChannelEnum.TcpClientEx" @ref=defalutDebugDriverPage> <DefalutDebugDriverPage Channel="ChannelEnum.TcpClientEx" @ref=defalutDebugDriverPage>
<MCard Flat Elevation="0"> <MCard Flat Elevation="0">
<MRow Class="my-1" NoGutters Justify="JustifyTypes.SpaceBetween" Align="AlignTypes.Center"> <MRow Class="my-1" NoGutters Justify="JustifyTypes.SpaceBetween" Align="AlignTypes.Center">
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.Slot)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Slot></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.Slot)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Slot></MTextField>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.Rack)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Rack></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.Rack)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Rack></MTextField>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.TimeOut)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.TimeOut)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
<MSelect Class="mx-1" Style="max-width:200px" @bind-Value="_plc.DataFormat" Outlined Label="@(_plc.Description(x => x.DataFormat))" <MSelect Class="ma-1" Style="max-width:200px" @bind-Value="_plc.DataFormat" Outlined Label="@(_plc.Description(x => x.DataFormat))"
Items=@(typeof(DataFormat).GetEnumList()) Items=@(typeof(DataFormat).GetEnumList())
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })" MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
ItemText=@((u) =>u.des) ItemText=@((u) =>u.des)

View File

@@ -25,11 +25,11 @@
<DefalutDebugDriverPage Channel="ChannelEnum.TcpClientEx" @ref=defalutDebugDriverPage> <DefalutDebugDriverPage Channel="ChannelEnum.TcpClientEx" @ref=defalutDebugDriverPage>
<MCard Flat Elevation="0"> <MCard Flat Elevation="0">
<MRow Class="my-1" NoGutters Justify="JustifyTypes.SpaceBetween" Align="AlignTypes.Center"> <MRow Class="my-1" NoGutters Justify="JustifyTypes.SpaceBetween" Align="AlignTypes.Center">
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.Slot)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Slot></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.Slot)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Slot></MTextField>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.Rack)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Rack></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.Rack)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Rack></MTextField>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.TimeOut)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.TimeOut)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
<MSelect Class="mx-1" Style="max-width:200px" @bind-Value="_plc.DataFormat" Outlined Label="@(_plc.Description(x => x.DataFormat))" <MSelect Class="ma-1" Style="max-width:200px" @bind-Value="_plc.DataFormat" Outlined Label="@(_plc.Description(x => x.DataFormat))"
Items=@(typeof(DataFormat).GetEnumList()) Items=@(typeof(DataFormat).GetEnumList())
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })" MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
ItemText=@((u) =>u.des) ItemText=@((u) =>u.des)

View File

@@ -25,11 +25,11 @@
<DefalutDebugDriverPage Channel="ChannelEnum.TcpClientEx" @ref=defalutDebugDriverPage> <DefalutDebugDriverPage Channel="ChannelEnum.TcpClientEx" @ref=defalutDebugDriverPage>
<MCard Flat Elevation="0"> <MCard Flat Elevation="0">
<MRow Class="my-1" NoGutters Justify="JustifyTypes.SpaceBetween" Align="AlignTypes.Center"> <MRow Class="my-1" NoGutters Justify="JustifyTypes.SpaceBetween" Align="AlignTypes.Center">
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.Slot)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Slot></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.Slot)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Slot></MTextField>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.Rack)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Rack></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.Rack)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Rack></MTextField>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.TimeOut)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.TimeOut)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
<MSelect Class="mx-1" Style="max-width:200px" @bind-Value="_plc.DataFormat" Outlined Label="@(_plc.Description(x => x.DataFormat))" <MSelect Class="ma-1" Style="max-width:200px" @bind-Value="_plc.DataFormat" Outlined Label="@(_plc.Description(x => x.DataFormat))"
Items=@(typeof(DataFormat).GetEnumList()) Items=@(typeof(DataFormat).GetEnumList())
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })" MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
ItemText=@((u) =>u.des) ItemText=@((u) =>u.des)

View File

@@ -25,11 +25,11 @@
<DefalutDebugDriverPage Channel="ChannelEnum.TcpClientEx" @ref=defalutDebugDriverPage> <DefalutDebugDriverPage Channel="ChannelEnum.TcpClientEx" @ref=defalutDebugDriverPage>
<MCard Flat Elevation="0"> <MCard Flat Elevation="0">
<MRow Class="my-1" NoGutters Justify="JustifyTypes.SpaceBetween" Align="AlignTypes.Center"> <MRow Class="my-1" NoGutters Justify="JustifyTypes.SpaceBetween" Align="AlignTypes.Center">
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.Slot)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Slot></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.Slot)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Slot></MTextField>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.Rack)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Rack></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.Rack)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Rack></MTextField>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.TimeOut)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.TimeOut)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
<MSelect Class="mx-1" Style="max-width:200px" @bind-Value="_plc.DataFormat" Outlined Label="@(_plc.Description(x => x.DataFormat))" <MSelect Class="ma-1" Style="max-width:200px" @bind-Value="_plc.DataFormat" Outlined Label="@(_plc.Description(x => x.DataFormat))"
Items=@(typeof(DataFormat).GetEnumList()) Items=@(typeof(DataFormat).GetEnumList())
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })" MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
ItemText=@((u) =>u.des) ItemText=@((u) =>u.des)

View File

@@ -25,11 +25,11 @@
<DefalutDebugDriverPage Channel="ChannelEnum.TcpClientEx" @ref=defalutDebugDriverPage> <DefalutDebugDriverPage Channel="ChannelEnum.TcpClientEx" @ref=defalutDebugDriverPage>
<MCard Flat Elevation="0"> <MCard Flat Elevation="0">
<MRow Class="my-1" NoGutters Justify="JustifyTypes.SpaceBetween" Align="AlignTypes.Center"> <MRow Class="my-1" NoGutters Justify="JustifyTypes.SpaceBetween" Align="AlignTypes.Center">
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.Slot)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Slot></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.Slot)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Slot></MTextField>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.Rack)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Rack></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.Rack)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Rack></MTextField>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.TimeOut)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.TimeOut)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
<MSelect Class="mx-1" Style="max-width:200px" @bind-Value="_plc.DataFormat" Outlined Label="@(_plc.Description(x => x.DataFormat))" <MSelect Class="ma-1" Style="max-width:200px" @bind-Value="_plc.DataFormat" Outlined Label="@(_plc.Description(x => x.DataFormat))"
Items=@(typeof(DataFormat).GetEnumList()) Items=@(typeof(DataFormat).GetEnumList())
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })" MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
ItemText=@((u) =>u.des) ItemText=@((u) =>u.des)

View File

@@ -25,11 +25,11 @@
<DefalutDebugDriverPage Channel="ChannelEnum.TcpClientEx" @ref=defalutDebugDriverPage> <DefalutDebugDriverPage Channel="ChannelEnum.TcpClientEx" @ref=defalutDebugDriverPage>
<MCard Flat Elevation="0"> <MCard Flat Elevation="0">
<MRow Class="my-1" NoGutters Justify="JustifyTypes.SpaceBetween" Align="AlignTypes.Center"> <MRow Class="my-1" NoGutters Justify="JustifyTypes.SpaceBetween" Align="AlignTypes.Center">
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.Slot)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Slot></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.Slot)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Slot></MTextField>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.Rack)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Rack></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.Rack)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.Rack></MTextField>
<MTextField Class="mx-1" Label=@(_plc.Description(x => x.TimeOut)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField> <MTextField Class="ma-1" Label=@(_plc.Description(x => x.TimeOut)) Dense Outlined HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
<MSelect Class="mx-1" Style="max-width:200px" @bind-Value="_plc.DataFormat" Outlined Label="@(_plc.Description(x => x.DataFormat))" <MSelect Class="ma-1" Style="max-width:200px" @bind-Value="_plc.DataFormat" Outlined Label="@(_plc.Description(x => x.DataFormat))"
Items=@(typeof(DataFormat).GetEnumList()) Items=@(typeof(DataFormat).GetEnumList())
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })" MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
ItemText=@((u) =>u.des) ItemText=@((u) =>u.des)

View File

@@ -2,6 +2,7 @@
<PropertyGroup> <PropertyGroup>
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>--> <!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
<EnableDynamicLoading>true</EnableDynamicLoading>
</PropertyGroup> </PropertyGroup>
@@ -13,7 +14,9 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\ThingsGateway.Blazor\ThingsGateway.Blazor.csproj" /> <ProjectReference Include="..\..\ThingsGateway.Blazor\ThingsGateway.Blazor.csproj" >
<IncludeAssets>Compile</IncludeAssets>
</ProjectReference>
<ProjectReference Include="..\Foundataion\ThingsGateway.Foundation.Adapter.Siemens\ThingsGateway.Foundation.Adapter.Siemens.csproj" /> <ProjectReference Include="..\Foundataion\ThingsGateway.Foundation.Adapter.Siemens\ThingsGateway.Foundation.Adapter.Siemens.csproj" />
</ItemGroup> </ItemGroup>

View File

@@ -68,7 +68,7 @@ public class BlazorAuthorizeHandler : AppAuthorizeHandler
//这里鉴别密码是否改变 //这里鉴别密码是否改变
var userId = context.User.Claims.FirstOrDefault(it => it.Type == ClaimConst.UserId).Value.ToLong(); var userId = context.User.Claims.FirstOrDefault(it => it.Type == ClaimConst.UserId).Value.ToLong();
var isOpenApi = context.User.Claims.FirstOrDefault(it => it.Type == ClaimConst.IsOpenApi)?.Value?.ToBool() == true; var isOpenApi = context.User.Claims.FirstOrDefault(it => it.Type == ClaimConst.IsOpenApi)?.Value?.ToBoolean() == true;
if (isOpenApi) if (isOpenApi)
{ {
var _openApiUserService = App.GetService<OpenApiUserService>(); var _openApiUserService = App.GetService<OpenApiUserService>();
@@ -91,7 +91,7 @@ public class BlazorAuthorizeHandler : AppAuthorizeHandler
if (user == null) { return false; } if (user == null) { return false; }
//超级管理员都能访问 //超级管理员都能访问
if (context.User.Claims.FirstOrDefault(it => it.Type == ClaimConst.IsSuperAdmin)?.Value.ToBool() == true) return true; if (context.User.Claims.FirstOrDefault(it => it.Type == ClaimConst.IsSuperAdmin)?.Value.ToBoolean() == true) return true;
if (context.Resource is RouteData routeData) if (context.Resource is RouteData routeData)
{ {
// 获取超级管理员特性 // 获取超级管理员特性
@@ -144,7 +144,7 @@ public class BlazorAuthorizeHandler : AppAuthorizeHandler
{ {
var userId = context.User.Claims.FirstOrDefault(it => it.Type == ClaimConst.UserId).Value; var userId = context.User.Claims.FirstOrDefault(it => it.Type == ClaimConst.UserId).Value;
var verificatId = context.User.Claims.FirstOrDefault(it => it.Type == ClaimConst.VerificatId)?.Value; var verificatId = context.User.Claims.FirstOrDefault(it => it.Type == ClaimConst.VerificatId)?.Value;
var isOpenApi = context.User.Claims.FirstOrDefault(it => it.Type == ClaimConst.IsOpenApi)?.Value?.ToBool(false) == true; var isOpenApi = context.User.Claims.FirstOrDefault(it => it.Type == ClaimConst.IsOpenApi)?.Value?.ToBoolean(false) == true;
var _verificatService = App.GetService<VerificatService>(); var _verificatService = App.GetService<VerificatService>();
if (isOpenApi) if (isOpenApi)
{ {

View File

@@ -0,0 +1,12 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-ef": {
"version": "7.0.10",
"commands": [
"dotnet-ef"
]
}
}
}

View File

@@ -0,0 +1,45 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using Furion;
using System.Reflection;
namespace ThingsGateway.Web.Entry;
/// <inheritdoc cref="ISingleFilePublish"/>
public class SingleFilePublish : ISingleFilePublish
{
/// <inheritdoc/>
public Assembly[] IncludeAssemblies()
{
return Array.Empty<Assembly>();
}
/// <inheritdoc/>
public string[] IncludeAssemblyNames()
{
return new[]
{
"ThingsGateway.Web.Core",
"ThingsGateway.Admin.ApiController",
"ThingsGateway.Admin.Application",
"ThingsGateway.Admin.Blazor",
"ThingsGateway.Admin.Blazor.Core",
"ThingsGateway.Admin.Core",
"ThingsGateway.ApiController",
"ThingsGateway.Application",
"ThingsGateway.Blazor",
"ThingsGateway.Foundation",
};
}
}

View File

@@ -88,6 +88,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Foundataion.Demo", "Foundat
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ModbusDemo", "ThingsGateway.Plugin\Foundataion.Demo\ModbusDemo\ModbusDemo.csproj", "{48D2CA26-E535-413D-8CA9-A4A2AAC6582D}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ModbusDemo", "ThingsGateway.Plugin\Foundataion.Demo\ModbusDemo\ModbusDemo.csproj", "{48D2CA26-E535-413D-8CA9-A4A2AAC6582D}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OPCUAClientDemo", "ThingsGateway.Plugin\Foundataion.Demo\OPCUAClientDemo\OPCUAClientDemo.csproj", "{3F83EF0F-002D-4D06-87A8-739399074DBA}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -186,6 +188,10 @@ Global
{48D2CA26-E535-413D-8CA9-A4A2AAC6582D}.Debug|Any CPU.Build.0 = Debug|Any CPU {48D2CA26-E535-413D-8CA9-A4A2AAC6582D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{48D2CA26-E535-413D-8CA9-A4A2AAC6582D}.Release|Any CPU.ActiveCfg = Release|Any CPU {48D2CA26-E535-413D-8CA9-A4A2AAC6582D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{48D2CA26-E535-413D-8CA9-A4A2AAC6582D}.Release|Any CPU.Build.0 = Release|Any CPU {48D2CA26-E535-413D-8CA9-A4A2AAC6582D}.Release|Any CPU.Build.0 = Release|Any CPU
{3F83EF0F-002D-4D06-87A8-739399074DBA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3F83EF0F-002D-4D06-87A8-739399074DBA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3F83EF0F-002D-4D06-87A8-739399074DBA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3F83EF0F-002D-4D06-87A8-739399074DBA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@@ -220,6 +226,7 @@ Global
{E1C327FA-C442-45DD-9265-9EA26573B61E} = {F2DF3BE7-D497-44B3-9CD6-CDDBC4FBD09C} {E1C327FA-C442-45DD-9265-9EA26573B61E} = {F2DF3BE7-D497-44B3-9CD6-CDDBC4FBD09C}
{E733E483-4823-4BD6-BC29-669426386A96} = {86119A5F-5717-42FF-8888-F034B4136A1B} {E733E483-4823-4BD6-BC29-669426386A96} = {86119A5F-5717-42FF-8888-F034B4136A1B}
{48D2CA26-E535-413D-8CA9-A4A2AAC6582D} = {E733E483-4823-4BD6-BC29-669426386A96} {48D2CA26-E535-413D-8CA9-A4A2AAC6582D} = {E733E483-4823-4BD6-BC29-669426386A96}
{3F83EF0F-002D-4D06-87A8-739399074DBA} = {E733E483-4823-4BD6-BC29-669426386A96}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {38B292E0-B3E7-4608-9912-1B057C2A508F} SolutionGuid = {38B292E0-B3E7-4608-9912-1B057C2A508F}