node-red-contrib-example-scada 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +12 -0
- package/scada.html +133 -0
- package/scada.js +150 -0
package/package.json
ADDED
package/scada.html
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
RED.nodes.registerType('设备标签写入', {
|
|
3
|
+
category: 'scada',
|
|
4
|
+
color: '#a6bbcf',
|
|
5
|
+
defaults: {
|
|
6
|
+
broker: {type:"http-broker", required:true},
|
|
7
|
+
name: { value: "" },
|
|
8
|
+
id: { value: "", required: true },
|
|
9
|
+
WriteType: { value: "", required: true },
|
|
10
|
+
WriteDevCode: { value: "", required: true },
|
|
11
|
+
WriteCommand: { value: "" , required: true},
|
|
12
|
+
Value: { value: "", required: true },
|
|
13
|
+
ValueType: { value: "Short" , required: true},
|
|
14
|
+
|
|
15
|
+
},
|
|
16
|
+
inputs: 1, // 一个输入端口
|
|
17
|
+
outputs: 1, // 一个输出端口
|
|
18
|
+
icon: 'file.png', // 节点图标
|
|
19
|
+
label: function() {
|
|
20
|
+
return this.name || "设备标签写入";
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
RED.nodes.registerType('http-broker',{
|
|
28
|
+
category: 'config',
|
|
29
|
+
defaults: {
|
|
30
|
+
host: {value:"localhost",required:true},
|
|
31
|
+
port: {value:1234,required:true,validate:RED.validators.number()},
|
|
32
|
+
},
|
|
33
|
+
label: function() {
|
|
34
|
+
return this.host+":"+this.port;
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
RED.nodes.registerType('获取单个设备采集值', {
|
|
39
|
+
category: 'scada', // 节点类别
|
|
40
|
+
color: '#a6bbcf', // 节点颜色
|
|
41
|
+
defaults: {
|
|
42
|
+
broker: {type:"http-broker", required:true},
|
|
43
|
+
name: { value: '' }, // 节点名称
|
|
44
|
+
deviceCode: { value: '' } // 用户输入的 deviceCode
|
|
45
|
+
},
|
|
46
|
+
inputs: 1, // 一个输入端口
|
|
47
|
+
outputs: 1, // 一个输出端口
|
|
48
|
+
icon: 'file.png', // 节点图标
|
|
49
|
+
label: function() { // 标签显示
|
|
50
|
+
return this.name || '获取单个设备采集值'; // 如果有名称,则显示名称,否则显示默认名称
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<script type="text/html" data-template-name="设备标签写入">
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
<div class="form-row">
|
|
60
|
+
<label for="node-input-broker"><i class="fa fa-globe"></i> 服务器</span></label>
|
|
61
|
+
<input type="text" id="node-input-broker">
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
<div class="form-row">
|
|
67
|
+
<label for="node-input-name"><i class="fa fa-tag"></i>名称 </label>
|
|
68
|
+
<input type="text" id="node-input-name" placeholder="node 名称" class="node-input">
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
<div class="form-row">
|
|
73
|
+
<label for="node-input-id"><i class="fa fa-tag"></i> ID格式:</label>
|
|
74
|
+
<select id="node-input-id" class="node-input" >
|
|
75
|
+
<option value="YYYYMMDD">YYYYMMDD</option>
|
|
76
|
+
<option value="HHmmss">HHmmss</option>
|
|
77
|
+
<option value="YYYYMMDDHHmmss">YYYYMMDDHHmmss</option>
|
|
78
|
+
</select>
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
<div class="form-row">
|
|
82
|
+
<label for="node-input-WriteType"><i class="fa fa-tag"></i> ID格式:</label>
|
|
83
|
+
<select id="node-input-WriteType" class="node-input" >
|
|
84
|
+
<option value="1">标签写入</option>
|
|
85
|
+
<option value="2">地址写入</option>
|
|
86
|
+
</select>
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
<div class="form-row">
|
|
90
|
+
<label for="node-input-WriteDevCode"><i class="fa fa-tag"></i> 写入设备号:</label>
|
|
91
|
+
<input type="text" id="node-input-WriteDevCode" placeholder="写入设备,注意:不带站号" class="node-input">
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
<div class="form-row">
|
|
95
|
+
<label for="node-input-WriteCommand"><i class="fa fa-tag"></i> 写入命令:</label>
|
|
96
|
+
<input type="text" id="node-input-WriteCommand" placeholder="当通过标签写入时为标签名,当通过地址写入时为写入地址" class="node-input">
|
|
97
|
+
</div>
|
|
98
|
+
<div class="form-row">
|
|
99
|
+
<label for="node-input-Value"><i class="fa fa-tag"></i> 写入目标值:</label>
|
|
100
|
+
<input type="text" id="node-input-Value" placeholder="写入目标值" class="node-input">
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
</script>
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
<script type="text/html" data-template-name="http-broker">
|
|
108
|
+
<div class="form-row">
|
|
109
|
+
<label for="node-config-input-host"><i class="fa fa-bookmark"></i> Host</label>
|
|
110
|
+
<input type="text" id="node-config-input-host">
|
|
111
|
+
</div>
|
|
112
|
+
<div class="form-row">
|
|
113
|
+
<label for="node-config-input-port"><i class="fa fa-bookmark"></i> Port</label>
|
|
114
|
+
<input type="text" id="node-config-input-port">
|
|
115
|
+
</div>
|
|
116
|
+
</script>
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
<script type="text/html" data-template-name="获取单个设备采集值">
|
|
120
|
+
<div class="form-row">
|
|
121
|
+
<label for="node-input-broker"><i class="fa fa-globe"></i> 服务器</span></label>
|
|
122
|
+
<input type="text" id="node-input-broker">
|
|
123
|
+
</div>
|
|
124
|
+
<div class="form-row">
|
|
125
|
+
<label for="node-input-name"><i class="fa fa-tag"></i> 名称</label>
|
|
126
|
+
<input type="text" id="node-input-name" placeholder="Node Name" class="node-input">
|
|
127
|
+
</div>
|
|
128
|
+
|
|
129
|
+
<div class="form-row">
|
|
130
|
+
<label for="node-input-deviceCode"><i class="fa fa-cogs"></i> 设备号</label>
|
|
131
|
+
<input type="text" id="node-input-deviceCode" placeholder="Enter Device Code" class="node-input">
|
|
132
|
+
</div>
|
|
133
|
+
</script>
|
package/scada.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
|
|
2
|
+
module.exports = function(RED) {
|
|
3
|
+
|
|
4
|
+
//设备标签写入配置
|
|
5
|
+
// 创建请求
|
|
6
|
+
const axios = require('axios');
|
|
7
|
+
function WriteDeviceConfigNode(config) {
|
|
8
|
+
RED.nodes.createNode(this, config);
|
|
9
|
+
var node = this;
|
|
10
|
+
|
|
11
|
+
function getCurrentFormattedDate(format = 'YYYYMMDD HHmmss') {
|
|
12
|
+
const now = new Date();
|
|
13
|
+
|
|
14
|
+
// 获取各个部分的时间
|
|
15
|
+
const year = now.getFullYear();
|
|
16
|
+
const month = String(now.getMonth() + 1).padStart(2, '0');
|
|
17
|
+
const day = String(now.getDate()).padStart(2, '0');
|
|
18
|
+
const hours = String(now.getHours()).padStart(2, '0');
|
|
19
|
+
const minutes = String(now.getMinutes()).padStart(2, '0');
|
|
20
|
+
const seconds = String(now.getSeconds()).padStart(2, '0');
|
|
21
|
+
|
|
22
|
+
// 替换格式中的占位符
|
|
23
|
+
return format
|
|
24
|
+
.replace('YYYY', year)
|
|
25
|
+
.replace('MM', month)
|
|
26
|
+
.replace('DD', day)
|
|
27
|
+
.replace('HH', hours)
|
|
28
|
+
.replace('mm', minutes)
|
|
29
|
+
.replace('ss', seconds);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
// 处理输入消息
|
|
35
|
+
this.on('input', function(msg) {
|
|
36
|
+
var id1 = msg.id || config.id;
|
|
37
|
+
var id = getCurrentFormattedDate(id1);
|
|
38
|
+
var WriteType = msg.WriteType || config.WriteType;
|
|
39
|
+
var WriteDevCode = msg.WriteDevCode || config.WriteDevCode;
|
|
40
|
+
var WriteCommand = msg.WriteCommand || config.WriteCommand;
|
|
41
|
+
var Value = msg.Value || config.Value;
|
|
42
|
+
var ValueType = msg.ValueType || config.ValueType;
|
|
43
|
+
|
|
44
|
+
// 构建 JSON 请求体
|
|
45
|
+
const payload = {
|
|
46
|
+
id: id,
|
|
47
|
+
WriteType: WriteType,
|
|
48
|
+
WriteDevCode: WriteDevCode,
|
|
49
|
+
WriteCommand: WriteCommand,
|
|
50
|
+
Value: Value,
|
|
51
|
+
ValueType: ValueType
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
// 设置 API 请求的 URL
|
|
56
|
+
var broker = RED.nodes.getNode(config.broker);
|
|
57
|
+
const url = "http://" + broker.host + ":" + broker.port + "/api/ScadaConfig/WriteDevices";
|
|
58
|
+
axios.post(url, payload)
|
|
59
|
+
.then(response => {
|
|
60
|
+
if(response.data.code == 200){
|
|
61
|
+
msg.payload = response.data;
|
|
62
|
+
node.send(msg);
|
|
63
|
+
node.status({ fill: "green", shape: "dot", text: "Success" });
|
|
64
|
+
|
|
65
|
+
}else {
|
|
66
|
+
node.error("Request failed: " + response.data.message);
|
|
67
|
+
node.status({fill: "red", shape: "ring", text: "Error"});
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
.catch(error => {
|
|
71
|
+
// 请求失败,记录错误
|
|
72
|
+
node.error("Request failed: " + error.message, msg);
|
|
73
|
+
msg.payload = { error: error.message };
|
|
74
|
+
node.status({ fill: "red", shape: "ring", text: "Error" });
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// 注册自定义节点
|
|
80
|
+
RED.nodes.registerType('设备标签写入', WriteDeviceConfigNode);
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
//http-broker配置
|
|
89
|
+
function RemoteServerNode(n) {
|
|
90
|
+
RED.nodes.createNode(this,n);
|
|
91
|
+
this.host = n.host;
|
|
92
|
+
this.port = n.port;
|
|
93
|
+
}
|
|
94
|
+
RED.nodes.registerType("http-broker",RemoteServerNode);
|
|
95
|
+
|
|
96
|
+
//获取单个设备采集值配置
|
|
97
|
+
function MyHttpNode(config) {
|
|
98
|
+
RED.nodes.createNode(this, config);
|
|
99
|
+
var node = this;
|
|
100
|
+
|
|
101
|
+
// 每次接收到消息时处理
|
|
102
|
+
this.on('input', function(msg) {
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
// 设置 API 请求的 URL
|
|
106
|
+
var broker = RED.nodes.getNode(config.broker);
|
|
107
|
+
var baseURL = "http://" + broker.host + ":" + broker.port + '/api/ScadaConfig/GetDevice?deviceCode={{deviceCode}}';
|
|
108
|
+
|
|
109
|
+
// 从消息中获取 deviceCode 或从节点配置中获取
|
|
110
|
+
var deviceCode = msg.deviceCode || config.deviceCode;
|
|
111
|
+
|
|
112
|
+
// 如果没有提供 deviceCode,返回错误
|
|
113
|
+
if (!deviceCode) {
|
|
114
|
+
node.error("deviceCode is missing");
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// 动态替换 URL 中的 {{deviceCode}}
|
|
119
|
+
var url = baseURL.replace('{{deviceCode}}', deviceCode);
|
|
120
|
+
|
|
121
|
+
// 使用 axios 发送 GET 请求
|
|
122
|
+
axios.get(url)
|
|
123
|
+
.then(response => {
|
|
124
|
+
if(response.data.code == 200 && response.data.msg != "null"){
|
|
125
|
+
msg.payload = response.data;
|
|
126
|
+
node.send(msg);
|
|
127
|
+
node.status({ fill: "green", shape: "dot", text: "Success" });
|
|
128
|
+
|
|
129
|
+
}else {
|
|
130
|
+
node.error("Request failed: 找不到该设备" );
|
|
131
|
+
node.status({fill: "red", shape: "ring", text: "Error"});
|
|
132
|
+
}
|
|
133
|
+
})
|
|
134
|
+
.catch(error => {
|
|
135
|
+
// 请求失败,记录错误并将错误信息传递到下游节点
|
|
136
|
+
node.error("Request failed: " + error.message, msg);
|
|
137
|
+
msg.payload = { error: error.message };
|
|
138
|
+
node.status({ fill: "red", shape: "ring", text: "Error" });
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// 注册自定义节点
|
|
147
|
+
RED.nodes.registerType("获取单个设备采集值", MyHttpNode);
|
|
148
|
+
|
|
149
|
+
};
|
|
150
|
+
|