Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
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\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" />
|
||||
<Compile Include="..\..\Web\ThingsGateway.Gateway.Application\Workers\ManageGateway\MqttLoggerExtensions.cs" Link="Pages\Mqtt\MqttLoggerExtensions.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,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,609 +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 MQTTnet.Diagnostics;
|
||||
|
||||
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 log = new MqttNetEventLogger();
|
||||
log.LogMessagePublished += Log_LogMessagePublished;
|
||||
var mqttFactory = new MqttFactory(log);
|
||||
_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 Log_LogMessagePublished(object sender, MqttNetLogMessagePublishedEventArgs e)
|
||||
{
|
||||
LogMessage.LogOut(e.LogMessage.Level, e.LogMessage.Source, e.LogMessage.Message, e.LogMessage.Exception);
|
||||
}
|
||||
|
||||
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,577 +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 MQTTnet.Diagnostics;
|
||||
|
||||
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 log = new MqttNetEventLogger();
|
||||
log.LogMessagePublished += Log_LogMessagePublished;
|
||||
var mqttFactory = new MqttFactory(log);
|
||||
_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 void Log_LogMessagePublished(object sender, MqttNetLogMessagePublishedEventArgs e)
|
||||
{
|
||||
LogMessage.LogOut(e.LogMessage.Level, e.LogMessage.Source, e.LogMessage.Message, e.LogMessage.Exception);
|
||||
}
|
||||
|
||||
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,125 +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 MQTTnet.Diagnostics;
|
||||
|
||||
using System.Text;
|
||||
|
||||
using ThingsGateway.Gateway.Application;
|
||||
|
||||
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()
|
||||
{
|
||||
var log = new MqttNetEventLogger();
|
||||
log.LogMessagePublished += Log_LogMessagePublished;
|
||||
MqttFactory = new MqttFactory(log);
|
||||
|
||||
|
||||
MqttClient = MqttFactory.CreateMqttClient();
|
||||
MqttClient.ApplicationMessageReceivedAsync += MqttClient_ApplicationMessageReceivedAsync;
|
||||
base.OnInitialized();
|
||||
}
|
||||
private void Log_LogMessagePublished(object sender, MqttNetLogMessagePublishedEventArgs e)
|
||||
{
|
||||
new EasyLogger(LogAction) { LogLevel = LogLevel.Trace }.LogOut(e.LogMessage.Level, e.LogMessage.Source, e.LogMessage.Message, e.LogMessage.Exception);
|
||||
}
|
||||
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,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,356 +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;
|
||||
}
|
||||
|
||||
private bool readDBInitSuccess;
|
||||
|
||||
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 (!readDBInitSuccess)
|
||||
{
|
||||
//事务
|
||||
var result = db.UseTran(() =>
|
||||
{
|
||||
db.Storageable(varList).As(driverPropertys.ReadDBTableName).PageSize(10000).ExecuteSqlBulkCopy();
|
||||
//db.Fastest<SQLRealValue>().AS(driverPropertys.ReadDBTableName).PageSize(100000).BulkMerge(varList);
|
||||
});
|
||||
if (result.IsSuccess)//如果成功了
|
||||
{
|
||||
readDBInitSuccess = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new(result.ErrorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
if (varList?.Count != 0)
|
||||
{
|
||||
//var result = await db.Storageable(varList).As(driverPropertys.ReadDBTableName).ExecuteCommandAsync(cancellationToken);
|
||||
db.Fastest<SQLRealValue>().AS(driverPropertys.ReadDBTableName).PageSize(100000).BulkUpdate(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
|
||||
{
|
||||
readDBInitSuccess = false;
|
||||
_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,58 +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.Rack != 0)
|
||||
{
|
||||
_plc.Rack = driverPropertys.Rack;
|
||||
}
|
||||
if (driverPropertys.Slot != 0)
|
||||
{
|
||||
_plc.Slot = driverPropertys.Slot;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,57 +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.Rack != 0)
|
||||
{
|
||||
_plc.Rack = driverPropertys.Rack;
|
||||
}
|
||||
if (driverPropertys.Slot != 0)
|
||||
{
|
||||
_plc.Slot = driverPropertys.Slot;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,57 +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.Rack != 0)
|
||||
{
|
||||
_plc.Rack = driverPropertys.Rack;
|
||||
}
|
||||
if (driverPropertys.Slot != 0)
|
||||
{
|
||||
_plc.Slot = driverPropertys.Slot;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,56 +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.Rack != 0)
|
||||
{
|
||||
_plc.Rack = driverPropertys.Rack;
|
||||
}
|
||||
if (driverPropertys.Slot != 0)
|
||||
{
|
||||
_plc.Slot = driverPropertys.Slot;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,57 +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.Rack != 0)
|
||||
{
|
||||
_plc.Rack = driverPropertys.Rack;
|
||||
}
|
||||
if (driverPropertys.Slot != 0)
|
||||
{
|
||||
_plc.Slot = driverPropertys.Slot;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,57 +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.Rack != 0)
|
||||
{
|
||||
_plc.Rack = driverPropertys.Rack;
|
||||
}
|
||||
if (driverPropertys.Slot != 0)
|
||||
{
|
||||
_plc.Slot = driverPropertys.Slot;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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,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 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,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.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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
|
||||
|
||||
<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)*TDengineDB*.dll" %25dir%25



" />
|
||||
|
||||
</Target>
|
||||
|
||||
<PropertyGroup>
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SqlSugar.TDengineCore" Version="2.8.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
||||
</Project>
|
||||
@@ -1,109 +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("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Web", "Web", "{9EB46BB6-D4EA-4B06-95EE-6C971E653030}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
Web\Directory.Build.props = Web\Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "script", "script", "{4A64518E-C072-4607-BBF7-7D392CEC9D58}"
|
||||
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}"
|
||||
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
|
||||
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
|
||||
{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
|
||||
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}
|
||||
{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}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C49B2D3E-6818-4E28-91B7-6E4E7E264BBB}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -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,113 +3,104 @@ 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}"
|
||||
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}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Admin", "Admin", "{5854938A-F669-40F4-A54C-EC2651730B73}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{C39748E6-34AC-4C4A-AEC7-7D807FFB4813}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Gateway", "Gateway", "{05A88744-64D9-4959-8A97-5189F327BBBE}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.OPCUA", "plugin\ThingsGateway.Plugin.OPCUA\ThingsGateway.Plugin.OPCUA.csproj", "{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@@ -141,114 +132,110 @@ 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
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -260,34 +247,32 @@ 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} = {C39748E6-34AC-4C4A-AEC7-7D807FFB4813}
|
||||
{616CA361-B667-42C8-B4DC-097C7CD39830} = {5854938A-F669-40F4-A54C-EC2651730B73}
|
||||
{16C62A28-BACE-4391-91F8-C2D78D063A1E} = {5854938A-F669-40F4-A54C-EC2651730B73}
|
||||
{8FA03089-322F-44CB-8E4B-F2637388E944} = {5854938A-F669-40F4-A54C-EC2651730B73}
|
||||
{14FF7150-6DB7-455B-AD00-6AB4DE37855B} = {5854938A-F669-40F4-A54C-EC2651730B73}
|
||||
{51313113-7BB8-494E-9C24-6787BECE39BB} = {C39748E6-34AC-4C4A-AEC7-7D807FFB4813}
|
||||
{5D7BE567-2345-46C8-9F54-DDC1DA96D198} = {05A88744-64D9-4959-8A97-5189F327BBBE}
|
||||
{5CF1B3EC-84E2-484A-8DFC-2ECD2EE18E2F} = {05A88744-64D9-4959-8A97-5189F327BBBE}
|
||||
{CD0F211A-F65B-4026-9750-68AC3C70D012} = {05A88744-64D9-4959-8A97-5189F327BBBE}
|
||||
{5CD79F91-7182-4A9D-9BEF-4DF410C782D2} = {05A88744-64D9-4959-8A97-5189F327BBBE}
|
||||
{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}
|
||||
{5854938A-F669-40F4-A54C-EC2651730B73} = {9EB46BB6-D4EA-4B06-95EE-6C971E653030}
|
||||
{C39748E6-34AC-4C4A-AEC7-7D807FFB4813} = {9EB46BB6-D4EA-4B06-95EE-6C971E653030}
|
||||
{05A88744-64D9-4959-8A97-5189F327BBBE} = {9EB46BB6-D4EA-4B06-95EE-6C971E653030}
|
||||
{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}
|
||||
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 |
Binary file not shown.
|
Before Width: | Height: | Size: 14 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 8.8 KiB |
@@ -1,33 +0,0 @@
|
||||
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_1416_20774)">
|
||||
<path d="M0 20C0 8.95431 8.95431 0 20 0C31.0457 0 40 8.95431 40 20C40 31.0457 31.0457 40 20 40C8.95431 40 0 31.0457 0 20Z" fill="#E9EDF7"/>
|
||||
<path d="M6.76525 36.4864C7.28664 29.3741 13.0134 27.2001 20.0011 27.2001C26.9889 27.2001 32.7156 29.3741 33.237 36.4864H33.2757V48.4031H6.72656V36.4864H6.76525Z" fill="#FF5252"/>
|
||||
<path d="M16.8613 22.161H22.5671V27.1615C22.5671 28.7371 21.2898 30.0144 19.7142 30.0144C18.1386 30.0144 16.8613 28.7371 16.8613 27.1615V22.161Z" fill="#FDCDC5"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M22.5394 25.6764C21.8857 26.3501 21.0923 26.7448 20.2369 26.7448H19.0227C18.2403 26.7448 17.5098 26.4146 16.8906 25.8428V21.6875H22.5394V25.6764Z" fill="#FBACA3"/>
|
||||
<path d="M12.8613 12.1824C12.8613 8.55546 15.8016 5.61523 19.4285 5.61523C23.0555 5.61523 25.9957 8.55546 25.9957 12.1824V13.7445V15.8658C25.9957 17.9068 24.9071 19.7929 23.1397 20.8138L21.7152 21.6367C20.3003 22.4541 18.5567 22.4541 17.1418 21.6367L15.7173 20.8138C13.9499 19.7929 12.8613 17.9068 12.8613 15.8658V13.7445V12.1824Z" fill="black"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.4286 13.6275C13.4286 10.7872 15.7311 8.48468 18.5714 8.48468H20.2857C23.126 8.48468 25.4286 10.7872 25.4286 13.6275V15.6476C25.7648 15.4531 26.1551 15.3418 26.5714 15.3418C27.8338 15.3418 28.8571 16.3652 28.8571 17.6275C28.8571 18.8899 27.8338 19.9133 26.5714 19.9133C26.1551 19.9133 25.7648 19.8019 25.4286 19.6075V19.7122C25.4286 21.6228 24.4737 23.407 22.884 24.4668L21.9643 25.0799C20.4288 26.1036 18.4283 26.1036 16.8928 25.0799L15.9731 24.4668C14.3834 23.407 13.4286 21.6228 13.4286 19.7122V19.6075C13.0924 19.8019 12.702 19.9133 12.2857 19.9133C11.0233 19.9133 10 18.8899 10 17.6275C10 16.3652 11.0233 15.3418 12.2857 15.3418C12.702 15.3418 13.0924 15.4531 13.4286 15.6476V13.6275Z" fill="#FDCDC5"/>
|
||||
<path d="M25.7051 16.979C25.8788 16.3711 27.2466 16.1974 27.6808 16.979" stroke="black" stroke-width="0.285714" stroke-linecap="round"/>
|
||||
<path d="M25.904 16.6965C26.2656 16.4163 26.9255 16.823 26.8524 17.3423" stroke="black" stroke-width="0.285714" stroke-linecap="round"/>
|
||||
<path d="M13.1602 16.979C12.9865 16.3711 11.6187 16.1974 11.1844 16.979" stroke="black" stroke-width="0.285714" stroke-linecap="round"/>
|
||||
<path d="M12.9612 16.6965C12.5996 16.4163 11.9398 16.823 12.0128 17.3423" stroke="black" stroke-width="0.285714" stroke-linecap="round"/>
|
||||
<ellipse cx="23.428" cy="18.2857" rx="1.42857" ry="1.14286" transform="rotate(-28.5497 23.428 18.2857)" fill="#FBACA3"/>
|
||||
<ellipse cx="14.8583" cy="18.286" rx="1.42857" ry="1.14286" fill="#FBACA3"/>
|
||||
<path d="M13.5765 14.858C13.5765 14.6213 13.7683 14.4294 14.005 14.4294H18.5765C18.8131 14.4294 19.005 14.6213 19.005 14.858V16.0008C19.005 16.8687 18.3015 17.5723 17.4336 17.5723H15.1479C14.28 17.5723 13.5765 16.8687 13.5765 16.0008V14.858Z" stroke="black" stroke-width="0.285714"/>
|
||||
<path d="M19.8616 14.858C19.8616 14.6213 20.0535 14.4294 20.2902 14.4294H24.8616C25.0983 14.4294 25.2902 14.6213 25.2902 14.858V16.0008C25.2902 16.8687 24.5866 17.5723 23.7188 17.5723H21.433C20.5652 17.5723 19.8616 16.8687 19.8616 16.0008V14.858Z" stroke="black" stroke-width="0.285714"/>
|
||||
<rect x="19.1465" y="14.858" width="0.571429" height="0.571429" fill="black"/>
|
||||
<rect x="25.4336" y="14.858" width="0.571429" height="0.571429" fill="black"/>
|
||||
<rect x="12.8613" y="14.858" width="0.571429" height="0.571429" fill="black"/>
|
||||
<circle cx="16.2902" cy="15.4286" r="0.571429" fill="black"/>
|
||||
<circle cx="22.5753" cy="15.4286" r="0.571429" fill="black"/>
|
||||
<ellipse cx="22.3617" cy="13.453" rx="1.32267" ry="0.661333" fill="black"/>
|
||||
<ellipse rx="1.32267" ry="0.661333" transform="matrix(0.978731 0.205148 0.205148 -0.978731 15.9888 13.1958)" fill="black"/>
|
||||
<path d="M19.5153 17.7146C19.1343 18.1908 18.7153 19.1432 20.0867 19.1432" stroke="black" stroke-width="0.571429"/>
|
||||
<path d="M22.6239 20.9277C22.1323 21.2528 21.277 21.6524 19.6156 21.6524C17.9542 21.6524 17.1711 21.2664 16.6074 20.9277" stroke="black" stroke-width="0.285714" stroke-linecap="round"/>
|
||||
<ellipse cx="19.6051" cy="22.7021" rx="0.482063" ry="0.275466" fill="#FBACA3"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1416_20774">
|
||||
<path d="M0 20C0 8.95431 8.95431 0 20 0C31.0457 0 40 8.95431 40 20C40 31.0457 31.0457 40 20 40C8.95431 40 0 31.0457 0 20Z" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.3 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user