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; } } }