Compare commits

...

72 Commits

Author SHA1 Message Date
2248356998 qq.com
03089adad6 发行1.10版本 2023-03-26 18:10:12 +08:00
2248356998 qq.com
4a1fe746ab 实时数据界面优化 2023-03-26 17:39:05 +08:00
2248356998 qq.com
aa52c05d2c 1、采用异步AutoResetEvent,修复多个设备下采集太慢的问题
2、弃用IntelligentConcurrentQueue(touchsocket集成类)
2023-03-26 17:32:29 +08:00
2248356998 qq.com
26407a43e7 1、优化设备状态页,减少signalr刷新所需包大小
2、日志前置等级添加
2023-03-24 18:32:10 +08:00
2248356998 qq.com
a02934bf19 修复导出表格时,null值报错 2023-03-23 22:09:53 +08:00
2248356998 qq.com
09c65fba09 导入错误时,忽略大于10行的错误信息显示 2023-03-23 20:01:19 +08:00
2248356998 qq.com
4305c727d0 更新readme 2023-03-22 15:29:35 +08:00
2248356998 qq.com
188339897f 优化log等级、json配置注解 2023-03-22 15:26:42 +08:00
2248356998 qq.com
4ecff9a707 OPCUA写入测试 2023-03-22 14:06:32 +08:00
2248356998 qq.com
355aed49c6 设备运行状态页面改为扩展 2023-03-22 13:46:23 +08:00
2248356998 qq.com
4717b6b0f0 更新文档 2023-03-22 10:44:44 +08:00
Diego2098
45ebe9048d rbmq插件优化 2023-03-21 23:38:00 +08:00
Diego2098
b2170c49a3 分包失败提示 2023-03-21 23:28:30 +08:00
Diego2098
dc2f4d6115 设备组列宽调整,补充上传设备组 2023-03-21 23:10:59 +08:00
Diego2098
1eb132440f 1、更新DataTypeEnum
2、OPCUA写入时需实际数据类型
2023-03-21 22:47:10 +08:00
Diego2098
a464bbc37a 更新Tests 2023-03-21 22:46:12 +08:00
2248356998 qq.com
ed995697c2 表格无数据时,修改默认宽度 2023-03-21 18:17:18 +08:00
2248356998 qq.com
163cd84c7b S7nuget版本 2023-03-21 15:44:50 +08:00
2248356998 qq.com
293d7cc292 masa nuget版本更改 2023-03-21 14:31:36 +08:00
2248356998 qq.com
5de1b4e74c GC策略修改 2023-03-21 14:07:17 +08:00
2248356998 qq.com
7b474975da 更新文档 2023-03-21 14:03:49 +08:00
2248356998 qq.com
beab51516b 更新文档 2023-03-21 13:56:14 +08:00
2248356998 qq.com
fe8685a50c 修改s7属性注释 2023-03-21 13:51:05 +08:00
2248356998 qq.com
f9af5d0885 更新readme 2023-03-21 13:49:10 +08:00
2248356998 qq.com
e8136a9720 更新S7协议插件 2023-03-21 13:45:58 +08:00
2248356998 qq.com
531e5d4556 修改S7特殊方法 2023-03-21 13:41:32 +08:00
2248356998 qq.com
e66255963a 修改s7 2023-03-21 13:38:43 +08:00
2248356998 qq.com
246aac8ee4 添加西门子S7协议插件 2023-03-21 13:37:17 +08:00
2248356998 qq.com
23cfeff685 版本恢复 2023-03-21 11:45:18 +08:00
2248356998 qq.com
a5e7e0d126 更新nuget,暂缓链路复用功能 2023-03-20 13:34:59 +08:00
2248356998 qq.com
5bebc30ba0 默认不开启转储 2023-03-20 09:22:11 +08:00
2248356998 qq.com
0e7057f5b9 更新opcda文档 2023-03-19 23:18:24 +08:00
2248356998 qq.com
7c6c365ba4 格式清理 2023-03-19 23:12:58 +08:00
2248356998 qq.com
424c9bb0c5 修复null值报错 2023-03-19 23:02:08 +08:00
2248356998 qq.com
9d0f26594c 添加设备组,变量按设备组别搜索 2023-03-19 22:56:02 +08:00
2248356998 qq.com
99c17de079 更新readme,opcda核心库提示 2023-03-19 20:40:54 +08:00
2248356998 qq.com
b1e3dd0af6 尝试修复中文在mac上乱码 2023-03-19 17:29:01 +08:00
2248356998 qq.com
261cb89530 修正中文在mac上乱码 2023-03-19 16:45:14 +08:00
2248356998 qq.com
ff6773ba37 删除未知文件 2023-03-19 16:35:24 +08:00
2248356998 qq.com
bdfbbfcbbd Merge branch 'master' of https://gitee.com/diego2098/ThingsGateway 2023-03-19 16:34:26 +08:00
2248356998 qq.com
0c4cd56758 添加设备组功能 2023-03-19 16:34:15 +08:00
士心
4a36658321 !4 修复MacOS环境下,数据库报错的问题
* 修复macos环境下,数据库报错
2023-03-19 08:28:54 +00:00
2248356998 qq.com
7aae938685 准备更新设备组/变量组功能 2023-03-19 11:49:06 +08:00
2248356998 qq.com
3723401e7a 更新ReadMe 2023-03-18 17:56:18 +08:00
2248356998 qq.com
70631366a9 1、最后校验失败时应该提示日志
2、暂停时设备状态修正
2023-03-18 17:49:08 +08:00
2248356998 qq.com
0e40bbda3e 更新文档 2023-03-18 16:47:29 +08:00
2248356998 qq.com
e9aa475398 ByteBlock实际长度 2023-03-18 16:45:39 +08:00
2248356998 qq.com
8d2a811184 修正串口描述类ToString 2023-03-18 16:32:15 +08:00
2248356998 qq.com
dd7f5b6700 更新文档 2023-03-18 16:23:23 +08:00
2248356998 qq.com
a4f6277737 更新nuget 2023-03-18 16:16:27 +08:00
2248356998 qq.com
c2bfaacbb7 更新readme 2023-03-18 16:15:14 +08:00
2248356998 qq.com
a17cbfa2d4 添加ModbusRtu种子数据 2023-03-18 16:14:37 +08:00
2248356998 qq.com
fb9a101555 添加ModbusRtu插件 2023-03-18 16:14:25 +08:00
2248356998 qq.com
e319cf0200 添加串口基础类 2023-03-18 16:14:08 +08:00
2248356998 qq.com
0a8395ef6a 更新文档 2023-03-17 18:19:14 +08:00
2248356998 qq.com
38df5e01be 更新文档 2023-03-17 17:52:04 +08:00
2248356998 qq.com
ebd891a868 种子数据更改 2023-03-17 17:51:58 +08:00
2248356998 qq.com
4ab2395cbe 采集检测间隔修改 2023-03-17 17:40:34 +08:00
2248356998 qq.com
5f1f989fc9 上传插件添加循环间隔属性 2023-03-17 17:30:06 +08:00
2248356998 qq.com
44b709eee3 添加rbmq插件种子数据 2023-03-17 16:30:02 +08:00
2248356998 qq.com
d0d7726597 rbmq插件文件夹更名 2023-03-17 16:16:23 +08:00
2248356998 qq.com
054c342aeb 优化内存queue,修复mqtt插件可能超出字节限制的情况 2023-03-17 16:04:24 +08:00
2248356998 qq.com
c79c33baf7 添加rbmq插件 2023-03-17 16:03:44 +08:00
2248356998 qq.com
23b00e35b2 设备禁用时,变量绑定的设备对应选项会显示禁用(灰色) 2023-03-17 11:29:14 +08:00
2248356998 qq.com
fe51079266 更新readme 2023-03-16 17:33:25 +08:00
2248356998 qq.com
0791b0bbee 选择插件时自动更新属性 2023-03-16 17:33:17 +08:00
2248356998 qq.com
dbf04c8eeb 更新赞助名单 2023-03-16 11:35:58 +08:00
2248356998 qq.com
6204256df8 限流服务默认不开启 2023-03-16 09:47:20 +08:00
2248356998 qq.com
93cc8c2327 增加简易定时看板 2023-03-15 16:01:54 +08:00
2248356998 qq.com
68a2e5bbbc 更新历史配置说明 2023-03-15 09:11:33 +08:00
Diego2098
72792153f2 !3 update handbook/docs/05、网关配置/5.5、其他配置.mdx.
Merge pull request !3 from zhubanghao/N/A
2023-03-14 13:39:16 +00:00
zhubanghao
88b6ef1897 update handbook/docs/05、网关配置/5.5、其他配置.mdx.
Signed-off-by: zhubanghao <58813184@qq.com>
2023-03-14 13:05:33 +00:00
238 changed files with 9288 additions and 2386 deletions

View File

@@ -4,8 +4,7 @@
#### 介绍
基于[ThingsBlazor](https://gitee.com/diego2098/ThingsBlazor)权限管理框架开发的跨平台边缘采集网关,支持南北端插件式开发,
动态更新插件,
并拥有较完善的北端Rpc权限管理。
动态更新插件,并拥有较完善的北端Rpc权限管理。
#### 功能亮点
@@ -13,14 +12,29 @@
- Blazor Server架构开发部署更简单
- 采集/上传配置完全支持Excel导入导出
- 插件式驱动,方便驱动二次开发,并支持动态更新
- Modbus、OPCDA、OPCUA采集插件支持导入节点
- Modbus Server、Mqtt Server(Client)、OPC UAServer插件,支持Rpc写入支持WebApi
- 支持时序数据库存储
- 实时/历史报警(Sql转储),支持布尔/高低限值
#### 社区版采集插件
> 支持分包解析/订阅
- Modbus(Rtu/Tcp/Udp)
- OPCDAClient支持导入节点
- OPCUAClient支持导入节点
- 西门子S7协议
#### 社区版上传插件
> 支持Rpc写入
- Modbus Server
- Mqtt Server
- Mqtt Client
> 不支持Rpc
- RabbitMQ
#### nuget
- Modbus库支持ModbusTcp、ModbusRtuOverTcp、ModbusUdp、ModbusServer等
- Modbus库支持ModbusTcp、ModbusRtu、ModbusRtuOverTcp、ModbusUdp、ModbusServer等
``` powershell
dotnet add package ThingsGateway.Foundation.Adapter.Modbus
```
@@ -32,6 +46,12 @@
``` powershell
dotnet add package ThingsGateway.Foundation.Adapter.OPCUA
```
- S7库
``` powershell
dotnet add package ThingsGateway.Foundation.Adapter.Siemens
```
#### 效果图
<table>
<tr>
@@ -59,6 +79,7 @@
#### 补充说明
* 使用OPC相关插件时请遵循OPC基金会的授权规则
* 使用OPCDA插件时需安装OPC核心库[文件地址](https://gitee.com/diego2098/ThingsGateway/attach_files)
#### 开源协议
@@ -66,11 +87,11 @@
#### 支持作者
如果对您有帮助请点击右上角⭐Star关注感谢支持开源
若希望捐赠项目请跳转到文档站点查看捐赠码或使用Gitee捐赠功能
若希望捐赠项目,请[点击](https://diego2098.gitee.io/thingsgateway/docs/03%E3%80%81%E6%94%AF%E6%8C%81%E9%A1%B9%E7%9B%AE%E4%B8%8EPro%E7%89%88%E8%AF%B4%E6%98%8E/%E6%94%AF%E6%8C%81%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE/)查看捐赠码或使用Gitee捐赠功能
#### 联系作者
* QQ群605534569

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
"use strict";(self.webpackChunkthingsgateway=self.webpackChunkthingsgateway||[]).push([[564],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>f});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),s=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(l.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),d=s(r),f=a,g=d["".concat(l,".").concat(f)]||d[f]||u[f]||i;return r?n.createElement(g,o(o({ref:t},p),{},{components:r})):n.createElement(g,o({ref:t},p))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,o[1]=c;for(var s=2;s<i;s++)o[s]=r[s];return n.createElement.apply(null,o)}return n.createElement.apply(null,r)}d.displayName="MDXCreateElement"},5771:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>c,toc:()=>s});var n=r(7462),a=(r(7294),r(3905));const i={id:"quickstart",title:"\u5feb\u901f\u542f\u52a8",sidebar_label:"04\u3001\u5feb\u901f\u542f\u52a8"},o=void 0,c={unversionedId:"quickstart",id:"quickstart",title:"\u5feb\u901f\u542f\u52a8",description:"\uff08\u4e00\uff09\u3001\u4e0b\u8f7d\u6e90\u7801",source:"@site/docs/04\u3001\u5feb\u901f\u542f\u52a8.mdx",sourceDirName:".",slug:"/quickstart",permalink:"/thingsgateway/docs/quickstart",draft:!1,editUrl:"https://gitee.com/diego2098/ThingsGateway/tree/master/handbook/docs/04\u3001\u5feb\u901f\u542f\u52a8.mdx",tags:[],version:"current",frontMatter:{id:"quickstart",title:"\u5feb\u901f\u542f\u52a8",sidebar_label:"04\u3001\u5feb\u901f\u542f\u52a8"},sidebar:"tutorialSidebar",previous:{title:"03\u3001\u652f\u6301\u5f00\u6e90\u9879\u76ee",permalink:"/thingsgateway/docs/\u652f\u6301\u5f00\u6e90\u9879\u76ee"},next:{title:"5.1\u3001\u91c7\u96c6\u8bbe\u5907",permalink:"/thingsgateway/docs/05\u3001\u7f51\u5173\u914d\u7f6e/collectdevice"}},l={},s=[{value:"\uff08\u4e00\uff09\u3001\u4e0b\u8f7d\u6e90\u7801",id:"\u4e00\u4e0b\u8f7d\u6e90\u7801",level:3},{value:"\uff08\u4e8c\uff09\u3001\u914d\u7f6e\u5e76\u542f\u52a8\u7cfb\u7edf",id:"\u4e8c\u914d\u7f6e\u5e76\u542f\u52a8\u7cfb\u7edf",level:3}],p={toc:s};function u(e){let{components:t,...i}=e;return(0,a.kt)("wrapper",(0,n.Z)({},p,i,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h3",{id:"\u4e00\u4e0b\u8f7d\u6e90\u7801"},"\uff08\u4e00\uff09\u3001\u4e0b\u8f7d\u6e90\u7801"),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"https://gitee.com/diego2098/ThingsGateway"},"\u6700\u65b0\u7248\u672c")," "),(0,a.kt)("h3",{id:"\u4e8c\u914d\u7f6e\u5e76\u542f\u52a8\u7cfb\u7edf"},"\uff08\u4e8c\uff09\u3001\u914d\u7f6e\u5e76\u542f\u52a8\u7cfb\u7edf"),(0,a.kt)("p",null,"1\u3001 vs2022\u6253\u5f00\u89e3\u51b3\u65b9\u6848\uff0c\u8bbe\u7f6eThingsGateway.Web.Server\u4e3a\u542f\u52a8\u9879\u76ee"),(0,a.kt)("p",null,"2\u3001 \u76f4\u63a5debug\u8fd0\u884c"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"\u9ed8\u8ba4\u8fd0\u884c\u5730\u5740\uff1ahttp://localhost:7100;")),(0,a.kt)("p",null,(0,a.kt)("img",{src:r(2405).Z,width:"2558",height:"1459"})))}u.isMDXComponent=!0},2405:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/login-ec50fefb8cb6a0b5ed67912fc045f617.png"}}]);

View File

@@ -0,0 +1 @@
"use strict";(self.webpackChunkthingsgateway=self.webpackChunkthingsgateway||[]).push([[564],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>f});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},o=Object.keys(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),s=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(l.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),d=s(r),f=a,g=d["".concat(l,".").concat(f)]||d[f]||u[f]||o;return r?n.createElement(g,i(i({ref:t},p),{},{components:r})):n.createElement(g,i({ref:t},p))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,i[1]=c;for(var s=2;s<o;s++)i[s]=r[s];return n.createElement.apply(null,i)}return n.createElement.apply(null,r)}d.displayName="MDXCreateElement"},5771:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>c,toc:()=>s});var n=r(7462),a=(r(7294),r(3905));const o={id:"quickstart",title:"\u5feb\u901f\u542f\u52a8",sidebar_label:"04\u3001\u5feb\u901f\u542f\u52a8"},i=void 0,c={unversionedId:"quickstart",id:"quickstart",title:"\u5feb\u901f\u542f\u52a8",description:"\uff08\u4e00\uff09\u3001\u4e0b\u8f7d\u6e90\u7801",source:"@site/docs/04\u3001\u5feb\u901f\u542f\u52a8.mdx",sourceDirName:".",slug:"/quickstart",permalink:"/thingsgateway/docs/quickstart",draft:!1,editUrl:"https://gitee.com/diego2098/ThingsGateway/tree/master/handbook/docs/04\u3001\u5feb\u901f\u542f\u52a8.mdx",tags:[],version:"current",frontMatter:{id:"quickstart",title:"\u5feb\u901f\u542f\u52a8",sidebar_label:"04\u3001\u5feb\u901f\u542f\u52a8"},sidebar:"tutorialSidebar",previous:{title:"3.2\u3001Pro\u7248\u8bf4\u660e",permalink:"/thingsgateway/docs/03\u3001\u652f\u6301\u9879\u76ee\u4e0ePro\u7248\u8bf4\u660e/Pro"},next:{title:"5.1\u3001\u91c7\u96c6\u8bbe\u5907",permalink:"/thingsgateway/docs/05\u3001\u7f51\u5173\u914d\u7f6e/collectdevice"}},l={},s=[{value:"\uff08\u4e00\uff09\u3001\u4e0b\u8f7d\u6e90\u7801",id:"\u4e00\u4e0b\u8f7d\u6e90\u7801",level:3},{value:"\uff08\u4e8c\uff09\u3001\u914d\u7f6e\u5e76\u542f\u52a8\u7cfb\u7edf",id:"\u4e8c\u914d\u7f6e\u5e76\u542f\u52a8\u7cfb\u7edf",level:3}],p={toc:s};function u(e){let{components:t,...o}=e;return(0,a.kt)("wrapper",(0,n.Z)({},p,o,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h3",{id:"\u4e00\u4e0b\u8f7d\u6e90\u7801"},"\uff08\u4e00\uff09\u3001\u4e0b\u8f7d\u6e90\u7801"),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"https://gitee.com/diego2098/ThingsGateway"},"\u6700\u65b0\u7248\u672c")," "),(0,a.kt)("h3",{id:"\u4e8c\u914d\u7f6e\u5e76\u542f\u52a8\u7cfb\u7edf"},"\uff08\u4e8c\uff09\u3001\u914d\u7f6e\u5e76\u542f\u52a8\u7cfb\u7edf"),(0,a.kt)("p",null,"1\u3001 vs2022\u6253\u5f00\u89e3\u51b3\u65b9\u6848\uff0c\u8bbe\u7f6eThingsGateway.Web.Server\u4e3a\u542f\u52a8\u9879\u76ee"),(0,a.kt)("p",null,"2\u3001 \u76f4\u63a5debug\u8fd0\u884c"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"\u9ed8\u8ba4\u8fd0\u884c\u5730\u5740\uff1ahttp://localhost:7100;")),(0,a.kt)("p",null,(0,a.kt)("img",{src:r(2405).Z,width:"2558",height:"1459"})))}u.isMDXComponent=!0},2405:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/login-ec50fefb8cb6a0b5ed67912fc045f617.png"}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
(()=>{"use strict";var e,t,a,r,f,o={},n={};function c(e){var t=n[e];if(void 0!==t)return t.exports;var a=n[e]={exports:{}};return o[e].call(a.exports,a,a.exports,c),a.exports}c.m=o,e=[],c.O=(t,a,r,f)=>{if(!a){var o=1/0;for(b=0;b<e.length;b++){a=e[b][0],r=e[b][1],f=e[b][2];for(var n=!0,i=0;i<a.length;i++)(!1&f||o>=f)&&Object.keys(c.O).every((e=>c.O[e](a[i])))?a.splice(i--,1):(n=!1,f<o&&(o=f));if(n){e.splice(b--,1);var d=r();void 0!==d&&(t=d)}}return t}f=f||0;for(var b=e.length;b>0&&e[b-1][2]>f;b--)e[b]=e[b-1];e[b]=[a,r,f]},c.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return c.d(t,{a:t}),t},a=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,c.t=function(e,r){if(1&r&&(e=this(e)),8&r)return e;if("object"==typeof e&&e){if(4&r&&e.__esModule)return e;if(16&r&&"function"==typeof e.then)return e}var f=Object.create(null);c.r(f);var o={};t=t||[null,a({}),a([]),a(a)];for(var n=2&r&&e;"object"==typeof n&&!~t.indexOf(n);n=a(n))Object.getOwnPropertyNames(n).forEach((t=>o[t]=()=>e[t]));return o.default=()=>e,c.d(f,o),f},c.d=(e,t)=>{for(var a in t)c.o(t,a)&&!c.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},c.f={},c.e=e=>Promise.all(Object.keys(c.f).reduce(((t,a)=>(c.f[a](e,t),t)),[])),c.u=e=>"assets/js/"+({22:"879054ab",53:"935f2afb",175:"c361d1eb",189:"186a3eb8",195:"c4f5d8e4",217:"b8d02a9c",242:"26929101",261:"cb4f4ca9",282:"96f6c49e",320:"b86d2c6e",373:"760264af",397:"13a5cec0",514:"1be78505",526:"fd321996",544:"a9d01d88",556:"39afbd6e",564:"976454a3",623:"5ae411f8",676:"2ae4ef1c",866:"ec4c2846",875:"444af13b",889:"7f2059f1",916:"f21858e6",918:"17896441",920:"1a4e3797",966:"4ab8a817",987:"8606c6a1",994:"53c1042e",996:"19b7f836"}[e]||e)+"."+{22:"39368577",53:"e90da8ff",175:"ee8bab92",189:"80ad5d61",195:"3eff4979",217:"bdf25ce5",242:"143c32d8",261:"983c3141",282:"b182a2f0",320:"82fd5222",373:"3ed61cd5",397:"36c4e731",443:"a35c493a",514:"79ca6d8a",523:"bb83377d",525:"ee7ff280",526:"f5d30c71",544:"0aefd47f",556:"81d00235",564:"7efa7a24",623:"9d713392",676:"152595fe",866:"de5833c1",875:"a37fbda4",889:"e7147378",916:"b12940cb",918:"e52e3593",920:"83cee253",966:"7d0118d3",972:"a79306f2",987:"f55d8fd1",994:"e1e7c39f",996:"98239486"}[e]+".js",c.miniCssF=e=>{},c.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),c.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r={},f="thingsgateway:",c.l=(e,t,a,o)=>{if(r[e])r[e].push(t);else{var n,i;if(void 0!==a)for(var d=document.getElementsByTagName("script"),b=0;b<d.length;b++){var u=d[b];if(u.getAttribute("src")==e||u.getAttribute("data-webpack")==f+a){n=u;break}}n||(i=!0,(n=document.createElement("script")).charset="utf-8",n.timeout=120,c.nc&&n.setAttribute("nonce",c.nc),n.setAttribute("data-webpack",f+a),n.src=e),r[e]=[t];var l=(t,a)=>{n.onerror=n.onload=null,clearTimeout(s);var f=r[e];if(delete r[e],n.parentNode&&n.parentNode.removeChild(n),f&&f.forEach((e=>e(a))),t)return t(a)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:n}),12e4);n.onerror=l.bind(null,n.onerror),n.onload=l.bind(null,n.onload),i&&document.head.appendChild(n)}},c.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},c.p="/thingsgateway/",c.gca=function(e){return e={17896441:"918",26929101:"242","879054ab":"22","935f2afb":"53",c361d1eb:"175","186a3eb8":"189",c4f5d8e4:"195",b8d02a9c:"217",cb4f4ca9:"261","96f6c49e":"282",b86d2c6e:"320","760264af":"373","13a5cec0":"397","1be78505":"514",fd321996:"526",a9d01d88:"544","39afbd6e":"556","976454a3":"564","5ae411f8":"623","2ae4ef1c":"676",ec4c2846:"866","444af13b":"875","7f2059f1":"889",f21858e6:"916","1a4e3797":"920","4ab8a817":"966","8606c6a1":"987","53c1042e":"994","19b7f836":"996"}[e]||e,c.p+c.u(e)},(()=>{var e={303:0,532:0};c.f.j=(t,a)=>{var r=c.o(e,t)?e[t]:void 0;if(0!==r)if(r)a.push(r[2]);else if(/^(303|532)$/.test(t))e[t]=0;else{var f=new Promise(((a,f)=>r=e[t]=[a,f]));a.push(r[2]=f);var o=c.p+c.u(t),n=new Error;c.l(o,(a=>{if(c.o(e,t)&&(0!==(r=e[t])&&(e[t]=void 0),r)){var f=a&&("load"===a.type?"missing":a.type),o=a&&a.target&&a.target.src;n.message="Loading chunk "+t+" failed.\n("+f+": "+o+")",n.name="ChunkLoadError",n.type=f,n.request=o,r[1](n)}}),"chunk-"+t,t)}},c.O.j=t=>0===e[t];var t=(t,a)=>{var r,f,o=a[0],n=a[1],i=a[2],d=0;if(o.some((t=>0!==e[t]))){for(r in n)c.o(n,r)&&(c.m[r]=n[r]);if(i)var b=i(c)}for(t&&t(a);d<o.length;d++)f=o[d],c.o(e,f)&&e[f]&&e[f][0](),e[f]=0;return c.O(b)},a=self.webpackChunkthingsgateway=self.webpackChunkthingsgateway||[];a.forEach(t.bind(null,0)),a.push=t.bind(null,a.push.bind(a))})()})();

View File

@@ -0,0 +1 @@
(()=>{"use strict";var e,t,a,r,f,o={},d={};function n(e){var t=d[e];if(void 0!==t)return t.exports;var a=d[e]={exports:{}};return o[e].call(a.exports,a,a.exports,n),a.exports}n.m=o,e=[],n.O=(t,a,r,f)=>{if(!a){var o=1/0;for(b=0;b<e.length;b++){a=e[b][0],r=e[b][1],f=e[b][2];for(var d=!0,c=0;c<a.length;c++)(!1&f||o>=f)&&Object.keys(n.O).every((e=>n.O[e](a[c])))?a.splice(c--,1):(d=!1,f<o&&(o=f));if(d){e.splice(b--,1);var i=r();void 0!==i&&(t=i)}}return t}f=f||0;for(var b=e.length;b>0&&e[b-1][2]>f;b--)e[b]=e[b-1];e[b]=[a,r,f]},n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},a=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,n.t=function(e,r){if(1&r&&(e=this(e)),8&r)return e;if("object"==typeof e&&e){if(4&r&&e.__esModule)return e;if(16&r&&"function"==typeof e.then)return e}var f=Object.create(null);n.r(f);var o={};t=t||[null,a({}),a([]),a(a)];for(var d=2&r&&e;"object"==typeof d&&!~t.indexOf(d);d=a(d))Object.getOwnPropertyNames(d).forEach((t=>o[t]=()=>e[t]));return o.default=()=>e,n.d(f,o),f},n.d=(e,t)=>{for(var a in t)n.o(t,a)&&!n.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},n.f={},n.e=e=>Promise.all(Object.keys(n.f).reduce(((t,a)=>(n.f[a](e,t),t)),[])),n.u=e=>"assets/js/"+({22:"879054ab",53:"935f2afb",175:"c361d1eb",189:"186a3eb8",195:"c4f5d8e4",217:"b8d02a9c",242:"26929101",261:"cb4f4ca9",282:"96f6c49e",320:"b86d2c6e",373:"760264af",397:"13a5cec0",514:"1be78505",526:"fd321996",544:"a9d01d88",556:"39afbd6e",564:"976454a3",593:"84ef20df",623:"5ae411f8",705:"46d61d03",866:"ec4c2846",874:"6dde87d0",875:"444af13b",889:"7f2059f1",916:"f21858e6",918:"17896441",920:"1a4e3797",946:"9a8d6690",966:"4ab8a817",987:"8606c6a1",994:"53c1042e",996:"19b7f836"}[e]||e)+"."+{22:"f2f9317e",53:"30ea2125",175:"ee8bab92",189:"24a97c3d",195:"3eff4979",217:"25449686",242:"143c32d8",261:"983c3141",282:"b182a2f0",320:"903ca3f1",373:"3ed61cd5",397:"36c4e731",443:"a35c493a",514:"79ca6d8a",523:"bb83377d",525:"ee7ff280",526:"f5d30c71",544:"0aefd47f",556:"73bcb94a",564:"a7b325a9",593:"b6365e51",623:"5d1d50cd",705:"b084f227",866:"de5833c1",874:"641bb477",875:"a37fbda4",889:"de3ea03b",916:"79872004",918:"e52e3593",920:"83cee253",946:"1f1d08eb",966:"7d0118d3",972:"a79306f2",987:"f55d8fd1",994:"8816391f",996:"7e71f890"}[e]+".js",n.miniCssF=e=>{},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r={},f="thingsgateway:",n.l=(e,t,a,o)=>{if(r[e])r[e].push(t);else{var d,c;if(void 0!==a)for(var i=document.getElementsByTagName("script"),b=0;b<i.length;b++){var u=i[b];if(u.getAttribute("src")==e||u.getAttribute("data-webpack")==f+a){d=u;break}}d||(c=!0,(d=document.createElement("script")).charset="utf-8",d.timeout=120,n.nc&&d.setAttribute("nonce",n.nc),d.setAttribute("data-webpack",f+a),d.src=e),r[e]=[t];var l=(t,a)=>{d.onerror=d.onload=null,clearTimeout(s);var f=r[e];if(delete r[e],d.parentNode&&d.parentNode.removeChild(d),f&&f.forEach((e=>e(a))),t)return t(a)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:d}),12e4);d.onerror=l.bind(null,d.onerror),d.onload=l.bind(null,d.onload),c&&document.head.appendChild(d)}},n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.p="/thingsgateway/",n.gca=function(e){return e={17896441:"918",26929101:"242","879054ab":"22","935f2afb":"53",c361d1eb:"175","186a3eb8":"189",c4f5d8e4:"195",b8d02a9c:"217",cb4f4ca9:"261","96f6c49e":"282",b86d2c6e:"320","760264af":"373","13a5cec0":"397","1be78505":"514",fd321996:"526",a9d01d88:"544","39afbd6e":"556","976454a3":"564","84ef20df":"593","5ae411f8":"623","46d61d03":"705",ec4c2846:"866","6dde87d0":"874","444af13b":"875","7f2059f1":"889",f21858e6:"916","1a4e3797":"920","9a8d6690":"946","4ab8a817":"966","8606c6a1":"987","53c1042e":"994","19b7f836":"996"}[e]||e,n.p+n.u(e)},(()=>{var e={303:0,532:0};n.f.j=(t,a)=>{var r=n.o(e,t)?e[t]:void 0;if(0!==r)if(r)a.push(r[2]);else if(/^(303|532)$/.test(t))e[t]=0;else{var f=new Promise(((a,f)=>r=e[t]=[a,f]));a.push(r[2]=f);var o=n.p+n.u(t),d=new Error;n.l(o,(a=>{if(n.o(e,t)&&(0!==(r=e[t])&&(e[t]=void 0),r)){var f=a&&("load"===a.type?"missing":a.type),o=a&&a.target&&a.target.src;d.message="Loading chunk "+t+" failed.\n("+f+": "+o+")",d.name="ChunkLoadError",d.type=f,d.request=o,r[1](d)}}),"chunk-"+t,t)}},n.O.j=t=>0===e[t];var t=(t,a)=>{var r,f,o=a[0],d=a[1],c=a[2],i=0;if(o.some((t=>0!==e[t]))){for(r in d)n.o(d,r)&&(n.m[r]=d[r]);if(c)var b=c(n)}for(t&&t(a);i<o.length;i++)f=o[i],n.o(e,f)&&e[f]&&e[f][0](),e[f]=0;return n.O(b)},a=self.webpackChunkthingsgateway=self.webpackChunkthingsgateway||[];a.forEach(t.bind(null,0)),a.push=t.bind(null,a.push.bind(a))})()})();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"><url><loc>https://diego2098.gitee.io/thingsgateway/search</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/05%E3%80%81%E7%BD%91%E5%85%B3%E9%85%8D%E7%BD%AE/collectdevice</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/05%E3%80%81%E7%BD%91%E5%85%B3%E9%85%8D%E7%BD%AE/otherconfig</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/05%E3%80%81%E7%BD%91%E5%85%B3%E9%85%8D%E7%BD%AE/plugincore</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/05%E3%80%81%E7%BD%91%E5%85%B3%E9%85%8D%E7%BD%AE/uploaddevice</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/05%E3%80%81%E7%BD%91%E5%85%B3%E9%85%8D%E7%BD%AE/variable</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/06%E3%80%81%E9%87%87%E9%9B%86%E9%A9%B1%E5%8A%A8%E8%AF%B4%E6%98%8E/modbus</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/06%E3%80%81%E9%87%87%E9%9B%86%E9%A9%B1%E5%8A%A8%E8%AF%B4%E6%98%8E/opcda</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/06%E3%80%81%E9%87%87%E9%9B%86%E9%A9%B1%E5%8A%A8%E8%AF%B4%E6%98%8E/opcua</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/07%E3%80%81%E4%B8%8A%E4%BC%A0%E9%A9%B1%E5%8A%A8%E8%AF%B4%E6%98%8E/ModbusServer</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/07%E3%80%81%E4%B8%8A%E4%BC%A0%E9%A9%B1%E5%8A%A8%E8%AF%B4%E6%98%8E/MqttClient</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/07%E3%80%81%E4%B8%8A%E4%BC%A0%E9%A9%B1%E5%8A%A8%E8%AF%B4%E6%98%8E/MqttServer</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/08%E3%80%81Demo/modbusdemo</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/08%E3%80%81Demo/modbusserverdemo</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/08%E3%80%81Demo/mqttclientdemo</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/08%E3%80%81Demo/mqttserverdemo</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/08%E3%80%81Demo/opcdademo</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/08%E3%80%81Demo/opcuademo</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/%E6%94%AF%E6%8C%81%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/quickstart</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/upgrade</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/</loc><changefreq>weekly</changefreq><priority>0.5</priority></url></urlset>
<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"><url><loc>https://diego2098.gitee.io/thingsgateway/search</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/03%E3%80%81%E6%94%AF%E6%8C%81%E9%A1%B9%E7%9B%AE%E4%B8%8EPro%E7%89%88%E8%AF%B4%E6%98%8E/%E6%94%AF%E6%8C%81%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/03%E3%80%81%E6%94%AF%E6%8C%81%E9%A1%B9%E7%9B%AE%E4%B8%8EPro%E7%89%88%E8%AF%B4%E6%98%8E/Pro</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/05%E3%80%81%E7%BD%91%E5%85%B3%E9%85%8D%E7%BD%AE/collectdevice</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/05%E3%80%81%E7%BD%91%E5%85%B3%E9%85%8D%E7%BD%AE/otherconfig</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/05%E3%80%81%E7%BD%91%E5%85%B3%E9%85%8D%E7%BD%AE/plugincore</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/05%E3%80%81%E7%BD%91%E5%85%B3%E9%85%8D%E7%BD%AE/uploaddevice</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/05%E3%80%81%E7%BD%91%E5%85%B3%E9%85%8D%E7%BD%AE/variable</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/06%E3%80%81%E9%87%87%E9%9B%86%E9%A9%B1%E5%8A%A8%E8%AF%B4%E6%98%8E/modbus</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/06%E3%80%81%E9%87%87%E9%9B%86%E9%A9%B1%E5%8A%A8%E8%AF%B4%E6%98%8E/opcda</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/06%E3%80%81%E9%87%87%E9%9B%86%E9%A9%B1%E5%8A%A8%E8%AF%B4%E6%98%8E/opcua</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/06%E3%80%81%E9%87%87%E9%9B%86%E9%A9%B1%E5%8A%A8%E8%AF%B4%E6%98%8E/Siemens</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/07%E3%80%81%E4%B8%8A%E4%BC%A0%E9%A9%B1%E5%8A%A8%E8%AF%B4%E6%98%8E/ModbusServer</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/07%E3%80%81%E4%B8%8A%E4%BC%A0%E9%A9%B1%E5%8A%A8%E8%AF%B4%E6%98%8E/MqttClient</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/07%E3%80%81%E4%B8%8A%E4%BC%A0%E9%A9%B1%E5%8A%A8%E8%AF%B4%E6%98%8E/MqttServer</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/07%E3%80%81%E4%B8%8A%E4%BC%A0%E9%A9%B1%E5%8A%A8%E8%AF%B4%E6%98%8E/RabbitMQClient</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/08%E3%80%81Demo/modbusdemo</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/08%E3%80%81Demo/modbusserverdemo</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/08%E3%80%81Demo/mqttclientdemo</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/08%E3%80%81Demo/mqttserverdemo</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/08%E3%80%81Demo/opcdademo</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/08%E3%80%81Demo/opcuademo</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/quickstart</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/docs/upgrade</loc><changefreq>weekly</changefreq><priority>0.5</priority></url><url><loc>https://diego2098.gitee.io/thingsgateway/</loc><changefreq>weekly</changefreq><priority>0.5</priority></url></urlset>

View File

@@ -12,9 +12,7 @@ import Tag from "@site/src/components/Tag.js";
ThingsGateway 由作者Diego及其他贡献者开发所有版权归作者Diego所有程序集源代码在遵循 Apache License 2.0 的开源协议以及**附加协议**下,可**免费**供其他开发者二次开发或(商业)使用。
# 附加协议
#### 个人使用须知:
### 个人使用须知:
- 不得将程序集用作违法犯罪活动。
- 不得将程序集单独包装售卖,申请专利等。
@@ -22,7 +20,7 @@ ThingsGateway 由作者Diego及其他贡献者开发所有版权归作者Dieg
**以上内容必须全部符合,个人使用授权才成立。**
#### 二次开发须知:
### 二次开发须知:
- 不得将程序集用作违法犯罪活动。
- 不得将程序集单独包装售卖,申请专利等。
@@ -32,13 +30,22 @@ ThingsGateway 由作者Diego及其他贡献者开发所有版权归作者Dieg
**以上内容必须全部符合,二次开发授权才成立。**
#### 盈利性(商业)用途使用须知:
### 盈利性(商业)用途使用须知:
- 不得将程序集用作违法犯罪活动。
- 不得将程序集单独包装售卖,申请专利等。
- **不得擦除程序集所有有关作者的信息,并必须于用户可见界面(如关于)中提名。**
**以上内容必须全部符合,使用授权才成立。**
**以上内容必须全部符合,商业使用授权才成立。**
## ThingsGatewayPro 商用许可
ThingsGatewayPro 软件框架与 ThingsGateway 一致另包含其他定制插件。所有版权归作者Diego所有。
ThingsGatewayPro 不公开开源,需要付费购买。
# 免责申明

View File

@@ -1,7 +1,7 @@
---
id: 支持开源项目
title: 支持开源项目
sidebar_label: 03、支持开源项目
sidebar_label: 3.1、支持开源项目
---
## 赞助ThingsGateway项目
@@ -14,8 +14,9 @@ sidebar_label: 03、支持开源项目
#### 赞助名单(以下排名只按照赞助时间顺序)
1. 绢10¥
2. 小蚂蚁 18.8¥)
1. 绢 10¥
2. 小蚂蚁 18.8¥+66.66¥
3. 伟 18.8¥)

View File

@@ -0,0 +1,45 @@
---
id: Pro
title: Pro版说明
sidebar_label: 3.2、Pro版说明
---
### 一、说明
ThingsGatewayPro是ThingsGateway的加强版本基础功能与ThingsGateway一致并添加一些额外功能插件
同时ThingsGatewayPro提供企业定制服务及必要的远程协助,具体收费可以咨询**作者Diego联系方式QQ2248356998**
### 二、授权
#### ThingsGatewayPro分为个人授权与企业授权区别在于授权归属
授权后获得证书凭据(图片形式)
#### 2.1 个人授权
- **授权归属于购买者个人所有**
- 价格 998¥
#### 2.2 企业授权
- **授权归属于企业所有,仅企业主体享有授权**
- 价格 998¥
### 三、插件差异
| 插件名称 | 说明 |
| ---------------| --------------------------|
| 待更新......| 待更新......|
### 四、购买
#### 购买途径
![](/img/pay.png)
# 请备注 - ThingsGatewayPro

View File

@@ -54,3 +54,5 @@ PORT=5432;DATABASE=SqlSugar4xTest;HOST=localhost;PASSWORD=haosql;USER ID=postgre
```
host=localhost;port=8812;username=admin;password=quest;database=qdb;ServerCompatibilityMode=NoTypeLoading;
```
QQ群里下载questdb.zip和QuestDB win启动bat文件,解压两个文件更改QuestDB win启动bat里的对应路径最后启动服务重启官网就可查的历史数据
![](/img/QuestdbSet.jpg)

View File

@@ -5,6 +5,8 @@ sidebar_label: 6.1、Modbus驱动
---
### (一)设备配置
1、Socket链路
| 属性 | 说明 | 默认值/备注|
| ---------------| --------------------------| ---|
| 连接超时时间 | 建立socket通讯的超时时间ms | 3000|
@@ -16,6 +18,19 @@ sidebar_label: 6.1、Modbus驱动
| 连接id检测 | 是否检查modbus的事务标识符和协议标识符为一致 | Flase |
| crc检测 | 是否检查modbus的事务标识符和协议标识符为一致 | True|
2、串口链路
| 属性 | 说明 | 默认值/备注|
| ---------------| --------------------------| ---|
| 默认解析顺序 | 4个字节以上的数据解析可设置为ABCD/BADC/CDBA/DCBA,默认ABCD |ABCDBig-Endian<br></br>BADCBig-Endian Byte Swap<br></br>CDABLittle-Endian Byte Swap<br></br>DCBALittle-Endian |
| COM口 | COM口 | COM1|
| 波特率 | | 9600|
| 数据位 | | 8|
| 校验位 | | None|
| 停止位 | | One|
| 默认站号 | 默认的mudbus站号id | 1|
| 读写超时时间 | 读取等待中的超时时间ms | 3000|
| crc检测 | 是否检查modbus的事务标识符和协议标识符为一致 | True|
### (二)变量配置
#### 变量地址说明

View File

@@ -3,6 +3,13 @@ id: opcda
title: OPCDA驱动
sidebar_label: 6.2、OPCDA驱动
---
:::tip `OPCDA驱动注意`
使用OPCDA插件时需安装OPC核心库[文件地址](https://gitee.com/diego2098/ThingsGateway/attach_files)
:::
### (一)设备配置
| 属性 | 说明 | 默认值/备注|

View File

@@ -0,0 +1,38 @@
---
id: Siemens
title: Siemens驱动
sidebar_label: 6.4、Siemens驱动
---
### (一)设备配置
| 属性 | 说明 | 默认值/备注|
| ---------------| --------------------------| ---|
| 连接超时时间 | 建立socket通讯的超时时间ms | 3000|
| 默认解析顺序 | 4个字节以上的数据解析可设置为ABCD/BADC/CDBA/DCBA,默认ABCD |ABCDBig-Endian<br></br>BADCBig-Endian Byte Swap<br></br>CDABLittle-Endian Byte Swap<br></br>DCBALittle-Endian |
| IP | 连接IP | 127.0.0.1|
| 端口 | 连接端口 | 102|
| 读写超时时间 | 读取等待中的超时时间ms | 3000|
| LocalTSAP | | 0 |
| DestTSAP | | 0|
### (二)变量配置
#### 变量地址说明
- 1、基本地址
| 地址 | 说明 |
| ---------------| --------------------------|
| Txxxxx | Timer寄存器,例如T100/T100.1 |
| Cxxxxx | Counter寄存器,例如C100/C100.1 |
| AIxxxxx | AI寄存器,例如AI100/AI100.1 |
| AQxxxxx | AQ寄存器,例如AQ100/AQ100.1 |
| Ixxxxx | I寄存器,例如I100/I100.1 |
| Qxxxxx | Q寄存器,例如Q100/Q100.1 |
| Mxxxxx | M寄存器,例如M100/M100.1 |
| DBxxxxx | DB寄存器,例如DB100.1/DB100.1.1 |
#### 变量特殊方法说明
无特殊方法

View File

@@ -76,7 +76,6 @@ Rpc返回Json
"activeTime": "2023-03-08T08:46:39.2708927+08:00",
"deviceStatus": 1,
"deviceOffMsg": "",
"intervalTime": 0,
"name": "ModbusTest",
"description": null,
"enable": true,

View File

@@ -72,7 +72,6 @@ Rpc返回Json
"activeTime": "2023-03-08T08:46:39.2708927+08:00",
"deviceStatus": 1,
"deviceOffMsg": "",
"intervalTime": 0,
"name": "ModbusTest",
"description": null,
"enable": true,

View File

@@ -0,0 +1,68 @@
---
id: RabbitMQClient
title: RabbitMQClient
sidebar_label: 7.4、RabbitMQClient
---
### (一)设备配置
| 属性 | 说明 | 默认值/备注|
| ---------------| --------------------------| ---|
| 账号 | 登录账号 | guest|
| 密码 | 登录密码 | guest|
| IP | 连接IP | 127.0.0.1|
| 端口 | 连接端口 | 5672|
| 虚拟Host | | / |
|路由名称 | |TG|
|变量队列名称| |ThingsGateway/Variable|
|设备队列名称| |ThingsGateway/Device|
|是否发布List| |False|
|是否声明队列| |False|
变量Json
```
[
{
"deviceName": "ModbusTest",
"rawValue": "12345",
"value": "12345",
"changeTime": "2023-03-08T08:42:36.1979048+08:00",
"collectTime": "2023-03-08T08:46:39.3070467+08:00",
"quality": 192,
"readExpressions": null,
"writeExpressions": null,
"intervalTime": 1000,
"otherMethod": null,
"variableAddress": "40001",
"name": "test40001",
"description": null,
"initialValue": null,
"protectTypeEnum": 1,
"dataTypeEnum": 7
}
]
```
设备Json:
```
[
{
"pluginName": "ThingsGateway.Modbus.ModbusTcp",
"deviceVariablesNum": 1,
"activeTime": "2023-03-08T08:46:39.2708927+08:00",
"deviceStatus": 1,
"deviceOffMsg": "",
"name": "ModbusTest",
"description": null,
"enable": true,
"createTime": "2023-03-06T17:31:23.0562652",
"updateTime": "0001-01-01T00:00:00"
}
]
```
### (二)变量配置

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

View File

@@ -57,8 +57,16 @@ namespace ThingsGateway.Foundation.Adapter.Modbus
{
try
{
if (response[1] >= 0x80)//错误码
return new OperResult<byte[]>(GetDescriptionByErrorCode(response[2]));
if (send.Length == 0)
{
var result = OperResult.CreateSuccessResult(GenericHelper.ArrayRemoveBegin(response, 3));
result.Message = "接收数据正确,但主机并没有主动请求数据";
result.ResultCode = ResultCode.Canceled;
return result;
}
if (send[0] != response[0])
return new OperResult<byte[]>(string.Format("站号不一致", send[0], response[0]));
if (send[1] != response[1])

View File

@@ -0,0 +1,109 @@
using System.Threading;
using System.Threading.Tasks;
using ThingsGateway.Foundation.Serial;
using TouchSocket.Resources;
namespace ThingsGateway.Foundation.Adapter.Modbus
{
public class ModbusRtu : ReadWriteDevicesSerialClientBase
{
public ModbusRtuDataHandleAdapter DataHandleAdapter = new();
public ModbusRtu(SerialClient serialClient) : base(serialClient)
{
ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big);
RegisterByteLength = 2;
}
public bool Crc16CheckEnable { get; set; }
public byte Station { get; set; } = 1;
public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken token = default)
{
try
{
await OpenAsync();
var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station);
if (commandResult.IsSuccess)
{
var item = commandResult.Content;
var result = await SerialClient.GetTGWaitingClient(new()).SendThenResponseAsync(item, TimeOut, token);
if (result.RequestInfo is MessageBase collectMessage)
{
return collectMessage;
}
}
else
{
return OperResult.CreateFailedResult<byte[]>(commandResult);
}
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
return new OperResult<byte[]>(TouchSocketStatus.UnknownError.GetDescription());
}
public override void SetDataAdapter()
{
DataHandleAdapter = new();
DataHandleAdapter.Crc16CheckEnable = Crc16CheckEnable;
SerialClient.SetDataHandlingAdapter(DataHandleAdapter);
}
public override async Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken token = default)
{
try
{
await OpenAsync();
var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station);
if (commandResult.IsSuccess)
{
var result = await SerialClient.GetTGWaitingClient(new()).SendThenResponseAsync(commandResult.Content, TimeOut, token);
if (result.RequestInfo is MessageBase collectMessage)
{
return collectMessage;
}
}
else
{
return OperResult.CreateFailedResult<bool[]>(commandResult);
}
}
catch (Exception ex)
{
return new OperResult<bool[]>(ex);
}
return new OperResult<byte[]>(TouchSocketStatus.UnknownError.GetDescription());
}
public override async Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken token = default)
{
try
{
await OpenAsync();
var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station);
if (commandResult.IsSuccess)
{
var result = await SerialClient.GetTGWaitingClient(new()).SendThenResponseAsync(commandResult.Content, TimeOut, token);
if (result.RequestInfo is MessageBase collectMessage)
{
return collectMessage;
}
}
else
{
return OperResult.CreateFailedResult<bool[]>(commandResult);
}
}
catch (Exception ex)
{
return new OperResult<bool[]>(ex);
}
return new OperResult<byte[]>(TouchSocketStatus.UnknownError.GetDescription());
}
}
}

View File

@@ -0,0 +1,23 @@
namespace ThingsGateway.Foundation.Adapter.Modbus
{
public class ModbusRtuDataHandleAdapter : ReadWriteDevicesSerialDataHandleAdapter<ModbusRtuMessage>
{
public bool Crc16CheckEnable { get; set; } = true;
public override byte[] PackCommand(byte[] command)
{
return ModbusHelper.AddCrc(command);
}
protected override ModbusRtuMessage GetInstance()
{
return new ModbusRtuMessage();
}
protected override OperResult<byte[]> UnpackResponse(
byte[] send, byte[] response)
{
return ModbusHelper.GetModbusRtuData(send, response, Crc16CheckEnable);
}
}
}

View File

@@ -28,7 +28,7 @@ namespace ThingsGateway.Foundation.Adapter.Modbus
if (commandResult.IsSuccess)
{
var item = commandResult.Content;
var result = await TcpClient.GetWaitingClient(new()).SendThenResponseAsync(item, TimeOut, token);
var result = await TcpClient.GetTGWaitingClient(new()).SendThenResponseAsync(item, TimeOut, token);
if (result.RequestInfo is MessageBase collectMessage)
{
return collectMessage;
@@ -60,7 +60,7 @@ namespace ThingsGateway.Foundation.Adapter.Modbus
var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station);
if (commandResult.IsSuccess)
{
var result = await TcpClient.GetWaitingClient(new()).SendThenResponseAsync(commandResult.Content, TimeOut, token);
var result = await TcpClient.GetTGWaitingClient(new()).SendThenResponseAsync(commandResult.Content, TimeOut, token);
if (result.RequestInfo is MessageBase collectMessage)
{
return collectMessage;
@@ -86,7 +86,7 @@ namespace ThingsGateway.Foundation.Adapter.Modbus
var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station);
if (commandResult.IsSuccess)
{
var result = await TcpClient.GetWaitingClient(new()).SendThenResponseAsync(commandResult.Content, TimeOut, token);
var result = await TcpClient.GetTGWaitingClient(new()).SendThenResponseAsync(commandResult.Content, TimeOut, token);
if (result.RequestInfo is MessageBase collectMessage)
{
return collectMessage;

View File

@@ -28,7 +28,7 @@ namespace ThingsGateway.Foundation.Adapter.Modbus
if (commandResult.IsSuccess)
{
var item = commandResult.Content;
var result = await UdpSession.GetWaitingClient(new()).SendThenResponseAsync(item, TimeOut, token);
var result = await UdpSession.GetTGWaitingClient(new()).SendThenResponseAsync(item, TimeOut, token);
if (result.RequestInfo is MessageBase collectMessage)
{
return collectMessage;
@@ -60,7 +60,7 @@ namespace ThingsGateway.Foundation.Adapter.Modbus
var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station);
if (commandResult.IsSuccess)
{
var result = await UdpSession.GetWaitingClient(new()).SendThenResponseAsync(commandResult.Content, TimeOut, token);
var result = await UdpSession.GetTGWaitingClient(new()).SendThenResponseAsync(commandResult.Content, TimeOut, token);
if (result.RequestInfo is MessageBase collectMessage)
{
return collectMessage;
@@ -86,7 +86,7 @@ namespace ThingsGateway.Foundation.Adapter.Modbus
var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station);
if (commandResult.IsSuccess)
{
var result = await UdpSession.GetWaitingClient(new()).SendThenResponseAsync(commandResult.Content, TimeOut, token);
var result = await UdpSession.GetTGWaitingClient(new()).SendThenResponseAsync(commandResult.Content, TimeOut, token);
if (result.RequestInfo is MessageBase collectMessage)
{
return collectMessage;

View File

@@ -27,7 +27,7 @@ namespace ThingsGateway.Foundation.Adapter.Modbus
if (commandResult.IsSuccess)
{
var item = commandResult.Content;
var result = TcpClient.GetWaitingClient(new()).SendThenResponse(item, TimeOut, token);
var result = TcpClient.GetTGWaitingClient(new()).SendThenResponse(item, TimeOut, token);
if (result.RequestInfo is MessageBase collectMessage)
{
return collectMessage;
@@ -60,7 +60,7 @@ namespace ThingsGateway.Foundation.Adapter.Modbus
var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station);
if (commandResult.IsSuccess)
{
var result = TcpClient.GetWaitingClient(new()).SendThenResponse(commandResult.Content, TimeOut, token);
var result = TcpClient.GetTGWaitingClient(new()).SendThenResponse(commandResult.Content, TimeOut, token);
if (result.RequestInfo is MessageBase collectMessage)
{
return collectMessage;
@@ -87,7 +87,7 @@ namespace ThingsGateway.Foundation.Adapter.Modbus
var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station);
if (commandResult.IsSuccess)
{
var result = TcpClient.GetWaitingClient(new()).SendThenResponse(commandResult.Content, TimeOut, token);
var result = TcpClient.GetTGWaitingClient(new()).SendThenResponse(commandResult.Content, TimeOut, token);
if (result.RequestInfo is MessageBase collectMessage)
{
return collectMessage;

View File

@@ -27,7 +27,7 @@ namespace ThingsGateway.Foundation.Adapter.Modbus
if (commandResult.IsSuccess)
{
var item = commandResult.Content;
var result = UdpSession.GetWaitingClient(new()).SendThenResponse(item, TimeOut, token);
var result = UdpSession.GetTGWaitingClient(new()).SendThenResponse(item, TimeOut, token);
if (result.RequestInfo is MessageBase collectMessage)
{
return collectMessage;
@@ -60,7 +60,7 @@ namespace ThingsGateway.Foundation.Adapter.Modbus
var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station);
if (commandResult.IsSuccess)
{
var result = UdpSession.GetWaitingClient(new()).SendThenResponse(commandResult.Content, TimeOut, token);
var result = UdpSession.GetTGWaitingClient(new()).SendThenResponse(commandResult.Content, TimeOut, token);
if (result.RequestInfo is MessageBase collectMessage)
{
return collectMessage;
@@ -87,7 +87,7 @@ namespace ThingsGateway.Foundation.Adapter.Modbus
var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station);
if (commandResult.IsSuccess)
{
var result = UdpSession.GetWaitingClient(new()).SendThenResponse(commandResult.Content, TimeOut, token);
var result = UdpSession.GetTGWaitingClient(new()).SendThenResponse(commandResult.Content, TimeOut, token);
if (result.RequestInfo is MessageBase collectMessage)
{
return collectMessage;

View File

@@ -3,11 +3,11 @@
<PropertyGroup>
<LangVersion>latestMajor</LangVersion>
<TargetFrameworks>net4.6.2;net6.0;net7.0</TargetFrameworks>
<Version>1.0.3</Version>
<Version>1.0.5</Version>
<Title>ThingsGateway.Foundation.Adapter.Modbus</Title>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Authors>Diego</Authors>
<Description>Modbus通讯类库支持MdobusTcp;ModbusRtuOverTcp;ModbusTcpServer</Description>
<Description>Modbus通讯类库支持MdobusTcp;ModbusRtu;ModbusRtuOverTcp;ModbusTcpServer</Description>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
<RunAnalyzersDuringBuild>True</RunAnalyzersDuringBuild>

View File

@@ -1,5 +1,6 @@
using OpcDaClient.Da;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
@@ -9,8 +10,6 @@ using System.Timers;
using ThingsGateway.Foundation.Extension;
using ThingsGateway.Foundation.Extension.Json;
using TouchSocket.Core;
using Timer = System.Timers.Timer;
//部分非托管交互代码来自https://gitee.com/Zer0Day/opc-client与OPC基金会opcnet库更改部分逻辑
@@ -29,7 +28,7 @@ namespace ThingsGateway.Foundation.Adapter.OPCDA
private List<OpcGroup> Groups = new();
private int IsQuit = 1;
private OpcServer m_server;
private IntelligentConcurrentQueue<ItemReadResult> results = new IntelligentConcurrentQueue<ItemReadResult>(100000);
private ConcurrentQueue<ItemReadResult> results = new ConcurrentQueue<ItemReadResult>();
private Dictionary<string, List<OpcItem>> Tags = new();
//定义组对象(订阅者)
public OPCDAClient(ILog logger)
@@ -285,7 +284,7 @@ namespace ThingsGateway.Foundation.Adapter.OPCDA
while (!DisposedValue)
{
if (results.Count > 0)
DataChangedHandler?.Invoke(results.ToListWithDequeue(results.Count));
DataChangedHandler?.Invoke(results.ToListWithDequeue());
if (OPCNode == null)
await Task.Delay(1000);
else

View File

@@ -3,7 +3,7 @@
<PropertyGroup>
<LangVersion>latestMajor</LangVersion>
<TargetFrameworks>net4.6.2;net6.0;net7.0</TargetFrameworks>
<Version>1.0.3</Version>
<Version>1.0.5</Version>
<Platforms>AnyCPU</Platforms>
<OutputType>Library</OutputType>

View File

@@ -1,6 +1,7 @@
using Opc.Ua;
using Opc.Ua.Client;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@@ -21,7 +22,7 @@ public class OPCUAClient : DisposableObject
private EventHandler m_ConnectComplete;
private IntelligentConcurrentQueue<(MonitoredItem, MonitoredItemNotification)> m_data = new(100000);
private ConcurrentQueue<(MonitoredItem, MonitoredItemNotification)> m_data = new();
private bool m_IsConnected;
private EventHandler m_KeepAliveComplete;
@@ -1415,7 +1416,7 @@ public class OPCUAClient : DisposableObject
while (!DisposedValue)
{
if (m_data.Count > 0)
DataChangedHandler?.Invoke(m_data.ToListWithDequeue(m_data.Count));
DataChangedHandler?.Invoke(m_data.ToListWithDequeue());
if (OPCNode == null)
await Task.Delay(1000);
else

View File

@@ -3,7 +3,7 @@
<PropertyGroup>
<LangVersion>latestMajor</LangVersion>
<TargetFrameworks>net4.6.2;net6.0;net7.0</TargetFrameworks>
<Version>1.0.3</Version>
<Version>1.0.5</Version>
<Platforms>AnyCPU</Platforms>
<OutputType>Library</OutputType>

View File

@@ -0,0 +1 @@
global using System;

View File

@@ -0,0 +1,225 @@
namespace ThingsGateway.Foundation.Adapter.Siemens
{
public enum S7Area : byte
{
PE = 0x81,
PA = 0x82,
MK = 0x83,
DB = 0x84,
CT = 0x1C,
TM = 0x1D,
AI = 0X06,
AQ = 0x07,
}
/// <summary>
/// 西门子PLC地址数据信息
/// </summary>
public class SiemensAddress : DeviceAddressBase
{
/// <summary>
/// 数据块代码
/// </summary>
public byte DataCode { get; set; }
/// <summary>
/// DB块数据信息
/// </summary>
public ushort DbBlock { get; set; }
public static int GetAddressStart(string address, bool isCounterOrTimer = false)
{
if (address.IndexOf('.') < 0)
{
return isCounterOrTimer ? Convert.ToInt32(address) : Convert.ToInt32(address) * 8;
}
string[] strArray = address.Split('.');
return (Convert.ToInt32(strArray[0]) * 8) + Convert.ToInt32(strArray[1]);
}
public static OperResult<SiemensAddress> ParseFrom(string address)
{
return ParseFrom(address, 0);
}
public static OperResult<SiemensAddress> ParseFrom(string address, int length)
{
SiemensAddress s7AddressData = new SiemensAddress();
try
{
address = address.ToUpper();
s7AddressData.Length = length;
s7AddressData.DbBlock = 0;
if (address.StartsWith("AI"))
{
s7AddressData.DataCode = (byte)S7Area.AI;
if (address.StartsWith("AIX") || address.StartsWith("AIB") || address.StartsWith("AIW") || address.StartsWith("AID"))
{
s7AddressData.AddressStart = GetAddressStart(address.Substring(3));
}
else
{
s7AddressData.AddressStart = GetAddressStart(address.Substring(2));
}
}
else if (address.StartsWith("AQ"))
{
s7AddressData.DataCode = (byte)S7Area.AQ;
if (address.StartsWith("AQX") || address.StartsWith("AQB") || address.StartsWith("AQW") || address.StartsWith("AQD"))
{
s7AddressData.AddressStart = GetAddressStart(address.Substring(3));
}
else
{
s7AddressData.AddressStart = GetAddressStart(address.Substring(2));
}
}
else if (address[0] == 'I')
{
s7AddressData.DataCode = (byte)S7Area.PE;
if (address.StartsWith("IX") || address.StartsWith("IB") || address.StartsWith("IW") || address.StartsWith("ID"))
{
s7AddressData.AddressStart = GetAddressStart(address.Substring(2));
}
else
{
s7AddressData.AddressStart = GetAddressStart(address.Substring(1));
}
}
else if (address[0] == 'Q')
{
s7AddressData.DataCode = (byte)S7Area.PA;
if (address.StartsWith("QX") || address.StartsWith("QB") || address.StartsWith("QW") || address.StartsWith("QD"))
{
s7AddressData.AddressStart = GetAddressStart(address.Substring(2));
}
else
{
s7AddressData.AddressStart = GetAddressStart(address.Substring(1));
}
}
else if (address[0] == 'M')
{
s7AddressData.DataCode = (byte)S7Area.MK;
if (address.StartsWith("MX") || address.StartsWith("MB") || address.StartsWith("MW") || address.StartsWith("MD"))
{
s7AddressData.AddressStart = GetAddressStart(address.Substring(2));
}
else
{
s7AddressData.AddressStart = GetAddressStart(address.Substring(1));
}
}
else if (address[0] == 'D' || address.Substring(0, 2) == "DB")
{
s7AddressData.DataCode = (byte)S7Area.DB;
string[] strArray = address.Split('.');
s7AddressData.DbBlock = address[1] != 'B' ? Convert.ToUInt16(strArray[0].Substring(1)) : Convert.ToUInt16(strArray[0].Substring(2));
string address1 = address.Substring(address.IndexOf('.') + 1);
if (address1.StartsWith("DBX") || address1.StartsWith("DBB") || address1.StartsWith("DBW") || address1.StartsWith("DBD"))
{
address1 = address1.Substring(3);
}
s7AddressData.AddressStart = GetAddressStart(address1);
}
else if (address[0] == 'T')
{
s7AddressData.DataCode = (byte)S7Area.TM;
s7AddressData.AddressStart = GetAddressStart(address.Substring(1), true);
}
else if (address[0] == 'C')
{
s7AddressData.DataCode = (byte)S7Area.CT;
s7AddressData.AddressStart = GetAddressStart(address.Substring(1), true);
}
else
{
if (address[0] != 'V')
{
return new OperResult<SiemensAddress>("不支持的类型");
}
s7AddressData.DataCode = (byte)S7Area.DB;
s7AddressData.DbBlock = 1;
if (address.StartsWith("VB") || address.StartsWith("VW") || address.StartsWith("VD") || address.StartsWith("VX"))
{
s7AddressData.AddressStart = GetAddressStart(address.Substring(2));
}
else
{
s7AddressData.AddressStart = GetAddressStart(address.Substring(1));
}
}
}
catch (Exception ex)
{
return new OperResult<SiemensAddress>(ex.Message);
}
return OperResult.CreateSuccessResult<SiemensAddress>(s7AddressData);
}
public override void Parse(string address, int length)
{
OperResult<SiemensAddress> from = ParseFrom(address, length);
if (!from.IsSuccess)
{
return;
}
AddressStart = from.Content.AddressStart;
Length = from.Content.Length;
DataCode = from.Content.DataCode;
DbBlock = from.Content.DbBlock;
}
/// <inheritdoc />
public override string ToString()
{
if (DataCode == (byte)S7Area.TM)
{
return "T" + AddressStart.ToString();
}
if (DataCode == (byte)S7Area.CT)
{
return "C" + AddressStart.ToString();
}
if (DataCode == (byte)S7Area.AI)
{
return "AI" + GetStringAddress(AddressStart);
}
if (DataCode == (byte)S7Area.AQ)
{
return "AQ" + GetStringAddress(AddressStart);
}
if (DataCode == (byte)S7Area.PE)
{
return "I" + GetStringAddress(AddressStart);
}
if (DataCode == (byte)S7Area.PA)
{
return "Q" + GetStringAddress(AddressStart);
}
if (DataCode == (byte)S7Area.MK)
{
return "M" + GetStringAddress(AddressStart);
}
return DataCode == (byte)S7Area.DB ? "DB" + DbBlock.ToString() + "." + GetStringAddress(AddressStart) : AddressStart.ToString();
}
private static string GetStringAddress(int addressStart)
{
return addressStart % 8 == 0 ? (addressStart / 8).ToString() : string.Format("{0}.{1}", addressStart / 8, addressStart % 8);
}
}
}

View File

@@ -0,0 +1,157 @@
using System.Collections.Generic;
namespace ThingsGateway.Foundation.Adapter.Siemens
{
/// <summary>
/// https://github.com/S7NetPlus/s7netplus/blob/develop/S7.Net/Types/DateTime.cs
/// Contains the methods to convert between <see cref="T:System.DateTime"/> and S7 representation of datetime values.
/// </summary>
public static class DateTime
{
/// <summary>
/// The minimum <see cref="T:System.DateTime"/> value supported by the specification.
/// </summary>
public static readonly System.DateTime SpecMinimumDateTime = new System.DateTime(1990, 1, 1);
/// <summary>
/// The maximum <see cref="T:System.DateTime"/> value supported by the specification.
/// </summary>
public static readonly System.DateTime SpecMaximumDateTime = new System.DateTime(2089, 12, 31, 23, 59, 59, 999);
/// <summary>
/// Parses a <see cref="T:System.DateTime"/> value from bytes.
/// </summary>
/// <param name="bytes">Input bytes read from PLC.</param>
/// <returns>A <see cref="T:System.DateTime"/> object representing the value read from PLC.</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when the length of
/// <paramref name="bytes"/> is not 8 or any value in <paramref name="bytes"/>
/// is outside the valid range of values.</exception>
public static System.DateTime FromByteArray(byte[] bytes)
{
return FromByteArrayImpl(bytes);
}
/// <summary>
/// Parses an array of <see cref="T:System.DateTime"/> values from bytes.
/// </summary>
/// <param name="bytes">Input bytes read from PLC.</param>
/// <returns>An array of <see cref="T:System.DateTime"/> objects representing the values read from PLC.</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when the length of
/// <paramref name="bytes"/> is not a multiple of 8 or any value in
/// <paramref name="bytes"/> is outside the valid range of values.</exception>
public static System.DateTime[] ToArray(byte[] bytes)
{
if (bytes.Length % 8 != 0)
throw new ArgumentOutOfRangeException(nameof(bytes), bytes.Length,
$"Parsing an array of DateTime requires a multiple of 8 bytes of input data, input data is '{bytes.Length}' long.");
var cnt = bytes.Length / 8;
var result = new System.DateTime[bytes.Length / 8];
for (var i = 0; i < cnt; i++)
result[i] = FromByteArrayImpl(new ArraySegment<byte>(bytes, i * 8, 8));
return result;
}
private static System.DateTime FromByteArrayImpl(IList<byte> bytes)
{
if (bytes.Count != 8)
throw new ArgumentOutOfRangeException(nameof(bytes), bytes.Count,
$"Parsing a DateTime requires exactly 8 bytes of input data, input data is {bytes.Count} bytes long.");
int DecodeBcd(byte input) => 10 * (input >> 4) + (input & 0b00001111);
int ByteToYear(byte bcdYear)
{
var input = DecodeBcd(bcdYear);
if (input < 90) return input + 2000;
if (input < 100) return input + 1900;
throw new ArgumentOutOfRangeException(nameof(bcdYear), bcdYear,
$"Value '{input}' is higher than the maximum '99' of S7 date and time representation.");
}
int AssertRangeInclusive(int input, byte min, byte max, string field)
{
if (input < min)
throw new ArgumentOutOfRangeException(nameof(input), input,
$"Value '{input}' is lower than the minimum '{min}' allowed for {field}.");
if (input > max)
throw new ArgumentOutOfRangeException(nameof(input), input,
$"Value '{input}' is higher than the maximum '{max}' allowed for {field}.");
return input;
}
var year = ByteToYear(bytes[0]);
var month = AssertRangeInclusive(DecodeBcd(bytes[1]), 1, 12, "month");
var day = AssertRangeInclusive(DecodeBcd(bytes[2]), 1, 31, "day of month");
var hour = AssertRangeInclusive(DecodeBcd(bytes[3]), 0, 23, "hour");
var minute = AssertRangeInclusive(DecodeBcd(bytes[4]), 0, 59, "minute");
var second = AssertRangeInclusive(DecodeBcd(bytes[5]), 0, 59, "second");
var hsec = AssertRangeInclusive(DecodeBcd(bytes[6]), 0, 99, "first two millisecond digits");
var msec = AssertRangeInclusive(bytes[7] >> 4, 0, 9, "third millisecond digit");
var dayOfWeek = AssertRangeInclusive(bytes[7] & 0b00001111, 1, 7, "day of week");
return new System.DateTime(year, month, day, hour, minute, second, hsec * 10 + msec);
}
/// <summary>
/// Converts a <see cref="T:System.DateTime"/> value to a byte array.
/// </summary>
/// <param name="dateTime">The DateTime value to convert.</param>
/// <returns>A byte array containing the S7 date time representation of <paramref name="dateTime"/>.</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when the value of
/// <paramref name="dateTime"/> is before <see cref="P:SpecMinimumDateTime"/>
/// or after <see cref="P:SpecMaximumDateTime"/>.</exception>
public static byte[] ToByteArray(System.DateTime dateTime)
{
byte EncodeBcd(int value)
{
return (byte)((value / 10 << 4) | value % 10);
}
if (dateTime < SpecMinimumDateTime)
throw new ArgumentOutOfRangeException(nameof(dateTime), dateTime,
$"Date time '{dateTime}' is before the minimum '{SpecMinimumDateTime}' supported in S7 date time representation.");
if (dateTime > SpecMaximumDateTime)
throw new ArgumentOutOfRangeException(nameof(dateTime), dateTime,
$"Date time '{dateTime}' is after the maximum '{SpecMaximumDateTime}' supported in S7 date time representation.");
byte MapYear(int year) => (byte)(year < 2000 ? year - 1900 : year - 2000);
int DayOfWeekToInt(DayOfWeek dayOfWeek) => (int)dayOfWeek + 1;
return new[]
{
EncodeBcd(MapYear(dateTime.Year)),
EncodeBcd(dateTime.Month),
EncodeBcd(dateTime.Day),
EncodeBcd(dateTime.Hour),
EncodeBcd(dateTime.Minute),
EncodeBcd(dateTime.Second),
EncodeBcd(dateTime.Millisecond / 10),
(byte) (dateTime.Millisecond % 10 << 4 | DayOfWeekToInt(dateTime.DayOfWeek))
};
}
/// <summary>
/// Converts an array of <see cref="T:System.DateTime"/> values to a byte array.
/// </summary>
/// <param name="dateTimes">The DateTime values to convert.</param>
/// <returns>A byte array containing the S7 date time representations of <paramref name="dateTime"/>.</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when any value of
/// <paramref name="dateTimes"/> is before <see cref="P:SpecMinimumDateTime"/>
/// or after <see cref="P:SpecMaximumDateTime"/>.</exception>
public static byte[] ToByteArray(System.DateTime[] dateTimes)
{
var bytes = new List<byte>(dateTimes.Length * 8);
foreach (var dateTime in dateTimes) bytes.AddRange(ToByteArray(dateTime));
return bytes.ToArray();
}
}
}

View File

@@ -0,0 +1,369 @@
using System.Text;
using System.Threading.Tasks;
using ThingsGateway.Foundation.Extension;
namespace ThingsGateway.Foundation.Adapter.Siemens
{
internal partial class SiemensHelper
{
#region
//internal static OperResult<byte[]> AnalysisReadBit(byte[] content)
//{
// int length = 1;
// if (content.Length < 21 || content[20] != 1)
// return new OperResult<byte[]>("数据块长度校验失败");
// byte[] numArray = new byte[length];
// if (content[21] == byte.MaxValue && content[22] == 3)//Bit:3;Byte:4;Counter或者Timer:9
// {
// numArray[0] = content[25];//+4
// }
// else
// {
// return new OperResult<byte[]>((int)content[21] + GetCpuError(content[21]));
// }
// return OperResult.CreateSuccessResult<byte[]>(numArray);
//}
internal static OperResult<byte[]> AnalysisReadByte(byte[] sends, byte[] content)
{
int length = 0;
int itemLen = (sends.Length - 19) / 12;
for (int index = 0; index < itemLen; index++)
{
if (sends[22 + (index * 12)] >= (byte)S7WordLength.Word)
{
length += ((sends[23 + (index * 12)] * 256) + sends[24 + (index * 12)]) * 2;
}
else
{
length += (sends[23 + (index * 12)] * 256) + sends[24 + (index * 12)];
}
}
if (content.Length < 21 || content[20] != itemLen)
{
return new OperResult<byte[]>("数据块长度校验失败");
}
byte[] dataArray = new byte[length];
int index1 = 0;
int dataIndex = 0;
for (int index2 = 21; index2 < content.Length; index2++)
{
if (index2 + 1 < content.Length)
{
int s7len = 0;
if (sends[22 + (index1 * 12)] >= (byte)S7WordLength.Word)
{
s7len = ((sends[23 + (index1 * 12)] * 256) + sends[24 + (index1 * 12)]) * 2;
}
else
{
s7len = (sends[23 + (index1 * 12)] * 256) + sends[24 + (index1 * 12)];
}
if (content[index2] == byte.MaxValue && content[index2 + 1] == 4)//Bit:3;Byte:4;Counter或者Timer:9
{
Array.Copy(content, index2 + 4, dataArray, dataIndex, s7len);
index2 += s7len + 3;
dataIndex += s7len;
index1++;
}
else if (content[index2] == byte.MaxValue && content[index2 + 1] == 9)//Counter或者Timer:9
{
int num = (content[index2 + 2] * 256) + content[index2 + 3];
if (num % 3 == 0)
{
for (int index3 = 0; index3 < num / 3; index3++)
{
Array.Copy(content, index2 + 5 + (3 * index3), dataArray, dataIndex, 2);
dataIndex += 2;
}
}
else
{
for (int index4 = 0; index4 < num / 5; index4++)
{
Array.Copy(content, index2 + 7 + (5 * index4), dataArray, dataIndex, 2);
dataIndex += 2;
}
}
index2 += num + 4;
index1++;
}
else
{
return new OperResult<byte[]>((int)content[index2] + GetCpuError(content[index2]));
}
}
}
return OperResult.CreateSuccessResult(dataArray);
}
internal static OperResult<byte[]> AnalysisWrite(byte[] content)
{
if (content.Length < 22)
{
return new OperResult<byte[]>(content) { Message = "未知错误" };
}
byte err = content[21];
if (err == byte.MaxValue)
{
return new OperResult<byte[]>((int)content[21] + GetCpuError(content[21]));
}
else
{
return OperResult.CreateSuccessResult(content);
}
}
private static string GetCpuError(ushort Error)
{
switch (Error)
{
case 0x05: return "地址超限";
case 0x06: return "返回长度无效";
case 0x07: return "数据大小不匹配";
case 0x0a:
case 0xd209: return "数据块不存在";
case 0x8500: return "超出PDU大小";
case 0xdc01: return "无效的值";
case 0x8104: return "功能不可用";
case 0xd241: return "需要密码";
case 0xd602: return "无效密码";
case 0xd604:
case 0xd605: return "没有设置密码或已清除";
default:
return "未知错误";
};
}
#endregion
#region
internal static OperResult<byte[]> GetReadCommand(SiemensAddress[] siemensAddress)
{
if (siemensAddress == null)
{
return new OperResult<byte[]>("地址为null");
}
int len = siemensAddress.Length <= 19 ? siemensAddress.Length : throw new Exception("读取数量大于19!");
int telegramLen = len * 12 + 19;
int parameterLen = len * 12 + 2;
byte[] numArray = new byte[telegramLen];
Array.Copy(S7_MULRW_HEADER, 0, numArray, 0, S7_MULRW_HEADER.Length);
numArray[2] = (byte)(telegramLen / 256);
numArray[3] = (byte)(telegramLen % 256);
numArray[13] = (byte)(parameterLen / 256);
numArray[14] = (byte)(parameterLen % 256);
numArray[18] = (byte)len;
for (int index = 0; index < len; index++)
{
Array.Copy(S7_MULRD_ITEM, 0, numArray, 19 + (index * 12), S7_MULRD_ITEM.Length);
if (siemensAddress[index].DataCode == (byte)S7WordLength.Counter || siemensAddress[index].DataCode == (byte)S7WordLength.Timer)
{
numArray[22 + (index * 12)] = siemensAddress[index].DataCode;
numArray[23 + (index * 12)] = (byte)(siemensAddress[index].Length / 256);
numArray[24 + (index * 12)] = (byte)(siemensAddress[index].Length % 256);
}
else
{
numArray[22 + (index * 12)] = (byte)S7WordLength.Byte;
numArray[23 + (index * 12)] = (byte)(siemensAddress[index].Length / 256);
numArray[24 + (index * 12)] = (byte)(siemensAddress[index].Length % 256);
}
numArray[25 + (index * 12)] = (byte)(siemensAddress[index].DbBlock / 256U);
numArray[26 + (index * 12)] = (byte)(siemensAddress[index].DbBlock % 256U);
numArray[27 + (index * 12)] = siemensAddress[index].DataCode;
numArray[28 + (index * 12)] = (byte)(siemensAddress[index].AddressStart / 256 / 256 % 256);
numArray[29 + (index * 12)] = (byte)(siemensAddress[index].AddressStart / 256 % 256);
numArray[30 + (index * 12)] = (byte)(siemensAddress[index].AddressStart % 256);
}
return OperResult.CreateSuccessResult(numArray);
}
internal static OperResult<byte[]> GetWriteBitCommand(SiemensAddress address, bool data)
{
int len = 1;
int telegramLen = 16 + 19 + len;//最后的1是写入值的byte数量
int parameterLen = 12 + 2;
byte[] numArray = new byte[telegramLen];
Array.Copy(S7_MULRW_HEADER, 0, numArray, 0, S7_MULRW_HEADER.Length);
numArray[2] = (byte)(telegramLen / 256);
numArray[3] = (byte)(telegramLen % 256);
numArray[13] = (byte)(parameterLen / 256);
numArray[14] = (byte)(parameterLen % 256);
numArray[15] = (byte)((4 + len) / 256);
numArray[16] = (byte)((4 + len) % 256);
numArray[17] = 5;
numArray[18] = (byte)1;
//写入Item与读取大致相同
numArray[19] = (byte)18;
numArray[20] = (byte)10;
numArray[21] = (byte)16;
numArray[22] = (byte)S7WordLength.Bit;
numArray[23] = (byte)(len / 256);
numArray[24] = (byte)(len % 256);
numArray[25] = (byte)(address.DbBlock / 256U);
numArray[26] = (byte)(address.DbBlock % 256U);
numArray[27] = (byte)address.DataCode;
numArray[28] = (byte)(address.AddressStart / 256 / 256);
numArray[29] = (byte)(address.AddressStart / 256);
numArray[30] = (byte)(address.AddressStart % 256);
//后面跟的是写入的数据信息
numArray[31] = 0;
numArray[32] = 3;//Bit:3;Byte:4;Counter或者Timer:9
numArray[33] = (byte)(len / 256);
numArray[34] = (byte)(len % 256);
numArray[35] = (byte)(data ? 1 : 0);
return OperResult.CreateSuccessResult(numArray);
}
internal static OperResult<byte[]> GetWriteByteCommand(SiemensAddress address, byte[] data)
{
int len = data.Length;
int telegramLen = 16 + 19 + len;//最后的1是写入值的byte数量
int parameterLen = 12 + 2;
byte[] numArray = new byte[telegramLen];
Array.Copy(S7_MULRW_HEADER, 0, numArray, 0, S7_MULRW_HEADER.Length);
numArray[2] = (byte)(telegramLen / 256);
numArray[3] = (byte)(telegramLen % 256);
numArray[13] = (byte)(parameterLen / 256);
numArray[14] = (byte)(parameterLen % 256);
numArray[15] = (byte)((4 + len) / 256);
numArray[16] = (byte)((4 + len) % 256);
numArray[17] = 5;
numArray[18] = (byte)1;
//写入Item与读取大致相同
numArray[19] = (byte)18;
numArray[20] = (byte)10;
numArray[21] = (byte)16;
numArray[22] = (byte)S7WordLength.Byte;
numArray[23] = (byte)(len / 256);
numArray[24] = (byte)(len % 256);
numArray[25] = (byte)(address.DbBlock / 256U);
numArray[26] = (byte)(address.DbBlock % 256U);
numArray[27] = (byte)address.DataCode;
numArray[28] = (byte)(address.AddressStart / 256 / 256);
numArray[29] = (byte)(address.AddressStart / 256);
numArray[30] = (byte)(address.AddressStart % 256);
//后面跟的是写入的数据信息
numArray[31] = 0;
numArray[32] = 4;//Bit:3;Byte:4;Counter或者Timer:9
numArray[33] = (byte)(len * 8 / 256);
numArray[34] = (byte)(len * 8 % 256);
data.CopyTo(numArray, 35);
return OperResult.CreateSuccessResult(numArray);
}
#endregion
#region
internal static async Task<OperResult<string>> ReadString(
SiemensS7PLC plc, string address, Encoding encoding)
{
//先读取一次获取长度,再读取实际值
if (plc.CurrentPlc != SiemensEnum.S200Smart)
{
var result1 = await plc.ReadAsync(address, 2);
if (!result1.IsSuccess)
{
return result1.Copy<string>();
}
if (result1.Content[0] == (byte)0 || result1.Content[0] == byte.MaxValue)
{
return new OperResult<string>("在PLC中不是字符串类型");
}
var result2 = await plc.ReadAsync(address, 2 + result1.Content[1]);
if (!result2.IsSuccess)
{
return result2.Copy<string>();
}
else
{
return OperResult.CreateSuccessResult(encoding.GetString(result2.Content, 2, result2.Content.Length - 2));
}
}
else
{
var result1 = await plc.ReadAsync(address, 1);
if (!result1.IsSuccess)
return result1.Copy<string>();
var result2 = await plc.ReadAsync(address, 1 + result1.Content[0]);
if (!result2.IsSuccess)
{
return result2.Copy<string>();
}
else
{
return OperResult.CreateSuccessResult(encoding.GetString(result2.Content, 1, result2.Content.Length - 1));
}
}
}
internal static async Task<OperResult> Write(SiemensS7PLC plc, string address, string value, Encoding encoding)
{
if (value == null)
value = string.Empty;
byte[] inBytes = encoding.GetBytes(value);
//if (encoding == Encoding.Unicode)
// inBytes = inBytes.BytesReverseByWord();
if (plc.CurrentPlc != SiemensEnum.S200Smart)
{
OperResult<byte[]> result = await plc.ReadAsync(address, 2);
if (!result.IsSuccess) return result;
if (result.Content[0] == byte.MaxValue) return new OperResult<string>("在PLC中不是字符串类型");
if (result.Content[0] == 0) result.Content[0] = 254;
if (value.Length > result.Content[0]) return new OperResult<string>("写入值长度超限");
return await plc.WriteAsync(
address,
DataHelper.SpliceArray(new byte[2] { result.Content[0], (byte)value.Length },
inBytes
));
}
return await plc.WriteAsync(address, DataHelper.SpliceArray<byte>(new byte[1]
{
(byte) value.Length
}, inBytes));
}
#endregion
}
public enum S7WordLength : byte
{
Bit = 0x01,
Byte = 0x02,
Char = 0x03,
Word = 0x04,
Int = 0x05,
DWord = 0x06,
DInt = 0x07,
Real = 0x08,
Counter = 0x1C,
Timer = 0x1D,
}
}

View File

@@ -0,0 +1,142 @@
namespace ThingsGateway.Foundation.Adapter.Siemens
{
internal partial class SiemensHelper
{
/// <summary>
/// S7连读写请求头(包含ISO头和COTP头)
/// </summary>
static byte[] S7_MULRW_HEADER = {
0x03,0x00,
0x00,0x1f, // 报文长度(item.len*12+19注意:根据传入读取item数量更改)
0x02,0xf0, 0x80, //COTP信息
0x32, // S7协议ID
0x01, // 类型,请求命令
0x00,0x00, // 冗余识别
0x00,0x01, // 序列号
0x00,0x0e, // parameter长度item.len*12+2注意:根据传入读取item数量更改
0x00,0x00, // Data Length+4 ,写入时填写读取时为0
0x04, // 4 Read Var, 5 Write Var ,注意更改
0x01, // Item数量item.len注意:根据传入读取item数量更改
};
// S7变量多读Item
static byte[] S7_MULRD_ITEM = {
0x12, // Var 规范.
0x0a, // 剩余的字节长度
0x10, // Syntax ID
(byte)S7WordLength.Byte, // 相关的数据长度代码(注意:根据传入的变量更改)
0x00,0x01, // 数据长度 (注意:根据传入的变量更改)
0x00,0x00, // DB编号 (注意:根据传入的变量更改)
0x84, // 数据块类型 (注意:根据传入的变量更改)
0x00,0x00,0x00 // 数据块偏移量 (注意:根据传入的变量更改)
};
// ISO连接请求报文(也包含ISO头和COTP头)
internal static byte[] ISO_CR = {
// TPKT (RFC1006 Header)
0x03, // RFC 1006 ID (3)
0x00, // 保留 0
0x00, // 数据包长度 (整个框架、有效载荷和TPDU包括在内)
0x16, // 数据包长度 (整个框架、有效载荷和TPDU包括在内)
// COTP (ISO 8073 Header)
0x11, // PDU Size Length
0xE0, // CR -连接请求ID
0x00, 0x00, // Dst Reference
0x00, 0x01, // Src Reference
0x00, // Class + Options Flags
//对于S7200/Smart ,下面参数也需要重写
0xC0, // PDU Max Length ID
0x01, 0x0A, // PDU Max Length
0xC1, // Src TSAP Identifier
0x02, // Src TSAP Length (2 bytes)
0x01, 0x00, // Src TSAP (需重写)
0xC2, // Dst TSAP Identifier
0x02, // Dst TSAP Length (2 bytes)
0x01, 0x02 // Dst TSAP (需重写)
};
// ISO连接请求报文(也包含ISO头和COTP头)
internal static byte[] ISO_CR200 = {
// TPKT (RFC1006 Header)
0x03, // RFC 1006 ID (3)
0x00, // 保留 0
0x00, // 数据包长度 (整个框架、有效载荷和TPDU包括在内)
0x16, // 数据包长度 (整个框架、有效载荷和TPDU包括在内)
// COTP (ISO 8073 Header)
0x11, // PDU Size Length
0xE0, // CR -连接请求ID
0x00, 0x00, // Dst Reference
0x00, 0x01, // Src Reference
0x00, // Class + Options Flags
//对于S7200/Smart
0xC1,0x02,
0x4D,0x57, //LOCALTASP
0xC2,
0x02,
0x4D,0x57, //DESTTASP
0xC0,
0x01,0x09
};
// ISO连接请求报文(也包含ISO头和COTP头)
internal static byte[] ISO_CR200SMART = {
// TPKT (RFC1006 Header)
0x03, // RFC 1006 ID (3)
0x00, // 保留 0
0x00, // 数据包长度 (整个框架、有效载荷和TPDU包括在内)
0x16, // 数据包长度 (整个框架、有效载荷和TPDU包括在内)
// COTP (ISO 8073 Header)
0x11, // PDU Size Length
0xE0, // CR -连接请求ID
0x00, 0x00, // Dst Reference
0x00, 0x01, // Src Reference
0x00, // Class + Options Flags
//对于S7200/Smart
0xC1,0x02,
0x10,0x00,//LOCALTASP
0xC2,
0x02,
0x03,0x00,//DESTTASP
0xC0,
0x01,0x0A
};
// PDU获取报文(也包含ISO头和COTP头)
internal static byte[] S7_PN = {
0x03, 0x00, 0x00, 0x19,
0x02, 0xf0, 0x80, // TPKT + COTP
0x32, 0x01, 0x00, 0x00,
//这里对于S7200/Smart需要重写
0x04, 0x00, 0x00, 0x08,
0x00, 0x00, 0xf0, 0x00,
0x00, 0x01, 0x00, 0x01,
0x01,0xE0 // PDU Length Requested 这里默认480字节对于S7200/Smart 960字节
};
// PDU获取报文(也包含ISO头和COTP头)
internal static byte[] S7200_PN = {
0x03, 0x00, 0x00, 0x19,
0x02, 0xf0, 0x80, // TPKT + COTP
0x32, 0x01, 0x00, 0x00,
0x00,0x00,0x00,0x08,
0x00, 0x00, 0xf0, 0x00,
0x00, 0x01, 0x00, 0x01,
0x01,0xE0 // PDU Length Requested 这里默认960字节
};
internal static byte[] S7200SMART_PN = {
0x03, 0x00, 0x00, 0x19,
0x02, 0xf0, 0x80, // TPKT + COTP
0x32, 0x01, 0x00, 0x00,
0xCC,0xC1,0x00,0x08,
0x00, 0x00, 0xf0, 0x00,
0x00, 0x01, 0x00, 0x01,
0x01,0xE0 // PDU Length Requested 这里默认960字节
};
}
}

View File

@@ -0,0 +1,26 @@
namespace ThingsGateway.Foundation.Adapter.Siemens
{
public class SiemensMessage : MessageBase, IMessage
{
public override int HeadBytesLength => 4;
public override bool CheckHeadBytes(byte[] token)
{
HeadBytes = token;
byte[] headBytes = HeadBytes;
if (headBytes == null || headBytes.Length < 4)
BodyLength = 0;
int length = (HeadBytes[2] * 256) + HeadBytes[3] - 4;
if (length < 0)
length = 0;
BodyLength = length;
return HeadBytes != null && HeadBytes[0] == 3 && HeadBytes[1] == 0;
}
protected override void SendBytesThen()
{
}
}
}

View File

@@ -0,0 +1,15 @@
namespace ThingsGateway.Foundation.Adapter.Siemens
{
public enum SiemensEnum
{
S200,
S200Smart,
S300,
S400,
S1200,
S1500,
}
}

View File

@@ -0,0 +1,335 @@
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using ThingsGateway.Foundation.Extension;
using TouchSocket.Core;
using TouchSocket.Resources;
using TouchSocket.Sockets;
namespace ThingsGateway.Foundation.Adapter.Siemens
{
/// <summary>
/// 相关命令含义源自网络资料/Shrap7/s7netplus
/// </summary>
public partial class SiemensS7PLC : ReadWriteDevicesTcpClientBase
{
public SiemensS7PLCDataHandleAdapter DataHandleAdapter = new();
private SiemensEnum _currentPlc = SiemensEnum.S1200;
private int pdu_length = 0;
private byte plc_rack = 0;
private byte plc_slot = 0;
private byte[] ISO_CR;
private byte[] S7_PN;
public SiemensEnum CurrentPlc => _currentPlc;
/// <summary>
/// 传入PLC类型程序内会改变相应PLC类型的S7协议LocalTSAP RemoteTSAP等
/// </summary>
/// <param name="tcpClient"></param>
/// <param name="siemensPLCEnum"></param>
public SiemensS7PLC(TcpClient tcpClient, SiemensEnum siemensPLCEnum) : base(tcpClient)
{
_currentPlc = siemensPLCEnum;
RegisterByteLength = 1;
ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big);
ISO_CR = new byte[22];
S7_PN = new byte[25];
Array.Copy(SiemensHelper.ISO_CR, ISO_CR, ISO_CR.Length);
Array.Copy(SiemensHelper.S7_PN, S7_PN, S7_PN.Length);
switch (siemensPLCEnum)
{
case SiemensEnum.S1200:
ISO_CR[21] = 0x00;
break;
case SiemensEnum.S300:
ISO_CR[21] = 0x02;
break;
case SiemensEnum.S400:
ISO_CR[21] = 0x03;
ISO_CR[17] = 0x00;
break;
case SiemensEnum.S1500:
ISO_CR[21] = 0x00;
break;
case SiemensEnum.S200Smart:
ISO_CR = SiemensHelper.ISO_CR200SMART;
S7_PN = SiemensHelper.S7200SMART_PN;
break;
case SiemensEnum.S200:
ISO_CR = SiemensHelper.ISO_CR200;
S7_PN = SiemensHelper.S7200_PN;
break;
}
tcpClient.Connected += Connected;
}
#region
/// <summary>
/// 远程TSAP需重新连接
/// </summary>
public int DestTSAP
{
get
{
return
_currentPlc == SiemensEnum.S200 || _currentPlc == SiemensEnum.S200Smart ?
(ISO_CR[17] * 256) + ISO_CR[18] :
(ISO_CR[20] * 256) + ISO_CR[21];
}
set
{
if (_currentPlc == SiemensEnum.S200 || _currentPlc == SiemensEnum.S200Smart)
{
ISO_CR[17] = BitConverter.GetBytes(value)[1];
ISO_CR[18] = BitConverter.GetBytes(value)[0];
}
else
{
ISO_CR[20] = BitConverter.GetBytes(value)[1];
ISO_CR[21] = BitConverter.GetBytes(value)[0];
}
}
}
/// <summary>
/// 本地TSAP需重新连接
/// </summary>
public int LocalTSAP
{
get
{
return
_currentPlc == SiemensEnum.S200 || _currentPlc == SiemensEnum.S200Smart ?
(ISO_CR[13] * 256) + ISO_CR[14] :
(ISO_CR[16] * 256) + ISO_CR[17];
}
set
{
if (_currentPlc == SiemensEnum.S200 || _currentPlc == SiemensEnum.S200Smart)
{
ISO_CR[13] = BitConverter.GetBytes(value)[1];
ISO_CR[14] = BitConverter.GetBytes(value)[0];
}
else
{
ISO_CR[16] = BitConverter.GetBytes(value)[1];
ISO_CR[17] = BitConverter.GetBytes(value)[0];
}
}
}
public int PDULength => pdu_length;
/// <summary>
/// 机架号,需重新连接
/// </summary>
public byte Rack
{
get => plc_rack;
set
{
plc_rack = value;
if (_currentPlc == SiemensEnum.S200 || _currentPlc == SiemensEnum.S200Smart)
{
return;
}
ISO_CR[21] = (byte)((plc_rack * 0x20) + plc_slot);
}
}
/// <summary>
/// 槽号,需重新连接
/// </summary>
public byte Slot
{
get => plc_slot;
set
{
plc_slot = value;
if (_currentPlc == SiemensEnum.S200 || _currentPlc == SiemensEnum.S200Smart)
{
return;
}
ISO_CR[21] = (byte)((plc_rack * 0x20) + plc_slot);
}
}
#endregion
public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken token = default)
{
try
{
await ConnectAsync();
var commandResult = GetReadByteCommand(address, length);
if (commandResult.IsSuccess)
{
List<byte> bytes = new();
foreach (var item in commandResult.Content)
{
var result = TcpClient.GetTGWaitingClient(new()).SendThenResponse(item, TimeOut, token);
if (result.RequestInfo is MessageBase collectMessage)
{
if (collectMessage.IsSuccess)
bytes.AddRange(collectMessage.Content);
else
return OperResult.CreateFailedResult<byte[]>(collectMessage);
}
}
return bytes.Count > 0 ? OperResult.CreateSuccessResult(bytes.ToArray()) : new OperResult<byte[]>(TouchSocketStatus.UnknownError.GetDescription());
}
else
{
return OperResult.CreateFailedResult<byte[]>(commandResult);
}
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
finally
{
}
}
/// <summary>
/// 读取变长字符串
/// </summary>
public async Task<OperResult<string>> ReadString(string address, Encoding encoding)
{
return await SiemensHelper.ReadString(this, address, encoding);
}
public async Task<OperResult<System.DateTime>> ReadDateTime(string address)
{
return ByteTransformHelper.GetResultFromBytes(await ReadAsync(address, 8), ThingsGateway.Foundation.Adapter.Siemens.DateTime.FromByteArray);
}
public async Task<OperResult<System.DateTime>> ReadDate(string address)
{
return (await this.ReadAsync(address, 2)).
Then(m => OperResult.CreateSuccessResult(ThingsGateway.Foundation.Adapter.Siemens.DateTime.SpecMinimumDateTime.AddDays(
ThingsGatewayBitConverter.ToUInt16(m, 0)))
);
}
public override void SetDataAdapter()
{
DataHandleAdapter = new();
TcpClient.SetDataHandlingAdapter(DataHandleAdapter);
}
public override Task<OperResult> WriteAsync(string address, string value, Encoding encoding, CancellationToken token = default)
{
return SiemensHelper.Write(this, address, value, encoding);
}
public override async Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken token = default)
{
try
{
await ConnectAsync();
var commandResult = GetWriteByteCommand(address, value);
if (commandResult.IsSuccess)
{
List<ResponsedData> bytes = new();
foreach (var item in commandResult.Content)
{
ResponsedData result = TcpClient.GetTGWaitingClient(new()).SendThenResponse(item, TimeOut, token);
bytes.Add(result);
}
return OperResult.CreateSuccessResult(bytes.ToArray());
}
else
{
return OperResult.CreateFailedResult<bool[]>(commandResult);
}
}
catch (Exception ex)
{
return new OperResult<bool[]>(ex);
}
finally
{
}
}
public override async Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken token = default)
{
if (value.Length > 1)
{
return new OperResult("不支持多写");
}
try
{
await ConnectAsync();
var commandResult = GetWriteBitCommand(address, value[0]);
if (commandResult.IsSuccess)
{
var result = TcpClient.GetTGWaitingClient(new()).SendThenResponse(commandResult.Content, TimeOut, token);
return OperResult.CreateSuccessResult(result);
}
else
{
return OperResult.CreateFailedResult<bool[]>(commandResult);
}
}
catch (Exception ex)
{
return new OperResult<bool[]>(ex);
}
finally
{
}
}
private void Connected(ITcpClient client, MsgEventArgs e)
{
try
{
var result1 = SendThenResponse(ISO_CR);
if (!result1.IsSuccess)
{
Logger?.Error(client.GetIPPort() + "ISO初始化失败");
return;
}
var result2 = SendThenResponse(S7_PN);
if (!result2.IsSuccess)
{
Logger?.Error(client.GetIPPort() + "初始化失败");
return;
}
pdu_length = ThingsGatewayBitConverter.ToUInt16(result2.Content.SelectLast(2), 0);
pdu_length = pdu_length < 200 ? 200 : pdu_length;
}
catch (Exception ex)
{
Logger.Exception(ex);
}
}
public async Task<OperResult> WriteDateTime(string address, System.DateTime dateTime)
{
return await WriteAsync(address, ThingsGateway.Foundation.Adapter.Siemens.DateTime.ToByteArray(dateTime));
}
public async Task<OperResult> WriteDate(string address, System.DateTime dateTime)
{
return await base.WriteAsync(address, Convert.ToUInt16((dateTime - ThingsGateway.Foundation.Adapter.Siemens.DateTime.SpecMinimumDateTime).TotalDays));
}
}
}

View File

@@ -0,0 +1,41 @@
namespace ThingsGateway.Foundation.Adapter.Siemens
{
public class SiemensS7PLCDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter<SiemensMessage>
{
public override byte[] PackCommand(byte[] command)
{
return command;
}
protected override void Reset()
{
base.Reset();
}
protected override OperResult<byte[]> UnpackResponse(
byte[] send,
byte[] response)
{
if (response[2] * 256 + response[3] == 7)
{
return new OperResult<byte[]>(response);
}
else
{
//已请求方为准,分开返回类型校验
switch (send[17])
{
case 0x04:
return SiemensHelper.AnalysisReadByte(send, response);
case 0x05:
return SiemensHelper.AnalysisWrite(response);
}
return OperResult.CreateSuccessResult(response);
}
}
protected override SiemensMessage GetInstance()
{
return new SiemensMessage();
}
}
}

View File

@@ -0,0 +1,94 @@
using System.Collections.Generic;
using ThingsGateway.Foundation.Extension;
namespace ThingsGateway.Foundation.Adapter.Siemens
{
public partial class SiemensS7PLC : ReadWriteDevicesTcpClientBase
{
private static OperResult<byte[]> GetWriteBitCommand(string address, bool data)
{
OperResult<SiemensAddress> result = SiemensAddress.ParseFrom(address);
if (!result.IsSuccess)
{
return result.Copy<byte[]>();
}
return SiemensHelper.GetWriteBitCommand(result.Content, data);
}
private OperResult<List<byte[]>> GetReadByteCommand(string address, int length)
{
OperResult<SiemensAddress> from = SiemensAddress.ParseFrom(address, length);
if (!from.IsSuccess) return from.Copy<List<byte[]>>();
ushort num1 = 0;
var listBytes = new List<byte[]>();
while (num1 < length)
{
//pdu长度重复生成报文直至全部生成
ushort num2 = (ushort)Math.Min(length - num1, pdu_length);
from.Content.Length = num2;
var result = GetReadByteCommand(new SiemensAddress[1] { from.Content });
if (!result.IsSuccess) return result.Copy<List<byte[]>>();
listBytes.AddRange(result.Content);
num1 += num2;
if (from.Content.DataCode == (byte)S7WordLength.Timer || from.Content.DataCode == (byte)S7WordLength.Counter)
{
from.Content.AddressStart += num2 / 2;
}
else
{
from.Content.AddressStart += num2 * 8;
}
}
return OperResult.CreateSuccessResult(listBytes);
}
private OperResult<List<byte[]>> GetReadByteCommand(SiemensAddress[] siemensAddress)
{
if (siemensAddress.Length <= 19)
{
return ByteTransformHelper.GetResultFromBytes(SiemensHelper.GetReadCommand(siemensAddress), m => new List<byte[]>() { m });
}
List<byte[]> byteList = new List<byte[]>();
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)
{
return SiemensAddress.ParseFrom(address).Then(m => GetWriteByteCommand(m, value));
}
private OperResult<List<byte[]>> GetWriteByteCommand(SiemensAddress address, byte[] value)
{
int length1 = value.Length;
ushort index = 0;
List<byte[]> bytes = new List<byte[]>();
while (index < length1)
{
//pdu长度重复生成报文直至全部生成
ushort length2 = (ushort)Math.Min(length1 - index, pdu_length);
byte[] data = ThingsGatewayBitConverter.ToByte(value, index, length2);
OperResult<byte[]> result1 = SiemensHelper.GetWriteByteCommand(address, data);
if (!result1.IsSuccess)
{
return result1.Copy<List<byte[]>>();
}
bytes.Add(result1.Content);
index += length2;
address.AddressStart += length2 * 8;
}
return OperResult.CreateSuccessResult(bytes);
}
}
}

View File

@@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<LangVersion>latestMajor</LangVersion>
<TargetFrameworks>net4.6.2;net6.0;net7.0</TargetFrameworks>
<Version>1.0.5</Version>
<Title>ThingsGateway.Foundation.Adapter.Siemens</Title>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Authors>Diego</Authors>
<Description>Siemens通讯类库</Description>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
<RunAnalyzersDuringBuild>True</RunAnalyzersDuringBuild>
<PackageProjectUrl>https://diego2098.gitee.io/thingsgateway/</PackageProjectUrl>
<RepositoryUrl>https://gitee.com/diego2098/ThingsGateway</RepositoryUrl>
<PackageOutputPath>$(SolutionDir)</PackageOutputPath>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>
<ItemGroup>
<None Include="..\..\..\README.md">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\ThingsGateway.Foundation\ThingsGateway.Foundation.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,122 +0,0 @@
using System.Diagnostics;
using ThingsGateway.Foundation.Adapter.Modbus;
using Xunit;
namespace ThingsGateway.Foundation.Tests
{
public class Modbus
{
TcpClient client;
private TouchSocketConfig config;
private ModbusRtuOverTcp RtuTcpClient;
private ModbusRtuOverUdp RtuUdpClient;
private ModbusTcp TcpClient;
private ModbusUdp UdpClient;
[Fact]
public async Task RtuTcpReadTest()
{
ModbusRtuTcpClient();
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < 10; i++)
{
string address = $"4{i * 2 + 1};DATA=ABCD;";
var byteConverter = ByteConverterHelper.GetTransByAddress(ref address, RtuTcpClient.ThingsGatewayBitConverter, out int length, out BcdFormat bcdFormat);
var test = await RtuTcpClient.ReadAsync(address, 1);
var data = byteConverter.ToInt16(test.Content, 0);
Console.WriteLine(data.ToJson());
}
for (int i = 100; i < 110; i++)
{
string address = $"4{i * 2 + 1};TEXT=UTF8;LEN=4";
var byteConverter = ByteConverterHelper.GetTransByAddress(ref address, RtuTcpClient.ThingsGatewayBitConverter, out int length, out BcdFormat bcdFormat);
var test = await RtuTcpClient.ReadAsync(address, length / RtuTcpClient.RegisterByteLength);
var data = byteConverter.ToString(test.Content, 0, length);
Console.WriteLine(data.ToJson());
}
stopwatch.Stop();
Console.WriteLine("<22>ܺ<EFBFBD>ʱ<EFBFBD><CAB1>" + stopwatch.Elapsed.TotalSeconds);
}
[Fact]
public async Task TcpReadTest()
{
ModbusTcpClient();
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < 10; i++)
{
string address = $"0{i + 1};";
var byteConverter = ByteConverterHelper.GetTransByAddress(ref address, TcpClient.ThingsGatewayBitConverter, out int length, out BcdFormat bcdFormat);
var test = await TcpClient.ReadAsync(address, 1);
var data = byteConverter.ToBoolean(test.Content, 0);
Console.WriteLine(data.ToJson());
}
stopwatch.Stop();
Console.WriteLine("<22>ܺ<EFBFBD>ʱ<EFBFBD><CAB1>" + stopwatch.Elapsed.TotalSeconds);
}
private void ModbusRtuTcpClient()
{
config = new TouchSocketConfig();
config.SetRemoteIPHost(new IPHost("127.0.0.1:5021"))
.SetBufferLength(300);
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
client = config.Container.Resolve<TcpClient>();
client.Setup(config);
RtuTcpClient = new(client);
RtuTcpClient.ConnectTimeOut = 5000;
RtuTcpClient.Station = 1;
RtuTcpClient.TimeOut = 5000;
}
private void ModbusRtuUdpClient()
{
config = new TouchSocketConfig();
config.SetRemoteIPHost(new IPHost("127.0.0.1:5022")).SetBindIPHost(new IPHost(0))
.SetBufferLength(3000);
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
var client1 = config.BuildWithUdpSession<UdpSession>();
RtuUdpClient = new(client1);
RtuUdpClient.ConnectTimeOut = 5000;
RtuUdpClient.Station = 1;
RtuUdpClient.TimeOut = 5000;
}
private void ModbusTcpClient()
{
config = new TouchSocketConfig();
config.SetRemoteIPHost(new IPHost("127.0.0.1:5023"))
.SetBufferLength(300);
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
client = config.Container.Resolve<TcpClient>();
client.Setup(config);
TcpClient = new(client);
TcpClient.ConnectTimeOut = 5000;
TcpClient.Station = 1;
TcpClient.TimeOut = 5000;
}
private void ModbusUdpClient()
{
config = new TouchSocketConfig();
config.SetRemoteIPHost(new IPHost("127.0.0.1:5024")).SetBindIPHost(new IPHost(0))
.SetBufferLength(3000);
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
var client1 = config.BuildWithUdpSession<UdpSession>();
UdpClient = new(client1);
UdpClient.ConnectTimeOut = 5000;
UdpClient.Station = 1;
UdpClient.TimeOut = 5000;
}
}
}

Some files were not shown because too many files have changed in this diff Show More