mirror of
				https://gitee.com/ThingsGateway/ThingsGateway.git
				synced 2025-11-04 17:43:58 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			321 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			321 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
#region copyright
 | 
						||
//------------------------------------------------------------------------------
 | 
						||
//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
						||
//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
						||
//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
						||
//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
						||
//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
						||
//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
						||
//  QQ群:605534569
 | 
						||
//------------------------------------------------------------------------------
 | 
						||
#endregion
 | 
						||
 | 
						||
using Microsoft.AspNetCore.Components;
 | 
						||
 | 
						||
using Opc.Ua;
 | 
						||
 | 
						||
using System.Collections.Generic;
 | 
						||
using System.Linq;
 | 
						||
using System.Reflection;
 | 
						||
 | 
						||
using ThingsGateway.Foundation.Adapter.OPCUA;
 | 
						||
using ThingsGateway.Foundation.Extension;
 | 
						||
 | 
						||
#if Plugin
 | 
						||
using ThingsGateway.Plugin.OPCUA;
 | 
						||
#endif
 | 
						||
namespace ThingsGateway.Foundation.Demo;
 | 
						||
 | 
						||
/// <summary>
 | 
						||
/// 导入变量
 | 
						||
/// </summary>
 | 
						||
public partial class OPCUAImportVariable
 | 
						||
{
 | 
						||
    private List<ReferenceDescription> actived = new();
 | 
						||
 | 
						||
    private OPCNodeAttribute[] nodeAttributes;
 | 
						||
 | 
						||
    private List<OPCUATagModel> Nodes = new();
 | 
						||
 | 
						||
    private bool overlay = true;
 | 
						||
    /// <summary>
 | 
						||
    /// opc对象
 | 
						||
    /// </summary>
 | 
						||
    [Parameter]
 | 
						||
    public ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient PLC { get; set; }
 | 
						||
    /// <summary>
 | 
						||
    /// 是否显示子变量
 | 
						||
    /// </summary>
 | 
						||
    [Parameter]
 | 
						||
    public bool IsShowSubvariable { get; set; }
 | 
						||
 | 
						||
    private List<ReferenceDescription> Actived
 | 
						||
    {
 | 
						||
        get => actived;
 | 
						||
        set
 | 
						||
        {
 | 
						||
            if (actived?.FirstOrDefault() != value?.FirstOrDefault() && value?.Count > 0)
 | 
						||
            {
 | 
						||
                actived = value;
 | 
						||
                if (actived.FirstOrDefault().NodeId != null)
 | 
						||
                    nodeAttributes = PLC.ReadNoteAttributes(actived.FirstOrDefault().NodeId.ToString());
 | 
						||
            }
 | 
						||
 | 
						||
        }
 | 
						||
 | 
						||
    }
 | 
						||
 | 
						||
    private List<ReferenceDescription> Selected { get; set; } = new();
 | 
						||
 | 
						||
#if Plugin
 | 
						||
    /// <summary>
 | 
						||
    /// 获取设备与变量列表
 | 
						||
    /// </summary>
 | 
						||
    /// <returns></returns>
 | 
						||
    public async Task<(CollectDevice, List<DeviceVariable>)> GetImportVariableListAsync()
 | 
						||
    {
 | 
						||
        var device = GetImportDevice();
 | 
						||
        //动态加载子项时,导出内容需要添加手动加载代码
 | 
						||
        foreach (var node in Selected.ToList())
 | 
						||
        {
 | 
						||
            List<OPCUATagModel> nodes = await PopulateBranchAsync((NodeId)node.NodeId, true, IsShowSubvariable);
 | 
						||
            if (nodes.Count > 0)
 | 
						||
            {
 | 
						||
                Selected.AddRange(nodes.SelectMany(a => a.GetAllTags()).Select(a => a.Tag).Where(a => a != null).ToList());
 | 
						||
            }
 | 
						||
        }
 | 
						||
        var data = (await SelectAsync(Selected, async a =>
 | 
						||
        {
 | 
						||
            var nodeClass = (await PLC.ReadNoteAttributeAsync(a.NodeId.ToString(), Attributes.NodeClass)).FirstOrDefault().Value.ToString();
 | 
						||
            if (nodeClass == nameof(NodeClass.Variable))
 | 
						||
            {
 | 
						||
                ProtectTypeEnum level = ProtectTypeEnum.ReadOnly;
 | 
						||
                DataTypeEnum dataTypeEnum = DataTypeEnum.Object;
 | 
						||
                try
 | 
						||
                {
 | 
						||
                    var userAccessLevel = (AccessLevelType)(await PLC.ReadNoteAttributeAsync(a.NodeId.ToString(), Attributes.UserAccessLevel)).FirstOrDefault().Value;
 | 
						||
                    level = (userAccessLevel.HasFlag(AccessLevelType.CurrentRead)) ?
 | 
						||
        userAccessLevel.HasFlag(AccessLevelType.CurrentWrite) ?
 | 
						||
        ProtectTypeEnum.ReadWrite : ProtectTypeEnum.ReadOnly : ProtectTypeEnum.WriteOnly;
 | 
						||
 | 
						||
                    var dataTypeId = (Opc.Ua.NodeId)(await PLC.ReadNoteAttributeAsync(a.NodeId.ToString(), Attributes.DataType)).FirstOrDefault().Value;
 | 
						||
                    var dataType = Opc.Ua.TypeInfo.GetSystemType(dataTypeId, PLC.Session.Factory);
 | 
						||
                    var result = dataType != null && Enum.TryParse<DataTypeEnum>(dataType.Name, out dataTypeEnum);
 | 
						||
                    if (!result)
 | 
						||
                    {
 | 
						||
                        dataTypeEnum = DataTypeEnum.Object;
 | 
						||
                    }
 | 
						||
                }
 | 
						||
                catch
 | 
						||
                {
 | 
						||
 | 
						||
                }
 | 
						||
 | 
						||
                var id = Yitter.IdGenerator.YitIdHelper.NextId();
 | 
						||
 | 
						||
                return new DeviceVariable()
 | 
						||
                {
 | 
						||
                    Name = a.DisplayName.Text + "-" + id,
 | 
						||
                    VariableAddress = a.NodeId.ToString(),
 | 
						||
                    DeviceId = device.Id,
 | 
						||
                    DataTypeEnum = dataTypeEnum,
 | 
						||
                    Id = id,
 | 
						||
                    ProtectTypeEnum = level,
 | 
						||
                    IntervalTime = 1000,
 | 
						||
                    RpcWriteEnable = true,
 | 
						||
                };
 | 
						||
            }
 | 
						||
            else
 | 
						||
            {
 | 
						||
                return null;
 | 
						||
            }
 | 
						||
        })).Where(a => a != null).ToList();
 | 
						||
        return (device, data);
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    /// <inheritdoc/>
 | 
						||
    private CollectDevice GetImportDevice()
 | 
						||
    {
 | 
						||
        var id = Yitter.IdGenerator.YitIdHelper.NextId();
 | 
						||
        var data = new CollectDevice()
 | 
						||
        {
 | 
						||
            Name = PLC.OPCNode.OPCUrl + "-" + id,
 | 
						||
            Id = id,
 | 
						||
            Enable = true,
 | 
						||
            IsLogOut = true,
 | 
						||
            DevicePropertys = new(),
 | 
						||
            PluginId = Furion.App.GetService<DriverPluginService>().GetIdByName(nameof(ThingsGateway.Plugin.OPCUA.OPCUAClient)).ToLong(),
 | 
						||
        };
 | 
						||
 | 
						||
        data.DevicePropertys.Add(new() { PropertyName = nameof(OPCUAClientProperty.OPCURL), Value = PLC.OPCNode.OPCUrl, Description = typeof(OPCUAClientProperty).GetProperty(nameof(OPCUAClientProperty.OPCURL)).GetCustomAttribute<DevicePropertyAttribute>().Description });
 | 
						||
        data.DevicePropertys.Add(new() { PropertyName = nameof(OPCUAClientProperty.UserName), Value = PLC.OPCNode.UserName, Description = typeof(OPCUAClientProperty).GetProperty(nameof(OPCUAClientProperty.UserName)).GetCustomAttribute<DevicePropertyAttribute>().Description });
 | 
						||
        data.DevicePropertys.Add(new() { PropertyName = nameof(OPCUAClientProperty.Password), Value = PLC.OPCNode.Password, Description = typeof(OPCUAClientProperty).GetProperty(nameof(OPCUAClientProperty.Password)).GetCustomAttribute<DevicePropertyAttribute>().Description });
 | 
						||
        data.DevicePropertys.Add(new() { PropertyName = nameof(OPCUAClientProperty.CheckDomain), Value = PLC.OPCNode.CheckDomain.ToString(), Description = typeof(OPCUAClientProperty).GetProperty(nameof(OPCUAClientProperty.CheckDomain)).GetCustomAttribute<DevicePropertyAttribute>().Description });
 | 
						||
        data.DevicePropertys.Add(new() { PropertyName = nameof(OPCUAClientProperty.LoadType), Value = PLC.OPCNode.LoadType.ToString(), Description = typeof(OPCUAClientProperty).GetProperty(nameof(OPCUAClientProperty.LoadType)).GetCustomAttribute<DevicePropertyAttribute>().Description });
 | 
						||
        data.DevicePropertys.Add(new() { PropertyName = nameof(OPCUAClientProperty.IsUseSecurity), Value = PLC.OPCNode.IsUseSecurity.ToString(), Description = typeof(OPCUAClientProperty).GetProperty(nameof(OPCUAClientProperty.IsUseSecurity)).GetCustomAttribute<DevicePropertyAttribute>().Description });
 | 
						||
        data.DevicePropertys.Add(new() { PropertyName = nameof(OPCUAClientProperty.ActiveSubscribe), Value = true.ToString(), Description = typeof(OPCUAClientProperty).GetProperty(nameof(OPCUAClientProperty.ActiveSubscribe)).GetCustomAttribute<DevicePropertyAttribute>().Description });
 | 
						||
        data.DevicePropertys.Add(new() { PropertyName = nameof(OPCUAClientProperty.DeadBand), Value = PLC.OPCNode.DeadBand.ToString(), Description = typeof(OPCUAClientProperty).GetProperty(nameof(OPCUAClientProperty.DeadBand)).GetCustomAttribute<DevicePropertyAttribute>().Description });
 | 
						||
        data.DevicePropertys.Add(new() { PropertyName = nameof(OPCUAClientProperty.GroupSize), Value = PLC.OPCNode.GroupSize.ToString(), Description = typeof(OPCUAClientProperty).GetProperty(nameof(OPCUAClientProperty.GroupSize)).GetCustomAttribute<DevicePropertyAttribute>().Description });
 | 
						||
        data.DevicePropertys.Add(new() { PropertyName = nameof(OPCUAClientProperty.UpdateRate), Value = PLC.OPCNode.UpdateRate.ToString(), Description = typeof(OPCUAClientProperty).GetProperty(nameof(OPCUAClientProperty.UpdateRate)).GetCustomAttribute<DevicePropertyAttribute>().Description });
 | 
						||
        data.DevicePropertys.Add(new() { PropertyName = nameof(OPCUAClientProperty.KeepAliveInterval), Value = PLC.OPCNode.KeepAliveInterval.ToString(), Description = typeof(OPCUAClientProperty).GetProperty(nameof(OPCUAClientProperty.KeepAliveInterval)).GetCustomAttribute<DevicePropertyAttribute>().Description });
 | 
						||
        return data;
 | 
						||
    }
 | 
						||
 | 
						||
#endif
 | 
						||
    /// <summary>
 | 
						||
    /// <inheritdoc/>
 | 
						||
    /// </summary>
 | 
						||
    protected override void OnInitialized()
 | 
						||
    {
 | 
						||
        Task.Run(async () =>
 | 
						||
        {
 | 
						||
            Nodes = await PopulateBranchAsync(ObjectIds.ObjectsFolder, isShowSubvariable: IsShowSubvariable);
 | 
						||
            overlay = false;
 | 
						||
            await InvokeAsync(StateHasChanged);
 | 
						||
        });
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    private async Task<ReferenceDescriptionCollection> GetReferenceDescriptionCollectionAsync(NodeId sourceId)
 | 
						||
    {
 | 
						||
        BrowseDescription nodeToBrowse1 = new()
 | 
						||
        {
 | 
						||
            NodeId = sourceId,
 | 
						||
            BrowseDirection = BrowseDirection.Forward,
 | 
						||
            ReferenceTypeId = ReferenceTypeIds.Aggregates,
 | 
						||
            IncludeSubtypes = true,
 | 
						||
            NodeClassMask = (uint)(NodeClass.Object | NodeClass.Variable | NodeClass.Method | NodeClass.ReferenceType | NodeClass.ObjectType | NodeClass.View | NodeClass.VariableType | NodeClass.DataType),
 | 
						||
            ResultMask = (uint)BrowseResultMask.All
 | 
						||
        };
 | 
						||
 | 
						||
        BrowseDescription nodeToBrowse2 = new()
 | 
						||
        {
 | 
						||
            NodeId = sourceId,
 | 
						||
            BrowseDirection = BrowseDirection.Forward,
 | 
						||
            ReferenceTypeId = ReferenceTypeIds.Organizes,
 | 
						||
            IncludeSubtypes = true,
 | 
						||
            NodeClassMask = (uint)(NodeClass.Object | NodeClass.Variable | NodeClass.Method | NodeClass.View | NodeClass.ReferenceType | NodeClass.ObjectType | NodeClass.VariableType | NodeClass.DataType),
 | 
						||
            ResultMask = (uint)BrowseResultMask.All
 | 
						||
        };
 | 
						||
 | 
						||
        BrowseDescriptionCollection nodesToBrowse = new()
 | 
						||
        {
 | 
						||
            nodeToBrowse1,
 | 
						||
            nodeToBrowse2
 | 
						||
        };
 | 
						||
 | 
						||
        ReferenceDescriptionCollection references = await FormUtils.BrowseAsync(PLC.Session, nodesToBrowse, false);
 | 
						||
        return references;
 | 
						||
    }
 | 
						||
    private async Task PopulateBranchAsync(OPCUATagModel model)
 | 
						||
    {
 | 
						||
        var sourceId = (NodeId)model.Tag.NodeId;
 | 
						||
        model.Nodes = await PopulateBranchAsync(sourceId, isShowSubvariable: IsShowSubvariable);
 | 
						||
    }
 | 
						||
 | 
						||
    private async Task<List<OPCUATagModel>> PopulateBranchAsync(NodeId sourceId, bool isAll = false, bool isShowSubvariable = false)
 | 
						||
    {
 | 
						||
        if (!PLC.Connected)
 | 
						||
        {
 | 
						||
            return new() { new() { Name = "未完成连接", Tag = new(), Nodes = null } };
 | 
						||
        }
 | 
						||
        List<OPCUATagModel> nodes = new()
 | 
						||
        {
 | 
						||
            new OPCUATagModel() { Name = "Browsering..." }
 | 
						||
        };
 | 
						||
 | 
						||
        ReferenceDescriptionCollection references = await GetReferenceDescriptionCollectionAsync(sourceId);
 | 
						||
        List<OPCUATagModel> list = new();
 | 
						||
        if (references != null)
 | 
						||
        {
 | 
						||
            for (int ii = 0; ii < references.Count; ii++)
 | 
						||
            {
 | 
						||
                ReferenceDescription target = references[ii];
 | 
						||
                OPCUATagModel child = new()
 | 
						||
                {
 | 
						||
                    Name = Utils.Format("{0}", target),
 | 
						||
                    Tag = target
 | 
						||
                };
 | 
						||
                if (isShowSubvariable || target.NodeClass != NodeClass.Variable)
 | 
						||
                {
 | 
						||
                    var data = await GetReferenceDescriptionCollectionAsync((NodeId)target.NodeId);
 | 
						||
                    if (data != null && data.Count > 0)
 | 
						||
                    {
 | 
						||
                        if (isAll)
 | 
						||
                            child.Nodes = await PopulateBranchAsync((NodeId)target.NodeId, isShowSubvariable: IsShowSubvariable);
 | 
						||
                        else
 | 
						||
                            child.Nodes = new();
 | 
						||
                    }
 | 
						||
                    else
 | 
						||
                    {
 | 
						||
                        child.Nodes = null;
 | 
						||
                    }
 | 
						||
                }
 | 
						||
                else
 | 
						||
                {
 | 
						||
                    child.Nodes = null;
 | 
						||
                }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
                ////if (target.NodeClass != NodeClass.Variable)  //这个判断注释后会让子节点也是变量的情况下无法加载
 | 
						||
                //{
 | 
						||
                //    var data = await GetReferenceDescriptionCollectionAsync((NodeId)target.NodeId);
 | 
						||
                //    if (data != null && data.Count > 0)
 | 
						||
                //    {
 | 
						||
                //        if (isAll)
 | 
						||
                //            child.Nodes = await PopulateBranchAsync((NodeId)target.NodeId);
 | 
						||
                //        else
 | 
						||
                //            child.Nodes = new();
 | 
						||
                //    }
 | 
						||
                //    else
 | 
						||
                //    {
 | 
						||
                //        child.Nodes = null;
 | 
						||
                //    }
 | 
						||
                //}
 | 
						||
                ////else
 | 
						||
                ////{
 | 
						||
                ////    child.Nodes = null;
 | 
						||
                ////}
 | 
						||
                list.Add(child);
 | 
						||
            }
 | 
						||
        }
 | 
						||
 | 
						||
        List<OPCUATagModel> listNode = list;
 | 
						||
 | 
						||
        nodes.Clear();
 | 
						||
        nodes.AddRange(listNode.ToArray());
 | 
						||
        return nodes;
 | 
						||
    }
 | 
						||
 | 
						||
    private Task<TResult[]> SelectAsync<T, TResult>(IEnumerable<T> source, Func<T, Task<TResult>> selector)
 | 
						||
    {
 | 
						||
        return Task.WhenAll(source.Select(selector));
 | 
						||
    }
 | 
						||
    internal class OPCUATagModel
 | 
						||
    {
 | 
						||
        internal string Name { get; set; }
 | 
						||
        internal string NodeId => (Tag.NodeId).ToString();
 | 
						||
        internal List<OPCUATagModel> Nodes { get; set; } = new();
 | 
						||
        internal ReferenceDescription Tag { get; set; }
 | 
						||
 | 
						||
        public List<OPCUATagModel> GetAllTags()
 | 
						||
        {
 | 
						||
            List<OPCUATagModel> allTags = new();
 | 
						||
            GetAllTagsRecursive(this, allTags);
 | 
						||
            return allTags;
 | 
						||
        }
 | 
						||
 | 
						||
        private void GetAllTagsRecursive(OPCUATagModel parentTag, List<OPCUATagModel> allTags)
 | 
						||
        {
 | 
						||
            allTags.Add(parentTag);
 | 
						||
 | 
						||
            if (parentTag.Nodes != null)
 | 
						||
                foreach (OPCUATagModel childTag in parentTag.Nodes)
 | 
						||
                {
 | 
						||
                    GetAllTagsRecursive(childTag, allTags);
 | 
						||
                }
 | 
						||
        }
 | 
						||
    }
 | 
						||
} |