mirror of
https://gitee.com/ThingsGateway/ThingsGateway.git
synced 2025-10-23 11:51:09 +08:00
Compare commits
91 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a533286658 | ||
|
|
e59f91cd82 | ||
|
|
5f8b85d8a4 | ||
|
|
47c7b88436 | ||
|
|
90006782f2 | ||
|
|
c3d49cbe70 | ||
|
|
112323a360 | ||
|
|
9d08c90fda | ||
|
|
602d24deec | ||
|
|
a2b9f66785 | ||
|
|
7cbf289b50 | ||
|
|
4097da79a5 | ||
|
|
91b7ae554f | ||
|
|
3121aa2542 | ||
|
|
4bf895e6e1 | ||
|
|
0c5489e920 | ||
|
|
d63c3aaa80 | ||
|
|
4f188ea6cc | ||
|
|
acb17018ae | ||
|
|
2affe2988d | ||
|
|
4174dd2206 | ||
|
|
e1c492f238 | ||
|
|
fb08e34fa3 | ||
|
|
a1793a0afe | ||
|
|
4da9763b49 | ||
|
|
81e0918bd0 | ||
|
|
c1e064f06d | ||
|
|
1c52be8b47 | ||
|
|
bcd82055ca | ||
|
|
c47d95d170 | ||
|
|
3e62f1ad51 | ||
|
|
8dcae973ef | ||
|
|
4cf35f7294 | ||
|
|
94c77d151b | ||
|
|
7f600e2b4b | ||
|
|
c809d0ba87 | ||
|
|
50f038ec89 | ||
|
|
9199a255a2 | ||
|
|
d324537b47 | ||
|
|
d0c05685f7 | ||
|
|
1063c930b5 | ||
|
|
79cbd44366 | ||
|
|
7fdac1c5cb | ||
|
|
0c0cf72ebb | ||
|
|
8e2fe175ed | ||
|
|
d1cff037c9 | ||
|
|
fc88a2fafa | ||
|
|
45fcceb056 | ||
|
|
7043477038 | ||
|
|
7dd685cf54 | ||
|
|
5f5e4969c0 | ||
|
|
8a53fd19e9 | ||
|
|
baf4714c36 | ||
|
|
7ba9ac7a5b | ||
|
|
85b8f26e8e | ||
|
|
594a0f1410 | ||
|
|
d317d757d7 | ||
|
|
fdf0ba6318 | ||
|
|
15bf7de5fa | ||
|
|
d3402b058e | ||
|
|
e7dfdd4031 | ||
|
|
b2dd7b6364 | ||
|
|
9bd6d9abbf | ||
|
|
cd14428fea | ||
|
|
19d9f03c2b | ||
|
|
0d57e72bbf | ||
|
|
329516a61b | ||
|
|
d566869589 | ||
|
|
9cb8d8e6c7 | ||
|
|
9de3c57e5d | ||
|
|
f32ff92b0b | ||
|
|
88d71e271e | ||
|
|
fd9c14612a | ||
|
|
e26e5a160f | ||
|
|
b836bfed22 | ||
|
|
a4b598c6d0 | ||
|
|
c9ab755839 | ||
|
|
9920edba53 | ||
|
|
12bd7280d1 | ||
|
|
d30ea7f63b | ||
|
|
ebd3390db6 | ||
|
|
9a374a9ebc | ||
|
|
b1bc22cb08 | ||
|
|
4930d53890 | ||
|
|
c31327b5bc | ||
|
|
3f2aa1f1e1 | ||
|
|
6e78c00a96 | ||
|
|
c27dde085e | ||
|
|
d26cc308c0 | ||
|
|
fb1efdf290 | ||
|
|
3c99f2a472 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -363,4 +363,6 @@ MigrationBackup/
|
||||
FodyWeavers.xsd
|
||||
|
||||
|
||||
/framework/*pro*
|
||||
/framework/*Pro*
|
||||
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
[*.cs]
|
||||
|
||||
# CA1848: 使用 LoggerMessage 委托
|
||||
dotnet_diagnostic.CA1848.severity = none
|
||||
|
||||
# CA2254: 模板应为静态表达式
|
||||
dotnet_diagnostic.CA2254.severity = suggestion
|
||||
|
||||
[*.cs]
|
||||
#### 命名样式 ####
|
||||
|
||||
# 命名规则
|
||||
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
|
||||
|
||||
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
|
||||
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
|
||||
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
|
||||
|
||||
# 符号规范
|
||||
|
||||
dotnet_naming_symbols.interface.applicable_kinds = interface
|
||||
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.interface.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
|
||||
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.types.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
|
||||
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.non_field_members.required_modifiers =
|
||||
|
||||
# 命名样式
|
||||
|
||||
dotnet_naming_style.begins_with_i.required_prefix = I
|
||||
dotnet_naming_style.begins_with_i.required_suffix =
|
||||
dotnet_naming_style.begins_with_i.word_separator =
|
||||
dotnet_naming_style.begins_with_i.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
|
||||
[*.vb]
|
||||
#### 命名样式 ####
|
||||
|
||||
# 命名规则
|
||||
|
||||
dotnet_naming_rule.interface_should_be_以_i_开始.severity = suggestion
|
||||
dotnet_naming_rule.interface_should_be_以_i_开始.symbols = interface
|
||||
dotnet_naming_rule.interface_should_be_以_i_开始.style = 以_i_开始
|
||||
|
||||
dotnet_naming_rule.类型_should_be_帕斯卡拼写法.severity = suggestion
|
||||
dotnet_naming_rule.类型_should_be_帕斯卡拼写法.symbols = 类型
|
||||
dotnet_naming_rule.类型_should_be_帕斯卡拼写法.style = 帕斯卡拼写法
|
||||
|
||||
dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.severity = suggestion
|
||||
dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.symbols = 非字段成员
|
||||
dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.style = 帕斯卡拼写法
|
||||
|
||||
# 符号规范
|
||||
|
||||
dotnet_naming_symbols.interface.applicable_kinds = interface
|
||||
dotnet_naming_symbols.interface.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
|
||||
dotnet_naming_symbols.interface.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.类型.applicable_kinds = class, struct, interface, enum
|
||||
dotnet_naming_symbols.类型.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
|
||||
dotnet_naming_symbols.类型.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.非字段成员.applicable_kinds = property, event, method
|
||||
dotnet_naming_symbols.非字段成员.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
|
||||
dotnet_naming_symbols.非字段成员.required_modifiers =
|
||||
|
||||
# 命名样式
|
||||
|
||||
dotnet_naming_style.以_i_开始.required_prefix = I
|
||||
dotnet_naming_style.以_i_开始.required_suffix =
|
||||
dotnet_naming_style.以_i_开始.word_separator =
|
||||
dotnet_naming_style.以_i_开始.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.帕斯卡拼写法.required_prefix =
|
||||
dotnet_naming_style.帕斯卡拼写法.required_suffix =
|
||||
dotnet_naming_style.帕斯卡拼写法.word_separator =
|
||||
dotnet_naming_style.帕斯卡拼写法.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.帕斯卡拼写法.required_prefix =
|
||||
dotnet_naming_style.帕斯卡拼写法.required_suffix =
|
||||
dotnet_naming_style.帕斯卡拼写法.word_separator =
|
||||
dotnet_naming_style.帕斯卡拼写法.capitalization = pascal_case
|
||||
63
framework/.gitattributes
vendored
63
framework/.gitattributes
vendored
@@ -1,63 +0,0 @@
|
||||
###############################################################################
|
||||
# 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
|
||||
364
framework/.gitignore
vendored
364
framework/.gitignore
vendored
@@ -1,364 +0,0 @@
|
||||
## 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/
|
||||
[Oo]ut/
|
||||
[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/
|
||||
|
||||
# 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
|
||||
|
||||
@@ -1,152 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
|
||||
<PropertyGroup Condition="'$(SolutionName)'=='ThingsGateway - Pro'">
|
||||
<DefineConstants>Pro</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Condition="'$(SolutionName)'=='ThingsGateway - Pro'">
|
||||
|
||||
|
||||
|
||||
<Compile Include="..\..\PluginPro\ThingsGateway.Plugin.Melsec\Page\QnA3E_BinaryDebugPage.razor.cs" Link="Pages\Melsec\QnA3E_BinaryDebugPage.razor.cs" />
|
||||
<Content Include="..\..\PluginPro\ThingsGateway.Plugin.Melsec\Page\QnA3E_BinaryDebugPage.razor" Link="Pages\Melsec\QnA3E_BinaryDebugPage.razor" />
|
||||
<ProjectReference Include="..\..\FoundationPro\ThingsGateway.Foundation.Adapter.Melsec\ThingsGateway.Foundation.Adapter.Melsec.csproj" />
|
||||
|
||||
|
||||
|
||||
<Compile Include="..\..\PluginPro\ThingsGateway.Plugin.AllenBradleyCip\Page\AllenBradleyCipTcpDebugPage.razor.cs" Link="Pages\ABCIP\AllenBradleyCipTcpDebugPage.razor.cs" />
|
||||
<Content Include="..\..\PluginPro\ThingsGateway.Plugin.AllenBradleyCip\Page\AllenBradleyCipTcpDebugPage.razor" Link="Pages\ABCIP\AllenBradleyCipTcpDebugPage.razor" />
|
||||
<ProjectReference Include="..\..\FoundationPro\ThingsGateway.Foundation.Adapter.AllenBradleyCip\ThingsGateway.Foundation.Adapter.AllenBradleyCip.csproj" />
|
||||
|
||||
<Compile Include="..\..\PluginPro\ThingsGateway.Plugin.Omron\Page\OmronFinsTcpDebugPage.razor.cs" Link="Pages\OmronFins\OmronFinsTcpDebugPage.razor.cs" />
|
||||
<Compile Include="..\..\PluginPro\ThingsGateway.Plugin.Omron\Page\OmronFinsUdpDebugPage.razor.cs" Link="Pages\OmronFins\OmronFinsUdpDebugPage.razor.cs" />
|
||||
<Content Include="..\..\PluginPro\ThingsGateway.Plugin.Omron\Page\OmronFinsTcpDebugPage.razor" Link="Pages\OmronFins\OmronFinsTcpDebugPage.razor" />
|
||||
<Content Include="..\..\PluginPro\ThingsGateway.Plugin.Omron\Page\OmronFinsUdpDebugPage.razor" Link="Pages\OmronFins\OmronFinsUdpDebugPage.razor" />
|
||||
<ProjectReference Include="..\..\FoundationPro\ThingsGateway.Foundation.Adapter.Omron\ThingsGateway.Foundation.Adapter.Omron.csproj" />
|
||||
|
||||
<Compile Include="..\..\PluginPro\ThingsGateway.Plugin.Secs\Page\SecsHsmsTcpDebugPage.razor.cs" Link="Pages\Secs\SecsHsmsTcpDebugPage.razor.cs" />
|
||||
<Content Include="..\..\PluginPro\ThingsGateway.Plugin.Secs\Page\SecsHsmsTcpDebugPage.razor" Link="Pages\Secs\SecsHsmsTcpDebugPage.razor" />
|
||||
<ProjectReference Include="..\..\FoundationPro\ThingsGateway.Foundation.Adapter.Secs\ThingsGateway.Foundation.Adapter.Secs.csproj" />
|
||||
|
||||
|
||||
<Compile Include="..\..\PluginPro\ThingsGateway.Plugin.TS550\Page\TS550DebugPage.razor.cs" Link="Pages\TS550\TS550DebugPage.razor.cs" />
|
||||
<Content Include="..\..\PluginPro\ThingsGateway.Plugin.TS550\Page\TS550DebugPage.razor" Link="Pages\TS550\TS550DebugPage.razor" />
|
||||
<ProjectReference Include="..\..\FoundationPro\ThingsGateway.Foundation.Adapter.TS550\ThingsGateway.Foundation.Adapter.TS550.csproj" />
|
||||
|
||||
<Compile Include="..\..\PluginPro\ThingsGateway.Plugin.Vigor\Page\VigorSerialDebugPage.razor.cs" Link="Pages\Vigor\VigorSerialDebugPage.razor.cs" />
|
||||
<Compile Include="..\..\PluginPro\ThingsGateway.Plugin.Vigor\Page\VigorSerialOverTcpDebugPage.razor.cs" Link="Pages\Vigor\VigorSerialOverTcpDebugPage.razor.cs" />
|
||||
<Content Include="..\..\PluginPro\ThingsGateway.Plugin.Vigor\Page\VigorSerialDebugPage.razor" Link="Pages\Vigor\VigorSerialDebugPage.razor" />
|
||||
<Content Include="..\..\PluginPro\ThingsGateway.Plugin.Vigor\Page\VigorSerialOverTcpDebugPage.razor" Link="Pages\Vigor\VigorSerialOverTcpDebugPage.razor" />
|
||||
<ProjectReference Include="..\..\FoundationPro\ThingsGateway.Foundation.Adapter.Vigor\ThingsGateway.Foundation.Adapter.Vigor.csproj" />
|
||||
|
||||
|
||||
<Compile Include="..\..\PluginProAF2021\ThingsGateway.Plugin.HZW_QTJC_01\Page\HZW_QTJC_01SerialDebugPage.razor.cs" Link="Pages\HZW_QTJC_01\HZW_QTJC_01SerialDebugPage.razor.cs" />
|
||||
<Compile Include="..\..\PluginProAF2021\ThingsGateway.Plugin.HZW_QTJC_01\Page\HZW_QTJC_01SerialOverTcpDebugPage.razor.cs" Link="Pages\HZW_QTJC_01\HZW_QTJC_01SerialOverTcpDebugPage.razor.cs" />
|
||||
<Content Include="..\..\PluginProAF2021\ThingsGateway.Plugin.HZW_QTJC_01\Page\HZW_QTJC_01SerialDebugPage.razor" Link="Pages\HZW_QTJC_01\HZW_QTJC_01SerialDebugPage.razor" />
|
||||
<Content Include="..\..\PluginProAF2021\ThingsGateway.Plugin.HZW_QTJC_01\Page\HZW_QTJC_01SerialOverTcpDebugPage.razor" Link="Pages\HZW_QTJC_01\HZW_QTJC_01SerialOverTcpDebugPage.razor" />
|
||||
<ProjectReference Include="..\..\PluginProAF2021\ThingsGateway.Foundation.Adapter.HZW_QTJC_01\ThingsGateway.Foundation.Adapter.HZW_QTJC_01.csproj" />
|
||||
|
||||
|
||||
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.DLT645\Page\DLT645_2007DebugPage.razor.cs" Link="Pages\DLT645\DLT645_2007DebugPage.razor.cs" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\MqttRpcNameVaueWithId.cs" Link="Pages\Mqtt\MqttRpcNameVaueWithId.cs" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\Page\MqttClientDebugPage.razor.cs" Link="Pages\Mqtt\MqttClientDebugPage.razor.cs" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\Page\MqttClientPage.razor.cs" Link="Pages\Mqtt\MqttClientPage.razor.cs" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\PrivateLogger.cs" Link="Pages\Mqtt\PrivateLogger.cs" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\RpcClass\MqttRpcClient.cs" Link="Pages\Mqtt\MqttRpcClient.cs" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\RpcClass\MqttRpcClientExtensions.cs" Link="Pages\Mqtt\MqttRpcClientExtensions.cs" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\RpcClass\MqttRpcTopicPair.cs" Link="Pages\Mqtt\MqttRpcTopicPair.cs" />
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.DLT645\Page\DLT645_2007DebugPage.razor" Link="Pages\DLT645\DLT645_2007DebugPage.razor" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.DLT645\Page\DLT645_2007OverTcpDebugPage.razor.cs" Link="Pages\DLT645\DLT645_2007OverTcpDebugPage.razor.cs" />
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.DLT645\Page\DLT645_2007OverTcpDebugPage.razor" Link="Pages\DLT645\DLT645_2007OverTcpDebugPage.razor" />
|
||||
|
||||
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusRtuDebugPage.razor.cs" Link="Pages\Modbus\ModbusRtuDebugPage.razor.cs" />
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusRtuDebugPage.razor" Link="Pages\Modbus\ModbusRtuDebugPage.razor" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusRtuOverTcpDebugPage.razor.cs" Link="Pages\Modbus\ModbusRtuOverTcpDebugPage.razor.cs" />
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusRtuOverTcpDebugPage.razor" Link="Pages\Modbus\ModbusRtuOverTcpDebugPage.razor" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusRtuOverUdpDebugPage.razor.cs" Link="Pages\Modbus\ModbusRtuOverUdpDebugPage.razor.cs" />
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusRtuOverUdpDebugPage.razor" Link="Pages\Modbus\ModbusRtuOverUdpDebugPage.razor" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusSerialServerDebugPage.razor.cs" Link="Pages\Modbus\ModbusSerialServerDebugPage.razor.cs" />
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusSerialServerDebugPage.razor" Link="Pages\Modbus\ModbusSerialServerDebugPage.razor" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusTcpDebugPage.razor.cs" Link="Pages\Modbus\ModbusTcpDebugPage.razor.cs" />
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusTcpDebugPage.razor" Link="Pages\Modbus\ModbusTcpDebugPage.razor" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusTcpDtuDebugPage.razor.cs" Link="Pages\Modbus\ModbusTcpDtuDebugPage.razor.cs" />
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusTcpDtuDebugPage.razor" Link="Pages\Modbus\ModbusTcpDtuDebugPage.razor" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusTcpServerDebugPage.razor.cs" Link="Pages\Modbus\ModbusTcpServerDebugPage.razor.cs" />
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusTcpServerDebugPage.razor" Link="Pages\Modbus\ModbusTcpServerDebugPage.razor" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusUdpDebugPage.razor.cs" Link="Pages\Modbus\ModbusUdpDebugPage.razor.cs" />
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusUdpDebugPage.razor" Link="Pages\Modbus\ModbusUdpDebugPage.razor" />
|
||||
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.OPCDA\Page\OPCDAClientDebugPage.razor.cs" Link="Pages\OPCDA\OPCDAClientDebugPage.razor.cs" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.OPCDA\Page\OPCDAClientPage.razor.cs" Link="Pages\OPCDA\OPCDAClientPage.razor.cs" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.OPCDA\Page\OPCDAImportVariable.razor.cs" Link="Pages\OPCDA\OPCDAImportVariable.razor.cs" />
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.OPCDA\Page\OPCDAClientDebugPage.razor" Link="Pages\OPCDA\OPCDAClientDebugPage.razor" />
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.OPCDA\Page\OPCDAClientPage.razor" Link="Pages\OPCDA\OPCDAClientPage.razor" />
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.OPCDA\Page\OPCDAImportVariable.razor" Link="Pages\OPCDA\OPCDAImportVariable.razor" />
|
||||
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.OPCUA\Page\OPCUAClientDebugPage.razor" Link="Pages\OPCUA\OPCUAClientDebugPage.razor" />
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.OPCUA\Page\OPCUAClientPage.razor" Link="Pages\OPCUA\OPCUAClientPage.razor" />
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.OPCUA\Page\OPCUAImportVariable.razor" Link="Pages\OPCUA\OPCUAImportVariable.razor" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.OPCUA\Page\OPCUAClientDebugPage.razor.cs" Link="Pages\OPCUA\OPCUAClientDebugPage.razor.cs" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.OPCUA\Page\OPCUAClientPage.razor.cs" Link="Pages\OPCUA\OPCUAClientPage.razor.cs" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.OPCUA\Page\OPCUAImportVariable.razor.cs" Link="Pages\OPCUA\OPCUAImportVariable.razor.cs" />
|
||||
|
||||
|
||||
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_1200DebugPage.razor" Link="Pages\Siemens\S7_1200DebugPage.razor" />
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_1500DebugPage.razor" Link="Pages\Siemens\S7_1500DebugPage.razor" />
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_200DebugPage.razor" Link="Pages\Siemens\S7_200DebugPage.razor" />
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_200SMARTDebugPage.razor" Link="Pages\Siemens\S7_200SMARTDebugPage.razor" />
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_300DebugPage.razor" Link="Pages\Siemens\S7_300DebugPage.razor" />
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_400DebugPage.razor" Link="Pages\Siemens\S7_400DebugPage.razor" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_1200DebugPage.razor.cs" Link="Pages\Siemens\S7_1200DebugPage.razor.cs" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_1500DebugPage.razor.cs" Link="Pages\Siemens\S7_1500DebugPage.razor.cs" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_200DebugPage.razor.cs" Link="Pages\Siemens\S7_200DebugPage.razor.cs" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_200SMARTDebugPage.razor.cs" Link="Pages\Siemens\S7_200SMARTDebugPage.razor.cs" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_300DebugPage.razor.cs" Link="Pages\Siemens\S7_300DebugPage.razor.cs" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_400DebugPage.razor.cs" Link="Pages\Siemens\S7_400DebugPage.razor.cs" />
|
||||
|
||||
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup >
|
||||
<!--<PackageReference Include="ThingsGateway.Foundation.Adapter.DLT645" Version="*" />
|
||||
<PackageReference Include="ThingsGateway.Foundation.Adapter.Modbus" Version="*" />
|
||||
<PackageReference Include="ThingsGateway.Foundation.Adapter.OPCDA" Version="*" />
|
||||
<PackageReference Include="ThingsGateway.Foundation.Adapter.OPCUA" Version="*" />
|
||||
<PackageReference Include="ThingsGateway.Foundation.Adapter.Siemens" Version="*" />-->
|
||||
<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.DLT645\ThingsGateway.Foundation.Adapter.DLT645.csproj" />
|
||||
<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.Modbus\ThingsGateway.Foundation.Adapter.Modbus.csproj" />
|
||||
<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.OPCDA\ThingsGateway.Foundation.Adapter.OPCDA.csproj" />
|
||||
<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.OPCUA\ThingsGateway.Foundation.Adapter.OPCUA.csproj" />
|
||||
<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.Siemens\ThingsGateway.Foundation.Adapter.Siemens.csproj" />
|
||||
|
||||
</ItemGroup>
|
||||
<ItemGroup >
|
||||
<ProjectReference Include="..\..\Web\ThingsGateway.Components\ThingsGateway.Components.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="wwwroot\**">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\Page\MqttClientDebugPage.razor" Link="Pages\Mqtt\MqttClientDebugPage.razor" />
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\Page\MqttClientPage.razor" Link="Pages\Mqtt\MqttClientPage.razor" />
|
||||
<PackageReference Include="MQTTnet" Version="4.3.1.873" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
||||
</Project>
|
||||
@@ -1,480 +0,0 @@
|
||||
#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 System.ComponentModel;
|
||||
|
||||
using ThingsGateway.Foundation.Extension.Generic;
|
||||
|
||||
namespace ThingsGateway.Foundation.Adapter.DLT645;
|
||||
/// <summary>
|
||||
/// DLT645_2007
|
||||
/// </summary>
|
||||
public class DLT645_2007 : ReadWriteDevicesSerialSessionBase
|
||||
{
|
||||
/// <summary>
|
||||
/// DLT645_2007
|
||||
/// </summary>
|
||||
/// <param name="serialSession"></param>
|
||||
public DLT645_2007(SerialSession serialSession) : base(serialSession)
|
||||
{
|
||||
ThingsGatewayBitConverter = new DLT645_2007BitConverter(EndianType.Big);
|
||||
RegisterByteLength = 2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增加FE FE FE FE的报文头部
|
||||
/// </summary>
|
||||
[Description("前导符报文头")]
|
||||
public bool EnableFEHead { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 写入需操作员代码
|
||||
/// </summary>
|
||||
[Description("操作员代码")]
|
||||
public string OperCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 写入密码
|
||||
/// </summary>
|
||||
[Description("写入密码")]
|
||||
public string Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 通讯地址BCD码,一般应该是12个字符
|
||||
/// </summary>
|
||||
[Description("通讯地址")]
|
||||
public string Station { get; set; }
|
||||
/// <inheritdoc/>
|
||||
public override string GetAddressDescription()
|
||||
{
|
||||
|
||||
var str = """
|
||||
查看附带文档或者相关资料,下面列举一下常见的数据标识地址
|
||||
|
||||
地址 说明
|
||||
-----------------------------------------
|
||||
02010100 A相电压
|
||||
02020100 A相电流
|
||||
02030000 瞬时总有功功率
|
||||
00000000 (当前)组合有功总电能
|
||||
00010000 (当前)正向有功总电能
|
||||
|
||||
""";
|
||||
return base.GetAddressDescription() + Environment.NewLine + str;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack)
|
||||
{
|
||||
return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
Connect(cancellationToken);
|
||||
var commandResult = DLT645Helper.GetDLT645_2007Command(address, (byte)ControlCode.Read, Station);
|
||||
if (commandResult.IsSuccess)
|
||||
{
|
||||
var result = WaitingClientEx.SendThenResponse(commandResult.Content, TimeOut, cancellationToken);
|
||||
return (MessageBase)result.RequestInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult<byte[]>(commandResult);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<byte[]>(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
await ConnectAsync(cancellationToken);
|
||||
var commandResult = DLT645Helper.GetDLT645_2007Command(address, (byte)ControlCode.Read, Station);
|
||||
if (commandResult.IsSuccess)
|
||||
{
|
||||
var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken);
|
||||
return (MessageBase)result.RequestInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult<byte[]>(commandResult);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<byte[]>(ex);
|
||||
}
|
||||
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override void SetDataAdapter(object socketClient = null)
|
||||
{
|
||||
var dataHandleAdapter = new DLT645_2007DataHandleAdapter
|
||||
{
|
||||
EnableFEHead = EnableFEHead
|
||||
};
|
||||
SerialSession.SetDataHandlingAdapter(dataHandleAdapter);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override OperResult Write(string address, string value, CancellationToken cancellationToken = default)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
Connect(cancellationToken);
|
||||
Password ??= string.Empty;
|
||||
OperCode ??= string.Empty;
|
||||
if (Password.Length < 8)
|
||||
Password = Password.PadLeft(8, '0');
|
||||
if (OperCode.Length < 8)
|
||||
OperCode = OperCode.PadLeft(8, '0');
|
||||
var data = DataTransUtil.SpliceArray(Password.ByHexStringToBytes(), OperCode.ByHexStringToBytes());
|
||||
string[] strArray = value.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var commandResult = DLT645Helper.GetDLT645_2007Command(address, (byte)ControlCode.Write, Station, data, strArray);
|
||||
if (commandResult.IsSuccess)
|
||||
{
|
||||
var result = WaitingClientEx.SendThenResponse(commandResult.Content, TimeOut, cancellationToken);
|
||||
return (MessageBase)result.RequestInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult(commandResult);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<byte[]>(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default) => Write(address, value.ToString(), cancellationToken);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default) => Write(address, value.ToString(), cancellationToken);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task<OperResult> WriteAsync(string address, string value, CancellationToken cancellationToken = default)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
await ConnectAsync(cancellationToken);
|
||||
Password ??= string.Empty;
|
||||
OperCode ??= string.Empty;
|
||||
if (Password.Length < 8)
|
||||
Password = Password.PadLeft(8, '0');
|
||||
if (OperCode.Length < 8)
|
||||
OperCode = OperCode.PadLeft(8, '0');
|
||||
var data = DataTransUtil.SpliceArray(Password.ByHexStringToBytes(), OperCode.ByHexStringToBytes());
|
||||
string[] strArray = value.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var commandResult = DLT645Helper.GetDLT645_2007Command(address, (byte)ControlCode.Write, Station, data, strArray);
|
||||
if (commandResult.IsSuccess)
|
||||
{
|
||||
var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken);
|
||||
return (MessageBase)result.RequestInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult(commandResult);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<byte[]>(ex);
|
||||
}
|
||||
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
|
||||
/// <inheritdoc/>
|
||||
public override Task<OperResult> WriteAsync(string address, uint value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
|
||||
/// <inheritdoc/>
|
||||
public override Task<OperResult> WriteAsync(string address, double value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
|
||||
/// <inheritdoc/>
|
||||
public override Task<OperResult> WriteAsync(string address, float value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
|
||||
/// <inheritdoc/>
|
||||
public override Task<OperResult> WriteAsync(string address, long value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
|
||||
/// <inheritdoc/>
|
||||
public override Task<OperResult> WriteAsync(string address, ulong value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
|
||||
/// <inheritdoc/>
|
||||
public override Task<OperResult> WriteAsync(string address, ushort value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
|
||||
/// <inheritdoc/>
|
||||
public override Task<OperResult> WriteAsync(string address, short value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
|
||||
/// <inheritdoc/>
|
||||
public override Task<OperResult> WriteAsync(string address, int value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
|
||||
|
||||
|
||||
#region 其他方法
|
||||
|
||||
/// <summary>
|
||||
/// 广播校时
|
||||
/// </summary>
|
||||
/// <param name="dateTime"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public OperResult BroadcastTime(DateTime dateTime, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
Connect(cancellationToken);
|
||||
string str = $"{dateTime.Second:D2}{dateTime.Minute:D2}{dateTime.Hour:D2}{dateTime.Day:D2}{dateTime.Month:D2}{dateTime.Year % 100:D2}";
|
||||
var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.BroadcastTime, str.ByHexStringToBytes().ToArray(), "999999999999".ByHexStringToBytes());
|
||||
if (commandResult.IsSuccess)
|
||||
{
|
||||
SerialSession.Send(commandResult.Content);
|
||||
return OperResult.CreateSuccessResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult(commandResult);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<string>(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 冻结
|
||||
/// </summary>
|
||||
/// <param name="dateTime"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<OperResult> FreezeAsync(DateTime dateTime, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
await ConnectAsync(cancellationToken);
|
||||
string str = $"{dateTime.Minute:D2}{dateTime.Hour:D2}{dateTime.Day:D2}{dateTime.Month:D2}";
|
||||
if (Station.IsNullOrEmpty()) Station = string.Empty;
|
||||
if (Station.Length < 12) Station = Station.PadLeft(12, '0');
|
||||
var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.Freeze, str.ByHexStringToBytes().ToArray(), Station.ByHexStringToBytes().Reverse().ToArray());
|
||||
if (commandResult.IsSuccess)
|
||||
{
|
||||
var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken);
|
||||
var result1 = ((MessageBase)result.RequestInfo);
|
||||
if (result1.IsSuccess)
|
||||
{
|
||||
return OperResult.CreateSuccessResult();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult(result1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult(commandResult);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<string>(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 读取通信地址
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<OperResult<string>> ReadDeviceStationAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
await ConnectAsync(cancellationToken);
|
||||
var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.ReadStation, null, "AAAAAAAAAAAA".ByHexStringToBytes());
|
||||
if (commandResult.IsSuccess)
|
||||
{
|
||||
var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken);
|
||||
var result1 = ((MessageBase)result.RequestInfo);
|
||||
if (result1.IsSuccess)
|
||||
{
|
||||
var buffer = result1.Content.SelectMiddle(0, 6).BytesAdd(-0x33);
|
||||
return OperResult.CreateSuccessResult(buffer.Reverse().ToArray().ToHexString());
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult<string>(result1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult<string>(commandResult);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<string>(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 修改波特率
|
||||
/// </summary>
|
||||
/// <param name="baudRate"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<OperResult> WriteBaudRateAsync(int baudRate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
await ConnectAsync(cancellationToken);
|
||||
byte baudRateByte;
|
||||
switch (baudRate)
|
||||
{
|
||||
case 600: baudRateByte = 0x02; break;
|
||||
case 1200: baudRateByte = 0x04; break;
|
||||
case 2400: baudRateByte = 0x08; break;
|
||||
case 4800: baudRateByte = 0x10; break;
|
||||
case 9600: baudRateByte = 0x20; break;
|
||||
case 19200: baudRateByte = 0x40; break;
|
||||
default: return new OperResult<string>($"不支持此波特率:{baudRate}");
|
||||
}
|
||||
if (Station.IsNullOrEmpty()) Station = string.Empty;
|
||||
if (Station.Length < 12) Station = Station.PadLeft(12, '0');
|
||||
var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WriteBaudRate, new byte[] { baudRateByte }, Station.ByHexStringToBytes().Reverse().ToArray());
|
||||
if (commandResult.IsSuccess)
|
||||
{
|
||||
var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken);
|
||||
var result1 = ((MessageBase)result.RequestInfo);
|
||||
if (result1.IsSuccess)
|
||||
{
|
||||
return OperResult.CreateSuccessResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult(result1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult(commandResult);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<string>(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新通信地址
|
||||
/// </summary>
|
||||
/// <param name="station"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<OperResult> WriteDeviceStationAsync(string station, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
await ConnectAsync(cancellationToken);
|
||||
var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WriteStation, station.ByHexStringToBytes().Reverse().ToArray(), "AAAAAAAAAAAA".ByHexStringToBytes());
|
||||
if (commandResult.IsSuccess)
|
||||
{
|
||||
var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken);
|
||||
var result1 = ((MessageBase)result.RequestInfo);
|
||||
if (result1.IsSuccess)
|
||||
{
|
||||
return OperResult.CreateSuccessResult();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult(result1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult(commandResult);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<string>(ex);
|
||||
}
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 修改密码
|
||||
/// </summary>
|
||||
/// <param name="level"></param>
|
||||
/// <param name="oldPassword"></param>
|
||||
/// <param name="newPassword"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<OperResult> WritePasswordAsync(byte level, string oldPassword, string newPassword, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
await ConnectAsync(cancellationToken);
|
||||
|
||||
if (Station.IsNullOrEmpty()) Station = string.Empty;
|
||||
if (Station.Length < 12) Station = Station.PadLeft(12, '0');
|
||||
string str = $"04000C{level + 1:D2}";
|
||||
|
||||
var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WritePassword,
|
||||
str.ByHexStringToBytes().Reverse().ToArray()
|
||||
.SpliceArray(oldPassword.ByHexStringToBytes().Reverse().ToArray())
|
||||
.SpliceArray(newPassword.ByHexStringToBytes().Reverse().ToArray())
|
||||
, Station.ByHexStringToBytes().Reverse().ToArray());
|
||||
if (commandResult.IsSuccess)
|
||||
{
|
||||
var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken);
|
||||
var result1 = ((MessageBase)result.RequestInfo);
|
||||
if (result1.IsSuccess)
|
||||
{
|
||||
return OperResult.CreateSuccessResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult(result1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult(commandResult);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<string>(ex);
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
@@ -1,480 +0,0 @@
|
||||
#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 System.ComponentModel;
|
||||
|
||||
using ThingsGateway.Foundation.Extension.Generic;
|
||||
|
||||
namespace ThingsGateway.Foundation.Adapter.DLT645;
|
||||
/// <summary>
|
||||
/// DLT645_2007
|
||||
/// </summary>
|
||||
public class DLT645_2007OverTcp : ReadWriteDevicesTcpClientBase
|
||||
{
|
||||
/// <summary>
|
||||
/// DLT645_2007
|
||||
/// </summary>
|
||||
/// <param name="tcpClient"></param>
|
||||
public DLT645_2007OverTcp(TcpClient tcpClient) : base(tcpClient)
|
||||
{
|
||||
ThingsGatewayBitConverter = new DLT645_2007BitConverter(EndianType.Big);
|
||||
RegisterByteLength = 2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增加FE FE FE FE的报文头部
|
||||
/// </summary>
|
||||
[Description("前导符报文头")]
|
||||
public bool EnableFEHead { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 写入需操作员代码
|
||||
/// </summary>
|
||||
[Description("操作员代码")]
|
||||
public string OperCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 写入密码
|
||||
/// </summary>
|
||||
[Description("写入密码")]
|
||||
public string Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 通讯地址BCD码,一般应该是12个字符
|
||||
/// </summary>
|
||||
[Description("通讯地址")]
|
||||
public string Station { get; set; }
|
||||
/// <inheritdoc/>
|
||||
public override string GetAddressDescription()
|
||||
{
|
||||
|
||||
var str = """
|
||||
查看附带文档或者相关资料,下面列举一下常见的数据标识地址
|
||||
|
||||
地址 说明
|
||||
-----------------------------------------
|
||||
02010100 A相电压
|
||||
02020100 A相电流
|
||||
02030000 瞬时总有功功率
|
||||
00000000 (当前)组合有功总电能
|
||||
00010000 (当前)正向有功总电能
|
||||
|
||||
""";
|
||||
return base.GetAddressDescription() + Environment.NewLine + str;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack)
|
||||
{
|
||||
return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
Connect(cancellationToken);
|
||||
var commandResult = DLT645Helper.GetDLT645_2007Command(address, (byte)ControlCode.Read, Station);
|
||||
if (commandResult.IsSuccess)
|
||||
{
|
||||
var result = WaitingClientEx.SendThenResponse(commandResult.Content, TimeOut, cancellationToken);
|
||||
return (MessageBase)result.RequestInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult<byte[]>(commandResult);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<byte[]>(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
await ConnectAsync(cancellationToken);
|
||||
var commandResult = DLT645Helper.GetDLT645_2007Command(address, (byte)ControlCode.Read, Station);
|
||||
if (commandResult.IsSuccess)
|
||||
{
|
||||
var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken);
|
||||
return (MessageBase)result.RequestInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult<byte[]>(commandResult);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<byte[]>(ex);
|
||||
}
|
||||
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override void SetDataAdapter(object socketClient = null)
|
||||
{
|
||||
var dataHandleAdapter = new DLT645_2007DataHandleAdapter
|
||||
{
|
||||
EnableFEHead = EnableFEHead
|
||||
};
|
||||
TcpClient.SetDataHandlingAdapter(dataHandleAdapter);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override OperResult Write(string address, string value, CancellationToken cancellationToken = default)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
Connect(cancellationToken);
|
||||
Password ??= string.Empty;
|
||||
OperCode ??= string.Empty;
|
||||
if (Password.Length < 8)
|
||||
Password = Password.PadLeft(8, '0');
|
||||
if (OperCode.Length < 8)
|
||||
OperCode = OperCode.PadLeft(8, '0');
|
||||
var data = DataTransUtil.SpliceArray(Password.ByHexStringToBytes(), OperCode.ByHexStringToBytes());
|
||||
string[] strArray = value.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var commandResult = DLT645Helper.GetDLT645_2007Command(address, (byte)ControlCode.Write, Station, data, strArray);
|
||||
if (commandResult.IsSuccess)
|
||||
{
|
||||
var result = WaitingClientEx.SendThenResponse(commandResult.Content, TimeOut, cancellationToken);
|
||||
return (MessageBase)result.RequestInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult(commandResult);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<byte[]>(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default) => Write(address, value.ToString(), cancellationToken);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default) => Write(address, value.ToString(), cancellationToken);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task<OperResult> WriteAsync(string address, string value, CancellationToken cancellationToken = default)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
await ConnectAsync(cancellationToken);
|
||||
Password ??= string.Empty;
|
||||
OperCode ??= string.Empty;
|
||||
if (Password.Length < 8)
|
||||
Password = Password.PadLeft(8, '0');
|
||||
if (OperCode.Length < 8)
|
||||
OperCode = OperCode.PadLeft(8, '0');
|
||||
var data = DataTransUtil.SpliceArray(Password.ByHexStringToBytes(), OperCode.ByHexStringToBytes());
|
||||
string[] strArray = value.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var commandResult = DLT645Helper.GetDLT645_2007Command(address, (byte)ControlCode.Write, Station, data, strArray);
|
||||
if (commandResult.IsSuccess)
|
||||
{
|
||||
var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken);
|
||||
return (MessageBase)result.RequestInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult(commandResult);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<byte[]>(ex);
|
||||
}
|
||||
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
|
||||
/// <inheritdoc/>
|
||||
public override Task<OperResult> WriteAsync(string address, uint value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
|
||||
/// <inheritdoc/>
|
||||
public override Task<OperResult> WriteAsync(string address, double value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
|
||||
/// <inheritdoc/>
|
||||
public override Task<OperResult> WriteAsync(string address, float value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
|
||||
/// <inheritdoc/>
|
||||
public override Task<OperResult> WriteAsync(string address, long value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
|
||||
/// <inheritdoc/>
|
||||
public override Task<OperResult> WriteAsync(string address, ulong value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
|
||||
/// <inheritdoc/>
|
||||
public override Task<OperResult> WriteAsync(string address, ushort value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
|
||||
/// <inheritdoc/>
|
||||
public override Task<OperResult> WriteAsync(string address, short value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
|
||||
/// <inheritdoc/>
|
||||
public override Task<OperResult> WriteAsync(string address, int value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
|
||||
|
||||
|
||||
#region 其他方法
|
||||
|
||||
/// <summary>
|
||||
/// 广播校时
|
||||
/// </summary>
|
||||
/// <param name="dateTime"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public OperResult BroadcastTime(DateTime dateTime, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
Connect(cancellationToken);
|
||||
string str = $"{dateTime.Second:D2}{dateTime.Minute:D2}{dateTime.Hour:D2}{dateTime.Day:D2}{dateTime.Month:D2}{dateTime.Year % 100:D2}";
|
||||
var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.BroadcastTime, str.ByHexStringToBytes().Reverse().ToArray(), "999999999999".ByHexStringToBytes());
|
||||
if (commandResult.IsSuccess)
|
||||
{
|
||||
TcpClient.Send(commandResult.Content);
|
||||
return OperResult.CreateSuccessResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult(commandResult);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<string>(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 冻结
|
||||
/// </summary>
|
||||
/// <param name="dateTime"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<OperResult> FreezeAsync(DateTime dateTime, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
await ConnectAsync(cancellationToken);
|
||||
string str = $"{dateTime.Minute:D2}{dateTime.Hour:D2}{dateTime.Day:D2}{dateTime.Month:D2}";
|
||||
if (Station.IsNullOrEmpty()) Station = string.Empty;
|
||||
if (Station.Length < 12) Station = Station.PadLeft(12, '0');
|
||||
var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.Freeze, str.ByHexStringToBytes().Reverse().ToArray(), Station.ByHexStringToBytes().Reverse().ToArray());
|
||||
if (commandResult.IsSuccess)
|
||||
{
|
||||
var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken);
|
||||
var result1 = ((MessageBase)result.RequestInfo);
|
||||
if (result1.IsSuccess)
|
||||
{
|
||||
return OperResult.CreateSuccessResult();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult(result1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult(commandResult);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<string>(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 读取通信地址
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<OperResult<string>> ReadDeviceStationAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
await ConnectAsync(cancellationToken);
|
||||
var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.ReadStation, null, "AAAAAAAAAAAA".ByHexStringToBytes());
|
||||
if (commandResult.IsSuccess)
|
||||
{
|
||||
var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken);
|
||||
var result1 = ((MessageBase)result.RequestInfo);
|
||||
if (result1.IsSuccess)
|
||||
{
|
||||
var buffer = result1.Content.SelectMiddle(0, 6).BytesAdd(-0x33);
|
||||
return OperResult.CreateSuccessResult(buffer.Reverse().ToArray().ToHexString());
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult<string>(result1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult<string>(commandResult);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<string>(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 修改波特率
|
||||
/// </summary>
|
||||
/// <param name="baudRate"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<OperResult> WriteBaudRateAsync(int baudRate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
await ConnectAsync(cancellationToken);
|
||||
byte baudRateByte;
|
||||
switch (baudRate)
|
||||
{
|
||||
case 600: baudRateByte = 0x02; break;
|
||||
case 1200: baudRateByte = 0x04; break;
|
||||
case 2400: baudRateByte = 0x08; break;
|
||||
case 4800: baudRateByte = 0x10; break;
|
||||
case 9600: baudRateByte = 0x20; break;
|
||||
case 19200: baudRateByte = 0x40; break;
|
||||
default: return new OperResult<string>($"不支持此波特率:{baudRate}");
|
||||
}
|
||||
if (Station.IsNullOrEmpty()) Station = string.Empty;
|
||||
if (Station.Length < 12) Station = Station.PadLeft(12, '0');
|
||||
var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WriteBaudRate, new byte[] { baudRateByte }, Station.ByHexStringToBytes().Reverse().ToArray());
|
||||
if (commandResult.IsSuccess)
|
||||
{
|
||||
var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken);
|
||||
var result1 = ((MessageBase)result.RequestInfo);
|
||||
if (result1.IsSuccess)
|
||||
{
|
||||
return OperResult.CreateSuccessResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult(result1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult(commandResult);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<string>(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新通信地址
|
||||
/// </summary>
|
||||
/// <param name="station"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<OperResult> WriteDeviceStationAsync(string station, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
await ConnectAsync(cancellationToken);
|
||||
var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WriteStation, station.ByHexStringToBytes().Reverse().ToArray(), "AAAAAAAAAAAA".ByHexStringToBytes());
|
||||
if (commandResult.IsSuccess)
|
||||
{
|
||||
var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken);
|
||||
var result1 = ((MessageBase)result.RequestInfo);
|
||||
if (result1.IsSuccess)
|
||||
{
|
||||
return OperResult.CreateSuccessResult();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult(result1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult(commandResult);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<string>(ex);
|
||||
}
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 修改密码
|
||||
/// </summary>
|
||||
/// <param name="level"></param>
|
||||
/// <param name="oldPassword"></param>
|
||||
/// <param name="newPassword"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<OperResult> WritePasswordAsync(byte level, string oldPassword, string newPassword, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
await ConnectAsync(cancellationToken);
|
||||
|
||||
if (Station.IsNullOrEmpty()) Station = string.Empty;
|
||||
if (Station.Length < 12) Station = Station.PadLeft(12, '0');
|
||||
string str = $"04000C{level:D2}";
|
||||
|
||||
var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WritePassword,
|
||||
str.ByHexStringToBytes().Reverse().ToArray()
|
||||
.SpliceArray(oldPassword.ByHexStringToBytes().Reverse().ToArray())
|
||||
.SpliceArray(newPassword.ByHexStringToBytes().Reverse().ToArray())
|
||||
, Station.ByHexStringToBytes().Reverse().ToArray());
|
||||
if (commandResult.IsSuccess)
|
||||
{
|
||||
var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken);
|
||||
var result1 = ((MessageBase)result.RequestInfo);
|
||||
if (result1.IsSuccess)
|
||||
{
|
||||
return OperResult.CreateSuccessResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult(result1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult(commandResult);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<string>(ex);
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
@@ -1,452 +0,0 @@
|
||||
#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 System.Collections.Concurrent;
|
||||
|
||||
using ThingsGateway.Foundation.Extension.Bool;
|
||||
using ThingsGateway.Foundation.Extension.Generic;
|
||||
|
||||
namespace ThingsGateway.Foundation.Adapter.Modbus;
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public class ModbusSerialServer : ReadWriteDevicesSerialSessionBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 接收外部写入时,传出变量地址/写入字节组/转换规则/客户端
|
||||
/// </summary>
|
||||
public Func<ModbusAddress, byte[], IThingsGatewayBitConverter, SerialSession, Task<OperResult>> WriteData;
|
||||
|
||||
/// <summary>
|
||||
/// 继电器
|
||||
/// </summary>
|
||||
private ConcurrentDictionary<byte, ByteBlock> ModbusServer01ByteBlocks = new();
|
||||
|
||||
/// <summary>
|
||||
/// 开关输入
|
||||
/// </summary>
|
||||
private ConcurrentDictionary<byte, ByteBlock> ModbusServer02ByteBlocks = new();
|
||||
|
||||
/// <summary>
|
||||
/// 输入寄存器
|
||||
/// </summary>
|
||||
private ConcurrentDictionary<byte, ByteBlock> ModbusServer03ByteBlocks = new();
|
||||
|
||||
/// <summary>
|
||||
/// 保持寄存器
|
||||
/// </summary>
|
||||
private ConcurrentDictionary<byte, ByteBlock> ModbusServer04ByteBlocks = new();
|
||||
/// <inheritdoc/>
|
||||
public ModbusSerialServer(SerialSession serialSession) : base(serialSession)
|
||||
{
|
||||
ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big);
|
||||
RegisterByteLength = 2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 多站点
|
||||
/// </summary>
|
||||
public bool MulStation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 默认站点
|
||||
/// </summary>
|
||||
public byte Station { get; set; } = 1;
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Dispose()
|
||||
{
|
||||
foreach (var item in ModbusServer01ByteBlocks)
|
||||
{
|
||||
item.Value.SafeDispose();
|
||||
}
|
||||
foreach (var item in ModbusServer02ByteBlocks)
|
||||
{
|
||||
item.Value.SafeDispose();
|
||||
}
|
||||
foreach (var item in ModbusServer03ByteBlocks)
|
||||
{
|
||||
item.Value.SafeDispose();
|
||||
}
|
||||
foreach (var item in ModbusServer04ByteBlocks)
|
||||
{
|
||||
item.Value.SafeDispose();
|
||||
}
|
||||
ModbusServer01ByteBlocks.Clear();
|
||||
ModbusServer02ByteBlocks.Clear();
|
||||
ModbusServer03ByteBlocks.Clear();
|
||||
ModbusServer04ByteBlocks.Clear();
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GetAddressDescription()
|
||||
{
|
||||
return base.GetAddressDescription() + Environment.NewLine + ModbusHelper.GetAddressDescription();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack)
|
||||
{
|
||||
return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack);
|
||||
|
||||
}
|
||||
|
||||
EasyLock easyLock = new();
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
easyLock.Wait();
|
||||
|
||||
ModbusAddress mAddress;
|
||||
try
|
||||
{
|
||||
mAddress = ModbusAddress.ParseFrom(address, Station);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<byte[]>(ex);
|
||||
}
|
||||
if (MulStation)
|
||||
{
|
||||
Init(mAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Station != mAddress.Station)
|
||||
{
|
||||
return new OperResult<byte[]>("地址错误");
|
||||
}
|
||||
Init(mAddress);
|
||||
|
||||
}
|
||||
|
||||
var ModbusServer01ByteBlock = ModbusServer01ByteBlocks[mAddress.Station];
|
||||
var ModbusServer02ByteBlock = ModbusServer02ByteBlocks[mAddress.Station];
|
||||
var ModbusServer03ByteBlock = ModbusServer03ByteBlocks[mAddress.Station];
|
||||
var ModbusServer04ByteBlock = ModbusServer04ByteBlocks[mAddress.Station];
|
||||
int len = mAddress.ReadFunction == 2 || mAddress.ReadFunction == 1 ? length : length * RegisterByteLength;
|
||||
switch (mAddress.ReadFunction)
|
||||
{
|
||||
case 1:
|
||||
byte[] bytes0 = new byte[len];
|
||||
ModbusServer01ByteBlock.Pos = mAddress.AddressStart;
|
||||
ModbusServer01ByteBlock.Read(bytes0);
|
||||
return OperResult.CreateSuccessResult(bytes0);
|
||||
case 2:
|
||||
byte[] bytes1 = new byte[len];
|
||||
ModbusServer02ByteBlock.Pos = mAddress.AddressStart;
|
||||
ModbusServer02ByteBlock.Read(bytes1);
|
||||
return OperResult.CreateSuccessResult(bytes1);
|
||||
case 3:
|
||||
|
||||
byte[] bytes3 = new byte[len];
|
||||
ModbusServer03ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
|
||||
ModbusServer03ByteBlock.Read(bytes3);
|
||||
return OperResult.CreateSuccessResult(bytes3);
|
||||
case 4:
|
||||
byte[] bytes4 = new byte[len];
|
||||
ModbusServer04ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
|
||||
ModbusServer04ByteBlock.Read(bytes4);
|
||||
return OperResult.CreateSuccessResult(bytes4);
|
||||
}
|
||||
return new OperResult<byte[]>("功能码错误");
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
easyLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.FromResult(Read(address, length));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void SetDataAdapter(object socketClient)
|
||||
{
|
||||
ModbusSerialServerDataHandleAdapter dataHandleAdapter = new();
|
||||
dataHandleAdapter.CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout);
|
||||
SerialSession.SetDataHandlingAdapter(dataHandleAdapter);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
easyLock.Wait();
|
||||
ModbusAddress mAddress;
|
||||
try
|
||||
{
|
||||
mAddress = ModbusAddress.ParseFrom(address, Station);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult(ex);
|
||||
}
|
||||
if (MulStation)
|
||||
{
|
||||
Init(mAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Station != mAddress.Station)
|
||||
{
|
||||
return new OperResult("地址错误");
|
||||
}
|
||||
Init(mAddress);
|
||||
}
|
||||
var ModbusServer03ByteBlock = ModbusServer03ByteBlocks[mAddress.Station];
|
||||
var ModbusServer04ByteBlock = ModbusServer04ByteBlocks[mAddress.Station];
|
||||
switch (mAddress.ReadFunction)
|
||||
{
|
||||
case 3:
|
||||
ModbusServer03ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
|
||||
ModbusServer03ByteBlock.Write(value);
|
||||
return OperResult.CreateSuccessResult();
|
||||
case 4:
|
||||
ModbusServer04ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
|
||||
ModbusServer04ByteBlock.Write(value);
|
||||
return OperResult.CreateSuccessResult();
|
||||
}
|
||||
return new OperResult("功能码错误");
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
easyLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
easyLock.Wait();
|
||||
ModbusAddress mAddress;
|
||||
try
|
||||
{
|
||||
mAddress = ModbusAddress.ParseFrom(address, Station);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (new OperResult(ex));
|
||||
}
|
||||
if (MulStation)
|
||||
{
|
||||
Init(mAddress);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Station != mAddress.Station)
|
||||
{
|
||||
return (new OperResult("地址错误"));
|
||||
}
|
||||
Init(mAddress);
|
||||
|
||||
}
|
||||
|
||||
var ModbusServer01ByteBlock = ModbusServer01ByteBlocks[mAddress.Station];
|
||||
var ModbusServer02ByteBlock = ModbusServer02ByteBlocks[mAddress.Station];
|
||||
switch (mAddress.ReadFunction)
|
||||
{
|
||||
case 1:
|
||||
ModbusServer01ByteBlock.Pos = mAddress.AddressStart;
|
||||
ModbusServer01ByteBlock.Write(value.BoolArrayToByte());
|
||||
return (OperResult.CreateSuccessResult());
|
||||
case 2:
|
||||
ModbusServer02ByteBlock.Pos = mAddress.AddressStart;
|
||||
ModbusServer02ByteBlock.Write(value.BoolArrayToByte());
|
||||
return (OperResult.CreateSuccessResult());
|
||||
}
|
||||
return new OperResult("功能码错误");
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
easyLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.FromResult(Write(address, value));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.FromResult(Write(address, value));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override async Task Received(SerialSession client, ReceivedDataEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var requestInfo = e.RequestInfo;
|
||||
//接收外部报文
|
||||
if (requestInfo is ModbusSerialServerMessage modbusServerMessage)
|
||||
{
|
||||
if (modbusServerMessage.CurModbusAddress == null)
|
||||
{
|
||||
return;//无法解析直接返回
|
||||
}
|
||||
if (!modbusServerMessage.IsSuccess)
|
||||
{
|
||||
return;//无法解析直接返回
|
||||
}
|
||||
|
||||
if (modbusServerMessage.CurModbusAddress.WriteFunction == 0)//读取
|
||||
{
|
||||
var data = Read(modbusServerMessage.CurModbusAddress.ToString(), modbusServerMessage.Length);
|
||||
if (data.IsSuccess)
|
||||
{
|
||||
var coreData = data.Content;
|
||||
if (modbusServerMessage.CurModbusAddress.ReadFunction == 1 || modbusServerMessage.CurModbusAddress.ReadFunction == 2)
|
||||
{
|
||||
coreData = data.Content.Select(m => m > 0).ToArray().BoolArrayToByte().SelectMiddle(0, (int)Math.Ceiling(modbusServerMessage.Length / 8.0));
|
||||
}
|
||||
var sendData = modbusServerMessage.ReceivedBytes.SelectMiddle(0, 2).SpliceArray(new byte[] { (byte)coreData.Length }, coreData);
|
||||
SerialSession.Send(sendData);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteError(SerialSession, modbusServerMessage);//返回错误码
|
||||
}
|
||||
}
|
||||
else//写入
|
||||
{
|
||||
var coreData = modbusServerMessage.Content;
|
||||
if (modbusServerMessage.CurModbusAddress.ReadFunction == 1 || modbusServerMessage.CurModbusAddress.ReadFunction == 2)
|
||||
{
|
||||
//写入继电器
|
||||
if (WriteData != null)
|
||||
{
|
||||
// 接收外部写入时,传出变量地址/写入字节组/转换规则/客户端
|
||||
if ((await WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, SerialSession)).IsSuccess)
|
||||
{
|
||||
var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData.ByteToBoolArray(modbusServerMessage.Length));
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
WriteSuccess03(SerialSession, modbusServerMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteError(SerialSession, modbusServerMessage);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteError(SerialSession, modbusServerMessage);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//写入内存区
|
||||
var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData.ByteToBoolArray(modbusServerMessage.Length));
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
WriteSuccess03(SerialSession, modbusServerMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteError(SerialSession, modbusServerMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//写入寄存器
|
||||
if (WriteData != null)
|
||||
{
|
||||
|
||||
if ((await WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, SerialSession)).IsSuccess)
|
||||
{
|
||||
var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
WriteSuccess03(SerialSession, modbusServerMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteError(SerialSession, modbusServerMessage);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteError(SerialSession, modbusServerMessage);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
WriteSuccess03(SerialSession, modbusServerMessage);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteError(SerialSession, modbusServerMessage);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, ToString());
|
||||
}
|
||||
//返回错误码
|
||||
static void WriteError(SerialSession SerialSession, ModbusSerialServerMessage modbusServerMessage)
|
||||
{
|
||||
var sendData = modbusServerMessage.ReceivedBytes.SelectMiddle(0, 2)
|
||||
.SpliceArray(new byte[] { (byte)1 });//01 lllegal function
|
||||
sendData[1] = (byte)(sendData[1] + 128);
|
||||
SerialSession.Send(sendData);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteSuccess03(SerialSession SerialSession, ModbusSerialServerMessage modbusServerMessage)
|
||||
{
|
||||
var sendData = modbusServerMessage.ReceivedBytes.SelectMiddle(0, 6);
|
||||
SerialSession.Send(sendData);
|
||||
}
|
||||
|
||||
private void Init(ModbusAddress mAddress)
|
||||
{
|
||||
ModbusServer01ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
|
||||
ModbusServer02ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
|
||||
ModbusServer03ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
|
||||
ModbusServer04ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
|
||||
}
|
||||
}
|
||||
@@ -1,470 +0,0 @@
|
||||
#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 System.Collections.Concurrent;
|
||||
using System.ComponentModel;
|
||||
|
||||
using ThingsGateway.Foundation.Extension.Bool;
|
||||
using ThingsGateway.Foundation.Extension.Generic;
|
||||
|
||||
namespace ThingsGateway.Foundation.Adapter.Modbus;
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public class ModbusTcpServer : ReadWriteDevicesTcpServerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 接收外部写入时,传出变量地址/写入字节组/转换规则/客户端
|
||||
/// </summary>
|
||||
public Func<ModbusAddress, byte[], IThingsGatewayBitConverter, SocketClient, Task<OperResult>> WriteData;
|
||||
|
||||
/// <summary>
|
||||
/// 继电器
|
||||
/// </summary>
|
||||
private ConcurrentDictionary<byte, ByteBlock> ModbusServer01ByteBlocks = new();
|
||||
|
||||
/// <summary>
|
||||
/// 开关输入
|
||||
/// </summary>
|
||||
private ConcurrentDictionary<byte, ByteBlock> ModbusServer02ByteBlocks = new();
|
||||
|
||||
/// <summary>
|
||||
/// 输入寄存器
|
||||
/// </summary>
|
||||
private ConcurrentDictionary<byte, ByteBlock> ModbusServer03ByteBlocks = new();
|
||||
|
||||
/// <summary>
|
||||
/// 保持寄存器
|
||||
/// </summary>
|
||||
private ConcurrentDictionary<byte, ByteBlock> ModbusServer04ByteBlocks = new();
|
||||
/// <inheritdoc/>
|
||||
public ModbusTcpServer(TcpService tcpService) : base(tcpService)
|
||||
{
|
||||
ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big);
|
||||
RegisterByteLength = 2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 多站点
|
||||
/// </summary>
|
||||
[Description("多站点")]
|
||||
public bool MulStation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 默认站点
|
||||
/// </summary>
|
||||
[Description("默认站点")]
|
||||
public byte Station { get; set; } = 1;
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Dispose()
|
||||
{
|
||||
foreach (var item in ModbusServer01ByteBlocks)
|
||||
{
|
||||
item.Value.SafeDispose();
|
||||
}
|
||||
foreach (var item in ModbusServer02ByteBlocks)
|
||||
{
|
||||
item.Value.SafeDispose();
|
||||
}
|
||||
foreach (var item in ModbusServer03ByteBlocks)
|
||||
{
|
||||
item.Value.SafeDispose();
|
||||
}
|
||||
foreach (var item in ModbusServer04ByteBlocks)
|
||||
{
|
||||
item.Value.SafeDispose();
|
||||
}
|
||||
ModbusServer01ByteBlocks.Clear();
|
||||
ModbusServer02ByteBlocks.Clear();
|
||||
ModbusServer03ByteBlocks.Clear();
|
||||
ModbusServer04ByteBlocks.Clear();
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GetAddressDescription()
|
||||
{
|
||||
return base.GetAddressDescription() + Environment.NewLine + ModbusHelper.GetAddressDescription();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack)
|
||||
{
|
||||
return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack);
|
||||
|
||||
}
|
||||
|
||||
EasyLock easyLock = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
easyLock.Wait();
|
||||
|
||||
ModbusAddress mAddress;
|
||||
try
|
||||
{
|
||||
mAddress = ModbusAddress.ParseFrom(address, Station);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<byte[]>(ex);
|
||||
}
|
||||
if (MulStation)
|
||||
{
|
||||
Init(mAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Station != mAddress.Station)
|
||||
{
|
||||
return new OperResult<byte[]>("地址错误");
|
||||
}
|
||||
Init(mAddress);
|
||||
|
||||
}
|
||||
|
||||
var ModbusServer01ByteBlock = ModbusServer01ByteBlocks[mAddress.Station];
|
||||
var ModbusServer02ByteBlock = ModbusServer02ByteBlocks[mAddress.Station];
|
||||
var ModbusServer03ByteBlock = ModbusServer03ByteBlocks[mAddress.Station];
|
||||
var ModbusServer04ByteBlock = ModbusServer04ByteBlocks[mAddress.Station];
|
||||
int len = mAddress.ReadFunction == 2 || mAddress.ReadFunction == 1 ? length : length * RegisterByteLength;
|
||||
switch (mAddress.ReadFunction)
|
||||
{
|
||||
case 1:
|
||||
byte[] bytes0 = new byte[len];
|
||||
ModbusServer01ByteBlock.Pos = mAddress.AddressStart;
|
||||
ModbusServer01ByteBlock.Read(bytes0);
|
||||
return OperResult.CreateSuccessResult(bytes0);
|
||||
case 2:
|
||||
byte[] bytes1 = new byte[len];
|
||||
ModbusServer02ByteBlock.Pos = mAddress.AddressStart;
|
||||
ModbusServer02ByteBlock.Read(bytes1);
|
||||
return OperResult.CreateSuccessResult(bytes1);
|
||||
case 3:
|
||||
|
||||
byte[] bytes3 = new byte[len];
|
||||
ModbusServer03ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
|
||||
ModbusServer03ByteBlock.Read(bytes3);
|
||||
return OperResult.CreateSuccessResult(bytes3);
|
||||
case 4:
|
||||
byte[] bytes4 = new byte[len];
|
||||
ModbusServer04ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
|
||||
ModbusServer04ByteBlock.Read(bytes4);
|
||||
return OperResult.CreateSuccessResult(bytes4);
|
||||
}
|
||||
return new OperResult<byte[]>("功能码错误");
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
easyLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.FromResult(Read(address, length));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void SetDataAdapter(object socketClient)
|
||||
{
|
||||
if (socketClient is SocketClient client)
|
||||
{
|
||||
ModbusTcpServerDataHandleAdapter dataHandleAdapter = new();
|
||||
dataHandleAdapter.CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout);
|
||||
client.SetDataHandlingAdapter(dataHandleAdapter);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in TcpService.GetClients())
|
||||
{
|
||||
ModbusTcpDataHandleAdapter dataHandleAdapter = new()
|
||||
{
|
||||
CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout)
|
||||
};
|
||||
item.SetDataHandlingAdapter(dataHandleAdapter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
easyLock.Wait();
|
||||
ModbusAddress mAddress;
|
||||
try
|
||||
{
|
||||
mAddress = ModbusAddress.ParseFrom(address, Station);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult(ex);
|
||||
}
|
||||
if (MulStation)
|
||||
{
|
||||
Init(mAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Station != mAddress.Station)
|
||||
{
|
||||
return new OperResult("地址错误");
|
||||
}
|
||||
Init(mAddress);
|
||||
}
|
||||
var ModbusServer03ByteBlock = ModbusServer03ByteBlocks[mAddress.Station];
|
||||
var ModbusServer04ByteBlock = ModbusServer04ByteBlocks[mAddress.Station];
|
||||
switch (mAddress.ReadFunction)
|
||||
{
|
||||
case 3:
|
||||
ModbusServer03ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
|
||||
ModbusServer03ByteBlock.Write(value);
|
||||
return OperResult.CreateSuccessResult();
|
||||
case 4:
|
||||
ModbusServer04ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
|
||||
ModbusServer04ByteBlock.Write(value);
|
||||
return OperResult.CreateSuccessResult();
|
||||
}
|
||||
return new OperResult("功能码错误");
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
easyLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
easyLock.Wait();
|
||||
ModbusAddress mAddress;
|
||||
try
|
||||
{
|
||||
mAddress = ModbusAddress.ParseFrom(address, Station);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (new OperResult(ex));
|
||||
}
|
||||
if (MulStation)
|
||||
{
|
||||
Init(mAddress);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Station != mAddress.Station)
|
||||
{
|
||||
return (new OperResult("地址错误"));
|
||||
}
|
||||
Init(mAddress);
|
||||
|
||||
}
|
||||
|
||||
var ModbusServer01ByteBlock = ModbusServer01ByteBlocks[mAddress.Station];
|
||||
var ModbusServer02ByteBlock = ModbusServer02ByteBlocks[mAddress.Station];
|
||||
switch (mAddress.ReadFunction)
|
||||
{
|
||||
case 1:
|
||||
ModbusServer01ByteBlock.Pos = mAddress.AddressStart;
|
||||
ModbusServer01ByteBlock.Write(value.BoolArrayToByte());
|
||||
return (OperResult.CreateSuccessResult());
|
||||
case 2:
|
||||
ModbusServer02ByteBlock.Pos = mAddress.AddressStart;
|
||||
ModbusServer02ByteBlock.Write(value.BoolArrayToByte());
|
||||
return (OperResult.CreateSuccessResult());
|
||||
}
|
||||
return new OperResult("功能码错误");
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
easyLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.FromResult(Write(address, value));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.FromResult(Write(address, value));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override async Task Received(SocketClient client, ReceivedDataEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var requestInfo = e.RequestInfo;
|
||||
//接收外部报文
|
||||
if (requestInfo is ModbusTcpServerMessage modbusServerMessage)
|
||||
{
|
||||
if (modbusServerMessage.CurModbusAddress == null)
|
||||
{
|
||||
return;//无法解析直接返回
|
||||
}
|
||||
if (!modbusServerMessage.IsSuccess)
|
||||
{
|
||||
return;//无法解析直接返回
|
||||
}
|
||||
|
||||
if (modbusServerMessage.CurModbusAddress.WriteFunction == 0)//读取
|
||||
{
|
||||
var data = Read(modbusServerMessage.CurModbusAddress.ToString(), modbusServerMessage.Length);
|
||||
if (data.IsSuccess)
|
||||
{
|
||||
var coreData = data.Content;
|
||||
if (modbusServerMessage.CurModbusAddress.ReadFunction == 1 || modbusServerMessage.CurModbusAddress.ReadFunction == 2)
|
||||
{
|
||||
coreData = data.Content.Select(m => m > 0).ToArray().BoolArrayToByte().SelectMiddle(0, (int)Math.Ceiling(modbusServerMessage.Length / 8.0));
|
||||
}
|
||||
var sendData = modbusServerMessage.ReceivedBytes.SelectMiddle(0, 8).SpliceArray(new byte[] { (byte)coreData.Length }, coreData);
|
||||
sendData[5] = (byte)(sendData.Length - 6);
|
||||
client.Send(sendData);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteError(client, modbusServerMessage);//返回错误码
|
||||
}
|
||||
}
|
||||
else//写入
|
||||
{
|
||||
var coreData = modbusServerMessage.Content;
|
||||
if (modbusServerMessage.CurModbusAddress.ReadFunction == 1 || modbusServerMessage.CurModbusAddress.ReadFunction == 2)
|
||||
{
|
||||
//写入继电器
|
||||
if (WriteData != null)
|
||||
{
|
||||
// 接收外部写入时,传出变量地址/写入字节组/转换规则/客户端
|
||||
if ((await WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, client)).IsSuccess)
|
||||
{
|
||||
var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData.ByteToBoolArray(modbusServerMessage.Length));
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
WriteSuccess03(client, modbusServerMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteError(client, modbusServerMessage);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteError(client, modbusServerMessage);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//写入内存区
|
||||
var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData.ByteToBoolArray(modbusServerMessage.Length));
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
WriteSuccess03(client, modbusServerMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteError(client, modbusServerMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//写入寄存器
|
||||
if (WriteData != null)
|
||||
{
|
||||
|
||||
if ((await WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, client)).IsSuccess)
|
||||
{
|
||||
var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
WriteSuccess03(client, modbusServerMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteError(client, modbusServerMessage);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteError(client, modbusServerMessage);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
WriteSuccess03(client, modbusServerMessage);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteError(client, modbusServerMessage);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, ToString());
|
||||
}
|
||||
//返回错误码
|
||||
static void WriteError(SocketClient client, ModbusTcpServerMessage modbusServerMessage)
|
||||
{
|
||||
var sendData = modbusServerMessage.ReceivedBytes.SelectMiddle(0, 8)
|
||||
.SpliceArray(new byte[] { (byte)1 });//01 lllegal function
|
||||
sendData[5] = (byte)(sendData.Length - 6);
|
||||
sendData[7] = (byte)(sendData[7] + 128);
|
||||
client.Send(sendData);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteSuccess03(SocketClient client, ModbusTcpServerMessage modbusServerMessage)
|
||||
{
|
||||
var sendData = modbusServerMessage.ReceivedBytes.SelectMiddle(0, 12);
|
||||
sendData[5] = (byte)(sendData.Length - 6);
|
||||
client.Send(sendData);
|
||||
}
|
||||
|
||||
private void Init(ModbusAddress mAddress)
|
||||
{
|
||||
ModbusServer01ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
|
||||
ModbusServer02ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
|
||||
ModbusServer03ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
|
||||
ModbusServer04ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
|
||||
</Project>
|
||||
@@ -1,129 +0,0 @@
|
||||
#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 ThingsGateway.Foundation.Extension.Generic;
|
||||
|
||||
namespace ThingsGateway.Foundation.Adapter.Siemens;
|
||||
|
||||
public partial class SiemensS7PLC : ReadWriteDevicesTcpClientBase
|
||||
{
|
||||
private static OperResult<byte[]> GetWriteBitCommand(string address, bool data)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = SiemensAddress.ParseFrom(address);
|
||||
return SiemensHelper.GetWriteBitCommand(result, data);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private OperResult<List<byte[]>> GetReadByteCommand(string address, int length)
|
||||
{
|
||||
try
|
||||
{
|
||||
var from = SiemensAddress.ParseFrom(address, length);
|
||||
ushort num1 = 0;
|
||||
var listBytes = new List<byte[]>();
|
||||
while (num1 < length)
|
||||
{
|
||||
//pdu长度,重复生成报文,直至全部生成
|
||||
ushort num2 = (ushort)Math.Min(length - num1, pdu_length);
|
||||
from.Length = num2;
|
||||
var result = GetReadByteCommand(new SiemensAddress[1] { from });
|
||||
if (!result.IsSuccess) return new(result);
|
||||
listBytes.AddRange(result.Content);
|
||||
num1 += num2;
|
||||
if (from.DataCode == (byte)S7WordLength.Timer || from.DataCode == (byte)S7WordLength.Counter)
|
||||
{
|
||||
from.Address += num2 / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
from.Address += num2 * 8;
|
||||
}
|
||||
}
|
||||
return OperResult.CreateSuccessResult(listBytes);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<List<byte[]>>(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private OperResult<List<byte[]>> GetReadByteCommand(SiemensAddress[] siemensAddress)
|
||||
{
|
||||
if (siemensAddress.Length <= 19)
|
||||
{
|
||||
return ByteTransformUtil.GetResultFromBytes(SiemensHelper.GetReadCommand(siemensAddress), m => new List<byte[]>() { m });
|
||||
}
|
||||
|
||||
List<byte[]> byteList = new();
|
||||
List<SiemensAddress[]> s7AddressDataArrayList = siemensAddress.ArraySplitByLength(19);
|
||||
for (int index = 0; index < s7AddressDataArrayList.Count; ++index)
|
||||
{
|
||||
var result = GetReadByteCommand(s7AddressDataArrayList[index]);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
byteList.AddRange(result.Content);
|
||||
}
|
||||
return OperResult.CreateSuccessResult(byteList);
|
||||
}
|
||||
|
||||
private OperResult<List<byte[]>> GetWriteByteCommand(string address, byte[] value)
|
||||
{
|
||||
try
|
||||
{
|
||||
var s_Address = SiemensAddress.ParseFrom(address);
|
||||
|
||||
return GetWriteByteCommand(s_Address, value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new(ex);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// DefalutConverter
|
||||
/// </summary>
|
||||
public static ThingsGatewayBitConverter DefalutConverter = new(BitConverter.IsLittleEndian ? EndianType.Little : EndianType.Big);
|
||||
private OperResult<List<byte[]>> GetWriteByteCommand(SiemensAddress address, byte[] value)
|
||||
{
|
||||
int length1 = value.Length;
|
||||
ushort index = 0;
|
||||
List<byte[]> bytes = new();
|
||||
while (index < length1)
|
||||
{
|
||||
//pdu长度,重复生成报文,直至全部生成
|
||||
ushort length2 = (ushort)Math.Min(length1 - index, pdu_length);
|
||||
byte[] data = DefalutConverter.ToByte(value, index, length2);
|
||||
OperResult<byte[]> result1 = SiemensHelper.GetWriteByteCommand(address, data);
|
||||
if (!result1.IsSuccess)
|
||||
{
|
||||
return new(result1);
|
||||
}
|
||||
bytes.Add(result1.Content);
|
||||
index += length2;
|
||||
address.Address += length2 * 8;
|
||||
}
|
||||
return OperResult.CreateSuccessResult(bytes);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Foundation.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 读写扩展方法
|
||||
/// </summary>
|
||||
public static class ReadWriteDevicesExtensions
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 在返回的字节数组中解析每个变量的值
|
||||
/// 根据每个变量的<see cref="IDeviceVariableRunTime.Index"/>
|
||||
/// 不支持变长字符串类型变量,一定不能存在于变量List中
|
||||
/// </summary>
|
||||
/// <param name="values">设备变量List</param>
|
||||
/// <param name="plc">设备</param>
|
||||
/// <param name="buffer">返回的字节数组</param>
|
||||
/// <param name="startIndex">开始序号</param>
|
||||
public static void PraseStructContent<T>(this IList<T> values, IReadWrite plc, byte[] buffer, int startIndex = 0) where T : IDeviceVariableRunTime
|
||||
{
|
||||
foreach (IDeviceVariableRunTime organizedVariable in values)
|
||||
{
|
||||
var deviceValue = organizedVariable;
|
||||
IThingsGatewayBitConverter byteConverter = deviceValue.ThingsGatewayBitConverter;
|
||||
var dataType = organizedVariable.DataTypeEnum;
|
||||
int index = organizedVariable.Index;
|
||||
switch (dataType)
|
||||
{
|
||||
case DataTypeEnum.String:
|
||||
Set(organizedVariable, byteConverter.ToString(buffer, index + startIndex, byteConverter.Length ?? 1));
|
||||
break;
|
||||
case DataTypeEnum.Boolean:
|
||||
Set(organizedVariable,
|
||||
byteConverter.Length > 1 ?
|
||||
byteConverter.ToBoolean(buffer, index + (startIndex * 8), byteConverter.Length.Value, plc.IsBitReverse(organizedVariable.VariableAddress)) :
|
||||
byteConverter.ToBoolean(buffer, index + (startIndex * 8), plc.IsBitReverse(organizedVariable.VariableAddress))
|
||||
);
|
||||
break;
|
||||
case DataTypeEnum.Byte:
|
||||
Set(organizedVariable,
|
||||
byteConverter.Length > 1 ?
|
||||
byteConverter.ToByte(buffer, index + (startIndex), byteConverter.Length.Value) :
|
||||
byteConverter.ToByte(buffer, index + startIndex));
|
||||
break;
|
||||
case DataTypeEnum.Int16:
|
||||
Set(organizedVariable,
|
||||
byteConverter.Length > 1 ?
|
||||
byteConverter.ToInt16(buffer, index + (startIndex), byteConverter.Length.Value) :
|
||||
byteConverter.ToInt16(buffer, index + startIndex));
|
||||
break;
|
||||
case DataTypeEnum.UInt16:
|
||||
Set(organizedVariable,
|
||||
byteConverter.Length > 1 ?
|
||||
byteConverter.ToUInt16(buffer, index + (startIndex), byteConverter.Length.Value) :
|
||||
byteConverter.ToUInt16(buffer, index + startIndex));
|
||||
break;
|
||||
case DataTypeEnum.Int32:
|
||||
Set(organizedVariable,
|
||||
byteConverter.Length > 1 ?
|
||||
byteConverter.ToInt32(buffer, index + (startIndex), byteConverter.Length.Value) :
|
||||
byteConverter.ToInt32(buffer, index + startIndex));
|
||||
break;
|
||||
case DataTypeEnum.UInt32:
|
||||
Set(organizedVariable,
|
||||
byteConverter.Length > 1 ?
|
||||
byteConverter.ToUInt32(buffer, index + (startIndex), byteConverter.Length.Value) :
|
||||
byteConverter.ToUInt32(buffer, index + startIndex));
|
||||
break;
|
||||
case DataTypeEnum.Int64:
|
||||
Set(organizedVariable,
|
||||
byteConverter.Length > 1 ?
|
||||
byteConverter.ToInt64(buffer, index + (startIndex), byteConverter.Length.Value) :
|
||||
byteConverter.ToInt64(buffer, index + startIndex));
|
||||
break;
|
||||
case DataTypeEnum.UInt64:
|
||||
Set(organizedVariable,
|
||||
byteConverter.Length > 1 ?
|
||||
byteConverter.ToUInt64(buffer, index + (startIndex), byteConverter.Length.Value) :
|
||||
byteConverter.ToUInt64(buffer, index + startIndex));
|
||||
break;
|
||||
case DataTypeEnum.Single:
|
||||
Set(organizedVariable,
|
||||
byteConverter.Length > 1 ?
|
||||
byteConverter.ToSingle(buffer, index + (startIndex), byteConverter.Length.Value) :
|
||||
byteConverter.ToSingle(buffer, index + startIndex));
|
||||
break;
|
||||
case DataTypeEnum.Double:
|
||||
Set(organizedVariable,
|
||||
byteConverter.Length > 1 ?
|
||||
byteConverter.ToDouble(buffer, index + (startIndex), byteConverter.Length.Value) :
|
||||
byteConverter.ToDouble(buffer, index + startIndex));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
static void Set(IDeviceVariableRunTime organizedVariable, object num)
|
||||
{
|
||||
var operResult = organizedVariable.SetValue(num); ;
|
||||
if (!operResult.IsSuccess)
|
||||
{
|
||||
throw new Exception(operResult.Message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Foundation.Extension;
|
||||
/// <summary>
|
||||
/// 对象拓展类
|
||||
/// </summary>
|
||||
public static class ObjectExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 转换布尔值
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static bool ToBoolean(this object value, bool defaultValue = false) => value?.ToString().ToUpper() switch
|
||||
{
|
||||
"0" or "FALSE" => false,
|
||||
"1" or "TRUE" => true,
|
||||
_ => defaultValue,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// ToLong
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static long ToLong(this object value, long defaultValue = 0)
|
||||
{
|
||||
if (value == null || value.ToString().IsNullOrEmpty())
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value is bool boolValue)
|
||||
{
|
||||
return boolValue ? 1 : 0;
|
||||
}
|
||||
return Int64.TryParse(value.ToString(), out var n) ? n : defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ToInt
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static int ToInt(this object value, int defaultValue = 0)
|
||||
{
|
||||
if (value == null || value.ToString().IsNullOrEmpty())
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value is bool boolValue)
|
||||
{
|
||||
return boolValue ? 1 : 0;
|
||||
}
|
||||
return int.TryParse(value.ToString(), out int n) ? n : defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ToDecimal
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static decimal ToDecimal(this object value, int defaultValue = 0)
|
||||
{
|
||||
if (value is Double d)
|
||||
{
|
||||
return Double.IsNaN(d) ? defaultValue : (Decimal)d;
|
||||
}
|
||||
var str = value?.ToString();
|
||||
if (str.IsNullOrEmpty())
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value is bool boolValue)
|
||||
{
|
||||
return boolValue ? 1 : 0;
|
||||
}
|
||||
return Decimal.TryParse(str, out var n) ? n : defaultValue;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// ToDecimal
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static double ToDouble(this object value, double defaultValue = 0)
|
||||
{
|
||||
if (value is Double d)
|
||||
{
|
||||
return Double.IsNaN(d) ? defaultValue : (Double)d;
|
||||
}
|
||||
var str = value?.ToString();
|
||||
if (str.IsNullOrEmpty())
|
||||
{
|
||||
return (double)defaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value is bool boolValue)
|
||||
{
|
||||
return boolValue ? 1 : 0;
|
||||
}
|
||||
return (double)(double.TryParse(str, out var n) ? n : defaultValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Foundation.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// DateHandleAdapterExtension
|
||||
/// </summary>
|
||||
public static class DataHandlingAdapterExtension
|
||||
{
|
||||
#region SingleStreamDataHandlingAdapter
|
||||
|
||||
/// <summary>
|
||||
/// 将<see cref="TouchSocketConfig"/>中的配置,装载在<see cref="SingleStreamDataHandlingAdapter"/>上。
|
||||
/// </summary>
|
||||
/// <param name="adapter"></param>
|
||||
/// <param name="config"></param>
|
||||
public static void Config(this SingleStreamDataHandlingAdapter adapter, TouchSocketConfig config)
|
||||
{
|
||||
if (config.GetValue(DataHandlingAdapterExtension.MaxPackageSizeProperty) is int v1)
|
||||
{
|
||||
adapter.MaxPackageSize = v1;
|
||||
}
|
||||
if (config.GetValue(DataHandlingAdapterExtension.CacheTimeoutProperty) != TimeSpan.Zero)
|
||||
{
|
||||
adapter.CacheTimeout = config.GetValue(DataHandlingAdapterExtension.CacheTimeoutProperty);
|
||||
}
|
||||
if (config.GetValue(DataHandlingAdapterExtension.CacheTimeoutEnableProperty) is bool v2)
|
||||
{
|
||||
adapter.CacheTimeoutEnable = v2;
|
||||
}
|
||||
if (config.GetValue(DataHandlingAdapterExtension.UpdateCacheTimeWhenRevProperty) is bool v3)
|
||||
{
|
||||
adapter.UpdateCacheTimeWhenRev = v3;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 适配器配置
|
||||
|
||||
/// <summary>
|
||||
/// 适配器数据包缓存启用。默认为缺省(null),如果有正常值会在设置适配器时,直接作用于<see cref="SingleStreamDataHandlingAdapter.CacheTimeout"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<bool?> CacheTimeoutEnableProperty = DependencyProperty<bool?>.Register("CacheTimeoutEnable", null);
|
||||
|
||||
/// <summary>
|
||||
/// 适配器数据包缓存时长。默认为缺省(<see cref="TimeSpan.Zero"/>)。当该值有效时会在设置适配器时,直接作用于<see cref="SingleStreamDataHandlingAdapter.CacheTimeout"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<TimeSpan> CacheTimeoutProperty = DependencyProperty<TimeSpan>.Register("CacheTimeout", TimeSpan.Zero);
|
||||
|
||||
/// <summary>
|
||||
/// 适配器数据包最大值。默认缺省(null),当该值有效时会在设置适配器时,直接作用于<see cref="DataHandlingAdapter.MaxPackageSize"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<int?> MaxPackageSizeProperty = DependencyProperty<int?>.Register("MaxPackageSize", null);
|
||||
|
||||
/// <summary>
|
||||
/// 适配器数据包缓存策略。默认缺省(null),当该值有效时会在设置适配器时,直接作用于<see cref="SingleStreamDataHandlingAdapter.UpdateCacheTimeWhenRev"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<bool?> UpdateCacheTimeWhenRevProperty = DependencyProperty<bool?>.Register("UpdateCacheTimeWhenRev", null);
|
||||
|
||||
/// <summary>
|
||||
/// 适配器数据包缓存时长。默认为缺省(<see cref="TimeSpan.Zero"/>)。当该值有效时会在设置适配器时,直接作用于<see cref="SingleStreamDataHandlingAdapter.CacheTimeout"/>
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TouchSocketConfig SetCacheTimeout(this TouchSocketConfig config, TimeSpan value)
|
||||
{
|
||||
config.SetValue(CacheTimeoutProperty, value);
|
||||
return config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 适配器数据包缓存启用。默认为缺省(null),如果有正常值会在设置适配器时,直接作用于<see cref="SingleStreamDataHandlingAdapter.CacheTimeoutEnable"/>
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TouchSocketConfig SetCacheTimeoutEnable(this TouchSocketConfig config, bool value)
|
||||
{
|
||||
config.SetValue(CacheTimeoutEnableProperty, value);
|
||||
return config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 适配器数据包最大值。默认缺省(null),当该值有效时会在设置适配器时,直接作用于<see cref="DataHandlingAdapter.MaxPackageSize"/>
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TouchSocketConfig SetMaxPackageSize(this TouchSocketConfig config, int value)
|
||||
{
|
||||
config.SetValue(MaxPackageSizeProperty, value);
|
||||
return config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 适配器数据包缓存策略。默认缺省(null),当该值有效时会在设置适配器时,直接作用于<see cref="SingleStreamDataHandlingAdapter.UpdateCacheTimeWhenRev"/>
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TouchSocketConfig SetUpdateCacheTimeWhenRev(this TouchSocketConfig config, bool value)
|
||||
{
|
||||
config.SetValue(UpdateCacheTimeWhenRevProperty, value);
|
||||
return config;
|
||||
}
|
||||
|
||||
#endregion 适配器配置
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Foundation.Dmtp
|
||||
{
|
||||
/// <summary>
|
||||
/// TcpDmtpAdapter
|
||||
/// </summary>
|
||||
public class TcpDmtpAdapter : CustomFixedHeaderByteBlockDataHandlingAdapter<DmtpMessage>
|
||||
{
|
||||
private SpinLock m_locker = new SpinLock();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool CanSendRequestInfo => true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool CanSplicingSend => false;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int HeaderLength => 6;
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override DmtpMessage GetInstance()
|
||||
{
|
||||
return new DmtpMessage();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void OnReceivedSuccess(DmtpMessage request)
|
||||
{
|
||||
request.SafeDispose();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void PreviewSend(IRequestInfo requestInfo)
|
||||
{
|
||||
if (!(requestInfo is DmtpMessage message))
|
||||
{
|
||||
throw new Exception($"无法将{nameof(requestInfo)}转换为{nameof(DmtpMessage)}");
|
||||
}
|
||||
if (message.BodyByteBlock != null && message.BodyByteBlock.Length > this.MaxPackageSize)
|
||||
{
|
||||
throw new Exception("发送的BodyLength={requestInfo.BodyLength},大于设定的MaxPackageSize={this.MaxPackageSize}");
|
||||
}
|
||||
using (var byteBlock = new ByteBlock(message.GetLength()))
|
||||
{
|
||||
message.Build(byteBlock);
|
||||
this.GoSend(byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void PreviewSend(IList<ArraySegment<byte>> transferBytes)
|
||||
{
|
||||
if (transferBytes.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var length = 0;
|
||||
foreach (var item in transferBytes)
|
||||
{
|
||||
length += item.Count;
|
||||
}
|
||||
|
||||
if (length > this.MaxPackageSize)
|
||||
{
|
||||
throw new Exception("发送数据大于设定值,相同解析器可能无法收到有效数据,已终止发送");
|
||||
}
|
||||
|
||||
var lockTaken = false;
|
||||
try
|
||||
{
|
||||
this.m_locker.Enter(ref lockTaken);
|
||||
foreach (var item in transferBytes)
|
||||
{
|
||||
this.GoSend(item.Array, item.Offset, item.Count);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (lockTaken)
|
||||
{
|
||||
this.m_locker.Exit(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,243 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:http://rrqm_home.gitee.io/touchsocket/
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using ThingsGateway.Foundation.Resources;
|
||||
|
||||
namespace ThingsGateway.Foundation.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// Http客户端
|
||||
/// </summary>
|
||||
public class HttpClient : HttpClientBase
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Http客户端基类
|
||||
/// </summary>
|
||||
public class HttpClientBase : TcpClientBase, IHttpClient
|
||||
{
|
||||
private readonly object m_requestLocker = new object();
|
||||
private readonly WaitData<HttpResponse> m_waitData;
|
||||
private bool m_getContent;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public HttpClientBase()
|
||||
{
|
||||
this.m_waitData = new WaitData<HttpResponse>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns></returns>
|
||||
public override ITcpClient Connect(int timeout = 5000)
|
||||
{
|
||||
if (this.Config.GetValue(HttpConfigExtensions.HttpProxyProperty) is HttpProxy httpProxy)
|
||||
{
|
||||
var proxyHost = httpProxy.Host;
|
||||
var credential = httpProxy.Credential;
|
||||
var remoteHost = this.Config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty);
|
||||
try
|
||||
{
|
||||
this.Config.SetRemoteIPHost(proxyHost);
|
||||
base.Connect(timeout);
|
||||
var request = new HttpRequest();
|
||||
request.InitHeaders()
|
||||
.SetHost(remoteHost.Host)
|
||||
.SetUrl(remoteHost.Host, true)
|
||||
.AsMethod("CONNECT");
|
||||
var response = this.Request(request, timeout: timeout);
|
||||
if (response.IsProxyAuthenticationRequired)
|
||||
{
|
||||
if (credential is null)
|
||||
{
|
||||
throw new Exception("未指定代理的凭据。");
|
||||
}
|
||||
var authHeader = response.Headers.Get(HttpHeaders.ProxyAuthenticate);
|
||||
if (authHeader.IsNullOrEmpty())
|
||||
{
|
||||
throw new Exception("未指定代理身份验证质询。");
|
||||
}
|
||||
|
||||
var ares = new AuthenticationChallenge(authHeader, credential);
|
||||
|
||||
request.Headers.Add(HttpHeaders.ProxyAuthorization, ares.ToString());
|
||||
if (!response.KeepAlive)
|
||||
{
|
||||
base.Close("代理要求关闭连接,随后重写连接。");
|
||||
base.Connect(timeout);
|
||||
}
|
||||
|
||||
response = this.Request(request, timeout: timeout);
|
||||
}
|
||||
|
||||
if (response.StatusCode != 200)
|
||||
{
|
||||
throw new Exception(response.StatusMessage);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.Config.SetRemoteIPHost(remoteHost);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
base.Connect(timeout);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="request"><inheritdoc/></param>
|
||||
/// <param name="onlyRequest"><inheritdoc/></param>
|
||||
/// <param name="timeout"><inheritdoc/></param>
|
||||
/// <param name="token"><inheritdoc/></param>
|
||||
/// <returns></returns>
|
||||
public HttpResponse Request(HttpRequest request, bool onlyRequest = false, int timeout = 10 * 1000, CancellationToken token = default)
|
||||
{
|
||||
lock (this.m_requestLocker)
|
||||
{
|
||||
this.m_getContent = false;
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
request.Build(byteBlock);
|
||||
|
||||
this.m_waitData.Reset();
|
||||
this.m_waitData.SetCancellationToken(token);
|
||||
|
||||
this.DefaultSend(byteBlock);
|
||||
if (onlyRequest)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (this.m_waitData.Wait(timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
return this.m_waitData.WaitResult;
|
||||
|
||||
case WaitDataStatus.Overtime:
|
||||
throw new TimeoutException(TouchSocketHttpResource.Overtime.GetDescription());
|
||||
case WaitDataStatus.Canceled:
|
||||
return default;
|
||||
|
||||
case WaitDataStatus.Default:
|
||||
case WaitDataStatus.Disposed:
|
||||
default:
|
||||
throw new Exception(TouchSocketHttpResource.UnknownError.GetDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="onlyRequest"></param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public HttpResponse RequestContent(HttpRequest request, bool onlyRequest = false, int timeout = 10 * 1000, CancellationToken token = default)
|
||||
{
|
||||
lock (this.m_requestLocker)
|
||||
{
|
||||
this.m_getContent = true;
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
request.Build(byteBlock);
|
||||
|
||||
this.m_waitData.Reset();
|
||||
this.m_waitData.SetCancellationToken(token);
|
||||
|
||||
this.DefaultSend(byteBlock);
|
||||
if (onlyRequest)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (this.m_waitData.Wait(timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
return this.m_waitData.WaitResult;
|
||||
|
||||
case WaitDataStatus.Overtime:
|
||||
throw new TimeoutException(TouchSocketHttpResource.Overtime.GetDescription());
|
||||
case WaitDataStatus.Canceled:
|
||||
return default;
|
||||
|
||||
case WaitDataStatus.Default:
|
||||
case WaitDataStatus.Disposed:
|
||||
default:
|
||||
throw new Exception(TouchSocketHttpResource.UnknownError.GetDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="disposing"></param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
this.m_waitData?.Dispose();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Task ReceivedData(ReceivedDataEventArgs e)
|
||||
{
|
||||
if (e.RequestInfo is HttpResponse response)
|
||||
{
|
||||
if (this.m_getContent)
|
||||
{
|
||||
response.TryGetContent(out _);
|
||||
}
|
||||
this.m_waitData.Set(response);
|
||||
}
|
||||
|
||||
return base.ReceivedData(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
protected override async Task OnConnecting(ConnectingEventArgs e)
|
||||
{
|
||||
this.Protocol = Protocol.Http;
|
||||
this.SetDataHandlingAdapter(new HttpClientDataHandlingAdapter());
|
||||
await base.OnConnecting(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:http://rrqm_home.gitee.io/touchsocket/
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace ThingsGateway.Foundation.Rpc
|
||||
{
|
||||
/// <summary>
|
||||
/// Rpc异常
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class RpcException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
///构造函数
|
||||
/// </summary>
|
||||
public RpcException() : base() { }
|
||||
|
||||
/// <summary>
|
||||
///构造函数
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
public RpcException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
///构造函数
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="inner"></param>
|
||||
public RpcException(string message, System.Exception inner) : base(message, inner) { }
|
||||
|
||||
/// <summary>
|
||||
///构造函数
|
||||
/// </summary>
|
||||
/// <param name="info"></param>
|
||||
/// <param name="context"></param>
|
||||
protected RpcException(System.Runtime.Serialization.SerializationInfo info,
|
||||
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rpc调用异常
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class RpcInvokeException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
///构造函数
|
||||
/// </summary>
|
||||
public RpcInvokeException() : base() { }
|
||||
|
||||
/// <summary>
|
||||
///构造函数
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
public RpcInvokeException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
///构造函数
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="inner"></param>
|
||||
public RpcInvokeException(string message, System.Exception inner) : base(message, inner) { }
|
||||
|
||||
/// <summary>
|
||||
///构造函数
|
||||
/// </summary>
|
||||
/// <param name="info"></param>
|
||||
/// <param name="context"></param>
|
||||
protected RpcInvokeException(System.Runtime.Serialization.SerializationInfo info,
|
||||
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
|
||||
}
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Plugin.DLT645;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public class DLT645_2007 : CollectBase
|
||||
{
|
||||
private readonly DLT645_2007Property driverPropertys = new();
|
||||
private ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007 _plc;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Type DriverDebugUIType => typeof(DLT645_2007DebugPage);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override CollectDriverPropertyBase DriverPropertys => driverPropertys;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public override bool IsSupportRequest => true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override IThingsGatewayBitConverter ThingsGatewayBitConverter { get => _plc?.ThingsGatewayBitConverter; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override IReadWrite PLC => _plc;
|
||||
/// <inheritdoc/>
|
||||
public override Task AfterStopAsync()
|
||||
{
|
||||
_plc?.Disconnect();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task BeforStartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await _plc?.ConnectAsync(cancellationToken);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override void InitDataAdapter()
|
||||
{
|
||||
_plc.SetDataAdapter();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool IsConnected()
|
||||
{
|
||||
return _plc?.SerialSession?.CanSend == true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override List<DeviceVariableSourceRead> LoadSourceRead(List<DeviceVariableRunTime> deviceVariables)
|
||||
{
|
||||
return _plc.LoadSourceRead<DeviceVariableSourceRead, DeviceVariableRunTime>(deviceVariables, 0);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
_plc?.Disconnect();
|
||||
_plc?.SafeDispose();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
protected override void Init(CollectDeviceRunTime device, object client = null)
|
||||
{
|
||||
if (client == null)
|
||||
{
|
||||
FoundataionConfig.SetSerialProperty(new()
|
||||
{
|
||||
PortName = driverPropertys.PortName,
|
||||
BaudRate = driverPropertys.BaudRate,
|
||||
DataBits = driverPropertys.DataBits,
|
||||
Parity = driverPropertys.Parity,
|
||||
StopBits = driverPropertys.StopBits,
|
||||
})
|
||||
;
|
||||
client = new SerialSession();
|
||||
((SerialSession)client).Setup(FoundataionConfig);
|
||||
}
|
||||
//载入配置
|
||||
_plc = new((SerialSession)client)
|
||||
{
|
||||
FrameTime = driverPropertys.FrameTime,
|
||||
CacheTimeout = driverPropertys.CacheTimeout,
|
||||
DataFormat = driverPropertys.DataFormat,
|
||||
EnableFEHead = driverPropertys.EnableFEHead,
|
||||
OperCode = driverPropertys.OperCode,
|
||||
Password = driverPropertys.Password,
|
||||
Station = driverPropertys.Station,
|
||||
TimeOut = driverPropertys.TimeOut
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken)
|
||||
{
|
||||
return await _plc.ReadAsync(address, length, cancellationToken);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Plugin.DLT645;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public class DLT645_2007OverTcp : CollectBase
|
||||
{
|
||||
|
||||
private readonly DLT645_2007OverTcpProperty driverPropertys = new();
|
||||
private ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp _plc;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Type DriverDebugUIType => typeof(DLT645_2007OverTcpDebugPage);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override CollectDriverPropertyBase DriverPropertys => driverPropertys;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool IsSupportRequest => true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override IThingsGatewayBitConverter ThingsGatewayBitConverter { get => _plc?.ThingsGatewayBitConverter; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override IReadWrite PLC => _plc;
|
||||
/// <inheritdoc/>
|
||||
public override Task AfterStopAsync()
|
||||
{
|
||||
_plc?.Disconnect();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task BeforStartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await _plc?.ConnectAsync(cancellationToken);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override void InitDataAdapter()
|
||||
{
|
||||
_plc.SetDataAdapter();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool IsConnected()
|
||||
{
|
||||
return _plc?.TcpClient?.CanSend == true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override List<DeviceVariableSourceRead> LoadSourceRead(List<DeviceVariableRunTime> deviceVariables)
|
||||
{
|
||||
return _plc.LoadSourceRead<DeviceVariableSourceRead, DeviceVariableRunTime>(deviceVariables, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
_plc?.Disconnect();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
protected override void Init(CollectDeviceRunTime device, object client = null)
|
||||
{
|
||||
if (client == null)
|
||||
{
|
||||
FoundataionConfig.SetRemoteIPHost(new IPHost($"{driverPropertys.IP}:{driverPropertys.Port}"))
|
||||
;
|
||||
client = new TcpClient();
|
||||
((TcpClient)client).Setup(FoundataionConfig);
|
||||
}
|
||||
//载入配置
|
||||
_plc = new((TcpClient)client)
|
||||
{
|
||||
FrameTime = driverPropertys.FrameTime,
|
||||
CacheTimeout = driverPropertys.CacheTimeout,
|
||||
DataFormat = driverPropertys.DataFormat,
|
||||
EnableFEHead = driverPropertys.EnableFEHead,
|
||||
OperCode = driverPropertys.OperCode,
|
||||
Password = driverPropertys.Password,
|
||||
Station = driverPropertys.Station,
|
||||
TimeOut = driverPropertys.TimeOut
|
||||
};
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
protected override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken)
|
||||
{
|
||||
return await _plc.ReadAsync(address, length, cancellationToken);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
global using System;
|
||||
global using System.Collections.Generic;
|
||||
global using System.Threading;
|
||||
global using System.Threading.Tasks;
|
||||
|
||||
global using ThingsGateway.Foundation.Core;
|
||||
global using ThingsGateway.Foundation.Demo;
|
||||
global using ThingsGateway.Foundation.Serial;
|
||||
global using ThingsGateway.Foundation.Sockets;
|
||||
global using ThingsGateway.Gateway.Application;
|
||||
global using ThingsGateway.Gateway.Core;
|
||||
@@ -1,413 +0,0 @@
|
||||
#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 Confluent.Kafka;
|
||||
|
||||
using Mapster;
|
||||
|
||||
namespace ThingsGateway.Plugin.Kafka;
|
||||
|
||||
using Furion;
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using ThingsGateway.Foundation.Extension.ConcurrentQueue;
|
||||
using ThingsGateway.Foundation.Extension.Generic;
|
||||
using ThingsGateway.Foundation.Extension.String;
|
||||
|
||||
/// <summary>
|
||||
/// Kafka消息生产
|
||||
/// </summary>
|
||||
public class KafkaProducer : UpLoadBase
|
||||
{
|
||||
private readonly ConcurrentQueue<DeviceData> _collectDeviceRunTimes = new();
|
||||
private readonly ConcurrentQueue<VariableData> _collectVariableRunTimes = new();
|
||||
private readonly KafkaProducerProperty driverPropertys = new();
|
||||
private readonly KafkaProducerVariableProperty variablePropertys = new();
|
||||
private GlobalDeviceData _globalDeviceData;
|
||||
private List<DeviceVariableRunTime> _uploadVariables = new();
|
||||
private bool isSuccess = true;
|
||||
private IProducer<Null, string> producer;
|
||||
private ProducerBuilder<Null, string> producerBuilder;
|
||||
private ProducerConfig producerconfig;
|
||||
/// <inheritdoc/>
|
||||
public override Type DriverDebugUIType => null;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override DriverPropertyBase DriverPropertys => driverPropertys;
|
||||
|
||||
private TimerTick exVariableTimerTick;
|
||||
private TimerTick exDeviceTimerTick;
|
||||
/// <inheritdoc/>
|
||||
public override List<DeviceVariableRunTime> UploadVariables => _uploadVariables;
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override VariablePropertyBase VariablePropertys => variablePropertys;
|
||||
/// <inheritdoc/>
|
||||
public override Task AfterStopAsync()
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Task BeforStartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override async Task ExecuteAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!driverPropertys.IsInterval)
|
||||
{
|
||||
////变化推送
|
||||
var varList = _collectVariableRunTimes.ToListWithDequeue();
|
||||
if (varList?.Count != 0)
|
||||
{
|
||||
//分解List,避免超出mqtt字节大小限制
|
||||
var varData = varList.ChunkTrivialBetter(driverPropertys.SplitSize);
|
||||
foreach (var item in varData)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
await KafKaUp(driverPropertys.VariableTopic, item.ToJsonString(), cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
if (isSuccess)
|
||||
producer.Flush(cancellationToken);
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (exVariableTimerTick.IsTickHappen())
|
||||
{
|
||||
try
|
||||
{
|
||||
var varList = _uploadVariables.Adapt<List<VariableData>>();
|
||||
if (varList?.Count != 0)
|
||||
{
|
||||
//分解List,避免超出mqtt字节大小限制
|
||||
var varData = varList.ChunkTrivialBetter(driverPropertys.SplitSize);
|
||||
foreach (var item in varData)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
await KafKaUp(driverPropertys.VariableTopic, item.ToJsonString(), cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
if (isSuccess)
|
||||
producer.Flush(cancellationToken);
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
try
|
||||
{
|
||||
if (!driverPropertys.IsInterval)
|
||||
{
|
||||
////变化推送
|
||||
var devList = _collectDeviceRunTimes.ToListWithDequeue();
|
||||
if (devList?.Count != 0)
|
||||
{
|
||||
//分解List,避免超出mqtt字节大小限制
|
||||
var devData = devList.ChunkTrivialBetter(driverPropertys.SplitSize);
|
||||
foreach (var item in devData)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
await KafKaUp(driverPropertys.DeviceTopic, item.ToJsonString(), cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
if (isSuccess)
|
||||
producer.Flush(cancellationToken);
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (exDeviceTimerTick.IsTickHappen())
|
||||
{
|
||||
var devList = _collectDevice.Adapt<List<DeviceData>>();
|
||||
if (devList?.Count != 0)
|
||||
{
|
||||
//分解List,避免超出mqtt字节大小限制
|
||||
var devData = devList.ChunkTrivialBetter(driverPropertys.SplitSize);
|
||||
foreach (var item in devData)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
await KafKaUp(driverPropertys.DeviceTopic, item.ToJsonString(), cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
if (isSuccess)
|
||||
producer.Flush(cancellationToken);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
if (driverPropertys.CycleInterval > UploadDeviceThread.CycleInterval + 50)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(driverPropertys.CycleInterval - UploadDeviceThread.CycleInterval, cancellationToken);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override bool IsConnected() => isSuccess;
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
_collectDevice.Where(a => _uploadVariables.Select(b => b.DeviceId).Contains(a.Id)).ForEach(a =>
|
||||
{
|
||||
a.DeviceStatusChange -= DeviceStatusChange;
|
||||
});
|
||||
_uploadVariables?.ForEach(a =>
|
||||
{
|
||||
a.VariableValueChange -= VariableValueChange;
|
||||
});
|
||||
producer?.Dispose();
|
||||
_uploadVariables = null;
|
||||
_collectDeviceRunTimes.Clear();
|
||||
_collectVariableRunTimes.Clear();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
private List<CollectDeviceRunTime> _collectDevice;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
/// <param name="device"></param>
|
||||
protected override void Init(UploadDeviceRunTime device)
|
||||
{
|
||||
#region Kafka 生产者
|
||||
//1、生产者配置
|
||||
producerconfig = new ProducerConfig
|
||||
{
|
||||
BootstrapServers = driverPropertys.BootStrapServers,
|
||||
ClientId = driverPropertys.ClientId,
|
||||
};
|
||||
//2、创建生产者
|
||||
producerBuilder = new ProducerBuilder<Null, string>(producerconfig);
|
||||
//3、错误日志监视
|
||||
producerBuilder.SetErrorHandler((p, msg) =>
|
||||
{
|
||||
isSuccess = false;
|
||||
LogMessage?.LogWarning(msg.Reason);
|
||||
});
|
||||
//kafka
|
||||
try
|
||||
{
|
||||
producer = producerBuilder.Build();
|
||||
}
|
||||
catch (DllNotFoundException)
|
||||
{
|
||||
if (!Library.IsLoaded)
|
||||
{
|
||||
string fileEx = ".dll";
|
||||
string osStr = "win-";
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
osStr = "win-";
|
||||
fileEx = ".dll";
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
osStr = "linux-";
|
||||
fileEx = ".so";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
osStr = "osx-";
|
||||
fileEx = ".dylib";
|
||||
}
|
||||
osStr += RuntimeInformation.ProcessArchitecture.ToString().ToLower();
|
||||
|
||||
var pathToLibrd = System.IO.Path.Combine(AppContext.BaseDirectory, "Plugins", "ThingsGateway.Plugin.Kafka", "runtimes", osStr, "native", $"librdkafka{fileEx}");
|
||||
Library.Load(pathToLibrd);
|
||||
}
|
||||
producer = producerBuilder.Build();
|
||||
}
|
||||
#endregion
|
||||
|
||||
_globalDeviceData = App.GetService<GlobalDeviceData>();
|
||||
|
||||
var tags = _globalDeviceData.AllVariables.Where(a => a.VariablePropertys.ContainsKey(device.Id))
|
||||
.Where(b => GetPropertyValue(b, nameof(variablePropertys.Enable)).GetBoolValue()).ToList();
|
||||
|
||||
_uploadVariables = tags;
|
||||
|
||||
_collectDevice = _globalDeviceData.CollectDevices.Where(a => _uploadVariables.Select(b => b.DeviceId).Contains(a.Id)).ToList();
|
||||
|
||||
_collectDevice.ForEach(a =>
|
||||
{
|
||||
a.DeviceStatusChange += DeviceStatusChange;
|
||||
});
|
||||
_uploadVariables.ForEach(a =>
|
||||
{
|
||||
a.VariableValueChange += VariableValueChange;
|
||||
});
|
||||
if (driverPropertys.UploadInterval <= 1000) driverPropertys.UploadInterval = 1000;
|
||||
exVariableTimerTick = new(driverPropertys.UploadInterval);
|
||||
exDeviceTimerTick = new(driverPropertys.UploadInterval);
|
||||
|
||||
}
|
||||
|
||||
private void DeviceStatusChange(CollectDeviceRunTime collectDeviceRunTime)
|
||||
{
|
||||
if (driverPropertys?.IsInterval != true)
|
||||
_collectDeviceRunTimes.Enqueue(collectDeviceRunTime.Adapt<DeviceData>());
|
||||
}
|
||||
|
||||
private async Task KafKaUp(string topic, string payLoad, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
using CancellationTokenSource cancellationTokenSource = new();
|
||||
using CancellationTokenSource stoppingToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationTokenSource.Token, cancellationToken);
|
||||
Task<DeliveryResult<Null, string>> resultTask = producer.ProduceAsync(topic, new Message<Null, string> { Value = payLoad }, stoppingToken.Token);
|
||||
var timeOutResult = await Task.WhenAny(resultTask, Task.Delay(driverPropertys.TimeOut, stoppingToken.Token));
|
||||
if (timeOutResult == resultTask)
|
||||
{
|
||||
var result = (timeOutResult as Task<DeliveryResult<Null, string>>).Result;
|
||||
if (result.Status != PersistenceStatus.Persisted)
|
||||
{
|
||||
isSuccess = false;
|
||||
await CacheDb.AddCacheData(topic, payLoad, driverPropertys.CacheMaxCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
isSuccess = true;
|
||||
//连接成功时补发缓存数据
|
||||
var cacheData = await CacheDb.GetCacheData();
|
||||
foreach (var item in cacheData)
|
||||
{
|
||||
var cacheResult = await producer.ProduceAsync(item.Topic, new Message<Null, string> { Value = item.CacheStr }, stoppingToken.Token);
|
||||
|
||||
if (cacheResult.Status == PersistenceStatus.Persisted)
|
||||
{
|
||||
LogMessage.Trace($"{FoundationConst.LogMessageHeader}主题:{item.Topic}{Environment.NewLine}负载:{item.CacheStr}");
|
||||
|
||||
await CacheDb.DeleteCacheData(item.Id);
|
||||
}
|
||||
}
|
||||
LogMessage.Trace($"{FoundationConst.LogMessageHeader}主题:{topic}{Environment.NewLine}负载:{payLoad}");
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
isSuccess = false;
|
||||
stoppingToken.Cancel();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
await CacheDb.AddCacheData(topic, payLoad, driverPropertys.CacheMaxCount);
|
||||
}
|
||||
}
|
||||
private void VariableValueChange(DeviceVariableRunTime collectVariableRunTime)
|
||||
{
|
||||
if (driverPropertys?.IsInterval != true)
|
||||
_collectVariableRunTimes.Enqueue(collectVariableRunTime.Adapt<VariableData>());
|
||||
}
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Plugin.Modbus;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public class ModbusRtu : CollectBase
|
||||
{
|
||||
private readonly ModbusRtuProperty driverPropertys = new();
|
||||
/// <inheritdoc/>
|
||||
protected override IReadWrite PLC => _plc;
|
||||
private ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu _plc;
|
||||
/// <inheritdoc/>
|
||||
public override Type DriverDebugUIType => typeof(ModbusRtuDebugPage);
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override CollectDriverPropertyBase DriverPropertys => driverPropertys;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public override bool IsSupportRequest => true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override IThingsGatewayBitConverter ThingsGatewayBitConverter { get => _plc?.ThingsGatewayBitConverter; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Task AfterStopAsync()
|
||||
{
|
||||
_plc?.Disconnect();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task BeforStartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await _plc?.ConnectAsync(cancellationToken);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
_plc?.Disconnect();
|
||||
_plc?.SafeDispose();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void InitDataAdapter()
|
||||
{
|
||||
_plc.SetDataAdapter();
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override bool IsConnected()
|
||||
{
|
||||
return _plc?.SerialSession?.CanSend == true;
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override List<DeviceVariableSourceRead> LoadSourceRead(List<DeviceVariableRunTime> deviceVariables)
|
||||
{
|
||||
return _plc.LoadSourceRead<DeviceVariableSourceRead, DeviceVariableRunTime>(deviceVariables, driverPropertys.MaxPack);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Init(CollectDeviceRunTime device, object client = null)
|
||||
{
|
||||
if (client == null)
|
||||
{
|
||||
FoundataionConfig.SetSerialProperty(new()
|
||||
{
|
||||
PortName = driverPropertys.PortName,
|
||||
BaudRate = driverPropertys.BaudRate,
|
||||
DataBits = driverPropertys.DataBits,
|
||||
Parity = driverPropertys.Parity,
|
||||
StopBits = driverPropertys.StopBits,
|
||||
})
|
||||
;
|
||||
client = new SerialSession();
|
||||
((SerialSession)client).Setup(FoundataionConfig);
|
||||
}
|
||||
//载入配置
|
||||
_plc = new((SerialSession)client)
|
||||
{
|
||||
Crc16CheckEnable = driverPropertys.Crc16CheckEnable,
|
||||
FrameTime = driverPropertys.FrameTime,
|
||||
CacheTimeout = driverPropertys.CacheTimeout,
|
||||
DataFormat = driverPropertys.DataFormat,
|
||||
Station = driverPropertys.Station,
|
||||
TimeOut = driverPropertys.TimeOut
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken)
|
||||
{
|
||||
return await _plc.ReadAsync(address, length, cancellationToken);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Plugin.Modbus;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public class ModbusRtuOverTcp : CollectBase
|
||||
{
|
||||
|
||||
private readonly ModbusRtuOverTcpProperty driverPropertys = new();
|
||||
/// <inheritdoc/>
|
||||
protected override IReadWrite PLC => _plc;
|
||||
private ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp _plc;
|
||||
/// <inheritdoc/>
|
||||
public override Type DriverDebugUIType => typeof(ModbusRtuOverTcpDebugPage);
|
||||
/// <inheritdoc/>
|
||||
public override CollectDriverPropertyBase DriverPropertys => driverPropertys;
|
||||
/// <inheritdoc/>
|
||||
public override bool IsSupportRequest => true;
|
||||
/// <inheritdoc/>
|
||||
public override IThingsGatewayBitConverter ThingsGatewayBitConverter { get => _plc?.ThingsGatewayBitConverter; }
|
||||
/// <inheritdoc/>
|
||||
public override Task AfterStopAsync()
|
||||
{
|
||||
_plc?.Disconnect();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task BeforStartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await _plc?.ConnectAsync(cancellationToken);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override void InitDataAdapter()
|
||||
{
|
||||
_plc.SetDataAdapter();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool IsConnected()
|
||||
{
|
||||
return _plc?.TcpClient?.CanSend == true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override List<DeviceVariableSourceRead> LoadSourceRead(List<DeviceVariableRunTime> deviceVariables)
|
||||
{
|
||||
return _plc.LoadSourceRead<DeviceVariableSourceRead, DeviceVariableRunTime>(deviceVariables, driverPropertys.MaxPack);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
_plc?.Disconnect();
|
||||
_plc?.SafeDispose();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
protected override void Init(CollectDeviceRunTime device, object client = null)
|
||||
{
|
||||
if (client == null)
|
||||
{
|
||||
FoundataionConfig.SetRemoteIPHost(new IPHost($"{driverPropertys.IP}:{driverPropertys.Port}"))
|
||||
;
|
||||
client = new TcpClient();
|
||||
((TcpClient)client).Setup(FoundataionConfig);
|
||||
}
|
||||
//载入配置
|
||||
_plc = new((TcpClient)client)
|
||||
{
|
||||
Crc16CheckEnable = driverPropertys.Crc16CheckEnable,
|
||||
FrameTime = driverPropertys.FrameTime,
|
||||
CacheTimeout = driverPropertys.CacheTimeout,
|
||||
DataFormat = driverPropertys.DataFormat,
|
||||
ConnectTimeOut = driverPropertys.ConnectTimeOut,
|
||||
Station = driverPropertys.Station,
|
||||
TimeOut = driverPropertys.TimeOut
|
||||
};
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
protected override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken)
|
||||
{
|
||||
return await _plc.ReadAsync(address, length, cancellationToken);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Plugin.Modbus;
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public class ModbusRtuOverUdp : CollectBase
|
||||
{
|
||||
private readonly ModbusRtuOverUdpProperty driverPropertys = new();
|
||||
/// <inheritdoc/>
|
||||
protected override IReadWrite PLC => _plc;
|
||||
private ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp _plc;
|
||||
/// <inheritdoc/>
|
||||
public override Type DriverDebugUIType => typeof(ModbusRtuOverUdpDebugPage);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override CollectDriverPropertyBase DriverPropertys => driverPropertys;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool IsSupportRequest => true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override IThingsGatewayBitConverter ThingsGatewayBitConverter { get => _plc?.ThingsGatewayBitConverter; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Task AfterStopAsync()
|
||||
{
|
||||
_plc.Disconnect();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Task BeforStartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return _plc.ConnectAsync(cancellationToken);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override void InitDataAdapter()
|
||||
{
|
||||
_plc.SetDataAdapter();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool IsConnected()
|
||||
{
|
||||
return _plc?.UdpSession?.CanSend == true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override List<DeviceVariableSourceRead> LoadSourceRead(List<DeviceVariableRunTime> deviceVariables)
|
||||
{
|
||||
return _plc.LoadSourceRead<DeviceVariableSourceRead, DeviceVariableRunTime>(deviceVariables, driverPropertys.MaxPack);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
_plc?.Disconnect();
|
||||
_plc?.SafeDispose();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
protected override void Init(CollectDeviceRunTime device, object client = null)
|
||||
{
|
||||
if (client == null)
|
||||
{
|
||||
FoundataionConfig.SetRemoteIPHost(new IPHost($"{driverPropertys.IP}:{driverPropertys.Port}"))
|
||||
.SetBindIPHost(new IPHost(0))
|
||||
;
|
||||
|
||||
client = new UdpSession();
|
||||
((UdpSession)client).Setup(FoundataionConfig);
|
||||
}
|
||||
//载入配置
|
||||
_plc = new((UdpSession)client)
|
||||
{
|
||||
Crc16CheckEnable = driverPropertys.Crc16CheckEnable,
|
||||
FrameTime = driverPropertys.FrameTime,
|
||||
DataFormat = driverPropertys.DataFormat,
|
||||
Station = driverPropertys.Station,
|
||||
TimeOut = driverPropertys.TimeOut
|
||||
};
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
protected override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken)
|
||||
{
|
||||
return await _plc.ReadAsync(address, length, cancellationToken);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,241 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
using ThingsGateway.Foundation.Adapter.Modbus;
|
||||
using ThingsGateway.Foundation.Extension;
|
||||
using ThingsGateway.Foundation.Extension.ConcurrentQueue;
|
||||
using ThingsGateway.Foundation.Extension.String;
|
||||
|
||||
namespace ThingsGateway.Plugin.Modbus;
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public class ModbusSerialServer : UpLoadBase
|
||||
{
|
||||
|
||||
private readonly ModbusSerialServerProperty driverPropertys = new();
|
||||
private readonly ModbusSerialServerVariableProperty variablePropertys = new();
|
||||
private Dictionary<ModbusAddress, DeviceVariableRunTime> _ModbusTags;
|
||||
private ThingsGateway.Foundation.Adapter.Modbus.ModbusSerialServer _plc;
|
||||
private ConcurrentQueue<(string, DeviceVariableRunTime)> Values = new();
|
||||
/// <inheritdoc/>
|
||||
public override Type DriverDebugUIType => typeof(ModbusSerialServerDebugPage);
|
||||
/// <inheritdoc/>
|
||||
public override UpDriverPropertyBase DriverPropertys => driverPropertys;
|
||||
/// <inheritdoc/>
|
||||
public override List<DeviceVariableRunTime> UploadVariables => _ModbusTags?.Values.ToList();
|
||||
/// <inheritdoc/>
|
||||
public override VariablePropertyBase VariablePropertys => variablePropertys;
|
||||
RpcSingletonService RpcCore { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override Task AfterStopAsync()
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Task BeforStartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return _plc?.ConnectAsync(cancellationToken);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override async Task ExecuteAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var list = Values.ToListWithDequeue();
|
||||
foreach (var item in list)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
break;
|
||||
var type = GetPropertyValue(item.Item2, nameof(ModbusSerialServerVariableProperty.ModbusType));
|
||||
if (Enum.TryParse<DataTypeEnum>(type, out DataTypeEnum result))
|
||||
{
|
||||
await _plc.WriteAsync(item.Item1, item.Item2.Value?.ToString(), 1, result, cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _plc.WriteAsync(item.Item1, item.Item2.Value?.ToString(), 1, item.Item2.DataTypeEnum, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
if (driverPropertys.CycleInterval > UploadDeviceThread.CycleInterval + 50)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(driverPropertys.CycleInterval - UploadDeviceThread.CycleInterval, cancellationToken);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool IsConnected()
|
||||
{
|
||||
return _plc?.SerialSession?.CanSend == true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
_ModbusTags?.Values?.ToList()?.ForEach(a => a.VariableValueChange -= VariableValueChange);
|
||||
if (_plc != null)
|
||||
_plc.WriteData -= WriteData;
|
||||
_plc?.Disconnect();
|
||||
_plc?.SafeDispose();
|
||||
_ModbusTags?.Clear();
|
||||
_ModbusTags = null;
|
||||
Values?.Clear();
|
||||
Values = null;
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
protected override void Init(UploadDeviceRunTime device)
|
||||
{
|
||||
var service = new SerialSession();
|
||||
FoundataionConfig.SetSerialProperty(new()
|
||||
{
|
||||
PortName = driverPropertys.PortName,
|
||||
BaudRate = driverPropertys.BaudRate,
|
||||
DataBits = driverPropertys.DataBits,
|
||||
Parity = driverPropertys.Parity,
|
||||
StopBits = driverPropertys.StopBits,
|
||||
})
|
||||
;
|
||||
service = new SerialSession();
|
||||
((SerialSession)service).Setup(FoundataionConfig);
|
||||
//载入配置
|
||||
_plc = new(service)
|
||||
{
|
||||
DataFormat = driverPropertys.DataFormat,
|
||||
Station = driverPropertys.Station,
|
||||
CacheTimeout = driverPropertys.CacheTimeout,
|
||||
MulStation = driverPropertys.MulStation
|
||||
};
|
||||
|
||||
var _globalDeviceData = App.GetService<GlobalDeviceData>();
|
||||
var tags = _globalDeviceData.AllVariables.Where(a => a.VariablePropertys.ContainsKey(device.Id))
|
||||
.Where(b => !string.IsNullOrEmpty(GetPropertyValue(b, nameof(variablePropertys.ServiceAddress))))
|
||||
.ToList();
|
||||
|
||||
tags.ForEach(a =>
|
||||
{
|
||||
a.VariableValueChange += VariableValueChange;
|
||||
VariableValueChange(a);
|
||||
});
|
||||
_plc.WriteData += WriteData;
|
||||
try
|
||||
{
|
||||
_ModbusTags = tags.ToDictionary(a =>
|
||||
{
|
||||
ModbusAddress address = ModbusAddress.ParseFrom(
|
||||
GetPropertyValue(a, nameof(variablePropertys.ServiceAddress))
|
||||
, driverPropertys.Station);
|
||||
return address;
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
tags.ForEach(a =>
|
||||
{
|
||||
a.VariableValueChange -= VariableValueChange;
|
||||
});
|
||||
_plc.WriteData -= WriteData;
|
||||
}
|
||||
RpcCore = App.GetService<RpcSingletonService>();
|
||||
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
private void VariableValueChange(DeviceVariableRunTime collectVariableRunTime)
|
||||
{
|
||||
var address = GetPropertyValue(collectVariableRunTime, nameof(variablePropertys.ServiceAddress));
|
||||
if (address != null && collectVariableRunTime.Value != null)
|
||||
{
|
||||
Values?.Enqueue((address, collectVariableRunTime));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RPC写入
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="bytes"></param>
|
||||
/// <param name="thingsGatewayBitConverter"></param>
|
||||
/// <param name="client"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<OperResult> WriteData(ModbusAddress address, byte[] bytes, IThingsGatewayBitConverter thingsGatewayBitConverter, SerialSession client)
|
||||
{
|
||||
try
|
||||
{
|
||||
var tag = _ModbusTags.FirstOrDefault(a => a.Key?.AddressStart == address.AddressStart && a.Key?.Station == address.Station && a.Key?.ReadFunction == address.ReadFunction);
|
||||
|
||||
if (tag.Value == null) return OperResult.CreateSuccessResult();
|
||||
var enable =
|
||||
GetPropertyValue(tag.Value, nameof(variablePropertys.VariableRpcEnable)).ToBoolean()
|
||||
&& driverPropertys.DeviceRpcEnable;
|
||||
if (!enable) return new OperResult("不允许写入");
|
||||
var type = GetPropertyValue(tag.Value, nameof(ModbusSerialServerVariableProperty.ModbusType));
|
||||
var addressStr = GetPropertyValue(tag.Value, nameof(ModbusSerialServerVariableProperty.ServiceAddress));
|
||||
if (Enum.TryParse<DataTypeEnum>(type, out DataTypeEnum result))
|
||||
{
|
||||
var result1 = await RpcCore.InvokeDeviceMethodAsync($"{nameof(ModbusSerialServer)}-{CurrentDevice.Name}",
|
||||
new Dictionary<string, string>
|
||||
{
|
||||
{
|
||||
tag.Value.Name,
|
||||
thingsGatewayBitConverter.GetDataFormBytes(addressStr , bytes,result).ToString()
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
);
|
||||
return result1.FirstOrDefault().Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
var result1 = await RpcCore.InvokeDeviceMethodAsync($"{nameof(ModbusSerialServer)}-{CurrentDevice.Name}",
|
||||
new Dictionary<string, string>
|
||||
{
|
||||
{
|
||||
tag.Value.Name,
|
||||
thingsGatewayBitConverter.GetDataFormBytes(addressStr , bytes,result).ToString()
|
||||
},
|
||||
}
|
||||
);
|
||||
return result1.FirstOrDefault().Value;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult(ex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Plugin.Modbus;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public class ModbusTcp : CollectBase
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
protected override IReadWrite PLC => _plc;
|
||||
private ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp _plc;
|
||||
|
||||
private readonly ModbusTcpProperty driverPropertys = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Type DriverDebugUIType => typeof(ModbusTcpDebugPage);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override CollectDriverPropertyBase DriverPropertys => driverPropertys;
|
||||
/// <inheritdoc/>
|
||||
public override bool IsSupportRequest => true;
|
||||
/// <inheritdoc/>
|
||||
public override IThingsGatewayBitConverter ThingsGatewayBitConverter { get => _plc?.ThingsGatewayBitConverter; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Task AfterStopAsync()
|
||||
{
|
||||
_plc?.Disconnect();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task BeforStartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await _plc?.ConnectAsync(cancellationToken);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override void InitDataAdapter()
|
||||
{
|
||||
_plc.SetDataAdapter();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool IsConnected()
|
||||
{
|
||||
return _plc?.TcpClient?.CanSend == true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override List<DeviceVariableSourceRead> LoadSourceRead(List<DeviceVariableRunTime> deviceVariables)
|
||||
{
|
||||
return _plc.LoadSourceRead<DeviceVariableSourceRead, DeviceVariableRunTime>(deviceVariables, driverPropertys.MaxPack);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
_plc?.Disconnect();
|
||||
_plc?.SafeDispose();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
protected override void Init(CollectDeviceRunTime device, object client = null)
|
||||
{
|
||||
if (client == null)
|
||||
{
|
||||
FoundataionConfig.SetRemoteIPHost(new IPHost($"{driverPropertys.IP}:{driverPropertys.Port}"))
|
||||
;
|
||||
client = new TcpClient();
|
||||
((TcpClient)client).Setup(FoundataionConfig);
|
||||
}
|
||||
//载入配置
|
||||
_plc = new((TcpClient)client)
|
||||
{
|
||||
DataFormat = driverPropertys.DataFormat,
|
||||
FrameTime = driverPropertys.FrameTime,
|
||||
CacheTimeout = driverPropertys.CacheTimeout,
|
||||
ConnectTimeOut = driverPropertys.ConnectTimeOut,
|
||||
Station = driverPropertys.Station,
|
||||
TimeOut = driverPropertys.TimeOut,
|
||||
IsCheckMessageId = driverPropertys.MessageIdCheckEnable
|
||||
};
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
protected override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken)
|
||||
{
|
||||
return await _plc.ReadAsync(address, length, cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Plugin.Modbus;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public class ModbusTcpDtu : CollectBase
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
protected override IReadWrite PLC => _plc;
|
||||
private ThingsGateway.Foundation.Adapter.Modbus.ModbusTcpDtu _plc;
|
||||
|
||||
private readonly ModbusTcpProperty driverPropertys = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Type DriverDebugUIType => typeof(ModbusTcpDebugPage);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override CollectDriverPropertyBase DriverPropertys => driverPropertys;
|
||||
/// <inheritdoc/>
|
||||
public override bool IsSupportRequest => true;
|
||||
/// <inheritdoc/>
|
||||
public override IThingsGatewayBitConverter ThingsGatewayBitConverter { get => _plc?.ThingsGatewayBitConverter; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Task AfterStopAsync()
|
||||
{
|
||||
_plc?.Disconnect();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task BeforStartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await _plc?.ConnectAsync(cancellationToken);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override void InitDataAdapter()
|
||||
{
|
||||
_plc.SetDataAdapter();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool IsConnected()
|
||||
{
|
||||
return _plc?.TcpService?.ServerState == ServerState.Running;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override List<DeviceVariableSourceRead> LoadSourceRead(List<DeviceVariableRunTime> deviceVariables)
|
||||
{
|
||||
return _plc.LoadSourceRead<DeviceVariableSourceRead, DeviceVariableRunTime>(deviceVariables, driverPropertys.MaxPack);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
_plc?.Disconnect();
|
||||
_plc?.SafeDispose();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
protected override void Init(CollectDeviceRunTime device, object client = null)
|
||||
{
|
||||
if (client == null)
|
||||
{
|
||||
IPHost iPHost = new(driverPropertys.Port);
|
||||
if (!string.IsNullOrEmpty(driverPropertys.IP))
|
||||
{
|
||||
iPHost = new IPHost($"{driverPropertys.IP}:{driverPropertys.Port}");
|
||||
}
|
||||
FoundataionConfig.SetListenIPHosts(new IPHost[] { iPHost });
|
||||
client = new TcpService();
|
||||
((TcpService)client).Setup(FoundataionConfig);
|
||||
}
|
||||
//载入配置
|
||||
_plc = new((TcpService)client)
|
||||
{
|
||||
DataFormat = driverPropertys.DataFormat,
|
||||
FrameTime = driverPropertys.FrameTime,
|
||||
CacheTimeout = driverPropertys.CacheTimeout,
|
||||
ConnectTimeOut = driverPropertys.ConnectTimeOut,
|
||||
Station = driverPropertys.Station,
|
||||
TimeOut = driverPropertys.TimeOut,
|
||||
IsCheckMessageId = driverPropertys.MessageIdCheckEnable
|
||||
};
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
protected override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken)
|
||||
{
|
||||
return await _plc.ReadAsync(address, length, cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
using ThingsGateway.Foundation.Adapter.Modbus;
|
||||
using ThingsGateway.Foundation.Extension;
|
||||
using ThingsGateway.Foundation.Extension.ConcurrentQueue;
|
||||
using ThingsGateway.Foundation.Extension.String;
|
||||
|
||||
namespace ThingsGateway.Plugin.Modbus;
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public class ModbusTcpServer : UpLoadBase
|
||||
{
|
||||
|
||||
private readonly ModbusTcpServerProperty driverPropertys = new();
|
||||
private readonly ModbusTcpServerVariableProperty variablePropertys = new();
|
||||
private Dictionary<ModbusAddress, DeviceVariableRunTime> _ModbusTags;
|
||||
private ThingsGateway.Foundation.Adapter.Modbus.ModbusTcpServer _plc;
|
||||
private ConcurrentQueue<(string, DeviceVariableRunTime)> Values = new();
|
||||
/// <inheritdoc/>
|
||||
public override Type DriverDebugUIType => typeof(ModbusTcpServerDebugPage);
|
||||
/// <inheritdoc/>
|
||||
public override UpDriverPropertyBase DriverPropertys => driverPropertys;
|
||||
/// <inheritdoc/>
|
||||
public override List<DeviceVariableRunTime> UploadVariables => _ModbusTags?.Values.ToList();
|
||||
/// <inheritdoc/>
|
||||
public override VariablePropertyBase VariablePropertys => variablePropertys;
|
||||
RpcSingletonService RpcCore { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override Task AfterStopAsync()
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Task BeforStartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return _plc?.ConnectAsync(cancellationToken);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override async Task ExecuteAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var list = Values.ToListWithDequeue();
|
||||
foreach (var item in list)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
break;
|
||||
var type = GetPropertyValue(item.Item2, nameof(ModbusTcpServerVariableProperty.ModbusType));
|
||||
if (Enum.TryParse<DataTypeEnum>(type, out DataTypeEnum result))
|
||||
{
|
||||
await _plc.WriteAsync(item.Item1, item.Item2.Value?.ToString(), 1, result, cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _plc.WriteAsync(item.Item1, item.Item2.Value?.ToString(), 1, item.Item2.DataTypeEnum, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
if (driverPropertys.CycleInterval > UploadDeviceThread.CycleInterval + 50)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(driverPropertys.CycleInterval - UploadDeviceThread.CycleInterval, cancellationToken);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool IsConnected()
|
||||
{
|
||||
return _plc?.TcpService?.ServerState == ServerState.Running;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
_ModbusTags?.Values?.ToList()?.ForEach(a => a.VariableValueChange -= VariableValueChange);
|
||||
if (_plc != null)
|
||||
_plc.WriteData -= WriteData;
|
||||
_plc?.Disconnect();
|
||||
_plc?.SafeDispose();
|
||||
_ModbusTags?.Clear();
|
||||
_ModbusTags = null;
|
||||
Values?.Clear();
|
||||
Values = null;
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
protected override void Init(UploadDeviceRunTime device)
|
||||
{
|
||||
IPHost iPHost = new(driverPropertys.Port);
|
||||
if (!string.IsNullOrEmpty(driverPropertys.IP))
|
||||
{
|
||||
iPHost = new IPHost($"{driverPropertys.IP}:{driverPropertys.Port}");
|
||||
}
|
||||
FoundataionConfig.SetListenIPHosts(new IPHost[] { iPHost });
|
||||
var service = new TcpService();
|
||||
service.Setup(FoundataionConfig);
|
||||
//载入配置
|
||||
_plc = new(service)
|
||||
{
|
||||
DataFormat = driverPropertys.DataFormat,
|
||||
Station = driverPropertys.Station,
|
||||
CacheTimeout = driverPropertys.CacheTimeout,
|
||||
MulStation = driverPropertys.MulStation
|
||||
};
|
||||
|
||||
var _globalDeviceData = App.GetService<GlobalDeviceData>();
|
||||
var tags = _globalDeviceData.AllVariables.Where(a => a.VariablePropertys.ContainsKey(device.Id))
|
||||
.Where(b => !string.IsNullOrEmpty(GetPropertyValue(b, nameof(variablePropertys.ServiceAddress))))
|
||||
.ToList();
|
||||
|
||||
tags.ForEach(a =>
|
||||
{
|
||||
a.VariableValueChange += VariableValueChange;
|
||||
VariableValueChange(a);
|
||||
});
|
||||
_plc.WriteData += WriteData;
|
||||
try
|
||||
{
|
||||
_ModbusTags = tags.ToDictionary(a =>
|
||||
{
|
||||
ModbusAddress address = ModbusAddress.ParseFrom(
|
||||
GetPropertyValue(a, nameof(variablePropertys.ServiceAddress))
|
||||
, driverPropertys.Station);
|
||||
return address;
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
tags.ForEach(a =>
|
||||
{
|
||||
a.VariableValueChange -= VariableValueChange;
|
||||
});
|
||||
_plc.WriteData -= WriteData;
|
||||
}
|
||||
RpcCore = App.GetService<RpcSingletonService>();
|
||||
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
private void VariableValueChange(DeviceVariableRunTime collectVariableRunTime)
|
||||
{
|
||||
var address = GetPropertyValue(collectVariableRunTime, nameof(variablePropertys.ServiceAddress));
|
||||
if (address != null && collectVariableRunTime.Value != null)
|
||||
{
|
||||
Values?.Enqueue((address, collectVariableRunTime));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RPC写入
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="bytes"></param>
|
||||
/// <param name="thingsGatewayBitConverter"></param>
|
||||
/// <param name="client"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<OperResult> WriteData(ModbusAddress address, byte[] bytes, IThingsGatewayBitConverter thingsGatewayBitConverter, SocketClient client)
|
||||
{
|
||||
try
|
||||
{
|
||||
var tag = _ModbusTags.FirstOrDefault(a => a.Key?.AddressStart == address.AddressStart && a.Key?.Station == address.Station && a.Key?.ReadFunction == address.ReadFunction);
|
||||
|
||||
if (tag.Value == null) return OperResult.CreateSuccessResult();
|
||||
var enable =
|
||||
GetPropertyValue(tag.Value, nameof(variablePropertys.VariableRpcEnable)).ToBoolean()
|
||||
&& driverPropertys.DeviceRpcEnable;
|
||||
if (!enable) return new OperResult("不允许写入");
|
||||
var type = GetPropertyValue(tag.Value, nameof(ModbusTcpServerVariableProperty.ModbusType));
|
||||
var addressStr = GetPropertyValue(tag.Value, nameof(ModbusTcpServerVariableProperty.ServiceAddress));
|
||||
if (Enum.TryParse<DataTypeEnum>(type, out DataTypeEnum result))
|
||||
{
|
||||
var result1 = await RpcCore.InvokeDeviceMethodAsync($"{nameof(ModbusTcpServer)}-{CurrentDevice.Name}-{$"{client.IP}:{client.Port}"}",
|
||||
new Dictionary<string, string>
|
||||
{
|
||||
{
|
||||
tag.Value.Name,
|
||||
thingsGatewayBitConverter.GetDataFormBytes(addressStr , bytes,result).ToString()
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
);
|
||||
return result1.FirstOrDefault().Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
var result1 = await RpcCore.InvokeDeviceMethodAsync($"{nameof(ModbusTcpServer)}-{CurrentDevice.Name}-{$"{client.IP}:{client.Port}"}",
|
||||
new Dictionary<string, string>
|
||||
{
|
||||
{
|
||||
tag.Value.Name,
|
||||
thingsGatewayBitConverter.GetDataFormBytes(addressStr , bytes,result).ToString()
|
||||
},
|
||||
}
|
||||
);
|
||||
return result1.FirstOrDefault().Value;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult(ex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Plugin.Modbus;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public class ModbusUdp : CollectBase
|
||||
{
|
||||
private readonly ModbusUdpProperty driverPropertys = new();
|
||||
|
||||
private ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp _plc;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Type DriverDebugUIType => typeof(ModbusUdpDebugPage);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override CollectDriverPropertyBase DriverPropertys => driverPropertys;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool IsSupportRequest => true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override IThingsGatewayBitConverter ThingsGatewayBitConverter { get => _plc?.ThingsGatewayBitConverter; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override IReadWrite PLC => _plc;
|
||||
/// <inheritdoc/>
|
||||
public override Task AfterStopAsync()
|
||||
{
|
||||
_plc.Disconnect();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Task BeforStartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return _plc.ConnectAsync(cancellationToken);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override void InitDataAdapter()
|
||||
{
|
||||
_plc.SetDataAdapter();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool IsConnected()
|
||||
{
|
||||
return _plc?.UdpSession?.CanSend == true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override List<DeviceVariableSourceRead> LoadSourceRead(List<DeviceVariableRunTime> deviceVariables)
|
||||
{
|
||||
return _plc.LoadSourceRead<DeviceVariableSourceRead, DeviceVariableRunTime>(deviceVariables, driverPropertys.MaxPack);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
_plc?.Disconnect();
|
||||
_plc?.SafeDispose();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
protected override void Init(CollectDeviceRunTime device, object client = null)
|
||||
{
|
||||
if (client == null)
|
||||
{
|
||||
FoundataionConfig.SetRemoteIPHost(new IPHost($"{driverPropertys.IP}:{driverPropertys.Port}"))
|
||||
.SetBindIPHost(new IPHost(0))
|
||||
;
|
||||
client = new UdpSession();
|
||||
((UdpSession)client).Setup(FoundataionConfig);
|
||||
}
|
||||
//载入配置
|
||||
_plc = new((UdpSession)client)
|
||||
{
|
||||
DataFormat = driverPropertys.DataFormat,
|
||||
FrameTime = driverPropertys.FrameTime,
|
||||
Station = driverPropertys.Station,
|
||||
TimeOut = driverPropertys.TimeOut,
|
||||
IsCheckMessageId = driverPropertys.MessageIdCheckEnable
|
||||
};
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
protected override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken)
|
||||
{
|
||||
return await _plc.ReadAsync(address, length, cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
@*
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
*@
|
||||
|
||||
@page "/ModbusRtu"
|
||||
|
||||
@using BlazorComponent;
|
||||
@using Microsoft.AspNetCore.Components.Web;
|
||||
@using Microsoft.JSInterop;
|
||||
@using ThingsGateway.Foundation.Core;
|
||||
@using Masa.Blazor;
|
||||
@namespace ThingsGateway.Foundation.Demo
|
||||
|
||||
<SerialSessionPage @ref=SerialSessionPage></SerialSessionPage>
|
||||
|
||||
<MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%">
|
||||
<div class="mb-4">驱动配置</div>
|
||||
<MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
|
||||
@if (_plc != null)
|
||||
{
|
||||
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.FrameTime)) Dense HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField>
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.CacheTimeout)) Dense HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField>
|
||||
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.Station)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Station></MTextField>
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.TimeOut)) Dense HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
|
||||
|
||||
<MSelect Class="ma-1" Outlined Style="max-width:200px" @bind-Value="_plc.DataFormat" Label="@(_plc.DescriptionWithOutSugar(x => x.DataFormat))"
|
||||
Items=@(typeof(DataFormat).GetEnumListWithOutSugar())
|
||||
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
|
||||
ItemText=@((u) =>u.Description)
|
||||
ItemValue=@(u =>(DataFormat)u.Value)
|
||||
HideDetails=@("auto") Height="30"
|
||||
Dense>
|
||||
</MSelect>
|
||||
|
||||
<MCheckbox Class="ma-1" Style="max-width:200px" Label=@(_plc.DescriptionWithOutSugar(x => x.Crc16CheckEnable)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Crc16CheckEnable></MCheckbox>
|
||||
|
||||
}
|
||||
</MRow>
|
||||
</MCard>
|
||||
|
||||
|
||||
<DriverDebugUIPage @ref=driverDebugUIPage Sections="_sections">
|
||||
|
||||
</DriverDebugUIPage>
|
||||
|
||||
|
||||
@code {
|
||||
private readonly List<(string Code, string Language)> _sections = new();
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
|
||||
<Exec Command=" set dir="$(SolutionDir)Web\ThingsGateway.Web.Entry\bin\$(Configuration)\$(TargetFramework)\Plugins\$(AssemblyName)"
 if not exist %25dir%25 md %25dir%25 
copy "$(TargetDir)*Modbus*.dll" %25dir%25


" />
|
||||
|
||||
</Target>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\DriverDebugUIBase.cs" Link="DebugPage\DriverDebugUIBase.cs" />
|
||||
<Compile Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\DriverDebugUIPage.razor.cs" Link="DebugPage\DriverDebugUIPage.razor.cs" />
|
||||
<Compile Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\SerialSessionPage.razor.cs" Link="DebugPage\SerialSessionPage.razor.cs" />
|
||||
<Compile Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\TcpClientPage.razor.cs" Link="DebugPage\TcpClientPage.razor.cs" />
|
||||
<Compile Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\TcpServerPage.razor.cs" Link="DebugPage\TcpServerPage.razor.cs" />
|
||||
<Compile Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\UdpSessionPage.razor.cs" Link="DebugPage\UdpSessionPage.razor.cs" />
|
||||
<Content Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\DriverDebugUIPage.razor" Link="DebugPage\DriverDebugUIPage.razor" />
|
||||
<Content Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\SerialSessionPage.razor" Link="DebugPage\SerialSessionPage.razor" />
|
||||
<Content Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\TcpClientPage.razor" Link="DebugPage\TcpClientPage.razor" />
|
||||
<Content Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\TcpServerPage.razor" Link="DebugPage\TcpServerPage.razor" />
|
||||
<Content Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\UdpSessionPage.razor" Link="DebugPage\UdpSessionPage.razor" />
|
||||
|
||||
|
||||
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.Modbus\ThingsGateway.Foundation.Adapter.Modbus.csproj" />
|
||||
<ProjectReference Include="..\..\Web\ThingsGateway.Components\ThingsGateway.Components.csproj">
|
||||
<Private>false</Private>
|
||||
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
||||
<ExcludeAssets>runtime</ExcludeAssets>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
</Project>
|
||||
@@ -1,601 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion;
|
||||
|
||||
using IoTSharp.Data;
|
||||
|
||||
using Mapster;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using MQTTnet;
|
||||
using MQTTnet.Client;
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
using ThingsGateway.Admin.Core;
|
||||
using ThingsGateway.Foundation.Extension.ConcurrentQueue;
|
||||
using ThingsGateway.Foundation.Extension.Generic;
|
||||
using ThingsGateway.Foundation.Extension.String;
|
||||
|
||||
namespace ThingsGateway.Plugin.Mqtt;
|
||||
|
||||
/// <summary>
|
||||
/// 参考IotSharpClient.SDK.MQTT
|
||||
/// </summary>
|
||||
public class IotSharpClient : UpLoadBase
|
||||
{
|
||||
/// <summary>
|
||||
/// rpcmethodname存疑,定为自定义方法,在ThingsGateway上写入变量的方法固定为"Write"
|
||||
/// </summary>
|
||||
private const string WriteMethod = "WRITE";
|
||||
|
||||
private readonly IotSharpClientProperty driverPropertys = new();
|
||||
private readonly EasyLock easyLock = new();
|
||||
private readonly IotSharpClientVariableProperty variablePropertys = new();
|
||||
private ConcurrentQueue<DeviceData> _collectDeviceRunTimes = new();
|
||||
private ConcurrentQueue<VariableData> _collectVariableRunTimes = new();
|
||||
private GlobalDeviceData _globalDeviceData;
|
||||
|
||||
private IMqttClient _mqttClient;
|
||||
|
||||
private MqttClientOptions _mqttClientOptions;
|
||||
|
||||
private MqttClientSubscribeOptions _mqttSubscribeOptions;
|
||||
|
||||
private RpcSingletonService _rpcCore;
|
||||
private List<DeviceVariableRunTime> _uploadVariables = new();
|
||||
private CollectDeviceWorker collectDeviceHostService;
|
||||
/// <inheritdoc/>
|
||||
public override Type DriverDebugUIType => null;
|
||||
private TimerTick exVariableTimerTick;
|
||||
private TimerTick exDeviceTimerTick;
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override UpDriverPropertyBase DriverPropertys => driverPropertys;
|
||||
/// <inheritdoc/>
|
||||
public override List<DeviceVariableRunTime> UploadVariables => _uploadVariables;
|
||||
/// <inheritdoc/>
|
||||
public override VariablePropertyBase VariablePropertys => variablePropertys;
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override Task AfterStopAsync()
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task BeforStartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (_mqttClient != null)
|
||||
{
|
||||
var result = await TryMqttClientAsync(cancellationToken);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
LogMessage?.LogWarning($"{ToString()}-连接MqttServer失败:{result.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override async Task ExecuteAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!driverPropertys.IsInterval)
|
||||
{
|
||||
////变化推送
|
||||
var varList = _collectVariableRunTimes.ToListWithDequeue();
|
||||
if (varList?.Count != 0)
|
||||
{
|
||||
//分解List,避免超出mqtt字节大小限制
|
||||
var varData = varList.GroupBy(a => a.DeviceName).ToList();
|
||||
foreach (var item in varData)
|
||||
{
|
||||
try
|
||||
{
|
||||
Dictionary<string, object> nameValueDict = new();
|
||||
foreach (var pair in item)
|
||||
{
|
||||
//只用最新的变量值
|
||||
nameValueDict.AddOrUpdate(pair.Name, pair.Value);
|
||||
}
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
await MqttUp($"devices/{item.Key}/telemetry", nameValueDict.ToJsonString(), cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (exVariableTimerTick.IsTickHappen())
|
||||
{
|
||||
try
|
||||
{
|
||||
var varList = _uploadVariables.Adapt<List<VariableData>>();
|
||||
if (varList?.Count != 0)
|
||||
{
|
||||
//分解List,避免超出mqtt字节大小限制
|
||||
var varData = varList.GroupBy(a => a.DeviceName).ToList();
|
||||
foreach (var item in varData)
|
||||
{
|
||||
try
|
||||
{
|
||||
Dictionary<string, object> nameValueDict = new();
|
||||
foreach (var pair in item)
|
||||
{
|
||||
//只用最新的变量值
|
||||
nameValueDict.AddOrUpdate(pair.Name, pair.Value);
|
||||
}
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
await MqttUp($"devices/{item.Key}/telemetry", nameValueDict.ToJsonString(), cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
try
|
||||
{
|
||||
if (!driverPropertys.IsInterval)
|
||||
{
|
||||
////变化推送
|
||||
var devList = _collectDeviceRunTimes.ToListWithDequeue();
|
||||
if (devList?.Count != 0)
|
||||
{
|
||||
//分解List,避免超出mqtt字节大小限制
|
||||
var devData = devList.ChunkTrivialBetter(driverPropertys.SplitSize);
|
||||
foreach (var item in devData)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (exDeviceTimerTick.IsTickHappen())
|
||||
{
|
||||
var devList = _collectDevice.Adapt<List<DeviceData>>();
|
||||
if (devList?.Count != 0)
|
||||
{
|
||||
//分解List,避免超出mqtt字节大小限制
|
||||
var devData = devList.ChunkTrivialBetter(driverPropertys.SplitSize);
|
||||
foreach (var item in devData)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
if (driverPropertys.CycleInterval > UploadDeviceThread.CycleInterval + 50)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(driverPropertys.CycleInterval - UploadDeviceThread.CycleInterval, cancellationToken);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool IsConnected() => _mqttClient?.IsConnected == true;
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString()
|
||||
{
|
||||
return $" {nameof(IotSharpClient)}-IP:{driverPropertys.IP}-Port:{driverPropertys.Port}-Accesstoken:{driverPropertys.Accesstoken}";
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
_globalDeviceData?.AllVariables?.ForEach(a => a.VariableValueChange -= VariableValueChange);
|
||||
|
||||
_collectDevice?.ForEach(a =>
|
||||
{
|
||||
a.DeviceStatusChange -= DeviceStatusChange;
|
||||
});
|
||||
_mqttClient?.SafeDispose();
|
||||
_mqttClient = null;
|
||||
_uploadVariables = null;
|
||||
_collectDeviceRunTimes.Clear();
|
||||
_collectVariableRunTimes.Clear();
|
||||
_collectDeviceRunTimes = null;
|
||||
_collectVariableRunTimes = null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogError(ex);
|
||||
}
|
||||
|
||||
}
|
||||
private List<CollectDeviceRunTime> _collectDevice;
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Init(UploadDeviceRunTime device)
|
||||
{
|
||||
var mqttFactory = new MqttFactory(new PrivateLogger(LogMessage));
|
||||
_mqttClientOptions = mqttFactory.CreateClientOptionsBuilder()
|
||||
.WithClientId(Guid.NewGuid().ToString())
|
||||
.WithCredentials(driverPropertys.Accesstoken)//账密
|
||||
.WithTcpServer(driverPropertys.IP, driverPropertys.Port)//服务器
|
||||
.WithCleanSession(true)
|
||||
.WithKeepAlivePeriod(TimeSpan.FromSeconds(120.0))
|
||||
.Build();
|
||||
_mqttSubscribeOptions = mqttFactory.CreateSubscribeOptionsBuilder()
|
||||
.WithTopicFilter(
|
||||
f =>
|
||||
{
|
||||
f.WithTopic($"devices/+/rpc/request/+/+");//RPC控制请求,需要订阅
|
||||
})
|
||||
|
||||
.Build();
|
||||
_mqttClient = mqttFactory.CreateMqttClient();
|
||||
_mqttClient.ConnectedAsync += MqttClient_ConnectedAsync;
|
||||
_mqttClient.ApplicationMessageReceivedAsync += MqttClient_ApplicationMessageReceivedAsync;
|
||||
_globalDeviceData = App.GetService<GlobalDeviceData>();
|
||||
_rpcCore = App.GetService<RpcSingletonService>();
|
||||
collectDeviceHostService = BackgroundServiceUtil.GetBackgroundService<CollectDeviceWorker>();
|
||||
|
||||
|
||||
var tags = _globalDeviceData.AllVariables.Where(a => a.VariablePropertys.ContainsKey(device.Id))
|
||||
.Where(b => GetPropertyValue(b, nameof(variablePropertys.Enable)).GetBoolValue())
|
||||
.ToList();
|
||||
|
||||
_uploadVariables = tags;
|
||||
|
||||
_collectDevice = _globalDeviceData.CollectDevices.Where(a => _uploadVariables.Select(b => b.DeviceId).Contains(a.Id)).ToList();
|
||||
|
||||
_collectDevice?.ForEach(a =>
|
||||
{
|
||||
a.DeviceStatusChange += DeviceStatusChange;
|
||||
});
|
||||
_uploadVariables.ForEach(a =>
|
||||
{
|
||||
a.VariableValueChange += VariableValueChange;
|
||||
});
|
||||
if (driverPropertys.UploadInterval <= 1000) driverPropertys.UploadInterval = 1000;
|
||||
exVariableTimerTick = new(driverPropertys.UploadInterval);
|
||||
exDeviceTimerTick = new(driverPropertys.UploadInterval);
|
||||
}
|
||||
|
||||
private void DeviceStatusChange(CollectDeviceRunTime collectDeviceRunTime)
|
||||
{
|
||||
if (driverPropertys?.IsInterval != true)
|
||||
_collectDeviceRunTimes.Enqueue(collectDeviceRunTime.Adapt<DeviceData>());
|
||||
}
|
||||
|
||||
private async Task MqttClient_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs e)
|
||||
{
|
||||
|
||||
if (e.ApplicationMessage.Topic.StartsWith($"devices/") && e.ApplicationMessage.Topic.Contains("/rpc/request/"))
|
||||
{
|
||||
var tps = e.ApplicationMessage.Topic.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var rpcmethodname = tps[4];
|
||||
var rpcdevicename = tps[1];
|
||||
var rpcrequestid = tps[5];
|
||||
if (!string.IsNullOrEmpty(rpcmethodname) && !string.IsNullOrEmpty(rpcdevicename) && !string.IsNullOrEmpty(rpcrequestid))
|
||||
{
|
||||
var rpcResponse = new RpcResponse()
|
||||
{
|
||||
DeviceId = rpcdevicename,
|
||||
ResponseId = rpcrequestid,
|
||||
Method = rpcmethodname,
|
||||
Success = false,
|
||||
Data = "参数为空"
|
||||
};
|
||||
await SendResponseAsync(rpcResponse);
|
||||
return;
|
||||
}
|
||||
if (!driverPropertys.DeviceRpcEnable)
|
||||
{
|
||||
var rpcResponse = new RpcResponse()
|
||||
{
|
||||
DeviceId = rpcdevicename,
|
||||
ResponseId = rpcrequestid,
|
||||
Method = rpcmethodname,
|
||||
Success = false,
|
||||
Data = "不允许写入"
|
||||
};
|
||||
await SendResponseAsync(rpcResponse);
|
||||
return;
|
||||
}
|
||||
//rpcmethodname定为自定义方法,在ThingsGateway上写入变量的方法固定为"Write"
|
||||
if (rpcmethodname.ToUpper() != WriteMethod)
|
||||
{
|
||||
var rpcResponse = new RpcResponse()
|
||||
{
|
||||
DeviceId = rpcdevicename,
|
||||
ResponseId = rpcrequestid,
|
||||
Method = rpcmethodname,
|
||||
Success = false,
|
||||
Data = "不支持的方法"
|
||||
};
|
||||
await SendResponseAsync(rpcResponse);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
RpcResponse rpcResponse = new();
|
||||
var nameValue = e.ApplicationMessage.ConvertPayloadToString().FromJsonString<List<KeyValuePair<string, string>>>();
|
||||
Dictionary<string, OperResult> results = new();
|
||||
if (nameValue?.Count > 0)
|
||||
{
|
||||
foreach (var item in nameValue)
|
||||
{
|
||||
var tag = _uploadVariables.FirstOrDefault(a => a.Name == item.Key);
|
||||
if (tag != null)
|
||||
{
|
||||
var rpcEnable =
|
||||
GetPropertyValue(tag, nameof(variablePropertys.VariableRpcEnable)).ToBoolean()
|
||||
&& driverPropertys.DeviceRpcEnable;
|
||||
if (rpcEnable == true)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
results.Add(item.Key, new OperResult("权限不足,变量不支持写入"));
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
results.Add(item.Key, new OperResult("不存在该变量"));
|
||||
}
|
||||
}
|
||||
|
||||
var result = await _rpcCore.InvokeDeviceMethodAsync(ToString() + "-" + rpcrequestid, nameValue
|
||||
.Where(a => !results.Any(b => b.Key == a.Key))
|
||||
.ToDictionary(a => a.Key, a => a.Value));
|
||||
|
||||
results.AddRange(result);
|
||||
rpcResponse = new()
|
||||
{
|
||||
DeviceId = rpcdevicename,
|
||||
ResponseId = rpcrequestid,
|
||||
Method = rpcmethodname,
|
||||
Success = !results.Any(a => !a.Value.IsSuccess),
|
||||
Data = results.ToJsonString()
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
rpcResponse = new()
|
||||
{
|
||||
DeviceId = rpcdevicename,
|
||||
ResponseId = rpcrequestid,
|
||||
Method = rpcmethodname,
|
||||
Success = false,
|
||||
Data = "消息体参数无法解析"
|
||||
};
|
||||
}
|
||||
|
||||
await SendResponseAsync(rpcResponse);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
async Task SendResponseAsync(RpcResponse rpcResponse)
|
||||
{
|
||||
try
|
||||
{
|
||||
var topic = $"devices/{rpcResponse.DeviceId}/rpc/response/{rpcResponse.Method}/{rpcResponse.ResponseId}";
|
||||
|
||||
var variableMessage = new MqttApplicationMessageBuilder()
|
||||
.WithTopic($"{topic}")
|
||||
.WithPayload(rpcResponse.ToJsonString()).Build();
|
||||
var isConnect = await TryMqttClientAsync(CancellationToken.None);
|
||||
if (isConnect.IsSuccess)
|
||||
await _mqttClient.PublishAsync(variableMessage);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private async Task MqttClient_ConnectedAsync(MqttClientConnectedEventArgs arg)
|
||||
{
|
||||
var subResult = await _mqttClient.SubscribeAsync(_mqttSubscribeOptions);
|
||||
|
||||
if (subResult.Items.Any(a => a.ResultCode > (MqttClientSubscribeResultCode)10))
|
||||
{
|
||||
LogMessage?.LogWarning(subResult.Items
|
||||
.Where(a => a.ResultCode > (MqttClientSubscribeResultCode)10)
|
||||
.Select(a => a.ToString()).ToJsonString());
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 上传mqtt内容,并进行离线缓存
|
||||
/// </summary>
|
||||
/// <param name="topic"></param>
|
||||
/// <param name="payLoad"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
private async Task MqttUp(string topic, string payLoad, CancellationToken cancellationToken)
|
||||
{
|
||||
var variableMessage = new MqttApplicationMessageBuilder()
|
||||
.WithTopic(topic)
|
||||
.WithPayload(payLoad).Build();
|
||||
var isConnect = await TryMqttClientAsync(cancellationToken);
|
||||
if (isConnect.IsSuccess)
|
||||
{
|
||||
//连接成功时补发缓存数据
|
||||
var cacheData = await CacheDb.GetCacheData();
|
||||
foreach (var item in cacheData)
|
||||
{
|
||||
var cacheMessage = new MqttApplicationMessageBuilder()
|
||||
.WithTopic(item.Topic)
|
||||
.WithPayload(item.CacheStr).Build();
|
||||
var cacheResult = await _mqttClient.PublishAsync(cacheMessage, cancellationToken);
|
||||
if (cacheResult.IsSuccess)
|
||||
{
|
||||
await CacheDb.DeleteCacheData(item.Id);
|
||||
LogMessage.Trace($"{FoundationConst.LogMessageHeader}主题:{item.Topic}{Environment.NewLine}负载:{item.CacheStr}");
|
||||
}
|
||||
}
|
||||
|
||||
var result = await _mqttClient.PublishAsync(variableMessage, cancellationToken);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
await CacheDb.AddCacheData(topic, payLoad, driverPropertys.CacheMaxCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogMessage.Trace($"{FoundationConst.LogMessageHeader}主题:{topic}{Environment.NewLine}负载:{payLoad}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await CacheDb.AddCacheData(topic, payLoad, driverPropertys.CacheMaxCount);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<OperResult> TryMqttClientAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (_mqttClient?.IsConnected == true)
|
||||
return OperResult.CreateSuccessResult();
|
||||
return await Cilent();
|
||||
|
||||
async Task<OperResult> Cilent()
|
||||
{
|
||||
if (_mqttClient?.IsConnected == true)
|
||||
return OperResult.CreateSuccessResult();
|
||||
try
|
||||
{
|
||||
await easyLock.WaitAsync();
|
||||
if (_mqttClient?.IsConnected == true)
|
||||
return OperResult.CreateSuccessResult();
|
||||
using var timeoutToken = new CancellationTokenSource(TimeSpan.FromMilliseconds(driverPropertys.ConnectTimeOut));
|
||||
using CancellationTokenSource StoppingToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutToken.Token);
|
||||
if (_mqttClient?.IsConnected == true)
|
||||
return OperResult.CreateSuccessResult();
|
||||
if (_mqttClient == null)
|
||||
return new OperResult("未初始化");
|
||||
var result = await _mqttClient?.ConnectAsync(_mqttClientOptions, StoppingToken.Token);
|
||||
if (result.ResultCode == MqttClientConnectResultCode.Success)
|
||||
{
|
||||
return OperResult.CreateSuccessResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult(result.ReasonString);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
easyLock.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
private void VariableValueChange(DeviceVariableRunTime collectVariableRunTime)
|
||||
{
|
||||
if (driverPropertys?.IsInterval != true)
|
||||
_collectVariableRunTimes.Enqueue(collectVariableRunTime.Adapt<VariableData>());
|
||||
}
|
||||
}
|
||||
@@ -1,569 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion;
|
||||
|
||||
using Mapster;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using MQTTnet;
|
||||
using MQTTnet.Client;
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
using System.Text;
|
||||
|
||||
using ThingsGateway.Foundation.Extension.ConcurrentQueue;
|
||||
using ThingsGateway.Foundation.Extension.Generic;
|
||||
using ThingsGateway.Foundation.Extension.String;
|
||||
|
||||
namespace ThingsGateway.Plugin.Mqtt;
|
||||
|
||||
/// <summary>
|
||||
/// MqttClient
|
||||
/// </summary>
|
||||
public class MqttClient : UpLoadBase
|
||||
{
|
||||
private readonly MqttClientProperty driverPropertys = new();
|
||||
private readonly EasyLock easyLock = new();
|
||||
private readonly MqttClientVariableProperty variablePropertys = new();
|
||||
private List<CollectDeviceRunTime> _collectDevice;
|
||||
private ConcurrentQueue<DeviceData> _collectDeviceRunTimes = new();
|
||||
private ConcurrentQueue<VariableData> _collectVariableRunTimes = new();
|
||||
private GlobalDeviceData _globalDeviceData;
|
||||
private IMqttClient _mqttClient;
|
||||
|
||||
private MqttClientOptions _mqttClientOptions;
|
||||
|
||||
private MqttClientSubscribeOptions _mqttSubscribeOptions;
|
||||
|
||||
private RpcSingletonService _rpcCore;
|
||||
|
||||
private List<DeviceVariableRunTime> _uploadVariables = new();
|
||||
|
||||
private CollectDeviceWorker collectDeviceHostService;
|
||||
private TimerTick exDeviceTimerTick;
|
||||
|
||||
private TimerTick exVariableTimerTick;
|
||||
/// <inheritdoc/>
|
||||
public override Type DriverDebugUIType => typeof(MqttClientDebugPage);
|
||||
/// <inheritdoc/>
|
||||
public override UpDriverPropertyBase DriverPropertys => driverPropertys;
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override List<DeviceVariableRunTime> UploadVariables => _uploadVariables;
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override VariablePropertyBase VariablePropertys => variablePropertys;
|
||||
/// <inheritdoc/>
|
||||
public override Task AfterStopAsync()
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task BeforStartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (_mqttClient != null)
|
||||
{
|
||||
var result = await TryMqttClientAsync(cancellationToken);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
LogMessage?.LogWarning($"{ToString()}-连接MqttServer失败:{result.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override async Task ExecuteAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!driverPropertys.IsInterval)
|
||||
{
|
||||
////变化推送
|
||||
var varList = _collectVariableRunTimes.ToListWithDequeue();
|
||||
if (varList?.Count != 0)
|
||||
{
|
||||
//分解List,避免超出mqtt字节大小限制
|
||||
var varData = varList.ChunkTrivialBetter(driverPropertys.SplitSize);
|
||||
foreach (var item in varData)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
await MqttUp($"{driverPropertys.VariableTopic}", item.GetSciptListValue(driverPropertys.BigTextScriptVariableModel), cancellationToken);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (exVariableTimerTick.IsTickHappen())
|
||||
{
|
||||
try
|
||||
{
|
||||
var varList = _uploadVariables.Adapt<List<VariableData>>();
|
||||
if (varList?.Count != 0)
|
||||
{
|
||||
//分解List,避免超出mqtt字节大小限制
|
||||
var varData = varList.ChunkTrivialBetter(driverPropertys.SplitSize);
|
||||
foreach (var item in varData)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
|
||||
await MqttUp($"{driverPropertys.VariableTopic}", item.GetSciptListValue(driverPropertys.BigTextScriptVariableModel), cancellationToken);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
try
|
||||
{
|
||||
if (!driverPropertys.IsInterval)
|
||||
{
|
||||
////变化推送
|
||||
var devList = _collectDeviceRunTimes.ToListWithDequeue();
|
||||
if (devList?.Count != 0)
|
||||
{
|
||||
//分解List,避免超出mqtt字节大小限制
|
||||
var devData = devList.ChunkTrivialBetter(driverPropertys.SplitSize);
|
||||
foreach (var item in devData)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
await MqttUp($"{driverPropertys.DeviceTopic}", item.GetSciptListValue(driverPropertys.BigTextScriptDeviceModel), cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (exDeviceTimerTick.IsTickHappen())
|
||||
{
|
||||
var devList = _collectDevice.Adapt<List<DeviceData>>();
|
||||
if (devList?.Count != 0)
|
||||
{
|
||||
//分解List,避免超出mqtt字节大小限制
|
||||
var devData = devList.ChunkTrivialBetter(driverPropertys.SplitSize);
|
||||
foreach (var item in devData)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
await MqttUp($"{driverPropertys.DeviceTopic}", item.GetSciptListValue(driverPropertys.BigTextScriptDeviceModel), cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
if (driverPropertys.CycleInterval > UploadDeviceThread.CycleInterval + 50)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(driverPropertys.CycleInterval - UploadDeviceThread.CycleInterval, cancellationToken);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override bool IsConnected() => _mqttClient?.IsConnected == true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString()
|
||||
{
|
||||
return $" {nameof(MqttClient)} IP:{driverPropertys.IP} Port:{driverPropertys.Port}";
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
_globalDeviceData?.AllVariables?.ForEach(a => a.VariableValueChange -= VariableValueChange);
|
||||
|
||||
_globalDeviceData?.CollectDevices?.ForEach(a =>
|
||||
{
|
||||
a.DeviceStatusChange -= DeviceStatusChange;
|
||||
});
|
||||
_mqttClient?.SafeDispose();
|
||||
_mqttClient = null;
|
||||
_uploadVariables = null;
|
||||
_collectDeviceRunTimes.Clear();
|
||||
_collectVariableRunTimes.Clear();
|
||||
_collectDeviceRunTimes = null;
|
||||
_collectVariableRunTimes = null;
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Init(UploadDeviceRunTime device)
|
||||
{
|
||||
var mqttFactory = new MqttFactory(new PrivateLogger(LogMessage));
|
||||
_mqttClientOptions = mqttFactory.CreateClientOptionsBuilder()
|
||||
.WithClientId(driverPropertys.ConnectId)
|
||||
.WithCredentials(driverPropertys.UserName, driverPropertys.Password)//账密
|
||||
.WithTcpServer(driverPropertys.IP, driverPropertys.Port)//服务器
|
||||
.WithCleanSession(true)
|
||||
.WithKeepAlivePeriod(TimeSpan.FromSeconds(120.0))
|
||||
.WithoutThrowOnNonSuccessfulConnectResponse()
|
||||
.Build();
|
||||
_mqttSubscribeOptions = mqttFactory.CreateSubscribeOptionsBuilder()
|
||||
.WithTopicFilter(
|
||||
f =>
|
||||
{
|
||||
f.WithTopic(driverPropertys.RpcWriteTopic);
|
||||
})
|
||||
.WithTopicFilter(
|
||||
f =>
|
||||
{
|
||||
f.WithTopic(driverPropertys.QuestRpcTopic);
|
||||
})
|
||||
.Build();
|
||||
_mqttClient = mqttFactory.CreateMqttClient();
|
||||
_mqttClient.ConnectedAsync += MqttClient_ConnectedAsync;
|
||||
_mqttClient.ApplicationMessageReceivedAsync += MqttClient_ApplicationMessageReceivedAsync;
|
||||
_globalDeviceData = App.GetService<GlobalDeviceData>();
|
||||
_rpcCore = App.GetService<RpcSingletonService>();
|
||||
collectDeviceHostService = BackgroundServiceUtil.GetBackgroundService<CollectDeviceWorker>();
|
||||
|
||||
var tags = _globalDeviceData.AllVariables.Where(a => a.VariablePropertys.ContainsKey(device.Id))
|
||||
.Where(b => GetPropertyValue(b, nameof(variablePropertys.Enable)).GetBoolValue())
|
||||
.ToList();
|
||||
|
||||
_uploadVariables = tags;
|
||||
|
||||
_collectDevice = _globalDeviceData.CollectDevices.Where(a => _uploadVariables.Select(b => b.DeviceId).Contains(a.Id)).ToList();
|
||||
if (!driverPropertys.IsInterval)
|
||||
{
|
||||
_collectDevice.ForEach(a =>
|
||||
{
|
||||
a.DeviceStatusChange += DeviceStatusChange;
|
||||
});
|
||||
_uploadVariables.ForEach(a =>
|
||||
{
|
||||
a.VariableValueChange += VariableValueChange;
|
||||
});
|
||||
}
|
||||
|
||||
if (driverPropertys.UploadInterval <= 1000) driverPropertys.UploadInterval = 1000;
|
||||
exVariableTimerTick = new(driverPropertys.UploadInterval);
|
||||
exDeviceTimerTick = new(driverPropertys.UploadInterval);
|
||||
|
||||
}
|
||||
|
||||
private async Task AllPublishAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
//保留消息
|
||||
//分解List,避免超出mqtt字节大小限制
|
||||
var varData = _globalDeviceData.AllVariables.Adapt<List<VariableData>>().ChunkTrivialBetter(driverPropertys.SplitSize);
|
||||
var devData = _globalDeviceData.CollectDevices.Adapt<List<DeviceData>>().ChunkTrivialBetter(driverPropertys.SplitSize);
|
||||
var isConnect = await TryMqttClientAsync(cancellationToken);
|
||||
foreach (var item in devData)
|
||||
{
|
||||
var devMessage = new MqttApplicationMessageBuilder()
|
||||
.WithTopic($"{driverPropertys.DeviceTopic}")
|
||||
.WithPayload(item.GetSciptListValue(driverPropertys.BigTextScriptDeviceModel)).Build();
|
||||
if (isConnect.IsSuccess)
|
||||
await _mqttClient.PublishAsync(devMessage, cancellationToken);
|
||||
}
|
||||
|
||||
foreach (var item in varData)
|
||||
{
|
||||
var varMessage = new MqttApplicationMessageBuilder()
|
||||
.WithTopic($"{driverPropertys.VariableTopic}")
|
||||
.WithPayload(item.GetSciptListValue(driverPropertys.BigTextScriptVariableModel)).Build();
|
||||
if (isConnect.IsSuccess)
|
||||
await _mqttClient.PublishAsync(varMessage, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private void DeviceStatusChange(CollectDeviceRunTime collectDeviceRunTime)
|
||||
{
|
||||
if (driverPropertys?.IsInterval != true)
|
||||
_collectDeviceRunTimes.Enqueue(collectDeviceRunTime.Adapt<DeviceData>());
|
||||
}
|
||||
|
||||
private async Task MqttClient_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs args)
|
||||
{
|
||||
if (args.ApplicationMessage.Topic == driverPropertys.QuestRpcTopic && args.ApplicationMessage.PayloadSegment.Count > 0)
|
||||
{
|
||||
await AllPublishAsync(CancellationToken.None);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!driverPropertys.DeviceRpcEnable || string.IsNullOrEmpty(args.ClientId))
|
||||
return;
|
||||
if (args.ApplicationMessage.Topic != driverPropertys.RpcWriteTopic)
|
||||
return;
|
||||
var rpcDatas = Encoding.UTF8.GetString(args.ApplicationMessage.PayloadSegment).FromJsonString<MqttRpcNameVaueWithId>();
|
||||
if (rpcDatas == null)
|
||||
return;
|
||||
|
||||
MqttRpcResult mqttRpcResult = new() { RpcId = rpcDatas.RpcId, Success = true };
|
||||
try
|
||||
{
|
||||
foreach (var rpcData in rpcDatas.WriteInfos)
|
||||
{
|
||||
|
||||
var tag = _uploadVariables.FirstOrDefault(a => a.Name == rpcData.Key);
|
||||
if (tag != null)
|
||||
{
|
||||
var rpcEnable = GetPropertyValue(tag, nameof(variablePropertys.VariableRpcEnable)).ToBoolean();
|
||||
if (rpcEnable == true)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
mqttRpcResult.Success = false;
|
||||
mqttRpcResult.Message.Add(rpcData.Key, new("权限不足,变量不支持写入"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mqttRpcResult.Success = false;
|
||||
mqttRpcResult.Message.Add(rpcData.Key, new("不存在该变量"));
|
||||
}
|
||||
}
|
||||
|
||||
var result = await _rpcCore.InvokeDeviceMethodAsync(ToString() + "-" + args.ClientId,
|
||||
rpcDatas.WriteInfos.Where(
|
||||
a => !mqttRpcResult.Message.Any(b => b.Key == a.Key)).ToDictionary(a => a.Key, a => a.Value));
|
||||
|
||||
mqttRpcResult.Message.AddRange(result);
|
||||
mqttRpcResult.Success = !mqttRpcResult.Message.Any(a => !a.Value.IsSuccess);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
try
|
||||
{
|
||||
var variableMessage = new MqttApplicationMessageBuilder()
|
||||
.WithTopic($"{driverPropertys.RpcSubTopic}")
|
||||
.WithPayload(mqttRpcResult.ToJsonString()).Build();
|
||||
var isConnect = await TryMqttClientAsync(CancellationToken.None);
|
||||
if (isConnect.IsSuccess)
|
||||
await _mqttClient.PublishAsync(variableMessage);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private async Task MqttClient_ConnectedAsync(MqttClientConnectedEventArgs arg)
|
||||
{
|
||||
var subResult = await _mqttClient.SubscribeAsync(_mqttSubscribeOptions);
|
||||
if (subResult.Items.Any(a => a.ResultCode > (MqttClientSubscribeResultCode)10))
|
||||
{
|
||||
LogMessage?.Warning($"订阅失败-{subResult.Items
|
||||
.Where(a => a.ResultCode > (MqttClientSubscribeResultCode)10)
|
||||
.Select(a =>
|
||||
new
|
||||
{
|
||||
Topic = a.TopicFilter.Topic,
|
||||
ResultCode = a.ResultCode.ToString()
|
||||
}
|
||||
)
|
||||
.ToJsonString()}");
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 上传mqtt内容,并进行离线缓存
|
||||
/// </summary>
|
||||
/// <param name="topic"></param>
|
||||
/// <param name="payLoad"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
private async Task MqttUp(string topic, string payLoad, CancellationToken cancellationToken)
|
||||
{
|
||||
var variableMessage = new MqttApplicationMessageBuilder()
|
||||
.WithTopic(topic)
|
||||
.WithPayload(payLoad).Build();
|
||||
var isConnect = await TryMqttClientAsync(cancellationToken);
|
||||
if (isConnect.IsSuccess)
|
||||
{
|
||||
//连接成功时补发缓存数据
|
||||
var cacheData = await CacheDb.GetCacheData();
|
||||
foreach (var item in cacheData)
|
||||
{
|
||||
var cacheMessage = new MqttApplicationMessageBuilder()
|
||||
.WithTopic(item.Topic)
|
||||
.WithPayload(item.CacheStr).Build();
|
||||
var cacheResult = await _mqttClient.PublishAsync(cacheMessage, cancellationToken);
|
||||
if (cacheResult.IsSuccess)
|
||||
{
|
||||
await CacheDb.DeleteCacheData(item.Id);
|
||||
LogMessage.Trace($"{FoundationConst.LogMessageHeader}主题:{item.Topic}{Environment.NewLine}负载:{item.CacheStr}");
|
||||
}
|
||||
}
|
||||
|
||||
var result = await _mqttClient.PublishAsync(variableMessage, cancellationToken);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
await CacheDb.AddCacheData(topic, payLoad, driverPropertys.CacheMaxCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogMessage.Trace($"{FoundationConst.LogMessageHeader}主题:{topic}{Environment.NewLine}负载:{payLoad}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await CacheDb.AddCacheData(topic, payLoad, driverPropertys.CacheMaxCount);
|
||||
}
|
||||
}
|
||||
private async Task<OperResult> TryMqttClientAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (_mqttClient?.IsConnected == true)
|
||||
return OperResult.CreateSuccessResult();
|
||||
return await Cilent();
|
||||
|
||||
async Task<OperResult> Cilent()
|
||||
{
|
||||
if (_mqttClient?.IsConnected == true)
|
||||
return OperResult.CreateSuccessResult();
|
||||
try
|
||||
{
|
||||
await easyLock.WaitAsync();
|
||||
if (_mqttClient?.IsConnected == true)
|
||||
return OperResult.CreateSuccessResult();
|
||||
using var timeoutToken = new CancellationTokenSource(TimeSpan.FromMilliseconds(driverPropertys.ConnectTimeOut));
|
||||
using CancellationTokenSource StoppingToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutToken.Token);
|
||||
if (_mqttClient?.IsConnected == true)
|
||||
return OperResult.CreateSuccessResult();
|
||||
if (_mqttClient == null)
|
||||
{
|
||||
return new OperResult("未初始化");
|
||||
|
||||
}
|
||||
var result = await _mqttClient?.ConnectAsync(_mqttClientOptions, StoppingToken.Token);
|
||||
if (result.ResultCode == MqttClientConnectResultCode.Success)
|
||||
{
|
||||
return OperResult.CreateSuccessResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult(result.ReasonString);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
easyLock.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void VariableValueChange(DeviceVariableRunTime collectVariableRunTime)
|
||||
{
|
||||
if (driverPropertys?.IsInterval != true)
|
||||
_collectVariableRunTimes.Enqueue(collectVariableRunTime.Adapt<VariableData>());
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
@*
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
*@
|
||||
|
||||
@page "/MqttClient"
|
||||
|
||||
@namespace ThingsGateway.Foundation.Demo
|
||||
@using BlazorComponent;
|
||||
@using Microsoft.AspNetCore.Components.Web;
|
||||
@using Masa.Blazor.Presets;
|
||||
@using Microsoft.JSInterop;
|
||||
|
||||
|
||||
@using ThingsGateway.Foundation.Core;
|
||||
@using ThingsGateway.Foundation.Extension;
|
||||
@using Masa.Blazor
|
||||
|
||||
|
||||
|
||||
<MqttClientPage @ref=mqttClientPage></MqttClientPage>
|
||||
|
||||
|
||||
<DriverDebugUIPage @ref=driverDebugUIPage Sections="_sections" ShowDefaultOtherContent=false>
|
||||
<ReadWriteContent>
|
||||
<div class="my-1 py-1">
|
||||
|
||||
<MTextarea Class="mx-1 my-1" Label="订阅主题" Dense Outlined HideDetails="@("auto")" @bind-Value=@driverDebugUIPage.Address />
|
||||
|
||||
<MButton Class="mx-1 my-1" Color="primary" OnClick="SubscribeAsync">
|
||||
添加
|
||||
</MButton>
|
||||
<MButton Class="mx-1 my-1" Color="primary" OnClick="UnsubscribeAsync">
|
||||
移除
|
||||
</MButton>
|
||||
|
||||
<MTextarea Class="mx-1 my-1" Label="发布主题" Dense Outlined HideDetails="@("auto")" @bind-Value=@PublishTopic />
|
||||
<MTextarea Class="mx-1 my-1" Label="发布内容" Dense Outlined HideDetails="@("auto")" @bind-Value=@PublishValue />
|
||||
|
||||
<MButton Class="mx-1 my-1" Color="primary" OnClick="PublishAsync">
|
||||
发布
|
||||
</MButton>
|
||||
|
||||
|
||||
<MSubheader Class="mt-4 font-weight-black"> Rpc </MSubheader>
|
||||
|
||||
<MTextarea Class="mx-1 mt-3 my-1" Label="Rpc主题" Dense Outlined HideDetails="@("auto")" @bind-Value=@MqttRpcTopicPair.RequestTopic />
|
||||
<MTextarea Class="mx-1 mt-3 my-1" Label="Rpc返回主题" Dense Outlined HideDetails="@("auto")" @bind-Value=@MqttRpcTopicPair.ResponseTopic />
|
||||
<MTextarea Class="mx-1 mt-3 my-1" Label="Rpc内容" Dense Outlined HideDetails="@("auto")" @bind-Value=@driverDebugUIPage.WriteValue />
|
||||
<MButton Class="mx-1 my-1" Color="primary" OnClick="RpcExecuteAsync">
|
||||
执行
|
||||
</MButton>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<MCol Class="my-1 py-1">
|
||||
<MRow NoGutters>
|
||||
|
||||
|
||||
|
||||
</MRow>
|
||||
|
||||
</MCol>
|
||||
|
||||
</ReadWriteContent>
|
||||
</DriverDebugUIPage>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@code {
|
||||
private readonly List<(string Code, string Language)> _sections = new();
|
||||
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
#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 Masa.Blazor;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
using MQTTnet;
|
||||
using MQTTnet.Extensions.Rpc;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using ThingsGateway.Plugin.Mqtt;
|
||||
|
||||
namespace ThingsGateway.Foundation.Demo;
|
||||
|
||||
/// <summary>
|
||||
/// MqttClientDebugPage
|
||||
/// </summary>
|
||||
public partial class MqttClientDebugPage : IDisposable
|
||||
{
|
||||
private DriverDebugUIPage driverDebugUIPage;
|
||||
private MqttClientPage mqttClientPage;
|
||||
|
||||
[Inject]
|
||||
IPopupService PopupService { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
mqttClientPage.SafeDispose();
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
if (mqttClientPage != null)
|
||||
{
|
||||
mqttClientPage.LogAction = driverDebugUIPage.LogOut;
|
||||
}
|
||||
//初始化
|
||||
driverDebugUIPage.Address = "ThingsGateway/Variable";
|
||||
|
||||
driverDebugUIPage.WriteValue = new MqttRpcNameVaueWithId()
|
||||
{
|
||||
RpcId = Guid.NewGuid().ToString(),
|
||||
WriteInfos = new Dictionary<string, string>()
|
||||
{
|
||||
{ "tag1", "123" }
|
||||
}
|
||||
}.ToJsonString();
|
||||
;
|
||||
mqttClientPage.IP = "127.0.0.1";
|
||||
mqttClientPage.Port = 1883;
|
||||
mqttClientPage.UserName = "admin";
|
||||
mqttClientPage.Password = "111111";
|
||||
mqttClientPage.StateHasChangedAsync();
|
||||
|
||||
//载入配置
|
||||
StateHasChanged();
|
||||
driverDebugUIPage.Sections.Clear();
|
||||
}
|
||||
|
||||
base.OnAfterRender(firstRender);
|
||||
}
|
||||
|
||||
private async Task SubscribeAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var mqttSubscribeOptions = mqttClientPage.MqttFactory.CreateSubscribeOptionsBuilder()
|
||||
.WithTopicFilter(
|
||||
f =>
|
||||
{
|
||||
f.WithTopic(driverDebugUIPage.Address);
|
||||
})
|
||||
.Build();
|
||||
|
||||
await mqttClientPage.MqttClient.SubscribeAsync(mqttSubscribeOptions, CancellationToken.None);
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Information, $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset)} - 订阅{driverDebugUIPage.Address}成功"));
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Error, $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset)} - {ex}"));
|
||||
}
|
||||
|
||||
}
|
||||
private async Task UnsubscribeAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var mqttSubscribeOptions = mqttClientPage.MqttFactory.CreateUnsubscribeOptionsBuilder()
|
||||
.WithTopicFilter(driverDebugUIPage.Address)
|
||||
.Build();
|
||||
|
||||
await mqttClientPage.MqttClient.UnsubscribeAsync(mqttSubscribeOptions, CancellationToken.None);
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Information, $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset)} - 取消订阅{driverDebugUIPage.Address}成功"));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Error, $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset)} - {ex}"));
|
||||
}
|
||||
|
||||
}
|
||||
string PublishTopic;
|
||||
string PublishValue;
|
||||
private async Task PublishAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var devMessage = new MqttApplicationMessageBuilder()
|
||||
.WithTopic($"{PublishTopic}")
|
||||
.WithPayload(PublishValue).Build();
|
||||
await mqttClientPage.MqttClient.PublishAsync(devMessage, CancellationToken.None);
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Information, $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset)} - 发布{PublishTopic}成功"));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Error, $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset)} - {ex}"));
|
||||
}
|
||||
|
||||
}
|
||||
MqttRpcTopicPair MqttRpcTopicPair = new() { RequestTopic = "ThingsGateway/RpcWrite", ResponseTopic = "ThingsGateway/RpcSub" };
|
||||
private async Task RpcExecuteAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
using MqttRpcClient mqttRpcClient = new(mqttClientPage.MqttClient);
|
||||
var data = await mqttRpcClient.ExecuteAsync(MqttRpcTopicPair, driverDebugUIPage.WriteValue, MQTTnet.Protocol.MqttQualityOfServiceLevel.AtMostOnce, TimeSpan.FromSeconds(10));
|
||||
var str = Encoding.UTF8.GetString(data);
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Information, $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset)} - {str}"));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Error, $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset)} - {ex}"));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
#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 MQTTnet;
|
||||
using MQTTnet.Client;
|
||||
|
||||
using System.Text;
|
||||
|
||||
using ThingsGateway.Plugin.Mqtt;
|
||||
|
||||
namespace ThingsGateway.Foundation.Demo;
|
||||
/// <summary>
|
||||
/// MqttClientPage
|
||||
/// </summary>
|
||||
public partial class MqttClientPage
|
||||
{
|
||||
/// <summary>
|
||||
/// 日志输出
|
||||
/// </summary>
|
||||
public Action<LogLevel, object, string, Exception> LogAction;
|
||||
|
||||
/// <summary>
|
||||
/// OPC
|
||||
/// </summary>
|
||||
public IMqttClient MqttClient;
|
||||
public MqttClientOptions MqttClientOptions;
|
||||
|
||||
public MqttFactory MqttFactory;
|
||||
|
||||
public string ConnectId;
|
||||
|
||||
public string IP;
|
||||
|
||||
public string Password;
|
||||
|
||||
public int Port;
|
||||
|
||||
public string UserName;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
MqttClient.SafeDispose();
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
MqttFactory = new MqttFactory(new PrivateLogger(new EasyLogger(LogAction) { LogLevel = LogLevel.Trace }));
|
||||
|
||||
|
||||
MqttClient = MqttFactory.CreateMqttClient();
|
||||
MqttClient.ApplicationMessageReceivedAsync += MqttClient_ApplicationMessageReceivedAsync;
|
||||
base.OnInitialized();
|
||||
}
|
||||
|
||||
private async Task Connect()
|
||||
{
|
||||
try
|
||||
{
|
||||
await MqttClient.DisconnectAsync();
|
||||
await GetMqttClient();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogAction?.Invoke(LogLevel.Error, null, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DisConnect()
|
||||
{
|
||||
try
|
||||
{
|
||||
await MqttClient.DisconnectAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogAction?.Invoke(LogLevel.Error, null, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<IMqttClient> GetMqttClient()
|
||||
{
|
||||
//载入配置
|
||||
MqttClientOptions = MqttFactory.CreateClientOptionsBuilder()
|
||||
.WithClientId(ConnectId)
|
||||
.WithCredentials(UserName, Password)//账密
|
||||
.WithTcpServer(IP, Port)//服务器
|
||||
.WithCleanSession(true)
|
||||
.WithKeepAlivePeriod(TimeSpan.FromSeconds(120.0))
|
||||
.WithoutThrowOnNonSuccessfulConnectResponse()
|
||||
.Build();
|
||||
await MqttClient.ConnectAsync(MqttClientOptions);
|
||||
return MqttClient;
|
||||
}
|
||||
|
||||
private void LogOut(byte logLevel, object source, string message, Exception exception) => LogAction?.Invoke((LogLevel)logLevel, source, message, exception);
|
||||
|
||||
private Task MqttClient_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs args)
|
||||
{
|
||||
LogAction?.Invoke(LogLevel.Info, this, $"[{args.ApplicationMessage.Topic}]:{Encoding.UTF8.GetString(args.ApplicationMessage.PayloadSegment)}", null);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task StateHasChangedAsync()
|
||||
{
|
||||
return InvokeAsync(StateHasChanged);
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
#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 MQTTnet.Diagnostics;
|
||||
|
||||
namespace ThingsGateway.Plugin.Mqtt
|
||||
{
|
||||
internal class PrivateLogger : IMqttNetLogger
|
||||
{
|
||||
readonly ILog LogMessage;
|
||||
public PrivateLogger(ILog logger)
|
||||
{
|
||||
LogMessage = logger;
|
||||
}
|
||||
|
||||
public bool IsEnabled => true;
|
||||
public void Publish(MqttNetLogLevel logLevel, string source, string message, object[] parameters, Exception exception)
|
||||
{
|
||||
switch (logLevel)
|
||||
{
|
||||
case MqttNetLogLevel.Verbose:
|
||||
LogMessage?.Log(LogLevel.Trace, source, message != null ? (parameters != null ? message != null ? (parameters != null ? string.Format(message, parameters) : message) : string.Empty : message) : string.Empty, exception);
|
||||
break;
|
||||
|
||||
case MqttNetLogLevel.Info:
|
||||
LogMessage?.Log(LogLevel.Info, source, message != null ? (parameters != null ? string.Format(message, parameters) : message) : string.Empty, exception);
|
||||
break;
|
||||
|
||||
case MqttNetLogLevel.Warning:
|
||||
LogMessage?.Log(LogLevel.Warning, source, message != null ? (parameters != null ? string.Format(message, parameters) : message) : string.Empty, exception);
|
||||
break;
|
||||
|
||||
case MqttNetLogLevel.Error:
|
||||
LogMessage?.Log(LogLevel.Warning, source, message != null ? (parameters != null ? string.Format(message, parameters) : message) : string.Empty, exception);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// <20>˴<EFBFBD><CBB4><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><C8A8><EFBFBD><EFBFBD>Ϊȫ<CEAA>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD>ǣ<EFBFBD><C7A3><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><D4AD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><D8B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><C2B7>ֶ<EFBFBD><D6B6><EFBFBD><EFBFBD><EFBFBD>
|
||||
// <20>˴<EFBFBD><CBB4><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><C8A8><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><D8B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><C4B4>룩<EFBFBD><EBA3A9><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><DFB1><EFBFBD>Diego<67><6F><EFBFBD><EFBFBD>
|
||||
// Դ<><D4B4><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9>Э<EFBFBD><D0AD><EFBFBD><EFBFBD>ѭ<EFBFBD><D1AD><EFBFBD>ֿ<EFBFBD><D6BF>Ŀ<EFBFBD>ԴЭ<D4B4>鼰<EFBFBD><E9BCB0><EFBFBD><EFBFBD>Э<EFBFBD><D0AD>
|
||||
// GiteeԴ<65><D4B4><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway
|
||||
// GithubԴ<62><D4B4><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway
|
||||
// ʹ<><CAB9><EFBFBD>ĵ<EFBFBD><C4B5><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQȺ<51><C8BA>605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using MQTTnet.Protocol;
|
||||
|
||||
using System.Text;
|
||||
|
||||
namespace MQTTnet.Extensions.Rpc
|
||||
{
|
||||
public static class MqttRpcClientExtensions
|
||||
{
|
||||
public static Task<byte[]> ExecuteAsync(this MqttRpcClient client, MqttRpcTopicPair mqttRpcTopicPair, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel, TimeSpan timeout)
|
||||
{
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
|
||||
var buffer = Encoding.UTF8.GetBytes(payload ?? string.Empty);
|
||||
|
||||
return client.ExecuteAsync(mqttRpcTopicPair, buffer, qualityOfServiceLevel, timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// <20>˴<EFBFBD><CBB4><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><C8A8><EFBFBD><EFBFBD>Ϊȫ<CEAA>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD>ǣ<EFBFBD><C7A3><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><D4AD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><D8B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><C2B7>ֶ<EFBFBD><D6B6><EFBFBD><EFBFBD><EFBFBD>
|
||||
// <20>˴<EFBFBD><CBB4><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><C8A8><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><D8B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><C4B4>룩<EFBFBD><EBA3A9><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><DFB1><EFBFBD>Diego<67><6F><EFBFBD><EFBFBD>
|
||||
// Դ<><D4B4><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9>Э<EFBFBD><D0AD><EFBFBD><EFBFBD>ѭ<EFBFBD><D1AD><EFBFBD>ֿ<EFBFBD><D6BF>Ŀ<EFBFBD>ԴЭ<D4B4>鼰<EFBFBD><E9BCB0><EFBFBD><EFBFBD>Э<EFBFBD><D0AD>
|
||||
// GiteeԴ<65><D4B4><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway
|
||||
// GithubԴ<62><D4B4><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway
|
||||
// ʹ<><CAB9><EFBFBD>ĵ<EFBFBD><C4B5><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQȺ<51><C8BA>605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace MQTTnet.Extensions.Rpc
|
||||
{
|
||||
public sealed class MqttRpcTopicPair
|
||||
{
|
||||
public string RequestTopic { get; set; }
|
||||
|
||||
public string ResponseTopic { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
|
||||
<Exec Command=" set dir="$(SolutionDir)Web\ThingsGateway.Web.Entry\bin\$(Configuration)\$(TargetFramework)\Plugins\$(AssemblyName)"
 if not exist %25dir%25 md %25dir%25 
copy "$(TargetDir)*Mqtt*.dll" %25dir%25


" />
|
||||
|
||||
</Target>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Web\ThingsGateway.Components\ThingsGateway.Components.csproj">
|
||||
<Private>false</Private>
|
||||
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
||||
<ExcludeAssets>runtime</ExcludeAssets>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\DriverDebugUIBase.cs" Link="DebugPage\DriverDebugUIBase.cs" />
|
||||
<Compile Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\DriverDebugUIPage.razor.cs" Link="DebugPage\DriverDebugUIPage.razor.cs" />
|
||||
<Compile Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\SerialSessionPage.razor.cs" Link="DebugPage\SerialSessionPage.razor.cs" />
|
||||
<Compile Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\TcpClientPage.razor.cs" Link="DebugPage\TcpClientPage.razor.cs" />
|
||||
<Compile Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\TcpServerPage.razor.cs" Link="DebugPage\TcpServerPage.razor.cs" />
|
||||
<Compile Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\UdpSessionPage.razor.cs" Link="DebugPage\UdpSessionPage.razor.cs" />
|
||||
<Content Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\DriverDebugUIPage.razor" Link="DebugPage\DriverDebugUIPage.razor" />
|
||||
<Content Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\SerialSessionPage.razor" Link="DebugPage\SerialSessionPage.razor" />
|
||||
<Content Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\TcpClientPage.razor" Link="DebugPage\TcpClientPage.razor" />
|
||||
<Content Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\TcpServerPage.razor" Link="DebugPage\TcpServerPage.razor" />
|
||||
<Content Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\UdpSessionPage.razor" Link="DebugPage\UdpSessionPage.razor" />
|
||||
|
||||
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
</Project>
|
||||
@@ -1,46 +0,0 @@
|
||||
@*
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
*@
|
||||
|
||||
@namespace ThingsGateway.Foundation.Demo
|
||||
@using BlazorComponent;
|
||||
@using Microsoft.AspNetCore.Components.Web;
|
||||
@using System.IO.Ports;
|
||||
@using System.Collections.Concurrent;
|
||||
@using ThingsGateway.Foundation.Core;
|
||||
@using ThingsGateway.Foundation.Adapter.OPCDA;
|
||||
@using Masa.Blazor
|
||||
@implements IDisposable
|
||||
<MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%">
|
||||
<div class="mb-4">设备配置</div>
|
||||
<MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
|
||||
<MTextField Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.GroupSize) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.GroupSize />
|
||||
<MTextField Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.UpdateRate) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.UpdateRate />
|
||||
|
||||
<MTextField Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.DeadBand) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.DeadBand />
|
||||
<MTextField Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.CheckRate) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.CheckRate />
|
||||
<MTextField Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.OPCIP) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.OPCIP />
|
||||
<MTextField Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.OPCName) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.OPCName />
|
||||
|
||||
<MCheckbox Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.ActiveSubscribe) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.ActiveSubscribe />
|
||||
|
||||
<MButton Class="ma-1" OnClick=@Connect Color="primary">
|
||||
连接
|
||||
</MButton>
|
||||
|
||||
<MButton Class="ma-1" OnClick=@DisConnect Color="red">
|
||||
断开
|
||||
</MButton>
|
||||
</MRow>
|
||||
|
||||
|
||||
|
||||
</MCard>
|
||||
@@ -1,59 +0,0 @@
|
||||
#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.Extensions.Logging;
|
||||
|
||||
namespace ThingsGateway.Plugin.OPCUA;
|
||||
|
||||
|
||||
public partial class OPCUAServer
|
||||
{
|
||||
private class OPCUALogger : ILogger
|
||||
{
|
||||
private ILog _log;
|
||||
public OPCUALogger(ILog log)
|
||||
{
|
||||
_log = log;
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Set the log level
|
||||
/// </summary>
|
||||
public Microsoft.Extensions.Logging.LogLevel LogLevel { get; set; } = Microsoft.Extensions.Logging.LogLevel.Trace;
|
||||
/// <inheritdoc/>
|
||||
public IDisposable BeginScope<TState>(TState state) => default;
|
||||
/// <inheritdoc/>
|
||||
public bool IsEnabled(Microsoft.Extensions.Logging.LogLevel logLevel) => logLevel >= LogLevel;
|
||||
/// <inheritdoc/>
|
||||
public void Log<TState>(
|
||||
Microsoft.Extensions.Logging.LogLevel logLevel,
|
||||
EventId eventId,
|
||||
TState state,
|
||||
Exception exception,
|
||||
Func<TState, Exception, string> formatter)
|
||||
{
|
||||
if (!IsEnabled(logLevel))
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
var message = formatter(state, exception);
|
||||
_log.Log((Foundation.Core.LogLevel)(byte)logLevel, state, message, exception);
|
||||
if (logLevel > Microsoft.Extensions.Logging.LogLevel.Information)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
@*
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
*@
|
||||
|
||||
@namespace ThingsGateway.Foundation.Demo
|
||||
|
||||
@using BlazorComponent;
|
||||
@using Microsoft.AspNetCore.Components.Web;
|
||||
@using System.IO.Ports;
|
||||
@using System.Collections.Concurrent;
|
||||
@using Opc.Ua.Client;
|
||||
@using Opc.Ua;
|
||||
@using System.Linq;
|
||||
@using ThingsGateway.Foundation.Core;
|
||||
@using ThingsGateway.Foundation.Adapter.OPCUA;
|
||||
@using Masa.Blazor
|
||||
@implements IDisposable
|
||||
|
||||
<MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%">
|
||||
<div class="mb-4">设备配置</div>
|
||||
<MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
|
||||
<MTextField Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.GroupSize) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.GroupSize />
|
||||
<MTextField Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.UpdateRate) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.UpdateRate />
|
||||
|
||||
<MTextField Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.DeadBand) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.DeadBand />
|
||||
<MTextField Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.KeepAliveInterval) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.KeepAliveInterval />
|
||||
|
||||
<MTextField Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.OPCUrl) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.OPCUrl />
|
||||
<MTextField Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.UserName) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.UserName />
|
||||
<MTextField Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.Password) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.Password />
|
||||
|
||||
<MCheckbox Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.ActiveSubscribe) Dense HideDetails="@("auto")" @bind-Value=@node.ActiveSubscribe />
|
||||
<MCheckbox Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.IsUseSecurity) Dense HideDetails="@("auto")" @bind-Value=@node.IsUseSecurity />
|
||||
<MCheckbox Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.CheckDomain) Dense HideDetails="@("auto")" @bind-Value=@node.CheckDomain />
|
||||
<MCheckbox Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.LoadType) Dense HideDetails="@("auto")" @bind-Value=@node.LoadType />
|
||||
|
||||
<MButton Class="ma-1" OnClick=@ConnectAsync Color="primary">
|
||||
连接
|
||||
</MButton>
|
||||
|
||||
<MButton Class="ma-1" OnClick=@DisConnect Color="red">
|
||||
断开
|
||||
</MButton>
|
||||
</MRow>
|
||||
|
||||
|
||||
|
||||
</MCard>
|
||||
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
@*
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
*@
|
||||
|
||||
@using System.Net.Http
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Microsoft.AspNetCore.Components.Routing
|
||||
@using Microsoft.AspNetCore.Components.Web
|
||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||
@using Microsoft.JSInterop
|
||||
@using BlazorComponent
|
||||
@using Masa.Blazor
|
||||
@using Masa.Blazor.Presets
|
||||
@using System.Net.Http.Json
|
||||
@using System.IO;
|
||||
@using System.Text.Json;
|
||||
@using System.Reflection;
|
||||
|
||||
@using ThingsGateway.Components;
|
||||
@using ThingsGateway.Admin.Core;
|
||||
@using ThingsGateway.Foundation.Core;
|
||||
@using ThingsGateway.Foundation.Extension.String;
|
||||
@using ThingsGateway.Admin.Application;
|
||||
|
||||
@using ThingsGateway.Core;
|
||||
@using ThingsGateway.Gateway.Application;
|
||||
@using ThingsGateway.Gateway.Core;
|
||||
@@ -1,325 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion;
|
||||
|
||||
using Mapster;
|
||||
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Reflection;
|
||||
|
||||
using ThingsGateway.Foundation.Extension;
|
||||
using ThingsGateway.Foundation.Extension.ConcurrentQueue;
|
||||
using ThingsGateway.Foundation.Extension.String;
|
||||
|
||||
namespace ThingsGateway.Plugin.QuestDB;
|
||||
public class QuestDB : UpLoadBase
|
||||
{
|
||||
private readonly ConcurrentQueue<QuestDBHistoryValue> DeviceVariableRunTimes = new();
|
||||
private readonly QuestDBProperty driverPropertys = new();
|
||||
private readonly QuestDBVariableProperty variablePropertys = new();
|
||||
private TypeAdapterConfig _config;
|
||||
private GlobalDeviceData _globalDeviceData;
|
||||
|
||||
private List<DeviceVariableRunTime> _uploadVariables = new();
|
||||
private TimerTick exTimerTick;
|
||||
public QuestDB()
|
||||
{
|
||||
_config = new TypeAdapterConfig();
|
||||
_config.ForType<DeviceVariableRunTime, HistoryValue>()
|
||||
.Map(dest => dest.Value, (src) => ValueReturn(src))
|
||||
.Map(dest => dest.CollectTime, (src) => src.CollectTime.ToUniversalTime())//注意sqlsugar插入时无时区,直接utc时间
|
||||
.Map(dest => dest.CreateTime, (src) => DateTime.UtcNow);//注意sqlsugar插入时无时区,直接utc时间
|
||||
}
|
||||
private static object ValueReturn(DeviceVariableRunTime src)
|
||||
{
|
||||
if (src.Value?.ToString()?.IsBoolValue() == true)
|
||||
{
|
||||
if (src.Value.ToBoolean())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return src.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public override Type DriverDebugUIType => null;
|
||||
public override UpDriverPropertyBase DriverPropertys => driverPropertys;
|
||||
public override List<DeviceVariableRunTime> UploadVariables => _uploadVariables;
|
||||
|
||||
public override VariablePropertyBase VariablePropertys => variablePropertys;
|
||||
|
||||
public override Task AfterStopAsync()
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override async Task BeforStartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
SqlSugarClient db = GetHisDbAsync();
|
||||
db.DbMaintenance.CreateDatabase();
|
||||
db.CodeFirst.InitTables(typeof(QuestDBHistoryValue));
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override async Task ExecuteAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var db = GetHisDbAsync();
|
||||
{
|
||||
if (!driverPropertys.IsInterval)
|
||||
{
|
||||
try
|
||||
{
|
||||
////变化推送
|
||||
var varList = DeviceVariableRunTimes.ToListWithDequeue();
|
||||
if (varList?.Count != 0)
|
||||
{
|
||||
await InserableAsync(db, varList, cancellationToken);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (exTimerTick.IsTickHappen())
|
||||
{
|
||||
try
|
||||
{
|
||||
var varList = _uploadVariables.ToList().Adapt<List<QuestDBHistoryValue>>(_config);
|
||||
if (varList?.Count != 0)
|
||||
{
|
||||
await InserableAsync(db, varList, cancellationToken);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (driverPropertys.CycleInterval > UploadDeviceThread.CycleInterval + 50)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(driverPropertys.CycleInterval - UploadDeviceThread.CycleInterval, cancellationToken);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override bool IsConnected() => _uploadVariables?.Count > 0;
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
_globalDeviceData?.AllVariables?.ForEach(a => a.VariableValueChange -= VariableValueChange);
|
||||
_uploadVariables = null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogError(ex);
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
protected override void Init(UploadDeviceRunTime device)
|
||||
{
|
||||
|
||||
_globalDeviceData = App.GetService<GlobalDeviceData>();
|
||||
|
||||
var tags = _globalDeviceData.AllVariables.Where(a => a.VariablePropertys.ContainsKey(device.Id))
|
||||
.Where(b => GetPropertyValue(b, nameof(variablePropertys.Enable)).ToBoolean())
|
||||
.ToList();
|
||||
|
||||
_uploadVariables = tags;
|
||||
|
||||
if (!driverPropertys.IsInterval)
|
||||
{
|
||||
_uploadVariables.ForEach(a =>
|
||||
{
|
||||
a.VariableValueChange += VariableValueChange;
|
||||
});
|
||||
}
|
||||
|
||||
if (_uploadVariables.Count == 0)
|
||||
{
|
||||
LogMessage.LogWarning("插件变量数量为0");
|
||||
}
|
||||
if (driverPropertys.IntervalTime < 1)
|
||||
driverPropertys.IntervalTime = 10;
|
||||
exTimerTick = new(driverPropertys.IntervalTime * 1000);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aop设置
|
||||
/// </summary>
|
||||
/// <param name="db"></param>
|
||||
private static void AopSetting(SqlSugarClient db)
|
||||
{
|
||||
var config = db.CurrentConnectionConfig;
|
||||
|
||||
// 设置超时时间
|
||||
db.Ado.CommandTimeOut = 30;
|
||||
|
||||
// 打印SQL语句
|
||||
db.Aop.OnLogExecuting = (sql, pars) =>
|
||||
{
|
||||
//如果不是开发环境就打印sql
|
||||
if (App.HostEnvironment.IsDevelopment())
|
||||
{
|
||||
if (sql.StartsWith("SELECT"))
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Green;
|
||||
}
|
||||
if (sql.StartsWith("UPDATE"))
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
}
|
||||
if (sql.StartsWith("INSERT"))
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Blue;
|
||||
}
|
||||
if (sql.StartsWith("DELETE"))
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
}
|
||||
WriteSqlLog(UtilMethods.GetSqlString(config.DbType, sql, pars));
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
Console.WriteLine();
|
||||
}
|
||||
};
|
||||
//异常
|
||||
db.Aop.OnError = (ex) =>
|
||||
{
|
||||
//如果不是开发环境就打印日志
|
||||
if (App.WebHostEnvironment.IsDevelopment())
|
||||
{
|
||||
if (ex.Parametres == null) return;
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
var pars = db.Utilities.SerializeObject(((SugarParameter[])ex.Parametres).ToDictionary(it => it.ParameterName, it => it.Value));
|
||||
WriteSqlLogError(UtilMethods.GetSqlString(config.DbType, ex.Sql, (SugarParameter[])ex.Parametres));
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
private static void WriteSqlLog(string msg)
|
||||
{
|
||||
Console.WriteLine("【Sql执行时间】:" + DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat());
|
||||
Console.WriteLine("【Sql语句】:" + msg + Environment.NewLine);
|
||||
}
|
||||
|
||||
private static void WriteSqlLogError(string msg)
|
||||
{
|
||||
Console.WriteLine("【Sql执行错误时间】:" + DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat());
|
||||
Console.WriteLine("【Sql语句】:" + msg + Environment.NewLine);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据库链接
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private SqlSugarClient GetHisDbAsync()
|
||||
{
|
||||
var configureExternalServices = new ConfigureExternalServices
|
||||
{
|
||||
EntityService = (type, column) => // 修改列可空-1、带?问号 2、String类型若没有Required
|
||||
{
|
||||
if ((type.PropertyType.IsGenericType && type.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||||
|| (type.PropertyType == typeof(string) && type.GetCustomAttribute<RequiredAttribute>() == null))
|
||||
column.IsNullable = true;
|
||||
},
|
||||
};
|
||||
var sqlSugarClient = new SqlSugarClient(new ConnectionConfig()
|
||||
{
|
||||
ConnectionString = driverPropertys.ConnectStr,//连接字符串
|
||||
DbType = DbType.QuestDB,//数据库类型
|
||||
IsAutoCloseConnection = true, //不设成true要手动close
|
||||
ConfigureExternalServices = configureExternalServices,
|
||||
}
|
||||
);
|
||||
AopSetting(sqlSugarClient);//aop配置
|
||||
return sqlSugarClient;
|
||||
}
|
||||
|
||||
private async Task InserableAsync(SqlSugarClient db, List<QuestDBHistoryValue> dbInserts, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await db.Insertable(dbInserts).ExecuteCommandAsync(cancellationToken);
|
||||
if (result > 0)
|
||||
LogMessage.Trace(FoundationConst.LogMessageHeader + dbInserts.ToJsonString());
|
||||
//连接成功时补发缓存数据
|
||||
var cacheData = await CacheDb.GetCacheData();
|
||||
foreach (var item in cacheData)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = item.CacheStr.FromJsonString<List<QuestDBHistoryValue>>();
|
||||
var cacheresult = await db.Insertable(data).ExecuteCommandAsync(cancellationToken);
|
||||
if (cacheresult > 0)
|
||||
{
|
||||
await CacheDb.DeleteCacheData(item.Id);
|
||||
LogMessage.Trace(FoundationConst.LogMessageHeader + $"主题:{item.Topic}{Environment.NewLine}负载:{item.CacheStr}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex);
|
||||
await CacheDb.AddCacheData("", dbInserts.ToJsonString(), driverPropertys.CacheMaxCount);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void VariableValueChange(DeviceVariableRunTime collectVariableRunTime)
|
||||
{
|
||||
if (!driverPropertys.IsInterval)
|
||||
DeviceVariableRunTimes.Enqueue(collectVariableRunTime.Adapt<QuestDBHistoryValue>(_config));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Plugin.QuestDB;
|
||||
|
||||
public class QuestDBProperty : UpDriverPropertyBase
|
||||
{
|
||||
[DeviceProperty("链接字符串", "")] public string ConnectStr { get; set; } = "host=localhost;port=8812;username=admin;password=quest;database=qdb;ServerCompatibilityMode=NoTypeLoading;";
|
||||
[DeviceProperty("是否间隔插入", "False时将每次变化写入")] public bool IsInterval { get; set; } = true;
|
||||
[DeviceProperty("间隔时间", "秒,实时表时代表更新间隔,历史表时代表插入间隔")] public int IntervalTime { get; set; } = 10;
|
||||
[DeviceProperty("缓存最大条数", "默认2千条")] public int CacheMaxCount { get; set; } = 2000;
|
||||
|
||||
/// <summary>
|
||||
/// 线程循环间隔
|
||||
/// </summary>
|
||||
[DeviceProperty("线程循环间隔", "最小10ms")]
|
||||
public int CycleInterval { get; set; } = 1000;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,495 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion;
|
||||
|
||||
using Mapster;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using RabbitMQ.Client;
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
using System.Text;
|
||||
|
||||
using ThingsGateway.Foundation.Extension.ConcurrentQueue;
|
||||
using ThingsGateway.Foundation.Extension.Generic;
|
||||
using ThingsGateway.Foundation.Extension.String;
|
||||
|
||||
namespace ThingsGateway.Plugin.RabbitMQ;
|
||||
/// <summary>
|
||||
/// RabbitMQ
|
||||
/// </summary>
|
||||
public class RabbitMQClient : UpLoadBase
|
||||
{
|
||||
private readonly RabbitMQClientProperty driverPropertys = new();
|
||||
private readonly RabbitMQClientVariableProperty variablePropertys = new();
|
||||
private ConcurrentQueue<DeviceData> _collectDeviceRunTimes = new();
|
||||
private ConcurrentQueue<VariableData> _collectVariableRunTimes = new();
|
||||
private IConnection _connection;
|
||||
private ConnectionFactory _connectionFactory;
|
||||
private GlobalDeviceData _globalDeviceData;
|
||||
private IModel _model;
|
||||
private RpcSingletonService _rpcCore;
|
||||
private List<DeviceVariableRunTime> _uploadVariables = new();
|
||||
/// <inheritdoc/>
|
||||
public override Type DriverDebugUIType => null;
|
||||
/// <inheritdoc/>
|
||||
public override UpDriverPropertyBase DriverPropertys => driverPropertys;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override List<DeviceVariableRunTime> UploadVariables => _uploadVariables;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override VariablePropertyBase VariablePropertys => variablePropertys;
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Task AfterStopAsync()
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Task BeforStartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private TimerTick exDeviceTimerTick;
|
||||
|
||||
private TimerTick exVariableTimerTick;
|
||||
/// <inheritdoc/>
|
||||
public override async Task ExecuteAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_model == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
// 创建连接
|
||||
_connection ??= _connectionFactory.CreateConnection();
|
||||
// 创建通道
|
||||
_model ??= _connection.CreateModel();
|
||||
// 声明路由队列
|
||||
if (driverPropertys.IsQueueDeclare)
|
||||
{
|
||||
_model?.QueueDeclare(driverPropertys.VariableQueueName, true, false, false);
|
||||
_model?.QueueDeclare(driverPropertys.DeviceQueueName, true, false, false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (!driverPropertys.IsInterval)
|
||||
{
|
||||
////变化推送
|
||||
var varList = _collectVariableRunTimes.ToListWithDequeue();
|
||||
if (varList?.Count != 0)
|
||||
{
|
||||
if (driverPropertys.IsList)
|
||||
{
|
||||
var listChunk = varList.ChunkTrivialBetter(driverPropertys.SplitSize);
|
||||
foreach (var variables in listChunk)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
var data = variables.GetSciptListValue(driverPropertys.BigTextScriptVariableModel);
|
||||
// 设置消息持久化
|
||||
IBasicProperties properties = _model?.CreateBasicProperties();
|
||||
await Publish(driverPropertys.VariableQueueName, data, properties);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var variable in varList)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
var data = variable.GetSciptListValue(driverPropertys.BigTextScriptVariableModel);
|
||||
// 设置消息持久化
|
||||
IBasicProperties properties = _model?.CreateBasicProperties();
|
||||
await Publish(driverPropertys.VariableQueueName, data, properties);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (exVariableTimerTick.IsTickHappen())
|
||||
{
|
||||
try
|
||||
{
|
||||
var varList = _uploadVariables.Adapt<List<VariableData>>();
|
||||
if (varList?.Count != 0)
|
||||
{
|
||||
if (driverPropertys.IsList)
|
||||
{
|
||||
var listChunk = varList.ChunkTrivialBetter(driverPropertys.SplitSize);
|
||||
foreach (var variables in listChunk)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
var data = variables.GetSciptListValue(driverPropertys.BigTextScriptVariableModel);
|
||||
// 设置消息持久化
|
||||
IBasicProperties properties = _model?.CreateBasicProperties();
|
||||
await Publish(driverPropertys.VariableQueueName, data, properties);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var variable in varList)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
var data = variable.GetSciptListValue(driverPropertys.BigTextScriptVariableModel);
|
||||
// 设置消息持久化
|
||||
IBasicProperties properties = _model?.CreateBasicProperties();
|
||||
await Publish(driverPropertys.VariableQueueName, data, properties);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
try
|
||||
{
|
||||
if (!driverPropertys.IsInterval)
|
||||
{
|
||||
////变化推送
|
||||
var devList = _collectDeviceRunTimes.ToListWithDequeue();
|
||||
if (devList?.Count != 0)
|
||||
{
|
||||
if (driverPropertys.IsList)
|
||||
{
|
||||
var listChunk = devList.ChunkTrivialBetter(driverPropertys.SplitSize);
|
||||
foreach (var devices in listChunk)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = devices.GetSciptListValue(driverPropertys.BigTextScriptDeviceModel);
|
||||
// 设置消息持久化
|
||||
IBasicProperties properties = _model?.CreateBasicProperties();
|
||||
await Publish(driverPropertys.DeviceQueueName, data, properties);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var devices in devList)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = devices.GetSciptListValue(driverPropertys.BigTextScriptDeviceModel);
|
||||
// 设置消息持久化
|
||||
IBasicProperties properties = _model?.CreateBasicProperties();
|
||||
await Publish(driverPropertys.DeviceQueueName, data, properties);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (exDeviceTimerTick.IsTickHappen())
|
||||
{
|
||||
var devList = _collectDevice.Adapt<List<DeviceData>>();
|
||||
if (devList?.Count != 0)
|
||||
{
|
||||
if (driverPropertys.IsList)
|
||||
{
|
||||
var listChunk = devList.ChunkTrivialBetter(driverPropertys.SplitSize);
|
||||
foreach (var devices in listChunk)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = devices.GetSciptListValue(driverPropertys.BigTextScriptDeviceModel);
|
||||
// 设置消息持久化
|
||||
IBasicProperties properties = _model?.CreateBasicProperties();
|
||||
await Publish(driverPropertys.DeviceQueueName, data, properties);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var devices in devList)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = devices.GetSciptListValue(driverPropertys.BigTextScriptDeviceModel);
|
||||
// 设置消息持久化
|
||||
IBasicProperties properties = _model?.CreateBasicProperties();
|
||||
await Publish(driverPropertys.DeviceQueueName, data, properties);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
if (driverPropertys.CycleInterval > UploadDeviceThread.CycleInterval + 50)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(driverPropertys.CycleInterval - UploadDeviceThread.CycleInterval, cancellationToken);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool IsConnected() => _connection?.IsOpen == true;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return $" {nameof(RabbitMQClient)} IP:{driverPropertys.IP} Port:{driverPropertys.Port}";
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
_globalDeviceData?.AllVariables.ForEach(a => a.VariableValueChange -= VariableValueChange);
|
||||
|
||||
_collectDevice?.ForEach(a =>
|
||||
{
|
||||
a.DeviceStatusChange -= DeviceStatusChange;
|
||||
});
|
||||
_model?.SafeDispose();
|
||||
_connection?.SafeDispose();
|
||||
_uploadVariables = null;
|
||||
_collectDeviceRunTimes.Clear();
|
||||
_collectVariableRunTimes.Clear();
|
||||
_collectDeviceRunTimes = null;
|
||||
_collectVariableRunTimes = null;
|
||||
}
|
||||
private List<CollectDeviceRunTime> _collectDevice;
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Init(UploadDeviceRunTime device)
|
||||
{
|
||||
_connectionFactory = new ConnectionFactory
|
||||
{
|
||||
HostName = driverPropertys.IP,
|
||||
Port = driverPropertys.Port,
|
||||
UserName = driverPropertys.UserName,
|
||||
Password = driverPropertys.Password,
|
||||
VirtualHost = driverPropertys.VirtualHost,
|
||||
};
|
||||
|
||||
|
||||
|
||||
_globalDeviceData = App.GetService<GlobalDeviceData>();
|
||||
_rpcCore = App.GetService<RpcSingletonService>();
|
||||
|
||||
|
||||
var tags = _globalDeviceData.AllVariables.Where(a => a.VariablePropertys.ContainsKey(device.Id))
|
||||
.Where(b => b.VariablePropertys[device.Id].Any(c =>
|
||||
{
|
||||
if (c.PropertyName == nameof(variablePropertys.Enable))
|
||||
{
|
||||
return c.Value?.GetBoolValue() == true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}))
|
||||
.ToList();
|
||||
|
||||
_uploadVariables = tags;
|
||||
|
||||
_collectDevice = _globalDeviceData.CollectDevices.Where(a => _uploadVariables.Select(b => b.DeviceId).Contains(a.Id)).ToList();
|
||||
|
||||
_collectDevice.ForEach(a =>
|
||||
{
|
||||
a.DeviceStatusChange += DeviceStatusChange;
|
||||
DeviceStatusChange(a);
|
||||
});
|
||||
_uploadVariables.ForEach(a =>
|
||||
{
|
||||
a.VariableValueChange += VariableValueChange;
|
||||
VariableValueChange(a);
|
||||
});
|
||||
|
||||
if (driverPropertys.UploadInterval <= 1000) driverPropertys.UploadInterval = 1000;
|
||||
exVariableTimerTick = new(driverPropertys.UploadInterval);
|
||||
exDeviceTimerTick = new(driverPropertys.UploadInterval);
|
||||
|
||||
}
|
||||
|
||||
private void DeviceStatusChange(CollectDeviceRunTime collectDeviceRunTime)
|
||||
{
|
||||
if (driverPropertys?.IsInterval != true)
|
||||
_collectDeviceRunTimes.Enqueue(collectDeviceRunTime.Adapt<DeviceData>());
|
||||
}
|
||||
|
||||
private async Task Publish(string queueName, string data, IBasicProperties properties)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (properties != null)
|
||||
properties.Persistent = true;
|
||||
if (_model != null)
|
||||
_model.BasicPublish(driverPropertys.ExchangeName, queueName, properties, Encoding.UTF8.GetBytes(data));
|
||||
else
|
||||
{
|
||||
await CacheDb.AddCacheData(queueName, data, driverPropertys.CacheMaxCount);
|
||||
return;
|
||||
}
|
||||
|
||||
//连接成功时补发缓存数据
|
||||
var cacheData = await CacheDb.GetCacheData(10);
|
||||
foreach (var item in cacheData)
|
||||
{
|
||||
try
|
||||
{
|
||||
_model?.BasicPublish(driverPropertys.ExchangeName, item.Topic, properties, Encoding.UTF8.GetBytes(item.CacheStr));
|
||||
LogMessage.Trace($"{FoundationConst.LogMessageHeader}主题:{item.Topic}{Environment.NewLine}负载:{item.CacheStr}");
|
||||
|
||||
await CacheDb.DeleteCacheData(item.Id);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
LogMessage.Trace($"{FoundationConst.LogMessageHeader}主题:{queueName}{Environment.NewLine}负载:{data}");
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
await CacheDb.AddCacheData(queueName, data, driverPropertys.CacheMaxCount);
|
||||
}
|
||||
|
||||
}
|
||||
private void VariableValueChange(DeviceVariableRunTime collectVariableRunTime)
|
||||
{
|
||||
if (driverPropertys?.IsInterval != true)
|
||||
_collectVariableRunTimes.Enqueue(collectVariableRunTime.Adapt<VariableData>());
|
||||
}
|
||||
}
|
||||
@@ -1,334 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion;
|
||||
|
||||
using Mapster;
|
||||
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Reflection;
|
||||
|
||||
using ThingsGateway.Foundation.Extension.ConcurrentQueue;
|
||||
using ThingsGateway.Foundation.Extension.String;
|
||||
|
||||
using Yitter.IdGenerator;
|
||||
|
||||
namespace ThingsGateway.Plugin.SQLDB;
|
||||
public class SQLDB : UpLoadBase
|
||||
{
|
||||
private readonly ConcurrentQueue<SQLHistoryValue> DeviceVariableRunTimes = new();
|
||||
private readonly SQLDBProperty driverPropertys = new();
|
||||
private readonly SQLDBVariableProperty variablePropertys = new();
|
||||
private TypeAdapterConfig _config;
|
||||
private GlobalDeviceData _globalDeviceData;
|
||||
|
||||
private List<DeviceVariableRunTime> _uploadVariables = new();
|
||||
private TimerTick exTimerTick;
|
||||
private TimerTick exRealTimerTick;
|
||||
public SQLDB()
|
||||
{
|
||||
_config = new TypeAdapterConfig();
|
||||
_config.ForType<DeviceVariableRunTime, SQLHistoryValue>()
|
||||
.Map(dest => dest.Id, (src) => YitIdHelper.NextId())
|
||||
.Map(dest => dest.CreateTime, (src) => DateTime.Now);
|
||||
}
|
||||
|
||||
public override Type DriverDebugUIType => null;
|
||||
public override UpDriverPropertyBase DriverPropertys => driverPropertys;
|
||||
public override List<DeviceVariableRunTime> UploadVariables => _uploadVariables;
|
||||
|
||||
public override VariablePropertyBase VariablePropertys => variablePropertys;
|
||||
|
||||
public override Task AfterStopAsync()
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override async Task BeforStartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var db = GetHisDbAsync();
|
||||
db.CodeFirst.InitTables(typeof(SQLHistoryValue));
|
||||
db.MappingTables.Add("SQLRealValue", driverPropertys.ReadDBTableName); // typeof(类).Name 可以拿到类名
|
||||
db.CodeFirst.InitTables(typeof(SQLRealValue)); //生成的表名是 newTableName
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override async Task ExecuteAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var db = GetHisDbAsync();
|
||||
|
||||
if (driverPropertys.IsReadDB)
|
||||
{
|
||||
if (exRealTimerTick.IsTickHappen())
|
||||
{
|
||||
try
|
||||
{
|
||||
var varList = _uploadVariables.ToList().Adapt<List<SQLRealValue>>();
|
||||
if (varList?.Count != 0)
|
||||
{
|
||||
//var result = await db.Storageable(varList).As(driverPropertys.ReadDBTableName).ExecuteCommandAsync(cancellationToken);
|
||||
await db.Fastest<SQLRealValue>().AS(driverPropertys.ReadDBTableName).PageSize(100000).BulkUpdateAsync(varList);
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (!driverPropertys.IsInterval)
|
||||
{
|
||||
try
|
||||
{
|
||||
////变化推送
|
||||
var varList = DeviceVariableRunTimes.ToListWithDequeue();
|
||||
if (varList?.Count != 0)
|
||||
{
|
||||
await InserableAsync(db, varList, cancellationToken);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (exTimerTick.IsTickHappen())
|
||||
{
|
||||
try
|
||||
{
|
||||
var varList = _uploadVariables.ToList().Adapt<List<SQLHistoryValue>>(_config);
|
||||
if (varList?.Count != 0)
|
||||
{
|
||||
await InserableAsync(db, varList, cancellationToken);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (driverPropertys.CycleInterval > UploadDeviceThread.CycleInterval + 50)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(driverPropertys.CycleInterval - UploadDeviceThread.CycleInterval, cancellationToken);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据库链接
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public SqlSugarClient GetHisDbAsync()
|
||||
{
|
||||
var configureExternalServices = new ConfigureExternalServices
|
||||
{
|
||||
EntityService = (type, column) => // 修改列可空-1、带?问号 2、String类型若没有Required
|
||||
{
|
||||
if ((type.PropertyType.IsGenericType && type.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||||
|| (type.PropertyType == typeof(string) && type.GetCustomAttribute<RequiredAttribute>() == null))
|
||||
column.IsNullable = true;
|
||||
},
|
||||
};
|
||||
var sqlSugarClient = new SqlSugarClient(new ConnectionConfig()
|
||||
{
|
||||
ConnectionString = driverPropertys.ConnectStr,//连接字符串
|
||||
DbType = driverPropertys.DbType,//数据库类型
|
||||
IsAutoCloseConnection = true, //不设成true要手动close
|
||||
ConfigureExternalServices = configureExternalServices,
|
||||
}
|
||||
);
|
||||
AopSetting(sqlSugarClient);//aop配置
|
||||
return sqlSugarClient;
|
||||
}
|
||||
|
||||
public override bool IsConnected() => _uploadVariables?.Count > 0;
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
_globalDeviceData?.AllVariables?.ForEach(a => a.VariableValueChange -= VariableValueChange);
|
||||
_uploadVariables = null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogError(ex);
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
protected override void Init(UploadDeviceRunTime device)
|
||||
{
|
||||
|
||||
_globalDeviceData = App.GetService<GlobalDeviceData>();
|
||||
|
||||
var tags = _globalDeviceData.AllVariables.Where(a => a.VariablePropertys.ContainsKey(device.Id))
|
||||
.Where(b => GetPropertyValue(b, nameof(variablePropertys.Enable)).ToBoolean())
|
||||
.ToList();
|
||||
|
||||
_uploadVariables = tags;
|
||||
|
||||
if (!driverPropertys.IsReadDB)
|
||||
if (!driverPropertys.IsInterval)
|
||||
{
|
||||
_uploadVariables.ForEach(a =>
|
||||
{
|
||||
a.VariableValueChange += VariableValueChange;
|
||||
});
|
||||
}
|
||||
|
||||
if (_uploadVariables.Count == 0)
|
||||
{
|
||||
LogMessage.LogWarning("插件变量数量为0");
|
||||
}
|
||||
if (driverPropertys.IntervalTime < 1)
|
||||
driverPropertys.IntervalTime = 10;
|
||||
exTimerTick = new(driverPropertys.IntervalTime * 1000);
|
||||
exRealTimerTick = new(driverPropertys.IntervalTime * 1000);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aop设置
|
||||
/// </summary>
|
||||
/// <param name="db"></param>
|
||||
private static void AopSetting(SqlSugarClient db)
|
||||
{
|
||||
var config = db.CurrentConnectionConfig;
|
||||
|
||||
// 设置超时时间
|
||||
db.Ado.CommandTimeOut = 30;
|
||||
|
||||
// 打印SQL语句
|
||||
db.Aop.OnLogExecuting = (sql, pars) =>
|
||||
{
|
||||
//如果不是开发环境就打印sql
|
||||
if (App.HostEnvironment.IsDevelopment())
|
||||
{
|
||||
if (sql.StartsWith("SELECT"))
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Green;
|
||||
}
|
||||
if (sql.StartsWith("UPDATE"))
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
}
|
||||
if (sql.StartsWith("INSERT"))
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Blue;
|
||||
}
|
||||
if (sql.StartsWith("DELETE"))
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
}
|
||||
WriteSqlLog(UtilMethods.GetSqlString(config.DbType, sql, pars));
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
Console.WriteLine();
|
||||
}
|
||||
};
|
||||
//异常
|
||||
db.Aop.OnError = (ex) =>
|
||||
{
|
||||
//如果不是开发环境就打印日志
|
||||
if (App.WebHostEnvironment.IsDevelopment())
|
||||
{
|
||||
if (ex.Parametres == null) return;
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
var pars = db.Utilities.SerializeObject(((SugarParameter[])ex.Parametres).ToDictionary(it => it.ParameterName, it => it.Value));
|
||||
WriteSqlLogError(UtilMethods.GetSqlString(config.DbType, ex.Sql, (SugarParameter[])ex.Parametres));
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
private static void WriteSqlLog(string msg)
|
||||
{
|
||||
Console.WriteLine("【Sql执行时间】:" + DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat());
|
||||
Console.WriteLine("【Sql语句】:" + msg + Environment.NewLine);
|
||||
}
|
||||
private static void WriteSqlLogError(string msg)
|
||||
{
|
||||
Console.WriteLine("【Sql执行错误时间】:" + DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat());
|
||||
Console.WriteLine("【Sql语句】:" + msg + Environment.NewLine);
|
||||
}
|
||||
private async Task InserableAsync(SqlSugarClient db, List<SQLHistoryValue> dbInserts, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await db.Insertable(dbInserts).SplitTable().ExecuteCommandAsync();
|
||||
if (result > 0)
|
||||
LogMessage.Trace(FoundationConst.LogMessageHeader + dbInserts.ToJsonString());
|
||||
//连接成功时补发缓存数据
|
||||
var cacheData = await CacheDb.GetCacheData();
|
||||
foreach (var item in cacheData)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = item.CacheStr.FromJsonString<List<SQLHistoryValue>>();
|
||||
var cacheresult = await db.Insertable(data).SplitTable().ExecuteCommandAsync();
|
||||
if (cacheresult > 0)
|
||||
{
|
||||
await CacheDb.DeleteCacheData(item.Id);
|
||||
LogMessage.Trace(FoundationConst.LogMessageHeader + $"主题:{item.Topic}{Environment.NewLine}负载:{item.CacheStr}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex);
|
||||
await CacheDb.AddCacheData("", dbInserts.ToJsonString(), driverPropertys.CacheMaxCount);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void VariableValueChange(DeviceVariableRunTime collectVariableRunTime)
|
||||
{
|
||||
if (!driverPropertys.IsReadDB)
|
||||
if (!driverPropertys.IsInterval)
|
||||
DeviceVariableRunTimes.Enqueue(collectVariableRunTime.Adapt<SQLHistoryValue>(_config));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
@*
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
*@
|
||||
|
||||
@page "/S7_1200"
|
||||
|
||||
@namespace ThingsGateway.Foundation.Demo
|
||||
@using BlazorComponent;
|
||||
@using Microsoft.AspNetCore.Components.Web;
|
||||
@using Microsoft.JSInterop;
|
||||
|
||||
@using ThingsGateway.Foundation.Adapter.Siemens;
|
||||
@using ThingsGateway.Foundation.Core;
|
||||
@using ThingsGateway.Foundation.Extension;
|
||||
@using ThingsGateway.Foundation.Serial;
|
||||
|
||||
@using Masa.Blazor
|
||||
|
||||
<TcpClientPage @ref=TcpClientPage></TcpClientPage>
|
||||
|
||||
<MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%">
|
||||
<div class="mb-4">驱动配置</div>
|
||||
<MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
|
||||
@if (_plc != null)
|
||||
{
|
||||
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.FrameTime)) Dense HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField>
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.CacheTimeout)) Dense HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField>
|
||||
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.TimeOut)) Dense HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.Slot)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Slot></MTextField>
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.Rack)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Rack></MTextField>
|
||||
|
||||
<MSelect Class="ma-1" Outlined Style="max-width:200px" @bind-Value="_plc.DataFormat" Label="@(_plc.DescriptionWithOutSugar(x => x.DataFormat))"
|
||||
Items=@(typeof(DataFormat).GetEnumListWithOutSugar())
|
||||
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
|
||||
ItemText=@((u) =>u.Description)
|
||||
ItemValue=@(u =>(DataFormat)u.Value)
|
||||
HideDetails=@("auto") Height="30"
|
||||
Dense>
|
||||
</MSelect>
|
||||
|
||||
|
||||
}
|
||||
</MRow>
|
||||
</MCard>
|
||||
|
||||
|
||||
<DriverDebugUIPage @ref=driverDebugUIPage Sections="_sections">
|
||||
|
||||
</DriverDebugUIPage>
|
||||
|
||||
|
||||
@code {
|
||||
private readonly List<(string Code, string Language)> _sections = new();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
#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 ThingsGateway.Foundation.Adapter.Siemens;
|
||||
|
||||
namespace ThingsGateway.Foundation.Demo;
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public partial class S7_1200DebugPage
|
||||
{
|
||||
/// <summary>
|
||||
/// SerialSessionPage
|
||||
/// </summary>
|
||||
private TcpClientPage TcpClientPage;
|
||||
private DriverDebugUIPage driverDebugUIPage;
|
||||
|
||||
private ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC _plc;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="firstRender"></param>
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
_sections.Add((
|
||||
"""
|
||||
private static async Task ModbusClientAsync()
|
||||
{
|
||||
//链路基础配置项
|
||||
var config = new TouchSocketConfig();
|
||||
config
|
||||
.SetRemoteIPHost(new IPHost("127.0.0.1:502"))//TCP/UDP链路才需要
|
||||
|
||||
var tcpClient1 = new TcpClient();//链路对象
|
||||
tcpClient1.Setup(config);
|
||||
|
||||
//创建协议对象,构造函数需要传入对应链路对象
|
||||
SiemensS7PLC plc = new(tcpClient1,SiemensEnum.S1500)
|
||||
{
|
||||
//协议配置
|
||||
DataFormat = DataFormat.ABCD,
|
||||
FrameTime = 0,
|
||||
CacheTimeout = 1000,
|
||||
ConnectTimeOut = 3000,
|
||||
Station = 1,
|
||||
TimeOut = 3000,
|
||||
IsCheckMessageId = true
|
||||
};
|
||||
|
||||
#region 读写测试
|
||||
var bytesResult = await plc.ReadAsync("400001", 20);
|
||||
var int32sResult = await plc.ReadInt32Async("400001", 20);
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
""", "csharp"));
|
||||
|
||||
if (TcpClientPage != null)
|
||||
TcpClientPage.LogAction = driverDebugUIPage.LogOut;
|
||||
_plc = new ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC(TcpClientPage.GetTcpClient(), SiemensEnum.S1200);
|
||||
driverDebugUIPage.Plc = _plc;
|
||||
|
||||
//初始化
|
||||
driverDebugUIPage.Address = "M100";
|
||||
int index = 0;
|
||||
driverDebugUIPage.DeviceVariableRunTimes.ForEach(a => a.VariableAddress = "M" + (100 + index++));
|
||||
TcpClientPage.Port = 102;
|
||||
TcpClientPage.StateHasChangedAsync();
|
||||
|
||||
//载入配置
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
base.OnAfterRender(firstRender);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
@*
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
*@
|
||||
|
||||
@page "/S7_1500"
|
||||
|
||||
@namespace ThingsGateway.Foundation.Demo
|
||||
@using BlazorComponent;
|
||||
@using Microsoft.AspNetCore.Components.Web;
|
||||
@using Microsoft.JSInterop;
|
||||
|
||||
@using ThingsGateway.Foundation.Adapter.Siemens;
|
||||
@using ThingsGateway.Foundation.Core;
|
||||
@using ThingsGateway.Foundation.Extension;
|
||||
@using ThingsGateway.Foundation.Serial;
|
||||
|
||||
@using Masa.Blazor
|
||||
|
||||
<TcpClientPage @ref=TcpClientPage></TcpClientPage>
|
||||
|
||||
<MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%">
|
||||
<div class="mb-4">驱动配置</div>
|
||||
<MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
|
||||
@if (_plc != null)
|
||||
{
|
||||
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.FrameTime)) Dense HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField>
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.CacheTimeout)) Dense HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField>
|
||||
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.TimeOut)) Dense HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.Slot)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Slot></MTextField>
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.Rack)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Rack></MTextField>
|
||||
|
||||
<MSelect Class="ma-1" Outlined Style="max-width:200px" @bind-Value="_plc.DataFormat" Label="@(_plc.DescriptionWithOutSugar(x => x.DataFormat))"
|
||||
Items=@(typeof(DataFormat).GetEnumListWithOutSugar())
|
||||
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
|
||||
ItemText=@((u) =>u.Description)
|
||||
ItemValue=@(u =>(DataFormat)u.Value)
|
||||
HideDetails=@("auto") Height="30"
|
||||
Dense>
|
||||
</MSelect>
|
||||
|
||||
|
||||
}
|
||||
</MRow>
|
||||
</MCard>
|
||||
|
||||
|
||||
<DriverDebugUIPage @ref=driverDebugUIPage Sections="_sections">
|
||||
|
||||
</DriverDebugUIPage>
|
||||
|
||||
|
||||
@code {
|
||||
private readonly List<(string Code, string Language)> _sections = new();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
#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 ThingsGateway.Foundation.Adapter.Siemens;
|
||||
|
||||
namespace ThingsGateway.Foundation.Demo;
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public partial class S7_1500DebugPage
|
||||
{
|
||||
/// <summary>
|
||||
/// SerialSessionPage
|
||||
/// </summary>
|
||||
private TcpClientPage TcpClientPage;
|
||||
private DriverDebugUIPage driverDebugUIPage;
|
||||
|
||||
private ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC _plc;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="firstRender"></param>
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
_sections.Add((
|
||||
"""
|
||||
private static async Task ModbusClientAsync()
|
||||
{
|
||||
//链路基础配置项
|
||||
var config = new TouchSocketConfig();
|
||||
config
|
||||
.SetRemoteIPHost(new IPHost("127.0.0.1:502"))//TCP/UDP链路才需要
|
||||
|
||||
var tcpClient1 = new TcpClient();//链路对象
|
||||
tcpClient1.Setup(config);
|
||||
|
||||
//创建协议对象,构造函数需要传入对应链路对象
|
||||
SiemensS7PLC plc = new(tcpClient1,SiemensEnum.S1500)
|
||||
{
|
||||
//协议配置
|
||||
DataFormat = DataFormat.ABCD,
|
||||
FrameTime = 0,
|
||||
CacheTimeout = 1000,
|
||||
ConnectTimeOut = 3000,
|
||||
Station = 1,
|
||||
TimeOut = 3000,
|
||||
IsCheckMessageId = true
|
||||
};
|
||||
|
||||
#region 读写测试
|
||||
var bytesResult = await plc.ReadAsync("400001", 20);
|
||||
var int32sResult = await plc.ReadInt32Async("400001", 20);
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
""", "csharp"));
|
||||
|
||||
if (TcpClientPage != null)
|
||||
TcpClientPage.LogAction = driverDebugUIPage.LogOut;
|
||||
_plc = new ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC(TcpClientPage.GetTcpClient(), SiemensEnum.S1500);
|
||||
driverDebugUIPage.Plc = _plc;
|
||||
|
||||
//初始化
|
||||
driverDebugUIPage.Address = "M100";
|
||||
int index = 0;
|
||||
driverDebugUIPage.DeviceVariableRunTimes.ForEach(a => a.VariableAddress = "M" + (100 + index++));
|
||||
TcpClientPage.Port = 102;
|
||||
TcpClientPage.StateHasChangedAsync();
|
||||
|
||||
|
||||
//载入配置
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
base.OnAfterRender(firstRender);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
@*
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
*@
|
||||
|
||||
@page "/S7_200"
|
||||
|
||||
@namespace ThingsGateway.Foundation.Demo
|
||||
@using BlazorComponent;
|
||||
@using Microsoft.AspNetCore.Components.Web;
|
||||
@using Microsoft.JSInterop;
|
||||
|
||||
@using ThingsGateway.Foundation.Adapter.Siemens;
|
||||
@using ThingsGateway.Foundation.Core;
|
||||
@using ThingsGateway.Foundation.Extension;
|
||||
@using ThingsGateway.Foundation.Serial;
|
||||
|
||||
@using Masa.Blazor
|
||||
|
||||
<TcpClientPage @ref=TcpClientPage></TcpClientPage>
|
||||
|
||||
<MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%">
|
||||
<div class="mb-4">驱动配置</div>
|
||||
<MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
|
||||
@if (_plc != null)
|
||||
{
|
||||
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.FrameTime)) Dense HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField>
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.CacheTimeout)) Dense HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField>
|
||||
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.TimeOut)) Dense HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.Slot)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Slot></MTextField>
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.Rack)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Rack></MTextField>
|
||||
|
||||
<MSelect Class="ma-1" Outlined Style="max-width:200px" @bind-Value="_plc.DataFormat" Label="@(_plc.DescriptionWithOutSugar(x => x.DataFormat))"
|
||||
Items=@(typeof(DataFormat).GetEnumListWithOutSugar())
|
||||
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
|
||||
ItemText=@((u) =>u.Description)
|
||||
ItemValue=@(u =>(DataFormat)u.Value)
|
||||
HideDetails=@("auto") Height="30"
|
||||
Dense>
|
||||
</MSelect>
|
||||
|
||||
|
||||
}
|
||||
</MRow>
|
||||
</MCard>
|
||||
|
||||
|
||||
<DriverDebugUIPage @ref=driverDebugUIPage Sections="_sections">
|
||||
|
||||
</DriverDebugUIPage>
|
||||
|
||||
|
||||
@code {
|
||||
private readonly List<(string Code, string Language)> _sections = new();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
#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 ThingsGateway.Foundation.Adapter.Siemens;
|
||||
|
||||
namespace ThingsGateway.Foundation.Demo;
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public partial class S7_200DebugPage
|
||||
{
|
||||
/// <summary>
|
||||
/// SerialSessionPage
|
||||
/// </summary>
|
||||
private TcpClientPage TcpClientPage;
|
||||
private DriverDebugUIPage driverDebugUIPage;
|
||||
|
||||
private ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC _plc;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="firstRender"></param>
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
_sections.Add((
|
||||
"""
|
||||
private static async Task ModbusClientAsync()
|
||||
{
|
||||
//链路基础配置项
|
||||
var config = new TouchSocketConfig();
|
||||
config
|
||||
.SetRemoteIPHost(new IPHost("127.0.0.1:502"))//TCP/UDP链路才需要
|
||||
|
||||
var tcpClient1 = new TcpClient();//链路对象
|
||||
tcpClient1.Setup(config);
|
||||
|
||||
//创建协议对象,构造函数需要传入对应链路对象
|
||||
SiemensS7PLC plc = new(tcpClient1,SiemensEnum.S1500)
|
||||
{
|
||||
//协议配置
|
||||
DataFormat = DataFormat.ABCD,
|
||||
FrameTime = 0,
|
||||
CacheTimeout = 1000,
|
||||
ConnectTimeOut = 3000,
|
||||
Station = 1,
|
||||
TimeOut = 3000,
|
||||
IsCheckMessageId = true
|
||||
};
|
||||
|
||||
#region 读写测试
|
||||
var bytesResult = await plc.ReadAsync("400001", 20);
|
||||
var int32sResult = await plc.ReadInt32Async("400001", 20);
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
""", "csharp"));
|
||||
|
||||
if (TcpClientPage != null)
|
||||
TcpClientPage.LogAction = driverDebugUIPage.LogOut;
|
||||
_plc = new ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC(TcpClientPage.GetTcpClient(), SiemensEnum.S200);
|
||||
driverDebugUIPage.Plc = _plc;
|
||||
|
||||
//初始化
|
||||
driverDebugUIPage.Address = "M100";
|
||||
int index = 0;
|
||||
driverDebugUIPage.DeviceVariableRunTimes.ForEach(a => a.VariableAddress = "M" + (100 + index++));
|
||||
TcpClientPage.Port = 102;
|
||||
TcpClientPage.StateHasChangedAsync();
|
||||
|
||||
|
||||
//载入配置
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
base.OnAfterRender(firstRender);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
@*
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
*@
|
||||
|
||||
@page "/S7_200SMART"
|
||||
|
||||
@namespace ThingsGateway.Foundation.Demo
|
||||
@using BlazorComponent;
|
||||
@using Microsoft.AspNetCore.Components.Web;
|
||||
@using Microsoft.JSInterop;
|
||||
|
||||
@using ThingsGateway.Foundation.Adapter.Siemens;
|
||||
@using ThingsGateway.Foundation.Core;
|
||||
@using ThingsGateway.Foundation.Extension;
|
||||
@using ThingsGateway.Foundation.Serial;
|
||||
|
||||
@using Masa.Blazor
|
||||
|
||||
<TcpClientPage @ref=TcpClientPage></TcpClientPage>
|
||||
|
||||
<MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%">
|
||||
<div class="mb-4">驱动配置</div>
|
||||
<MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
|
||||
@if (_plc != null)
|
||||
{
|
||||
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.FrameTime)) Dense HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField>
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.CacheTimeout)) Dense HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField>
|
||||
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.TimeOut)) Dense HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.Slot)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Slot></MTextField>
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.Rack)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Rack></MTextField>
|
||||
|
||||
<MSelect Class="ma-1" Outlined Style="max-width:200px" @bind-Value="_plc.DataFormat" Label="@(_plc.DescriptionWithOutSugar(x => x.DataFormat))"
|
||||
Items=@(typeof(DataFormat).GetEnumListWithOutSugar())
|
||||
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
|
||||
ItemText=@((u) =>u.Description)
|
||||
ItemValue=@(u =>(DataFormat)u.Value)
|
||||
HideDetails=@("auto") Height="30"
|
||||
Dense>
|
||||
</MSelect>
|
||||
|
||||
|
||||
}
|
||||
</MRow>
|
||||
</MCard>
|
||||
|
||||
|
||||
<DriverDebugUIPage @ref=driverDebugUIPage Sections="_sections">
|
||||
|
||||
</DriverDebugUIPage>
|
||||
|
||||
|
||||
@code {
|
||||
private readonly List<(string Code, string Language)> _sections = new();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
#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 ThingsGateway.Foundation.Adapter.Siemens;
|
||||
|
||||
namespace ThingsGateway.Foundation.Demo;
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public partial class S7_200SMARTDebugPage
|
||||
{
|
||||
/// <summary>
|
||||
/// SerialSessionPage
|
||||
/// </summary>
|
||||
private TcpClientPage TcpClientPage;
|
||||
private DriverDebugUIPage driverDebugUIPage;
|
||||
|
||||
private ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC _plc;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="firstRender"></param>
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
_sections.Add((
|
||||
"""
|
||||
private static async Task ModbusClientAsync()
|
||||
{
|
||||
//链路基础配置项
|
||||
var config = new TouchSocketConfig();
|
||||
config
|
||||
.SetRemoteIPHost(new IPHost("127.0.0.1:502"))//TCP/UDP链路才需要
|
||||
|
||||
var tcpClient1 = new TcpClient();//链路对象
|
||||
tcpClient1.Setup(config);
|
||||
|
||||
//创建协议对象,构造函数需要传入对应链路对象
|
||||
SiemensS7PLC plc = new(tcpClient1,SiemensEnum.S1500)
|
||||
{
|
||||
//协议配置
|
||||
DataFormat = DataFormat.ABCD,
|
||||
FrameTime = 0,
|
||||
CacheTimeout = 1000,
|
||||
ConnectTimeOut = 3000,
|
||||
Station = 1,
|
||||
TimeOut = 3000,
|
||||
IsCheckMessageId = true
|
||||
};
|
||||
|
||||
#region 读写测试
|
||||
var bytesResult = await plc.ReadAsync("400001", 20);
|
||||
var int32sResult = await plc.ReadInt32Async("400001", 20);
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
""", "csharp"));
|
||||
|
||||
if (TcpClientPage != null)
|
||||
TcpClientPage.LogAction = driverDebugUIPage.LogOut;
|
||||
_plc = new ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC(TcpClientPage.GetTcpClient(), SiemensEnum.S200Smart);
|
||||
driverDebugUIPage.Plc = _plc;
|
||||
|
||||
//初始化
|
||||
driverDebugUIPage.Address = "M100";
|
||||
int index = 0;
|
||||
driverDebugUIPage.DeviceVariableRunTimes.ForEach(a => a.VariableAddress = "M" + (100 + index++));
|
||||
TcpClientPage.Port = 102;
|
||||
TcpClientPage.StateHasChangedAsync();
|
||||
|
||||
|
||||
//载入配置
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
base.OnAfterRender(firstRender);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
@*
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
*@
|
||||
|
||||
@page "/S7_300"
|
||||
|
||||
@namespace ThingsGateway.Foundation.Demo
|
||||
@using BlazorComponent;
|
||||
@using Microsoft.AspNetCore.Components.Web;
|
||||
@using Microsoft.JSInterop;
|
||||
|
||||
@using ThingsGateway.Foundation.Adapter.Siemens;
|
||||
@using ThingsGateway.Foundation.Core;
|
||||
@using ThingsGateway.Foundation.Extension;
|
||||
@using ThingsGateway.Foundation.Serial;
|
||||
|
||||
@using Masa.Blazor
|
||||
|
||||
<TcpClientPage @ref=TcpClientPage></TcpClientPage>
|
||||
|
||||
<MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%">
|
||||
<div class="mb-4">驱动配置</div>
|
||||
<MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
|
||||
@if (_plc != null)
|
||||
{
|
||||
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.FrameTime)) Dense HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField>
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.CacheTimeout)) Dense HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField>
|
||||
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.TimeOut)) Dense HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.Slot)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Slot></MTextField>
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.Rack)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Rack></MTextField>
|
||||
|
||||
<MSelect Class="ma-1" Outlined Style="max-width:200px" @bind-Value="_plc.DataFormat" Label="@(_plc.DescriptionWithOutSugar(x => x.DataFormat))"
|
||||
Items=@(typeof(DataFormat).GetEnumListWithOutSugar())
|
||||
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
|
||||
ItemText=@((u) =>u.Description)
|
||||
ItemValue=@(u =>(DataFormat)u.Value)
|
||||
HideDetails=@("auto") Height="30"
|
||||
Dense>
|
||||
</MSelect>
|
||||
|
||||
|
||||
}
|
||||
</MRow>
|
||||
</MCard>
|
||||
|
||||
|
||||
<DriverDebugUIPage @ref=driverDebugUIPage Sections="_sections">
|
||||
|
||||
</DriverDebugUIPage>
|
||||
|
||||
|
||||
@code {
|
||||
private readonly List<(string Code, string Language)> _sections = new();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
@*
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
*@
|
||||
|
||||
@page "/S7_400"
|
||||
|
||||
@namespace ThingsGateway.Foundation.Demo
|
||||
@using BlazorComponent;
|
||||
@using Microsoft.AspNetCore.Components.Web;
|
||||
@using Microsoft.JSInterop;
|
||||
|
||||
@using ThingsGateway.Foundation.Adapter.Siemens;
|
||||
@using ThingsGateway.Foundation.Core;
|
||||
@using ThingsGateway.Foundation.Extension;
|
||||
@using ThingsGateway.Foundation.Serial;
|
||||
|
||||
@using Masa.Blazor
|
||||
|
||||
<TcpClientPage @ref=TcpClientPage></TcpClientPage>
|
||||
|
||||
<MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%">
|
||||
<div class="mb-4">驱动配置</div>
|
||||
<MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
|
||||
@if (_plc != null)
|
||||
{
|
||||
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.FrameTime)) Dense HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField>
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.CacheTimeout)) Dense HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField>
|
||||
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.TimeOut)) Dense HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.Slot)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Slot></MTextField>
|
||||
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.Rack)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Rack></MTextField>
|
||||
|
||||
<MSelect Class="ma-1" Outlined Style="max-width:200px" @bind-Value="_plc.DataFormat" Label="@(_plc.DescriptionWithOutSugar(x => x.DataFormat))"
|
||||
Items=@(typeof(DataFormat).GetEnumListWithOutSugar())
|
||||
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
|
||||
ItemText=@((u) =>u.Description)
|
||||
ItemValue=@(u =>(DataFormat)u.Value)
|
||||
HideDetails=@("auto") Height="30"
|
||||
Dense>
|
||||
</MSelect>
|
||||
|
||||
|
||||
}
|
||||
</MRow>
|
||||
</MCard>
|
||||
|
||||
|
||||
<DriverDebugUIPage @ref=driverDebugUIPage Sections="_sections">
|
||||
|
||||
</DriverDebugUIPage>
|
||||
|
||||
|
||||
@code {
|
||||
private readonly List<(string Code, string Language)> _sections = new();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
#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 ThingsGateway.Foundation.Adapter.Siemens;
|
||||
|
||||
namespace ThingsGateway.Foundation.Demo;
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public partial class S7_400DebugPage
|
||||
{
|
||||
/// <summary>
|
||||
/// SerialSessionPage
|
||||
/// </summary>
|
||||
private TcpClientPage TcpClientPage;
|
||||
private DriverDebugUIPage driverDebugUIPage;
|
||||
|
||||
private ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC _plc;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="firstRender"></param>
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
_sections.Add((
|
||||
"""
|
||||
private static async Task ModbusClientAsync()
|
||||
{
|
||||
//链路基础配置项
|
||||
var config = new TouchSocketConfig();
|
||||
config
|
||||
.SetRemoteIPHost(new IPHost("127.0.0.1:502"))//TCP/UDP链路才需要
|
||||
|
||||
var tcpClient1 = new TcpClient();//链路对象
|
||||
tcpClient1.Setup(config);
|
||||
|
||||
//创建协议对象,构造函数需要传入对应链路对象
|
||||
SiemensS7PLC plc = new(tcpClient1,SiemensEnum.S1500)
|
||||
{
|
||||
//协议配置
|
||||
DataFormat = DataFormat.ABCD,
|
||||
FrameTime = 0,
|
||||
CacheTimeout = 1000,
|
||||
ConnectTimeOut = 3000,
|
||||
Station = 1,
|
||||
TimeOut = 3000,
|
||||
IsCheckMessageId = true
|
||||
};
|
||||
|
||||
#region 读写测试
|
||||
var bytesResult = await plc.ReadAsync("400001", 20);
|
||||
var int32sResult = await plc.ReadInt32Async("400001", 20);
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
""", "csharp"));
|
||||
|
||||
if (TcpClientPage != null)
|
||||
TcpClientPage.LogAction = driverDebugUIPage.LogOut;
|
||||
_plc = new ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC(TcpClientPage.GetTcpClient(), SiemensEnum.S400);
|
||||
driverDebugUIPage.Plc = _plc;
|
||||
|
||||
//初始化
|
||||
driverDebugUIPage.Address = "M100";
|
||||
int index = 0;
|
||||
driverDebugUIPage.DeviceVariableRunTimes.ForEach(a => a.VariableAddress = "M" + (100 + index++));
|
||||
TcpClientPage.Port = 102;
|
||||
TcpClientPage.StateHasChangedAsync();
|
||||
|
||||
|
||||
//载入配置
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
base.OnAfterRender(firstRender);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Plugin.Siemens
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public class S7_1200 : Siemens
|
||||
{
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public override Type DriverDebugUIType => typeof(S7_1200DebugPage);
|
||||
/// <inheritdoc/>
|
||||
public override CollectDriverPropertyBase DriverPropertys => driverPropertys;
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Init(CollectDeviceRunTime device, object client = null)
|
||||
{
|
||||
if (client == null)
|
||||
{
|
||||
FoundataionConfig.SetRemoteIPHost(new IPHost($"{driverPropertys.IP}:{driverPropertys.Port}"))
|
||||
;
|
||||
client = new TcpClient();
|
||||
((TcpClient)client).Setup(FoundataionConfig);
|
||||
}
|
||||
//载入配置
|
||||
_plc = new((TcpClient)client, SiemensEnum.S1200)
|
||||
{
|
||||
DataFormat = driverPropertys.DataFormat,
|
||||
ConnectTimeOut = driverPropertys.ConnectTimeOut,
|
||||
TimeOut = driverPropertys.TimeOut
|
||||
};
|
||||
if (driverPropertys.LocalTSAP != 0)
|
||||
{
|
||||
_plc.LocalTSAP = driverPropertys.LocalTSAP;
|
||||
}
|
||||
if (driverPropertys.DestTSAP != 0)
|
||||
{
|
||||
_plc.DestTSAP = driverPropertys.DestTSAP;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Plugin.Siemens
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public class S7_1500 : Siemens
|
||||
{
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Type DriverDebugUIType => typeof(S7_1500DebugPage);
|
||||
/// <inheritdoc/>
|
||||
public override CollectDriverPropertyBase DriverPropertys => driverPropertys;
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Init(CollectDeviceRunTime device, object client = null)
|
||||
{
|
||||
if (client == null)
|
||||
{
|
||||
FoundataionConfig.SetRemoteIPHost(new IPHost($"{driverPropertys.IP}:{driverPropertys.Port}"))
|
||||
;
|
||||
client = new TcpClient();
|
||||
((TcpClient)client).Setup(FoundataionConfig);
|
||||
}
|
||||
//载入配置
|
||||
_plc = new((TcpClient)client, SiemensEnum.S1500)
|
||||
{
|
||||
DataFormat = driverPropertys.DataFormat,
|
||||
ConnectTimeOut = driverPropertys.ConnectTimeOut,
|
||||
TimeOut = driverPropertys.TimeOut
|
||||
};
|
||||
if (driverPropertys.LocalTSAP != 0)
|
||||
{
|
||||
_plc.LocalTSAP = driverPropertys.LocalTSAP;
|
||||
}
|
||||
if (driverPropertys.DestTSAP != 0)
|
||||
{
|
||||
_plc.DestTSAP = driverPropertys.DestTSAP;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Plugin.Siemens
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public class S7_200 : Siemens
|
||||
{
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Type DriverDebugUIType => typeof(S7_200DebugPage);
|
||||
/// <inheritdoc/>
|
||||
public override CollectDriverPropertyBase DriverPropertys => driverPropertys;
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Init(CollectDeviceRunTime device, object client = null)
|
||||
{
|
||||
if (client == null)
|
||||
{
|
||||
FoundataionConfig.SetRemoteIPHost(new IPHost($"{driverPropertys.IP}:{driverPropertys.Port}"))
|
||||
;
|
||||
client = new TcpClient();
|
||||
((TcpClient)client).Setup(FoundataionConfig);
|
||||
}
|
||||
//载入配置
|
||||
_plc = new((TcpClient)client, SiemensEnum.S200)
|
||||
{
|
||||
DataFormat = driverPropertys.DataFormat,
|
||||
ConnectTimeOut = driverPropertys.ConnectTimeOut,
|
||||
TimeOut = driverPropertys.TimeOut
|
||||
};
|
||||
if (driverPropertys.LocalTSAP != 0)
|
||||
{
|
||||
_plc.LocalTSAP = driverPropertys.LocalTSAP;
|
||||
}
|
||||
if (driverPropertys.DestTSAP != 0)
|
||||
{
|
||||
_plc.DestTSAP = driverPropertys.DestTSAP;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Plugin.Siemens
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public class S7_200SMART : Siemens
|
||||
{
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Type DriverDebugUIType => typeof(S7_200SMARTDebugPage);
|
||||
/// <inheritdoc/>
|
||||
public override CollectDriverPropertyBase DriverPropertys => driverPropertys;
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Init(CollectDeviceRunTime device, object client = null)
|
||||
{
|
||||
if (client == null)
|
||||
{
|
||||
FoundataionConfig.SetRemoteIPHost(new IPHost($"{driverPropertys.IP}:{driverPropertys.Port}"))
|
||||
;
|
||||
client = new TcpClient();
|
||||
((TcpClient)client).Setup(FoundataionConfig);
|
||||
}
|
||||
//载入配置
|
||||
_plc = new((TcpClient)client, SiemensEnum.S200Smart)
|
||||
{
|
||||
DataFormat = driverPropertys.DataFormat,
|
||||
ConnectTimeOut = driverPropertys.ConnectTimeOut,
|
||||
TimeOut = driverPropertys.TimeOut
|
||||
};
|
||||
if (driverPropertys.LocalTSAP != 0)
|
||||
{
|
||||
_plc.LocalTSAP = driverPropertys.LocalTSAP;
|
||||
}
|
||||
if (driverPropertys.DestTSAP != 0)
|
||||
{
|
||||
_plc.DestTSAP = driverPropertys.DestTSAP;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Plugin.Siemens
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public class S7_300 : Siemens
|
||||
{
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Type DriverDebugUIType => typeof(S7_300DebugPage);
|
||||
/// <inheritdoc/>
|
||||
public override CollectDriverPropertyBase DriverPropertys => driverPropertys;
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Init(CollectDeviceRunTime device, object client = null)
|
||||
{
|
||||
if (client == null)
|
||||
{
|
||||
FoundataionConfig.SetRemoteIPHost(new IPHost($"{driverPropertys.IP}:{driverPropertys.Port}"))
|
||||
;
|
||||
client = new TcpClient();
|
||||
((TcpClient)client).Setup(FoundataionConfig);
|
||||
}
|
||||
//载入配置
|
||||
_plc = new((TcpClient)client, SiemensEnum.S300)
|
||||
{
|
||||
DataFormat = driverPropertys.DataFormat,
|
||||
ConnectTimeOut = driverPropertys.ConnectTimeOut,
|
||||
TimeOut = driverPropertys.TimeOut
|
||||
};
|
||||
if (driverPropertys.LocalTSAP != 0)
|
||||
{
|
||||
_plc.LocalTSAP = driverPropertys.LocalTSAP;
|
||||
}
|
||||
if (driverPropertys.DestTSAP != 0)
|
||||
{
|
||||
_plc.DestTSAP = driverPropertys.DestTSAP;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Plugin.Siemens
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public class S7_400 : Siemens
|
||||
{
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Type DriverDebugUIType => typeof(S7_400DebugPage);
|
||||
/// <inheritdoc/>
|
||||
public override CollectDriverPropertyBase DriverPropertys => driverPropertys;
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Init(CollectDeviceRunTime device, object client = null)
|
||||
{
|
||||
if (client == null)
|
||||
{
|
||||
FoundataionConfig.SetRemoteIPHost(new IPHost($"{driverPropertys.IP}:{driverPropertys.Port}"))
|
||||
;
|
||||
client = new TcpClient();
|
||||
((TcpClient)client).Setup(FoundataionConfig);
|
||||
}
|
||||
//载入配置
|
||||
_plc = new((TcpClient)client, SiemensEnum.S400)
|
||||
{
|
||||
DataFormat = driverPropertys.DataFormat,
|
||||
ConnectTimeOut = driverPropertys.ConnectTimeOut,
|
||||
TimeOut = driverPropertys.TimeOut
|
||||
};
|
||||
if (driverPropertys.LocalTSAP != 0)
|
||||
{
|
||||
_plc.LocalTSAP = driverPropertys.LocalTSAP;
|
||||
}
|
||||
if (driverPropertys.DestTSAP != 0)
|
||||
{
|
||||
_plc.DestTSAP = driverPropertys.DestTSAP;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
@*
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
*@
|
||||
|
||||
@using System.Net.Http
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Microsoft.AspNetCore.Components.Routing
|
||||
@using Microsoft.AspNetCore.Components.Web
|
||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||
@using Microsoft.JSInterop
|
||||
@using BlazorComponent
|
||||
@using Masa.Blazor
|
||||
@using Masa.Blazor.Presets
|
||||
@using System.Net.Http.Json
|
||||
@using System.IO;
|
||||
@using System.Text.Json;
|
||||
@using System.Reflection;
|
||||
|
||||
@using ThingsGateway.Components;
|
||||
@using ThingsGateway.Admin.Core;
|
||||
@using ThingsGateway.Foundation.Core;
|
||||
@using ThingsGateway.Foundation.Extension.String;
|
||||
@using ThingsGateway.Admin.Application;
|
||||
|
||||
@using ThingsGateway.Core;
|
||||
@using ThingsGateway.Gateway.Application;
|
||||
@using ThingsGateway.Gateway.Core;
|
||||
@@ -1,325 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
|
||||
using Furion;
|
||||
|
||||
using Mapster;
|
||||
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Reflection;
|
||||
|
||||
using ThingsGateway.Foundation.Extension;
|
||||
using ThingsGateway.Foundation.Extension.ConcurrentQueue;
|
||||
using ThingsGateway.Foundation.Extension.String;
|
||||
|
||||
namespace ThingsGateway.Plugin.SQLDB;
|
||||
public class TDengineDB : UpLoadBase
|
||||
{
|
||||
private readonly ConcurrentQueue<TDHistoryValue> DeviceVariableRunTimes = new();
|
||||
private readonly TDengineDBProperty driverPropertys = new();
|
||||
private readonly TDengineDBVariableProperty variablePropertys = new();
|
||||
private GlobalDeviceData _globalDeviceData;
|
||||
private TypeAdapterConfig _config;
|
||||
|
||||
private List<DeviceVariableRunTime> _uploadVariables = new();
|
||||
private TimerTick exTimerTick;
|
||||
public TDengineDB()
|
||||
{
|
||||
_config = new TypeAdapterConfig();
|
||||
_config.ForType<DeviceVariableRunTime, HistoryValue>()
|
||||
.Map(dest => dest.Value, (src) => ValueReturn(src));
|
||||
}
|
||||
private static object ValueReturn(DeviceVariableRunTime src)
|
||||
{
|
||||
if (src.Value?.ToString()?.IsBoolValue() == true)
|
||||
{
|
||||
if (src.Value.ToBoolean())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return src.Value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override Type DriverDebugUIType => null;
|
||||
public override UpDriverPropertyBase DriverPropertys => driverPropertys;
|
||||
public override List<DeviceVariableRunTime> UploadVariables => _uploadVariables;
|
||||
|
||||
public override VariablePropertyBase VariablePropertys => variablePropertys;
|
||||
|
||||
public override Task AfterStopAsync()
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override async Task BeforStartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
SqlSugarClient db = GetHisDbAsync();
|
||||
db.DbMaintenance.CreateDatabase();
|
||||
db.CodeFirst.InitTables(typeof(TDHistoryValue));
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override async Task ExecuteAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var db = GetHisDbAsync();
|
||||
{
|
||||
if (!driverPropertys.IsInterval)
|
||||
{
|
||||
try
|
||||
{
|
||||
////变化推送
|
||||
var varList = DeviceVariableRunTimes.ToListWithDequeue();
|
||||
if (varList?.Count != 0)
|
||||
{
|
||||
await InserableAsync(db, varList, cancellationToken);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (exTimerTick.IsTickHappen())
|
||||
{
|
||||
try
|
||||
{
|
||||
var varList = _uploadVariables.ToList().Adapt<List<TDHistoryValue>>(_config);
|
||||
if (varList?.Count != 0)
|
||||
{
|
||||
await InserableAsync(db, varList, cancellationToken);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (driverPropertys.CycleInterval > UploadDeviceThread.CycleInterval + 50)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(driverPropertys.CycleInterval - UploadDeviceThread.CycleInterval, cancellationToken);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override bool IsConnected() => _uploadVariables?.Count > 0;
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
_globalDeviceData?.AllVariables?.ForEach(a => a.VariableValueChange -= VariableValueChange);
|
||||
_uploadVariables = null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogError(ex);
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
protected override void Init(UploadDeviceRunTime device)
|
||||
{
|
||||
|
||||
_globalDeviceData = App.GetService<GlobalDeviceData>();
|
||||
|
||||
var tags = _globalDeviceData.AllVariables.Where(a => a.VariablePropertys.ContainsKey(device.Id))
|
||||
.Where(b => GetPropertyValue(b, nameof(variablePropertys.Enable)).ToBoolean())
|
||||
.ToList();
|
||||
|
||||
_uploadVariables = tags;
|
||||
|
||||
if (!driverPropertys.IsInterval)
|
||||
{
|
||||
_uploadVariables.ForEach(a =>
|
||||
{
|
||||
a.VariableValueChange += VariableValueChange;
|
||||
});
|
||||
}
|
||||
|
||||
if (_uploadVariables.Count == 0)
|
||||
{
|
||||
LogMessage.LogWarning("插件变量数量为0");
|
||||
}
|
||||
if (driverPropertys.IntervalTime < 1)
|
||||
driverPropertys.IntervalTime = 10;
|
||||
exTimerTick = new(driverPropertys.IntervalTime * 1000);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aop设置
|
||||
/// </summary>
|
||||
/// <param name="db"></param>
|
||||
private static void AopSetting(SqlSugarClient db)
|
||||
{
|
||||
var config = db.CurrentConnectionConfig;
|
||||
|
||||
// 设置超时时间
|
||||
db.Ado.CommandTimeOut = 30;
|
||||
|
||||
// 打印SQL语句
|
||||
db.Aop.OnLogExecuting = (sql, pars) =>
|
||||
{
|
||||
//如果不是开发环境就打印sql
|
||||
if (App.HostEnvironment.IsDevelopment())
|
||||
{
|
||||
if (sql.StartsWith("SELECT"))
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Green;
|
||||
}
|
||||
if (sql.StartsWith("UPDATE"))
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
}
|
||||
if (sql.StartsWith("INSERT"))
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Blue;
|
||||
}
|
||||
if (sql.StartsWith("DELETE"))
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
}
|
||||
WriteSqlLog(UtilMethods.GetSqlString(config.DbType, sql, pars));
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
Console.WriteLine();
|
||||
}
|
||||
};
|
||||
//异常
|
||||
db.Aop.OnError = (ex) =>
|
||||
{
|
||||
//如果不是开发环境就打印日志
|
||||
if (App.WebHostEnvironment.IsDevelopment())
|
||||
{
|
||||
if (ex.Parametres == null) return;
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
var pars = db.Utilities.SerializeObject(((SugarParameter[])ex.Parametres).ToDictionary(it => it.ParameterName, it => it.Value));
|
||||
WriteSqlLogError(UtilMethods.GetSqlString(config.DbType, ex.Sql, (SugarParameter[])ex.Parametres));
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
private static void WriteSqlLog(string msg)
|
||||
{
|
||||
Console.WriteLine("【Sql执行时间】:" + DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat());
|
||||
Console.WriteLine("【Sql语句】:" + msg + Environment.NewLine);
|
||||
}
|
||||
|
||||
private static void WriteSqlLogError(string msg)
|
||||
{
|
||||
Console.WriteLine("【Sql执行错误时间】:" + DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat());
|
||||
Console.WriteLine("【Sql语句】:" + msg + Environment.NewLine);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据库链接
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private SqlSugarClient GetHisDbAsync()
|
||||
{
|
||||
var configureExternalServices = new ConfigureExternalServices
|
||||
{
|
||||
EntityService = (type, column) => // 修改列可空-1、带?问号 2、String类型若没有Required
|
||||
{
|
||||
if ((type.PropertyType.IsGenericType && type.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||||
|| (type.PropertyType == typeof(string) && type.GetCustomAttribute<RequiredAttribute>() == null))
|
||||
column.IsNullable = true;
|
||||
},
|
||||
};
|
||||
var sqlSugarClient = new SqlSugarClient(new ConnectionConfig()
|
||||
{
|
||||
ConnectionString = driverPropertys.ConnectStr,//连接字符串
|
||||
DbType = DbType.TDengine,//数据库类型
|
||||
IsAutoCloseConnection = true, //不设成true要手动close
|
||||
ConfigureExternalServices = configureExternalServices,
|
||||
}
|
||||
);
|
||||
AopSetting(sqlSugarClient);//aop配置
|
||||
return sqlSugarClient;
|
||||
}
|
||||
|
||||
private async Task InserableAsync(SqlSugarClient db, List<TDHistoryValue> dbInserts, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await db.Insertable(dbInserts).ExecuteCommandAsync(cancellationToken);
|
||||
if (result > 0)
|
||||
LogMessage.Trace(FoundationConst.LogMessageHeader + dbInserts.ToJsonString());
|
||||
//连接成功时补发缓存数据
|
||||
var cacheData = await CacheDb.GetCacheData();
|
||||
foreach (var item in cacheData)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = item.CacheStr.FromJsonString<List<TDHistoryValue>>();
|
||||
var cacheresult = await db.Insertable(data).ExecuteCommandAsync(cancellationToken);
|
||||
if (cacheresult > 0)
|
||||
{
|
||||
await CacheDb.DeleteCacheData(item.Id);
|
||||
LogMessage.Trace(FoundationConst.LogMessageHeader + $"主题:{item.Topic}{Environment.NewLine}负载:{item.CacheStr}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex);
|
||||
await CacheDb.AddCacheData("", dbInserts.ToJsonString(), driverPropertys.CacheMaxCount);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void VariableValueChange(DeviceVariableRunTime collectVariableRunTime)
|
||||
{
|
||||
if (!driverPropertys.IsInterval)
|
||||
DeviceVariableRunTimes.Enqueue(collectVariableRunTime.Adapt<TDHistoryValue>(_config));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
|
||||
namespace ThingsGateway.Plugin.SQLDB;
|
||||
|
||||
public class TDengineDBProperty : UpDriverPropertyBase
|
||||
{
|
||||
[DeviceProperty("链接字符串", "")] public string ConnectStr { get; set; } = "Host=localhost;Port=6030;Username=root;Password=taosdata;Database=test";
|
||||
[DeviceProperty("是否间隔插入", "False时将每次变化写入")] public bool IsInterval { get; set; } = true;
|
||||
[DeviceProperty("间隔时间", "秒,实时表时代表更新间隔,历史表时代表插入间隔")] public int IntervalTime { get; set; } = 10;
|
||||
[DeviceProperty("缓存最大条数", "默认2千条")] public int CacheMaxCount { get; set; } = 2000;
|
||||
|
||||
/// <summary>
|
||||
/// 线程循环间隔
|
||||
/// </summary>
|
||||
[DeviceProperty("线程循环间隔", "最小10ms")]
|
||||
public int CycleInterval { get; set; } = 1000;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3,48 +3,40 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.6.33927.249
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation", "Foundation\ThingsGateway.Foundation\ThingsGateway.Foundation.csproj", "{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Web", "Web", "{9EB46BB6-D4EA-4B06-95EE-6C971E653030}"
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "admin", "admin", "{4E66C22C-0636-4949-BF6A-9E3BBE1550BA}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
Web\Directory.Build.props = Web\Directory.Build.props
|
||||
admin\Directory.Build.props = admin\Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "script", "script", "{4A64518E-C072-4607-BBF7-7D392CEC9D58}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Components", "admin\ThingsGateway.Components\ThingsGateway.Components.csproj", "{0A891D8E-23B3-46AD-8D30-565EE5004F93}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Core", "admin\ThingsGateway.Core\ThingsGateway.Core.csproj", "{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Core", "admin\ThingsGateway.Admin.Core\ThingsGateway.Admin.Core.csproj", "{5DA3D2BD-6768-4479-B52F-49E022EFF310}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Blazor", "admin\ThingsGateway.Admin.Blazor\ThingsGateway.Admin.Blazor.csproj", "{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Application", "admin\ThingsGateway.Admin.Application\ThingsGateway.Admin.Application.csproj", "{D6685A42-2712-417A-92C5-5EFF90B9FA94}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.ApiController", "admin\ThingsGateway.Admin.ApiController\ThingsGateway.Admin.ApiController.csproj", "{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "web", "web", "{F0C9A8CB-231B-45E0-B91B-4FEF7EF47197}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
web\Directory.Build.props = web\Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Web.Core", "web\ThingsGateway.Web.Core\ThingsGateway.Web.Core.csproj", "{D37EC028-EA46-4510-8261-6E780A906314}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Web.Entry", "web\ThingsGateway.Web.Entry\ThingsGateway.Web.Entry.csproj", "{C5F662EB-991F-438D-BF61-EF87E7371C04}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "解决方案项", "解决方案项", "{97B23D8B-C6C0-4746-A21F-C7B49354B284}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
..\.gitignore = ..\.gitignore
|
||||
..\README.md = ..\README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Components", "Web\ThingsGateway.Components\ThingsGateway.Components.csproj", "{799C49A4-8E23-475A-A82D-080854718BEE}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation", "foundation\ThingsGateway.Foundation\ThingsGateway.Foundation.csproj", "{6961511A-8787-42AF-827D-B630B2AF4791}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Core", "Web\ThingsGateway.Admin.Core\ThingsGateway.Admin.Core.csproj", "{616CA361-B667-42C8-B4DC-097C7CD39830}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Application", "Web\ThingsGateway.Admin.Application\ThingsGateway.Admin.Application.csproj", "{16C62A28-BACE-4391-91F8-C2D78D063A1E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.ApiController", "Web\ThingsGateway.Admin.ApiController\ThingsGateway.Admin.ApiController.csproj", "{8FA03089-322F-44CB-8E4B-F2637388E944}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Blazor", "Web\ThingsGateway.Admin.Blazor\ThingsGateway.Admin.Blazor.csproj", "{14FF7150-6DB7-455B-AD00-6AB4DE37855B}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Web.Entry", "Web\ThingsGateway.Web.Entry\ThingsGateway.Web.Entry.csproj", "{2861AA39-AAAE-47ED-9ACC-4C165DDF3EF1}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Web.Core", "Web\ThingsGateway.Web.Core\ThingsGateway.Web.Core.csproj", "{9FF2A8A6-48D0-4D8A-9EAD-1905174291CC}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Core", "Web\ThingsGateway.Core\ThingsGateway.Core.csproj", "{51313113-7BB8-494E-9C24-6787BECE39BB}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Admin", "Admin", "{79E7042F-F9E3-4D87-BFA9-4B7DD9736735}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{BB9C2A85-7A8A-4CF9-BF44-34DE9848EC15}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E8D2CBBA-9BCC-44E0-B192-BA0214010203}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Foundation", "Foundation", "{B6288ADE-A570-4962-8907-991B0FF2D89C}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
Foundation\Directory.Build.props = Foundation\Directory.Build.props
|
||||
EndProjectSection
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "foundation", "foundation", "{268A1A81-2685-47E1-9986-5934A58A31A4}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@@ -52,58 +44,56 @@ Global
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{799C49A4-8E23-475A-A82D-080854718BEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{799C49A4-8E23-475A-A82D-080854718BEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{799C49A4-8E23-475A-A82D-080854718BEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{799C49A4-8E23-475A-A82D-080854718BEE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{616CA361-B667-42C8-B4DC-097C7CD39830}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{616CA361-B667-42C8-B4DC-097C7CD39830}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{616CA361-B667-42C8-B4DC-097C7CD39830}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{616CA361-B667-42C8-B4DC-097C7CD39830}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{16C62A28-BACE-4391-91F8-C2D78D063A1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{16C62A28-BACE-4391-91F8-C2D78D063A1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{16C62A28-BACE-4391-91F8-C2D78D063A1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{16C62A28-BACE-4391-91F8-C2D78D063A1E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8FA03089-322F-44CB-8E4B-F2637388E944}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8FA03089-322F-44CB-8E4B-F2637388E944}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8FA03089-322F-44CB-8E4B-F2637388E944}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8FA03089-322F-44CB-8E4B-F2637388E944}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{14FF7150-6DB7-455B-AD00-6AB4DE37855B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{14FF7150-6DB7-455B-AD00-6AB4DE37855B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{14FF7150-6DB7-455B-AD00-6AB4DE37855B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{14FF7150-6DB7-455B-AD00-6AB4DE37855B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2861AA39-AAAE-47ED-9ACC-4C165DDF3EF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2861AA39-AAAE-47ED-9ACC-4C165DDF3EF1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2861AA39-AAAE-47ED-9ACC-4C165DDF3EF1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2861AA39-AAAE-47ED-9ACC-4C165DDF3EF1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9FF2A8A6-48D0-4D8A-9EAD-1905174291CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9FF2A8A6-48D0-4D8A-9EAD-1905174291CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9FF2A8A6-48D0-4D8A-9EAD-1905174291CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9FF2A8A6-48D0-4D8A-9EAD-1905174291CC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{51313113-7BB8-494E-9C24-6787BECE39BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{51313113-7BB8-494E-9C24-6787BECE39BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{51313113-7BB8-494E-9C24-6787BECE39BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{51313113-7BB8-494E-9C24-6787BECE39BB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D37EC028-EA46-4510-8261-6E780A906314}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D37EC028-EA46-4510-8261-6E780A906314}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D37EC028-EA46-4510-8261-6E780A906314}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D37EC028-EA46-4510-8261-6E780A906314}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C5F662EB-991F-438D-BF61-EF87E7371C04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C5F662EB-991F-438D-BF61-EF87E7371C04}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C5F662EB-991F-438D-BF61-EF87E7371C04}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C5F662EB-991F-438D-BF61-EF87E7371C04}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6961511A-8787-42AF-827D-B630B2AF4791}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6961511A-8787-42AF-827D-B630B2AF4791}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6961511A-8787-42AF-827D-B630B2AF4791}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6961511A-8787-42AF-827D-B630B2AF4791}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{2070116F-7A1B-47E2-A2F2-7BEC29ECE891} = {B6288ADE-A570-4962-8907-991B0FF2D89C}
|
||||
{799C49A4-8E23-475A-A82D-080854718BEE} = {BB9C2A85-7A8A-4CF9-BF44-34DE9848EC15}
|
||||
{616CA361-B667-42C8-B4DC-097C7CD39830} = {79E7042F-F9E3-4D87-BFA9-4B7DD9736735}
|
||||
{16C62A28-BACE-4391-91F8-C2D78D063A1E} = {79E7042F-F9E3-4D87-BFA9-4B7DD9736735}
|
||||
{8FA03089-322F-44CB-8E4B-F2637388E944} = {79E7042F-F9E3-4D87-BFA9-4B7DD9736735}
|
||||
{14FF7150-6DB7-455B-AD00-6AB4DE37855B} = {79E7042F-F9E3-4D87-BFA9-4B7DD9736735}
|
||||
{2861AA39-AAAE-47ED-9ACC-4C165DDF3EF1} = {9EB46BB6-D4EA-4B06-95EE-6C971E653030}
|
||||
{9FF2A8A6-48D0-4D8A-9EAD-1905174291CC} = {9EB46BB6-D4EA-4B06-95EE-6C971E653030}
|
||||
{51313113-7BB8-494E-9C24-6787BECE39BB} = {BB9C2A85-7A8A-4CF9-BF44-34DE9848EC15}
|
||||
{79E7042F-F9E3-4D87-BFA9-4B7DD9736735} = {9EB46BB6-D4EA-4B06-95EE-6C971E653030}
|
||||
{BB9C2A85-7A8A-4CF9-BF44-34DE9848EC15} = {9EB46BB6-D4EA-4B06-95EE-6C971E653030}
|
||||
{0A891D8E-23B3-46AD-8D30-565EE5004F93} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{5DA3D2BD-6768-4479-B52F-49E022EFF310} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{D6685A42-2712-417A-92C5-5EFF90B9FA94} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{D37EC028-EA46-4510-8261-6E780A906314} = {F0C9A8CB-231B-45E0-B91B-4FEF7EF47197}
|
||||
{C5F662EB-991F-438D-BF61-EF87E7371C04} = {F0C9A8CB-231B-45E0-B91B-4FEF7EF47197}
|
||||
{6961511A-8787-42AF-827D-B630B2AF4791} = {268A1A81-2685-47E1-9986-5934A58A31A4}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C49B2D3E-6818-4E28-91B7-6E4E7E264BBB}
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.6.33927.249
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation", "Foundation\ThingsGateway.Foundation\ThingsGateway.Foundation.csproj", "{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Components", "Web\ThingsGateway.Components\ThingsGateway.Components.csproj", "{799C49A4-8E23-475A-A82D-080854718BEE}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Core", "Web\ThingsGateway.Core\ThingsGateway.Core.csproj", "{51313113-7BB8-494E-9C24-6787BECE39BB}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.UpgradeManger", "UpgradeManger\ThingsGateway.UpgradeManger\ThingsGateway.UpgradeManger.csproj", "{84362F1D-E788-4646-B555-5A3629B55EFC}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Upgrade", "UpgradeManger\ThingsGateway.Upgrade\ThingsGateway.Upgrade.csproj", "{681F774F-7B0B-450A-917C-1385E1847CA6}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{799C49A4-8E23-475A-A82D-080854718BEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{799C49A4-8E23-475A-A82D-080854718BEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{799C49A4-8E23-475A-A82D-080854718BEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{799C49A4-8E23-475A-A82D-080854718BEE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{51313113-7BB8-494E-9C24-6787BECE39BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{51313113-7BB8-494E-9C24-6787BECE39BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{51313113-7BB8-494E-9C24-6787BECE39BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{51313113-7BB8-494E-9C24-6787BECE39BB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{84362F1D-E788-4646-B555-5A3629B55EFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{84362F1D-E788-4646-B555-5A3629B55EFC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{84362F1D-E788-4646-B555-5A3629B55EFC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{84362F1D-E788-4646-B555-5A3629B55EFC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{681F774F-7B0B-450A-917C-1385E1847CA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{681F774F-7B0B-450A-917C-1385E1847CA6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{681F774F-7B0B-450A-917C-1385E1847CA6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{681F774F-7B0B-450A-917C-1385E1847CA6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C49B2D3E-6818-4E28-91B7-6E4E7E264BBB}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -3,107 +3,107 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.6.33927.249
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation", "Foundation\ThingsGateway.Foundation\ThingsGateway.Foundation.csproj", "{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation", "foundation\ThingsGateway.foundation\ThingsGateway.Foundation.csproj", "{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Foundation", "Foundation", "{0874CBC5-C583-4FAD-BA93-94571D446898}"
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "foundation", "foundation", "{0874CBC5-C583-4FAD-BA93-94571D446898}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
Foundation\Directory.Build.props = Foundation\Directory.Build.props
|
||||
foundation\Directory.Build.props = foundation\Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Adapter.DLT645", "Foundation\ThingsGateway.Foundation.Adapter.DLT645\ThingsGateway.Foundation.Adapter.DLT645.csproj", "{92963877-0185-45A5-A0EB-CEC0D55FF9B0}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Adapter.DLT645", "foundation\ThingsGateway.Foundation.Adapter.DLT645\ThingsGateway.Foundation.Adapter.DLT645.csproj", "{92963877-0185-45A5-A0EB-CEC0D55FF9B0}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Adapter.Modbus", "Foundation\ThingsGateway.Foundation.Adapter.Modbus\ThingsGateway.Foundation.Adapter.Modbus.csproj", "{24510CCE-0B60-4A03-9719-CF367C3528E9}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Adapter.Modbus", "foundation\ThingsGateway.Foundation.Adapter.Modbus\ThingsGateway.Foundation.Adapter.Modbus.csproj", "{24510CCE-0B60-4A03-9719-CF367C3528E9}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Adapter.OPCDA", "Foundation\ThingsGateway.Foundation.Adapter.OPCDA\ThingsGateway.Foundation.Adapter.OPCDA.csproj", "{566783A4-222B-46F5-AA12-0753997B3254}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Adapter.OPCDA", "foundation\ThingsGateway.Foundation.Adapter.OPCDA\ThingsGateway.Foundation.Adapter.OPCDA.csproj", "{566783A4-222B-46F5-AA12-0753997B3254}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Adapter.OPCUA", "Foundation\ThingsGateway.Foundation.Adapter.OPCUA\ThingsGateway.Foundation.Adapter.OPCUA.csproj", "{BEFBC44A-E140-4E3E-AFBE-2DD8B98EB9BF}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Adapter.OPCUA", "foundation\ThingsGateway.Foundation.Adapter.OPCUA\ThingsGateway.Foundation.Adapter.OPCUA.csproj", "{BEFBC44A-E140-4E3E-AFBE-2DD8B98EB9BF}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Adapter.Siemens", "Foundation\ThingsGateway.Foundation.Adapter.Siemens\ThingsGateway.Foundation.Adapter.Siemens.csproj", "{9695B353-D773-40DD-B65E-7B10EB0C16EC}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Adapter.Siemens", "foundation\ThingsGateway.Foundation.Adapter.Siemens\ThingsGateway.Foundation.Adapter.Siemens.csproj", "{9695B353-D773-40DD-B65E-7B10EB0C16EC}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Demo", "Demo", "{95008B83-0324-4A7C-80DE-2BBDDD1A9099}"
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "demo", "demo", "{358AE1E1-4DD6-4D1F-8935-1ACBB0111A01}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
Demo\Directory.Build.props = Demo\Directory.Build.props
|
||||
demo\Directory.Build.props = demo\Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Web", "Web", "{9EB46BB6-D4EA-4B06-95EE-6C971E653030}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Demo.Photino", "demo\ThingsGateway.Foundation.Demo.Photino\ThingsGateway.Foundation.Demo.Photino.csproj", "{2192217C-CF77-422E-9E63-DF4003ABF01A}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Demo.Rcl", "demo\ThingsGateway.Foundation.Demo.Rcl\ThingsGateway.Foundation.Demo.Rcl.csproj", "{DE376FAD-1E99-4CEE-96B2-08B1D1F3D1DB}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Demo.Winform", "demo\ThingsGateway.Foundation.Demo.Winform\ThingsGateway.Foundation.Demo.Winform.csproj", "{ACAA3F0D-CE2B-49F4-883A-ED23ADD9E325}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gateway", "gateway", "{DFB97103-FC3A-4DC3-A327-DA8C65BDA607}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
Web\Directory.Build.props = Web\Directory.Build.props
|
||||
gateway\Directory.Build.props = gateway\Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "script", "script", "{4A64518E-C072-4607-BBF7-7D392CEC9D58}"
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "admin", "admin", "{4E66C22C-0636-4949-BF6A-9E3BBE1550BA}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
admin\Directory.Build.props = admin\Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Components", "admin\ThingsGateway.Components\ThingsGateway.Components.csproj", "{0A891D8E-23B3-46AD-8D30-565EE5004F93}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Core", "admin\ThingsGateway.Core\ThingsGateway.Core.csproj", "{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Core", "admin\ThingsGateway.Admin.Core\ThingsGateway.Admin.Core.csproj", "{5DA3D2BD-6768-4479-B52F-49E022EFF310}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Blazor", "admin\ThingsGateway.Admin.Blazor\ThingsGateway.Admin.Blazor.csproj", "{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Application", "admin\ThingsGateway.Admin.Application\ThingsGateway.Admin.Application.csproj", "{D6685A42-2712-417A-92C5-5EFF90B9FA94}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.ApiController", "admin\ThingsGateway.Admin.ApiController\ThingsGateway.Admin.ApiController.csproj", "{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Gateway.Core", "gateway\ThingsGateway.Gateway.Core\ThingsGateway.Gateway.Core.csproj", "{1A4D0B95-9FC5-4687-94E2-B6F86B5427F2}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Gateway.Blazor", "gateway\ThingsGateway.Gateway.Blazor\ThingsGateway.Gateway.Blazor.csproj", "{69EA3D89-CB40-425A-8D70-5E4A33337BE5}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Gateway.Application", "gateway\ThingsGateway.Gateway.Application\ThingsGateway.Gateway.Application.csproj", "{90AB5C24-1AA3-4F58-9987-B307B92B5193}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Gateway.ApiController", "gateway\ThingsGateway.Gateway.ApiController\ThingsGateway.Gateway.ApiController.csproj", "{4C7A5A90-8292-413B-8848-419D9DCDE66F}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "web", "web", "{F0C9A8CB-231B-45E0-B91B-4FEF7EF47197}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
web\Directory.Build.props = web\Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Web.Core", "web\ThingsGateway.Web.Core\ThingsGateway.Web.Core.csproj", "{D37EC028-EA46-4510-8261-6E780A906314}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Web.Entry", "web\ThingsGateway.Web.Entry\ThingsGateway.Web.Entry.csproj", "{C5F662EB-991F-438D-BF61-EF87E7371C04}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "plugin", "plugin", "{E65490B8-D2E2-4693-B39C-15703B1EBFBB}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
plugin\Directory.Build.props = plugin\Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.Modbus", "plugin\ThingsGateway.Plugin.Modbus\ThingsGateway.Plugin.Modbus.csproj", "{ECF3A7A3-2363-4A38-BC78-8FF9A8564603}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.Mqtt", "plugin\ThingsGateway.Plugin.Mqtt\ThingsGateway.Plugin.Mqtt.csproj", "{53C870AE-0249-4485-AE63-F8A16EA4BCB4}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "解决方案项", "解决方案项", "{97B23D8B-C6C0-4746-A21F-C7B49354B284}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
..\.gitignore = ..\.gitignore
|
||||
..\README.md = ..\README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Components", "Web\ThingsGateway.Components\ThingsGateway.Components.csproj", "{799C49A4-8E23-475A-A82D-080854718BEE}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.Kafka", "plugin\ThingsGateway.Plugin.Kafka\ThingsGateway.Plugin.Kafka.csproj", "{E4B8B8E6-FAE7-43BA-9A51-33A3CD9FB825}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Core", "Web\ThingsGateway.Admin.Core\ThingsGateway.Admin.Core.csproj", "{616CA361-B667-42C8-B4DC-097C7CD39830}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.SQLDB", "plugin\ThingsGateway.Plugin.SQLDB\ThingsGateway.Plugin.SQLDB.csproj", "{C102AB3A-377E-4753-AFA7-C13250D7DF00}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Application", "Web\ThingsGateway.Admin.Application\ThingsGateway.Admin.Application.csproj", "{16C62A28-BACE-4391-91F8-C2D78D063A1E}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.QuestDB", "plugin\ThingsGateway.Plugin.QuestDB\ThingsGateway.Plugin.QuestDB.csproj", "{0DE1D254-0BD2-4D98-B939-5440BE5EB552}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.ApiController", "Web\ThingsGateway.Admin.ApiController\ThingsGateway.Admin.ApiController.csproj", "{8FA03089-322F-44CB-8E4B-F2637388E944}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.TDengineDB", "plugin\ThingsGateway.Plugin.TDengineDB\ThingsGateway.Plugin.TDengineDB.csproj", "{C1911F84-6FDB-4DEC-8938-69B2E3901CC4}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Blazor", "Web\ThingsGateway.Admin.Blazor\ThingsGateway.Admin.Blazor.csproj", "{14FF7150-6DB7-455B-AD00-6AB4DE37855B}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.RabbitMQ", "plugin\ThingsGateway.Plugin.RabbitMQ\ThingsGateway.Plugin.RabbitMQ.csproj", "{A8E68E17-4EBF-4E4C-8272-B489329A68BF}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Web.Entry", "Web\ThingsGateway.Web.Entry\ThingsGateway.Web.Entry.csproj", "{2861AA39-AAAE-47ED-9ACC-4C165DDF3EF1}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.Siemens", "plugin\ThingsGateway.Plugin.Siemens\ThingsGateway.Plugin.Siemens.csproj", "{5FAFD46E-6B98-4C75-B1EB-085AA18F15FD}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Web.Core", "Web\ThingsGateway.Web.Core\ThingsGateway.Web.Core.csproj", "{9FF2A8A6-48D0-4D8A-9EAD-1905174291CC}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.DLT645", "plugin\ThingsGateway.Plugin.DLT645\ThingsGateway.Plugin.DLT645.csproj", "{AC4295F2-AB2F-4137-99EF-80FA5C83896B}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Core", "Web\ThingsGateway.Core\ThingsGateway.Core.csproj", "{51313113-7BB8-494E-9C24-6787BECE39BB}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.OPCDA", "plugin\ThingsGateway.Plugin.OPCDA\ThingsGateway.Plugin.OPCDA.csproj", "{9DA9AED3-9572-4378-A2A6-4D792D67ADDC}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Gateway.ApiController", "Web\ThingsGateway.Gateway.ApiController\ThingsGateway.Gateway.ApiController.csproj", "{5D7BE567-2345-46C8-9F54-DDC1DA96D198}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.OPCUA", "plugin\ThingsGateway.Plugin.OPCUA\ThingsGateway.Plugin.OPCUA.csproj", "{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Gateway.Application", "Web\ThingsGateway.Gateway.Application\ThingsGateway.Gateway.Application.csproj", "{5CF1B3EC-84E2-484A-8DFC-2ECD2EE18E2F}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Gateway.Blazor", "Web\ThingsGateway.Gateway.Blazor\ThingsGateway.Gateway.Blazor.csproj", "{CD0F211A-F65B-4026-9750-68AC3C70D012}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Gateway.Core", "Web\ThingsGateway.Gateway.Core\ThingsGateway.Gateway.Core.csproj", "{5CD79F91-7182-4A9D-9BEF-4DF410C782D2}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugin", "Plugin", "{CC8D0880-B73E-4DFC-9052-86504728708E}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
Plugin\Directory.Build.props = Plugin\Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.Modbus", "Plugin\ThingsGateway.Plugin.Modbus\ThingsGateway.Plugin.Modbus.csproj", "{2057E5BE-FACA-4D44-A2BA-E1F864A8DAFF}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.DLT645", "Plugin\ThingsGateway.Plugin.DLT645\ThingsGateway.Plugin.DLT645.csproj", "{A723D4D7-B796-4D97-BA68-95E5696C9559}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.Kafka", "Plugin\ThingsGateway.Plugin.Kafka\ThingsGateway.Plugin.Kafka.csproj", "{D9944D52-81B4-4DBC-8C3B-2A334CCBD4F6}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.Mqtt", "Plugin\ThingsGateway.Plugin.Mqtt\ThingsGateway.Plugin.Mqtt.csproj", "{C5C89B2F-D9C9-4A67-A9BE-4E5F0B42162F}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.OPCDA", "Plugin\ThingsGateway.Plugin.OPCDA\ThingsGateway.Plugin.OPCDA.csproj", "{7562C85D-267D-4718-8857-422B625C5BD0}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.OPCUA", "Plugin\ThingsGateway.Plugin.OPCUA\ThingsGateway.Plugin.OPCUA.csproj", "{A0E1EAC7-10DD-4520-973F-CC385BBFBD84}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.RabbitMQ", "Plugin\ThingsGateway.Plugin.RabbitMQ\ThingsGateway.Plugin.RabbitMQ.csproj", "{503529C4-842A-47F0-928B-C8DC5B0A367D}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.Siemens", "Plugin\ThingsGateway.Plugin.Siemens\ThingsGateway.Plugin.Siemens.csproj", "{8A9F6586-3320-4F03-B3DA-09BF39AA90A0}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E8D2CBBA-9BCC-44E0-B192-BA0214010203}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UpgradeManger", "UpgradeManger", "{237C7BC5-7B07-40B5-AF42-CE2F8E0893C3}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
UpgradeManger\Directory.Build.props = UpgradeManger\Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.UpgradeManger", "UpgradeManger\ThingsGateway.UpgradeManger\ThingsGateway.UpgradeManger.csproj", "{84362F1D-E788-4646-B555-5A3629B55EFC}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Upgrade", "UpgradeManger\ThingsGateway.Upgrade\ThingsGateway.Upgrade.csproj", "{681F774F-7B0B-450A-917C-1385E1847CA6}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Demo.Rcl", "Demo\ThingsGateway.Foundation.Demo.Rcl\ThingsGateway.Foundation.Demo.Rcl.csproj", "{637A662B-7B70-4CE8-8F5F-0A095B9D77EC}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Demo.Photino", "Demo\ThingsGateway.Foundation.Demo.Photino\ThingsGateway.Foundation.Demo.Photino.csproj", "{C5519C51-0A0C-4317-A43D-FFBB6B344ACB}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.SQLDB", "Plugin\ThingsGateway.Plugin.SQLDB\ThingsGateway.Plugin.SQLDB.csproj", "{7EBD5500-0DA0-415A-831D-5DC350917501}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.QuestDB", "Plugin\ThingsGateway.Plugin.QuestDB\ThingsGateway.Plugin.QuestDB.csproj", "{A99787D7-A93B-4357-A8B5-B5F1FD2930AB}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.TDengineDB", "Plugin\ThingsGateway.Plugin.TDengineDB\ThingsGateway.Plugin.TDengineDB.csproj", "{2C827B2C-75DF-413B-9AB2-2D1B438AC082}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.SQLHisAlarm", "plugin\ThingsGateway.Plugin.SQLHisAlarm\ThingsGateway.Plugin.SQLHisAlarm.csproj", "{0947E6C0-6371-4483-B0ED-191FB5073151}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@@ -135,114 +135,114 @@ Global
|
||||
{9695B353-D773-40DD-B65E-7B10EB0C16EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9695B353-D773-40DD-B65E-7B10EB0C16EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9695B353-D773-40DD-B65E-7B10EB0C16EC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{799C49A4-8E23-475A-A82D-080854718BEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{799C49A4-8E23-475A-A82D-080854718BEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{799C49A4-8E23-475A-A82D-080854718BEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{799C49A4-8E23-475A-A82D-080854718BEE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{616CA361-B667-42C8-B4DC-097C7CD39830}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{616CA361-B667-42C8-B4DC-097C7CD39830}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{616CA361-B667-42C8-B4DC-097C7CD39830}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{616CA361-B667-42C8-B4DC-097C7CD39830}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{16C62A28-BACE-4391-91F8-C2D78D063A1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{16C62A28-BACE-4391-91F8-C2D78D063A1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{16C62A28-BACE-4391-91F8-C2D78D063A1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{16C62A28-BACE-4391-91F8-C2D78D063A1E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8FA03089-322F-44CB-8E4B-F2637388E944}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8FA03089-322F-44CB-8E4B-F2637388E944}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8FA03089-322F-44CB-8E4B-F2637388E944}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8FA03089-322F-44CB-8E4B-F2637388E944}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{14FF7150-6DB7-455B-AD00-6AB4DE37855B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{14FF7150-6DB7-455B-AD00-6AB4DE37855B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{14FF7150-6DB7-455B-AD00-6AB4DE37855B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{14FF7150-6DB7-455B-AD00-6AB4DE37855B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2861AA39-AAAE-47ED-9ACC-4C165DDF3EF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2861AA39-AAAE-47ED-9ACC-4C165DDF3EF1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2861AA39-AAAE-47ED-9ACC-4C165DDF3EF1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2861AA39-AAAE-47ED-9ACC-4C165DDF3EF1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9FF2A8A6-48D0-4D8A-9EAD-1905174291CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9FF2A8A6-48D0-4D8A-9EAD-1905174291CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9FF2A8A6-48D0-4D8A-9EAD-1905174291CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9FF2A8A6-48D0-4D8A-9EAD-1905174291CC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{51313113-7BB8-494E-9C24-6787BECE39BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{51313113-7BB8-494E-9C24-6787BECE39BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{51313113-7BB8-494E-9C24-6787BECE39BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{51313113-7BB8-494E-9C24-6787BECE39BB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5D7BE567-2345-46C8-9F54-DDC1DA96D198}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5D7BE567-2345-46C8-9F54-DDC1DA96D198}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5D7BE567-2345-46C8-9F54-DDC1DA96D198}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5D7BE567-2345-46C8-9F54-DDC1DA96D198}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5CF1B3EC-84E2-484A-8DFC-2ECD2EE18E2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5CF1B3EC-84E2-484A-8DFC-2ECD2EE18E2F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5CF1B3EC-84E2-484A-8DFC-2ECD2EE18E2F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5CF1B3EC-84E2-484A-8DFC-2ECD2EE18E2F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CD0F211A-F65B-4026-9750-68AC3C70D012}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CD0F211A-F65B-4026-9750-68AC3C70D012}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CD0F211A-F65B-4026-9750-68AC3C70D012}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CD0F211A-F65B-4026-9750-68AC3C70D012}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5CD79F91-7182-4A9D-9BEF-4DF410C782D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5CD79F91-7182-4A9D-9BEF-4DF410C782D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5CD79F91-7182-4A9D-9BEF-4DF410C782D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5CD79F91-7182-4A9D-9BEF-4DF410C782D2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2057E5BE-FACA-4D44-A2BA-E1F864A8DAFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2057E5BE-FACA-4D44-A2BA-E1F864A8DAFF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2057E5BE-FACA-4D44-A2BA-E1F864A8DAFF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2057E5BE-FACA-4D44-A2BA-E1F864A8DAFF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A723D4D7-B796-4D97-BA68-95E5696C9559}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A723D4D7-B796-4D97-BA68-95E5696C9559}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A723D4D7-B796-4D97-BA68-95E5696C9559}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A723D4D7-B796-4D97-BA68-95E5696C9559}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D9944D52-81B4-4DBC-8C3B-2A334CCBD4F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D9944D52-81B4-4DBC-8C3B-2A334CCBD4F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D9944D52-81B4-4DBC-8C3B-2A334CCBD4F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D9944D52-81B4-4DBC-8C3B-2A334CCBD4F6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C5C89B2F-D9C9-4A67-A9BE-4E5F0B42162F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C5C89B2F-D9C9-4A67-A9BE-4E5F0B42162F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C5C89B2F-D9C9-4A67-A9BE-4E5F0B42162F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C5C89B2F-D9C9-4A67-A9BE-4E5F0B42162F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7562C85D-267D-4718-8857-422B625C5BD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7562C85D-267D-4718-8857-422B625C5BD0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7562C85D-267D-4718-8857-422B625C5BD0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7562C85D-267D-4718-8857-422B625C5BD0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A0E1EAC7-10DD-4520-973F-CC385BBFBD84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A0E1EAC7-10DD-4520-973F-CC385BBFBD84}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A0E1EAC7-10DD-4520-973F-CC385BBFBD84}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A0E1EAC7-10DD-4520-973F-CC385BBFBD84}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{503529C4-842A-47F0-928B-C8DC5B0A367D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{503529C4-842A-47F0-928B-C8DC5B0A367D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{503529C4-842A-47F0-928B-C8DC5B0A367D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{503529C4-842A-47F0-928B-C8DC5B0A367D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8A9F6586-3320-4F03-B3DA-09BF39AA90A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8A9F6586-3320-4F03-B3DA-09BF39AA90A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8A9F6586-3320-4F03-B3DA-09BF39AA90A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8A9F6586-3320-4F03-B3DA-09BF39AA90A0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{84362F1D-E788-4646-B555-5A3629B55EFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{84362F1D-E788-4646-B555-5A3629B55EFC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{84362F1D-E788-4646-B555-5A3629B55EFC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{84362F1D-E788-4646-B555-5A3629B55EFC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{681F774F-7B0B-450A-917C-1385E1847CA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{681F774F-7B0B-450A-917C-1385E1847CA6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{681F774F-7B0B-450A-917C-1385E1847CA6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{681F774F-7B0B-450A-917C-1385E1847CA6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{637A662B-7B70-4CE8-8F5F-0A095B9D77EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{637A662B-7B70-4CE8-8F5F-0A095B9D77EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{637A662B-7B70-4CE8-8F5F-0A095B9D77EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{637A662B-7B70-4CE8-8F5F-0A095B9D77EC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C5519C51-0A0C-4317-A43D-FFBB6B344ACB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C5519C51-0A0C-4317-A43D-FFBB6B344ACB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C5519C51-0A0C-4317-A43D-FFBB6B344ACB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C5519C51-0A0C-4317-A43D-FFBB6B344ACB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7EBD5500-0DA0-415A-831D-5DC350917501}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7EBD5500-0DA0-415A-831D-5DC350917501}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7EBD5500-0DA0-415A-831D-5DC350917501}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7EBD5500-0DA0-415A-831D-5DC350917501}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A99787D7-A93B-4357-A8B5-B5F1FD2930AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A99787D7-A93B-4357-A8B5-B5F1FD2930AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A99787D7-A93B-4357-A8B5-B5F1FD2930AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A99787D7-A93B-4357-A8B5-B5F1FD2930AB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2C827B2C-75DF-413B-9AB2-2D1B438AC082}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2C827B2C-75DF-413B-9AB2-2D1B438AC082}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2C827B2C-75DF-413B-9AB2-2D1B438AC082}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2C827B2C-75DF-413B-9AB2-2D1B438AC082}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2192217C-CF77-422E-9E63-DF4003ABF01A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2192217C-CF77-422E-9E63-DF4003ABF01A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2192217C-CF77-422E-9E63-DF4003ABF01A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2192217C-CF77-422E-9E63-DF4003ABF01A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DE376FAD-1E99-4CEE-96B2-08B1D1F3D1DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DE376FAD-1E99-4CEE-96B2-08B1D1F3D1DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DE376FAD-1E99-4CEE-96B2-08B1D1F3D1DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DE376FAD-1E99-4CEE-96B2-08B1D1F3D1DB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{ACAA3F0D-CE2B-49F4-883A-ED23ADD9E325}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ACAA3F0D-CE2B-49F4-883A-ED23ADD9E325}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ACAA3F0D-CE2B-49F4-883A-ED23ADD9E325}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ACAA3F0D-CE2B-49F4-883A-ED23ADD9E325}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1A4D0B95-9FC5-4687-94E2-B6F86B5427F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1A4D0B95-9FC5-4687-94E2-B6F86B5427F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1A4D0B95-9FC5-4687-94E2-B6F86B5427F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1A4D0B95-9FC5-4687-94E2-B6F86B5427F2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{69EA3D89-CB40-425A-8D70-5E4A33337BE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{69EA3D89-CB40-425A-8D70-5E4A33337BE5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{69EA3D89-CB40-425A-8D70-5E4A33337BE5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{69EA3D89-CB40-425A-8D70-5E4A33337BE5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{90AB5C24-1AA3-4F58-9987-B307B92B5193}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{90AB5C24-1AA3-4F58-9987-B307B92B5193}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{90AB5C24-1AA3-4F58-9987-B307B92B5193}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{90AB5C24-1AA3-4F58-9987-B307B92B5193}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4C7A5A90-8292-413B-8848-419D9DCDE66F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4C7A5A90-8292-413B-8848-419D9DCDE66F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4C7A5A90-8292-413B-8848-419D9DCDE66F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4C7A5A90-8292-413B-8848-419D9DCDE66F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D37EC028-EA46-4510-8261-6E780A906314}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D37EC028-EA46-4510-8261-6E780A906314}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D37EC028-EA46-4510-8261-6E780A906314}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D37EC028-EA46-4510-8261-6E780A906314}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C5F662EB-991F-438D-BF61-EF87E7371C04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C5F662EB-991F-438D-BF61-EF87E7371C04}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C5F662EB-991F-438D-BF61-EF87E7371C04}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C5F662EB-991F-438D-BF61-EF87E7371C04}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{ECF3A7A3-2363-4A38-BC78-8FF9A8564603}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ECF3A7A3-2363-4A38-BC78-8FF9A8564603}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ECF3A7A3-2363-4A38-BC78-8FF9A8564603}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ECF3A7A3-2363-4A38-BC78-8FF9A8564603}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{53C870AE-0249-4485-AE63-F8A16EA4BCB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{53C870AE-0249-4485-AE63-F8A16EA4BCB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{53C870AE-0249-4485-AE63-F8A16EA4BCB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{53C870AE-0249-4485-AE63-F8A16EA4BCB4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E4B8B8E6-FAE7-43BA-9A51-33A3CD9FB825}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E4B8B8E6-FAE7-43BA-9A51-33A3CD9FB825}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E4B8B8E6-FAE7-43BA-9A51-33A3CD9FB825}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E4B8B8E6-FAE7-43BA-9A51-33A3CD9FB825}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C102AB3A-377E-4753-AFA7-C13250D7DF00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C102AB3A-377E-4753-AFA7-C13250D7DF00}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C102AB3A-377E-4753-AFA7-C13250D7DF00}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C102AB3A-377E-4753-AFA7-C13250D7DF00}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0DE1D254-0BD2-4D98-B939-5440BE5EB552}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0DE1D254-0BD2-4D98-B939-5440BE5EB552}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0DE1D254-0BD2-4D98-B939-5440BE5EB552}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0DE1D254-0BD2-4D98-B939-5440BE5EB552}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C1911F84-6FDB-4DEC-8938-69B2E3901CC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C1911F84-6FDB-4DEC-8938-69B2E3901CC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C1911F84-6FDB-4DEC-8938-69B2E3901CC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C1911F84-6FDB-4DEC-8938-69B2E3901CC4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A8E68E17-4EBF-4E4C-8272-B489329A68BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A8E68E17-4EBF-4E4C-8272-B489329A68BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A8E68E17-4EBF-4E4C-8272-B489329A68BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A8E68E17-4EBF-4E4C-8272-B489329A68BF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5FAFD46E-6B98-4C75-B1EB-085AA18F15FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5FAFD46E-6B98-4C75-B1EB-085AA18F15FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5FAFD46E-6B98-4C75-B1EB-085AA18F15FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5FAFD46E-6B98-4C75-B1EB-085AA18F15FD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AC4295F2-AB2F-4137-99EF-80FA5C83896B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AC4295F2-AB2F-4137-99EF-80FA5C83896B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AC4295F2-AB2F-4137-99EF-80FA5C83896B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AC4295F2-AB2F-4137-99EF-80FA5C83896B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9DA9AED3-9572-4378-A2A6-4D792D67ADDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9DA9AED3-9572-4378-A2A6-4D792D67ADDC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9DA9AED3-9572-4378-A2A6-4D792D67ADDC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9DA9AED3-9572-4378-A2A6-4D792D67ADDC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0947E6C0-6371-4483-B0ED-191FB5073151}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0947E6C0-6371-4483-B0ED-191FB5073151}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0947E6C0-6371-4483-B0ED-191FB5073151}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0947E6C0-6371-4483-B0ED-191FB5073151}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -254,33 +254,33 @@ Global
|
||||
{566783A4-222B-46F5-AA12-0753997B3254} = {0874CBC5-C583-4FAD-BA93-94571D446898}
|
||||
{BEFBC44A-E140-4E3E-AFBE-2DD8B98EB9BF} = {0874CBC5-C583-4FAD-BA93-94571D446898}
|
||||
{9695B353-D773-40DD-B65E-7B10EB0C16EC} = {0874CBC5-C583-4FAD-BA93-94571D446898}
|
||||
{799C49A4-8E23-475A-A82D-080854718BEE} = {9EB46BB6-D4EA-4B06-95EE-6C971E653030}
|
||||
{616CA361-B667-42C8-B4DC-097C7CD39830} = {9EB46BB6-D4EA-4B06-95EE-6C971E653030}
|
||||
{16C62A28-BACE-4391-91F8-C2D78D063A1E} = {9EB46BB6-D4EA-4B06-95EE-6C971E653030}
|
||||
{8FA03089-322F-44CB-8E4B-F2637388E944} = {9EB46BB6-D4EA-4B06-95EE-6C971E653030}
|
||||
{14FF7150-6DB7-455B-AD00-6AB4DE37855B} = {9EB46BB6-D4EA-4B06-95EE-6C971E653030}
|
||||
{2861AA39-AAAE-47ED-9ACC-4C165DDF3EF1} = {9EB46BB6-D4EA-4B06-95EE-6C971E653030}
|
||||
{9FF2A8A6-48D0-4D8A-9EAD-1905174291CC} = {9EB46BB6-D4EA-4B06-95EE-6C971E653030}
|
||||
{51313113-7BB8-494E-9C24-6787BECE39BB} = {9EB46BB6-D4EA-4B06-95EE-6C971E653030}
|
||||
{5D7BE567-2345-46C8-9F54-DDC1DA96D198} = {9EB46BB6-D4EA-4B06-95EE-6C971E653030}
|
||||
{5CF1B3EC-84E2-484A-8DFC-2ECD2EE18E2F} = {9EB46BB6-D4EA-4B06-95EE-6C971E653030}
|
||||
{CD0F211A-F65B-4026-9750-68AC3C70D012} = {9EB46BB6-D4EA-4B06-95EE-6C971E653030}
|
||||
{5CD79F91-7182-4A9D-9BEF-4DF410C782D2} = {9EB46BB6-D4EA-4B06-95EE-6C971E653030}
|
||||
{2057E5BE-FACA-4D44-A2BA-E1F864A8DAFF} = {CC8D0880-B73E-4DFC-9052-86504728708E}
|
||||
{A723D4D7-B796-4D97-BA68-95E5696C9559} = {CC8D0880-B73E-4DFC-9052-86504728708E}
|
||||
{D9944D52-81B4-4DBC-8C3B-2A334CCBD4F6} = {CC8D0880-B73E-4DFC-9052-86504728708E}
|
||||
{C5C89B2F-D9C9-4A67-A9BE-4E5F0B42162F} = {CC8D0880-B73E-4DFC-9052-86504728708E}
|
||||
{7562C85D-267D-4718-8857-422B625C5BD0} = {CC8D0880-B73E-4DFC-9052-86504728708E}
|
||||
{A0E1EAC7-10DD-4520-973F-CC385BBFBD84} = {CC8D0880-B73E-4DFC-9052-86504728708E}
|
||||
{503529C4-842A-47F0-928B-C8DC5B0A367D} = {CC8D0880-B73E-4DFC-9052-86504728708E}
|
||||
{8A9F6586-3320-4F03-B3DA-09BF39AA90A0} = {CC8D0880-B73E-4DFC-9052-86504728708E}
|
||||
{84362F1D-E788-4646-B555-5A3629B55EFC} = {237C7BC5-7B07-40B5-AF42-CE2F8E0893C3}
|
||||
{681F774F-7B0B-450A-917C-1385E1847CA6} = {237C7BC5-7B07-40B5-AF42-CE2F8E0893C3}
|
||||
{637A662B-7B70-4CE8-8F5F-0A095B9D77EC} = {95008B83-0324-4A7C-80DE-2BBDDD1A9099}
|
||||
{C5519C51-0A0C-4317-A43D-FFBB6B344ACB} = {95008B83-0324-4A7C-80DE-2BBDDD1A9099}
|
||||
{7EBD5500-0DA0-415A-831D-5DC350917501} = {CC8D0880-B73E-4DFC-9052-86504728708E}
|
||||
{A99787D7-A93B-4357-A8B5-B5F1FD2930AB} = {CC8D0880-B73E-4DFC-9052-86504728708E}
|
||||
{2C827B2C-75DF-413B-9AB2-2D1B438AC082} = {CC8D0880-B73E-4DFC-9052-86504728708E}
|
||||
{2192217C-CF77-422E-9E63-DF4003ABF01A} = {358AE1E1-4DD6-4D1F-8935-1ACBB0111A01}
|
||||
{DE376FAD-1E99-4CEE-96B2-08B1D1F3D1DB} = {358AE1E1-4DD6-4D1F-8935-1ACBB0111A01}
|
||||
{ACAA3F0D-CE2B-49F4-883A-ED23ADD9E325} = {358AE1E1-4DD6-4D1F-8935-1ACBB0111A01}
|
||||
{0A891D8E-23B3-46AD-8D30-565EE5004F93} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{5DA3D2BD-6768-4479-B52F-49E022EFF310} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{D6685A42-2712-417A-92C5-5EFF90B9FA94} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{1A4D0B95-9FC5-4687-94E2-B6F86B5427F2} = {DFB97103-FC3A-4DC3-A327-DA8C65BDA607}
|
||||
{69EA3D89-CB40-425A-8D70-5E4A33337BE5} = {DFB97103-FC3A-4DC3-A327-DA8C65BDA607}
|
||||
{90AB5C24-1AA3-4F58-9987-B307B92B5193} = {DFB97103-FC3A-4DC3-A327-DA8C65BDA607}
|
||||
{4C7A5A90-8292-413B-8848-419D9DCDE66F} = {DFB97103-FC3A-4DC3-A327-DA8C65BDA607}
|
||||
{D37EC028-EA46-4510-8261-6E780A906314} = {F0C9A8CB-231B-45E0-B91B-4FEF7EF47197}
|
||||
{C5F662EB-991F-438D-BF61-EF87E7371C04} = {F0C9A8CB-231B-45E0-B91B-4FEF7EF47197}
|
||||
{ECF3A7A3-2363-4A38-BC78-8FF9A8564603} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
|
||||
{53C870AE-0249-4485-AE63-F8A16EA4BCB4} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
|
||||
{E4B8B8E6-FAE7-43BA-9A51-33A3CD9FB825} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
|
||||
{C102AB3A-377E-4753-AFA7-C13250D7DF00} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
|
||||
{0DE1D254-0BD2-4D98-B939-5440BE5EB552} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
|
||||
{C1911F84-6FDB-4DEC-8938-69B2E3901CC4} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
|
||||
{A8E68E17-4EBF-4E4C-8272-B489329A68BF} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
|
||||
{5FAFD46E-6B98-4C75-B1EB-085AA18F15FD} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
|
||||
{AC4295F2-AB2F-4137-99EF-80FA5C83896B} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
|
||||
{9DA9AED3-9572-4378-A2A6-4D792D67ADDC} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
|
||||
{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
|
||||
{0947E6C0-6371-4483-B0ED-191FB5073151} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C49B2D3E-6818-4E28-91B7-6E4E7E264BBB}
|
||||
|
||||
@@ -1,270 +0,0 @@
|
||||
#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 System.Diagnostics;
|
||||
|
||||
using ThingsGateway.Foundation.Core;
|
||||
|
||||
namespace ThingsGateway.Upgrade
|
||||
{
|
||||
/// <summary>
|
||||
/// StartCommand.txt 中配置启动主程序的指令,比如
|
||||
/// 如果是直接启动:ThingsGateway.Web.Entry.exe
|
||||
/// 如果是WindowsService:Net Start ThingsGateway
|
||||
/// 如果是其他部署(linux,pm2等等),填写对应的启动命令
|
||||
/// </summary>
|
||||
internal class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
//Thread.Sleep(15000);
|
||||
Thread.Sleep(5000);
|
||||
var path = args[0];
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
var data = DirectoryUtility.GetDirectories(path);
|
||||
if (data.Length == 0)
|
||||
{
|
||||
ConsleError($"目录{path}下不存在文件");
|
||||
}
|
||||
else
|
||||
{
|
||||
var oldFolder = $"{AppContext.BaseDirectory}FileTemp/ThingsGatewayOld/{DateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}";
|
||||
try
|
||||
{
|
||||
|
||||
//复制原文件,错误时可恢复
|
||||
ConsleInfo($"正在备份原文件");
|
||||
CopyDirectory(AppContext.BaseDirectory, oldFolder, new[] { "logs", "FileTemp" }, new[] { "ThingsGateway.Upgrade" });
|
||||
ConsleInfo($"备份原文件成功");
|
||||
|
||||
//停止主程序进程
|
||||
|
||||
string filePath = $"{AppContext.BaseDirectory}ThingsGateway.Web.Entry";
|
||||
// 查找正在运行的进程
|
||||
var process = Process.GetProcesses().Where(p =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (p.ProcessName == "ThingsGateway.Web.Entry")
|
||||
{
|
||||
return (Path.GetDirectoryName(p.MainModule.FileName) + Path.DirectorySeparatorChar).Equals(AppContext.BaseDirectory, StringComparison.OrdinalIgnoreCase);
|
||||
//return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false; // 进程访问被拒绝或没有主模块
|
||||
}
|
||||
})?.FirstOrDefault();
|
||||
if (process != null)
|
||||
{
|
||||
var exit = process.WaitForExit(300000);
|
||||
if (!exit)
|
||||
{
|
||||
ConsleError("无法终止主程序,更新过程停止");
|
||||
|
||||
Recovery(oldFolder);
|
||||
|
||||
Directory.Delete(oldFolder, true);
|
||||
Directory.Delete(path, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
//程序已退出
|
||||
|
||||
//复制文件到主程序文件夹
|
||||
ConsleInfo($"正在复制文件到主程序文件夹");
|
||||
CopyDirectory(path, AppContext.BaseDirectory, new[] { "logs", "FileTemp" }, new[] { "ThingsGateway.Upgrade" });
|
||||
ConsleInfo($"复制文件到主程序文件夹成功");
|
||||
|
||||
//尝试启动
|
||||
var dataString = FileUtil.ReadFile($"{AppContext.BaseDirectory}StartCommand.txt");//读取文件
|
||||
var startCommand = dataString;
|
||||
StartCommand(startCommand);
|
||||
|
||||
|
||||
Thread.Sleep(5000);
|
||||
// 查找正在运行的进程
|
||||
var process1 = Process.GetProcesses().Where(p =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (p.ProcessName == "ThingsGateway.Web.Entry")
|
||||
{
|
||||
return (Path.GetDirectoryName(p.MainModule.FileName) + Path.DirectorySeparatorChar).Equals(AppContext.BaseDirectory, StringComparison.OrdinalIgnoreCase);
|
||||
//return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false; // 进程访问被拒绝或没有主模块
|
||||
}
|
||||
})?.FirstOrDefault();
|
||||
if (process1 != null)
|
||||
{
|
||||
//代表启动正常
|
||||
ConsleInfo("更新成功");
|
||||
Directory.Delete(oldFolder, true);
|
||||
Directory.Delete(path, true);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
//恢复原文件
|
||||
Recovery(oldFolder);
|
||||
Directory.Delete(oldFolder, true);
|
||||
|
||||
Directory.Delete(path, true);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ConsleError(ex.ToString());
|
||||
|
||||
//恢复原文件
|
||||
Recovery(oldFolder);
|
||||
Directory.Delete(oldFolder, true);
|
||||
Directory.Delete(path, true);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ConsleError($"不存在目录{path}");
|
||||
//尝试启动
|
||||
var dataString1 = FileUtil.ReadFile($"{AppContext.BaseDirectory}StartCommand.txt");//读取文件
|
||||
var startCommand1 = dataString1;
|
||||
StartCommand(startCommand1);
|
||||
|
||||
}
|
||||
|
||||
Thread.Sleep(10000);
|
||||
Console.ReadLine();
|
||||
}
|
||||
|
||||
private static void Recovery(string oldFolder)
|
||||
{
|
||||
ConsleInfo("更新失败,恢复原文件");
|
||||
CopyDirectory(oldFolder, AppContext.BaseDirectory, new[] { "logs", "FileTemp" }, new[] { "ThingsGateway.Upgrade" });
|
||||
//尝试启动
|
||||
var dataString1 = FileUtil.ReadFile($"{AppContext.BaseDirectory}StartCommand.txt");//读取文件
|
||||
var startCommand1 = dataString1;
|
||||
StartCommand(startCommand1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 复制文件夹及文件
|
||||
/// </summary>
|
||||
/// <param name="sourceFolder">原文件路径</param>
|
||||
/// <param name="destFolder">目标文件路径</param>
|
||||
/// <param name="ignoreFolder">忽略文件夹</param>
|
||||
/// <param name="ignoreFiles">忽略文件</param>
|
||||
/// <returns></returns>
|
||||
public static void CopyDirectory(string sourceFolder, string destFolder, string[] ignoreFolder, string[] ignoreFiles)
|
||||
{
|
||||
//如果目标路径不存在,则创建目标路径
|
||||
if (!Directory.Exists(destFolder))
|
||||
{
|
||||
Directory.CreateDirectory(destFolder);
|
||||
}
|
||||
//得到原文件根目录下的所有文件
|
||||
var files = Directory.GetFiles(sourceFolder);
|
||||
foreach (var file in files)
|
||||
{
|
||||
if (ignoreFiles.Contains(Path.GetFileNameWithoutExtension(file)))
|
||||
{ continue; }
|
||||
var name = Path.GetFileName(file);
|
||||
var dest = Path.Combine(destFolder, name);
|
||||
File.Copy(file, dest, true);//复制文件
|
||||
}
|
||||
//得到原文件根目录下的所有文件夹
|
||||
var folders = Directory.GetDirectories(sourceFolder);
|
||||
foreach (var folder in folders)
|
||||
{
|
||||
if (ignoreFolder.Contains(Path.GetFileName(folder)))
|
||||
{ continue; }
|
||||
var name = Path.GetFileName(folder);
|
||||
var dest = Path.Combine(destFolder, name);
|
||||
CopyDirectory(folder, dest, ignoreFolder, ignoreFiles);//构建目标路径,递归复制文件
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void ConsleInfo(string str)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Green;
|
||||
Console.WriteLine(str);
|
||||
}
|
||||
|
||||
public static void ConsleError(string str)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine(str);
|
||||
}
|
||||
|
||||
public static void StartCommand(string command)
|
||||
{
|
||||
// 创建进程对象
|
||||
Process process = new Process();
|
||||
// 设置进程启动信息
|
||||
process.StartInfo.FileName = GetCommandInterpreter(); // 获取当前平台的命令解释器
|
||||
process.StartInfo.Arguments = GetCommandArguments(command); // 获取命令行参数
|
||||
process.StartInfo.UseShellExecute = true;
|
||||
process.StartInfo.WorkingDirectory = AppContext.BaseDirectory;
|
||||
// 启动进程
|
||||
process.Start();
|
||||
}
|
||||
|
||||
// 获取当前平台的命令解释器
|
||||
static string GetCommandInterpreter()
|
||||
{
|
||||
if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows))
|
||||
{
|
||||
return "cmd.exe";
|
||||
}
|
||||
else if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Linux))
|
||||
{
|
||||
return "/bin/bash";
|
||||
}
|
||||
else if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.OSX))
|
||||
{
|
||||
return "/bin/bash";
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException("该平台不支持执行命令行。");
|
||||
}
|
||||
|
||||
// 获取命令行参数
|
||||
static string GetCommandArguments(string command)
|
||||
{
|
||||
if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows))
|
||||
{
|
||||
return $"/c {command}";
|
||||
}
|
||||
else // Linux 或 macOS
|
||||
{
|
||||
return $"-c \"{command}\"";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"profiles": {
|
||||
"ThingsGateway.Upgrade": {
|
||||
"commandName": "Project",
|
||||
"commandLineArgs": "E:\\Tg\\ThingsGateway\\ThingsGateway-DEV\\framework\\Web\\ThingsGateway.Web.Entry\\bin\\Debug\\net6.0\\FileTemp\\tcp---127.0.0.1-7400-"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
Net Start ThingsGateway
|
||||
@@ -1,32 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command=" set dir="$(SolutionDir)Web\ThingsGateway.Web.Entry\bin\$(Configuration)\$(TargetFramework)\"
 if not exist %25dir%25 md %25dir%25 
copy "$(TargetDir)*" %25dir%25


" />
|
||||
</Target>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="StartCommand.txt" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\..\Foundation\ThingsGateway.Foundation\Foundation\Utils\FileUtil.cs" Link="FileUtil.cs" />
|
||||
<Compile Include="..\..\Foundation\ThingsGateway.Foundation\TouchSocket\Core\Extensions\DateTimeExtensions.cs" Link="DateTimeExtensions.cs" />
|
||||
<Compile Include="..\..\Foundation\ThingsGateway.Foundation\TouchSocket\Core\IO\DirectoryUtility.cs" Link="DirectoryUtility.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="StartCommand.txt">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,26 +0,0 @@
|
||||
@*
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
*@
|
||||
|
||||
@namespace ThingsGateway.UpgradeManger
|
||||
|
||||
<Router AppAssembly="@typeof(App).Assembly">
|
||||
<Found Context="routeData">
|
||||
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
|
||||
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
|
||||
</Found>
|
||||
<NotFound>
|
||||
<LayoutView Layout="@typeof(MainLayout)">
|
||||
<p role="alert">Sorry, there's nothing at this address.</p>
|
||||
</LayoutView>
|
||||
</NotFound>
|
||||
</Router>
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
global using System;
|
||||
global using System.Collections.Generic;
|
||||
global using System.IO;
|
||||
global using System.Linq;
|
||||
global using System.Threading;
|
||||
global using System.Threading.Tasks;
|
||||
|
||||
global using ThingsGateway.Components;
|
||||
global using ThingsGateway.Foundation.Core;
|
||||
global using ThingsGateway.Foundation.Rpc;
|
||||
global using ThingsGateway.Foundation.Sockets;
|
||||
@@ -1,11 +0,0 @@
|
||||
[
|
||||
{
|
||||
"Href": "/index",
|
||||
"Title": "首页"
|
||||
},
|
||||
{
|
||||
"Title": "更新管理",
|
||||
"Href": "/UpgradeManger"
|
||||
}
|
||||
|
||||
]
|
||||
@@ -1,36 +0,0 @@
|
||||
@*
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
*@
|
||||
|
||||
@page "/"
|
||||
@layout BaseLayout
|
||||
@inject NavigationManager NavigationManager
|
||||
@namespace ThingsGateway.UpgradeManger
|
||||
@using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
@code {
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="firstRender"></param>
|
||||
/// <returns></returns>
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
NavigationManager.NavigateTo("index");
|
||||
}
|
||||
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
@*
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
*@
|
||||
|
||||
@page "/index"
|
||||
|
||||
<div class="ml-2">
|
||||
<div class="my-6 ">
|
||||
<MLabel Class="text-h3" Color="primary">ThingsGateway</MLabel>
|
||||
</div>
|
||||
<div>
|
||||
<strong class="text--lighten-1 text-h5 my-1">文档</strong>
|
||||
</div>
|
||||
<div class="my-2 ml-4">
|
||||
<PCopyableText>
|
||||
https://diego2098.gitee.io/thingsgateway-docs/
|
||||
</PCopyableText>
|
||||
</div>
|
||||
<div>
|
||||
<strong class="text--lighten-1 text-h5 my-1">协议</strong>
|
||||
</div>
|
||||
<div class="my-2 ml-4">
|
||||
<PCopyableText Text="https://gitee.com/diego2098/ThingsGateway/blob/master/LICENSE.zh">
|
||||
Apache-2.0开源协议
|
||||
</PCopyableText>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<strong class="text--lighten-1 text-h5 my-1">赞助</strong>
|
||||
</div>
|
||||
<div class="my-2 ml-4">
|
||||
<PCopyableText Text="https://diego2098.gitee.io/thingsgateway-docs/docs/donate">
|
||||
ThingsGateway赞助途径
|
||||
</PCopyableText>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<strong class="text--lighten-1 text-h5 my-1">社区</strong>
|
||||
</div>
|
||||
<div class="my-2 ml-4">
|
||||
<PCopyableText Text="605534569">
|
||||
QQ群:605534569
|
||||
</PCopyableText>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,262 +0,0 @@
|
||||
@*
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
*@
|
||||
|
||||
@page "/UpgradeManger"
|
||||
@namespace ThingsGateway.UpgradeManger
|
||||
@using System.Linq.Expressions;
|
||||
@using BlazorComponent;
|
||||
|
||||
@using Mapster;
|
||||
@using Masa.Blazor.Presets;
|
||||
@using System.IO;
|
||||
@using Masa.Blazor;
|
||||
@using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
@inherits BaseComponentBase
|
||||
|
||||
@inject NavigationManager NavigationManager
|
||||
@layout MainLayout
|
||||
<MRow NoGutters>
|
||||
<MCol Md=@(IsShowTreeView?2:0)>
|
||||
<MSheet Show=IsShowTreeView Style=@($"height: calc(100vh - {BlazorResourceConst.DefaultHeight}px);border-radius:0px;")>
|
||||
<MCardTitle Class="text-body-2">
|
||||
当前已连接的客户端
|
||||
</MCardTitle>
|
||||
|
||||
<MVirtualScroll Context="item" Class="my-2" Height=@($"calc(100vh - {BlazorResourceConst.DefaultHeight+100}px)") OverscanCount=2 ItemSize="60" Items="TcpDmtpSocketClients">
|
||||
|
||||
<ItemContent>
|
||||
|
||||
<MListItem OnClick=@(()=>ChoiceTcpDmtpSocketClient(item))>
|
||||
<MListItemContent>
|
||||
<MListItemTitle>
|
||||
<div class="mt-1 d-flex align-center justify-space-between" title=@($"{item.GetIPPort()} - {item.Id}")>
|
||||
<span>@($"{item.GetIPPort()} - {item.Id}")</span>
|
||||
</div>
|
||||
</MListItemTitle>
|
||||
</MListItemContent>
|
||||
|
||||
</MListItem>
|
||||
|
||||
<MDivider></MDivider>
|
||||
|
||||
|
||||
</ItemContent>
|
||||
</MVirtualScroll>
|
||||
|
||||
|
||||
</MSheet>
|
||||
</MCol>
|
||||
<MCol Md=@(IsShowTreeView?10:12)>
|
||||
<MButton Class="mx-1" OnClick=@(() =>
|
||||
{
|
||||
IsShowTreeView=!IsShowTreeView;
|
||||
}
|
||||
) Color="primary" Icon>
|
||||
<MIcon>mdi-menu</MIcon>
|
||||
</MButton>
|
||||
<MSheet Rounded="false" Class="pa-2" Style="width:100%">
|
||||
<MRow Class="my-1" Justify="JustifyTypes.Start" Align="AlignTypes.Start" NoGutters>
|
||||
|
||||
<MCol Md="5">
|
||||
@if (TcpDmtpSocketClient != null && GatewayInfo != null)
|
||||
{
|
||||
<MSheet Class="ml-4">
|
||||
<MDescriptions Title="当前选择的网关" Bordered="true">
|
||||
<ActionsContent>
|
||||
<MButton Class="text-capitalize mr-1" Color="primary" OnClick="()=>ChoiceTcpDmtpSocketClient(TcpDmtpSocketClient)">
|
||||
刷新
|
||||
</MButton>
|
||||
</ActionsContent>
|
||||
<ChildContent>
|
||||
<MDescriptionsItem Label=连接信息 Span=3>@($"{TcpDmtpSocketClient.GetIPPort()} - {TcpDmtpSocketClient.Id}")</MDescriptionsItem>
|
||||
<MDescriptionsItem Label=连接状态 Span=3 Class=@(!TcpDmtpSocketClient.CanSend?"red--text":"green--text")>@TcpDmtpSocketClient.CanSend</MDescriptionsItem>
|
||||
<MDescriptionsItem Label=更新时间 Span=3>@GatewayInfo.UpdateTime</MDescriptionsItem>
|
||||
<MDescriptionsItem Label=软件版本 Span=3>@GatewayInfo.Version</MDescriptionsItem>
|
||||
<MDescriptionsItem Label=采集设备数量 Span=3>@GatewayInfo.CollectDeviceCount</MDescriptionsItem>
|
||||
<MDescriptionsItem Label=上传设备数量 Span=3>@GatewayInfo.UploadDeviceCount</MDescriptionsItem>
|
||||
<MDescriptionsItem Label=变量数量 Span=3>@GatewayInfo.VariableCount</MDescriptionsItem>
|
||||
</ChildContent>
|
||||
</MDescriptions>
|
||||
</MSheet>
|
||||
|
||||
<MTabs @bind-Value="tab" Class="ma-2">
|
||||
<MTab Value=1> 配置更新 </MTab>
|
||||
<MTab Value=2> 软件更新 </MTab>
|
||||
</MTabs>
|
||||
|
||||
<MTabsItems Value="tab">
|
||||
<MTabItem Value="1">
|
||||
@if (tab == 1)
|
||||
{
|
||||
<MContainer>
|
||||
|
||||
<MRow Dense>
|
||||
|
||||
<MCol Cols="12" Md="12">
|
||||
<div class="m-descriptions-header__title my-2">
|
||||
导出配置信息
|
||||
</div>
|
||||
</MCol>
|
||||
|
||||
|
||||
<MCol Cols="12" Md="12">
|
||||
|
||||
<MButton Color="primary" Loading=isUploadLoading Disabled=disabled Class="ma-2" OnClick=@(()=>ExcelUpload())>
|
||||
导出网关配置信息
|
||||
</MButton>
|
||||
</MCol>
|
||||
<MCol Cols="12" Md="12">
|
||||
|
||||
<MButton Color="primary" Loading=isUploadLoading Disabled=disabled Class="ma-2" OnClick=@(()=>DBUpload())>
|
||||
导出网关配置数据库(SQLITE)
|
||||
</MButton>
|
||||
</MCol>
|
||||
|
||||
</MRow>
|
||||
|
||||
<MDivider></MDivider>
|
||||
|
||||
<MRow Dense>
|
||||
|
||||
<MCol Cols="12" Md="12">
|
||||
<div class="m-descriptions-header__title my-2">
|
||||
更新网关配置信息
|
||||
</div>
|
||||
</MCol>
|
||||
|
||||
<MCol Cols="12" Md="12">
|
||||
<MFileInput Label="采集设备Excel" HideDetails=@("true") @bind-Value="_importCollectDevicesFile" Style="width:90%;" ShowSize></MFileInput>
|
||||
</MCol>
|
||||
<MCol Cols="12" Md="12">
|
||||
<MSwitch Label=删除后更新 HideDetails=@("true") @bind-Value=@IsCollectDevicesFullUp />
|
||||
</MCol>
|
||||
|
||||
<MCol Cols="12" Md="12">
|
||||
<MFileInput Label="上传设备Excel" HideDetails=@("true") @bind-Value="_importUploadDevicesFile" Style="width:90%;" ShowSize></MFileInput>
|
||||
</MCol>
|
||||
|
||||
<MCol Cols="12" Md="12">
|
||||
<MSwitch Label=删除后更新 HideDetails=@("true") @bind-Value=@IsUploadDevicesFullUp />
|
||||
</MCol>
|
||||
|
||||
|
||||
<MCol Cols="12" Md="12">
|
||||
<MFileInput Label="采集变量Excel" HideDetails=@("true") @bind-Value="_importDeviceVariablesFile" Style="width:90%;" ShowSize></MFileInput>
|
||||
</MCol>
|
||||
|
||||
<MCol Cols="12" Md="12">
|
||||
<MSwitch Label=删除后更新 HideDetails=@("true") @bind-Value=@IsDeviceVariablesFullUp />
|
||||
</MCol>
|
||||
|
||||
<MCol Cols="12" Md="12">
|
||||
<MFileInput Label="内存变量Excel" HideDetails=@("true") @bind-Value="_importMemoryVariablesFile" Style="width:90%;" ShowSize></MFileInput>
|
||||
</MCol>
|
||||
|
||||
<MCol Cols="12" Md="12">
|
||||
<MSwitch Label=删除后更新 HideDetails=@("true") @bind-Value=@IsMemoryVariablesFullUp />
|
||||
</MCol>
|
||||
|
||||
|
||||
<MCol Cols="12" Md="12">
|
||||
|
||||
<MButton Loading=isUploadLoading Disabled=disabled Class="ma-2" Color="primary"
|
||||
OnClick=@(()=>ExcelDown())>
|
||||
推送Excel文件
|
||||
</MButton>
|
||||
</MCol>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</MRow>
|
||||
|
||||
<MDivider></MDivider>
|
||||
|
||||
<MRow Dense>
|
||||
|
||||
<MCol Cols="12" Md="12">
|
||||
<div class="m-descriptions-header__title my-2">
|
||||
重启
|
||||
</div>
|
||||
</MCol>
|
||||
|
||||
|
||||
<MCol Cols="12" Md="12">
|
||||
|
||||
<MButton Color="primary" Loading=isUploadLoading Disabled=disabled Class="ma-2" OnClick=@(()=>DBRestart())>
|
||||
重启网关运行态
|
||||
</MButton>
|
||||
</MCol>
|
||||
<MCol Cols="12" Md="12">
|
||||
|
||||
</MCol>
|
||||
|
||||
</MRow>
|
||||
|
||||
</MContainer>
|
||||
|
||||
}
|
||||
</MTabItem>
|
||||
|
||||
<MTabItem Value="2">
|
||||
@if (tab == 2)
|
||||
{
|
||||
|
||||
<MCol Cols="12" Md="12">
|
||||
|
||||
<MButton Loading=isUploadLoading Disabled=disabled Class="ma-2" Color="primary"
|
||||
OnClick=@(()=>FileDown())>
|
||||
推送文件
|
||||
</MButton>
|
||||
</MCol>
|
||||
|
||||
<MCol Cols="12" Md="12">
|
||||
|
||||
<MButton Loading=isUploadLoading Disabled=disabled Class="ma-2" Color="primary"
|
||||
OnClick=@(()=>FileRestart())>
|
||||
重启更新
|
||||
</MButton>
|
||||
</MCol>
|
||||
|
||||
|
||||
}
|
||||
</MTabItem>
|
||||
|
||||
|
||||
</MTabsItems>
|
||||
|
||||
}
|
||||
|
||||
</MCol>
|
||||
|
||||
<MCol Md="7">
|
||||
<MCard Style="overflow-y:auto;width:100%" Elevation="0" Flat Class="ml-4">
|
||||
<ConsoleTxt Messages="UpgradeManger.Messages" Height=600></ConsoleTxt>
|
||||
</MCard>
|
||||
</MCol>
|
||||
|
||||
</MRow>
|
||||
|
||||
</MSheet>
|
||||
|
||||
</MCol>
|
||||
|
||||
</MRow>
|
||||
@code {
|
||||
StringNumber tab;
|
||||
bool IsShowTreeView = true;
|
||||
|
||||
}
|
||||
@@ -1,324 +0,0 @@
|
||||
#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 BlazorComponent;
|
||||
|
||||
using Masa.Blazor;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.JSInterop;
|
||||
|
||||
using ThingsGateway.Core;
|
||||
using ThingsGateway.Foundation.Dmtp;
|
||||
using ThingsGateway.Foundation.Dmtp.Rpc;
|
||||
|
||||
namespace ThingsGateway.UpgradeManger;
|
||||
|
||||
/// <summary>
|
||||
/// UpgradeManger
|
||||
/// </summary>
|
||||
public partial class UpgradeMangerPage
|
||||
{
|
||||
readonly PeriodicTimer _periodicTimer = new(TimeSpan.FromSeconds(5));
|
||||
IBrowserFile _importCollectDevicesFile;
|
||||
|
||||
IBrowserFile _importDeviceVariablesFile;
|
||||
IBrowserFile _importMemoryVariablesFile;
|
||||
|
||||
IBrowserFile _importUploadDevicesFile;
|
||||
|
||||
private bool IsCollectDevicesFullUp;
|
||||
|
||||
private bool IsDeviceVariablesFullUp;
|
||||
private bool IsMemoryVariablesFullUp;
|
||||
|
||||
private bool isUploadLoading;
|
||||
|
||||
|
||||
private bool IsUploadDevicesFullUp;
|
||||
|
||||
private IJSObjectReference JSObjectReference;
|
||||
|
||||
[Inject]
|
||||
IJSRuntime JSRuntime { get; set; }
|
||||
|
||||
List<TcpDmtpSocketClient> TcpDmtpSocketClients { get; set; }
|
||||
|
||||
[Inject]
|
||||
UpgradeManger UpgradeManger { get; set; }
|
||||
/// <inheritdoc/>
|
||||
public override void Dispose()
|
||||
{
|
||||
_periodicTimer?.Dispose();
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_ = RunTimerAsync();
|
||||
base.OnInitialized();
|
||||
}
|
||||
bool disabled => TcpDmtpSocketClient?.CanSend != true;
|
||||
GatewayInfo GatewayInfo;
|
||||
TcpDmtpSocketClient TcpDmtpSocketClient;
|
||||
GatewayExcel GatewayExcel;
|
||||
|
||||
|
||||
async Task ExcelUpload()
|
||||
{
|
||||
try
|
||||
{
|
||||
isUploadLoading = true;
|
||||
|
||||
GatewayExcel = await TcpDmtpSocketClient.GetDmtpRpcActor().InvokeTAsync<GatewayExcel>("GetGatewayExcelAsync", InvokeOption.WaitInvoke);
|
||||
|
||||
if (GatewayExcel.CollectDevice?.Length > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
GatewayExcel.CollectDevice.Seek(0, SeekOrigin.Begin);
|
||||
using var streamRef = new DotNetStreamReference(stream: GatewayExcel.CollectDevice);
|
||||
JSObjectReference ??= await JSRuntime.LoadModuleAsync("js/downloadFileFromStream");
|
||||
await JSObjectReference.InvokeVoidAsync("downloadFileFromStream", $"{TcpDmtpSocketClient.GetIPPort()}采集设备表导出{DateTimeExtensions.CurrentDateTime.ToString("yyyy-MM-dd HH-mm-ss-fff zz")}.xlsx", streamRef);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UpgradeManger.LogMessage.LogWarning(ex, "采集设备表导出失败");
|
||||
}
|
||||
|
||||
}
|
||||
if (GatewayExcel.UploadDevice?.Length > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
GatewayExcel.UploadDevice.Seek(0, SeekOrigin.Begin);
|
||||
using var streamRef = new DotNetStreamReference(stream: GatewayExcel.UploadDevice);
|
||||
JSObjectReference ??= await JSRuntime.LoadModuleAsync("js/downloadFileFromStream");
|
||||
await JSObjectReference.InvokeVoidAsync("downloadFileFromStream", $"{TcpDmtpSocketClient.GetIPPort()}上传设备表导出{DateTimeExtensions.CurrentDateTime.ToString("yyyy-MM-dd HH-mm-ss-fff zz")}.xlsx", streamRef);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UpgradeManger.LogMessage.LogWarning(ex, "上传设备表导出失败");
|
||||
}
|
||||
|
||||
}
|
||||
if (GatewayExcel.MemoryVariable?.Length > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
GatewayExcel.MemoryVariable.Seek(0, SeekOrigin.Begin);
|
||||
using var streamRef = new DotNetStreamReference(stream: GatewayExcel.MemoryVariable);
|
||||
JSObjectReference ??= await JSRuntime.LoadModuleAsync("js/downloadFileFromStream");
|
||||
await JSObjectReference.InvokeVoidAsync("downloadFileFromStream", $"{TcpDmtpSocketClient.GetIPPort()}内存变量表导出{DateTimeExtensions.CurrentDateTime.ToString("yyyy-MM-dd HH-mm-ss-fff zz")}.xlsx", streamRef);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UpgradeManger.LogMessage.LogWarning(ex, "内存变量表导出失败");
|
||||
}
|
||||
|
||||
}
|
||||
if (GatewayExcel.DeviceVariable?.Length > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
GatewayExcel.DeviceVariable.Seek(0, SeekOrigin.Begin);
|
||||
using var streamRef = new DotNetStreamReference(stream: GatewayExcel.DeviceVariable);
|
||||
JSObjectReference ??= await JSRuntime.LoadModuleAsync("js/downloadFileFromStream");
|
||||
await JSObjectReference.InvokeVoidAsync("downloadFileFromStream", $"{TcpDmtpSocketClient.GetIPPort()}采集变量表导出{DateTimeExtensions.CurrentDateTime.ToString("yyyy-MM-dd HH-mm-ss-fff zz")}.xlsx", streamRef);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UpgradeManger.LogMessage.LogWarning(ex, "采集变量表导出失败");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
await PopupService.EnqueueSnackbarAsync("上传成功", AlertTypes.Success);
|
||||
}
|
||||
finally { isUploadLoading = false; }
|
||||
|
||||
}
|
||||
|
||||
async Task DBUpload()
|
||||
{
|
||||
try
|
||||
{
|
||||
isUploadLoading = true;
|
||||
await UpgradeManger.DBUpload(TcpDmtpSocketClient);
|
||||
|
||||
}
|
||||
finally { isUploadLoading = false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 下发子网关配置
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task ExcelDown()
|
||||
{
|
||||
try
|
||||
{
|
||||
isUploadLoading = true;
|
||||
GatewayExcel gatewayExcel = new();
|
||||
if (_importCollectDevicesFile != null)
|
||||
{
|
||||
using var fs1 = new MemoryStream();
|
||||
using var stream1 = _importCollectDevicesFile.OpenReadStream(512000000);
|
||||
await stream1.CopyToAsync(fs1);
|
||||
fs1.Seek(0, SeekOrigin.Begin);
|
||||
gatewayExcel.CollectDevice = fs1;
|
||||
}
|
||||
if (_importUploadDevicesFile != null)
|
||||
{
|
||||
|
||||
using var fs2 = new MemoryStream();
|
||||
using var stream2 = _importUploadDevicesFile.OpenReadStream(512000000);
|
||||
await stream2.CopyToAsync(fs2);
|
||||
fs2.Seek(0, SeekOrigin.Begin);
|
||||
gatewayExcel.UploadDevice = fs2;
|
||||
}
|
||||
if (_importDeviceVariablesFile != null)
|
||||
{
|
||||
using var fs3 = new MemoryStream();
|
||||
using var stream3 = _importDeviceVariablesFile.OpenReadStream(512000000);
|
||||
await stream3.CopyToAsync(fs3);
|
||||
fs3.Seek(0, SeekOrigin.Begin);
|
||||
gatewayExcel.DeviceVariable = fs3;
|
||||
}
|
||||
if (_importMemoryVariablesFile != null)
|
||||
{
|
||||
using var fs4 = new MemoryStream();
|
||||
using var stream4 = _importMemoryVariablesFile.OpenReadStream(512000000);
|
||||
await stream4.CopyToAsync(fs4);
|
||||
fs4.Seek(0, SeekOrigin.Begin);
|
||||
gatewayExcel.MemoryVariable = fs4;
|
||||
}
|
||||
|
||||
var result = await TcpDmtpSocketClient.GetDmtpRpcActor().InvokeTAsync<OperResult>("SetGatewayExcelAsync", new InvokeOption(30000), gatewayExcel);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
await PopupService.EnqueueSnackbarAsync("更新成功", AlertTypes.Success);
|
||||
}
|
||||
else
|
||||
{
|
||||
await PopupService.EnqueueSnackbarAsync(result.Message, AlertTypes.Error);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await PopupService.EnqueueSnackbarAsync(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
isUploadLoading = false;
|
||||
}
|
||||
|
||||
}
|
||||
private async Task FileDown()
|
||||
{
|
||||
try
|
||||
{
|
||||
isUploadLoading = true;
|
||||
var data = Program.app.MainWindow.ShowOpenFolder("选择更新文件夹", AppContext.BaseDirectory);
|
||||
if (data.Length > 0)
|
||||
{
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
await UpgradeManger.FileDown(TcpDmtpSocketClient, data.FirstOrDefault());
|
||||
}
|
||||
);
|
||||
await PopupService.EnqueueSnackbarAsync("推送成功", AlertTypes.Success);
|
||||
}
|
||||
|
||||
}
|
||||
finally { isUploadLoading = false; }
|
||||
|
||||
}
|
||||
|
||||
private async Task FileRestart()
|
||||
{
|
||||
try
|
||||
{
|
||||
isUploadLoading = true;
|
||||
var confirm = await PopupService.ConfirmAsync("重启", "网关重启,会暂时断开连接,会在约1分钟后重新连接 ?", AlertTypes.Warning);
|
||||
if (confirm)
|
||||
{
|
||||
await TcpDmtpSocketClient.GetDmtpRpcActor().InvokeTAsync<OperResult>("FileRestart", InvokeOption.WaitSend);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
isUploadLoading = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// DBRestart
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task DBRestart()
|
||||
{
|
||||
try
|
||||
{
|
||||
isUploadLoading = true;
|
||||
await TcpDmtpSocketClient.GetDmtpRpcActor().InvokeTAsync<OperResult>("DBRestartAsync", new InvokeOption(30000));
|
||||
await PopupService.EnqueueSnackbarAsync("重启成功", AlertTypes.Success);
|
||||
}
|
||||
finally
|
||||
{
|
||||
isUploadLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async Task ChoiceTcpDmtpSocketClient(TcpDmtpSocketClient item)
|
||||
{
|
||||
TcpDmtpSocketClient = item;
|
||||
GatewayInfo = await item.GetDmtpRpcActor().InvokeTAsync<GatewayInfo>("GetGatewayInfo", InvokeOption.WaitInvoke);
|
||||
}
|
||||
|
||||
private async Task RefreshAsync()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
TcpDmtpSocketClients = UpgradeManger.TcpDmtpService.GetClients().ToList();
|
||||
|
||||
}
|
||||
|
||||
private async Task RunTimerAsync()
|
||||
{
|
||||
await RefreshAsync();
|
||||
while (await _periodicTimer.WaitForNextTickAsync())
|
||||
{
|
||||
try
|
||||
{
|
||||
await RefreshAsync();
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
#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.Extensions.DependencyInjection;
|
||||
|
||||
using Photino.Blazor;
|
||||
|
||||
namespace ThingsGateway.UpgradeManger;
|
||||
|
||||
internal class Program
|
||||
{
|
||||
internal static PhotinoBlazorApp app;
|
||||
[STAThread]
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
System.IO.Directory.SetCurrentDirectory(AppContext.BaseDirectory);
|
||||
|
||||
var appBuilder = PhotinoBlazorAppBuilder.CreateDefault(args);
|
||||
|
||||
appBuilder.RootComponents.Add<App>("#app");
|
||||
appBuilder.Services.ThingsGatewayComponentsConfigureServices();
|
||||
appBuilder.Services.AddSingleton<UpgradeManger>();
|
||||
|
||||
app = appBuilder.Build();
|
||||
app.MainWindow.SetTitle("ThingsGateway.UpgradeManger");
|
||||
app.MainWindow.SetIconFile("wwwroot/favicon.ico");
|
||||
AppDomain.CurrentDomain.UnhandledException += (sender, error) =>
|
||||
{
|
||||
};
|
||||
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
|
||||
var upgradeManger = app.Services.GetService<UpgradeManger>();
|
||||
_ = upgradeManger.ExecuteAsync(cancellationTokenSource.Token);
|
||||
app.Run();
|
||||
|
||||
cancellationTokenSource.Cancel();
|
||||
cancellationTokenSource.Dispose();
|
||||
|
||||
Thread.Sleep(2000);
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
@*
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
*@
|
||||
|
||||
@namespace ThingsGateway.UpgradeManger
|
||||
@inherits LayoutComponentBase
|
||||
|
||||
<CascadingValue Value="IsMobile" Name="IsMobile">
|
||||
<MApp>
|
||||
<MErrorHandler>
|
||||
@Body
|
||||
</MErrorHandler>
|
||||
</MApp>
|
||||
</CascadingValue>
|
||||
|
||||
@code {
|
||||
public bool IsMobile { get; set; }
|
||||
[Inject]
|
||||
public MasaBlazor MasaBlazor { get; set; }
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
MasaBlazor.BreakpointChanged += BreakpointOnOnUpdate;
|
||||
}
|
||||
|
||||
private void BreakpointOnOnUpdate(object sender, BreakpointChangedEventArgs e)
|
||||
{
|
||||
IsMobile = MasaBlazor.Breakpoint.Mobile;
|
||||
if (e.MobileChanged)
|
||||
{
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
@*
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
*@
|
||||
|
||||
@namespace ThingsGateway.UpgradeManger
|
||||
@using System.Text;
|
||||
@inherits LayoutComponentBase
|
||||
@layout BaseLayout
|
||||
|
||||
<PPageTabsProvider>
|
||||
|
||||
<CascadingValue Value="@this" IsFixed>
|
||||
<CascadingValue Value="@Changed" Name="Changed">
|
||||
|
||||
<MNavigationDrawer Color="barcolor" @bind-Value="_drawerOpen" App Width="200">
|
||||
<Logo CONFIG_COPYRIGHT=@CONFIG_COPYRIGHT CONFIG_TITLE=@CONFIG_TITLE HeightInt=@(IsMobile?BlazorResourceConst.AppBarHeight:BlazorResourceConst.AppBarHeight+BlazorResourceConst.PageTabsHeight) />
|
||||
<AppList ClassString="overflow-y-auto" Routable
|
||||
StyleString=@($"height: calc(100vh - {BlazorResourceConst.AppBarHeight+BlazorResourceConst.PageTabsHeight}px);")
|
||||
Items="Navs" />
|
||||
</MNavigationDrawer>
|
||||
|
||||
<MAppBar Color="barcolor" Style=@($"{(!(IsMobile||_drawerOpen!=true)? "left:200px;":"")}") Elevation="1" App Flat ClippedRight Dense ElevateOnScroll
|
||||
MaxHeight="@(BlazorResourceConst.AppBarHeight)" Height="@(BlazorResourceConst.AppBarHeight)">
|
||||
<MButton Class="mr-0" Icon Small=IsMobile OnClick=@(() => _drawerOpen = !_drawerOpen)>
|
||||
<MIcon>mdi-menu</MIcon>
|
||||
</MButton>
|
||||
|
||||
</MAppBar>
|
||||
|
||||
<MMain Style=@($"{(!(IsMobile||_drawerOpen!=true)? "padding-left:200px;":"")}")>
|
||||
<div class="full-width">
|
||||
<PageTabs @ref="_pageTabs" PageTabItems="pageTabItems" />
|
||||
</div>
|
||||
<MDivider Center></MDivider>
|
||||
<MCard Flat Class="overflow-y-auto overflow-x-hidden ma-auto pa-0 rounded-0" Style=@($"height: calc(100vh - {BlazorResourceConst.AppBarHeight+BlazorResourceConst.PageTabsHeight+BlazorResourceConst.FooterHeight}px);")>
|
||||
<PPageContainer PageTabs="@_pageTabs?.PPageTabs">
|
||||
@Body
|
||||
</PPageContainer>
|
||||
</MCard>
|
||||
<MSheet Class="d-flex justify-center align-center rounded-0" Style=@($"height: {BlazorResourceConst.FooterHeight}px;")>
|
||||
<Foter CONFIG_COPYRIGHT=@CONFIG_COPYRIGHT CONFIG_COPYRIGHT_URL=@CONFIG_COPYRIGHT_URL CONFIG_TITLE=@CONFIG_TITLE></Foter>
|
||||
</MSheet>
|
||||
</MMain>
|
||||
</CascadingValue>
|
||||
</CascadingValue>
|
||||
|
||||
</PPageTabsProvider>
|
||||
@code {
|
||||
bool Changed { get; set; }
|
||||
private bool? _drawerOpen = true;
|
||||
|
||||
private PageTabs _pageTabs;
|
||||
|
||||
/// <summary>
|
||||
/// IsMobile
|
||||
/// </summary>
|
||||
[CascadingParameter(Name = "IsMobile")]
|
||||
public bool IsMobile { get; set; }
|
||||
|
||||
}
|
||||
@code {
|
||||
|
||||
private string CONFIG_COPYRIGHT = "Diego";
|
||||
|
||||
private string CONFIG_COPYRIGHT_URL = "https://gitee.com/diego2098/ThingsGateway";
|
||||
|
||||
private string CONFIG_TITLE = "ThingsGateway";
|
||||
}
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
private List<NavItem> Navs { get; set; } = new();
|
||||
private List<PageTabItem> pageTabItems { get; set; } = new();
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
var dataString =FileUtil. ReadFile($"{AppContext.BaseDirectory}Navs.json");//读取文件
|
||||
Navs=dataString.FromJsonString<List<NavItem>>();
|
||||
pageTabItems = Navs.PasePageTabItem();
|
||||
base.OnInitialized();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<ApplicationIcon>wwwroot\favicon.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Photino.Blazor" Version="2.6.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation\ThingsGateway.Foundation.csproj" />
|
||||
<ProjectReference Include="..\..\Web\ThingsGateway.Components\ThingsGateway.Components.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="wwwroot\**">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="Navs.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="UpgradeMangerConfig.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,266 +0,0 @@
|
||||
#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 System.Diagnostics;
|
||||
|
||||
using ThingsGateway.Core;
|
||||
using ThingsGateway.Foundation.Dmtp;
|
||||
using ThingsGateway.Foundation.Dmtp.FileTransfer;
|
||||
using ThingsGateway.Foundation.Dmtp.Rpc;
|
||||
|
||||
namespace ThingsGateway.UpgradeManger;
|
||||
|
||||
/// <summary>
|
||||
/// UpgradeManger
|
||||
/// </summary>
|
||||
public partial class UpgradeManger
|
||||
{
|
||||
/// <summary>
|
||||
/// UpgradeMangerConfig
|
||||
/// </summary>
|
||||
public UpgradeMangerConfig Config;
|
||||
|
||||
/// <summary>
|
||||
/// Messages
|
||||
/// </summary>
|
||||
public ConcurrentLinkedList<(Microsoft.Extensions.Logging.LogLevel level, string message)> Messages = new();
|
||||
|
||||
/// <summary>
|
||||
/// TcpDmtpService
|
||||
/// </summary>
|
||||
public TcpDmtpService TcpDmtpService;
|
||||
/// <summary>
|
||||
/// LogMessage
|
||||
/// </summary>
|
||||
public LoggerGroup LogMessage;
|
||||
/// <inheritdoc/>
|
||||
public async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
LogMessage = new LoggerGroup() { LogLevel = LogLevel.Trace };
|
||||
LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = LogLevel.Trace });
|
||||
|
||||
var dataString = FileUtil.ReadFile($"{AppContext.BaseDirectory}UpgradeMangerConfig.json");//读取文件
|
||||
Config = dataString.FromJsonString<UpgradeMangerConfig>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogError(ex, "程序初始化配置失败");
|
||||
}
|
||||
TcpDmtpService = CreateTcpDmtpService(Config);
|
||||
while (!stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
TcpDmtpService.Start();
|
||||
await Task.Delay(10000, stoppingToken);
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogError(ex);
|
||||
}
|
||||
}
|
||||
TcpDmtpService.Dispose();
|
||||
}
|
||||
|
||||
private TcpDmtpService CreateTcpDmtpService(UpgradeMangerConfig autoUpdateConfig)
|
||||
{
|
||||
var config = new TouchSocketConfig()
|
||||
.SetListenIPHosts(autoUpdateConfig.UpdateServerUri)
|
||||
.SetVerifyToken(autoUpdateConfig.VerifyToken)
|
||||
.ConfigureContainer(a =>
|
||||
{
|
||||
a.AddLogger(LogMessage);
|
||||
a.AddDmtpRouteService();//添加路由策略
|
||||
})
|
||||
.ConfigurePlugins(a =>
|
||||
{
|
||||
a.UseDmtpFileTransfer();//必须添加文件传输插件
|
||||
a.UseDmtpHeartbeat()//使用Dmtp心跳
|
||||
.SetTick(TimeSpan.FromSeconds(3))
|
||||
.SetMaxFailCount(3);
|
||||
a.UseDmtpRpc();
|
||||
});
|
||||
TcpDmtpService service = new TcpDmtpService();
|
||||
service.Connecting = (client, e) =>
|
||||
{
|
||||
service.Logger.Info($"{client.GetIPPort()}:Connecting");
|
||||
return EasyTask.CompletedTask;
|
||||
};//有客户端正在连接
|
||||
service.Connected = (client, e) => { service.Logger.Info($"{client.GetIPPort()}:Connected"); return EasyTask.CompletedTask; };//有客户端连接
|
||||
service.Disconnected = (client, e) => { service.Logger.Info($"{client.GetIPPort()}:Disconnected"); return EasyTask.CompletedTask; };//有客户端断开连接
|
||||
service.Setup(config);
|
||||
return service;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 底层日志输出
|
||||
/// </summary>
|
||||
private void LogOut(ThingsGateway.Foundation.Core.LogLevel logLevel, object source, string message, Exception exception)
|
||||
{
|
||||
Messages.Add(((Microsoft.Extensions.Logging.LogLevel)logLevel,
|
||||
$"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat()} - {message} {exception}"));
|
||||
if (Messages.Count > 2500)
|
||||
{
|
||||
Messages.Clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// DBUpload
|
||||
/// </summary>
|
||||
/// <param name="tcpDmtpSocketClient"></param>
|
||||
/// <returns></returns>
|
||||
public async Task DBUpload(TcpDmtpSocketClient tcpDmtpSocketClient)
|
||||
{
|
||||
var folderPath = $"{AppContext.BaseDirectory}ThingsGatewayDB/";
|
||||
// 检查文件夹是否存在
|
||||
if (!Directory.Exists(folderPath))
|
||||
{
|
||||
Directory.CreateDirectory(folderPath);
|
||||
}
|
||||
|
||||
var metadata = new Metadata();//传递到客户端的元数据
|
||||
metadata.Add(FilePluginUtil.DmtpType, DmtpTypeEnum.GatewayDB.ToString());
|
||||
|
||||
var fileOperator = new FileOperator//实例化本次传输的控制器,用于获取传输进度、速度、状态等。
|
||||
{
|
||||
SavePath = $"{folderPath}/{tcpDmtpSocketClient.IP}-{tcpDmtpSocketClient.Port}ThingsGateway.db",//服务器本地保存路径
|
||||
ResourcePath = string.Empty,//请求客户端文件的资源路径
|
||||
Metadata = metadata,//传递到客户端的元数据
|
||||
Timeout = TimeSpan.FromSeconds(60),//传输超时时长
|
||||
TryCount = 10,//当遇到失败时,尝试次数
|
||||
FileSectionSize = 1024 * 512//分包大小,当网络较差时,应该适当减小该值
|
||||
};
|
||||
|
||||
//此处的作用相当于Timer,定时每秒输出当前的传输进度和速度。
|
||||
var loopAction = LoopAction.CreateLoopAction(-1, 1000, (loop) =>
|
||||
{
|
||||
if (fileOperator.Result.ResultCode != ResultCode.Default)
|
||||
{
|
||||
loop.Dispose();
|
||||
}
|
||||
LogMessage.Info($"进度:{fileOperator.Progress},速度:{fileOperator.Speed() / 1024}kb/s");
|
||||
});
|
||||
|
||||
//此方法会阻塞,直到传输结束,也可以使用PullFileAsync
|
||||
var result = await tcpDmtpSocketClient.GetDmtpFileTransferActor().PullFileAsync(fileOperator);
|
||||
|
||||
loopAction.Run();
|
||||
|
||||
LogMessage.Info($" {result.ResultCode},具体消息:{result.Message}");
|
||||
if (result.ResultCode != ResultCode.Success)
|
||||
throw new Exception(result.Message);
|
||||
OpenFile(folderPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DBUpload
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task FileDown(TcpDmtpSocketClient tcpDmtpSocketClient, string folderPath)
|
||||
{
|
||||
|
||||
string[] files = Directory.GetFiles(folderPath, "", SearchOption.AllDirectories);
|
||||
await files.ParallelForEachAsync(async (file, cancellationToken) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!Path.GetRelativePath(folderPath, file).Contains("FileTemp"))
|
||||
{
|
||||
|
||||
|
||||
var metadata = new Metadata();//传递到客户端的元数据
|
||||
metadata.Add(FilePluginUtil.DmtpType, DmtpTypeEnum.File.ToString());
|
||||
metadata.Add(FilePluginUtil.FileName, Path.GetRelativePath(folderPath, file));
|
||||
|
||||
var fileOperator = new FileOperator//实例化本次传输的控制器,用于获取传输进度、速度、状态等。
|
||||
{
|
||||
SavePath = string.Empty,//客户端本地保存路径
|
||||
ResourcePath = file,//服务器文件的资源路径
|
||||
Metadata = metadata,//传递到客户端的元数据
|
||||
Timeout = TimeSpan.FromSeconds(60),//传输超时时长
|
||||
TryCount = 10,//当遇到失败时,尝试次数
|
||||
FileSectionSize = 1024 * 512//分包大小,当网络较差时,应该适当减小该值
|
||||
};
|
||||
|
||||
//此处的作用相当于Timer,定时每秒输出当前的传输进度和速度。
|
||||
var loopAction = LoopAction.CreateLoopAction(-1, 1000, (loop) =>
|
||||
{
|
||||
if (fileOperator.Result.ResultCode != ResultCode.Default)
|
||||
{
|
||||
loop.Dispose();
|
||||
}
|
||||
LogMessage.Info($"进度:{fileOperator.Progress},速度:{fileOperator.Speed() / 1024}kb/s");
|
||||
});
|
||||
|
||||
//此方法会阻塞,直到传输结束,也可以使用PullFileAsync
|
||||
var result = await tcpDmtpSocketClient.GetDmtpFileTransferActor().PushFileAsync(fileOperator);
|
||||
|
||||
loopAction.Run();
|
||||
LogMessage.Info($" {result.ResultCode},具体消息:{result.Message}");
|
||||
if (result.ResultCode != ResultCode.Success)
|
||||
throw new Exception(result.Message);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex, "传输出错");
|
||||
}
|
||||
}, 10);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 打开指定目录下的文件
|
||||
/// </summary>
|
||||
private static void OpenFile(string folderPath)
|
||||
{
|
||||
|
||||
Process process = new Process();
|
||||
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
process.StartInfo.FileName = "explorer.exe";
|
||||
process.StartInfo.Arguments = folderPath.Replace("/", "\\");
|
||||
}
|
||||
else if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
process.StartInfo.FileName = "open";
|
||||
process.StartInfo.Arguments = folderPath;
|
||||
}
|
||||
else if (OperatingSystem.IsLinux())
|
||||
{
|
||||
process.StartInfo.FileName = "xdg-open";
|
||||
process.StartInfo.Arguments = folderPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException("不支持的操作系统");
|
||||
}
|
||||
|
||||
process.Start();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"UpdateServerUri": "127.0.0.1:7400", //管理服务IP
|
||||
"VerifyToken": "ThingsGateway" //验证Token
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
{
|
||||
"RECORDS": [
|
||||
{
|
||||
"Id": "22222222222222",
|
||||
"Category": "SYS_CONFIGBASEDEFAULT",
|
||||
"ConfigKey": "CONFIG_SWAGGER_NAME",
|
||||
"ConfigValue": "admin",
|
||||
"Remark": "swagger账号",
|
||||
"SortCode": "1",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "22222222222223",
|
||||
"Category": "SYS_CONFIGBASEDEFAULT",
|
||||
"ConfigKey": "CONFIG_SWAGGER_PASSWORD",
|
||||
"ConfigValue": "123456",
|
||||
"Remark": "swagger密码",
|
||||
"SortCode": "2",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "22222222222224",
|
||||
"Category": "SYS_CONFIGBASEDEFAULT",
|
||||
"ConfigKey": "CONFIG_SWAGGERLOGIN_OPEN",
|
||||
"ConfigValue": "false",
|
||||
"Remark": "swagger开启登录",
|
||||
"SortCode": "3",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
|
||||
{
|
||||
"Id": "22222222222226",
|
||||
"Category": "SYS_CONFIGBASEDEFAULT",
|
||||
"ConfigKey": "CONFIG_TITLE",
|
||||
"ConfigValue": "ThingsGateway",
|
||||
"Remark": "标题",
|
||||
"SortCode": "5",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "22222222222228",
|
||||
"Category": "SYS_CONFIGBASEDEFAULT",
|
||||
"ConfigKey": "CONFIG_COPYRIGHT",
|
||||
"ConfigValue": "ThingsGateway ©2023 Diego",
|
||||
"Remark": "系统版权",
|
||||
"SortCode": "6",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "22222222222229",
|
||||
"Category": "SYS_CONFIGBASEDEFAULT",
|
||||
"ConfigKey": "CONFIG_COPYRIGHT_URL",
|
||||
"ConfigValue": "https://gitee.com/diego2098/ThingsGateway",
|
||||
"Remark": "系统版权链接地址",
|
||||
"SortCode": "7",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "22222222222231",
|
||||
"Category": "SYS_CONFIGBASEDEFAULT",
|
||||
"ConfigKey": "CONFIG_PASSWORD",
|
||||
"ConfigValue": "111111",
|
||||
"Remark": "默认用户密码",
|
||||
"SortCode": "8",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "22222222222227",
|
||||
"Category": "SYS_CONFIGBASEDEFAULT",
|
||||
"ConfigKey": "CONFIG_VERIFICAT_EXPIRES",
|
||||
"ConfigValue": "14400",
|
||||
"Remark": "Verificat过期时间(分)",
|
||||
"SortCode": "9",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "22222222222232",
|
||||
"Category": "SYS_CONFIGBASEDEFAULT",
|
||||
"ConfigKey": "CONFIG_SINGLE_OPEN",
|
||||
"ConfigValue": "false",
|
||||
"Remark": "单用户登录开关",
|
||||
"SortCode": "10",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "22222222222230",
|
||||
"Category": "SYS_CONFIGBASEDEFAULT",
|
||||
"ConfigKey": "CONFIG_CAPTCHA_OPEN",
|
||||
"ConfigValue": "true",
|
||||
"Remark": "登录验证码开关",
|
||||
"SortCode": "11",
|
||||
"IsDelete": "false"
|
||||
},
|
||||
{
|
||||
"Id": "22222222222225",
|
||||
"Category": "SYS_CONFIGBASEDEFAULT",
|
||||
"ConfigKey": "CONFIG_REMARK",
|
||||
"ConfigValue": "边缘采集网关",
|
||||
"Remark": "说明",
|
||||
"SortCode": "12",
|
||||
"IsDelete": "false"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"RECORDS": [
|
||||
{
|
||||
"Id": "212725263001001",
|
||||
"Code": "superAdmin",
|
||||
"Name": "超级管理员",
|
||||
"SortCode": "1"
|
||||
},
|
||||
{
|
||||
"Id": "212725263001002",
|
||||
"Code": "admin",
|
||||
"Name": "业务管理员",
|
||||
"SortCode": "2"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
{
|
||||
"RECORDS": [
|
||||
{
|
||||
"Id": "212725263002001",
|
||||
"Account": "superAdmin",
|
||||
"LastLoginDevice": "PC",
|
||||
"LastLoginIp": "0.0.0.1",
|
||||
"LastLoginTime": "2023-03-03 21:18:43.7092169",
|
||||
"LatestLoginDevice": "PC",
|
||||
"LatestLoginIp": "0.0.0.1",
|
||||
"LatestLoginTime": "2023-03-03 21:19:16.1043309",
|
||||
"Password": "7DA385A25A98388E",
|
||||
"SortCode": "1",
|
||||
"UserEnable": "true",
|
||||
"IsDelete": "false",
|
||||
"UpdateTime": "2023-03-03 21:19:16.1202211"
|
||||
},
|
||||
{
|
||||
"Id": "201725263002001",
|
||||
"Account": "admin",
|
||||
"LastLoginDevice": "PC",
|
||||
"LastLoginIp": "0.0.0.1",
|
||||
"LastLoginTime": "2023-03-03 18:20:49.1875384",
|
||||
"LatestLoginDevice": "PC",
|
||||
"LatestLoginIp": "0.0.0.1",
|
||||
"LatestLoginTime": "2023-03-03 18:23:08.6424099",
|
||||
"Password": "7DA385A25A98388E",
|
||||
"SortCode": "2",
|
||||
"UserEnable": "true",
|
||||
"IsDelete": "false",
|
||||
"UpdateTime": "2023-03-03 18:23:08.6727296"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
@*
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
*@
|
||||
|
||||
@page "/admin/role"
|
||||
@using System.Linq.Expressions;
|
||||
@using BlazorComponent;
|
||||
@using Masa.Blazor.Presets;
|
||||
@using Microsoft.AspNetCore.Authorization;
|
||||
@using ThingsGateway.Admin.Application;
|
||||
|
||||
@namespace ThingsGateway.Admin.Blazor
|
||||
@attribute [Authorize]
|
||||
@inject UserResoures UserResoures
|
||||
@inherits BaseComponentBase
|
||||
@layout MainLayout
|
||||
<AppDataTable @ref="_datatable" TItem="SysRole" SearchItem="RolePageInput" AddItem="RoleAddInput" EditItem="RoleEditInput" DescFunc=@(memberInfo=>memberInfo.GetCustomAttribute<SqlSugar.SugarColumn>(true)?.ColumnDescription)
|
||||
SearchModel="@search" IsShowSearchKey
|
||||
QueryCallAsync="QueryCallAsync" AddCallAsync="AddCallAsync"
|
||||
EditCallAsync="EditCallAsync" DeleteCallAsync="DeleteCallAsync"
|
||||
IsShowQueryButton
|
||||
IsShowAddButton=@UserResoures.IsHasButtonWithRole("sysroleadd")
|
||||
IsShowDeleteButton=@UserResoures.IsHasButtonWithRole("sysroledelete")
|
||||
IsShowEditButton=@UserResoures.IsHasButtonWithRole("sysroleedit")>
|
||||
|
||||
<AddTemplate>
|
||||
@GetRenderFragment(context)
|
||||
|
||||
</AddTemplate>
|
||||
|
||||
<EditTemplate>
|
||||
@GetRenderFragment(context)
|
||||
</EditTemplate>
|
||||
|
||||
<ItemColOperTemplate>
|
||||
<MList Dense>
|
||||
@if (@UserResoures.IsHasButtonWithRole("sysroleperresuorce"))
|
||||
{
|
||||
<MListItem OnClick="async()=>
|
||||
{
|
||||
ChoiceRoleId=context.Item.Id;
|
||||
await ResuorceInitAsync();
|
||||
IsShowResuorces=true;
|
||||
}">
|
||||
<MListItemTitle Class="ml-2">资源权限</MListItemTitle>
|
||||
</MListItem>
|
||||
|
||||
}
|
||||
@if (@UserResoures.IsHasButtonWithRole("sysroleperuser"))
|
||||
{
|
||||
<MListItem OnClick="async()=>
|
||||
{
|
||||
ChoiceRoleId=context.Item.Id;
|
||||
await UserInitAsync();
|
||||
IsShowUsers=true;
|
||||
}">
|
||||
<MListItemTitle Class="ml-2">授权用户</MListItemTitle>
|
||||
</MListItem>
|
||||
|
||||
}
|
||||
</MList>
|
||||
</ItemColOperTemplate>
|
||||
|
||||
</AppDataTable>
|
||||
|
||||
<PDrawer @bind-Value="IsShowResuorces" OnCancel="() => IsShowResuorces = false"
|
||||
Title=资源授权
|
||||
Width=@(IsMobile?"100%":"600")
|
||||
MaxWidth="600" OnSave="OnRoleHasResuorcesSaveAsync">
|
||||
@if (IsShowResuorces)
|
||||
{
|
||||
<MSheet Outlined Class="ma-0 pa-2">
|
||||
<MRow Align="AlignTypes.Center">
|
||||
<MCol> <MLabel Class="ml-4 font-weight-black">菜单</MLabel> </MCol>
|
||||
<MDivider Vertical />
|
||||
<MCol> <MLabel Class="ml-4 font-weight-black">按钮</MLabel> </MCol>
|
||||
</MRow>
|
||||
</MSheet>
|
||||
@foreach (var menu in ResTreeSelectors)
|
||||
{
|
||||
<MSheet Outlined Class="ma-0 pa-4">
|
||||
<MRow Align="AlignTypes.Center">
|
||||
<MCol>
|
||||
<MListItem IsActive=@(RoleHasResuorces.Any(it=>it.MenuId==menu.Id))>
|
||||
<ItemContent>
|
||||
<MListItemContent>
|
||||
<MListItemTitle>@menu.Title</MListItemTitle>
|
||||
</MListItemContent>
|
||||
<MListItemAction>
|
||||
<MCheckbox TValue=bool Value="@context.Active" ValueChanged=@(enable=>
|
||||
{
|
||||
if(!enable)
|
||||
RoleHasResuorces.RemoveWhere(it=>it.MenuId==menu.Id);
|
||||
else if(!RoleHasResuorces.Any(it=>it.MenuId==menu.Id))
|
||||
RoleHasResuorces.Add(new() {MenuId=menu.Id});
|
||||
}
|
||||
)></MCheckbox>
|
||||
</MListItemAction>
|
||||
</ItemContent>
|
||||
</MListItem>
|
||||
</MCol>
|
||||
<MDivider Vertical />
|
||||
<MCol>
|
||||
@GetButtonCore(menu)
|
||||
</MCol>
|
||||
|
||||
</MRow>
|
||||
|
||||
</MSheet>
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
</PDrawer>
|
||||
|
||||
<PDrawer @bind-Value="IsShowUsers" OnCancel="() => IsShowUsers = false"
|
||||
Title=授权用户
|
||||
Width=@(IsMobile?"100%":"500")
|
||||
MaxWidth="500" OnSave="OnUsersSaveAsync">
|
||||
|
||||
<MCard Flat Class="ma-0 pa-4">
|
||||
<MCardTitle Class="py-2">
|
||||
<MTextField Dense Style="max-width:200px;" HideDetails=@("auto") Class="my-1 mx-2 ml-6" @bind-Value="SearchKey"
|
||||
Outlined Label=@typeof(SysUser).GetDescription(nameof(SysUser.Account)) />
|
||||
</MCardTitle>
|
||||
<MTreeview Class="my-1" Dense OpenAll TItem="UserSelectorOutput" TKey="UserSelectorOutput" Selectable @bind-Value="UsersChoice"
|
||||
Items="AllUsers" ItemText="r=>r.Account" ItemChildren="r=>null"
|
||||
ItemKey=@(r=>r)>
|
||||
<LabelContent>
|
||||
<span title=@context.Item.Account>
|
||||
@context.Item.Account
|
||||
</span>
|
||||
</LabelContent>
|
||||
</MTreeview>
|
||||
</MCard>
|
||||
|
||||
</PDrawer>
|
||||
|
||||
|
||||
@code {
|
||||
RenderFragment GetButtonCore(RoleGrantResourceMenu menu)
|
||||
{
|
||||
RenderFragment ViewSubMenu = null;
|
||||
|
||||
foreach (var button in menu.Button ?? new())
|
||||
{
|
||||
ViewSubMenu +=
|
||||
@<MListItem Class="ml-6" IsActive=@(RoleHasResuorces.FirstOrDefault(it=>it.MenuId==menu.Id)?.ButtonInfo?.Contains(button.Id)==true)>
|
||||
<ItemContent>
|
||||
<MListItemContent>
|
||||
<MListItemTitle>@button.Title</MListItemTitle>
|
||||
</MListItemContent>
|
||||
<MListItemAction>
|
||||
<MCheckbox TValue=bool Value="@context.Active" ValueChanged=@(a=>
|
||||
{
|
||||
if(!a)
|
||||
{
|
||||
RoleHasResuorces.FirstOrDefault(it=>it.MenuId==menu.Id)?.ButtonInfo?.RemoveWhere(it=>it==button.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !(RoleHasResuorces.FirstOrDefault(it=>it.MenuId==menu.Id)?.ButtonInfo?.Any(it=>it==button.Id)==true))
|
||||
{
|
||||
if(!RoleHasResuorces.Any(it=>it.MenuId==menu.Id))
|
||||
{
|
||||
RoleHasResuorces.Add(new() {MenuId=menu.Id});
|
||||
}
|
||||
RoleHasResuorces.FirstOrDefault(it=>it.MenuId==menu.Id).ButtonInfo.Add(button.Id);
|
||||
}
|
||||
}
|
||||
})></MCheckbox>
|
||||
</MListItemAction>
|
||||
</ItemContent>
|
||||
</MListItem>
|
||||
;
|
||||
}
|
||||
|
||||
return ViewSubMenu;
|
||||
}
|
||||
|
||||
RenderFragment GetRenderFragment(RoleAddInput context)
|
||||
{
|
||||
RenderFragment renderFragment =
|
||||
@<div>
|
||||
<MSubheader Class="mt-4 font-weight-black"> @(context.Description(x => x.Name)) </MSubheader>
|
||||
<MTextField Dense Outlined HideDetails="@("auto")" @bind-Value=@context.Name />
|
||||
|
||||
<MSubheader Class="mt-4 mb-5 font-weight-black">@(context.Description(x => x.SortCode)) </MSubheader>
|
||||
<MSlider @bind-Value=@context.SortCode Class="mb-5" TValue=int ThumbLabel="@("always")" Dense />
|
||||
</div>
|
||||
;
|
||||
return renderFragment;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
#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 Masa.Blazor;
|
||||
using Masa.Blazor.Presets;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
|
||||
|
||||
namespace ThingsGateway.Admin.Blazor;
|
||||
/// <summary>
|
||||
/// 角色页面
|
||||
/// </summary>
|
||||
public partial class Role
|
||||
{
|
||||
private readonly RolePageInput search = new();
|
||||
private IAppDataTable _datatable;
|
||||
private List<UserSelectorOutput> AllUsers;
|
||||
long ChoiceRoleId;
|
||||
bool IsShowResuorces;
|
||||
bool IsShowUsers;
|
||||
List<RoleGrantResourceMenu> ResTreeSelectors = new();
|
||||
List<RelationRoleResuorce> RoleHasResuorces = new();
|
||||
private List<UserSelectorOutput> UsersChoice;
|
||||
|
||||
[CascadingParameter]
|
||||
MainLayout MainLayout { get; set; }
|
||||
|
||||
|
||||
|
||||
private string SearchKey { get; set; }
|
||||
|
||||
private Task AddCallAsync(RoleAddInput input)
|
||||
{
|
||||
return App.GetService<RoleService>().AddAsync(input);
|
||||
}
|
||||
private async Task DeleteCallAsync(IEnumerable<SysRole> sysRoles)
|
||||
{
|
||||
await App.GetService<RoleService>().DeleteAsync(sysRoles.Select(a => a.Id).ToArray());
|
||||
await MainLayout.StateHasChangedAsync();
|
||||
}
|
||||
|
||||
private async Task EditCallAsync(RoleEditInput input)
|
||||
{
|
||||
await App.GetService<RoleService>().EditAsync(input);
|
||||
await MainLayout.StateHasChangedAsync();
|
||||
}
|
||||
private async Task OnRoleHasResuorcesSaveAsync(ModalActionEventArgs args)
|
||||
{
|
||||
try
|
||||
{
|
||||
GrantResourceInput userGrantRoleInput = new();
|
||||
var data = new List<SysResource>();
|
||||
userGrantRoleInput.Id = ChoiceRoleId;
|
||||
userGrantRoleInput.GrantInfoList = RoleHasResuorces;
|
||||
await App.GetService<RoleService>().GrantResourceAsync(userGrantRoleInput);
|
||||
IsShowResuorces = false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
args.Cancel();
|
||||
await PopupService.EnqueueSnackbarAsync(ex, false);
|
||||
}
|
||||
await MainLayout.StateHasChangedAsync();
|
||||
}
|
||||
private async Task OnUsersSaveAsync(ModalActionEventArgs args)
|
||||
{
|
||||
try
|
||||
{
|
||||
GrantUserInput userGrantRoleInput = new();
|
||||
userGrantRoleInput.Id = ChoiceRoleId;
|
||||
userGrantRoleInput.GrantInfoList = UsersChoice.Select(it => it.Id).ToList();
|
||||
await App.GetService<RoleService>().GrantUserAsync(userGrantRoleInput);
|
||||
IsShowUsers = false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
args.Cancel();
|
||||
await PopupService.EnqueueSnackbarAsync(ex, false);
|
||||
}
|
||||
await MainLayout.StateHasChangedAsync();
|
||||
}
|
||||
|
||||
private Task<ISqlSugarPagedList<SysRole>> QueryCallAsync(RolePageInput input)
|
||||
{
|
||||
return App.GetService<RoleService>().PageAsync(input);
|
||||
}
|
||||
|
||||
private async Task ResuorceInitAsync()
|
||||
{
|
||||
ResTreeSelectors = (await App.GetService<ResourceService>().GetRoleGrantResourceMenusAsync());
|
||||
RoleHasResuorces = (await App.GetService<RoleService>().OwnResourceAsync(ChoiceRoleId))?.GrantInfoList;
|
||||
}
|
||||
|
||||
private async Task<List<UserSelectorOutput>> UserInitAsync()
|
||||
{
|
||||
AllUsers = await App.GetService<SysUserService>().UserSelectorAsync(SearchKey);
|
||||
var data = await App.GetService<RoleService>().OwnUserAsync(ChoiceRoleId);
|
||||
UsersChoice = AllUsers.Where(a => data.Contains(a.Id)).ToList();
|
||||
return AllUsers;
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
#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 Masa.Blazor;
|
||||
using Masa.Blazor.Presets;
|
||||
|
||||
namespace ThingsGateway.Admin.Blazor;
|
||||
|
||||
/// <summary>
|
||||
/// 用户界面
|
||||
/// </summary>
|
||||
public partial class User
|
||||
{
|
||||
private readonly UserPageInput search = new();
|
||||
private IAppDataTable _datatable;
|
||||
private List<SysRole> AllRoles;
|
||||
long ChoiceUserId;
|
||||
bool IsShowRoles;
|
||||
List<SysRole> RolesChoice = new();
|
||||
string SearchName;
|
||||
[CascadingParameter]
|
||||
MainLayout MainLayout { get; set; }
|
||||
|
||||
|
||||
private Task AddCallAsync(UserAddInput input)
|
||||
{
|
||||
return App.GetService<SysUserService>().AddAsync(input);
|
||||
}
|
||||
private async Task DeleteCallAsync(IEnumerable<SysUser> users)
|
||||
{
|
||||
await App.GetService<SysUserService>().DeleteAsync(users.Select(a => a.Id).ToArray());
|
||||
await MainLayout.StateHasChangedAsync();
|
||||
}
|
||||
|
||||
private async Task EditCallAsync(UserEditInput users)
|
||||
{
|
||||
await App.GetService<SysUserService>().EditAsync(users);
|
||||
await MainLayout.StateHasChangedAsync();
|
||||
}
|
||||
|
||||
private async Task OnRolesSaveAsync(ModalActionEventArgs args)
|
||||
{
|
||||
try
|
||||
{
|
||||
UserGrantRoleInput userGrantRoleInput = new();
|
||||
userGrantRoleInput.Id = ChoiceUserId;
|
||||
userGrantRoleInput.RoleIdList = RolesChoice.Select(it => it.Id).ToList();
|
||||
await App.GetService<SysUserService>().GrantRoleAsync(userGrantRoleInput);
|
||||
IsShowRoles = false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
args.Cancel();
|
||||
await PopupService.EnqueueSnackbarAsync(ex, false);
|
||||
}
|
||||
await MainLayout.StateHasChangedAsync();
|
||||
}
|
||||
private Task<ISqlSugarPagedList<SysUser>> QueryCallAsync(UserPageInput input)
|
||||
{
|
||||
return App.GetService<SysUserService>().PageAsync(input);
|
||||
}
|
||||
|
||||
private async Task ResetPasswordAsync(SysUser sysUser)
|
||||
{
|
||||
await App.GetService<SysUserService>().ResetPasswordAsync(sysUser.Id);
|
||||
await PopupService.EnqueueSnackbarAsync(new("成功", AlertTypes.Success));
|
||||
await MainLayout.StateHasChangedAsync();
|
||||
}
|
||||
|
||||
private async Task RoleInitAsync()
|
||||
{
|
||||
AllRoles = await App.GetService<RoleService>().RoleSelectorAsync();
|
||||
var data = await App.GetService<RoleService>().GetRoleIdListByUserIdAsync(ChoiceUserId);
|
||||
RolesChoice = AllRoles.Where(a => data.Contains(a.Id)).ToList();
|
||||
}
|
||||
private async Task UserStatusChangeAsync(SysUser context, bool enable)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (enable)
|
||||
await App.GetService<SysUserService>().EnableUserAsync(context.Id);
|
||||
else
|
||||
await App.GetService<SysUserService>().DisableUserAsync(context.Id);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await _datatable?.QueryClickAsync();
|
||||
await MainLayout.StateHasChangedAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,213 +0,0 @@
|
||||
@*
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
*@
|
||||
|
||||
@page "/login"
|
||||
@layout BaseLayout
|
||||
@inherits BaseComponentBase
|
||||
@namespace ThingsGateway.Admin.Blazor
|
||||
@using BlazorComponent;
|
||||
@using Furion.DataEncryption;
|
||||
@using Masa.Blazor.Presets;
|
||||
@using ThingsGateway.Admin.Application;
|
||||
|
||||
<Ajax></Ajax>
|
||||
@if (IsMobile)
|
||||
{
|
||||
<MCard @onkeydown=Enter Height=@("100%")>
|
||||
@GetLoginCore()
|
||||
</MCard>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MRow NoGutters Style="height:100%">
|
||||
<MCol Md=7 Sm=12>
|
||||
<MSheet Elevation=1 Style="width:100%; height:100%;" Class="d-flex align-start flex-column mb-6">
|
||||
<div class="d-flex align-center ml-12 mt-12">
|
||||
<MAvatar Size="40" Color="teal">
|
||||
<span class="white--text text-h6">@CONFIG_TITLE?.GetNameLen2()</span>
|
||||
</MAvatar>
|
||||
<h1>@CONFIG_TITLE</h1>
|
||||
</div>
|
||||
<div class="d-flex align-center ml-12 mt-12 mb-auto">
|
||||
<h3>@CONFIG_REMARK</h3>
|
||||
</div>
|
||||
<div class="d-flex align-center pa-2" style="width:100%;height:100%;">
|
||||
<MImage Src=@(BlazorResourceConst.ResourceUrl+"images/login-left.svg")></MImage>
|
||||
</div>
|
||||
</MSheet>
|
||||
|
||||
</MCol>
|
||||
|
||||
<MCol Md=5 Sm=12 Align="AlignTypes.Center">
|
||||
<MRow Md=6 Sm=12 Justify="JustifyTypes.Center" Align="AlignTypes.Center">
|
||||
<MCard Class="px-16 py-12" @onkeydown=Enter>
|
||||
@GetLoginCore()
|
||||
</MCard>
|
||||
</MRow>
|
||||
</MCol>
|
||||
|
||||
</MRow>
|
||||
|
||||
}
|
||||
|
||||
@code {
|
||||
|
||||
RenderFragment GetLoginCore()
|
||||
{
|
||||
RenderFragment ViewSubMenu =
|
||||
@<div class="mt-2 px-2 py-1 mx-auto text-center my-auto">
|
||||
<MAvatar Size=80>
|
||||
<MImage Src=@UserLogoUrl>
|
||||
</MImage>
|
||||
</MAvatar>
|
||||
<h5 class="mt-2 mb-12">@Welcome 👋</h5>
|
||||
<MTextField TValue="string"
|
||||
Label=账号
|
||||
Outlined
|
||||
HideDetails="@("auto")"
|
||||
@bind-Value=@loginModel.Account>
|
||||
</MTextField>
|
||||
<MTextField TValue="string"
|
||||
Class="mt-5"
|
||||
Label="密码"
|
||||
Type="@(_showPassword ? "text" : "password")"
|
||||
AppendIcon="@(_showPassword ? "mdi-eye" : "mdi-eye-off")"
|
||||
OnAppendClick="()=>_showPassword = !_showPassword"
|
||||
Outlined
|
||||
HideDetails="@("auto")"
|
||||
@bind-Value=@Password>
|
||||
</MTextField>
|
||||
@if (_showCaptcha)
|
||||
{
|
||||
<PImageCaptcha @ref=captcha @bind-Value="CaptchaValue"
|
||||
TextFieldClass="mt-5 mx-auto"
|
||||
Label=验证码 Outlined Dense
|
||||
OnRefresh="RefreshCode"
|
||||
ErrorMessage=验证码错误>
|
||||
</PImageCaptcha>
|
||||
}
|
||||
<MButton Class="mt-8 rounded-4" OnClick=LoginAsync Height=45 Width=@("100%") Color="primary">登录</MButton>
|
||||
</div>
|
||||
;
|
||||
return ViewSubMenu;
|
||||
}
|
||||
}
|
||||
@code {
|
||||
private string CaptchaValue;
|
||||
bool _showPassword;
|
||||
bool _showCaptcha;
|
||||
private readonly LoginInput loginModel = new();
|
||||
|
||||
|
||||
[Inject]
|
||||
AjaxService AjaxService { get; set; }
|
||||
|
||||
|
||||
string UserLogoUrl { get; set; } = BlazorResourceConst.ResourceUrl + "images/defaultUser.svg";
|
||||
|
||||
string Welcome { get; set; }
|
||||
|
||||
private ValidCodeOutput CaptchaInfo { get; set; }
|
||||
|
||||
private string Password { get; set; }
|
||||
|
||||
private string CONFIG_REMARK { get; set; }
|
||||
|
||||
private string CONFIG_TITLE { get; set; }
|
||||
|
||||
private async Task Enter(KeyboardEventArgs e)
|
||||
{
|
||||
if (e.Code == "Enter" || e.Code == "NumpadEnter")
|
||||
{
|
||||
await LoginAsync();
|
||||
}
|
||||
}
|
||||
private PImageCaptcha captcha;
|
||||
|
||||
private async Task LoginAsync()
|
||||
{
|
||||
loginModel.ValidCodeReqNo = CaptchaInfo.ValidCodeReqNo;
|
||||
loginModel.ValidCode = CaptchaValue;
|
||||
loginModel.Password = DESCEncryption.Encrypt(Password, DESCKeyConst.DESCKey);
|
||||
if (IsMobile)
|
||||
{
|
||||
loginModel.Device = AuthDeviceTypeEnum.APP;
|
||||
}
|
||||
else
|
||||
{
|
||||
loginModel.Device = AuthDeviceTypeEnum.PC;
|
||||
}
|
||||
|
||||
var ajaxOption = new AjaxOption { Url = "/auth/b/login", Data = loginModel, };
|
||||
var str = await AjaxService.GetMessageAsync(ajaxOption);
|
||||
if (str != null)
|
||||
{
|
||||
var ret = str.FromJsonString<UnifyResult<LoginOutput>>();
|
||||
if (ret.Code != 200)
|
||||
{
|
||||
if (captcha != null)
|
||||
{
|
||||
await captcha.RefreshCode();
|
||||
}
|
||||
await PopupService.EnqueueSnackbarAsync(new("登录错误" + ": " + ret.Msg.ToString(), AlertTypes.Error));
|
||||
}
|
||||
else
|
||||
{
|
||||
await PopupService.EnqueueSnackbarAsync(new("登录成功", AlertTypes.Success));
|
||||
await Task.Delay(500);
|
||||
var userId = await App.GetService<SysUserService>().GetIdByAccountAsync(loginModel.Account);
|
||||
var data = await App.GetService<UserCenterService>().GetLoginDefaultRazorAsync(userId);
|
||||
var sameLevelMenus = await App.GetService<ResourceService>().GetaMenuAndSpaListAsync();
|
||||
if (NavigationManager.ToAbsoluteUri(NavigationManager.Uri).AbsolutePath == "/Login" || NavigationManager.ToAbsoluteUri(NavigationManager.Uri).AbsolutePath == "/")
|
||||
await AjaxService.GotoAsync(sameLevelMenus.FirstOrDefault(a => a.Id == data)?.Component ?? "index");
|
||||
else
|
||||
await AjaxService.GotoAsync(NavigationManager.Uri);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (captcha != null)
|
||||
{
|
||||
await captcha.RefreshCode();
|
||||
}
|
||||
await PopupService.EnqueueSnackbarAsync(new("登录错误", AlertTypes.Error));
|
||||
}
|
||||
}
|
||||
[Inject]
|
||||
private NavigationManager NavigationManager { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
#if DEBUG
|
||||
loginModel.Account = "superAdmin";
|
||||
Password = "111111";
|
||||
#endif
|
||||
GetCaptchaInfo();
|
||||
CONFIG_TITLE = (await App.GetService<IConfigService>().GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_TITLE))?.ConfigValue;
|
||||
CONFIG_REMARK = (await App.GetService<IConfigService>().GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_REMARK))?.ConfigValue;
|
||||
_showCaptcha = (await App.GetService<IConfigService>().GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_CAPTCHA_OPEN))?.ConfigValue?.ToBoolean() == true;
|
||||
Welcome = "欢迎使用" + CONFIG_TITLE + "!";
|
||||
await base.OnParametersSetAsync();
|
||||
}
|
||||
|
||||
private void GetCaptchaInfo()
|
||||
{
|
||||
CaptchaInfo = App.GetService<AuthService>().GetCaptchaInfo();
|
||||
}
|
||||
|
||||
private Task<string> RefreshCode()
|
||||
{
|
||||
CaptchaInfo = App.GetService<AuthService>().GetCaptchaInfo();
|
||||
return Task.FromResult(CaptchaInfo.CodeValue);
|
||||
}
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
@*
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
*@
|
||||
|
||||
@namespace ThingsGateway.Admin.Blazor
|
||||
@using Masa.Blazor.Presets
|
||||
@using ThingsGateway.Admin.Application;
|
||||
@inherits LayoutComponentBase
|
||||
@layout BaseLayout
|
||||
@if (UserManager.UserId > 0)
|
||||
{
|
||||
<SysSignalR></SysSignalR>
|
||||
}
|
||||
<PPageTabsProvider>
|
||||
|
||||
<CascadingValue Value="@this" IsFixed>
|
||||
<CascadingValue Value="@Changed" Name="Changed">
|
||||
|
||||
<MNavigationDrawer Color="barcolor" @bind-Value="_drawerOpen" App Width="200">
|
||||
@if (IsMobile)
|
||||
{
|
||||
<MSystemBar Color="barcolor" Height="@(BlazorResourceConst.PageTabsHeight)">
|
||||
<MButton Icon OnClick=@(()=> _drawerOpen = !_drawerOpen)>
|
||||
<MIcon>
|
||||
mdi-close-thick
|
||||
</MIcon>
|
||||
</MButton>
|
||||
<MSpacer />
|
||||
<AppbarButtons />
|
||||
</MSystemBar>
|
||||
}
|
||||
<Logo CONFIG_COPYRIGHT=@CONFIG_COPYRIGHT CONFIG_TITLE=@CONFIG_TITLE HeightInt=@(IsMobile?BlazorResourceConst.AppBarHeight:BlazorResourceConst.AppBarHeight+BlazorResourceConst.PageTabsHeight) />
|
||||
<AppList ClassString="overflow-y-auto" Routable
|
||||
StyleString=@($"height: calc(100vh - {BlazorResourceConst.AppBarHeight+BlazorResourceConst.PageTabsHeight}px);")
|
||||
Items="Navs" />
|
||||
</MNavigationDrawer>
|
||||
|
||||
<MAppBar Color="barcolor" Style=@($"{(!(IsMobile||_drawerOpen!=true)? "left:200px;":"")}") Elevation="1" App Flat ClippedRight Dense ElevateOnScroll
|
||||
MaxHeight="@(BlazorResourceConst.AppBarHeight)" Height="@(BlazorResourceConst.AppBarHeight)">
|
||||
<MButton Class="mr-0" Icon Small=IsMobile OnClick=@(() => _drawerOpen = !_drawerOpen)>
|
||||
<MIcon>mdi-menu</MIcon>
|
||||
</MButton>
|
||||
<AppBarItems BreadcrumbSysResources="BreadcrumbSysResources" SearchSysResources="SearchSysResources" CONFIG_COPYRIGHT=@CONFIG_COPYRIGHT CONFIG_COPYRIGHT_URL=@CONFIG_COPYRIGHT_URL CONFIG_TITLE=@CONFIG_TITLE>
|
||||
</AppBarItems>
|
||||
|
||||
</MAppBar>
|
||||
|
||||
<MMain Style=@($"{(!(IsMobile||_drawerOpen!=true)? "padding-left:200px;":"")}")>
|
||||
<div class="full-width">
|
||||
<PageTabs @ref="_pageTabs" PageTabItems="PageTabItems" />
|
||||
</div>
|
||||
<MDivider Center></MDivider>
|
||||
<MCard Flat Class="overflow-y-auto overflow-x-hidden ma-auto pa-0 rounded-0" Style=@($"height: calc(100vh - {BlazorResourceConst.AppBarHeight+BlazorResourceConst.PageTabsHeight+BlazorResourceConst.FooterHeight}px);")>
|
||||
<PPageContainer PageTabs="@_pageTabs?.PPageTabs">
|
||||
@Body
|
||||
</PPageContainer>
|
||||
</MCard>
|
||||
<MSheet Class="d-flex justify-center align-center rounded-0" Style=@($"height: {BlazorResourceConst.FooterHeight}px; ")>
|
||||
<Foter CONFIG_COPYRIGHT=@CONFIG_COPYRIGHT CONFIG_COPYRIGHT_URL=@CONFIG_COPYRIGHT_URL CONFIG_TITLE=@CONFIG_TITLE></Foter>
|
||||
</MSheet>
|
||||
</MMain>
|
||||
</CascadingValue>
|
||||
</CascadingValue>
|
||||
|
||||
</PPageTabsProvider>
|
||||
|
||||
|
||||
@code {
|
||||
private bool? _drawerOpen = true;
|
||||
private PageTabs _pageTabs;
|
||||
private List<SysResource> BreadcrumbSysResources = new();
|
||||
private string CONFIG_COPYRIGHT = "";
|
||||
private string CONFIG_COPYRIGHT_URL = "";
|
||||
private string CONFIG_TITLE = "";
|
||||
private List<SysResource> SearchSysResources = new();
|
||||
/// <summary>
|
||||
/// IsMobile
|
||||
/// </summary>
|
||||
[CascadingParameter(Name = "IsMobile")]
|
||||
public bool IsMobile { get; set; }
|
||||
|
||||
bool Changed { get; set; }
|
||||
private List<NavItem> Navs { get; set; } = new();
|
||||
private List<PageTabItem> PageTabItems { get; set; } = new();
|
||||
[Inject]
|
||||
private UserResoures UserResoures { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 页面刷新
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task StateHasChangedAsync()
|
||||
{
|
||||
CONFIG_COPYRIGHT = (await App.GetService<IConfigService>().GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_COPYRIGHT)).ConfigValue;
|
||||
CONFIG_TITLE = (await App.GetService<IConfigService>().GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_TITLE)).ConfigValue;
|
||||
CONFIG_COPYRIGHT_URL = (await App.GetService<IConfigService>().GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_COPYRIGHT_URL)).ConfigValue;
|
||||
await UserResoures.InitUserAsync();
|
||||
await UserResoures.InitMenuAsync();
|
||||
Navs = UserResoures.Menus.ParseNavItem();
|
||||
PageTabItems = UserResoures.PageTabItems;
|
||||
SearchSysResources = UserResoures.SameLevelMenus;
|
||||
BreadcrumbSysResources = UserResoures.AllSameLevelMenuSpas;
|
||||
Changed = !Changed;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await StateHasChangedAsync();
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using System.Collections;
|
||||
using System.Data;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ThingsGateway.Admin.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 对象拓展
|
||||
/// </summary>
|
||||
[SuppressSniffer]
|
||||
public static class ListExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// SqlSugar是否忽略字段
|
||||
/// </summary>
|
||||
/// <param name="pi"></param>
|
||||
/// <returns></returns>
|
||||
private static bool IsIgnoreColumn(PropertyInfo pi)
|
||||
{
|
||||
return pi.GetCustomAttribute<SugarColumn>(false).IsIgnore == true;
|
||||
}
|
||||
/// <summary>
|
||||
/// SqlSugar是否Json字段
|
||||
/// </summary>
|
||||
/// <param name="pi"></param>
|
||||
/// <returns></returns>
|
||||
private static bool IsJsonColumn(PropertyInfo pi)
|
||||
{
|
||||
return pi.GetCustomAttribute<SugarColumn>(false).IsJson == true;
|
||||
}
|
||||
/// <summary>
|
||||
/// List转DataTable
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="list"></param>
|
||||
/// <returns></returns>
|
||||
public static DataTable ToDataTable<T>(this List<T> list)
|
||||
{
|
||||
DataTable result = new();
|
||||
if (list.Count > 0)
|
||||
{
|
||||
var propertys = list[0].GetType().GetPropertiesWithCache();
|
||||
foreach (PropertyInfo pi in propertys)
|
||||
{
|
||||
Type colType = pi.PropertyType;
|
||||
if (colType.IsGenericType && colType.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||||
{
|
||||
colType = colType.GetGenericArguments().First();
|
||||
}
|
||||
if (IsIgnoreColumn(pi))
|
||||
continue;
|
||||
if (IsJsonColumn(pi))//如果是json特性就是sting类型
|
||||
colType = typeof(string);
|
||||
if (colType.IsEnum)//如果是Enum需要转string才会保存Enum字符串
|
||||
colType = typeof(string);
|
||||
result.Columns.Add(pi.Name, colType);
|
||||
}
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
ArrayList tempList = new();
|
||||
foreach (PropertyInfo pi in propertys)
|
||||
{
|
||||
if (IsIgnoreColumn(pi))
|
||||
continue;
|
||||
object obj = pi.GetValue(list[i], null);
|
||||
if (IsJsonColumn(pi))//如果是json特性就是转化为json格式
|
||||
obj = obj?.ToJsonString();//如果json字符串是空就传null
|
||||
tempList.Add(obj);
|
||||
}
|
||||
object[] array = tempList.ToArray();
|
||||
result.LoadDataRow(array, true);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
#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 System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Globalization;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ThingsGateway.Admin.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 扩展方法
|
||||
/// </summary>
|
||||
public static class TypeExtensions
|
||||
{
|
||||
private static SysMemoryCache SysMemoryCache = new SysMemoryCache();
|
||||
/// <summary>
|
||||
/// 获取 DisplayName属性名称
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="item"></param>
|
||||
/// <param name="accessor"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
public static string Description<T>(this T item, Expression<Func<T, object>> accessor)
|
||||
{
|
||||
if (accessor.Body == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(accessor));
|
||||
}
|
||||
|
||||
var expression = accessor.Body;
|
||||
if (expression is UnaryExpression unaryExpression && unaryExpression.NodeType == ExpressionType.Convert && unaryExpression.Type == typeof(object))
|
||||
{
|
||||
expression = unaryExpression.Operand;
|
||||
}
|
||||
|
||||
if (expression is not MemberExpression memberExpression)
|
||||
{
|
||||
throw new ArgumentException("只能访问字段或属性");
|
||||
}
|
||||
|
||||
return typeof(T).GetDescription(memberExpression.Member.Name) ?? memberExpression.Member.Name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取成员的描述信息
|
||||
/// </summary>
|
||||
/// <param name="memberInfo"></param>
|
||||
/// <param name="func"></param>
|
||||
/// <returns></returns>
|
||||
public static string FindDisplayAttribute(this MemberInfo memberInfo, Func<MemberInfo, string> func = null)
|
||||
{
|
||||
var dn = memberInfo.GetCustomAttribute<DisplayNameAttribute>(true)?.DisplayName
|
||||
?? memberInfo.GetCustomAttribute<DescriptionAttribute>(true)?.Description
|
||||
?? memberInfo.GetCustomAttribute<DisplayAttribute>(true)?.Description
|
||||
?? memberInfo.GetCustomAttribute<SqlSugar.SugarColumn>(true)?.ColumnDescription
|
||||
?? func?.Invoke(memberInfo)
|
||||
?? memberInfo.Name
|
||||
;
|
||||
|
||||
return dn;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得类型属性的描述信息
|
||||
/// </summary>
|
||||
/// <param name="modelType"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetDescription(this Type modelType, string name)
|
||||
{
|
||||
var cacheKey = $"{nameof(GetDescription)}-{CultureInfo.CurrentUICulture.Name}-{modelType.FullName}-{name}-{modelType.TypeHandle.Value}";
|
||||
var str = SysMemoryCache.GetOrCreate(cacheKey, entry =>
|
||||
{
|
||||
string dn = default;
|
||||
{
|
||||
|
||||
var props = modelType.GetPropertiesWithCache();
|
||||
var propertyInfo = props.FirstOrDefault(p => p.Name == name);
|
||||
if (propertyInfo != null)
|
||||
{
|
||||
dn = FindDisplayAttribute(propertyInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
var fields = modelType.GetFieldsWithCache();
|
||||
var fieldInfo = fields.FirstOrDefault(p => p.Name == name);
|
||||
dn = FindDisplayAttribute(fieldInfo);
|
||||
|
||||
}
|
||||
}
|
||||
return dn ?? name;
|
||||
}, false);
|
||||
|
||||
return str;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取枚举类型的所有项,返回集合
|
||||
/// </summary>
|
||||
public static List<EnumItem> GetEnumList<T>(this T type) where T : Type
|
||||
{
|
||||
var enumType = type;
|
||||
List<EnumItem> list = new();
|
||||
var fieldInfos = enumType.GetFieldsWithCache().ToList();
|
||||
for (int i = 1; i < fieldInfos.Count; i++)
|
||||
{
|
||||
var fieldInfo = fieldInfos[i];
|
||||
var des = fieldInfo.FindDisplayAttribute();
|
||||
int value = (int)Enum.Parse(enumType, fieldInfo.Name);
|
||||
list.Add(new(fieldInfo.Name, des, value));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion;
|
||||
using Furion.Logging;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using System.Text;
|
||||
|
||||
using LogLevel = Microsoft.Extensions.Logging.LogLevel;
|
||||
|
||||
namespace ThingsGateway.Admin.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 日志写入文件的组件
|
||||
/// </summary>
|
||||
public sealed class LoggingFileComponent : IServiceComponent
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public void Load(IServiceCollection services, ComponentContext componentContext)
|
||||
{
|
||||
var logFileEnable = App.GetConfig<bool?>("Logging:LogEnable:File");
|
||||
if (logFileEnable != true) return;
|
||||
|
||||
//获取默认日志等级
|
||||
var defaultLevel = App.GetConfig<LogLevel?>("Logging:LogLevel:File");
|
||||
//获取程序根目录
|
||||
var rootPath = App.HostEnvironment.ContentRootPath;
|
||||
if (defaultLevel != null)//如果默认日志等级不是空
|
||||
{
|
||||
//遍历日志等级
|
||||
foreach (LogLevel level in Enum.GetValues(typeof(LogLevel)))
|
||||
{
|
||||
//如果日志等级是默认等级和最大等级之间
|
||||
if (level >= defaultLevel && level != LogLevel.None)
|
||||
{
|
||||
//每天创建一个日志文件
|
||||
services.AddLogging(builder =>
|
||||
{
|
||||
var fileName = $"logs/{level}/{{0:yyyy}}-{{0:MM}}-{{0:dd}}{{0:zz}}.log";
|
||||
builder.AddFile(fileName, options =>
|
||||
{
|
||||
SetLogOptions(options, level);//日志格式化
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//添加日志文件
|
||||
services.AddFileLogging("logs/{0:yyyy}-{0:MM}-{0:dd}{0:zz}.log", options =>
|
||||
{
|
||||
SetLogOptions(options, null);//日志格式化
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 日志格式化
|
||||
/// </summary>
|
||||
/// <param name="options"></param>
|
||||
/// <param name="logLevel"></param>
|
||||
private static void SetLogOptions(FileLoggerOptions options, LogLevel? logLevel)
|
||||
{
|
||||
//每天创建一个日志文件
|
||||
var rootPath = App.HostEnvironment.ContentRootPath;
|
||||
if (logLevel != null)//如果日志等级不为空
|
||||
{
|
||||
//过滤日志等级
|
||||
options.WriteFilter = (logMsg) =>
|
||||
{
|
||||
//不写入LoggingMonitor
|
||||
if (logMsg.LogName == "System.Logging.LoggingMonitor")
|
||||
return false;
|
||||
//只写入NetCore日志
|
||||
if (!logMsg.LogName.StartsWith("System") && !logMsg.LogName.StartsWith("Microsoft"))
|
||||
return false;
|
||||
return logMsg.LogLevel == logLevel;
|
||||
};
|
||||
}
|
||||
//定义日志文件名
|
||||
options.FileNameRule = fileName =>
|
||||
{
|
||||
return rootPath + "\\" + string.Format(fileName, DateTimeExtensions.CurrentDateTime);
|
||||
};
|
||||
options.FileSizeLimitBytes = 50 * 1024 * 1024;//日志最大50M
|
||||
options.MessageFormat = logMsg =>
|
||||
{
|
||||
var stringBuilder = new StringBuilder();
|
||||
stringBuilder.AppendLine("【日志级别】:" + logMsg.LogLevel);
|
||||
stringBuilder.AppendLine("【日志类名】:" + logMsg.LogName);
|
||||
stringBuilder.AppendLine("【日志时间】:" + DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat());
|
||||
stringBuilder.AppendLine("【日志内容】:" + logMsg.Message);
|
||||
if (logMsg.Exception != null)
|
||||
{
|
||||
stringBuilder.AppendLine("【异常信息】:" + logMsg.Exception);
|
||||
}
|
||||
return stringBuilder.ToString();
|
||||
};
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 9.0 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user