diff --git a/.vs/IoTGateway/DesignTimeBuild/.dtbcache.v2 b/.vs/IoTGateway/DesignTimeBuild/.dtbcache.v2
index f1ee907..e2ccd17 100644
Binary files a/.vs/IoTGateway/DesignTimeBuild/.dtbcache.v2 and b/.vs/IoTGateway/DesignTimeBuild/.dtbcache.v2 differ
diff --git a/.vs/IoTGateway/v17/.futdcache.v1 b/.vs/IoTGateway/v17/.futdcache.v1
index 5cfc7a7..5bc732e 100644
Binary files a/.vs/IoTGateway/v17/.futdcache.v1 and b/.vs/IoTGateway/v17/.futdcache.v1 differ
diff --git a/.vs/IoTGateway/v17/.suo b/.vs/IoTGateway/v17/.suo
index 93918d5..68565c0 100644
Binary files a/.vs/IoTGateway/v17/.suo and b/.vs/IoTGateway/v17/.suo differ
diff --git a/.vs/IoTGateway/v17/fileList.bin b/.vs/IoTGateway/v17/fileList.bin
index f18580b..77c9609 100644
Binary files a/.vs/IoTGateway/v17/fileList.bin and b/.vs/IoTGateway/v17/fileList.bin differ
diff --git a/IoTGateway.DataAccess/Migrations/20220323063908_attribut.Designer.cs b/IoTGateway.DataAccess/Migrations/20220323063908_attribut.Designer.cs
new file mode 100644
index 0000000..1554681
--- /dev/null
+++ b/IoTGateway.DataAccess/Migrations/20220323063908_attribut.Designer.cs
@@ -0,0 +1,801 @@
+//
+using System;
+using IoTGateway.DataAccess;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace IoTGateway.DataAccess.Migrations
+{
+ [DbContext(typeof(DataContext))]
+ [Migration("20220323063908_attribut")]
+ partial class attribut
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder.HasAnnotation("ProductVersion", "6.0.1");
+
+ modelBuilder.Entity("IoTGateway.Model.Device", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("AutoStart")
+ .HasColumnType("INTEGER");
+
+ b.Property("CreateBy")
+ .HasColumnType("TEXT");
+
+ b.Property("CreateTime")
+ .HasColumnType("TEXT");
+
+ b.Property("Description")
+ .HasColumnType("TEXT");
+
+ b.Property("DeviceName")
+ .HasColumnType("TEXT");
+
+ b.Property("DeviceTypeEnum")
+ .HasColumnType("INTEGER");
+
+ b.Property("DriverId")
+ .HasColumnType("TEXT");
+
+ b.Property("Index")
+ .HasColumnType("INTEGER");
+
+ b.Property("ParentId")
+ .HasColumnType("TEXT");
+
+ b.Property("UpdateBy")
+ .HasColumnType("TEXT");
+
+ b.Property("UpdateTime")
+ .HasColumnType("TEXT");
+
+ b.HasKey("ID");
+
+ b.HasIndex("DriverId");
+
+ b.HasIndex("ParentId");
+
+ b.ToTable("Devices");
+ });
+
+ modelBuilder.Entity("IoTGateway.Model.DeviceConfig", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("CreateBy")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("CreateTime")
+ .HasColumnType("TEXT");
+
+ b.Property("DataSide")
+ .HasColumnType("INTEGER");
+
+ b.Property("Description")
+ .HasColumnType("TEXT");
+
+ b.Property("DeviceConfigName")
+ .HasColumnType("TEXT");
+
+ b.Property("DeviceId")
+ .HasColumnType("TEXT");
+
+ b.Property("EnumInfo")
+ .HasColumnType("TEXT");
+
+ b.Property("UpdateBy")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("UpdateTime")
+ .HasColumnType("TEXT");
+
+ b.Property("Value")
+ .HasColumnType("TEXT");
+
+ b.HasKey("ID");
+
+ b.HasIndex("DeviceId");
+
+ b.ToTable("DeviceConfigs");
+ });
+
+ modelBuilder.Entity("IoTGateway.Model.DeviceVariable", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("DataType")
+ .HasColumnType("INTEGER");
+
+ b.Property("Description")
+ .HasColumnType("TEXT");
+
+ b.Property("DeviceAddress")
+ .HasColumnType("TEXT");
+
+ b.Property("DeviceId")
+ .HasColumnType("TEXT");
+
+ b.Property("Expressions")
+ .HasColumnType("TEXT");
+
+ b.Property("Method")
+ .HasColumnType("TEXT");
+
+ b.Property("Name")
+ .HasColumnType("TEXT");
+
+ b.Property("ProtectType")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("ID");
+
+ b.HasIndex("DeviceId");
+
+ b.ToTable("DeviceVariables");
+ });
+
+ modelBuilder.Entity("IoTGateway.Model.Driver", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("AssembleName")
+ .HasColumnType("TEXT");
+
+ b.Property("AuthorizesNum")
+ .HasColumnType("INTEGER");
+
+ b.Property("CreateBy")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("CreateTime")
+ .HasColumnType("TEXT");
+
+ b.Property("DriverName")
+ .HasColumnType("TEXT");
+
+ b.Property("FileName")
+ .HasColumnType("TEXT");
+
+ b.Property("UpdateBy")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("UpdateTime")
+ .HasColumnType("TEXT");
+
+ b.HasKey("ID");
+
+ b.ToTable("Drivers");
+ });
+
+ modelBuilder.Entity("IoTGateway.Model.SystemConfig", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("CreateBy")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("CreateTime")
+ .HasColumnType("TEXT");
+
+ b.Property("GatewayName")
+ .HasColumnType("TEXT");
+
+ b.Property("IoTPlatformType")
+ .HasColumnType("INTEGER");
+
+ b.Property("MqttIp")
+ .HasColumnType("TEXT");
+
+ b.Property("MqttPort")
+ .HasColumnType("INTEGER");
+
+ b.Property("MqttUName")
+ .HasColumnType("TEXT");
+
+ b.Property("MqttUPwd")
+ .HasColumnType("TEXT");
+
+ b.Property("UpdateBy")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("UpdateTime")
+ .HasColumnType("TEXT");
+
+ b.HasKey("ID");
+
+ b.ToTable("SystemConfig");
+ });
+
+ modelBuilder.Entity("WalkingTec.Mvvm.Core.ActionLog", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("ActionName")
+ .HasMaxLength(255)
+ .HasColumnType("TEXT");
+
+ b.Property("ActionTime")
+ .HasColumnType("TEXT");
+
+ b.Property("ActionUrl")
+ .HasMaxLength(250)
+ .HasColumnType("TEXT");
+
+ b.Property("CreateBy")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("CreateTime")
+ .HasColumnType("TEXT");
+
+ b.Property("Duration")
+ .HasColumnType("REAL");
+
+ b.Property("IP")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("ITCode")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("LogType")
+ .HasColumnType("INTEGER");
+
+ b.Property("ModuleName")
+ .HasMaxLength(255)
+ .HasColumnType("TEXT");
+
+ b.Property("Remark")
+ .HasColumnType("TEXT");
+
+ b.Property("UpdateBy")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("UpdateTime")
+ .HasColumnType("TEXT");
+
+ b.HasKey("ID");
+
+ b.ToTable("ActionLogs");
+ });
+
+ modelBuilder.Entity("WalkingTec.Mvvm.Core.DataPrivilege", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("CreateBy")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("CreateTime")
+ .HasColumnType("TEXT");
+
+ b.Property("Domain")
+ .HasColumnType("TEXT");
+
+ b.Property("GroupCode")
+ .HasColumnType("TEXT");
+
+ b.Property("RelateId")
+ .HasColumnType("TEXT");
+
+ b.Property("TableName")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("UpdateBy")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("UpdateTime")
+ .HasColumnType("TEXT");
+
+ b.Property("UserCode")
+ .HasColumnType("TEXT");
+
+ b.HasKey("ID");
+
+ b.ToTable("DataPrivileges");
+ });
+
+ modelBuilder.Entity("WalkingTec.Mvvm.Core.FileAttachment", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("ExtraInfo")
+ .HasColumnType("TEXT");
+
+ b.Property("FileData")
+ .HasColumnType("BLOB");
+
+ b.Property("FileExt")
+ .IsRequired()
+ .HasMaxLength(10)
+ .HasColumnType("TEXT");
+
+ b.Property("FileName")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("HandlerInfo")
+ .HasColumnType("TEXT");
+
+ b.Property("Length")
+ .HasColumnType("INTEGER");
+
+ b.Property("Path")
+ .HasColumnType("TEXT");
+
+ b.Property("SaveMode")
+ .HasColumnType("TEXT");
+
+ b.Property("UploadTime")
+ .HasColumnType("TEXT");
+
+ b.HasKey("ID");
+
+ b.ToTable("FileAttachments");
+ });
+
+ modelBuilder.Entity("WalkingTec.Mvvm.Core.FrameworkGroup", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("CreateBy")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("CreateTime")
+ .HasColumnType("TEXT");
+
+ b.Property("GroupCode")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("TEXT");
+
+ b.Property("GroupName")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("GroupRemark")
+ .HasColumnType("TEXT");
+
+ b.Property("TenantCode")
+ .HasColumnType("TEXT");
+
+ b.Property("UpdateBy")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("UpdateTime")
+ .HasColumnType("TEXT");
+
+ b.HasKey("ID");
+
+ b.ToTable("FrameworkGroups");
+ });
+
+ modelBuilder.Entity("WalkingTec.Mvvm.Core.FrameworkMenu", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("ActionName")
+ .HasColumnType("TEXT");
+
+ b.Property("ClassName")
+ .HasColumnType("TEXT");
+
+ b.Property("DisplayOrder")
+ .IsRequired()
+ .HasColumnType("INTEGER");
+
+ b.Property("Domain")
+ .HasColumnType("TEXT");
+
+ b.Property("FolderOnly")
+ .HasColumnType("INTEGER");
+
+ b.Property("Icon")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("IsInherit")
+ .HasColumnType("INTEGER");
+
+ b.Property("IsInside")
+ .IsRequired()
+ .HasColumnType("INTEGER");
+
+ b.Property("IsPublic")
+ .HasColumnType("INTEGER");
+
+ b.Property("MethodName")
+ .HasColumnType("TEXT");
+
+ b.Property("ModuleName")
+ .HasColumnType("TEXT");
+
+ b.Property("PageName")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("ParentId")
+ .HasColumnType("TEXT");
+
+ b.Property("ShowOnMenu")
+ .HasColumnType("INTEGER");
+
+ b.Property("Url")
+ .HasColumnType("TEXT");
+
+ b.HasKey("ID");
+
+ b.HasIndex("ParentId");
+
+ b.ToTable("FrameworkMenus");
+ });
+
+ modelBuilder.Entity("WalkingTec.Mvvm.Core.FrameworkRole", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("CreateBy")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("CreateTime")
+ .HasColumnType("TEXT");
+
+ b.Property("RoleCode")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("TEXT");
+
+ b.Property("RoleName")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("RoleRemark")
+ .HasColumnType("TEXT");
+
+ b.Property("TenantCode")
+ .HasColumnType("TEXT");
+
+ b.Property("UpdateBy")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("UpdateTime")
+ .HasColumnType("TEXT");
+
+ b.HasKey("ID");
+
+ b.ToTable("FrameworkRoles");
+ });
+
+ modelBuilder.Entity("WalkingTec.Mvvm.Core.FrameworkUser", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("Address")
+ .HasMaxLength(200)
+ .HasColumnType("TEXT");
+
+ b.Property("CellPhone")
+ .HasColumnType("TEXT");
+
+ b.Property("CreateBy")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("CreateTime")
+ .HasColumnType("TEXT");
+
+ b.Property("Email")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("Gender")
+ .HasColumnType("INTEGER");
+
+ b.Property("HomePhone")
+ .HasMaxLength(30)
+ .HasColumnType("TEXT");
+
+ b.Property("ITCode")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("IsValid")
+ .HasColumnType("INTEGER");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("Password")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("TEXT");
+
+ b.Property("PhotoId")
+ .HasColumnType("TEXT");
+
+ b.Property("TenantCode")
+ .HasColumnType("TEXT");
+
+ b.Property("UpdateBy")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("UpdateTime")
+ .HasColumnType("TEXT");
+
+ b.Property("ZipCode")
+ .HasColumnType("TEXT");
+
+ b.HasKey("ID");
+
+ b.HasIndex("PhotoId");
+
+ b.ToTable("FrameworkUsers");
+ });
+
+ modelBuilder.Entity("WalkingTec.Mvvm.Core.FrameworkUserGroup", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("CreateBy")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("CreateTime")
+ .HasColumnType("TEXT");
+
+ b.Property("GroupCode")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("UpdateBy")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("UpdateTime")
+ .HasColumnType("TEXT");
+
+ b.Property("UserCode")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.HasKey("ID");
+
+ b.ToTable("FrameworkUserGroups");
+ });
+
+ modelBuilder.Entity("WalkingTec.Mvvm.Core.FrameworkUserRole", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("CreateBy")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("CreateTime")
+ .HasColumnType("TEXT");
+
+ b.Property("RoleCode")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("UpdateBy")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("UpdateTime")
+ .HasColumnType("TEXT");
+
+ b.Property("UserCode")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.HasKey("ID");
+
+ b.ToTable("FrameworkUserRoles");
+ });
+
+ modelBuilder.Entity("WalkingTec.Mvvm.Core.FunctionPrivilege", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("Allowed")
+ .IsRequired()
+ .HasColumnType("INTEGER");
+
+ b.Property("CreateBy")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("CreateTime")
+ .HasColumnType("TEXT");
+
+ b.Property("MenuItemId")
+ .HasColumnType("TEXT");
+
+ b.Property("RoleCode")
+ .HasColumnType("TEXT");
+
+ b.Property("UpdateBy")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("UpdateTime")
+ .HasColumnType("TEXT");
+
+ b.HasKey("ID");
+
+ b.HasIndex("MenuItemId");
+
+ b.ToTable("FunctionPrivileges");
+ });
+
+ modelBuilder.Entity("WalkingTec.Mvvm.Core.PersistedGrant", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("CreationTime")
+ .HasColumnType("TEXT");
+
+ b.Property("Expiration")
+ .HasColumnType("TEXT");
+
+ b.Property("RefreshToken")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("Type")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("UserCode")
+ .HasColumnType("TEXT");
+
+ b.HasKey("ID");
+
+ b.ToTable("PersistedGrants");
+ });
+
+ modelBuilder.Entity("IoTGateway.Model.Device", b =>
+ {
+ b.HasOne("IoTGateway.Model.Driver", "Driver")
+ .WithMany()
+ .HasForeignKey("DriverId");
+
+ b.HasOne("IoTGateway.Model.Device", "Parent")
+ .WithMany("Children")
+ .HasForeignKey("ParentId");
+
+ b.Navigation("Driver");
+
+ b.Navigation("Parent");
+ });
+
+ modelBuilder.Entity("IoTGateway.Model.DeviceConfig", b =>
+ {
+ b.HasOne("IoTGateway.Model.Device", "Device")
+ .WithMany("DeviceConfigs")
+ .HasForeignKey("DeviceId");
+
+ b.Navigation("Device");
+ });
+
+ modelBuilder.Entity("IoTGateway.Model.DeviceVariable", b =>
+ {
+ b.HasOne("IoTGateway.Model.Device", "Device")
+ .WithMany("DeviceVariables")
+ .HasForeignKey("DeviceId");
+
+ b.Navigation("Device");
+ });
+
+ modelBuilder.Entity("WalkingTec.Mvvm.Core.FrameworkMenu", b =>
+ {
+ b.HasOne("WalkingTec.Mvvm.Core.FrameworkMenu", "Parent")
+ .WithMany("Children")
+ .HasForeignKey("ParentId");
+
+ b.Navigation("Parent");
+ });
+
+ modelBuilder.Entity("WalkingTec.Mvvm.Core.FrameworkUser", b =>
+ {
+ b.HasOne("WalkingTec.Mvvm.Core.FileAttachment", "Photo")
+ .WithMany()
+ .HasForeignKey("PhotoId")
+ .OnDelete(DeleteBehavior.Restrict);
+
+ b.Navigation("Photo");
+ });
+
+ modelBuilder.Entity("WalkingTec.Mvvm.Core.FunctionPrivilege", b =>
+ {
+ b.HasOne("WalkingTec.Mvvm.Core.FrameworkMenu", "MenuItem")
+ .WithMany("Privileges")
+ .HasForeignKey("MenuItemId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("MenuItem");
+ });
+
+ modelBuilder.Entity("IoTGateway.Model.Device", b =>
+ {
+ b.Navigation("Children");
+
+ b.Navigation("DeviceConfigs");
+
+ b.Navigation("DeviceVariables");
+ });
+
+ modelBuilder.Entity("WalkingTec.Mvvm.Core.FrameworkMenu", b =>
+ {
+ b.Navigation("Children");
+
+ b.Navigation("Privileges");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/IoTGateway.DataAccess/Migrations/20220323063908_attribut.cs b/IoTGateway.DataAccess/Migrations/20220323063908_attribut.cs
new file mode 100644
index 0000000..c06c241
--- /dev/null
+++ b/IoTGateway.DataAccess/Migrations/20220323063908_attribut.cs
@@ -0,0 +1,26 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace IoTGateway.DataAccess.Migrations
+{
+ public partial class attribut : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn(
+ name: "DataSide",
+ table: "DeviceConfigs",
+ type: "INTEGER",
+ nullable: false,
+ defaultValue: 0);
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropColumn(
+ name: "DataSide",
+ table: "DeviceConfigs");
+ }
+ }
+}
diff --git a/IoTGateway.DataAccess/Migrations/DataContextModelSnapshot.cs b/IoTGateway.DataAccess/Migrations/DataContextModelSnapshot.cs
index 206af2a..5181c14 100644
--- a/IoTGateway.DataAccess/Migrations/DataContextModelSnapshot.cs
+++ b/IoTGateway.DataAccess/Migrations/DataContextModelSnapshot.cs
@@ -78,6 +78,9 @@ namespace IoTGateway.DataAccess.Migrations
b.Property("CreateTime")
.HasColumnType("TEXT");
+ b.Property("DataSide")
+ .HasColumnType("INTEGER");
+
b.Property("Description")
.HasColumnType("TEXT");
diff --git a/IoTGateway.Model/Common.cs b/IoTGateway.Model/Common.cs
index 5f32c80..91952c9 100644
--- a/IoTGateway.Model/Common.cs
+++ b/IoTGateway.Model/Common.cs
@@ -17,4 +17,11 @@ namespace IoTGateway.Model
[Display(Name = "读写")]
ReadAndWrite = 1
}
+
+ public enum DataSide
+ {
+ AnySide=0,
+ //ServerSide=1,
+ ClientSide=2,
+ }
}
\ No newline at end of file
diff --git a/IoTGateway.Model/DeviceConfig.cs b/IoTGateway.Model/DeviceConfig.cs
index 97928e9..b6cbf83 100644
--- a/IoTGateway.Model/DeviceConfig.cs
+++ b/IoTGateway.Model/DeviceConfig.cs
@@ -8,6 +8,8 @@ namespace IoTGateway.Model
{
[Display(Name = "名称")]
public string DeviceConfigName { get; set; }
+ [Display(Name = "属性侧")]
+ public DataSide DataSide { get; set; }
[Display(Name = "描述")]
public string Description { get; set; }
[Display(Name = "值")]
diff --git a/IoTGateway.ViewModel/BasicData/DeviceConfigVMs/DeviceConfigListVM.cs b/IoTGateway.ViewModel/BasicData/DeviceConfigVMs/DeviceConfigListVM.cs
index e8bbee6..45e5720 100644
--- a/IoTGateway.ViewModel/BasicData/DeviceConfigVMs/DeviceConfigListVM.cs
+++ b/IoTGateway.ViewModel/BasicData/DeviceConfigVMs/DeviceConfigListVM.cs
@@ -51,6 +51,7 @@ namespace IoTGateway.ViewModel.BasicData.DeviceConfigVMs
{
return new List>{
this.MakeGridHeader(x => x.DeviceConfigName).SetWidth(100),
+ this.MakeGridHeader(x => x.DataSide).SetWidth(100),
this.MakeGridHeader(x => x.Description).SetWidth(100),
this.MakeGridHeader(x => x.Value).SetWidth(100),
this.MakeGridHeader(x => x.DeviceName_view).SetWidth(100),
@@ -62,25 +63,28 @@ namespace IoTGateway.ViewModel.BasicData.DeviceConfigVMs
public override IOrderedQueryable GetSearchQuery()
{
var query = DC.Set()
- .CheckContain(Searcher.DeviceConfigName, x=>x.DeviceConfigName)
- .CheckContain(Searcher.Value, x=>x.Value)
- .CheckEqual(Searcher.DeviceId, x=>x.DeviceId)
+ .CheckContain(Searcher.DeviceConfigName, x => x.DeviceConfigName)
+ .CheckContain(Searcher.Value, x => x.Value)
+ .CheckEqual(Searcher.DeviceId, x => x.DeviceId)
+ .CheckEqual(Searcher.DataSide, x => x.DataSide)
.Select(x => new DeviceConfig_View
{
- ID = x.ID,
+ ID = x.ID,
DeviceConfigName = x.DeviceConfigName,
+ DataSide = x.DataSide,
Description = x.Description,
Value = x.Value,
EnumInfo = x.EnumInfo,
DeviceName_view = x.Device.DeviceName,
})
- .OrderBy(x => x.DeviceName_view).ThenBy(x=>x.DeviceConfigName);
+ .OrderBy(x => x.DeviceName_view).ThenBy(x => x.DeviceConfigName);
return query;
}
}
- public class DeviceConfig_View : DeviceConfig{
+ public class DeviceConfig_View : DeviceConfig
+ {
[Display(Name = "设备名")]
public String DeviceName_view { get; set; }
diff --git a/IoTGateway.ViewModel/BasicData/DeviceConfigVMs/DeviceConfigSearcher.cs b/IoTGateway.ViewModel/BasicData/DeviceConfigVMs/DeviceConfigSearcher.cs
index f44bfae..b36adce 100644
--- a/IoTGateway.ViewModel/BasicData/DeviceConfigVMs/DeviceConfigSearcher.cs
+++ b/IoTGateway.ViewModel/BasicData/DeviceConfigVMs/DeviceConfigSearcher.cs
@@ -14,6 +14,8 @@ namespace IoTGateway.ViewModel.BasicData.DeviceConfigVMs
{
[Display(Name = "名称")]
public String DeviceConfigName { get; set; }
+ [Display(Name = "属性侧")]
+ public DataSide? DataSide { get; set; }
[Display(Name = "值")]
public String Value { get; set; }
public List AllDevices { get; set; }
diff --git a/IoTGateway.ViewModel/BasicData/DeviceVMs/AttributeVM.cs b/IoTGateway.ViewModel/BasicData/DeviceVMs/AttributeVM.cs
new file mode 100644
index 0000000..5d45de7
--- /dev/null
+++ b/IoTGateway.ViewModel/BasicData/DeviceVMs/AttributeVM.cs
@@ -0,0 +1,56 @@
+using Microsoft.EntityFrameworkCore;
+using Plugin;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using WalkingTec.Mvvm.Core;
+using WalkingTec.Mvvm.Core.Extensions;
+using IoTGateway.Model;
+
+namespace IoTGateway.ViewModel.BasicData.DeviceVMs
+{
+ public class AttributeVM : BaseVM
+ {
+ public string 请求结果 { get; set; }
+ public string 设备名称 { get; set; }
+
+ public void Request()
+ {
+ using (var transaction = DC.BeginTransaction())
+ {
+ try
+ {
+ var device = DC.Set().Where(x => x.ID == Guid.Parse(FC["id"].ToString())).Include(x => x.Parent).Include(x=>x.DeviceConfigs).Include(x => x.Driver).FirstOrDefault();
+
+ if (device == null)
+ 请求结果 = "复制失败,找不到设备";
+ else
+ {
+ var myMqttClient = Wtm.ServiceProvider.GetService(typeof(MyMqttClient)) as MyMqttClient;
+ myMqttClient.RequestAttributes(device.DeviceName, true, device.DeviceConfigs.Where(x => x.DataSide == DataSide.AnySide).Select(x => x.DeviceConfigName).ToArray());
+ }
+ DC.SaveChanges();
+ transaction.Commit();
+ 请求结果 = "请求成功";
+
+ var pluginManager = Wtm.ServiceProvider.GetService(typeof(DeviceService)) as DeviceService;
+ pluginManager?.UpdateDevice(device);
+ }
+ catch (Exception ex)
+ {
+ transaction.Rollback();
+
+ 请求结果 = $"请求超时,{ex}";
+ }
+ }
+ }
+
+ protected override void InitVM()
+ {
+ var device = DC.Set().AsNoTracking().Include(x => x.Parent).Where(x => x.ID == Guid.Parse(FC["id"].ToString())).FirstOrDefault();
+ 设备名称 = $"{device?.Parent?.DeviceName}===>{device?.DeviceName}";
+
+ base.InitVM();
+ }
+ }
+}
diff --git a/IoTGateway.ViewModel/BasicData/DeviceVMs/DeviceListVM.cs b/IoTGateway.ViewModel/BasicData/DeviceVMs/DeviceListVM.cs
index f3e998e..ff94a64 100644
--- a/IoTGateway.ViewModel/BasicData/DeviceVMs/DeviceListVM.cs
+++ b/IoTGateway.ViewModel/BasicData/DeviceVMs/DeviceListVM.cs
@@ -18,6 +18,7 @@ namespace IoTGateway.ViewModel.BasicData.DeviceVMs
return new List
{
this.MakeAction("Device","Copy","设备复制","设备复制", GridActionParameterTypesEnum.SingleId,"BasicData",600).SetIconCls("layui-icon layui-icon-template-1").SetPromptMessage("你确定复制设备,包括配置参数和变量?").SetDialogTitle("复制设备确认").SetHideOnToolBar(true).SetShowInRow(true).SetBindVisiableColName("copy"),
+ this.MakeAction("Device","Attribute","请求属性","请求属性", GridActionParameterTypesEnum.SingleId,"BasicData",600).SetIconCls("layui-icon layui-icon-download-circle").SetPromptMessage("你确定请求客户端属性和共享属性吗?").SetDialogTitle("请求属性确认").SetHideOnToolBar(true).SetShowInRow(true).SetBindVisiableColName("attribute"),
this.MakeAction("Device","CreateGroup","创建组","创建组", GridActionParameterTypesEnum.NoId,"BasicData",600).SetIconCls("_wtmicon _wtmicon-zuzhiqunzu").SetDialogTitle("创建组").SetShowInRow(false),
this.MakeStandardAction("Device", GridActionStandardTypesEnum.Create, "创建设备","BasicData", dialogWidth: 800,name:"创建设备").SetIconCls("layui-icon layui-icon-senior"),
this.MakeStandardAction("Device", GridActionStandardTypesEnum.Edit, Localizer["Sys.Edit"], "BasicData", dialogWidth: 800),
@@ -45,6 +46,10 @@ namespace IoTGateway.ViewModel.BasicData.DeviceVMs
if(a.DeviceTypeEnum== DeviceTypeEnum.Device)
return "true";
return "false";
+ }),this.MakeGridHeader(x=>"attribute").SetHide().SetFormat((a,b)=>{
+ if(a.DeviceTypeEnum== DeviceTypeEnum.Device)
+ return "true";
+ return "false";
}),
this.MakeGridHeaderAction(width: 280)
};
diff --git a/IoTGateway.ViewModel/BasicData/DeviceVariableVMs/DeviceVariableListVM.cs b/IoTGateway.ViewModel/BasicData/DeviceVariableVMs/DeviceVariableListVM.cs
index e419ae9..6515368 100644
--- a/IoTGateway.ViewModel/BasicData/DeviceVariableVMs/DeviceVariableListVM.cs
+++ b/IoTGateway.ViewModel/BasicData/DeviceVariableVMs/DeviceVariableListVM.cs
@@ -44,10 +44,10 @@ namespace IoTGateway.ViewModel.BasicData.DeviceVariableVMs
{
foreach (var item in device.Children)
{
- var deviceThread = deviceService.DeviceThreads.Where(x => x.Device.ID.ToString() == (string)item.Value).FirstOrDefault();
+ var deviceThread = deviceService.DeviceThreads.Where(x => x._device.ID.ToString() == (string)item.Value).FirstOrDefault();
item.Text = item.Text;
- item.Icon = deviceThread.Device.AutoStart ? (deviceThread.Driver.IsConnected ? "layui-icon-link" : "layui-icon-unlink") : "layui-icon-pause";
+ item.Icon = deviceThread._device.AutoStart ? (deviceThread._driver.IsConnected ? "layui-icon-link" : "layui-icon-unlink") : "layui-icon-pause";
item.Expended = true;
}
}
@@ -86,7 +86,7 @@ namespace IoTGateway.ViewModel.BasicData.DeviceVariableVMs
var deviceService = Wtm.ServiceProvider.GetService(typeof(DeviceService)) as DeviceService;
foreach (var item in EntityList)
{
- var DapThread = deviceService.DeviceThreads.Where(x => x.Device.ID == item.DeviceId).FirstOrDefault();
+ var DapThread = deviceService.DeviceThreads.Where(x => x._device.ID == item.DeviceId).FirstOrDefault();
if (DapThread?.DeviceValues != null && DapThread.DeviceValues.ContainsKey(item.ID))
{
item.Value = DapThread.DeviceValues[item.ID].Value?.ToString();
diff --git a/IoTGateway.ViewModel/BasicData/DeviceVariableVMs/DeviceVariableVM.cs b/IoTGateway.ViewModel/BasicData/DeviceVariableVMs/DeviceVariableVM.cs
index c415f7a..66f15a5 100644
--- a/IoTGateway.ViewModel/BasicData/DeviceVariableVMs/DeviceVariableVM.cs
+++ b/IoTGateway.ViewModel/BasicData/DeviceVariableVMs/DeviceVariableVM.cs
@@ -32,7 +32,7 @@ namespace IoTGateway.ViewModel.BasicData.DeviceVariableVMs
{
var deviceService = Wtm.ServiceProvider.GetService(typeof(DeviceService)) as DeviceService;
AllMethods = deviceService.GetDriverMethods(Entity.DeviceId);
- var DapThread = deviceService.DeviceThreads.Where(x => x.Device.ID == Entity.DeviceId).FirstOrDefault();
+ var DapThread = deviceService.DeviceThreads.Where(x => x._device.ID == Entity.DeviceId).FirstOrDefault();
}
}
diff --git a/IoTGateway.ViewModel/BasicData/DriverVMs/DriverVM.cs b/IoTGateway.ViewModel/BasicData/DriverVMs/DriverVM.cs
index 71aeb44..29d7bdb 100644
--- a/IoTGateway.ViewModel/BasicData/DriverVMs/DriverVM.cs
+++ b/IoTGateway.ViewModel/BasicData/DriverVMs/DriverVM.cs
@@ -23,8 +23,8 @@ namespace IoTGateway.ViewModel.BasicData.DriverVMs
public override void DoAdd()
{
- var drvierService = Wtm.ServiceProvider.GetService(typeof(DrvierService)) as DrvierService;
- Entity.AssembleName = drvierService.GetAssembleNameByFileName(Entity.FileName);
+ var DriverService = Wtm.ServiceProvider.GetService(typeof(DriverService)) as DriverService;
+ Entity.AssembleName = DriverService.GetAssembleNameByFileName(Entity.FileName);
if (string.IsNullOrEmpty(Entity.AssembleName))
{
MSD.AddModelError("", "程序集获取失败");
diff --git a/IoTGateway.ViewModel/BasicData/UpdateDevices.cs b/IoTGateway.ViewModel/BasicData/UpdateDevices.cs
index fa08475..770ea26 100644
--- a/IoTGateway.ViewModel/BasicData/UpdateDevices.cs
+++ b/IoTGateway.ViewModel/BasicData/UpdateDevices.cs
@@ -78,7 +78,7 @@ namespace IoTGateway.ViewModel.BasicData
case FromVM.Device:
foreach (var deviceId in Ids)
{
- var device = DC.Set().AsNoTracking().Include(x => x.Parent).Where(x => x.ID == deviceId).Include(x => x.DeviceVariables).Include(x => x.Driver).SingleOrDefault();
+ var device = DC.Set().AsNoTracking().Include(x => x.Parent).Where(x => x.ID == deviceId).Include(x => x.DeviceVariables).Include(x => x.Driver).Include(x=>x.DeviceConfigs).SingleOrDefault();
if (!devices.Where(x => x.ID == device.ID).Any())
devices.Add(device);
}
diff --git a/IoTGateway.ViewModel/Config/SystemConfigVMs/SystemConfigVM.cs b/IoTGateway.ViewModel/Config/SystemConfigVMs/SystemConfigVM.cs
index c5d3e39..125aefc 100644
--- a/IoTGateway.ViewModel/Config/SystemConfigVMs/SystemConfigVM.cs
+++ b/IoTGateway.ViewModel/Config/SystemConfigVMs/SystemConfigVM.cs
@@ -30,7 +30,7 @@ namespace IoTGateway.ViewModel.Config.SystemConfigVMs
{
base.DoEdit(updateAllFields);
var myMqttClient = Wtm.ServiceProvider.GetService(typeof(MyMqttClient)) as MyMqttClient;
- myMqttClient.InitClient();
+ myMqttClient.ConnectAsync();
}
public override void DoDelete()
diff --git a/IoTGateway/Areas/BasicData/Controllers/DeviceController.cs b/IoTGateway/Areas/BasicData/Controllers/DeviceController.cs
index 1807228..c3b83b8 100644
--- a/IoTGateway/Areas/BasicData/Controllers/DeviceController.cs
+++ b/IoTGateway/Areas/BasicData/Controllers/DeviceController.cs
@@ -280,7 +280,29 @@ namespace IoTGateway.Controllers
}
#endregion
+ #region 获取属性
+ [ActionDescription("获取属性")]
+ public ActionResult Attribute()
+ {
+ var vm = Wtm.CreateVM();
+ return PartialView(vm);
+ }
+ [HttpPost]
+ [ActionDescription("获取属性")]
+ public ActionResult Attribute(AttributeVM vm)
+ {
+ if (!ModelState.IsValid)
+ {
+ return PartialView(vm);
+ }
+ else
+ {
+ vm.Request();
+ return FFResult().CloseDialog().RefreshGrid().Alert($"{vm.请求结果}");
+ }
+ }
+ #endregion
public IActionResult GetMethods(Guid? ID)
{
return JsonMore(_DeviceService.GetDriverMethods(ID));
diff --git a/IoTGateway/Areas/BasicData/Views/Device/Attribute.cshtml b/IoTGateway/Areas/BasicData/Views/Device/Attribute.cshtml
new file mode 100644
index 0000000..d9dd76f
--- /dev/null
+++ b/IoTGateway/Areas/BasicData/Views/Device/Attribute.cshtml
@@ -0,0 +1,14 @@
+@model IoTGateway.ViewModel.BasicData.DeviceVMs.AttributeVM
+@inject IStringLocalizer Localizer;
+
+
+
+
+ @Model.设备名称
+
+
+
+
+
+
+
diff --git a/IoTGateway/Areas/BasicData/Views/DeviceConfig/Create.cshtml b/IoTGateway/Areas/BasicData/Views/DeviceConfig/Create.cshtml
index 3683df8..1285497 100644
--- a/IoTGateway/Areas/BasicData/Views/DeviceConfig/Create.cshtml
+++ b/IoTGateway/Areas/BasicData/Views/DeviceConfig/Create.cshtml
@@ -1,10 +1,12 @@
-@model IoTGateway.ViewModel.BasicData.DeviceConfigVMs.DeviceConfigVM
+@using IoTGateway.Model
+@model IoTGateway.ViewModel.BasicData.DeviceConfigVMs.DeviceConfigVM
@inject IStringLocalizer Localizer;
+
diff --git a/IoTGateway/Controllers/HomeController.cs b/IoTGateway/Controllers/HomeController.cs
index 5d8a025..a916b0d 100644
--- a/IoTGateway/Controllers/HomeController.cs
+++ b/IoTGateway/Controllers/HomeController.cs
@@ -53,21 +53,21 @@ namespace IoTGateway.Controllers
data.Add(new ChartData
{
- Value = _deviceService.DeviceThreads.Where(x => !x.Device.AutoStart).Count(),
+ Value = _deviceService.DeviceThreads.Where(x => !x._device.AutoStart).Count(),
Category = "停止",
Series = "Device"
});
data.Add(new ChartData
{
- Value = _deviceService.DeviceThreads.Where(x => x.Device.AutoStart && x.Driver.IsConnected).Count(),
+ Value = _deviceService.DeviceThreads.Where(x => x._device.AutoStart && x._driver.IsConnected).Count(),
Category = "运行",
Series = "Device",
});
data.Add(new ChartData
{
- Value = _deviceService.DeviceThreads.Where(x => x.Device.AutoStart && !x.Driver.IsConnected).Count(),
+ Value = _deviceService.DeviceThreads.Where(x => x._device.AutoStart && !x._driver.IsConnected).Count(),
Category = "异常",
Series = "Device"
});
@@ -78,18 +78,18 @@ namespace IoTGateway.Controllers
public IActionResult GetDeviceVariableChart()
{
var data = new List();
- foreach (var deviceThread in _deviceService.DeviceThreads.OrderBy(x => x.Device.DeviceName))
+ foreach (var deviceThread in _deviceService.DeviceThreads.OrderBy(x => x._device.DeviceName))
{
data.Add(new ChartData
{
- Category = deviceThread.Device.DeviceName,
+ Category = deviceThread._device.DeviceName,
Value = deviceThread.DeviceValues.Where(x => x.Value.StatusType != VaribaleStatusTypeEnum.Good).Count(),
Series = "Others"
});
data.Add(new ChartData
{
- Category = deviceThread.Device.DeviceName,
+ Category = deviceThread._device.DeviceName,
Value = deviceThread.DeviceValues.Where(x => x.Value.StatusType == VaribaleStatusTypeEnum.Good).Count(),
Series = "Good"
});
diff --git a/IoTGateway/Startup.cs b/IoTGateway/Startup.cs
index a25b8f1..59233ae 100644
--- a/IoTGateway/Startup.cs
+++ b/IoTGateway/Startup.cs
@@ -46,18 +46,20 @@ namespace IoTGateway
{
options.UseWtmMvcOptions();
})
- .AddJsonOptions(options => {
+ .AddJsonOptions(options =>
+ {
options.UseWtmJsonOptions();
})
-
+
.ConfigureApiBehaviorOptions(options =>
{
options.UseWtmApiOptions();
})
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
.AddWtmDataAnnotationsLocalization(typeof(Program));
-
- services.AddWtmContext(ConfigRoot, (options)=> {
+
+ services.AddWtmContext(ConfigRoot, (options) =>
+ {
options.DataPrivileges = DataPrivilegeSettings();
options.CsSelector = CSSelector;
options.FileSubDirSelector = SubDirSelector;
@@ -75,7 +77,7 @@ namespace IoTGateway
services.AddHostedService();
services.AddSingleton();
- services.AddSingleton();
+ services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
@@ -137,7 +139,7 @@ namespace IoTGateway
app.UseWtmContext();
-
+
}
///
diff --git a/IoTGateway/appsettings.json b/IoTGateway/appsettings.json
index f0dbb3f..d06446c 100644
--- a/IoTGateway/appsettings.json
+++ b/IoTGateway/appsettings.json
@@ -3,13 +3,13 @@
"Console": {
"IncludeScopes": true,
"LogLevel": {
- "Default": "Error"
+ "Default": "Information"
}
},
"Debug": {
"IncludeScopes": true,
"LogLevel": {
- "Default": "Error"
+ "Default": "Information"
}
},
"WTM": {
diff --git a/IoTGateway/iotgateway.db b/IoTGateway/iotgateway.db
index 1fe8438..f132ff4 100644
Binary files a/IoTGateway/iotgateway.db and b/IoTGateway/iotgateway.db differ
diff --git a/Plugins/Plugin/DeviceService.cs b/Plugins/Plugin/DeviceService.cs
index a03fc6f..62d7f35 100644
--- a/Plugins/Plugin/DeviceService.cs
+++ b/Plugins/Plugin/DeviceService.cs
@@ -16,12 +16,14 @@ using IoTGateway.DataAccess;
using IoTGateway.Model;
using DynamicExpresso;
using MQTTnet.Server;
+using Microsoft.Extensions.Logging;
namespace Plugin
{
public class DeviceService : IDisposable
{
- public DrvierService _DrvierManager;
+ private readonly ILogger _logger;
+ public DriverService _DrvierManager;
public List DeviceThreads = new List();
private MyMqttClient _MyMqttClient;
@@ -29,9 +31,9 @@ namespace Plugin
private string connnectSetting = IoTBackgroundService.connnectSetting;
private DBTypeEnum DBType = IoTBackgroundService.DBType;
private Interpreter interpreter = new();
-
- public DeviceService(IConfiguration ConfigRoot, DrvierService drvierManager, MyMqttClient myMqttClient, UAService uAService, IMqttServer mqttServer )
+ public DeviceService(IConfiguration ConfigRoot, DriverService drvierManager, MyMqttClient myMqttClient, UAService uAService, IMqttServer mqttServer, ILogger logger)
{
+ _logger = logger;
_DrvierManager = drvierManager;
_MyMqttClient = myMqttClient;
_MqttServer = mqttServer;
@@ -41,6 +43,7 @@ namespace Plugin
using (var DC = new DataContext(connnectSetting, DBType))
{
var Devices = DC.Set().Where(x => x.DeviceTypeEnum == DeviceTypeEnum.Device).Include(x => x.Parent).Include(x => x.Driver).Include(x => x.DeviceConfigs).Include(x => x.DeviceVariables).AsNoTracking().ToList();
+ _logger.LogInformation($"Loaded Devices Count:{Devices.Count()}");
foreach (var Device in Devices)
{
CreateDeviceThread(Device);
@@ -50,6 +53,7 @@ namespace Plugin
catch (Exception ex)
{
+ _logger.LogError($"LoadDevicesError", ex);
}
}
@@ -57,12 +61,14 @@ namespace Plugin
{
try
{
+ _logger.LogInformation($"UpdateDevice Start:{device.DeviceName}");
RemoveDeviceThread(device);
CreateDeviceThread(device);
+ _logger.LogInformation($"UpdateDevice End:{device.DeviceName}");
}
catch (Exception ex)
{
- Console.WriteLine($"{device.DeviceName},更新失败");
+ _logger.LogError($"UpdateDevice Error:{device.DeviceName}", ex);
}
}
@@ -75,13 +81,12 @@ namespace Plugin
public void CreateDeviceThread(Device Device)
{
- using (var DC = new DataContext(connnectSetting, DBType))
+ try
{
- var systemManage = DC.Set().FirstOrDefault();
- if (systemManage == null)
- Console.WriteLine("配置信息错误,无法启动");
- else
+ _logger.LogInformation($"CreateDeviceThread Start:{Device.DeviceName}");
+ using (var DC = new DataContext(connnectSetting, DBType))
{
+ var systemManage = DC.Set().FirstOrDefault();
var driver = _DrvierManager.DriverInfos.Where(x => x.Type.FullName == Device.Driver.AssembleName).SingleOrDefault();
var settings = DC.Set().Where(x => x.DeviceId == Device.ID).AsNoTracking().ToList();
Type[] types = new Type[1] { typeof(Guid) };
@@ -137,10 +142,17 @@ namespace Plugin
p.SetValue(DeviceObj, value);
}
- var deviceThread = new DeviceThread(Device, DeviceObj, systemManage.GatewayName, _MyMqttClient, interpreter, _MqttServer);
+ var deviceThread = new DeviceThread(Device, DeviceObj, systemManage.GatewayName, _MyMqttClient, interpreter, _MqttServer, _logger);
DeviceThreads.Add(deviceThread);
+
}
+ _logger.LogInformation($"CreateDeviceThread End:{Device.DeviceName}");
+ }
+ catch (Exception ex)
+ {
+ _logger.LogInformation($"CreateDeviceThread Error:{Device.DeviceName}", ex);
+
}
}
@@ -155,7 +167,7 @@ namespace Plugin
{
if (Device != null)
{
- var DeviceThread = DeviceThreads.Where(x => x.Device.ID == Device.ID).FirstOrDefault();
+ var DeviceThread = DeviceThreads.Where(x => x._device.ID == Device.ID).FirstOrDefault();
if (DeviceThread != null)
{
DeviceThread.StopThread();
@@ -174,21 +186,32 @@ namespace Plugin
public List GetDriverMethods(Guid? DeviceId)
{
List driverFilesComboSelect = new List();
- foreach (var method in DeviceThreads.Where(x => x.Device.ID == DeviceId).FirstOrDefault()?.Methods)
+ try
{
- var Attribute = method.CustomAttributes.ToList().FirstOrDefault().ConstructorArguments;
- var item = new ComboSelectListItem
+ _logger.LogInformation($"GetDriverMethods Start:{DeviceId}");
+ foreach (var method in DeviceThreads.Where(x => x._device.ID == DeviceId).FirstOrDefault()?.Methods)
{
- Text = method.Name,
- Value = method.Name,
- };
- driverFilesComboSelect.Add(item);
+ var Attribute = method.CustomAttributes.ToList().FirstOrDefault().ConstructorArguments;
+ var item = new ComboSelectListItem
+ {
+ Text = method.Name,
+ Value = method.Name,
+ };
+ driverFilesComboSelect.Add(item);
+ }
+ _logger.LogInformation($"GetDriverMethods End:{DeviceId}");
}
+ catch (Exception ex)
+ {
+
+ _logger.LogInformation($"GetDriverMethods Error:{DeviceId}");
+ }
+
return driverFilesComboSelect;
}
public void Dispose()
{
- int t = 0;
+ _logger.LogInformation("Dispose");
}
public Task StartAsync(CancellationToken cancellationToken)
diff --git a/Plugins/Plugin/DeviceThread.cs b/Plugins/Plugin/DeviceThread.cs
index 76e6cb6..f921ce2 100644
--- a/Plugins/Plugin/DeviceThread.cs
+++ b/Plugins/Plugin/DeviceThread.cs
@@ -12,13 +12,15 @@ using WalkingTec.Mvvm.Core;
using DynamicExpresso;
using MQTTnet.Server;
using Newtonsoft.Json;
+using Microsoft.Extensions.Logging;
namespace Plugin
{
public class DeviceThread : IDisposable
{
- public Device Device { get; set; }
- public IDriver Driver { get; set; }
+ private readonly ILogger _logger;
+ public readonly Device _device;
+ public readonly IDriver _driver;
public Dictionary DeviceValues { get; set; } = new();
internal List Methods { get; set; }
private Task task { get; set; } = null;
@@ -26,140 +28,141 @@ namespace Plugin
private CancellationTokenSource tokenSource = new CancellationTokenSource();
private Interpreter Interpreter = null;
- public DeviceThread(Device device, IDriver driver, string ProjectId, MyMqttClient myMqttClient, Interpreter interpreter, IMqttServer mqttServer)
+ public DeviceThread(Device device, IDriver driver, string ProjectId, MyMqttClient myMqttClient, Interpreter interpreter, IMqttServer mqttServer, ILogger logger)
{
- Device = device;
- Driver = driver;
+ _device = device;
+ _driver = driver;
Interpreter = interpreter;
- Methods = Driver.GetType().GetMethods().Where(x => x.GetCustomAttribute(typeof(MethodAttribute)) != null).ToList();
- if (Device.AutoStart)
+ _logger = logger;
+ Methods = _driver.GetType().GetMethods().Where(x => x.GetCustomAttribute(typeof(MethodAttribute)) != null).ToList();
+ if (_device.AutoStart)
{
- Console.WriteLine($"采集线程已启动:{Device.DeviceName}");
+ _logger.LogInformation($"线程已启动:{_device.DeviceName}");
using (var DC = new DataContext(IoTBackgroundService.connnectSetting, IoTBackgroundService.DBType))
{
- if (Device.DeviceVariables != null)
+ if (_device.DeviceVariables != null)
{
- foreach (var item in Device.DeviceVariables)
+ foreach (var item in _device.DeviceVariables)
{
DeviceValues[item.ID] = new() { StatusType = VaribaleStatusTypeEnum.Bad };
}
}
}
+ myMqttClient.UploadAttributeAsync(device.DeviceName, device.DeviceConfigs.Where(x => x.DataSide == DataSide.ClientSide).ToDictionary(x => x.DeviceConfigName, x => x.Value));
+
task = Task.Run(() =>
- {
- while (true)
- {
- if (tokenSource.IsCancellationRequested)
- {
- Console.WriteLine($"{Device.DeviceName},停止线程");
- return;
- }
+ {
+ while (true)
+ {
+ if (tokenSource.IsCancellationRequested)
+ {
+ _logger.LogInformation($"停止线程:{_device.DeviceName}");
+ return;
+ }
- try
- {
- Dictionary> sendModel = new() { { Device.DeviceName, new() } };
+ try
+ {
+ Dictionary> sendModel = new() { { _device.DeviceName, new() } };
- var payLoad = new PayLoad() { Values = new() };
- if (false)//Device.DeviceConfigs != null 配置数据先不上传
- foreach (var DeviceConfig in Device.DeviceConfigs)
- payLoad.Values[DeviceConfig.DeviceConfigName] = DeviceConfig.Value;
+ var payLoad = new PayLoad() { Values = new() };
- if (driver.IsConnected)
- {
- if (Device.DeviceVariables != null)
- {
- foreach (var item in Device.DeviceVariables)
- {
- var ret = new DriverReturnValueModel();
- var ioarg = new DriverAddressIoArgModel
- {
- ID = item.ID,
- Address = item.DeviceAddress,
- ValueType = item.DataType
- };
- var method = Methods.Where(x => x.Name == item.Method).FirstOrDefault();
- if (method == null)
- ret.StatusType = VaribaleStatusTypeEnum.MethodError;
- else
- ret = (DriverReturnValueModel)method.Invoke(Driver, new object[1] { ioarg });
+ if (driver.IsConnected)
+ {
+ if (_device.DeviceVariables != null)
+ {
+ foreach (var item in _device.DeviceVariables)
+ {
+ var ret = new DriverReturnValueModel();
+ var ioarg = new DriverAddressIoArgModel
+ {
+ ID = item.ID,
+ Address = item.DeviceAddress,
+ ValueType = item.DataType
+ };
+ var method = Methods.Where(x => x.Name == item.Method).FirstOrDefault();
+ if (method == null)
+ ret.StatusType = VaribaleStatusTypeEnum.MethodError;
+ else
+ ret = (DriverReturnValueModel)method.Invoke(_driver, new object[1] { ioarg });
- if (ret.StatusType == VaribaleStatusTypeEnum.Good && !string.IsNullOrWhiteSpace(item.Expressions?.Trim()))
- {
- try
- {
- ret.CookedValue = interpreter.Eval(DealMysqlStr(item.Expressions).Replace("raw", ret.Value?.ToString()));
- }
- catch (Exception)
- {
- ret.StatusType = VaribaleStatusTypeEnum.ExpressionError;
- }
- }
- else
- ret.CookedValue = ret.Value;
+ if (ret.StatusType == VaribaleStatusTypeEnum.Good && !string.IsNullOrWhiteSpace(item.Expressions?.Trim()))
+ {
+ try
+ {
+ ret.CookedValue = interpreter.Eval(DealMysqlStr(item.Expressions).Replace("raw", ret.Value?.ToString()));
+ }
+ catch (Exception)
+ {
+ ret.StatusType = VaribaleStatusTypeEnum.ExpressionError;
+ }
+ }
+ else
+ ret.CookedValue = ret.Value;
- payLoad.Values[item.Name] = ret.CookedValue;
+ payLoad.Values[item.Name] = ret.CookedValue;
- ret.VarId = item.ID;
+ ret.VarId = item.ID;
- //变化了才推送到mqttserver,用于前端展示
- if (DeviceValues[item.ID].StatusType != ret.StatusType || DeviceValues[item.ID].Value?.ToString() != ret.Value?.ToString() || DeviceValues[item.ID].CookedValue?.ToString() != ret.CookedValue?.ToString())
- {
- //这是设备变量列表要用的
- mqttServer.PublishAsync($"internal/v1/gateway/telemetry/{Device.DeviceName}/{item.Name}", JsonConvert.SerializeObject(ret));
- //这是在线组态要用的
- mqttServer.PublishAsync($"v1/gateway/telemetry/{Device.DeviceName}/{item.Name}", JsonConvert.SerializeObject(ret.CookedValue));
- }
+ //变化了才推送到mqttserver,用于前端展示
+ if (DeviceValues[item.ID].StatusType != ret.StatusType || DeviceValues[item.ID].Value?.ToString() != ret.Value?.ToString() || DeviceValues[item.ID].CookedValue?.ToString() != ret.CookedValue?.ToString())
+ {
+ //这是设备变量列表要用的
+ mqttServer.PublishAsync($"internal/v1/gateway/telemetry/{_device.DeviceName}/{item.Name}", JsonConvert.SerializeObject(ret));
+ //这是在线组态要用的
+ mqttServer.PublishAsync($"v1/gateway/telemetry/{_device.DeviceName}/{item.Name}", JsonConvert.SerializeObject(ret.CookedValue));
+ }
- DeviceValues[item.ID] = ret;
+ DeviceValues[item.ID] = ret;
- }
- payLoad.TS = (long)(DateTime.Now - TsStartDt).TotalMilliseconds;
+ }
+ payLoad.TS = (long)(DateTime.Now - TsStartDt).TotalMilliseconds;
- if (DeviceValues.Any(x => x.Value.Value ==null))
- {
- payLoad.Values = null;
- payLoad.DeviceStatus = DeviceStatusTypeEnum.Bad;
- }
- else
- {
- payLoad.DeviceStatus = DeviceStatusTypeEnum.Good;
- sendModel[Device.DeviceName] = new List { payLoad };
- myMqttClient.Publish(Device,sendModel);
- }
- }
+ if (DeviceValues.Any(x => x.Value.Value == null))
+ {
+ payLoad.Values = null;
+ payLoad.DeviceStatus = DeviceStatusTypeEnum.Bad;
+ }
+ else
+ {
+ payLoad.DeviceStatus = DeviceStatusTypeEnum.Good;
+ sendModel[_device.DeviceName] = new List { payLoad };
+ myMqttClient.PublishTelemetry(_device, sendModel);
+ }
+ }
- }
- else
- {
- driver.Connect();
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine($"线程循环异常,{Device.DeviceName},{ex}");
- }
+ }
+ else
+ {
+ driver.Connect();
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError($"线程循环异常,{_device.DeviceName}", ex);
+ }
- Thread.Sleep((int)Driver.MinPeriod);
- }
- });
+ Thread.Sleep((int)_driver.MinPeriod);
+ }
+ });
}
}
public void StopThread()
{
+ _logger.LogInformation($"线程停止:{_device.DeviceName}");
if (task != null)
{
- Driver.Close();
+ _driver.Close();
tokenSource.Cancel();
}
}
public void Dispose()
{
- Driver.Dispose();
- Console.WriteLine($"{Device.DeviceName},释放");
+ _driver.Dispose();
+ _logger.LogInformation($"线程释放,{_device.DeviceName}");
}
//mysql会把一些符号转义,没找到原因,先临时处理下
diff --git a/Plugins/Plugin/DrvierService.cs b/Plugins/Plugin/DrvierService.cs
index fcaa65f..bf0dec9 100644
--- a/Plugins/Plugin/DrvierService.cs
+++ b/Plugins/Plugin/DrvierService.cs
@@ -11,23 +11,28 @@ using System.Threading.Tasks;
using WalkingTec.Mvvm.Core;
using IoTGateway.DataAccess;
using IoTGateway.Model;
+using Microsoft.Extensions.Logging;
namespace Plugin
{
- public class DrvierService//: IDependency
+ public class DriverService//: IDependency
{
+ private readonly ILogger _logger;
string DriverPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"drivers/net6.0");
string[] driverFiles;
public List DriverInfos = new List();
- public DrvierService(IConfiguration ConfigRoot)
+ public DriverService(IConfiguration ConfigRoot, ILogger logger)
{
+ _logger = logger;
try
{
- driverFiles = Directory.GetFiles(DriverPath).Where(x => Path.GetExtension(x) == ".dll").ToArray();
+ _logger.LogInformation("LoadDriverFiles Start");
+ driverFiles = Directory.GetFiles(DriverPath).Where(x => Path.GetExtension(x) == ".dll").ToArray();
+ _logger.LogInformation($"LoadDriverFiles End,Count{driverFiles.Count()}");
}
- catch (Exception)
+ catch (Exception ex)
{
-
+ _logger.LogError("LoadDriverFiles Error", ex);
}
LoadAllDrivers();
}
@@ -91,6 +96,7 @@ namespace Plugin
ID = Guid.NewGuid(),
DeviceId = dapID,
DeviceConfigName = property.Name,
+ DataSide= DataSide.AnySide,
Description = ((ConfigParameterAttribute)config).Description,
Value = property.GetValue(iObj)?.ToString()
};
@@ -112,6 +118,7 @@ namespace Plugin
{
try
{
+ _logger.LogInformation("LoadAllDrivers Start");
foreach (var file in driverFiles)
{
var dll = Assembly.LoadFrom(file);
@@ -125,10 +132,11 @@ namespace Plugin
DriverInfos.Add(driverInfo);
}
}
+ _logger.LogInformation($"LoadAllDrivers End,Count{DriverInfos.Count}");
}
catch (Exception ex)
{
- Console.WriteLine("驱动加载失败,一般是驱动项目引用的nuget或dll没有复制到驱动文件夹");
+ _logger.LogError("LoadAllDrivers Error,一般是驱动项目引用的nuget或dll没有复制到驱动文件夹", ex);
}
}
diff --git a/Plugins/Plugin/ModbusSlaveService.cs b/Plugins/Plugin/ModbusSlaveService.cs
index 41479ff..8944e62 100644
--- a/Plugins/Plugin/ModbusSlaveService.cs
+++ b/Plugins/Plugin/ModbusSlaveService.cs
@@ -1,4 +1,5 @@
-using Modbus.Data;
+using Microsoft.Extensions.Logging;
+using Modbus.Data;
using Modbus.Device;
using System;
using System.Collections.Generic;
@@ -12,13 +13,15 @@ namespace Plugin
{
public class ModbusSlaveService : IDisposable
{
+ private readonly ILogger _logger;
TcpListener slaveTcpListener;
private Timer m_simulationTimer;
private object Lock=new object();
private ModbusSlave slave;
private Task task { get; set; } = null;
- public ModbusSlaveService()
+ public ModbusSlaveService(ILogger logger)
{
+ _logger = logger;
byte slaveId = 1;
int port = 503;
IPAddress address = IPAddress.Any;
@@ -30,6 +33,7 @@ namespace Plugin
slave.DataStore = DataStoreFactory.CreateDefaultDataStore();
slave.ListenAsync();
m_simulationTimer = new Timer(DoSimulation, null, 1000, 1000);
+ _logger.LogInformation($"Modbus Server Started");
}
private void DoSimulation(object state)
@@ -53,11 +57,12 @@ namespace Plugin
}
catch (Exception ex)
{
- Console.WriteLine($"modbus模拟数据失败了,{ex}");
+ _logger.LogError($"Modbus Server Error", ex);
}
}
public void Dispose()
{
+ _logger.LogError($"Modbus Server Dispose");
m_simulationTimer.Dispose();
slaveTcpListener.Stop();
}
diff --git a/Plugins/Plugin/MyMqttClient.cs b/Plugins/Plugin/MyMqttClient.cs
index fe1b897..1bb38c0 100644
--- a/Plugins/Plugin/MyMqttClient.cs
+++ b/Plugins/Plugin/MyMqttClient.cs
@@ -1,91 +1,221 @@
-using Microsoft.Extensions.Configuration;
+using IoTGateway.DataAccess;
+using IoTGateway.Model;
+using Microsoft.Extensions.Logging;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Disconnecting;
using MQTTnet.Client.Options;
using MQTTnet.Client.Receiving;
-using System;
+using MQTTnet.Protocol;
using Newtonsoft.Json;
-using WalkingTec.Mvvm.Core;
-using System.Collections.Generic;
-using IoTGateway.DataAccess;
-using IoTGateway.Model;
-using System.Linq;
using PluginInterface;
-using Microsoft.Extensions.DependencyInjection;
using Quickstarts.ReferenceServer;
-using Opc.Ua;
namespace Plugin
{
- public class MyMqttClient//: IDependency
+ public class MyMqttClient
{
- private IMqttClient _mqttClient = null;
- private ReferenceNodeManager _uaNodeManager = null;
- private MqttClientOptionsBuilder builder = null;
- private SystemConfig systemConfig = null;
- public MyMqttClient(UAService uaService)
+ private readonly ILogger _logger;
+ private readonly ReferenceNodeManager _uaNodeManager = null;
+
+ private SystemConfig? _systemConfig;
+ private IMqttClientOptions clientOptions;
+ public bool IsConnected => (Client?.IsConnected).GetValueOrDefault();
+ private IMqttClient Client { get; set; }
+ public event EventHandler OnExcRpc;
+ public event EventHandler OnReceiveAttributes;
+ public MyMqttClient(UAService uaService, ILogger logger)
{
+ _logger = logger;
_uaNodeManager = uaService.server.m_server.nodeManagers[0] as ReferenceNodeManager;
- InitClient();
+ ConnectAsync();
}
- public void InitClient()
+
+ public async Task ConnectAsync()
+ {
+ bool initok = false;
+ try
+ {
+ using (var DC = new DataContext(IoTBackgroundService.connnectSetting, IoTBackgroundService.DBType))
+ {
+ _systemConfig = DC.Set().FirstOrDefault();
+ if (_systemConfig == null)
+ {
+ _systemConfig = new SystemConfig()
+ {
+ ID = Guid.NewGuid(),
+ GatewayName = "iotgateway",
+ MqttIp = "localhost",
+ MqttPort = 1888,
+ MqttUName = "user",
+ MqttUPwd = "pwd",
+ IoTPlatformType = IoTPlatformType.IoTSharp
+ };
+ DC.Set().Add(_systemConfig);
+ DC.SaveChanges();
+ }
+ var factory = new MqttFactory();
+ Client = (MqttClient)factory.CreateMqttClient();
+ clientOptions = new MqttClientOptionsBuilder()
+ .WithClientId(_systemConfig.GatewayName + Guid.NewGuid().ToString())
+ .WithTcpServer(_systemConfig.MqttIp, _systemConfig.MqttPort)
+ .WithCredentials(_systemConfig.MqttUName, _systemConfig.MqttUPwd)
+ .WithCommunicationTimeout(TimeSpan.FromSeconds(30))
+ .WithKeepAlivePeriod(TimeSpan.FromSeconds(20))
+ .Build();
+
+ Client.ApplicationMessageReceivedHandler = new MqttApplicationMessageReceivedHandlerDelegate(Client_ApplicationMessageReceived);
+ Client.ConnectedHandler = new MqttClientConnectedHandlerDelegate(x => OnConnected());
+ Client.DisconnectedHandler = new MqttClientDisconnectedHandlerDelegate(x => OnDisconnectedAsync());
+ try
+ {
+ Client.ConnectAsync(clientOptions);
+ initok = true;
+ }
+ catch (Exception exception)
+ {
+ _logger.LogError("MQTT CONNECTING FAILED", exception);
+ }
+ _logger.LogInformation("MQTT WAITING FOR APPLICATION MESSAGES");
+ }
+ }
+ catch (Exception exception)
+ {
+ _logger.LogError("MQTT CONNECTING FAILED", exception);
+ }
+ return initok;
+ }
+
+ private async Task OnDisconnectedAsync()
{
try
{
- if (_mqttClient != null)
- _mqttClient.Dispose();
+ await Client.ConnectAsync(clientOptions);
+ }
+ catch (Exception exception)
+ {
+ _logger.LogError("MQTT CONNECTING FAILED", exception);
+ }
+ }
- using (var DC = new DataContext(IoTBackgroundService.connnectSetting, IoTBackgroundService.DBType))
+ private void OnConnected()
+ {
+ Client.SubscribeAsync($"devices/+/rpc/request/+/+", MqttQualityOfServiceLevel.ExactlyOnce);
+ Client.SubscribeAsync($"devices/Modbus/attributes/update/", MqttQualityOfServiceLevel.ExactlyOnce);
+ Client.SubscribeAsync($"devices/+/attributes/response/+", MqttQualityOfServiceLevel.ExactlyOnce);
+ _logger.LogInformation($"MQTT CONNECTED WITH SERVER ");
+ }
+
+ private Task Client_ApplicationMessageReceived(MqttApplicationMessageReceivedEventArgs e)
+ {
+ _logger.LogDebug($"ApplicationMessageReceived Topic {e.ApplicationMessage.Topic} QualityOfServiceLevel:{e.ApplicationMessage.QualityOfServiceLevel} Retain:{e.ApplicationMessage.Retain} ");
+ try
+ {
+ if (e.ApplicationMessage.Topic.StartsWith($"devices/") && e.ApplicationMessage.Topic.Contains("/response/"))
{
- systemConfig = DC.Set().FirstOrDefault();
- if (systemConfig == null)
- Console.WriteLine("配置信息错误,无法启动");
- else
+ ReceiveAttributes(e);
+ }
+ else if (e.ApplicationMessage.Topic.StartsWith($"devices/") && e.ApplicationMessage.Topic.Contains("/rpc/request/"))
+ {
+ var tps = e.ApplicationMessage.Topic.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
+ var rpcmethodname = tps[4];
+ var rpcdevicename = tps[1];
+ var rpcrequestid = tps[5];
+ _logger.LogInformation($"rpcmethodname={rpcmethodname} ");
+ _logger.LogInformation($"rpcdevicename={rpcdevicename } ");
+ _logger.LogInformation($"rpcrequestid={rpcrequestid} ");
+ if (!string.IsNullOrEmpty(rpcmethodname) && !string.IsNullOrEmpty(rpcdevicename) && !string.IsNullOrEmpty(rpcrequestid))
{
- _mqttClient = new MqttFactory().CreateMqttClient();
- _mqttClient.ConnectedHandler = new MqttClientConnectedHandlerDelegate(x => OnConnected());
- _mqttClient.DisconnectedHandler = new MqttClientDisconnectedHandlerDelegate(x => OnDisconnected());
- _mqttClient.ApplicationMessageReceivedHandler = new MqttApplicationMessageReceivedHandlerDelegate(OnReceived);
- builder = new MqttClientOptionsBuilder()
- .WithCommunicationTimeout(TimeSpan.FromSeconds(60))
- .WithKeepAlivePeriod(TimeSpan.FromSeconds(20))
- .WithTcpServer(systemConfig.MqttIp, systemConfig.MqttPort)
- .WithClientId(systemConfig.MqttUName + Guid.NewGuid().ToString())
- .WithCredentials(systemConfig.MqttUName, systemConfig.MqttUPwd);
-
- _mqttClient.ConnectAsync(builder.Build());
+ OnExcRpc?.Invoke(Client, new RpcRequest()
+ {
+ Method = rpcmethodname,
+ DeviceId = rpcdevicename,
+ RequestId = rpcrequestid,
+ Params = e.ApplicationMessage.ConvertPayloadToString()
+ });
}
}
}
catch (Exception ex)
{
-
+ _logger.LogError($"ClientId:{e.ClientId} Topic:{e.ApplicationMessage.Topic},Payload:{e.ApplicationMessage.ConvertPayloadToString()}", ex);
}
-
+ return Task.CompletedTask;
}
- public void Publish(Device device, Dictionary> SendModel)
+ private void ReceiveAttributes(MqttApplicationMessageReceivedEventArgs e)
+ {
+ var tps = e.ApplicationMessage.Topic.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
+ var rpcmethodname = tps[2];
+ var rpcdevicename = tps[1];
+ var rpcrequestid = tps[4];
+ _logger.LogInformation($"rpcmethodname={rpcmethodname} ");
+ _logger.LogInformation($"rpcdevicename={rpcdevicename } ");
+ _logger.LogInformation($"rpcrequestid={rpcrequestid} ");
+
+ if (!string.IsNullOrEmpty(rpcmethodname) && !string.IsNullOrEmpty(rpcdevicename) && !string.IsNullOrEmpty(rpcrequestid))
+ {
+ if (e.ApplicationMessage.Topic.Contains("/attributes/"))
+ {
+ OnReceiveAttributes?.Invoke(Client, new AttributeResponse()
+ {
+ KeyName = rpcmethodname,
+ DeviceName = rpcdevicename,
+ Id = rpcrequestid,
+ Data = e.ApplicationMessage.ConvertPayloadToString()
+ });
+ }
+ }
+ }
+
+ public Task UploadAttributeAsync(string _devicename, object obj)
+ {
+ return Client.PublishAsync(new MqttApplicationMessageBuilder().WithTopic($"devices/{_devicename}/attributes").WithPayload(Newtonsoft.Json.JsonConvert.SerializeObject(obj)).Build());
+ }
+
+ public Task UploadTelemetryDataAsync(string _devicename, object obj)
+ {
+ return Client.PublishAsync(new MqttApplicationMessageBuilder().WithTopic($"devices/{_devicename}/telemetry").WithPayload(Newtonsoft.Json.JsonConvert.SerializeObject(obj)).Build());
+ }
+
+ public Task ResponseExecommand(RpcResponse rpcResult)
+ {
+ ///IoTSharp/Clients/RpcClient.cs#L65 var responseTopic = $"/devices/{deviceid}/rpc/response/{methodName}/{rpcid}";
+ string topic = $"devices/{rpcResult.DeviceId}/rpc/response/{rpcResult.Method.ToString()}/{rpcResult.ResponseId}";
+ return Client.PublishAsync(new MqttApplicationMessageBuilder().WithTopic(topic).WithPayload(rpcResult.Data.ToString()).WithQualityOfServiceLevel(MqttQualityOfServiceLevel.ExactlyOnce).Build());
+ }
+
+ public Task RequestAttributes(string _device, bool anySide, params string[] args)
+ {
+ string id = Guid.NewGuid().ToString();
+ string topic = $"devices/{_device}/attributes/request/{id}";
+ Dictionary keys = new Dictionary();
+ keys.Add(anySide ? "anySide" : "server", string.Join(",", args));
+ Client.SubscribeAsync($"devices/{_device}/attributes/response/{id}", MqttQualityOfServiceLevel.ExactlyOnce);
+ return Client.PublishAsync(topic, Newtonsoft.Json.JsonConvert.SerializeObject(keys), MqttQualityOfServiceLevel.ExactlyOnce);
+ }
+
+ public void PublishTelemetry(Device device, Dictionary> SendModel)
{
try
{
- switch (systemConfig.IoTPlatformType)
+ switch (_systemConfig.IoTPlatformType)
{
case IoTPlatformType.ThingsBoard:
- _mqttClient.PublishAsync("v1/gateway/telemetry", JsonConvert.SerializeObject(SendModel));
+ Client.PublishAsync("v1/gateway/telemetry", JsonConvert.SerializeObject(SendModel));
break;
case IoTPlatformType.IoTSharp:
foreach (var payload in SendModel[device.DeviceName])
{
- _mqttClient.PublishAsync($"devices/{device.DeviceName}/telemetry", JsonConvert.SerializeObject(payload.Values));
+ UploadTelemetryDataAsync(device.DeviceName, payload.Values);
}
break;
case IoTPlatformType.AliCloudIoT:
case IoTPlatformType.TencentIoTHub:
case IoTPlatformType.BaiduIoTCore:
case IoTPlatformType.OneNET:
- default:
+ default:
break;
}
foreach (var payload in SendModel[device.DeviceName])
@@ -93,7 +223,7 @@ namespace Plugin
foreach (var kv in payload.Values)
{
//更新到UAService
- _uaNodeManager?.UpdateNode($"{device.Parent.DeviceName}.{device.DeviceName}.{kv.Key}", kv.Value);
+ _uaNodeManager.UpdateNode($"{device.Parent.DeviceName}.{device.DeviceName}.{kv.Key}", kv.Value);
}
}
@@ -106,27 +236,27 @@ namespace Plugin
}
- private void Update2UAService()
- {
- int i = 0;
- }
+ }
+ public class RpcRequest
+ {
+ public string DeviceId { get; set; }
+ public string Method { get; set; }
+ public string RequestId { get; set; }
+ public string Params { get; set; }
+ }
+ public class RpcResponse
+ {
+ public string DeviceId { get; set; }
+ public string Method { get; set; }
+ public string ResponseId { get; set; }
+ public string Data { get; set; }
+ }
+ public class AttributeResponse
+ {
+ public string Id { get; set; }
+ public string DeviceName { get; set; }
+ public string KeyName { get; set; }
- private void OnReceived(MqttApplicationMessageReceivedEventArgs obj)
- {
- var topic = obj.ApplicationMessage.Topic;
- var msg = System.Text.Encoding.UTF8.GetString(obj.ApplicationMessage.Payload);
- Console.WriteLine($"{topic}: {msg}");
- }
-
- private void OnDisconnected()
- {
- Console.WriteLine("Mqtt连接断开");
- _mqttClient.ConnectAsync(builder.Build());
- }
-
- private void OnConnected()
- {
- Console.WriteLine("Mqtt连接正常");
- }
+ public string Data { get; set; }
}
}