首次提交:本地项目同步到Gitea

This commit is contained in:
zhusenlin
2026-03-06 17:37:42 +08:00
commit 88f7748e9c
27 changed files with 176346 additions and 0 deletions

63
.gitattributes vendored Normal file
View File

@@ -0,0 +1,63 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

459
.gitignore vendored Normal file
View File

@@ -0,0 +1,459 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# Tye
.tye/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
##
## Visual studio for Mac
##
# globs
Makefile.in
*.userprefs
*.usertasks
config.make
config.status
aclocal.m4
install-sh
autom4te.cache/
*.tar.gz
tarballs/
test-results/
# Mac bundle stuff
*.dmg
*.app
# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
# Windows thumbnail cache files
Thumbs.db
ehthumbs.db
ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk
# JetBrains Rider
.idea/
*.sln.iml
##
## Visual Studio Code
##
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
# 保留 Cowain.TestProject/Plugins 文件夹本身(关键:! 表示不忽略)
!Cowain.TestProject/Plugins/
# 忽略 Plugins 文件夹下的所有内容(递归匹配所有文件/子文件夹)
Cowain.TestProject/Plugins/**/*

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) [year] [fullname]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

40
README.md Normal file
View File

@@ -0,0 +1,40 @@
# OPCUA读写复杂结构体示例
## 概述
欢迎使用OPCUA读写结构体示例资源库。本项目旨在为开发者提供一种直观且实用的方法展示如何在OPC UA (Open Platform Communications Unified Architecture)框架下读写复杂的结构体数据。OPC UA是一种工业标准协议用于实现不同系统间的数据交换特别擅长处理和传输结构化的复杂数据。
## 特点
- **示例代码**: 提供了清晰的代码实例演示如何构建和解析包含嵌套结构、数组等复杂数据类型的OPC UA变量。
- **教程性引导**: 通过本示例新手到中级开发者可以快速上手OPC UA中高级特性的应用。
- **跨平台兼容**: 代码设计考虑到了多语言环境主要以C#, Java或Python中的至少一种实现确保广泛的应用场景支持。
- **学习资源**: 包含详细的注释和解释帮助理解OPC UA结构体序列化和反序列化的原理。
## 使用场景
- 工业自动化: 设备状态监控,其中设备参数可能是一个复杂的结构,如温度传感器包含位置信息、精度和实际读数等。
- 数据集成: 当需要将多个不同类型数据整合成统一格式进行交换时,比如能源管理系统。
- IIoT应用: 在物联网环境中,复杂的设备配置或诊断信息传递。
## 快速入门
1. **安装依赖**: 确保你的开发环境已安装必要的OPC UA库。对于不同语言推荐使用官方或社区维护的OPC UA SDK。
2. **获取代码**: 克隆此仓库到本地。
3. **运行示例**: 查阅仓库内的`README`或特定语言文档,找到启动示例应用程序的步骤。
4. **探索与实践**: 阅读代码,尝试修改结构体定义或读写逻辑来适应你的具体需求。
## 注意事项
- 在使用前请确保你对OPC UA的基本概念有所了解包括节点管理、数据模型和安全设置。
- 实际部署中,考虑到生产环境的安全性和稳定性,应仔细测试所有自定义的结构体读写逻辑。
## 贡献与反馈
我们鼓励社区成员参与贡献无论是代码改进、文档补充还是问题报告。请遵守仓库内的贡献指南并通过GitHub Issue进行交流。
加入我们,共同推进工业通信技术的发展,享受高效、安全的数据交换带来的便利!
---
开始您的OPCUA之旅探索如何高效地管理和操作复杂数据结构提升您的应用在现代工业环境下的交互能力。祝您编码愉快

View File

@@ -0,0 +1,25 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31321.278
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleOPCUAClient", "SampleOPCUAClient\SampleOPCUAClient.csproj", "{CE43F3F8-9FC1-4BC9-8947-AF18E536D005}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CE43F3F8-9FC1-4BC9-8947-AF18E536D005}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CE43F3F8-9FC1-4BC9-8947-AF18E536D005}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CE43F3F8-9FC1-4BC9-8947-AF18E536D005}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CE43F3F8-9FC1-4BC9-8947-AF18E536D005}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {92EE55D7-4E9A-4A7E-93AF-39122B7F1396}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,449 @@
[
{
"ItemID": "2",
"ItemName": "焊接时间",
"ItemAdress": "",
"Item_MQTT_Name": "v2",
"ItemLength": "1",
"ItemType": "String",
"IsRead": false,
"IsSave": true,
"UploadMode": "ChangeUpload",
"calculates": [
{
"CalculationRule": "Cloos_Device_Status_Accumulation",
"IsCalculate": true,
"otherItemAdress": "13",
"ConstantValue": "1",
"AccumulationValue": [
"4"
]
}
]
},
{
"ItemID": "3",
"ItemName": "工作时间",
"ItemAdress": "",
"Item_MQTT_Name": "v3",
"ItemLength": "1",
"ItemType": "String",
"IsRead": false,
"IsSave": true,
"UploadMode": "ChangeUpload",
"calculates": [
{
"CalculationRule": "Addition",
"IsCalculate": false,
"otherItemAdress": "2;35",
"ConstantValue": "1"
}
]
},
{
"ItemID": "4",
"ItemName": "焊接效率",
"ItemAdress": "",
"Item_MQTT_Name": "v4",
"ItemLength": "1",
"ItemType": "String",
"IsRead": false,
"IsSave": false,
"UploadMode": "ChangeUpload",
"calculates": [
{
"CalculationRule": "Division",
"IsCalculate": false,
"otherItemAdress": "2;32",
"ConstantValue": "1"
}
]
},
{
"ItemID": "5",
"ItemName": "焊丝消耗",
"ItemAdress": "",
"Item_MQTT_Name": "v5",
"ItemLength": "1",
"ItemType": "String",
"IsRead": false,
"IsSave": true,
"UploadMode": "ChangeUpload",
"calculates": [
{
"CalculationRule": "MaterialConsumption",
"IsCalculate": true,
"otherItemAdress": "50",
"ConstantValue": "1"
}
]
},
{
"ItemID": "6",
"ItemName": "电能消耗",
"ItemAdress": "",
"Item_MQTT_Name": "v6",
"ItemLength": "1",
"ItemType": "String",
"IsRead": false,
"IsSave": true,
"UploadMode": "ChangeUpload",
"calculates": [
{
"CalculationRule": "PowerConsumption",
"IsCalculate": true,
"otherItemAdress": "20;22",
"ConstantValue": "1"
}
]
},
{
"ItemID": "7",
"ItemName": "气体流量源数据",
"ItemAdress": "ns=2;s=DynamicWeldData.GasFlow",
"Item_MQTT_Name": "",
"ItemLength": "1",
"ItemType": "String",
"IsRead": true,
"IsCalculate": false,
"CalculationRule": "NuN",
"otherItemAdress": "",
"ConstantValue": "1"
},
{
"ItemID": "8",
"ItemName": "气体流量",
"ItemAdress": "",
"Item_MQTT_Name": "v7",
"ItemLength": "1",
"ItemType": "String",
"IsRead": false,
"IsSave": false,
"UploadMode": "ChangeUpload",
"calculates": [
{
"CalculationRule": "ArrayAnalysis",
"IsCalculate": false,
"otherItemAdress": "7",
"ConstantValue": "1"
}
]
},
{
"ItemID": "9",
"ItemName": "气体消耗",
"ItemAdress": "",
"Item_MQTT_Name": "v8",
"ItemLength": "1",
"ItemType": "String",
"IsRead": false,
"IsSave": true,
"UploadMode": "ChangeUpload",
"calculates": [
{
"CalculationRule": "MaterialConsumption",
"IsCalculate": true,
"otherItemAdress": "8",
"ConstantValue": "1"
}
]
},
{
"ItemID": "13",
"ItemName": "设备状态",
"ItemAdress": "",
"Item_MQTT_Name": "v12",
"ItemLength": "1",
"ItemType": "String",
"IsRead": false,
"UploadMode": "PeriodicUpload",
"calculates": [
{
"CalculationRule": "Cloos_Device_Status",
"IsCalculate": false,
"otherItemAdress": "51;52;22;20;24",
"ConstantValue": "1"
}
]
},
{
"ItemID": "14",
"ItemName": "控制器序列号",
"ItemAdress": "ns=2;s=GeneralInfo.SerialNumber",
"Item_MQTT_Name": "v13",
"ItemLength": "1",
"ItemType": "String",
"IsRead": true,
"UploadMode": "ChangeUpload"
},
{
"ItemID": "19",
"ItemName": "实际焊接电压源数据",
"ItemAdress": "ns=2;s=DynamicWeldData.Voltage",
"Item_MQTT_Name": "",
"ItemLength": "1",
"ItemType": "String",
"IsRead": true
},
{
"ItemID": "20",
"ItemName": "实际焊接电压",
"ItemAdress": "",
"Item_MQTT_Name": "v16",
"ItemLength": "1",
"ItemType": "String",
"IsRead": false,
"IsSave": false,
"UploadMode": "ChangeUpload",
"calculates": [
{
"CalculationRule": "ArrayAnalysis",
"IsCalculate": false,
"otherItemAdress": "19",
"ConstantValue": "1"
}
]
},
{
"ItemID": "21",
"ItemName": "实际焊接电流源数据",
"ItemAdress": "ns=2;s=DynamicWeldData.Current",
"Item_MQTT_Name": "",
"ItemLength": "1",
"ItemType": "String",
"IsRead": true
},
{
"ItemID": "22",
"ItemName": "实际焊接电流",
"ItemAdress": "",
"Item_MQTT_Name": "v17",
"ItemLength": "1",
"ItemType": "String",
"IsRead": false,
"IsSave": false,
"UploadMode": "ChangeUpload",
"calculates": [
{
"CalculationRule": "ArrayAnalysis",
"IsCalculate": false,
"otherItemAdress": "21",
"ConstantValue": "1"
}
]
},
{
"ItemID": "23",
"ItemName": "送丝速度源数据",
"ItemAdress": "ns=2;s=DynamicWeldData.WireSpeed",
"Item_MQTT_Name": "",
"ItemLength": "1",
"ItemType": "String",
"IsRead": true
},
{
"ItemID": "50",
"ItemName": "送丝速度",
"ItemAdress": "",
"Item_MQTT_Name": "v18",
"ItemLength": "1",
"ItemType": "String",
"IsRead": false,
"IsSave": false,
"UploadMode": "ChangeUpload",
"calculates": [
{
"CalculationRule": "ArrayAnalysis",
"IsCalculate": false,
"otherItemAdress": "23",
"ConstantValue": "1"
}
]
},
{
"ItemID": "24",
"ItemName": "故障代码",
"ItemAdress": "ns=2;s=RobotData.ErrorNumber",
"Item_MQTT_Name": "v19",
"ItemLength": "1",
"ItemType": "String",
"IsRead": true,
"UploadMode": "ChangeUpload"
},
{
"ItemID": "28",
"ItemName": "工艺编号",
"ItemAdress": "ns=2;s=RobotData.ProgramName",
"Item_MQTT_Name": "v23",
"ItemLength": "1",
"ItemType": "String",
"IsRead": true,
"UploadMode": "ChangeUpload"
},
{
"ItemID": "29",
"ItemName": "焊接规范阈值",
"ItemAdress": "",
"Item_MQTT_Name": "v24",
"ItemLength": "1",
"ItemType": "String",
"ItemValue": "0.2",
"IsRead": false,
"UploadMode": "ChangeUpload"
},
{
"ItemID": "30",
"ItemName": "额定功率",
"ItemAdress": "",
"Item_MQTT_Name": "v25",
"ItemLength": "1",
"ItemType": "String",
"ItemValue": "6",
"IsRead": false,
"UploadMode": "ChangeUpload"
},
{
"ItemID": "31",
"ItemName": "起弧标志",
"Item_MQTT_Name": "v26",
"ItemAdress": "ns=2;s=RobotData.ArcSwitchOn",
"ItemLength": "1",
"ItemType": "String",
"IsRead": true,
"UploadMode": "ChangeUpload"
},
{
"ItemID": "32",
"ItemName": "设备在线时长",
"ItemAdress": "",
"Item_MQTT_Name": "v27",
"ItemLength": "1",
"ItemType": "String",
"IsRead": false,
"IsSave": true,
"UploadMode": "ChangeUpload",
"calculates": [
{
"CalculationRule": "Cloos_Device_Status_Accumulation",
"IsCalculate": true,
"otherItemAdress": "13",
"ConstantValue": "1",
"AccumulationValue": [
"2",
"3",
"4",
"5"
]
}
]
},
{
"ItemID": "33",
"ItemName": "停机状态时长",
"ItemAdress": "",
"Item_MQTT_Name": "",
"ItemLength": "1",
"ItemType": "String",
"IsRead": false,
"IsSave": true,
"UploadMode": "ChangeUpload",
"calculates": [
{
"CalculationRule": "Cloos_Device_Status_Accumulation",
"IsCalculate": true,
"otherItemAdress": "13",
"ConstantValue": "1",
"AccumulationValue": [
"1"
]
}
]
},
{
"ItemID": "34",
"ItemName": "待机状态时长",
"ItemAdress": "",
"Item_MQTT_Name": "v28",
"ItemLength": "1",
"ItemType": "String",
"IsRead": false,
"IsSave": true,
"UploadMode": "ChangeUpload",
"calculates": [
{
"CalculationRule": "Cloos_Device_Status_Accumulation",
"IsCalculate": true,
"otherItemAdress": "13",
"ConstantValue": "1",
"AccumulationValue": [
"2"
]
}
]
},
{
"ItemID": "35",
"ItemName": "空载状态时长",
"ItemAdress": "",
"Item_MQTT_Name": "v29",
"ItemLength": "1",
"ItemType": "String",
"IsRead": false,
"IsSave": true,
"UploadMode": "ChangeUpload",
"calculates": [
{
"CalculationRule": "Cloos_Device_Status_Accumulation",
"IsCalculate": true,
"otherItemAdress": "13",
"ConstantValue": "1",
"AccumulationValue": [
"3"
]
}
]
},
{
"ItemID": "36",
"ItemName": "报警状态时长",
"ItemAdress": "",
"Item_MQTT_Name": "v30",
"ItemLength": "1",
"ItemType": "String",
"IsRead": false,
"IsSave": true,
"UploadMode": "ChangeUpload",
"calculates": [
{
"CalculationRule": "Cloos_Device_Status_Accumulation",
"IsCalculate": true,
"otherItemAdress": "13",
"ConstantValue": "1",
"AccumulationValue": [
"5"
]
}
]
},
{
"ItemID": "51",
"ItemName": "设备通电",
"ItemAdress": "",
"Item_MQTT_Name": "",
"ItemLength": "1",
"ItemType": "String",
"IsRead": false,
"UploadMode": "ChangeUpload"
},
{
"ItemID": "52",
"ItemName": "程序执行模式",
"ItemAdress": "ns=2;s=RobotData.InterpreterActive",
"Item_MQTT_Name": "",
"ItemLength": "1",
"ItemType": "Bool",
"IsRead": true,
"UploadMode": "ChangeUpload"
}
]

View File

@@ -0,0 +1,162 @@
namespace SampleOPCUAClient
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
textBox1 = new System.Windows.Forms.TextBox();
button1 = new System.Windows.Forms.Button();
label1 = new System.Windows.Forms.Label();
button2 = new System.Windows.Forms.Button();
button3 = new System.Windows.Forms.Button();
button4 = new System.Windows.Forms.Button();
button5 = new System.Windows.Forms.Button();
button6 = new System.Windows.Forms.Button();
SuspendLayout();
//
// textBox1
//
textBox1.Location = new System.Drawing.Point(204, 78);
textBox1.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5);
textBox1.Name = "textBox1";
textBox1.Size = new System.Drawing.Size(740, 38);
textBox1.TabIndex = 0;
textBox1.Text = "opc.tcp://192.168.250.1:4840";
//
// button1
//
button1.Location = new System.Drawing.Point(990, 67);
button1.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5);
button1.Name = "button1";
button1.Size = new System.Drawing.Size(178, 64);
button1.TabIndex = 1;
button1.Text = "连接";
button1.UseVisualStyleBackColor = true;
button1.Click += button1_Click;
//
// label1
//
label1.AutoSize = true;
label1.Location = new System.Drawing.Point(74, 84);
label1.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0);
label1.Name = "label1";
label1.Size = new System.Drawing.Size(113, 31);
label1.TabIndex = 2;
label1.Text = "OPC地址";
//
// button2
//
button2.Location = new System.Drawing.Point(1228, 67);
button2.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5);
button2.Name = "button2";
button2.Size = new System.Drawing.Size(178, 64);
button2.TabIndex = 3;
button2.Text = "读取";
button2.UseVisualStyleBackColor = true;
button2.Click += button2_Click;
//
// button3
//
button3.Location = new System.Drawing.Point(1228, 233);
button3.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5);
button3.Name = "button3";
button3.Size = new System.Drawing.Size(178, 64);
button3.TabIndex = 4;
button3.Text = "订阅";
button3.UseVisualStyleBackColor = true;
button3.Click += button3_Click;
//
// button4
//
button4.Location = new System.Drawing.Point(990, 233);
button4.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5);
button4.Name = "button4";
button4.Size = new System.Drawing.Size(178, 64);
button4.TabIndex = 5;
button4.Text = "结构体";
button4.UseVisualStyleBackColor = true;
button4.Click += button4_Click;
//
// button5
//
button5.Location = new System.Drawing.Point(770, 233);
button5.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5);
button5.Name = "button5";
button5.Size = new System.Drawing.Size(178, 64);
button5.TabIndex = 6;
button5.Text = "读取";
button5.UseVisualStyleBackColor = true;
button5.Click += button5_Click;
//
// button6
//
button6.Location = new System.Drawing.Point(990, 356);
button6.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5);
button6.Name = "button6";
button6.Size = new System.Drawing.Size(178, 64);
button6.TabIndex = 7;
button6.Text = "结构体写入";
button6.UseVisualStyleBackColor = true;
button6.Click += button6_Click;
//
// Form1
//
AutoScaleDimensions = new System.Drawing.SizeF(14F, 31F);
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
ClientSize = new System.Drawing.Size(1600, 821);
Controls.Add(button6);
Controls.Add(button5);
Controls.Add(button4);
Controls.Add(button3);
Controls.Add(button2);
Controls.Add(label1);
Controls.Add(button1);
Controls.Add(textBox1);
Margin = new System.Windows.Forms.Padding(6, 5, 6, 5);
Name = "Form1";
Text = "Form1";
FormClosing += Form1_FormClosing;
Load += Form1_Load;
ResumeLayout(false);
PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.Button button3;
private System.Windows.Forms.Button button4;
private System.Windows.Forms.Button button5;
private System.Windows.Forms.Button button6;
}
}

View File

@@ -0,0 +1,247 @@
using Opc.Ua;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Treasure.DataModel;
using Treasure.;
namespace SampleOPCUAClient
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
List<ItemBase> itemBases = new List<ItemBase>();
private void button1_Click(object sender, EventArgs e)
{
//连接OPC
pro_OPCUAp = new Pro_OPCUA(textBox1.Text);
isRunning = true;
MessageBox.Show("连接完成");
}
Pro_OPCUA pro_OPCUAp;
private void Form1_Load(object sender, EventArgs e)
{
itemBases = SystemConfigLoad<List<ItemBase>>("48.json");
}
/// <summary>
/// 配置读取
/// </summary>
/// <param name="filename"></param>
/// <returns></returns>
public static T SystemConfigLoad<T>(string filename = "System.json")
{
try
{
using (var sr = new System.IO.StreamReader(System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, filename)))
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(sr.ReadToEnd());
}
}
catch (Exception ex)
{
return default(T);
}
}
bool isRunning = false;
private void button2_Click(object sender, EventArgs e)
{
if (pro_OPCUAp==null)
{
MessageBox.Show("请先建立连接");
return;
}
//启动采集
Task.Factory.StartNew(() =>
{
try
{
//当设备启用时,进行数据采集
while (isRunning)
{
try
{
pro_OPCUAp.ReadItems(itemBases);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
continue;
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
});
}
/// <summary>
/// 订阅
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button3_Click(object sender, EventArgs e)
{
//启动采集
Task.Factory.StartNew(() =>
{
try
{
//当设备启用时,进行数据采集
try
{
pro_OPCUAp.subscription(itemBases);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
});
}
/// <summary>
/// 结构体
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button4_Click(object sender, EventArgs e)
{
//启动采集
Task.Factory.StartNew(() =>
{
List<string> items = new List<string>() { "ns=4;s=StationStatus1"};
while (isRunning)
{
for (int i = 0; i < items.Count; i++)
{
try
{
pro_OPCUAp.structItem(items[i]);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
continue;
}
}
System.Threading.Thread.Sleep(2000);
}
});
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
isRunning = false;
}
private void button5_Click(object sender, EventArgs e)
{
if (pro_OPCUAp == null)
{
MessageBox.Show("请先建立连接");
return;
}
//启动采集
Task.Factory.StartNew(() =>
{
try
{
//当设备启用时,进行数据采集
while (isRunning)
{
try
{
pro_OPCUAp.readAndWrite();
System.Threading.Thread.Sleep(2000);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
System.Threading.Thread.Sleep(2000);
continue;
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
});
}
private void button6_Click(object sender, EventArgs e)
{
ExtensionObject[] AA = new ExtensionObject[3];
WriteVar structs = new WriteVar
{
index = 0,
Name = "AA",
DataType = 0,
StringValue = "",
IntValue = 25,
FloatValue = 0.0F
};
var result = pro_OPCUAp.GetValueByteFromObj(structs);
AA[0] = result;
WriteVar structs1 = new WriteVar
{
index = 0,
Name = "BBB",
DataType = 1,
StringValue = "",
IntValue = 0,
FloatValue = 1.22F
};
var result1 = pro_OPCUAp.GetValueByteFromObj(structs1);
AA[1] = result1;
WriteVar structs2 = new WriteVar
{
index = 0,
Name = "C",
DataType = 2,
StringValue = "WUXE",
IntValue = 0,
FloatValue = 0.0F
};
var result2= pro_OPCUAp.GetValueByteFromObj(structs2);
AA[2] = result2;
//byte[] re = new byte[23] { 3,0,0,0,56,56,56,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0};
for (int i = 0; i < AA.Length; i++)
{
AA[i] = new ExtensionObject { Body = getNewByte() };
}
pro_OPCUAp.WriteVarStruct(AA);
}
public byte[] getNewByte()
{
byte[] item = new byte[20];
for (int i = 0; i < item.Length; i++)
{
item[i] = 0;
}
return item;
}
}
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,247 @@
//******************************************************************************************************
//
//文件名FileName ItemBase.cs
//
//功能描述Description 数据项模型
//
//数据表Tables Nothing
//
//作者Author wudehang
//
//日期Create Date 2021-03-09
//
//CLR版本CLR Version net Core 5.0
//
//版本Version 1.0.0
//
//公司Company 南京埃斯顿自动化股份有限公司
//
//备注: 数据项定义分为两种,一种为从设备上读取的源数据,另一种为需要根据源数据计算的数据,源数据只从设备中读取,不进行边缘计算。
//******************************************************************************************************
using System;
using System.Collections.Generic;
namespace Treasure.DataModel
{
/// <summary>
/// 数据项模型
/// </summary>
public class ItemBase
{
private string m_lastItemValue;
private string m_ItemValue="0";
/// <summary>
/// 数据项唯一标识
/// </summary>
public string ItemID { get; set; }
/// <summary>
/// 数据项名称
/// </summary>
public string ItemName { get; set; }
/// <summary>
/// 数据项名称
/// </summary>
public string Item_MQTT_Name { get; set; }
/// <summary>
/// 数据项地址
/// </summary>
public string ItemAdress { get; set; }
/// <summary>
/// 数据长度
/// </summary>
public short ItemLength { get; set; }
/// <summary>
/// 数据项类型
/// </summary>
public DataType? ItemType { get; set; }
/// <summary>
/// 上传模式
/// </summary>
public UploadMode UploadMode { get; set; } = UploadMode.PeriodicUpload;
/// <summary>
/// 是否从设备中读取
/// </summary>
public bool IsRead { get; set; }
/// <summary>
/// 数据项是否断电保持
/// </summary>
public bool IsSave { get; set; }
/// <summary>
/// 上次更新数据时间
/// </summary>
public DateTime? LastUpDateTime { get; set; }
/// <summary>
/// 当前更新数据时间
/// </summary>
public DateTime? UpDateTime { get; set; }
/// <summary>
/// 上次读取数据值
/// </summary>
public string lastItemValue
{
get
{
return m_lastItemValue;
}
set
{
if (value == "")
m_lastItemValue = "0";
else
m_lastItemValue = value;
}
}
/// <summary>
/// 计算后数据值
/// </summary>
public string ItemValue
{
get
{
if(m_ItemValue==""|| m_ItemValue == null)
{
return "0";
}
return m_ItemValue;
}
set
{
if (value == "")
m_ItemValue = "0";
else
m_ItemValue = value;
}
}
#nullable enable
/// <summary>
/// 顺序计算规则组
/// </summary>
public List<Calculate>? calculates = new List<Calculate>();
}
/// <summary>
/// 数据计算规则配置项
/// </summary>
public class Calculate
{
private string? m_ConstantValue;
/// <summary>
/// 计算规则索引
/// </summary>
public int CalculateIndex { get; set; }
/// <summary>
/// 计算规则配置
/// </summary>
public string? CalculationRule { get; set; }
/// <summary>
/// 本数据项是否在计算中被用到
/// </summary>
public bool IsCalculate { get; set; }
/// <summary>
/// 计算所需另一数据地址
/// </summary>
public string? otherItemAdress { get; set; }
/// <summary>
/// 计算所需的常数值
/// </summary>
public string? ConstantValue
{
get
{
return m_ConstantValue;
}
set
{
if (value == "")
m_ConstantValue = "0";
else
m_ConstantValue = value;
}
}
#nullable enable
/// <summary>
/// 累计计算数据的标志值集合
/// </summary>
public List<string>? AccumulationValue { get; set; } = new List<string>();
/// <summary>
/// 数据映射集合
/// </summary>
public List<DataMapp>? m_dataMapp { get; set; }
}
/// <summary>
/// 数据映射项
/// </summary>
public class DataMapp
{
/// <summary>
/// 数据地址或数据值索引
/// </summary>
public dynamic? Index { get; set; } = null;
/// <summary>
/// 数据映射信息
/// </summary>
public string Msg { get; set; } = "";
}
/// <summary>
/// 数据项类型
/// </summary>
public enum DataType
{
/// <summary>
/// 布尔值
/// </summary>
Bool,
/// <summary>
/// 字节型
/// </summary>
Byte,
/// <summary>
/// 短整型
/// </summary>
Short,
/// <summary>
/// 整型
/// </summary>
Int,
/// <summary>
/// 单精度浮点数
/// </summary>
Float,
/// <summary>
/// 双精度浮点数
/// </summary>
Double,
/// <summary>
/// 字符串类型
/// </summary>
String,
/// <summary>
/// 结构体类型
/// </summary>
Struct
}
/// <summary>
/// 数据项上行模式
/// </summary>
public enum UploadMode
{
/// <summary>
/// 周期上传
/// </summary>
PeriodicUpload,
/// <summary>
/// 变化上传
/// </summary>
ChangeUpload
}
}

View File

@@ -0,0 +1,499 @@
//******************************************************************************************************
//
//文件名FileName Pro_OPCUA.cs
//
//功能描述Description OPCUA通讯协议库包含OPCUA Client 和 Server
//
//数据表Tables Nothing
//
//作者Author wudehang
//
//日期Create Date 2021-03-09
//
//CLR版本CLR Version net Core 5.0
//
//版本Version 1.0.0
//
//公司Company 南京埃斯顿自动化股份有限公司
//
//******************************************************************************************************
using Opc.Ua;
using Opc.Ua.Client;
using Opc.Ua.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Treasure.
{
/// <summary>
/// A tool bar used to connect to a server.
/// </summary>
public partial class Pro_OPCUA
{
#region Constructors
/// <summary>
/// Initializes the object.
/// </summary>
public Pro_OPCUA()
{
m_endpoints = new Dictionary<Uri, EndpointDescription>();
}
#endregion
#region Private Fields
private ApplicationConfiguration m_configuration;
private Session m_session;
private SessionReconnectHandler m_reconnectHandler;
private EventHandler m_ReconnectComplete;
private EventHandler m_ReconnectStarting;
private EventHandler m_KeepAliveComplete;
private EventHandler m_ConnectComplete;
private Dictionary<Uri, EndpointDescription> m_endpoints;
#endregion
#region Public Members
/// <summary>
/// Default session values.
/// </summary>
public static readonly uint DefaultSessionTimeout = 60000;
/// <summary>
/// 默认发现超时
/// </summary>
public static readonly int DefaultDiscoverTimeout = 15000;
/// <summary>
/// 默认重新连接时间
/// </summary>
public static readonly int DefaultReconnectPeriod = 1000;
/// <summary>
/// The name of the session to create.
/// </summary>
public string SessionName { get; set; }
/// <summary>
/// Gets or sets a flag indicating that the domain checks should be ignored when connecting.
/// </summary>
public bool DisableDomainCheck { get; set; }
/// <summary>
/// Gets the cached EndpointDescription for a Url.
/// </summary>
public EndpointDescription GetEndpointDescription(Uri url)
{
EndpointDescription endpointDescription;
if (m_endpoints.TryGetValue(url, out endpointDescription))
{
return endpointDescription;
}
return null;
}
/// <summary>
/// The URL displayed in the control.
/// </summary>
public string ServerUrl
{
get;
set;
}
/// <summary>
/// Whether to use security when connecting.
/// </summary>
public bool UseSecurity
{
get;
set;
}
/// <summary>
/// Get the Client status.
/// </summary>
public string ConnectStatus
{
get { return m_ConnectStatus; }
}
private string m_ConnectStatus;
/// <summary>
/// The locales to use when creating the session.
/// </summary>
public string[] PreferredLocales { get; set; }
/// <summary>
/// The user identity to use when creating the session.
/// </summary>
public IUserIdentity UserIdentity { get; set; } = new UserIdentity();
/// <summary>
/// The client application configuration.
/// </summary>
public ApplicationConfiguration Configuration
{
get => m_configuration;
set
{
if (!Object.ReferenceEquals(m_configuration, value))
{
m_configuration = value;
}
}
}
/// <summary>
/// The currently active session.
/// </summary>
public Session Session => m_session;
/// <summary>
/// The number of seconds between reconnect attempts (0 means reconnect is disabled).
/// </summary>
public int ReconnectPeriod { get; set; } = DefaultReconnectPeriod;
/// <summary>
/// The discover timeout.
/// </summary>
public int DiscoverTimeout { get; set; } = DefaultDiscoverTimeout;
/// <summary>
/// The session timeout.
/// </summary>
public uint SessionTimeout { get; set; } = DefaultSessionTimeout;
/// <summary>
/// Raised when a good keep alive from the server arrives.
/// </summary>
public event EventHandler KeepAliveComplete
{
add { m_KeepAliveComplete += value; }
remove { m_KeepAliveComplete -= value; }
}
/// <summary>
/// Raised when a reconnect operation starts.
/// </summary>
public event EventHandler ReconnectStarting
{
add { m_ReconnectStarting += value; }
remove { m_ReconnectStarting -= value; }
}
/// <summary>
/// Raised when a reconnect operation completes.
/// </summary>
public event EventHandler ReconnectComplete
{
add { m_ReconnectComplete += value; }
remove { m_ReconnectComplete -= value; }
}
/// <summary>
/// Raised after successfully connecting to or disconnecing from a server.
/// </summary>
public event EventHandler ConnectComplete
{
add { m_ConnectComplete += value; }
remove { m_ConnectComplete -= value; }
}
/// <summary>
/// Creates a new session.
/// </summary>
/// <returns>The new session object.</returns>
private async Task<Session> Connect(
ITransportWaitingConnection connection,
EndpointDescription endpointDescription,
bool useSecurity,
uint sessionTimeout = 0)
{
// disconnect from existing session.
InternalDisconnect();
// select the best endpoint.
if (endpointDescription == null)
{
endpointDescription = CoreClientUtils.SelectEndpoint(m_configuration, connection, useSecurity, DiscoverTimeout);
}
EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(m_configuration);
ConfiguredEndpoint endpoint = new ConfiguredEndpoint(null, endpointDescription, endpointConfiguration);
m_session = await Session.Create(
m_configuration,
connection,
endpoint,
false,
!DisableDomainCheck,
(String.IsNullOrEmpty(SessionName)) ? m_configuration.ApplicationName : SessionName,
sessionTimeout == 0 ? DefaultSessionTimeout : sessionTimeout,
UserIdentity,
PreferredLocales);
// set up keep alive callback.
m_session.KeepAlive += new KeepAliveEventHandler(Session_KeepAlive);
// return the new session.
return m_session;
}
/// <summary>
/// Creates a new session.
/// </summary>
/// <returns>The new session object.</returns>
private async Task<Session> ConnectServer(
string serverUrl,
bool useSecurity,
uint sessionTimeout = 0)
{
try
{
// disconnect from existing session.
InternalDisconnect();
// select the best endpoint.
Console.WriteLine("获取远程节点1");
var endpointDescription = CoreClientUtils.SelectEndpoint(serverUrl, useSecurity, 600000);
var endpointConfiguration = EndpointConfiguration.Create(m_configuration);
var endpoint = new ConfiguredEndpoint(null, endpointDescription, endpointConfiguration);
// Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(endpoint));
Console.WriteLine("开始连接");
m_session = await Session.Create(
m_configuration,
endpoint,
false,
!DisableDomainCheck,
(String.IsNullOrEmpty(SessionName)) ? m_configuration.ApplicationName : SessionName,
sessionTimeout == 0 ? DefaultSessionTimeout : sessionTimeout,
UserIdentity,
PreferredLocales);
// set up keep alive callback.
m_session.KeepAlive += new KeepAliveEventHandler(Session_KeepAlive);
Console.WriteLine("连接完成");
Console.WriteLine(m_session.Connected);
isCconnect = true;
}
catch (Exception ex)
{
if (m_session!=null)
{
m_session.KeepAlive += new KeepAliveEventHandler(Session_KeepAlive);
}
else
{
isCconnect = false;
}
}
try
{
UpdateStatus(false, DateTime.Now, "Connected, loading complex type system.");
}
catch (Exception e)
{
UpdateStatus(true, DateTime.Now, "Connected, failed to load complex type system.");
Utils.Trace(e, "Failed to load complex type system.");
}
// return the new session.
return m_session;
}
/// <summary>
/// Creates a new session.
/// </summary>
/// <param name="serverUrl">The URL of a server endpoint.</param>
/// <param name="useSecurity">Whether to use security.</param>
/// <param name="sessionTimeout">会话超时时间.</param>
/// <returns>The new session object.</returns>
public async Task<Session> ConnectServerAsync(
string serverUrl = null,
bool useSecurity = false,
uint sessionTimeout = 0
)
{
return await Task.Run(() => ConnectServer(serverUrl, useSecurity, sessionTimeout));
}
/// <summary>
/// Create a new reverse connection.
/// </summary>
/// <param name="connection"></param>
/// <param name="useSecurity"></param>
/// <param name="discoverTimeout"></param>
/// <param name="sessionTimeout"></param>
public async Task<Session> ConnectServerAsync(
ITransportWaitingConnection connection,
bool useSecurity,
int discoverTimeout = -1,
uint sessionTimeout = 0
)
{
if (connection.EndpointUrl == null)
{
throw new ArgumentException("Endpoint URL is not valid.");
}
EndpointDescription endpointDescription = null;
if (!m_endpoints.TryGetValue(connection.EndpointUrl, out endpointDescription))
{
// Discovery uses the reverse connection and closes it
// return and wait for next reverse hello
endpointDescription = CoreClientUtils.SelectEndpoint(m_configuration, connection, useSecurity, discoverTimeout);
m_endpoints[connection.EndpointUrl] = endpointDescription;
return null;
}
return await Connect(connection, endpointDescription, useSecurity, sessionTimeout);
}
/// <summary>
/// Disconnects from the server.
/// </summary>
public Task DisconnectAsync()
{
UpdateStatus(false, DateTime.Now, "Disconnected");
return Task.Run(() => InternalDisconnect());
}
/// <summary>
/// Disconnects from the server.
/// </summary>
private void InternalDisconnect()
{
// stop any reconnect operation.
if (m_reconnectHandler != null)
{
m_reconnectHandler.Dispose();
m_reconnectHandler = null;
}
// disconnect any existing session.
if (m_session != null)
{
m_session.KeepAlive -= Session_KeepAlive;
m_session.Close(10000);
m_session = null;
}
}
/// <summary>
/// Disconnects from the server.
/// </summary>
public void Disconnect()
{
UpdateStatus(false, DateTime.Now, "Disconnected");
// stop any reconnect operation.
InternalDisconnect();
}
/// <summary>
/// Prompts the user to choose a server on another host.
/// </summary>
public void Discover(string hostName)
{
//待修改:添加服务器发现功能
// string endpointUrl = new DiscoverServerDlg().ShowDialog(m_configuration, hostName);
//if (endpointUrl != null)
//{
// ServerUrl = endpointUrl;
//}
}
#endregion
#region Event Handlers
/// <summary>
/// Updates the status control.
/// </summary>
/// <param name="error">Whether the status represents an error.</param>
/// <param name="time">The time associated with the status.</param>
/// <param name="status">The status message.</param>
/// <param name="args">Arguments used to format the status message.</param>
private void UpdateStatus(bool error, DateTime time, string status, params object[] args)
{
m_ConnectStatus= String.Format(status, args);
}
/// <summary>
/// Handles a keep alive event from a session.
/// </summary>
private void Session_KeepAlive(Session session, KeepAliveEventArgs e)
{
try
{
// check for events from discarded sessions.
if (!Object.ReferenceEquals(session, m_session))
{
return;
}
// start reconnect sequence on communication error.
if (Opc.Ua.ServiceResult.IsBad(e.Status))
{
if (ReconnectPeriod <= 0)
{
UpdateStatus(true, e.CurrentTime, "Communication Error ({0})", e.Status);
return;
}
UpdateStatus(true, e.CurrentTime, "Reconnecting in {0}s", ReconnectPeriod);
if (m_reconnectHandler == null)
{
if (m_ReconnectStarting != null)
{
m_ReconnectStarting(this, e);
}
m_reconnectHandler = new SessionReconnectHandler();
m_reconnectHandler.BeginReconnect(m_session, ReconnectPeriod * 1000, Server_ReconnectComplete);
}
return;
}
// update status.
UpdateStatus(false, e.CurrentTime, "Connected [{0}]", session.Endpoint.EndpointUrl);
// raise any additional notifications.
if (m_KeepAliveComplete != null)
{
m_KeepAliveComplete(this, e);
}
}
catch (Exception exception)
{
throw new Exception("Session_KeepAlive", exception);
}
}
/// <summary>
/// Handles a reconnect event complete from the reconnect handler.
/// </summary>
private void Server_ReconnectComplete(object sender, EventArgs e)
{
try
{
// ignore callbacks from discarded objects.
if (!Object.ReferenceEquals(sender, m_reconnectHandler))
{
return;
}
m_session = m_reconnectHandler.Session;
m_reconnectHandler.Dispose();
m_reconnectHandler = null;
// raise any additional notifications.
if (m_ReconnectComplete != null)
{
m_ReconnectComplete(this, e);
}
}
catch (Exception exception)
{
throw new Exception("Server_ReconnectComplete", exception);
}
}
#endregion
}
}

View File

@@ -0,0 +1,262 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>Opc.Ua.Bindings.Https</name>
</assembly>
<members>
<member name="T:Opc.Ua.Bindings.HttpsServiceHost">
<summary>
Creates a new <see cref="T:Opc.Ua.Bindings.HttpsTransportListener"/> with
<see cref="T:Opc.Ua.ITransportListener"/> interface.
</summary>
</member>
<member name="P:Opc.Ua.Bindings.HttpsServiceHost.UriScheme">
<summary>
The protocol supported by the listener.
</summary>
</member>
<member name="M:Opc.Ua.Bindings.HttpsServiceHost.Create">
<summary>
The method creates a new instance of a <see cref="T:Opc.Ua.Bindings.HttpsTransportListener"/>.
</summary>
<returns>The transport listener.</returns>
</member>
<member name="M:Opc.Ua.Bindings.HttpsServiceHost.CreateServiceHost(Opc.Ua.ServerBase,System.Collections.Generic.IDictionary{System.String,System.Threading.Tasks.Task},Opc.Ua.ApplicationConfiguration,System.Collections.Generic.IList{System.String},Opc.Ua.ApplicationDescription,System.Collections.Generic.List{Opc.Ua.ServerSecurityPolicy},System.Security.Cryptography.X509Certificates.X509Certificate2,System.Security.Cryptography.X509Certificates.X509Certificate2Collection)">
<inheritdoc/>
<summary>
Create a new service host for UA HTTPS.
</summary>
</member>
<member name="T:Opc.Ua.Bindings.HttpsTransportChannelFactory">
<summary>
Creates a new HttpsTransportChannel with ITransportChannel interface.
</summary>
</member>
<member name="P:Opc.Ua.Bindings.HttpsTransportChannelFactory.UriScheme">
<summary>
The protocol supported by the channel.
</summary>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportChannelFactory.Create">
<summary>
The method creates a new instance of a Https transport channel
</summary>
<returns>The transport channel</returns>
</member>
<member name="T:Opc.Ua.Bindings.HttpsTransportChannel">
<summary>
Wraps the HttpsTransportChannel and provides an ITransportChannel implementation.
</summary>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportChannel.Dispose">
<inheritdoc/>
</member>
<member name="P:Opc.Ua.Bindings.HttpsTransportChannel.UriScheme">
<inheritdoc/>
</member>
<member name="P:Opc.Ua.Bindings.HttpsTransportChannel.SupportedFeatures">
<inheritdoc/>
</member>
<member name="P:Opc.Ua.Bindings.HttpsTransportChannel.EndpointDescription">
<inheritdoc/>
</member>
<member name="P:Opc.Ua.Bindings.HttpsTransportChannel.EndpointConfiguration">
<inheritdoc/>
</member>
<member name="P:Opc.Ua.Bindings.HttpsTransportChannel.MessageContext">
<inheritdoc/>
</member>
<member name="P:Opc.Ua.Bindings.HttpsTransportChannel.CurrentToken">
<inheritdoc/>
</member>
<member name="P:Opc.Ua.Bindings.HttpsTransportChannel.OperationTimeout">
<inheritdoc/>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportChannel.Initialize(System.Uri,Opc.Ua.TransportChannelSettings)">
<inheritdoc/>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportChannel.Initialize(Opc.Ua.ITransportWaitingConnection,Opc.Ua.TransportChannelSettings)">
<summary>
Initializes a secure channel with a waiting reverse connection.
</summary>
<param name="connection">The connection to use.</param>
<param name="settings">The settings to use when creating the channel.</param>
<exception cref="T:Opc.Ua.ServiceResultException">Thrown if any communication error occurs.</exception>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportChannel.Open">
<inheritdoc/>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportChannel.Close">
<inheritdoc/>
</member>
<member name="T:Opc.Ua.Bindings.HttpsTransportChannel.AsyncResult">
<summary>
The async result class for the Https transport.
</summary>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportChannel.BeginSendRequest(Opc.Ua.IServiceRequest,System.AsyncCallback,System.Object)">
<inheritdoc/>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportChannel.EndSendRequest(System.IAsyncResult)">
<inheritdoc/>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportChannel.BeginOpen(System.AsyncCallback,System.Object)">
<inheritdoc/>
<remarks>Not implemented here.</remarks>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportChannel.EndOpen(System.IAsyncResult)">
<inheritdoc/>
<remarks>Not implemented here.</remarks>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportChannel.Reconnect">
<inheritdoc/>
<remarks>Not implemented here.</remarks>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportChannel.Opc#Ua#ITransportChannel#Reconnect(Opc.Ua.ITransportWaitingConnection)">
<inheritdoc/>
<remarks>Not implemented here.</remarks>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportChannel.BeginReconnect(System.AsyncCallback,System.Object)">
<inheritdoc/>
<remarks>Not implemented here.</remarks>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportChannel.EndReconnect(System.IAsyncResult)">
<inheritdoc/>
<remarks>Not implemented here.</remarks>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportChannel.BeginClose(System.AsyncCallback,System.Object)">
<inheritdoc/>
<remarks>Not implemented here.</remarks>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportChannel.EndClose(System.IAsyncResult)">
<inheritdoc/>
<remarks>Not implemented here.</remarks>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportChannel.SendRequest(Opc.Ua.IServiceRequest)">
<inheritdoc/>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportChannel.SaveSettings(System.Uri,Opc.Ua.TransportChannelSettings)">
<summary>
Save the settings for a connection.
</summary>
<param name="url">The server url.</param>
<param name="settings">The settings for the transport channel.</param>
</member>
<member name="T:Opc.Ua.Bindings.HttpsTransportListenerFactory">
<summary>
Creates a new <see cref="T:Opc.Ua.Bindings.HttpsTransportListener"/> with
<see cref="T:Opc.Ua.ITransportListener"/> interface.
</summary>
</member>
<member name="P:Opc.Ua.Bindings.HttpsTransportListenerFactory.UriScheme">
<summary>
The protocol supported by the listener.
</summary>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportListenerFactory.Create">
<summary>
The method creates a new instance of a <see cref="T:Opc.Ua.Bindings.HttpsTransportListener"/>.
</summary>
<returns>The transport listener.</returns>
</member>
<member name="T:Opc.Ua.Bindings.Startup">
<summary>
Implements the kestrel startup of the Https listener.
</summary>
</member>
<member name="P:Opc.Ua.Bindings.Startup.Listener">
<summary>
Get the Https listener.
</summary>
</member>
<member name="M:Opc.Ua.Bindings.Startup.Configure(Microsoft.AspNetCore.Builder.IApplicationBuilder)">
<summary>
Configure the request pipeline for the listener.
</summary>
<param name="appBuilder">The application builder.</param>
</member>
<member name="T:Opc.Ua.Bindings.HttpsTransportListener">
<summary>
Manages the connections for a UA HTTPS server.
</summary>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportListener.#ctor">
<summary>
Initializes a new instance of the <see cref="T:Opc.Ua.Bindings.HttpsTransportListener"/> class.
</summary>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportListener.Dispose">
<summary>
Frees any unmanaged resources.
</summary>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportListener.Dispose(System.Boolean)">
<summary>
An overrideable version of the Dispose.
</summary>
</member>
<member name="P:Opc.Ua.Bindings.HttpsTransportListener.UriScheme">
<summary>
The URI scheme handled by the listener.
</summary>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportListener.Open(System.Uri,Opc.Ua.TransportListenerSettings,Opc.Ua.ITransportListenerCallback)">
<summary>
Opens the listener and starts accepting connection.
</summary>
<param name="baseAddress">The base address.</param>
<param name="settings">The settings to use when creating the listener.</param>
<param name="callback">The callback to use when requests arrive via the channel.</param>
<exception cref="T:System.ArgumentNullException">Thrown if any parameter is null.</exception>
<exception cref="T:Opc.Ua.ServiceResultException">Thrown if any communication error occurs.</exception>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportListener.Close">
<summary>
Closes the listener and stops accepting connection.
</summary>
<exception cref="T:Opc.Ua.ServiceResultException">Thrown if any communication error occurs.</exception>
</member>
<member name="E:Opc.Ua.Bindings.HttpsTransportListener.ConnectionWaiting">
<summary>
Raised when a new connection is waiting for a client.
</summary>
</member>
<member name="E:Opc.Ua.Bindings.HttpsTransportListener.ConnectionStatusChanged">
<summary>
Raised when a monitored connection's status changed.
</summary>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportListener.CreateReverseConnection(System.Uri,System.Int32)">
<inheritdoc/>
<remarks>
Reverse connect for the https transport listener is not implemeted.
</remarks>
</member>
<member name="P:Opc.Ua.Bindings.HttpsTransportListener.EndpointUrl">
<summary>
Gets the URL for the listener's endpoint.
</summary>
<value>The URL for the listener's endpoint.</value>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportListener.Start">
<summary>
Starts listening at the specified port.
</summary>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportListener.Stop">
<summary>
Stops listening.
</summary>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportListener.SendAsync(Microsoft.AspNetCore.Http.HttpContext)">
<summary>
Handles requests arriving from a channel.
</summary>
</member>
<member name="M:Opc.Ua.Bindings.HttpsTransportListener.CertificateUpdate(Opc.Ua.ICertificateValidator,System.Security.Cryptography.X509Certificates.X509Certificate2,System.Security.Cryptography.X509Certificates.X509Certificate2Collection)">
<summary>
Called when a UpdateCertificate event occured.
</summary>
</member>
</members>
</doc>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,201 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>Opc.Ua.Configuration</name>
</assembly>
<members>
<member name="T:Opc.Ua.Configuration.IApplicationMessageDlg">
<summary>
Interface to create application callbacks.
</summary>
</member>
<member name="M:Opc.Ua.Configuration.IApplicationMessageDlg.Message(System.String,System.Boolean)">
<summary>
The application message.
</summary>
<param name="text">The text of the message.</param>
<param name="ask">If the application should ask the user.</param>
</member>
<member name="M:Opc.Ua.Configuration.IApplicationMessageDlg.ShowAsync">
<summary>
Show the message and return result.
</summary>
</member>
<member name="T:Opc.Ua.Configuration.ApplicationInstance">
<summary>
A class that install, configures and runs a UA application.
</summary>
</member>
<member name="M:Opc.Ua.Configuration.ApplicationInstance.#ctor">
<summary>
Initializes a new instance of the <see cref="T:Opc.Ua.Configuration.ApplicationInstance"/> class.
</summary>
</member>
<member name="M:Opc.Ua.Configuration.ApplicationInstance.#ctor(Opc.Ua.ApplicationConfiguration)">
<summary>
Initializes a new instance of the <see cref="T:Opc.Ua.Configuration.ApplicationInstance"/> class.
</summary>
<param name="applicationConfiguration">The application configuration.</param>
</member>
<member name="P:Opc.Ua.Configuration.ApplicationInstance.ApplicationName">
<summary>
Gets or sets the name of the application.
</summary>
<value>The name of the application.</value>
</member>
<member name="P:Opc.Ua.Configuration.ApplicationInstance.ApplicationType">
<summary>
Gets or sets the type of the application.
</summary>
<value>The type of the application.</value>
</member>
<member name="P:Opc.Ua.Configuration.ApplicationInstance.ConfigSectionName">
<summary>
Gets or sets the name of the config section containing the path to the application configuration file.
</summary>
<value>The name of the config section.</value>
</member>
<member name="P:Opc.Ua.Configuration.ApplicationInstance.ConfigurationType">
<summary>
Gets or sets the type of configuration file.
</summary>
<value>The type of configuration file.</value>
</member>
<member name="P:Opc.Ua.Configuration.ApplicationInstance.Server">
<summary>
Gets the server.
</summary>
<value>The server.</value>
</member>
<member name="P:Opc.Ua.Configuration.ApplicationInstance.ApplicationConfiguration">
<summary>
Gets the application configuration used when the Start() method was called.
</summary>
<value>The application configuration.</value>
</member>
<member name="P:Opc.Ua.Configuration.ApplicationInstance.NoGdsAgentAdmin">
<summary>
Gets or sets a flag that indicates whether the application will be set up for management with the GDS agent.
</summary>
<value>If true the application will not be visible to the GDS local agent after installation.</value>
</member>
<member name="P:Opc.Ua.Configuration.ApplicationInstance.MessageDlg">
<summary>
Get or set the message dialog.
</summary>
</member>
<member name="P:Opc.Ua.Configuration.ApplicationInstance.CertificatePasswordProvider">
<summary>
Get or set the certificate password provider.
</summary>
</member>
<member name="M:Opc.Ua.Configuration.ApplicationInstance.ProcessCommandLine">
<summary>
Processes the command line.
</summary>
<returns>
True if the arguments were processed; False otherwise.
</returns>
</member>
<member name="M:Opc.Ua.Configuration.ApplicationInstance.StartAsService(Opc.Ua.ServerBase)">
<summary>
Starts the UA server as a Windows Service.
</summary>
<param name="server">The server.</param>
</member>
<member name="M:Opc.Ua.Configuration.ApplicationInstance.Start(Opc.Ua.ServerBase)">
<summary>
Starts the UA server.
</summary>
<param name="server">The server.</param>
</member>
<member name="M:Opc.Ua.Configuration.ApplicationInstance.Stop">
<summary>
Stops the UA server.
</summary>
</member>
<member name="M:Opc.Ua.Configuration.ApplicationInstance.FixupAppConfig(Opc.Ua.ApplicationConfiguration)">
<summary>
Helper to replace localhost with the hostname
in the application uri and base adresses of the
configuration.
</summary>
<param name="configuration"></param>
</member>
<member name="M:Opc.Ua.Configuration.ApplicationInstance.LoadAppConfig(System.Boolean,System.String,Opc.Ua.ApplicationType,System.Type,System.Boolean,Opc.Ua.ICertificatePasswordProvider)">
<summary>
Loads the configuration.
</summary>
</member>
<member name="M:Opc.Ua.Configuration.ApplicationInstance.LoadApplicationConfiguration(System.String,System.Boolean)">
<summary>
Loads the application configuration.
</summary>
</member>
<member name="M:Opc.Ua.Configuration.ApplicationInstance.LoadApplicationConfiguration(System.Boolean)">
<summary>
Loads the application configuration.
</summary>
</member>
<member name="M:Opc.Ua.Configuration.ApplicationInstance.CheckApplicationInstanceCertificate(System.Boolean,System.UInt16)">
<summary>
Checks for a valid application instance certificate.
</summary>
<param name="silent">if set to <c>true</c> no dialogs will be displayed.</param>
<param name="minimumKeySize">Minimum size of the key.</param>
</member>
<member name="M:Opc.Ua.Configuration.ApplicationInstance.CheckApplicationInstanceCertificate(System.Boolean,System.UInt16,System.UInt16)">
<summary>
Checks for a valid application instance certificate.
</summary>
<param name="silent">if set to <c>true</c> no dialogs will be displayed.</param>
<param name="minimumKeySize">Minimum size of the key.</param>
<param name="lifeTimeInMonths">The lifetime in months.</param>
</member>
<member name="M:Opc.Ua.Configuration.ApplicationInstance.CertificateValidator_CertificateValidation(Opc.Ua.CertificateValidator,Opc.Ua.CertificateValidationEventArgs)">
<summary>
Handles a certificate validation error.
</summary>
</member>
<member name="M:Opc.Ua.Configuration.ApplicationInstance.CheckApplicationInstanceCertificate(Opc.Ua.ApplicationConfiguration,System.Security.Cryptography.X509Certificates.X509Certificate2,System.Boolean,System.UInt16)">
<summary>
Creates an application instance certificate if one does not already exist.
</summary>
</member>
<member name="M:Opc.Ua.Configuration.ApplicationInstance.CheckDomainsInCertificate(Opc.Ua.ApplicationConfiguration,System.Security.Cryptography.X509Certificates.X509Certificate2,System.Boolean)">
<summary>
Checks that the domains in the server addresses match the domains in the certificates.
</summary>
</member>
<member name="M:Opc.Ua.Configuration.ApplicationInstance.CreateApplicationInstanceCertificate(Opc.Ua.ApplicationConfiguration,System.UInt16,System.UInt16)">
<summary>
Creates the application instance certificate.
</summary>
<param name="configuration">The configuration.</param>
<param name="keySize">Size of the key.</param>
<param name="lifeTimeInMonths">The lifetime in months.</param>
<returns>The new certificate</returns>
</member>
<member name="M:Opc.Ua.Configuration.ApplicationInstance.DeleteApplicationInstanceCertificate(Opc.Ua.ApplicationConfiguration)">
<summary>
Deletes an existing application instance certificate.
</summary>
<param name="configuration">The configuration instance that stores the configurable information for a UA application.</param>
</member>
<member name="M:Opc.Ua.Configuration.ApplicationInstance.AddToTrustedStore(Opc.Ua.ApplicationConfiguration,System.Security.Cryptography.X509Certificates.X509Certificate2)">
<summary>
Adds the certificate to the Trusted Certificate Store
</summary>
<param name="configuration">The application's configuration which specifies the location of the TrustedStore.</param>
<param name="certificate">The certificate to register.</param>
</member>
<member name="M:Opc.Ua.Configuration.ApplicationInstance.ApproveMessage(System.String,System.Boolean)">
<summary>
Show a message for approval and return result.
</summary>
<param name="message"></param>
<param name="silent"></param>
<returns>True if approved, false otherwise.</returns>
</member>
</members>
</doc>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,635 @@
//******************************************************************************************************
//
//文件名FileName Pro_OPCUA.cs
//
//功能描述Description OPCUA通讯协议库包含OPCUA Client 和 Server
//
//数据表Tables Nothing
//
//作者Author wudehang
//
//日期Create Date 2021-03-09
//
//CLR版本CLR Version net Core 5.0
//
//版本Version 1.0.0
//
//公司Company 南京埃斯顿自动化股份有限公司
//
//******************************************************************************************************
using Newtonsoft.Json.Linq;
using Opc.Ua;
using Opc.Ua.Client;
using Opc.Ua.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using Treasure.DataModel;
namespace Treasure.
{
/// <summary>
/// OPCUA 通讯协议
/// </summary>
public partial class Pro_OPCUA : ProtocolBase
{
/// <summary>
/// 应用程序对象
/// </summary>
private ApplicationInstance m_application = new ApplicationInstance();
/// <summary>
/// 连接地址
/// </summary>
private string m_ConnectStr { get; set; }
/// <summary>
/// OPC连接状态
/// </summary>
private bool isCconnect { get; set; }
/// <summary>
/// 构造函数
/// </summary>
public Pro_OPCUA(string ConnectStr)
{
m_ConnectStr = ConnectStr;
m_application.ApplicationType = ApplicationType.Client;
m_application.ConfigSectionName = "Treasure.OPCUAClient";
try
{
Console.WriteLine("加载客户端配置");
// 加载opcua客户端配置
m_application.LoadApplicationConfiguration(false).Wait();
m_configuration = m_application.ApplicationConfiguration;
// 核对客户端证书
m_application.CheckApplicationInstanceCertificate(true, 0).Wait();
//建立会话
Connect();
}
catch (Exception ex)
{
throw new Exception("OPUAConfiguration:" + ex.ToString());
}
}
/// <summary>
/// 通讯协议参数初始化
/// </summary>
public override void ProtocolInit(string IP, short Port, string ConnectStr)
{
}
/// <summary>
/// 开始采集
/// </summary>
public override void ReadItems(List<ItemBase> itemBases)
{
int j = 20;
for (int i = 0; i < itemBases.Count; i += 20)
{
//读取数据
ReadNodes(itemBases.Take(j).Skip(i).ToList());
j += 20;
}
}
public void readAndWrite()
{
try
{
if (isCconnect)
{
//Console.WriteLine("数据节点转换");
//节点格式转换
ReadValueIdCollection nodesToRead = new ReadValueIdCollection();
nodesToRead.Add(new ReadValueId()
{
NodeId = new NodeId("ns=2;s=WRITEVAR"),
AttributeId = Attributes.Value
});
DataValueCollection resultsValues = null;
DiagnosticInfoCollection diagnosticInfos = null;
m_session.Read(
null,
0,
TimestampsToReturn.Both,
nodesToRead,
out resultsValues,
out diagnosticInfos);
//验证结果
ClientBase.ValidateResponse(resultsValues, nodesToRead);
WriteValueCollection nodesToWrite = new WriteValueCollection();
byte[] itt = (resultsValues[0].Value as ExtensionObject[])[0].Body as byte[];
ExtensionObject[] AA = new ExtensionObject[100];
for (int i = 0; i < AA.Length; i++)
{
AA[i] = new ExtensionObject()
{
Body = itt
};
}
var aa = resultsValues[0].Value;
nodesToWrite.Add(new WriteValue()
{
NodeId = new NodeId("ns=2;s=WRITEVAR"),
AttributeId = Attributes.Value,
Value = new DataValue()
{
Value = AA
// resultsValues[0].Value
}
});
StatusCodeCollection resultsValues1 = null;
DiagnosticInfoCollection diagnosticInfos1 = null;
//Console.WriteLine("数据读取开始");
// Call Read Service
m_session.Write(
null,
nodesToWrite,
out resultsValues1,
out diagnosticInfos1);
//验证结果
ClientBase.ValidateResponse(resultsValues1, nodesToWrite);
}
else
{
Connect();
}
}
catch (Exception ex)
{
throw new Exception("OPUAReadNodes:" + ex.Message + ex.StackTrace);
}
}
/// <summary>
/// 开始采集
/// </summary>
public override void ReadItem(ItemBase itemBases)
{
//读取数据
//itemBases.ItemValue = ReadNode(itemBases.ItemAdress).Value.ToString();
}
/// <summary>
/// 连接初始化
/// </summary>
public override async void Connect()
{
try
{
//待修改 sessionTimeout 设置长一些
await ConnectServer(m_ConnectStr, false);
}
catch (Exception)
{
throw;
}
}
/// <summary>
/// 连接校验(在每次读取时,进行连接校验),连接校验失败,则进行一次重连
/// </summary>
public override void CheckConnect()
{
}
/// <summary>
/// 连接断开
/// </summary>
public override void Close()
{
if (m_session != null)
{
m_session.Close();
m_session.Dispose();
m_session = null;
}
}
/// <summary>
/// OPCUA单个Tag读取
/// </summary>
/// <param name="Tag"></param>
/// <returns></returns>
public Node ReadNode(string Tag)
{
try
{
return m_session.ReadNode(new NodeId(Tag));
}
catch (Exception ex)
{
throw new Exception("OPUAReadNode:" + ex.Message + ex.StackTrace);
}
}
Subscription m_subscription;
/// <summary>
/// 订阅
/// </summary>
/// <param name="itemBases"></param>
public void subscription(List<ItemBase> itemBases)
{
if (m_session == null || m_session.Connected == false)
{
Console.WriteLine("Session not connected!");
return;
}
try
{
// Create a subscription for receiving data change notifications
// Define Subscription parameters
m_subscription = new Subscription(m_session.DefaultSubscription);
m_subscription.DisplayName = "Console ReferenceClient Subscription";
m_subscription.PublishingEnabled = true;
m_subscription.PublishingInterval = 200;
for (int i = 0; i < itemBases.Count; i++)
{
// Create MonitoredItems for data changes
MonitoredItem intMonitoredItem = new MonitoredItem(m_subscription.DefaultItem);
// Int32 Node - Objects\CTT\Scalar\Simulation\Int32
intMonitoredItem.StartNodeId = new NodeId(itemBases[i].ItemAdress);
intMonitoredItem.AttributeId = Attributes.Value;
intMonitoredItem.DisplayName = itemBases[i].ItemID + itemBases[i].ItemName;
intMonitoredItem.SamplingInterval = 200;
intMonitoredItem.Notification += OnMonitoredItemNotification;
m_subscription.AddItem(intMonitoredItem);
}
var aa = m_session.AddSubscription(m_subscription);
// Create the subscription on Server side
m_subscription.Create();
}
catch (Exception ex)
{
Console.WriteLine("Subscribe error: {0}", ex.Message);
}
}
/// <summary>
/// 停止订阅
/// </summary>
public void EndSubscription()
{
}
/// <summary>
/// Handle DataChange notifications from Server
/// </summary>
private void OnMonitoredItemNotification(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs e)
{
try
{
// Log MonitoredItem Notification event
MonitoredItemNotification notification = e.NotificationValue as MonitoredItemNotification;
Console.WriteLine("Notification Received for Variable \"{0}\" and Value = {1}.", monitoredItem.DisplayName, notification.Value);
}
catch (Exception ex)
{
Console.WriteLine("OnMonitoredItemNotification error: {0}", ex.Message);
}
}
public string structItem(string ItemAdress)
{
DataValue item = m_session.ReadValue(new NodeId(ItemAdress));
string aaa = ReadStruct(ItemAdress, item);
return aaa;
}
/// <summary>
/// 读取结构体数据
/// </summary>
public string ReadStruct(string ItemAdress, DataValue value)
{
NodeId node = new NodeId(ItemAdress);
//获取Node 信息 验证Node的数据类型
VariableNode nodeInfo = m_session.ReadNode(node) as VariableNode;
string aa1 = Newtonsoft.Json.JsonConvert.SerializeObject(nodeInfo);
//DataValue value = m_session.ReadValue(node);
var datatypeNode = (m_session.ReadNode(nodeInfo.DataType)) as DataTypeNode;
var typeDefine = datatypeNode.DataTypeDefinition.Body as StructureDefinition;
//var datatypeNode1 = (m_session.ReadNode(new NodeId("ns=2;i=3073"))) as DataTypeNode;
string aa = Newtonsoft.Json.JsonConvert.SerializeObject(datatypeNode);
//string aaa = Newtonsoft.Json.JsonConvert.SerializeObject(datatypeNode1);
int index = 0;
if (value.Value is ExtensionObject[])//数组
{
JArray res = new JArray();
foreach (var item in value.Value as ExtensionObject[])
{
res.Add(GetJsonFromExtensionObject(ItemAdress, item, typeDefine, ref index));
}
return res.ToString();
}
else //非数组
{
return GetJsonFromExtensionObject(ItemAdress, value.Value as ExtensionObject, typeDefine, ref index).ToString();
}
}
private JObject GetJsonFromExtensionObject(string address, ExtensionObject value, StructureDefinition structure, ref int index)
{
JObject res = new JObject();
var data = value.Body as byte[];
foreach (var field in structure.Fields)
{
if (field.ValueRank == 1)
{
//是数组,需要读取数组长度
string fieldNodeId = $"{address}.{field.Name}"; // 例如:"StationStatus1.AlarmA1"
VariableNode fieldNode = m_session.ReadNode(new NodeId(fieldNodeId)) as VariableNode;
if (fieldNode.ArrayDimensions != null && fieldNode.ArrayDimensions.Count > 0)
{
int count = (int)BitConverter.ToUInt32(data.Skip(index).Take(4).ToArray(), 0);
index += 4;
for (int i = 0; i < count; i++)
{
res[$"{field.Name}[{i}]"] = BitConverter.ToBoolean(data.Skip(index + i).Take(1).ToArray(), 0);
}
index += count;
}
}
else if (field.DataType.NamespaceIndex == 2)
{
//结构体嵌套
var count = BitConverter.ToUInt32(data.Skip(index).Take(4).ToArray(), 0);
index += 4;
var datatypeNode1 = (m_session.ReadNode(field.DataType)) as DataTypeNode;
var typeDefine = datatypeNode1.DataTypeDefinition.Body as StructureDefinition;
for (int i = 0; i < count; i++)
{
res[field.Name + i] = GetJsonFromExtensionObject(address, value, typeDefine, ref index);
}
}
else
{
string name = field.Name;
if (field.DataType == DataTypeIds.String)
{
int length = (int)BitConverter.ToUInt32(data.Skip(index).Take(4).ToArray(), 0);
index += 4;
string re = Encoding.Default.GetString(data.Skip(index).Take(length).ToArray());
res[name] = re;
index += length;
}
if (field.DataType == DataTypeIds.UInt32)
{
UInt32 re = BitConverter.ToUInt32(data.Skip(index).Take(4).ToArray(), 0);
index += 4;
res[name] = re;
}
if (field.DataType == DataTypeIds.Float)
{
float re = BitConverter.ToSingle(data.Skip(index).Take(4).ToArray(), 0);
index += 4;
res[name] = re;
}
if (field.DataType == DataTypeIds.Boolean)
{
bool re = BitConverter.ToBoolean(data.Skip(index).Take(1).ToArray());
res[name] = re;
index += 1;
}
if (field.DataType == DataTypeIds.Double)
{
double re = BitConverter.ToDouble(data.Skip(index).Take(8).ToArray());
res[name] = re;
index += 8;
}
}
}
return res;
}
/// <summary>
/// OPCUA批量Tag读取
/// </summary>
/// <param name="itemBases">需要读取的节点</param>
/// <returns></returns>
public void ReadNodes(List<ItemBase> itemBases)
{
try
{
if (isCconnect)
{
//Console.WriteLine("数据节点转换");
//节点格式转换
ReadValueIdCollection nodesToRead = new ReadValueIdCollection();
for (int i = 0; i < itemBases.Count; i++)
{
nodesToRead.Add(new ReadValueId()
{
NodeId = new NodeId(itemBases[i].ItemAdress),
AttributeId = Attributes.Value
});
}
NodeId ss = itemBases[0].ItemAdress;
//EncodeableFactory.GlobalFactory.AddEncodeableType(typeof(QTI_Data));
// Read the node attributes
DataValueCollection resultsValues = null;
DiagnosticInfoCollection diagnosticInfos = null;
//Console.WriteLine("数据读取开始");
// Call Read Service
m_session.Read(
null,
0,
TimestampsToReturn.Both,
nodesToRead,
out resultsValues,
out diagnosticInfos);
//验证结果
ClientBase.ValidateResponse(resultsValues, nodesToRead);
for (int i = 0; i < resultsValues.Count; i++)
{
if (resultsValues[i].Value == null)
{
itemBases[i].ItemValue = "";
}
else
{
//若是字符串数据的话,则进行直接赋值
if (resultsValues[i].WrappedValue.TypeInfo.BuiltInType == BuiltInType.String)
{
itemBases[i].ItemValue = resultsValues[i].Value.ToString();
}
else
{
itemBases[i].ItemValue = Newtonsoft.Json.JsonConvert.SerializeObject(resultsValues[i].Value);
}
}
//在这里进行结构体类型数据处理
if (itemBases[i].ItemType == DataType.Struct)
{
// itemBases[i].ItemValue = ReadStruct(itemBases[i].ItemAdress, resultsValues[i]);
}
}
}
else
{
Connect();
}
}
catch (Exception ex)
{
throw new Exception("OPUAReadNodes:" + ex.Message + ex.StackTrace);
}
}
/// <summary>
/// OPCUATag写入
/// </summary>
/// <param name="adress">需要写入节点的地址</param>
/// <param name="value">需要写入节点的值</param>
/// <returns></returns>
public bool WriteNode(WriteValueCollection value)
{
try
{
if (isCconnect)
{
StatusCodeCollection resultsValues = null;
DiagnosticInfoCollection diagnosticInfos = null;
//Console.WriteLine("数据读取开始");
// Call Read Service
var result = m_session.Write(
null,
value,
out resultsValues,
out diagnosticInfos);
//写入返回值为bad则写入失败
if (StatusCode.IsBad(result.ServiceResult))
{
return false;
}
//验证结果
ClientBase.ValidateResponse(resultsValues, value);
return true;
}
return false;
}
catch (Exception ex)
{
throw new Exception("OPUAReadNodes:" + ex.Message + ex.StackTrace);
}
}
/// <summary>
/// 从对象中获取对象所有的值并转化为byte[]
/// </summary>
/// <param name="value">需要写入节点的值组成的byte数组列表</param>
/// <returns></returns>
public ExtensionObject GetValueByteFromObj(WriteVar value)
{
List<byte> result = new List<byte>();
//前4位为字符串数据长度
var length = BitConverter.GetBytes(value.Name.Length);
result.AddRange(length);
//数据项名称
var Name = Encoding.Default.GetBytes(value.Name);
result.AddRange(Name);
//数据类型
var DataType = BitConverter.GetBytes(value.DataType);
result.AddRange(DataType);
//字符串数据转换
if (value.StringValue.Length == 0)
{
result.AddRange(new byte[4] { 0, 0, 0, 0 });
}
else
{
//前4位为字符串数据长度
length = BitConverter.GetBytes(value.StringValue.Length);
result.AddRange(length);
//字符串数据
var StringValue = Encoding.Default.GetBytes(value.StringValue);
result.AddRange(StringValue);
}
//整数数据
var IntValue = BitConverter.GetBytes(value.IntValue);
result.AddRange(IntValue);
//浮点数数据
var FloatValue = BitConverter.GetBytes(value.FloatValue);
result.AddRange(FloatValue);
return new ExtensionObject { Body = result.ToArray() };
}
/// <summary>
/// OPCUATag写入
/// </summary>
/// <param name="value">需要写入节点的值组成的byte数组列表</param>
/// <returns></returns>
public void WriteVarStruct(ExtensionObject[] value)
{
WriteValueCollection nodesToWrite = new WriteValueCollection();
nodesToWrite.Add(new WriteValue()
{
NodeId = new NodeId("ns=2;s=WRITEVAR"),
AttributeId = Attributes.Value,
Value = new DataValue()
{
Value = value
}
});
WriteNode(nodesToWrite);
}
///// <summary>
///// OPCUATag写入
///// </summary>
///// <param name="value">需要写入节点的值组成的byte数组列表</param>
///// <returns></returns>
//public void WriteVarStruct(WriteVar writeVar)
//{
// List<byte> result = new List<byte>();
// WriteValueCollection nodesToWrite = new WriteValueCollection();
// nodesToWrite.Add(new WriteValue()
// {
// NodeId = new NodeId("ns=2;s=WRITEVAR"),
// AttributeId = Attributes.Value,
// Value = new DataValue()
// {
// Value = value
// }
// });
// WriteNode(nodesToWrite);
//}
}
/// <summary>
/// writevar对象
/// </summary>
public class WriteVar
{
/// <summary>
/// 数组索引
/// </summary>
public int index = 0;
/// <summary>
/// 数据项名称
/// </summary>
public string Name = "";
/// <summary>
/// 数据类型
/// </summary>
public int DataType = 0;
/// <summary>
/// 字符串值
/// </summary>
public string StringValue = "";
/// <summary>
/// 整数值
/// </summary>
public int IntValue = 0;
/// <summary>
/// 浮点数值
/// </summary>
public float FloatValue = 0.0F;
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace SampleOPCUAClient
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.SetHighDpiMode(HighDpiMode.SystemAware);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}

View File

@@ -0,0 +1,70 @@
//******************************************************************************************************
//
//文件名FileName ProtocolBase.cs
//
//功能描述Description 通讯协议 基类,定义了通讯协议包含的基本功能及必要属性
//
//数据表Tables Nothing
//
//作者Author wudehang
//
//日期Create Date 2021-03-09
//
//CLR版本CLR Version net Core 5.0
//
//版本Version 1.0.0
//
//公司Company 南京埃斯顿自动化股份有限公司
//
//******************************************************************************************************
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Treasure.DataModel;
namespace Treasure.
{
/// <summary>
/// 通讯协议 基类
/// </summary>
public abstract class ProtocolBase
{
/// <summary>
/// ip地址
/// </summary>
protected string m_IP { get; set; }
/// <summary>
/// 端口
/// </summary>
protected short m_Port { get; set; }
/// <summary>
/// 连接字符串
/// </summary>
protected string m_MonnectStr { get; set; }
/// <summary>
/// 通讯协议参数初始化
/// </summary>
public abstract void ProtocolInit(string IP, short Port, string ConnectStr);
/// <summary>
/// 批量读取数据,包含数据类型分类,数据读取等
/// </summary>
public abstract void ReadItems(List<ItemBase> itemBases);
/// <summary>
/// 单个读取数据,包含数据类型分类,数据读取等
/// </summary>
public abstract void ReadItem(ItemBase itemBase);
/// <summary>
/// 连接初始化
/// </summary>
public abstract void Connect();
/// <summary>
/// 连接校验(在每次读取时,进行连接校验),连接校验失败,则进行一次重连
/// </summary>
public abstract void CheckConnect();
/// <summary>
/// 连接断开
/// </summary>
public abstract void Close();
}
}

View File

@@ -0,0 +1,41 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net9.0-windows7.0</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="System.ServiceModel.Primitives" Version="4.8.1" />
</ItemGroup>
<ItemGroup>
<Reference Include="Opc.Ua.Bindings.Https">
<HintPath>OPC依赖项\Opc.Ua.Bindings.Https.dll</HintPath>
</Reference>
<Reference Include="Opc.Ua.Client">
<HintPath>OPC依赖项\Opc.Ua.Client.dll</HintPath>
</Reference>
<Reference Include="Opc.Ua.Configuration">
<HintPath>OPC依赖项\Opc.Ua.Configuration.dll</HintPath>
</Reference>
<Reference Include="Opc.Ua.Core">
<HintPath>OPC依赖项\Opc.Ua.Core.dll</HintPath>
</Reference>
<Reference Include="Opc.Ua.Security.Certificates">
<HintPath>OPC依赖项\Opc.Ua.Security.Certificates.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<None Update="48.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Treasure.OPCUAClient.Config.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="utf-8"?>
<ApplicationConfiguration
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ua="http://opcfoundation.org/UA/2008/02/Types.xsd"
xmlns="http://opcfoundation.org/UA/SDK/Configuration.xsd"
>
<ApplicationName>Quickstart Console Reference Client</ApplicationName>
<ApplicationUri>urn:localhost:Quickstarts:Console ReferenceClient</ApplicationUri>
<ProductUri>uri:opcfoundation.org:Quickstarts:Console ReferenceClient</ProductUri>
<ApplicationType>Client_1</ApplicationType>
<SecurityConfiguration>
<!-- Where the application instance certificate is stored (MachineDefault) -->
<ApplicationCertificate>
<StoreType>Directory</StoreType>
<StorePath>%CommonApplicationData%\OPC Foundation\pki\own</StorePath>
<SubjectName>CN=Quickstart Console Reference Client, C=US, S=Arizona, O=OPC Foundation, DC=localhost</SubjectName>
</ApplicationCertificate>
<!-- Where the issuer certificate are stored (certificate authorities) -->
<TrustedIssuerCertificates>
<StoreType>Directory</StoreType>
<StorePath>%CommonApplicationData%\OPC Foundation\pki\issuer</StorePath>
</TrustedIssuerCertificates>
<!-- Where the trust list is stored -->
<TrustedPeerCertificates>
<StoreType>Directory</StoreType>
<StorePath>%CommonApplicationData%\OPC Foundation\pki\trusted</StorePath>
</TrustedPeerCertificates>
<!-- The directory used to store invalid certficates for later review by the administrator. -->
<RejectedCertificateStore>
<StoreType>Directory</StoreType>
<StorePath>%CommonApplicationData%\OPC Foundation\pki\rejected</StorePath>
</RejectedCertificateStore>
<!-- WARNING: The following setting (to automatically accept untrusted certificates) should be used
for easy debugging purposes ONLY and turned off for production deployments! -->
<AutoAcceptUntrustedCertificates>false</AutoAcceptUntrustedCertificates>
</SecurityConfiguration>
<TransportConfigurations></TransportConfigurations>
<TransportQuotas>
<OperationTimeout>600000</OperationTimeout>
<MaxStringLength>1048576</MaxStringLength>
<MaxByteStringLength>1048576</MaxByteStringLength>
<MaxArrayLength>65535</MaxArrayLength>
<MaxMessageSize>4194304</MaxMessageSize>
<MaxBufferSize>65535</MaxBufferSize>
<ChannelLifetime>300000</ChannelLifetime>
<SecurityTokenLifetime>3600000</SecurityTokenLifetime>
</TransportQuotas>
<ClientConfiguration>
<DefaultSessionTimeout>60000</DefaultSessionTimeout>
<WellKnownDiscoveryUrls>
<ua:String>opc.tcp://{0}:4840</ua:String>
<ua:String>http://{0}:52601/UADiscovery</ua:String>
<ua:String>http://{0}/UADiscovery/Default.svc</ua:String>
</WellKnownDiscoveryUrls>
<DiscoveryServers></DiscoveryServers>
<MinSubscriptionLifetime>10000</MinSubscriptionLifetime>
</ClientConfiguration>
<Extensions>
</Extensions>
<TraceConfiguration>
<OutputFilePath>%CommonApplicationData%\OPC Foundation\Logs\Quickstarts.ConsoleReferenceClient.log.txt</OutputFilePath>
<DeleteOnLoad>true</DeleteOnLoad>
<!-- Show Only Errors -->
<!-- <TraceMasks>1</TraceMasks> -->
<!-- Show Only Security and Errors -->
<!-- <TraceMasks>513</TraceMasks> -->
<!-- Show Only Security, Errors and Trace -->
<!-- <TraceMasks>515</TraceMasks> -->
<!-- Show Only Security, COM Calls, Errors and Trace -->
<!-- <TraceMasks>771</TraceMasks> -->
<!-- Show Only Security, Service Calls, Errors and Trace -->
<!-- <TraceMasks>523</TraceMasks> -->
<!-- Show Only Security, ServiceResultExceptions, Errors and Trace -->
<!-- <TraceMasks>519</TraceMasks> -->
</TraceConfiguration>
</ApplicationConfiguration>