Compare commits

...

31 Commits
1.2.0 ... 1.3.0

Author SHA1 Message Date
2248356998 qq.com
7fd160e1a2 😀 更新1.3.0 2023-04-04 10:15:34 +08:00
2248356998 qq.com
97a0d940eb update iotSharpClient 2023-04-04 09:25:16 +08:00
2248356998 qq.com
efaa099d81 update iotSharpClient 2023-04-04 09:23:22 +08:00
2248356998 qq.com
47864a804b IosSharpClient Rpc优化 2023-04-04 09:22:22 +08:00
2248356998 qq.com
91136c0e43 IotSharp Rpc方法完善 2023-04-04 09:19:48 +08:00
2248356998 qq.com
28c3b1bd61 添加写入多个变量的api方法 2023-04-04 09:18:58 +08:00
2248356998 qq.com
551352bc40 update IotSharpClient 2023-04-03 20:16:38 +08:00
2248356998 qq.com
e73c24c925 更新种子 2023-04-03 19:34:12 +08:00
2248356998 qq.com
7ec4c286cc 添加IotSharp插件 2023-04-03 19:30:52 +08:00
2248356998 qq.com
6705e2ec4b 分页显示令牌 2023-04-03 15:29:35 +08:00
2248356998 qq.com
6f0373063b 后台启动时Furion RootServices NULL值 2023-04-03 15:19:59 +08:00
2248356998 qq.com
f64eef60b5 修复不存在采集设备时,初始化报警/历史服务bug 2023-04-03 14:12:56 +08:00
2248356998 qq.com
89546bf86b 弹窗消息在SignalR订阅方法中需InvokeAsync 2023-04-03 13:35:14 +08:00
2248356998 qq.com
793678feca 修复规范化结果包装2次导致登录返回结果不正确的问题 2023-04-03 12:45:19 +08:00
2248356998 qq.com
923cc3019a 更新演示地址 2023-04-03 10:47:49 +08:00
2248356998 qq.com
10eb98a5f6 readme 2023-04-02 18:12:18 +08:00
2248356998 qq.com
bd9e89d8dd readme 2023-04-02 18:08:56 +08:00
2248356998 qq.com
1926b4ce73 更新readme 2023-04-02 18:05:54 +08:00
2248356998 qq.com
4ef3062d74 更新readme 2023-04-02 18:05:28 +08:00
2248356998 qq.com
abb6e0f60f 更新包 2023-04-02 17:10:32 +08:00
2248356998 qq.com
f204d8d84e 添加注释 2023-04-02 16:59:46 +08:00
2248356998 qq.com
fa301656f1 调整依赖,添加关系图 2023-04-01 17:28:35 +08:00
2248356998 qq.com
7e1221028f 调整依赖,更新版本1.2.1 2023-04-01 15:45:02 +08:00
2248356998 qq.com
41308cb2dd 整理 2023-04-01 13:57:57 +08:00
2248356998 qq.com
130600521c 😀 OPCUAServer支持历史查询数据 2023-03-31 18:32:55 +08:00
2248356998 qq.com
cd57548a48 添加ThingsGateway.Foundation注释 2023-03-31 16:25:33 +08:00
2248356998 qq.com
efacc99f76 硬件信息获取添加延时 2023-03-30 20:51:08 +08:00
2248356998 qq.com
f0d236e172 脚本显示优化 2023-03-30 19:51:38 +08:00
2248356998 qq.com
a8118bd8c6 更新文档 2023-03-30 19:39:35 +08:00
2248356998 qq.com
0e58f2ef53 mqtt/mq上传 添加上传实体自定义脚本 2023-03-30 19:07:18 +08:00
2248356998 qq.com
f4b22b3a0c 表达式整理 2023-03-30 16:23:03 +08:00
232 changed files with 2506 additions and 717 deletions

BIN
Image/gitLogo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -1,5 +1,7 @@
<div align="center"><h1 align="center">ThingsGateway</a></h1></div>
<div align="center"><h3 align="center">边缘采集网关</h3></div>

<div align='center'>
<img src="https://gitee.com/diego2098/ThingsGateway/raw/master/Image/gitLogo.png" height=100 />
</div>
#### 介绍
@@ -15,6 +17,13 @@
- 支持时序数据库存储
- 实时/历史报警(Sql转储),支持布尔/高低限值
#### 演示
http://120.24.62.140:5000/
默认账户密码superAdmin 111111
#### 社区版采集插件
> 支持分包解析/订阅
- Modbus(Rtu/Tcp/Udp)
@@ -25,12 +34,13 @@
#### 社区版上传插件
> 支持Rpc写入
- Modbus Server
- OPCUA Server
- Mqtt Server
- Mqtt Client
- OPCUA Server (支持历史查询)
- Mqtt Server (支持自定义json)
- Mqtt Client (支持自定义json)
- IotSharp Client (IotSharp网关插件Rpc待测试)
> 不支持Rpc
- RabbitMQ
- RabbitMQ (支持自定义json)
#### nuget
@@ -101,8 +111,9 @@
#### 支持作者
如果对您有帮助请点击右上角⭐Star关注感谢支持开源
若希望捐赠项目,请[点击](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捐赠功能
若希望捐赠项目,请查看以下捐赠码或使用Gitee捐赠功能
<img src="https://gitee.com/diego2098/ThingsGateway/raw/master/Image/pay.png" height=180 />
#### 联系作者
* QQ群605534569

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 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

View File

@@ -0,0 +1 @@
(()=>{"use strict";var e,t,a,r,f,d={},o={};function c(e){var t=o[e];if(void 0!==t)return t.exports;var a=o[e]={exports:{}};return d[e].call(a.exports,a,a.exports,c),a.exports}c.m=d,e=[],c.O=(t,a,r,f)=>{if(!a){var d=1/0;for(b=0;b<e.length;b++){a=e[b][0],r=e[b][1],f=e[b][2];for(var o=!0,n=0;n<a.length;n++)(!1&f||d>=f)&&Object.keys(c.O).every((e=>c.O[e](a[n])))?a.splice(n--,1):(o=!1,f<d&&(d=f));if(o){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]},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 d={};t=t||[null,a({}),a([]),a(a)];for(var o=2&r&&e;"object"==typeof o&&!~t.indexOf(o);o=a(o))Object.getOwnPropertyNames(o).forEach((t=>d[t]=()=>e[t]));return d.default=()=>e,c.d(f,d),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",86:"0f093a7e",156:"d143b96c",175:"c361d1eb",189:"186a3eb8",195:"c4f5d8e4",217:"b8d02a9c",242:"26929101",261:"cb4f4ca9",282:"96f6c49e",320:"b86d2c6e",331:"7ec71e5c",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:"0dacf5e1",53:"b4814792",86:"63c5ac72",156:"2384a5de",175:"ee8bab92",189:"24a97c3d",195:"43de62e4",217:"25449686",242:"143c32d8",261:"983c3141",282:"b182a2f0",320:"0fb2dcd2",331:"c0b9e422",373:"3ed61cd5",397:"6b3a2f46",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:"533fbe7b",875:"a37fbda4",889:"595088ad",916:"79872004",918:"e52e3593",920:"83cee253",946:"1f1d08eb",966:"7d0118d3",972:"a79306f2",987:"f55d8fd1",994:"8816391f",996:"7e71f890"}[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,d)=>{if(r[e])r[e].push(t);else{var o,n;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){o=u;break}}o||(n=!0,(o=document.createElement("script")).charset="utf-8",o.timeout=120,c.nc&&o.setAttribute("nonce",c.nc),o.setAttribute("data-webpack",f+a),o.src=e),r[e]=[t];var l=(t,a)=>{o.onerror=o.onload=null,clearTimeout(s);var f=r[e];if(delete r[e],o.parentNode&&o.parentNode.removeChild(o),f&&f.forEach((e=>e(a))),t)return t(a)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:o}),12e4);o.onerror=l.bind(null,o.onerror),o.onload=l.bind(null,o.onload),n&&document.head.appendChild(o)}},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","0f093a7e":"86",d143b96c:"156",c361d1eb:"175","186a3eb8":"189",c4f5d8e4:"195",b8d02a9c:"217",cb4f4ca9:"261","96f6c49e":"282",b86d2c6e:"320","7ec71e5c":"331","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,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 d=c.p+c.u(t),o=new Error;c.l(d,(a=>{if(c.o(e,t)&&(0!==(r=e[t])&&(e[t]=void 0),r)){var f=a&&("load"===a.type?"missing":a.type),d=a&&a.target&&a.target.src;o.message="Loading chunk "+t+" failed.\n("+f+": "+d+")",o.name="ChunkLoadError",o.type=f,o.request=d,r[1](o)}}),"chunk-"+t,t)}},c.O.j=t=>0===e[t];var t=(t,a)=>{var r,f,d=a[0],o=a[1],n=a[2],i=0;if(d.some((t=>0!==e[t]))){for(r in o)c.o(o,r)&&(c.m[r]=o[r]);if(n)var b=n(c)}for(t&&t(a);i<d.length;i++)f=d[i],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

@@ -1 +0,0 @@
(()=>{"use strict";var e,t,a,r,f,c={},d={};function o(e){var t=d[e];if(void 0!==t)return t.exports;var a=d[e]={exports:{}};return c[e].call(a.exports,a,a.exports,o),a.exports}o.m=c,e=[],o.O=(t,a,r,f)=>{if(!a){var c=1/0;for(i=0;i<e.length;i++){a=e[i][0],r=e[i][1],f=e[i][2];for(var d=!0,n=0;n<a.length;n++)(!1&f||c>=f)&&Object.keys(o.O).every((e=>o.O[e](a[n])))?a.splice(n--,1):(d=!1,f<c&&(c=f));if(d){e.splice(i--,1);var b=r();void 0!==b&&(t=b)}}return t}f=f||0;for(var i=e.length;i>0&&e[i-1][2]>f;i--)e[i]=e[i-1];e[i]=[a,r,f]},o.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return o.d(t,{a:t}),t},a=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,o.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);o.r(f);var c={};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=>c[t]=()=>e[t]));return c.default=()=>e,o.d(f,c),f},o.d=(e,t)=>{for(var a in t)o.o(t,a)&&!o.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((t,a)=>(o.f[a](e,t),t)),[])),o.u=e=>"assets/js/"+({22:"879054ab",53:"935f2afb",86:"0f093a7e",156:"d143b96c",175:"c361d1eb",189:"186a3eb8",195:"c4f5d8e4",217:"b8d02a9c",242:"26929101",261:"cb4f4ca9",282:"96f6c49e",320:"b86d2c6e",331:"7ec71e5c",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:"b4814792",86:"63c5ac72",156:"2384a5de",175:"ee8bab92",189:"24a97c3d",195:"f48e6acd",217:"25449686",242:"143c32d8",261:"983c3141",282:"b182a2f0",320:"b89a4fe1",331:"c0b9e422",373:"3ed61cd5",397:"6b3a2f46",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",o.miniCssF=e=>{},o.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),o.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r={},f="thingsgateway:",o.l=(e,t,a,c)=>{if(r[e])r[e].push(t);else{var d,n;if(void 0!==a)for(var b=document.getElementsByTagName("script"),i=0;i<b.length;i++){var u=b[i];if(u.getAttribute("src")==e||u.getAttribute("data-webpack")==f+a){d=u;break}}d||(n=!0,(d=document.createElement("script")).charset="utf-8",d.timeout=120,o.nc&&d.setAttribute("nonce",o.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),n&&document.head.appendChild(d)}},o.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.p="/thingsgateway/",o.gca=function(e){return e={17896441:"918",26929101:"242","879054ab":"22","935f2afb":"53","0f093a7e":"86",d143b96c:"156",c361d1eb:"175","186a3eb8":"189",c4f5d8e4:"195",b8d02a9c:"217",cb4f4ca9:"261","96f6c49e":"282",b86d2c6e:"320","7ec71e5c":"331","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,o.p+o.u(e)},(()=>{var e={303:0,532:0};o.f.j=(t,a)=>{var r=o.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 c=o.p+o.u(t),d=new Error;o.l(c,(a=>{if(o.o(e,t)&&(0!==(r=e[t])&&(e[t]=void 0),r)){var f=a&&("load"===a.type?"missing":a.type),c=a&&a.target&&a.target.src;d.message="Loading chunk "+t+" failed.\n("+f+": "+c+")",d.name="ChunkLoadError",d.type=f,d.request=c,r[1](d)}}),"chunk-"+t,t)}},o.O.j=t=>0===e[t];var t=(t,a)=>{var r,f,c=a[0],d=a[1],n=a[2],b=0;if(c.some((t=>0!==e[t]))){for(r in d)o.o(d,r)&&(o.m[r]=d[r]);if(n)var i=n(o)}for(t&&t(a);b<c.length;b++)f=c[b],o.o(e,f)&&e[f]&&e[f][0](),e[f]=0;return o.O(i)},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

View File

@@ -4,8 +4,8 @@
<meta charset="UTF-8">
<meta name="generator" content="Docusaurus v2.2.0">
<title data-rh="true">其他配置说明 | ThingsGateway</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:url" content="https://diego2098.gitee.io/thingsgateway/docs/05、网关配置/otherconfig"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="其他配置说明 | ThingsGateway"><meta data-rh="true" name="description" content="(一)报警属性"><meta data-rh="true" property="og:description" content="(一)报警属性"><link data-rh="true" rel="icon" href="/thingsgateway/img/favicon.ico"><link data-rh="true" rel="canonical" href="https://diego2098.gitee.io/thingsgateway/docs/05、网关配置/otherconfig"><link data-rh="true" rel="alternate" href="https://diego2098.gitee.io/thingsgateway/docs/05、网关配置/otherconfig" hreflang="en"><link data-rh="true" rel="alternate" href="https://diego2098.gitee.io/thingsgateway/docs/05、网关配置/otherconfig" hreflang="x-default"><link rel="stylesheet" href="/thingsgateway/assets/css/styles.a3991719.css">
<link rel="preload" href="/thingsgateway/assets/js/runtime~main.d5cdb1c6.js" as="script">
<link rel="preload" href="/thingsgateway/assets/js/main.5d8abb7d.js" as="script">
<link rel="preload" href="/thingsgateway/assets/js/runtime~main.58b30133.js" as="script">
<link rel="preload" href="/thingsgateway/assets/js/main.968ec5b8.js" as="script">
</head>
<body class="navigation-with-keyboard">
<script>!function(){function t(t){document.documentElement.setAttribute("data-theme",t)}var e=function(){var t=null;try{t=localStorage.getItem("theme")}catch(t){}return t}();t(null!==e?e:"light")}()</script><div id="__docusaurus">
@@ -13,7 +13,7 @@
连接字符串格式:</p><ul><li>Mysql</li></ul><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">server=localhost;Database=SqlSugar4xTest;Uid=root;Pwd=haosql;</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> //有些服务器防火墙有问题需要加上 min pool size=1 避免认为是恶意请求</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><ul><li>SqlServer</li></ul><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">server=.;uid=sa;pwd=haosql;database=SQLSUGAR4XTEST</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><ul><li>PostgreSQL</li></ul><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">PORT=5432;DATABASE=SqlSugar4xTest;HOST=localhost;PASSWORD=haosql;USER ID=postgres</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="二历史属性">(二)历史属性<a class="hash-link" href="#二历史属性" title="Direct link to heading"></a></h3><p><img loading="lazy" src="/thingsgateway/assets/images/otherconfig2-21d951b3891ec96f750e3c7278e1e4e2.png" width="2287" height="822" class="img_ev3q"></p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="转储使能-1">转储使能<a class="hash-link" href="#转储使能-1" title="Direct link to heading"></a></h4><p>历史数据转储开启/关闭</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="数据库类型-1">数据库类型<a class="hash-link" href="#数据库类型-1" title="Direct link to heading"></a></h4><p>选择转储的时序数据库QuestDb</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="连接字符串-1">连接字符串<a class="hash-link" href="#连接字符串-1" title="Direct link to heading"></a></h4><p>对应数据的连接字符串
连接字符串格式:</p><ul><li>QuestDb</li></ul><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">host=localhost;port=8812;username=admin;password=quest;database=qdb;ServerCompatibilityMode=NoTypeLoading;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>QQ群里下载questdb.zip和QuestDB win启动bat文件,解压两个文件更改QuestDB win启动bat里的对应路径最后启动服务重启官网就可查的历史数据
<img loading="lazy" src="/thingsgateway/assets/images/QuestdbSet-e6a2ca678b890ff721f54decb8f81eb4.jpg" width="1617" height="894" class="img_ev3q"></p></div><footer class="theme-doc-footer docusaurus-mt-lg"><div class="theme-doc-footer-edit-meta-row row"><div class="col"><a href="https://gitee.com/diego2098/ThingsGateway/tree/master/handbook/docs/05、网关配置/5.5、其他配置.mdx" target="_blank" rel="noreferrer noopener" class="theme-edit-this-page"><svg fill="currentColor" height="20" width="20" viewBox="0 0 40 40" class="iconEdit_Z9Sw" aria-hidden="true"><g><path d="m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"></path></g></svg>Edit this page</a></div><div class="col lastUpdated_vwxv"></div></div></footer></article><nav class="pagination-nav docusaurus-mt-lg" aria-label="Docs pages navigation"><a class="pagination-nav__link pagination-nav__link--prev" href="/thingsgateway/docs/05、网关配置/plugincore"><div class="pagination-nav__sublabel">Previous</div><div class="pagination-nav__label">5.4、插件管理</div></a><a class="pagination-nav__link pagination-nav__link--next" href="/thingsgateway/docs/06、采集驱动说明/modbus"><div class="pagination-nav__sublabel">Next</div><div class="pagination-nav__label">6.1、Modbus驱动</div></a></nav></div></div><div class="col col--3"><div class="tableOfContents_bqdL thin-scrollbar theme-doc-toc-desktop"><ul class="table-of-contents table-of-contents__left-border"><li><a href="#一报警属性" class="table-of-contents__link toc-highlight">(一)报警属性</a></li><li><a href="#二历史属性" class="table-of-contents__link toc-highlight">(二)历史属性</a></li></ul></div></div></div></div></main></div></div><footer class="footer footer--dark"><div class="container container-fluid"><div class="row footer__links"><div class="col footer__col"><div class="footer__title">文档</div><ul class="footer__items clean-list"><li class="footer__item"><a class="footer__link-item" href="/thingsgateway/docs">手册</a></li></ul></div><div class="col footer__col"><div class="footer__title">社区</div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://gitee.com/diego2098/ThingsGateway/issues" target="_blank" rel="noopener noreferrer" class="footer__link-item">讨论<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://gitee.com/diego2098/ThingsGateway/board" target="_blank" rel="noopener noreferrer" class="footer__link-item">看板<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li></ul></div><div class="col footer__col"><div class="footer__title">更多</div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://gitee.com/diego2098/ThingsGateway" target="_blank" rel="noopener noreferrer" class="footer__link-item">仓库<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li></ul></div></div><div class="footer__bottom text--center"><div class="footer__copyright">Copyright © 2020-2023 Diego.</div></div></div></footer></div>
<script src="/thingsgateway/assets/js/runtime~main.d5cdb1c6.js"></script>
<script src="/thingsgateway/assets/js/main.5d8abb7d.js"></script>
<script src="/thingsgateway/assets/js/runtime~main.58b30133.js"></script>
<script src="/thingsgateway/assets/js/main.968ec5b8.js"></script>
</body>
</html>

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: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 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

@@ -28,6 +28,12 @@ import Tag from "@site/src/components/Tag.js";
##
## v1.3.0(已发布)
- &nbsp;<Tag>新增</Tag> 添加IotSharp插件
## v1.2.0(已发布)

View File

@@ -92,5 +92,32 @@ Rpc返回Json
### (三)实体脚本
脚本功能由cs-script实现
<img src={require('../../static/img/script1.png').default} width="400" />
```
//提供这个例子
//定义返回List
List<dynamic> newModelList=new List<dynamic>();
//input为固定传入值在变量脚本中为变量实体类List在设备脚本中为设备实体类List查看上面的json说明
foreach (var item in input)
{
//添加自定义值
newModelList.Add(new
{
customName=item.name,//变量名称
customValue=item.value,//变量值
customCollectTime=item.collectTime.ToString("yyyy-MM-dd HH:mm:ss fffffff"), //采集时间,这里格式化为自定义时间格式
});
}
return newModelList;
```
<img src={require('../../static/img/script2.png').default} width="400" />
可以看到mqtt上传内容已经改为以上脚本返回值

View File

@@ -90,3 +90,6 @@ Rpc返回Json
### (三)实体脚本
移至 [这里](MqttServer) 查看

View File

@@ -65,4 +65,8 @@ sidebar_label: 7.4、RabbitMQClient
```
### (二)变量配置
### (三)实体脚本
移至 [这里](MqttServer) 查看

View File

@@ -74,7 +74,7 @@ function Banner() {
<div className="ThingsGateway-get-start-btn">
<Link className="ThingsGateway-get-start" to={useBaseUrl("docs")}>
入门指南
<span className="ThingsGateway-version">^1.2.0</span>
<span className="ThingsGateway-version">^1.3.0</span>
</Link>
</div>
</div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

View File

@@ -4,7 +4,7 @@
<LangVersion>latestMajor</LangVersion>
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
<TargetFrameworks>net4.6.2;net6.0;net7.0</TargetFrameworks>
<Version>1.2.0</Version>
<Version>1.3.0</Version>
<Title>ThingsGateway.Foundation.Adapter.Modbus</Title>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Authors>Diego</Authors>

View File

@@ -4,7 +4,7 @@
<LangVersion>latestMajor</LangVersion>
<TargetFrameworks>net4.6.2;net6.0;net7.0</TargetFrameworks>
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
<Version>1.2.0</Version>
<Version>1.3.0</Version>
<Platforms>AnyCPU</Platforms>
<OutputType>Library</OutputType>

View File

@@ -1407,7 +1407,7 @@ public class OPCUAClient : DisposableObject
EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(m_configuration);
ConfiguredEndpoint endpoint = new ConfiguredEndpoint(null, endpointDescription, endpointConfiguration);
var d= await m_application.CheckApplicationInstanceCertificate(true, 0);
var d = await m_application.CheckApplicationInstanceCertificate(true, 0);
//var x509 = await m_configuration.SecurityConfiguration.ApplicationCertificate.Find(true);
m_session = await Opc.Ua.Client.Session.Create(
m_configuration,

View File

@@ -4,7 +4,7 @@
<LangVersion>latestMajor</LangVersion>
<TargetFrameworks>net4.6.2;net6.0;net7.0</TargetFrameworks>
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
<Version>1.2.0</Version>
<Version>1.3.0</Version>
<Platforms>AnyCPU</Platforms>
<OutputType>Library</OutputType>

View File

@@ -1 +1,4 @@
global using System;
global using TouchSocket.Core;
global using TouchSocket.Sockets;

View File

@@ -5,9 +5,7 @@ using System.Threading.Tasks;
using ThingsGateway.Foundation.Extension;
using TouchSocket.Core;
using TouchSocket.Resources;
using TouchSocket.Sockets;
namespace ThingsGateway.Foundation.Adapter.Siemens
{

View File

@@ -4,7 +4,7 @@
<LangVersion>latestMajor</LangVersion>
<TargetFrameworks>net4.6.2;net6.0;net7.0</TargetFrameworks>
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
<Version>1.2.0</Version>
<Version>1.3.0</Version>
<Title>ThingsGateway.Foundation.Adapter.Siemens</Title>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Authors>Diego</Authors>

View File

@@ -7,7 +7,7 @@
<IsPackable>false</IsPackable>
<Platforms>AnyCPU;x86</Platforms>
<Version>1.2.0</Version>
<Version>1.3.0</Version>
</PropertyGroup>
<ItemGroup>

View File

@@ -0,0 +1,2 @@
global using TouchSocket.Core;
global using TouchSocket.Sockets;

View File

@@ -6,9 +6,6 @@ using ThingsGateway.Foundation;
using ThingsGateway.Foundation.Serial;
using ThingsGateway.Web.Foundation;
using TouchSocket.Core;
using TouchSocket.Sockets;
namespace ThingsGateway.Modbus
{
public class ModbusRtu : DriverBase, IDisposable

View File

@@ -3,9 +3,6 @@
using ThingsGateway.Foundation;
using ThingsGateway.Web.Foundation;
using TouchSocket.Core;
using TouchSocket.Sockets;
namespace ThingsGateway.Modbus
{
public class ModbusRtuOverTcp : DriverBase, IDisposable

View File

@@ -3,8 +3,6 @@
using ThingsGateway.Foundation;
using ThingsGateway.Web.Foundation;
using TouchSocket.Sockets;
namespace ThingsGateway.Modbus
{
public class ModbusRtuOverUdp : DriverBase

View File

@@ -9,9 +9,6 @@ using ThingsGateway.Foundation.Adapter.Modbus;
using ThingsGateway.Foundation.Extension;
using ThingsGateway.Web.Foundation;
using TouchSocket.Core;
using TouchSocket.Sockets;
namespace ThingsGateway.Modbus
{
public class ModbusServer : UpLoadBase

View File

@@ -3,9 +3,6 @@
using ThingsGateway.Foundation;
using ThingsGateway.Web.Foundation;
using TouchSocket.Core;
using TouchSocket.Sockets;
namespace ThingsGateway.Modbus
{
public class ModbusTcp : DriverBase

View File

@@ -3,9 +3,6 @@
using ThingsGateway.Foundation;
using ThingsGateway.Web.Foundation;
using TouchSocket.Core;
using TouchSocket.Sockets;
namespace ThingsGateway.Modbus
{

View File

@@ -5,7 +5,7 @@
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Version>1.2.0</Version>
<Version>1.3.0</Version>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
<EnableDynamicLoading>true</EnableDynamicLoading>
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>

View File

@@ -0,0 +1,430 @@
using IoTSharp.Data;
using Mapster;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using MQTTnet;
using MQTTnet.Client;
using NewLife.Serialization;
using System.Collections.Concurrent;
using ThingsGateway.Foundation;
using ThingsGateway.Foundation.Extension;
using ThingsGateway.Web.Foundation;
using TouchSocket.Core;
namespace ThingsGateway.Mqtt
{
/// <summary>
/// 参考IotSharpClient.SDK.MQTT
/// </summary>
public class IotSharpClient : UpLoadBase
{
public IotSharpClient(IServiceScopeFactory scopeFactory) : base(scopeFactory)
{
}
public override OperResult IsConnected()
{
if (_mqttClient?.IsConnected == true)
{
return OperResult.CreateSuccessResult();
}
else
{
return new OperResult();
}
}
[DeviceProperty("Accesstoken", "")] public string Accesstoken { get; set; } = "Accesstoken";
[DeviceProperty("IP", "")] public string IP { get; set; } = "127.0.0.1";
[DeviceProperty("端口", "")] public int Port { get; set; } = 1883;
[DeviceProperty("连接超时时间", "")] public int ConnectTimeOut { get; set; } = 3000;
[DeviceProperty("允许Rpc写入", "")] public bool DeviceRpcEnable { get; set; }
[DeviceProperty("循环间隔", "最小500ms")] public int CycleInterval { get; set; } = 1000;
public override async Task BeforStart()
{
if (_mqttClient != null)
{
var result = await TryMqttClient();
if (!result.IsSuccess)
{
_logger?.LogWarning(ToString() + $"-连接MqttServer失败{result.Message}");
}
}
}
public override void Dispose()
{
_globalCollectDeviceData?.CollectVariables?.ForEach(a => a.VariableValueChange -= VariableValueChange);
_globalCollectDeviceData?.CollectDevices?.ForEach(a =>
{
a.DeviceStatusCahnge -= DeviceStatusCahnge;
});
_mqttClient?.Dispose();
_mqttClient = null;
}
private UploadDevice _curDevice { get; set; }
RpcCore _rpcCore { get; set; }
private IMqttClient _mqttClient;
private MqttClientOptions _mqttClientOptions;
private MqttClientSubscribeOptions _mqttSubscribeOptions;
CollectDeviceHostService collectDeviceHostService;
protected override void Init(UploadDevice device)
{
_curDevice = device;
var mqttFactory = new MqttFactory(new PrivateLogger(_logger));
_mqttClientOptions = mqttFactory.CreateClientOptionsBuilder()
.WithClientId(Guid.NewGuid().ToString())
.WithCredentials(Accesstoken)//账密
.WithTcpServer(IP, Port)//服务器
.WithCleanSession(true)
.WithKeepAlivePeriod(TimeSpan.FromSeconds(120.0))
.Build();
_mqttSubscribeOptions = mqttFactory.CreateSubscribeOptionsBuilder()
.WithTopicFilter(
f =>
{
f.WithTopic($"devices/+/rpc/request/+/+");//RPC控制请求需要订阅
})
.Build();
_mqttClient = mqttFactory.CreateMqttClient();
_mqttClient.ConnectedAsync += _mqttClient_ConnectedAsync;
_mqttClient.ApplicationMessageReceivedAsync += _mqttClient_ApplicationMessageReceivedAsync;
using var serviceScope = _scopeFactory.CreateScope();
_globalCollectDeviceData = serviceScope.ServiceProvider.GetService<GlobalCollectDeviceData>();
_rpcCore = serviceScope.ServiceProvider.GetService<RpcCore>();
collectDeviceHostService = serviceScope.GetBackgroundService<CollectDeviceHostService>();
_globalCollectDeviceData.CollectDevices.ForEach(a =>
{
a.DeviceStatusCahnge += DeviceStatusCahnge;
});
_globalCollectDeviceData.CollectVariables.ForEach(a =>
{
a.VariableValueChange += VariableValueChange;
});
_ = Task.Run(
async () =>
{
await Task.Delay(ConnectTimeOut * 20);
bool lastIsSuccess = _mqttClient?.IsConnected == true;
while (_mqttClient != null)
{
try
{
var result = await TryMqttClient();
if (!result.IsSuccess && lastIsSuccess)
{
lastIsSuccess = false;
_logger?.LogWarning(ToString() + $"-连接MqttServer失败{result.Message}");
}
else if (result.IsSuccess && !lastIsSuccess)
{
lastIsSuccess = true;
_logger?.LogInformation(ToString() + $"-连接MqttServer成功{result.Message}");
}
}
finally
{
await Task.Delay(ConnectTimeOut * 10);
}
}
});
}
private async Task _mqttClient_ConnectedAsync(MqttClientConnectedEventArgs arg)
{
var subResult = await _mqttClient.SubscribeAsync(_mqttSubscribeOptions);
if (subResult.Items.Any(a => a.ResultCode > (MqttClientSubscribeResultCode)10))
{
_logger.LogWarning(subResult.Items
.Where(a => a.ResultCode > (MqttClientSubscribeResultCode)10)
.Select(a => a.ToString()).ToJson());
}
}
public override string ToString()
{
return $" {nameof(IotSharpClient)}-IP:{IP}-Port:{Port}-Accesstoken:{Accesstoken}";
}
private GlobalCollectDeviceData _globalCollectDeviceData;
private ConcurrentQueue<VariableData> CollectVariableRunTimes { get; set; } = new();
private ConcurrentQueue<DeviceData> CollectDeviceRunTimes { get; set; } = new();
private void DeviceStatusCahnge(CollectDeviceRunTime collectDeviceRunTime)
{
CollectDeviceRunTimes.Enqueue(collectDeviceRunTime.Adapt<DeviceData>());
}
private void VariableValueChange(CollectVariableRunTime collectVariableRunTime)
{
CollectVariableRunTimes.Enqueue(collectVariableRunTime.Adapt<VariableData>());
}
private EasyLock lockobj { get; set; } = new();
private async Task<OperResult> TryMqttClient(bool reconnect = false)
{
if (_mqttClient?.IsConnected == true)
return OperResult.CreateSuccessResult();
return await Cilent();
async Task<OperResult> Cilent()
{
if (_mqttClient?.IsConnected == true)
return OperResult.CreateSuccessResult();
try
{
lockobj.Lock();
if (_mqttClient?.IsConnected == true)
return OperResult.CreateSuccessResult();
using (var timeoutToken = new CancellationTokenSource(TimeSpan.FromSeconds(ConnectTimeOut)))
{
if (_mqttClient?.IsConnected == true)
return OperResult.CreateSuccessResult();
if (_mqttClient == null)
return new OperResult("未初始化");
var result = await _mqttClient?.ConnectAsync(_mqttClientOptions, timeoutToken.Token);
if (result.ResultCode == MqttClientConnectResultCode.Success)
{
return OperResult.CreateSuccessResult();
}
else
{
return new OperResult(result.ReasonString);
}
}
}
catch (Exception ex)
{
return new OperResult(ex);
}
finally
{
lockobj.UnLock();
}
}
}
/// <summary>
/// rpcmethodname存疑定为自定义方法在ThingsGateway上写入变量的方法固定为"Write"
/// </summary>
private const string WriteMethod = "WRITE";
private async Task _mqttClient_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs e)
{
if (e.ApplicationMessage.Topic.StartsWith($"devices/") && e.ApplicationMessage.Topic.Contains("/rpc/request/"))
{
var tps = e.ApplicationMessage.Topic.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
var rpcmethodname = tps[4];
var rpcdevicename = tps[1];
var rpcrequestid = tps[5];
if (!string.IsNullOrEmpty(rpcmethodname) && !string.IsNullOrEmpty(rpcdevicename) && !string.IsNullOrEmpty(rpcrequestid))
{
var rpcResponse = new RpcResponse()
{
DeviceId = rpcdevicename,
ResponseId = rpcrequestid,
Method = rpcmethodname,
Success = false,
Data = "参数为空"
};
await SendResponse(rpcResponse);
return;
}
if (!DeviceRpcEnable)
{
var rpcResponse = new RpcResponse()
{
DeviceId = rpcdevicename,
ResponseId = rpcrequestid,
Method = rpcmethodname,
Success = false,
Data = "不允许写入"
};
await SendResponse(rpcResponse);
return;
}
//rpcmethodname定为自定义方法在ThingsGateway上写入变量的方法固定为"Write"
if (rpcmethodname.ToUpper() != WriteMethod)
{
var rpcResponse = new RpcResponse()
{
DeviceId = rpcdevicename,
ResponseId = rpcrequestid,
Method = rpcmethodname,
Success = false,
Data = "不支持的方法"
};
await SendResponse(rpcResponse);
return;
}
else
{
RpcResponse rpcResponse = new();
var nameValue = e.ApplicationMessage.ConvertPayloadToString().ToJsonEntity<List<NameValue>>();
Dictionary<string, OperResult> results = new();
if (nameValue?.Count > 0)
{
foreach (var item in nameValue)
{
var result = await _rpcCore.InvokeDeviceMethod(ToString() + "-" + rpcrequestid, item);
results.Add(item.Name, result);
}
rpcResponse = new()
{
DeviceId = rpcdevicename,
ResponseId = rpcrequestid,
Method = rpcmethodname,
Success = !results.Any(a => !a.Value.IsSuccess),
Data = results.ToJson()
};
}
else
{
rpcResponse = new()
{
DeviceId = rpcdevicename,
ResponseId = rpcrequestid,
Method = rpcmethodname,
Success = false,
Data = "消息体参数无法解析"
};
}
await SendResponse(rpcResponse);
}
}
async Task SendResponse(RpcResponse rpcResponse)
{
try
{
var topic = $"devices/{rpcResponse.DeviceId}/rpc/response/{rpcResponse.Method}/{rpcResponse.ResponseId}";
var variableMessage = new MqttApplicationMessageBuilder()
.WithTopic($"{topic}")
.WithPayload(rpcResponse.ToJson()).Build();
if (_mqttClient.IsConnected)
await _mqttClient.PublishAsync(variableMessage);
}
catch
{
}
}
}
private static DateTime timeSpan = new DateTime(1970, 1, 1, 0, 0, 0);
public override async Task ExecuteAsync(CancellationToken cancellationToken)
{
try
{
////变化推送
var varList = CollectVariableRunTimes.ToListWithDequeue();
if (varList?.Count != 0)
{
//分解List避免超出mqtt字节大小限制.ChunkTrivialBetter(500)
var varData = varList.GroupBy(a=>a.deviceName).ToList();
foreach (var item in varData)
{
try
{
if (!cancellationToken.IsCancellationRequested)
{
var variableMessage = new MqttApplicationMessageBuilder()
.WithTopic($"devices/{item.Key}/telemetry")
.WithPayload(item.ToDictionary(o => o.name, o => o.value).ToJson()).Build();
if (_mqttClient.IsConnected)
await _mqttClient.PublishAsync(variableMessage, cancellationToken);
}
else
{
break;
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, ToString());
}
}
}
}
catch (Exception ex)
{
_logger?.LogWarning(ex, ToString());
}
try
{
////变化推送
var devList = CollectDeviceRunTimes.ToListWithDequeue();
if (devList?.Count != 0)
{
//分解List避免超出mqtt字节大小限制
var devData = devList.ChunkTrivialBetter(500);
foreach (var item in devData)
{
try
{
if (!cancellationToken.IsCancellationRequested)
{
// var variableMessage = new MqttApplicationMessageBuilder()
//.WithTopic($"{DeviceTopic}")
//.WithPayload(item.GetSciptListValue(BigTextScriptDeviceModel)).Build();
// if (_mqttClient.IsConnected)
// await _mqttClient.PublishAsync(variableMessage);
}
else
{
break;
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, ToString());
}
}
}
}
catch (Exception ex)
{
_logger?.LogWarning(ex, ToString());
}
if (CycleInterval > 500 + 50)
{
await Task.Delay(CycleInterval - 500);
}
else
{
}
}
}
}

View File

@@ -0,0 +1,14 @@
using Newtonsoft.Json;
namespace IoTSharp.Data
{
public class RpcResponse
{
public string DeviceId { get; set; }
public string Method { get; set; }
public string ResponseId { get; set; }
public string Data { get; set; }
public bool Success { get; set; }
}
}

View File

@@ -21,7 +21,6 @@ namespace ThingsGateway.Mqtt
{
public class MqttClient : UpLoadBase
{
public MqttClient(IServiceScopeFactory scopeFactory) : base(scopeFactory)
{
}
@@ -47,12 +46,14 @@ namespace ThingsGateway.Mqtt
[DeviceProperty("Rpc返回Topic", "")] public string RpcSubTopic { get; set; } = "ThingsGateway/RpcSub";
[DeviceProperty("数据请求RpcTopic", "这个主题接收到任何数据都会把全部的信息发送到变量/设备主题中")] public string QuestRpcTopic { get; set; } = "ThingsGateway/Quest";
[DeviceProperty("变量Topic", "")] public string VariableTopic { get; set; } = "ThingsGateway/Variable";
[DeviceProperty("设备Topic", "")] public string DeviceTopic { get; set; } = "ThingsGateway/Device";
[DeviceProperty("循环间隔", "最小500ms")] public int CycleInterval { get; set; } = 1000;
[DeviceProperty("设备实体脚本", "查看文档说明,为空时不起作用")] public string BigTextScriptDeviceModel { get; set; }
[DeviceProperty("变量实体脚本", "查看文档说明,为空时不起作用")] public string BigTextScriptVariableModel { get; set; }
public override async Task BeforStart()
{
@@ -112,7 +113,7 @@ namespace ThingsGateway.Mqtt
using var serviceScope = _scopeFactory.CreateScope();
_globalCollectDeviceData = serviceScope.ServiceProvider.GetService<GlobalCollectDeviceData>();
_rpcCore = serviceScope.ServiceProvider.GetService<RpcCore>();
collectDeviceHostService = serviceScope.ServiceProvider.GetBackgroundService<CollectDeviceHostService>();
collectDeviceHostService = serviceScope.GetBackgroundService<CollectDeviceHostService>();
_globalCollectDeviceData.CollectDevices.ForEach(a =>
{
@@ -238,11 +239,14 @@ namespace ThingsGateway.Mqtt
//分解List避免超出mqtt字节大小限制
var varData = _globalCollectDeviceData.CollectVariables.Adapt<List<VariableData>>().ChunkTrivialBetter(500);
var devData = _globalCollectDeviceData.CollectVariables.Adapt<List<DeviceData>>().ChunkTrivialBetter(500);
foreach (var item in devData)
{
var devMessage = new MqttApplicationMessageBuilder()
.WithTopic($"{DeviceTopic}")
.WithPayload(item.ToJson()).Build();
.WithPayload(item.GetSciptListValue(BigTextScriptDeviceModel)).Build();
await _mqttClient.PublishAsync(devMessage);
}
@@ -250,7 +254,7 @@ namespace ThingsGateway.Mqtt
{
var varMessage = new MqttApplicationMessageBuilder()
.WithTopic($"{VariableTopic}")
.WithPayload(item.ToJson()).Build();
.WithPayload(item.GetSciptListValue(BigTextScriptVariableModel)).Build();
await _mqttClient.PublishAsync(varMessage);
}
}
@@ -311,11 +315,19 @@ namespace ThingsGateway.Mqtt
{
try
{
var variableMessage = new MqttApplicationMessageBuilder()
if (!cancellationToken.IsCancellationRequested)
{
var variableMessage = new MqttApplicationMessageBuilder()
.WithTopic($"{VariableTopic}")
.WithPayload(item.ToJson()).Build();
if (_mqttClient.IsConnected)
await _mqttClient.PublishAsync(variableMessage);
.WithPayload(item.GetSciptListValue(BigTextScriptVariableModel)).Build();
if (_mqttClient.IsConnected)
await _mqttClient.PublishAsync(variableMessage, cancellationToken);
}
else
{
break;
}
}
catch (Exception ex)
{
@@ -341,11 +353,18 @@ namespace ThingsGateway.Mqtt
{
try
{
var variableMessage = new MqttApplicationMessageBuilder()
if (!cancellationToken.IsCancellationRequested)
{
var variableMessage = new MqttApplicationMessageBuilder()
.WithTopic($"{DeviceTopic}")
.WithPayload(item.ToJson()).Build();
if (_mqttClient.IsConnected)
await _mqttClient.PublishAsync(variableMessage);
.WithPayload(item.GetSciptListValue(BigTextScriptDeviceModel)).Build();
if (_mqttClient.IsConnected)
await _mqttClient.PublishAsync(variableMessage);
}
else
{
break;
}
}
catch (Exception ex)
{

View File

@@ -42,6 +42,10 @@ namespace ThingsGateway.Mqtt
[DeviceProperty("设备Topic", "")] public string DeviceTopic { get; set; } = "ThingsGateway/Device";
[DeviceProperty("循环间隔", "最小500ms")] public int CycleInterval { get; set; } = 1000;
[DeviceProperty("设备实体脚本", "查看文档说明,为空时不起作用")] public string BigTextScriptDeviceModel { get; set; }
[DeviceProperty("变量实体脚本", "查看文档说明,为空时不起作用")] public string BigTextScriptVariableModel { get; set; }
public override string ToString()
{
return $" {nameof(MqttServer)} IP:{IP} Port:{Port}";
@@ -80,13 +84,13 @@ namespace ThingsGateway.Mqtt
{
Messages.Add(new MqttApplicationMessageBuilder()
.WithTopic($"{VariableTopic}")
.WithPayload(item.ToJson()).Build());
.WithPayload(item.GetSciptListValue(BigTextScriptVariableModel)).Build());
}
foreach (var item in devData)
{
Messages.Add(new MqttApplicationMessageBuilder()
.WithTopic($"{DeviceTopic}")
.WithPayload(item.ToJson()).Build());
.WithPayload(item.GetSciptListValue(BigTextScriptDeviceModel)).Build());
}
arg.LoadedRetainedMessages = Messages;
return CompletedTask.Instance;
@@ -215,11 +219,18 @@ namespace ThingsGateway.Mqtt
{
try
{
var message = new MqttApplicationMessageBuilder()
if (!cancellationToken.IsCancellationRequested)
{
var message = new MqttApplicationMessageBuilder()
.WithTopic($"{VariableTopic}")
.WithPayload(item.ToJson()).Build();
await _mqttServer.InjectApplicationMessage(
new InjectedMqttApplicationMessage(message));
.WithPayload(item.GetSciptListValue(BigTextScriptVariableModel)).Build();
await _mqttServer.InjectApplicationMessage(
new InjectedMqttApplicationMessage(message));
}
else
{
break;
}
}
catch (Exception ex)
{
@@ -247,11 +258,18 @@ namespace ThingsGateway.Mqtt
{
try
{
var message = new MqttApplicationMessageBuilder()
if (!cancellationToken.IsCancellationRequested)
{
var message = new MqttApplicationMessageBuilder()
.WithTopic($"{DeviceTopic}")
.WithPayload(item.ToJson()).Build();
await _mqttServer.InjectApplicationMessage(
new InjectedMqttApplicationMessage(message));
.WithPayload(item.GetSciptListValue(BigTextScriptDeviceModel)).Build();
await _mqttServer.InjectApplicationMessage(
new InjectedMqttApplicationMessage(message));
}
else
{
break;
}
}
catch (Exception ex)
{

View File

@@ -5,7 +5,7 @@
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
<Version>1.2.0</Version>
<Version>1.3.0</Version>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
<EnableDynamicLoading>true</EnableDynamicLoading>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

View File

@@ -5,7 +5,7 @@
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
<Version>1.2.0</Version>
<Version>1.3.0</Version>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
<EnableDynamicLoading>true</EnableDynamicLoading>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

View File

@@ -62,7 +62,7 @@ public partial class OPCUAServer : UpLoadBase
}
/// <inheritdoc/>
public override async Task ExecuteAsync(CancellationToken stoppingToken)
public override async Task ExecuteAsync(CancellationToken cancellationToken)
{
try
{
@@ -74,7 +74,14 @@ public partial class OPCUAServer : UpLoadBase
{
try
{
m_server.NodeManager.UpVariable(item);
if (!cancellationToken.IsCancellationRequested)
{
m_server.NodeManager.UpVariable(item);
}
else
{
break;
}
}
catch (Exception ex)
{
@@ -121,7 +128,7 @@ public partial class OPCUAServer : UpLoadBase
private void VariableValueChange(CollectVariableRunTime collectVariableRunTime)
{
CollectVariableRunTimes.Enqueue(collectVariableRunTime.Adapt<VariableData>());
CollectVariableRunTimes.Enqueue(collectVariableRunTime.Adapt<VariableData>());
}
@@ -214,7 +221,7 @@ public partial class OPCUAServer : UpLoadBase
TrustedPeerCertificates = new CertificateTrustList()
{
StoreType = CertificateStoreType.Directory,
StorePath = "%CommonApplicationData%\\ThingsGateway\\pki\\issuer",
StorePath = "%CommonApplicationData%\\ThingsGateway\\pki\\issuer",
},
TrustedIssuerCertificates = new CertificateTrustList()

View File

@@ -7,6 +7,8 @@ using Opc.Ua.Server;
using ThingsGateway.Web.Foundation;
using TouchSocket.Core;
namespace ThingsGateway.OPCUA;
@@ -25,12 +27,18 @@ public class ThingsGatewayNodeManager : CustomNodeManager2
private Dictionary<NodeId, OPCUATag> _idTags = new Dictionary<NodeId, OPCUATag>();
private RpcCore _rpcCore;
private IServiceScope _serviceScope;
private TypeAdapterConfig _config;
/// <inheritdoc cref="ThingsGatewayNodeManager"/>
public ThingsGatewayNodeManager(IServiceScope serviceScope, IServerInternal server, ApplicationConfiguration configuration) : base(server, configuration, ReferenceServer)
{
_serviceScope = serviceScope;
_rpcCore = serviceScope.ServiceProvider.GetService<RpcCore>();
_globalCollectDeviceData = serviceScope.ServiceProvider.GetService<GlobalCollectDeviceData>();
_config = new TypeAdapterConfig();
_config.ForType<ValueHis, DataValue>()
.Map(dest => dest.WrappedValue, (src) => new Variant(src.Value))
.Map(dest => dest.SourceTimestamp, (src) => src.CollectTime)
.Map(dest => dest.StatusCode, (src) => src.Quality == 192 ? StatusCodes.Good : StatusCodes.Bad);
}
@@ -84,12 +92,20 @@ public class ThingsGatewayNodeManager : CustomNodeManager2
}
/// <summary>
/// 读取历史数据
/// </summary>
public override void HistoryRead(OperationContext context, HistoryReadDetails details, TimestampsToReturn timestampsToReturn, bool releaseContinuationPoints, IList<HistoryReadValueId> nodesToRead, IList<HistoryReadResult> results, IList<ServiceResult> errors)
public override void HistoryRead(OperationContext context,
HistoryReadDetails details,
TimestampsToReturn timestampsToReturn,
bool releaseContinuationPoints,
IList<HistoryReadValueId> nodesToRead,
IList<HistoryReadResult> results,
IList<ServiceResult> errors)
{
ReadProcessedDetails readDetail = details as ReadProcessedDetails;
base.HistoryRead(context, details, timestampsToReturn, releaseContinuationPoints, nodesToRead, results, errors);
var readDetail = details as ReadRawModifiedDetails;
//必须带有时间范围
if (readDetail == null || readDetail.StartTime == DateTime.MinValue || readDetail.EndTime == DateTime.MinValue)
{
@@ -125,10 +141,17 @@ public class ThingsGatewayNodeManager : CustomNodeManager2
if (data.Count > 0)
{
var hisDataValue = data.Adapt<List<DataValue>>(_config);
HistoryData hisData = new HistoryData();
hisData.DataValues.AddRange(hisDataValue);
errors[i] = StatusCodes.Good;
//切记Processed设为true否则客户端会报错
historyRead.Processed = true;
results[i] = new HistoryReadResult()
{
StatusCode = StatusCodes.Good,
HistoryData = new ExtensionObject(data)
HistoryData = new ExtensionObject(hisData)
};
}
else
@@ -147,7 +170,6 @@ public class ThingsGatewayNodeManager : CustomNodeManager2
};
}
}
base.HistoryRead(context, details, timestampsToReturn, releaseContinuationPoints, nodesToRead, results, errors);
}
/// <inheritdoc/>
public override NodeId New(ISystemContext context, NodeState node)
@@ -261,15 +283,13 @@ public class ThingsGatewayNodeManager : CustomNodeManager2
variable.WriteMask = AttributeWriteMask.DisplayName | AttributeWriteMask.Description;
variable.UserWriteMask = AttributeWriteMask.DisplayName | AttributeWriteMask.Description;
variable.ValueRank = ValueRanks.Scalar;
variable.Id = variableRunTime.Id;
variable.DataType = DataNodeType(variableRunTime);
var level = ProtectTypeTrans(variableRunTime.ProtectTypeEnum);
var level = ProtectTypeTrans(variableRunTime);
variable.AccessLevel = level;
variable.UserAccessLevel = level;
variable.Historizing = variableRunTime.HisEnable;
variable.Historizing = false;
variable.StatusCode = StatusCodes.Good;
variable.Timestamp = DateTime.Now;
variable.Value = Opc.Ua.TypeInfo.GetDefaultValue(variable.DataType, ValueRanks.Scalar, Server.TypeTree);
@@ -278,7 +298,7 @@ public class ThingsGatewayNodeManager : CustomNodeManager2
{
parent.AddChild(variable);
}
_idTags.Add(variable.NodeId, variable);
_idTags.AddOrUpdate(variable.NodeId, variable);
return variable;
}
@@ -365,15 +385,26 @@ public class ThingsGatewayNodeManager : CustomNodeManager2
}
private byte ProtectTypeTrans(ProtectTypeEnum protectTypeEnum)
private byte ProtectTypeTrans(CollectVariableRunTime variableRunTime)
{
switch (protectTypeEnum)
byte result = 0;
switch (variableRunTime.ProtectTypeEnum)
{
case ProtectTypeEnum.ReadOnly: return AccessLevels.CurrentRead;
case ProtectTypeEnum.ReadOnly:
result = (byte)(result | AccessLevels.CurrentRead);
break;
case ProtectTypeEnum.ReadWrite:
return AccessLevels.CurrentReadOrWrite;
result = (byte)(result | AccessLevels.CurrentReadOrWrite);
break;
default:
return AccessLevels.CurrentRead;
result = (byte)(result | AccessLevels.CurrentRead);
break;
}
if (variableRunTime.HisEnable)
{
result = (byte)(result | AccessLevels.HistoryRead);
}
return result;
}
}

View File

@@ -28,7 +28,6 @@ public partial class ThingsGatewayServer : StandardServer
_logger = logger;
_serviceScope = serviceScope;
}
/// <inheritdoc/>
public override UserTokenPolicyCollection GetUserTokenPolicies(ApplicationConfiguration configuration, EndpointDescription description)
{
@@ -234,7 +233,7 @@ public partial class ThingsGatewayServer : StandardServer
"Security token is not a valid username token. An empty password is not accepted.");
}
var _openApiUserService = _serviceScope.ServiceProvider.GetService<IOpenApiUserService>();
var userInfo = _openApiUserService.GetUserByAccount(userName).GetAwaiter().GetResult();//获取用户信息
var userInfo = _openApiUserService.GetUserByAccount(userName).GetAwaiter().GetResult();//获取用户信息
if (userInfo == null)
{
// construct translation object with default text.
@@ -260,7 +259,7 @@ public partial class ThingsGatewayServer : StandardServer
{
return new UserIdentity(userNameToken);
}
}
private void VerifyUserTokenCertificate(X509Certificate2 certificate)

View File

@@ -5,7 +5,7 @@
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<Version>1.2.0</Version>
<Version>1.3.0</Version>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
<EnableDynamicLoading>true</EnableDynamicLoading>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

View File

@@ -3,8 +3,6 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NewLife.Serialization;
using RabbitMQ.Client;
using System.Collections.Concurrent;
@@ -14,8 +12,6 @@ using ThingsGateway.Foundation;
using ThingsGateway.Foundation.Extension;
using ThingsGateway.Web.Foundation;
using TouchSocket.Core;
namespace ThingsGateway.RabbitMQ
{
public class RabbitMQClient : UpLoadBase
@@ -49,6 +45,8 @@ namespace ThingsGateway.RabbitMQ
[DeviceProperty("是否发布List", "")] public bool IsList { get; set; } = false;
[DeviceProperty("是否声明队列", "")] public bool IsQueueDeclare { get; set; } = false;
[DeviceProperty("循环间隔", "最小500ms")] public int CycleInterval { get; set; } = 1000;
[DeviceProperty("设备实体脚本", "查看文档说明,为空时不起作用")] public string BigTextScriptDeviceModel { get; set; }
[DeviceProperty("变量实体脚本", "查看文档说明,为空时不起作用")] public string BigTextScriptVariableModel { get; set; }
public string ExchangeName { get; set; } = "";
@@ -136,6 +134,7 @@ namespace ThingsGateway.RabbitMQ
{
try
{
// 创建连接
if (_connection == null)
_connection = _connectionFactory.CreateConnection();
@@ -148,6 +147,8 @@ namespace ThingsGateway.RabbitMQ
_model?.QueueDeclare(VariableQueueName, true, false, false);
_model?.QueueDeclare(DeviceQueueName, true, false, false);
}
}
catch (Exception ex)
{
@@ -168,11 +169,18 @@ namespace ThingsGateway.RabbitMQ
{
try
{
var data = Encoding.UTF8.GetBytes(variables.ToJson());
// 设置消息持久化
IBasicProperties properties = _model?.CreateBasicProperties();
properties.Persistent = true;
_model?.BasicPublish(ExchangeName, VariableQueueName, properties, data);
if (!cancellationToken.IsCancellationRequested)
{
var data = Encoding.UTF8.GetBytes(variables.GetSciptListValue(BigTextScriptVariableModel));
// 设置消息持久化
IBasicProperties properties = _model?.CreateBasicProperties();
properties.Persistent = true;
_model?.BasicPublish(ExchangeName, VariableQueueName, properties, data);
}
else
{
break;
}
}
catch (Exception ex)
{
@@ -187,11 +195,19 @@ namespace ThingsGateway.RabbitMQ
{
try
{
var data = Encoding.UTF8.GetBytes(variable.ToJson());
// 设置消息持久化
IBasicProperties properties = _model?.CreateBasicProperties();
properties.Persistent = true;
_model?.BasicPublish(ExchangeName, VariableQueueName, properties, data);
if (!cancellationToken.IsCancellationRequested)
{
var data = Encoding.UTF8.GetBytes(variable.GetSciptListValue(BigTextScriptVariableModel));
// 设置消息持久化
IBasicProperties properties = _model?.CreateBasicProperties();
properties.Persistent = true;
_model?.BasicPublish(ExchangeName, VariableQueueName, properties, data);
}
else
{
break;
}
}
catch (Exception ex)
{
@@ -220,7 +236,7 @@ namespace ThingsGateway.RabbitMQ
{
try
{
var data = Encoding.UTF8.GetBytes(devices.ToJson());
var data = Encoding.UTF8.GetBytes(devices.GetSciptListValue(BigTextScriptDeviceModel));
// 设置消息持久化
IBasicProperties properties = _model?.CreateBasicProperties();
properties.Persistent = true;
@@ -239,7 +255,7 @@ namespace ThingsGateway.RabbitMQ
{
try
{
var data = Encoding.UTF8.GetBytes(devices.ToJson());
var data = Encoding.UTF8.GetBytes(devices.GetSciptListValue(BigTextScriptDeviceModel));
// 设置消息持久化
IBasicProperties properties = _model?.CreateBasicProperties();
properties.Persistent = true;

View File

@@ -5,7 +5,7 @@
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Version>1.2.0</Version>
<Version>1.3.0</Version>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
<EnableDynamicLoading>true</EnableDynamicLoading>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

View File

@@ -1,7 +1,5 @@
global using Microsoft.Extensions.DependencyInjection;
global using System.Net;
global using ThingsGateway.Foundation.Adapter.Siemens;
global using ThingsGateway.Web.Foundation;

View File

@@ -5,7 +5,7 @@
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
<ImplicitUsings>enable</ImplicitUsings>
<Version>1.2.0</Version>
<Version>1.3.0</Version>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
<EnableDynamicLoading>true</EnableDynamicLoading>
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>

View File

@@ -1,5 +1,8 @@
namespace System.ComponentModel
{
/// <summary>
/// 操作事件说明
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class OperDescAttribute : Attribute
{
@@ -13,9 +16,17 @@
Description = description;
Catcategory = catcategory;
}
/// <summary>
/// 分类
/// </summary>
public string Catcategory { get; }
/// <summary>
/// 说明
/// </summary>
public string Description { get; }
/// <summary>
/// 记录参数
/// </summary>
public bool IsRecordPar { get; set; } = true;
}
}

View File

@@ -1,8 +1,6 @@
using Furion.Reflection;
using Furion.Reflection.Extensions;
using System.Text;
namespace ThingsGateway.Application
{
/// <summary>

View File

@@ -2,7 +2,7 @@
using Microsoft.AspNetCore.Mvc;
namespace ThingsGateway.Web.Entry.Controllers
namespace ThingsGateway.Application
{
/// <summary>
/// B端登录控制器
@@ -13,7 +13,10 @@ namespace ThingsGateway.Web.Entry.Controllers
public class AuthController : IDynamicApiController
{
private readonly IAuthService _authService;
/// <summary>
/// <inheritdoc cref="AuthController"/>
/// </summary>
/// <param name="authService"></param>
public AuthController(IAuthService authService)
{
_authService = authService;

View File

@@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Mvc;
using ThingsGateway.Application.Services.Auth;
namespace ThingsGateway.Web.Entry.Controllers
namespace ThingsGateway.Application
{
/// <summary>
/// OpenApi登录控制器
@@ -17,7 +17,10 @@ namespace ThingsGateway.Web.Entry.Controllers
public class OpenApiAuthController : IDynamicApiController
{
private readonly OpenApiAuthService _authService;
/// <summary>
/// <inheritdoc cref="OpenApiAuthController"/>
/// </summary>
/// <param name="authService"></param>
public OpenApiAuthController(OpenApiAuthService authService)
{
_authService = authService;

View File

@@ -1,11 +1,10 @@
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.DynamicApiController;
using Furion.SpecificationDocument;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
namespace ThingsGateway.Web.Entry.Controllers
namespace ThingsGateway.Application
{
/// <summary>
/// 系统登录授权服务
@@ -16,7 +15,11 @@ namespace ThingsGateway.Web.Entry.Controllers
{
private readonly IMemoryCache _cache;
private readonly ConfigService _configService;
/// <summary>
/// <inheritdoc cref="SwaggerController"/>
/// </summary>
/// <param name="sysConfigService"></param>
/// <param name="cache"></param>
public SwaggerController(ConfigService sysConfigService,
IMemoryCache cache)
{

View File

@@ -7,7 +7,11 @@
{
private readonly SqlSugarScope _db;
private readonly SysCacheService _sysCacheService;
/// <summary>
/// <inheritdoc cref="AuthEventSubscriber"/>
/// </summary>
/// <param name="sysCacheService"></param>
/// <param name="services"></param>
public AuthEventSubscriber(SysCacheService sysCacheService, IServiceProvider services)
{
_db = DbContext.Db;
@@ -15,7 +19,7 @@
this._services = services;
}
public IServiceProvider _services { get; }
private IServiceProvider _services { get; }
/// <summary>
/// 登录事件

View File

@@ -6,7 +6,10 @@
public class UserEventSubscriber : IEventSubscriber, ISingleton
{
private readonly IServiceProvider _services;
/// <summary>
/// <inheritdoc cref="UserEventSubscriber"/>
/// </summary>
/// <param name="services"></param>
public UserEventSubscriber(IServiceProvider services)
{
this._services = services;

View File

@@ -9,7 +9,9 @@ namespace ThingsGateway.Application
{
private readonly ICache _cache;
private string _symbol = "TBCache_TBCache";
/// <summary>
/// <inheritdoc cref="ApplicationCacheService"/>
/// </summary>
public ApplicationCacheService()
{
_cache = new MemoryCache();
@@ -18,8 +20,6 @@ namespace ThingsGateway.Application
/// <summary>
/// 检查缓存是否存在
/// </summary>
/// <param name="key">键</param>
/// <returns></returns>
public bool ExistKey(string prefixKey, string key)
{
var str = prefixKey + _symbol + key;
@@ -29,9 +29,6 @@ namespace ThingsGateway.Application
/// <summary>
/// 获取缓存
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
public T Get<T>(string prefixKey, string key)
{
var str = prefixKey + _symbol + key;
@@ -41,8 +38,6 @@ namespace ThingsGateway.Application
/// <summary>
/// 根据键名前缀获取缓存
/// </summary>
/// <param name="prefixKey">键名前缀</param>
/// <returns></returns>
public IDictionary<string, T> GetByPrefixKey<T>(string prefixKey)
{
var delKeys = _cache.Keys.Where(u => u.Split(_symbol).FirstOrDefault() == prefixKey).ToArray();
@@ -53,8 +48,6 @@ namespace ThingsGateway.Application
/// <summary>
/// 根据键名前缀获取全部中间key
/// </summary>
/// <param name="prefixKey">键名前缀</param>
/// <returns></returns>
public List<long> GetKeyByPrefixKey(string prefixKey)
{
var delKeys = _cache.Keys.SelectMany(u =>
@@ -74,9 +67,6 @@ namespace ThingsGateway.Application
/// <summary>
/// 获取缓存
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
public T GetOrAdd<T>(string prefixKey, string key, Func<string, T> func, int expire = -1)
{
var str = prefixKey + _symbol + key;
@@ -86,8 +76,6 @@ namespace ThingsGateway.Application
/// <summary>
/// 删除缓存
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public void Remove(string prefixKey, string key)
{
var str = prefixKey + _symbol + key;
@@ -109,9 +97,6 @@ namespace ThingsGateway.Application
/// <summary>
/// 增加缓存
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public void Set(string prefixKey, string key, object value)
{
var str = prefixKey + _symbol + key;
@@ -121,10 +106,6 @@ namespace ThingsGateway.Application
/// <summary>
/// 增加缓存并设置过期时间
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="expire"></param>
/// <returns></returns>
public void Set(string prefixKey, string key, object value, TimeSpan expire)
{
var str = prefixKey + _symbol + key;

View File

@@ -1,10 +1,12 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc;
using System.Globalization;
namespace ThingsGateway.Application
{
/// <summary>
/// 扩展方法
/// </summary>
public static class ApplicationExtension
{
private static ApplicationCacheService ApplicationCacheService;
@@ -14,6 +16,10 @@ namespace ThingsGateway.Application
ApplicationCacheService = App.GetService<ApplicationCacheService>();
}
/// <summary>
/// 获取全部Api授权树
/// </summary>
/// <returns></returns>
public static List<OpenApiPermissionTreeSelector> OpenApiPermissionTreeSelector()
{
var cacheKey = $"{nameof(OpenApiPermissionTreeSelector)}-{CultureInfo.CurrentUICulture.Name}";

View File

@@ -5,6 +5,7 @@ global using Furion.FriendlyException;
global using Mapster;
global using Microsoft.AspNetCore.Authorization;
global using Microsoft.AspNetCore.Http;
global using Microsoft.AspNetCore.SignalR;
global using Microsoft.CodeAnalysis;
@@ -15,13 +16,15 @@ global using NewLife.Serialization;
global using SqlSugar;
global using System;
global using System.ComponentModel;
global using System.ComponentModel.DataAnnotations;
global using System.Reflection;
global using System.Text;
global using System.Threading.Tasks;
global using ThingsGateway.Core;
global using ThingsGateway.Core.Extension;
global using ThingsGateway.Core.Utils;
global using Yitter.IdGenerator;

View File

@@ -1,7 +1,5 @@
using Furion.Schedule;
using System.Threading;
namespace ThingsGateway.Web.Core;
/// <summary>
@@ -12,12 +10,15 @@ namespace ThingsGateway.Web.Core;
public class LogJob : IJob
{
private readonly IServiceProvider _serviceProvider;
/// <summary>
/// <inheritdoc cref="LogJob"/>
/// </summary>
/// <param name="serviceProvider"></param>
public LogJob(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
/// <inheritdoc/>
public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
{
var db = DbContext.Db.CopyNew();

View File

@@ -7,7 +7,7 @@
{
private readonly SqlSugarScope _db;
private readonly SysCacheService _sysCacheService;
/// <inheritdoc/>
public OpenApiAuthEventSubscriber(SysCacheService sysCacheService, IServiceProvider services)
{
_db = DbContext.Db;
@@ -15,7 +15,7 @@
this._services = services;
}
public IServiceProvider _services { get; }
private IServiceProvider _services { get; }
/// <summary>
/// 登录事件

View File

@@ -5,6 +5,9 @@
/// </summary>
public class LoginOpenApiOutPut : BaseLoginOutPut
{
/// <summary>
/// TOKEN
/// </summary>
public string Token { get; set; }
}
}

View File

@@ -1,9 +1,20 @@
namespace ThingsGateway.Application.Services.Auth
{
/// <summary>
/// 登录服务
/// </summary>
public interface IOpenApiAuthService : ITransient
{
/// <summary>
/// 登录
/// </summary>
/// <param name="input">登录参数</param>
/// <returns>Token信息</returns>
Task<LoginOpenApiOutPut> LoginOpenApi(LoginOpenApiInput input);
/// <summary>
/// 登出
/// </summary>
/// <returns></returns>
Task LoginOut();
}
}

View File

@@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Authentication;
namespace ThingsGateway.Application.Services.Auth
{
/// <inheritdoc cref="IOpenApiAuthService"/>
public class OpenApiAuthService : IOpenApiAuthService, ITransient
{
private readonly IConfigService _configService;
@@ -11,6 +12,7 @@ namespace ThingsGateway.Application.Services.Auth
private readonly IOpenApiUserService _openApiUserService;
private readonly SysCacheService _sysCacheService;
/// <inheritdoc cref="IOpenApiAuthService"/>
public OpenApiAuthService(
IEventPublisher eventPublisher,
IOpenApiUserService openApiUserService,

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