smart-nodes 0.3.15 → 0.3.26
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/LICENSE.md +1 -1
- package/README.md +51 -21
- package/central/central.js +12 -8
- package/compare/compare.html +48 -0
- package/compare/compare.js +36 -20
- package/counter/counter.html +104 -0
- package/counter/counter.js +120 -0
- package/delay/delay.js +39 -37
- package/examples/heating-curve.json +480 -0
- package/examples/heating-curve.png +0 -0
- package/examples/mixing-valve.json +622 -0
- package/examples/mixing-valve.png +0 -0
- package/forwarder/forwarder.js +28 -26
- package/heating-curve/heating-curve.html +348 -0
- package/heating-curve/heating-curve.js +134 -0
- package/hysteresis/hysteresis.js +58 -45
- package/icons/smart_counter.png +0 -0
- package/light-control/light-control.js +42 -30
- package/logic/logic.html +18 -2
- package/logic/logic.js +25 -23
- package/long-press-control/long-press-control.js +6 -4
- package/mixing-valve/mixing-valve.html +188 -0
- package/mixing-valve/mixing-valve.js +357 -0
- package/multi-press-control/multi-press-control.js +3 -1
- package/package.json +8 -1
- package/scene-control/scene-control.js +37 -27
- package/scheduler/scheduler.js +27 -25
- package/shutter-complex-control/shutter-complex-control.js +64 -62
- package/shutter-control/shutter-control.js +41 -37
- package/smart_helper.js +156 -5
- package/statistic/statistic.js +30 -28
- package/text-exec/text-exec.js +14 -6
- package/LICENSE +0 -21
package/hysteresis/hysteresis.js
CHANGED
|
@@ -1,36 +1,39 @@
|
|
|
1
|
-
|
|
2
1
|
module.exports = function (RED)
|
|
3
2
|
{
|
|
3
|
+
"use strict";
|
|
4
|
+
|
|
4
5
|
function HysteresisNode(config)
|
|
5
6
|
{
|
|
6
7
|
const node = this;
|
|
7
8
|
RED.nodes.createNode(node, config);
|
|
8
9
|
|
|
9
|
-
const
|
|
10
|
+
const smart_context = require("../persistence.js")(RED);
|
|
10
11
|
const helper = require("../smart_helper.js");
|
|
11
12
|
|
|
12
|
-
var
|
|
13
|
+
var node_settings = {
|
|
13
14
|
active: null,
|
|
14
|
-
|
|
15
|
+
last_message: null,
|
|
16
|
+
setpoint: parseFloat(config.setpoint),
|
|
17
|
+
hysteresis: parseFloat(config.hysteresis)
|
|
15
18
|
};
|
|
16
19
|
|
|
17
20
|
if (config.save_state)
|
|
18
21
|
{
|
|
19
22
|
// load old saved values
|
|
20
|
-
|
|
23
|
+
node_settings = Object.assign(node_settings, smart_context.get(node.id));
|
|
21
24
|
|
|
22
|
-
switch (
|
|
25
|
+
switch (node_settings.active)
|
|
23
26
|
{
|
|
24
27
|
case true:
|
|
25
|
-
node.status({ fill: "green", shape: "dot", text:
|
|
28
|
+
node.status({ fill: "green", shape: "dot", text: helper.getCurrentTimeForStatus() + ": Load last state: Higher" });
|
|
26
29
|
break;
|
|
27
30
|
|
|
28
31
|
case false:
|
|
29
|
-
node.status({ fill: "red", shape: "dot", text:
|
|
32
|
+
node.status({ fill: "red", shape: "dot", text: helper.getCurrentTimeForStatus() + ": Load last state: Lower" });
|
|
30
33
|
break;
|
|
31
34
|
|
|
32
35
|
default:
|
|
33
|
-
node.status({ fill: "yellow", shape: "ring", text:
|
|
36
|
+
node.status({ fill: "yellow", shape: "ring", text: helper.getCurrentTimeForStatus() + ": No last state available" });
|
|
34
37
|
break;
|
|
35
38
|
}
|
|
36
39
|
}
|
|
@@ -38,12 +41,10 @@ module.exports = function (RED)
|
|
|
38
41
|
{
|
|
39
42
|
// delete old saved values
|
|
40
43
|
node.status({});
|
|
41
|
-
|
|
44
|
+
smart_context.del(node.id);
|
|
42
45
|
}
|
|
43
46
|
|
|
44
47
|
// dynamic config
|
|
45
|
-
let setpoint = parseFloat(config.setpoint);
|
|
46
|
-
let hysteresis = parseFloat(config.hysteresis);
|
|
47
48
|
let out_higher = helper.evaluateNodeProperty(RED, config.out_higher, config.out_higher_type);
|
|
48
49
|
let out_lower = helper.evaluateNodeProperty(RED, config.out_lower, config.out_lower_type);
|
|
49
50
|
|
|
@@ -52,75 +53,75 @@ module.exports = function (RED)
|
|
|
52
53
|
node.on("input", function (msg)
|
|
53
54
|
{
|
|
54
55
|
let value = parseFloat(msg.payload);
|
|
55
|
-
let
|
|
56
|
+
let real_topic = helper.getTopicName(msg.topic);
|
|
56
57
|
|
|
57
|
-
if (isNaN(value) &&
|
|
58
|
+
if (isNaN(value) && real_topic !== "resend")
|
|
58
59
|
{
|
|
59
60
|
// node.error("Invalid payload: " + msg.payload);
|
|
60
61
|
return;
|
|
61
62
|
}
|
|
62
63
|
|
|
63
|
-
switch (
|
|
64
|
+
switch (real_topic)
|
|
64
65
|
{
|
|
65
66
|
case "setpoint":
|
|
66
|
-
setpoint = value;
|
|
67
|
-
node.status({ fill:
|
|
67
|
+
node_settings.setpoint = value;
|
|
68
|
+
node.status({ fill: node_settings.active ? "green" : "red", shape: "ring", text: helper.getCurrentTimeForStatus() + ": New setpoint: " + value + "" });
|
|
68
69
|
|
|
69
70
|
if (config.save_state)
|
|
70
|
-
|
|
71
|
+
smart_context.set(node.id, node_settings);
|
|
71
72
|
break;
|
|
72
73
|
|
|
73
74
|
case "hysteresis":
|
|
74
|
-
hysteresis = value;
|
|
75
|
-
node.status({ fill:
|
|
75
|
+
node_settings.hysteresis = value;
|
|
76
|
+
node.status({ fill: node_settings.active ? "green" : "red", shape: "ring", text: helper.getCurrentTimeForStatus() + ": New hysteresis: " + value + "" });
|
|
76
77
|
|
|
77
78
|
if (config.save_state)
|
|
78
|
-
|
|
79
|
+
smart_context.set(node.id, node_settings);
|
|
79
80
|
break;
|
|
80
81
|
|
|
81
82
|
case "resend":
|
|
82
|
-
if (
|
|
83
|
+
if (node_settings.active === true && node_settings.last_message != null)
|
|
83
84
|
{
|
|
84
|
-
node.status({ fill: "green", shape: "dot", text:
|
|
85
|
-
node.send([
|
|
85
|
+
node.status({ fill: "green", shape: "dot", text: helper.getCurrentTimeForStatus() + ": Resend higher value" });
|
|
86
|
+
node.send([node_settings.last_message, null]);
|
|
86
87
|
}
|
|
87
|
-
else if (
|
|
88
|
+
else if (node_settings.active === false && node_settings.last_message != null)
|
|
88
89
|
{
|
|
89
|
-
node.status({ fill: "red", shape: "dot", text:
|
|
90
|
-
node.send([null,
|
|
90
|
+
node.status({ fill: "red", shape: "dot", text: helper.getCurrentTimeForStatus() + ": Resend lower value" });
|
|
91
|
+
node.send([null, node_settings.last_message]);
|
|
91
92
|
}
|
|
92
93
|
else
|
|
93
94
|
{
|
|
94
|
-
node.status({ fill: "yellow", shape: "ring", text:
|
|
95
|
+
node.status({ fill: "yellow", shape: "ring", text: helper.getCurrentTimeForStatus() + ": No resend, state is unknown" });
|
|
95
96
|
}
|
|
96
97
|
break;
|
|
97
98
|
|
|
98
99
|
default:
|
|
99
|
-
if (value >= setpoint + hysteresis &&
|
|
100
|
+
if (value >= node_settings.setpoint + node_settings.hysteresis && node_settings.active !== true)
|
|
100
101
|
{
|
|
101
|
-
node.status({ fill: "green", shape: "dot", text:
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
node.status({ fill: "green", shape: "dot", text: helper.getCurrentTimeForStatus() + ": Turned higher by value " + value + "" });
|
|
103
|
+
node_settings.active = true;
|
|
104
|
+
node_settings.last_message = createMessage(out_higher ?? msg, value);
|
|
104
105
|
|
|
105
106
|
if (config.save_state)
|
|
106
|
-
|
|
107
|
+
smart_context.set(node.id, node_settings);
|
|
107
108
|
|
|
108
|
-
node.send([
|
|
109
|
+
node.send([node_settings.last_message, null]);
|
|
109
110
|
}
|
|
110
|
-
else if (value <= setpoint - hysteresis &&
|
|
111
|
+
else if (value <= node_settings.setpoint - node_settings.hysteresis && node_settings.active !== false)
|
|
111
112
|
{
|
|
112
|
-
node.status({ fill: "red", shape: "dot", text:
|
|
113
|
-
|
|
114
|
-
|
|
113
|
+
node.status({ fill: "red", shape: "dot", text: helper.getCurrentTimeForStatus() + ": Turned lower by value " + value + "" });
|
|
114
|
+
node_settings.active = false;
|
|
115
|
+
node_settings.last_message = createMessage(out_lower ?? msg, value);
|
|
115
116
|
|
|
116
117
|
if (config.save_state)
|
|
117
|
-
|
|
118
|
+
smart_context.set(node.id, node_settings);
|
|
118
119
|
|
|
119
|
-
node.send([null,
|
|
120
|
+
node.send([null, node_settings.last_message]);
|
|
120
121
|
}
|
|
121
122
|
else
|
|
122
123
|
{
|
|
123
|
-
node.status({ fill:
|
|
124
|
+
node.status({ fill: node_settings.active ? "green" : "red", shape: "ring", text: helper.getCurrentTimeForStatus() + ": No change by value " + value + "" });
|
|
124
125
|
}
|
|
125
126
|
break;
|
|
126
127
|
}
|
|
@@ -130,14 +131,26 @@ module.exports = function (RED)
|
|
|
130
131
|
{
|
|
131
132
|
});
|
|
132
133
|
|
|
133
|
-
|
|
134
|
+
let createMessage = (msg, value) =>
|
|
135
|
+
{
|
|
136
|
+
return Object.assign({}, msg, {
|
|
137
|
+
smart_info: {
|
|
138
|
+
active: node_settings.active,
|
|
139
|
+
hysteresis: node_settings.hysteresis,
|
|
140
|
+
setpoint: node_settings.setpoint,
|
|
141
|
+
last_value: value
|
|
142
|
+
}
|
|
143
|
+
})
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
if (config.save_state && config.resend_on_start && node_settings.active != null && node_settings.last_message != null)
|
|
134
147
|
{
|
|
135
148
|
setTimeout(() =>
|
|
136
149
|
{
|
|
137
|
-
if (
|
|
138
|
-
node.send([
|
|
150
|
+
if (node_settings.active)
|
|
151
|
+
node.send([node_settings.last_message, null]);
|
|
139
152
|
else
|
|
140
|
-
node.send([null,
|
|
153
|
+
node.send([null, node_settings.last_message]);
|
|
141
154
|
}, 10000);
|
|
142
155
|
}
|
|
143
156
|
}
|
|
Binary file
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
module.exports = function (RED)
|
|
2
2
|
{
|
|
3
|
+
"use strict";
|
|
4
|
+
|
|
3
5
|
function LightControlNode(config)
|
|
4
6
|
{
|
|
5
7
|
const node = this;
|
|
6
8
|
RED.nodes.createNode(node, config);
|
|
7
9
|
|
|
8
|
-
const
|
|
10
|
+
const smart_context = require("../persistence.js")(RED);
|
|
9
11
|
const helper = require("../smart_helper.js");
|
|
10
12
|
|
|
11
13
|
// used from text-exec node
|
|
@@ -15,9 +17,9 @@ module.exports = function (RED)
|
|
|
15
17
|
node.exec_text_names = [];
|
|
16
18
|
|
|
17
19
|
// persistent values
|
|
18
|
-
var
|
|
20
|
+
var node_settings = Object.assign({}, {
|
|
19
21
|
last_value: false,
|
|
20
|
-
},
|
|
22
|
+
}, smart_context.get(node.id));
|
|
21
23
|
|
|
22
24
|
// dynamic config
|
|
23
25
|
let max_time_on = helper.getTimeInMs(config.max_time_on, config.max_time_on_unit);
|
|
@@ -27,7 +29,7 @@ module.exports = function (RED)
|
|
|
27
29
|
let max_time_on_timeout = null;
|
|
28
30
|
let isPermanent = false;
|
|
29
31
|
let isMotion = false;
|
|
30
|
-
let
|
|
32
|
+
let timeout_end_date = null;
|
|
31
33
|
let alarm_active = false;
|
|
32
34
|
|
|
33
35
|
// central handling
|
|
@@ -44,7 +46,7 @@ module.exports = function (RED)
|
|
|
44
46
|
handleTopic(msg);
|
|
45
47
|
|
|
46
48
|
setStatus();
|
|
47
|
-
|
|
49
|
+
smart_context.set(node.id, node_settings);
|
|
48
50
|
});
|
|
49
51
|
|
|
50
52
|
node.on("close", function ()
|
|
@@ -62,9 +64,11 @@ module.exports = function (RED)
|
|
|
62
64
|
case "status":
|
|
63
65
|
// Make sure it is bool
|
|
64
66
|
msg.payload = !!msg.payload;
|
|
65
|
-
doRestartTimer = nodeSettings.last_value != msg.payload;
|
|
66
67
|
|
|
67
|
-
|
|
68
|
+
if (node_settings.last_value == msg.payload && max_time_on_timeout != null)
|
|
69
|
+
doRestartTimer = false;
|
|
70
|
+
|
|
71
|
+
node_settings.last_value = msg.payload;
|
|
68
72
|
break;
|
|
69
73
|
|
|
70
74
|
case "off":
|
|
@@ -72,7 +76,7 @@ module.exports = function (RED)
|
|
|
72
76
|
if (msg.payload === false)
|
|
73
77
|
return;
|
|
74
78
|
|
|
75
|
-
|
|
79
|
+
node_settings.last_value = false;
|
|
76
80
|
break;
|
|
77
81
|
|
|
78
82
|
case "on":
|
|
@@ -80,19 +84,19 @@ module.exports = function (RED)
|
|
|
80
84
|
if (msg.payload === false)
|
|
81
85
|
return;
|
|
82
86
|
|
|
83
|
-
|
|
87
|
+
node_settings.last_value = true;
|
|
84
88
|
break;
|
|
85
89
|
|
|
86
90
|
case "set":
|
|
87
91
|
// Make sure it is bool
|
|
88
92
|
msg.payload = !!msg.payload;
|
|
89
|
-
|
|
93
|
+
node_settings.last_value = msg.payload;
|
|
90
94
|
break;
|
|
91
95
|
|
|
92
96
|
case "set_permanent":
|
|
93
97
|
// Make sure it is bool
|
|
94
98
|
msg.payload = !!msg.payload;
|
|
95
|
-
|
|
99
|
+
node_settings.last_value = msg.payload;
|
|
96
100
|
isPermanent = msg.payload;
|
|
97
101
|
break;
|
|
98
102
|
|
|
@@ -104,16 +108,16 @@ module.exports = function (RED)
|
|
|
104
108
|
if (msg.payload == false)
|
|
105
109
|
{
|
|
106
110
|
// It already was off, so don't turn on
|
|
107
|
-
if (
|
|
111
|
+
if (node_settings.last_value == false)
|
|
108
112
|
return;
|
|
109
113
|
|
|
110
114
|
// If time is set to 0, then turn off immediately
|
|
111
115
|
if (helper.getTimeInMsFromString(msg.time_on ?? max_time_on) == 0)
|
|
112
|
-
|
|
116
|
+
node_settings.last_value = false;
|
|
113
117
|
}
|
|
114
118
|
else
|
|
115
119
|
{
|
|
116
|
-
|
|
120
|
+
node_settings.last_value = true;
|
|
117
121
|
}
|
|
118
122
|
break;
|
|
119
123
|
|
|
@@ -129,7 +133,7 @@ module.exports = function (RED)
|
|
|
129
133
|
if (msg.payload === false)
|
|
130
134
|
return;
|
|
131
135
|
|
|
132
|
-
|
|
136
|
+
node_settings.last_value = !node_settings.last_value;
|
|
133
137
|
break;
|
|
134
138
|
}
|
|
135
139
|
|
|
@@ -144,24 +148,24 @@ module.exports = function (RED)
|
|
|
144
148
|
switch (alarm_action)
|
|
145
149
|
{
|
|
146
150
|
case "ON":
|
|
147
|
-
|
|
151
|
+
node_settings.last_value = true;
|
|
148
152
|
break;
|
|
149
153
|
|
|
150
154
|
default:
|
|
151
155
|
case "OFF":
|
|
152
|
-
|
|
156
|
+
node_settings.last_value = false;
|
|
153
157
|
break;
|
|
154
158
|
}
|
|
155
159
|
}
|
|
156
160
|
|
|
157
161
|
if (alarm_active || helper.getTopicName(msg.topic) != "status")
|
|
158
|
-
node.send({ payload:
|
|
162
|
+
node.send({ payload: node_settings.last_value });
|
|
159
163
|
|
|
160
164
|
// Output is on, now
|
|
161
|
-
if (
|
|
165
|
+
if (node_settings.last_value && doRestartTimer)
|
|
162
166
|
startAutoOffIfNeeded(helper.getTimeInMsFromString(msg.time_on ?? max_time_on));
|
|
163
167
|
|
|
164
|
-
notifyCentral(
|
|
168
|
+
notifyCentral(node_settings.last_value);
|
|
165
169
|
}
|
|
166
170
|
|
|
167
171
|
let startAutoOffIfNeeded = origTimeMs =>
|
|
@@ -178,24 +182,26 @@ module.exports = function (RED)
|
|
|
178
182
|
timeMs = max_time_on;
|
|
179
183
|
}
|
|
180
184
|
|
|
181
|
-
|
|
185
|
+
// calculate end date for status message
|
|
186
|
+
timeout_end_date = new Date();
|
|
187
|
+
timeout_end_date.setMilliseconds(timeout_end_date.getMilliseconds() + timeMs);
|
|
182
188
|
|
|
183
189
|
// Stop if any timeout is set
|
|
184
190
|
stopAutoOff();
|
|
185
191
|
|
|
186
192
|
// 0 = Always on
|
|
187
|
-
if (timeMs <= 0 || isPermanent || isMotion || !
|
|
193
|
+
if (timeMs <= 0 || isPermanent || isMotion || !node_settings.last_value)
|
|
188
194
|
return;
|
|
189
195
|
|
|
190
196
|
max_time_on_timeout = setTimeout(() =>
|
|
191
197
|
{
|
|
192
198
|
max_time_on_timeout = null;
|
|
193
|
-
|
|
199
|
+
node_settings.last_value = false;
|
|
194
200
|
node.send({ payload: false });
|
|
195
201
|
notifyCentral(false);
|
|
196
202
|
|
|
197
203
|
setStatus();
|
|
198
|
-
|
|
204
|
+
smart_context.set(node.id, node_settings);
|
|
199
205
|
}, timeMs);
|
|
200
206
|
};
|
|
201
207
|
|
|
@@ -212,18 +218,18 @@ module.exports = function (RED)
|
|
|
212
218
|
{
|
|
213
219
|
if (alarm_active)
|
|
214
220
|
{
|
|
215
|
-
node.status({ fill: "red", shape: "dot", text:
|
|
221
|
+
node.status({ fill: "red", shape: "dot", text: helper.getCurrentTimeForStatus() + ": ALARM is active" });
|
|
216
222
|
}
|
|
217
|
-
else if (
|
|
223
|
+
else if (node_settings.last_value)
|
|
218
224
|
{
|
|
219
|
-
if (isPermanent || isMotion ||
|
|
220
|
-
node.status({ fill: "green", shape: "dot", text:
|
|
225
|
+
if (isPermanent || isMotion || timeout_end_date == null)
|
|
226
|
+
node.status({ fill: "green", shape: "dot", text: helper.getCurrentTimeForStatus() + ": On" });
|
|
221
227
|
else if (max_time_on_timeout)
|
|
222
|
-
node.status({ fill: "yellow", shape: "ring", text:
|
|
228
|
+
node.status({ fill: "yellow", shape: "ring", text: helper.getCurrentTimeForStatus() + ": Wait " + helper.formatDateToStatus(timeout_end_date, "until") + " for auto off" });
|
|
223
229
|
}
|
|
224
230
|
else
|
|
225
231
|
{
|
|
226
|
-
node.status({ fill: "red", shape: "dot", text:
|
|
232
|
+
node.status({ fill: "red", shape: "dot", text: helper.getCurrentTimeForStatus() + ": Off" });
|
|
227
233
|
}
|
|
228
234
|
}
|
|
229
235
|
|
|
@@ -234,10 +240,16 @@ module.exports = function (RED)
|
|
|
234
240
|
|
|
235
241
|
config.links.forEach(link =>
|
|
236
242
|
{
|
|
243
|
+
// console.log(node.id + " -> " + link);
|
|
244
|
+
// console.log({ source: node.id, state: state });
|
|
237
245
|
RED.events.emit("node:" + link, { source: node.id, state: state });
|
|
238
246
|
});
|
|
239
247
|
}
|
|
240
248
|
|
|
249
|
+
// After node red restart, start also the timeout
|
|
250
|
+
if (node_settings.last_value)
|
|
251
|
+
startAutoOffIfNeeded(helper.getTimeInMsFromString(max_time_on));
|
|
252
|
+
|
|
241
253
|
setStatus();
|
|
242
254
|
}
|
|
243
255
|
|
package/logic/logic.html
CHANGED
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
inverts: { value: "" },
|
|
11
11
|
invert_output: { value: false },
|
|
12
12
|
out_false: { value: '{"topic": ""}' },
|
|
13
|
+
out_false_type: { value: 'json' },
|
|
13
14
|
out_true: { value: '{"topic": ""}' },
|
|
15
|
+
out_true_type: { value: 'json' },
|
|
14
16
|
save_state: { value: true },
|
|
15
17
|
resend_on_start: { value: true }
|
|
16
18
|
},
|
|
@@ -66,12 +68,24 @@
|
|
|
66
68
|
|
|
67
69
|
$("#node-input-out_true").typedInput({
|
|
68
70
|
type: "json",
|
|
69
|
-
types: ["json"
|
|
71
|
+
types: ["json", {
|
|
72
|
+
value: "null",
|
|
73
|
+
label: "Nichts senden",
|
|
74
|
+
icon: "fa fa-times",
|
|
75
|
+
hasValue: false,
|
|
76
|
+
}],
|
|
77
|
+
typeField: "#node-input-out_true_type"
|
|
70
78
|
});
|
|
71
79
|
|
|
72
80
|
$("#node-input-out_false").typedInput({
|
|
73
81
|
type: "json",
|
|
74
|
-
types: ["json"
|
|
82
|
+
types: ["json", {
|
|
83
|
+
value: "null",
|
|
84
|
+
label: "Nichts senden",
|
|
85
|
+
icon: "fa fa-times",
|
|
86
|
+
hasValue: false,
|
|
87
|
+
}],
|
|
88
|
+
typeField: "#node-input-out_false_type"
|
|
75
89
|
});
|
|
76
90
|
|
|
77
91
|
$("#node-input-save_state").on("change", ev =>
|
|
@@ -137,10 +151,12 @@
|
|
|
137
151
|
<div class="form-row">
|
|
138
152
|
<label for="node-input-out_true"><i class="fa fa-check-circle"></i> Wahr</label>
|
|
139
153
|
<input type="text" id="node-input-out_true"/>
|
|
154
|
+
<input type="hidden" id="node-input-out_true_type">
|
|
140
155
|
</div>
|
|
141
156
|
<div class="form-row">
|
|
142
157
|
<label for="node-input-out_false"><i class="fa fa-times-circle"></i> Falsch</label>
|
|
143
158
|
<input type="text" id="node-input-out_false" />
|
|
159
|
+
<input type="hidden" id="node-input-out_false_type">
|
|
144
160
|
</div>
|
|
145
161
|
<div class="form-row">
|
|
146
162
|
<span><strong>Hinweis:</strong> <code>msg.payload</code> wird automatisch auf das Logik-Ergebnis gesetzt.</span>
|
package/logic/logic.js
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
module.exports = function (RED)
|
|
2
2
|
{
|
|
3
|
+
"use strict";
|
|
4
|
+
|
|
3
5
|
function LogicNode(config)
|
|
4
6
|
{
|
|
5
7
|
const node = this;
|
|
6
8
|
RED.nodes.createNode(node, config);
|
|
7
9
|
|
|
8
|
-
const
|
|
10
|
+
const smart_context = require("../persistence.js")(RED);
|
|
9
11
|
const helper = require("../smart_helper.js");
|
|
10
12
|
|
|
11
13
|
// dynamic config
|
|
12
14
|
let logic = config.logic;
|
|
13
|
-
let out_true = helper.evaluateNodeProperty(RED, config.out_true, "json");
|
|
14
|
-
let out_false = helper.evaluateNodeProperty(RED, config.out_false, "json");
|
|
15
|
+
let out_true = helper.evaluateNodeProperty(RED, config.out_true, config.out_true_type || "json");
|
|
16
|
+
let out_false = helper.evaluateNodeProperty(RED, config.out_false, config.out_false_type || "json");
|
|
15
17
|
let logic_inputs = config.logic_inputs;
|
|
16
18
|
let inverts = config.inverts.split(",").map(n => parseInt(n));
|
|
17
19
|
let invert_output = config.invert_output;
|
|
@@ -19,7 +21,7 @@ module.exports = function (RED)
|
|
|
19
21
|
// runtime values
|
|
20
22
|
|
|
21
23
|
|
|
22
|
-
var
|
|
24
|
+
var node_settings = {
|
|
23
25
|
input_states: Array.from({ length: logic_inputs }).fill(false),
|
|
24
26
|
last_message: null,
|
|
25
27
|
};
|
|
@@ -27,12 +29,12 @@ module.exports = function (RED)
|
|
|
27
29
|
if (config.save_state)
|
|
28
30
|
{
|
|
29
31
|
// load old saved values
|
|
30
|
-
|
|
32
|
+
node_settings = Object.assign(node_settings, smart_context.get(node.id));
|
|
31
33
|
}
|
|
32
34
|
else
|
|
33
35
|
{
|
|
34
36
|
// delete old saved values
|
|
35
|
-
|
|
37
|
+
smart_context.del(node.id);
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
node.on("input", function (msg)
|
|
@@ -51,9 +53,9 @@ module.exports = function (RED)
|
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
if (inverts.includes(input))
|
|
54
|
-
|
|
56
|
+
node_settings.input_states[input - 1] = !msg.payload;
|
|
55
57
|
else
|
|
56
|
-
|
|
58
|
+
node_settings.input_states[input - 1] = !!msg.payload; // !! => Convert to boolean
|
|
57
59
|
|
|
58
60
|
setStatus();
|
|
59
61
|
let result = getResult();
|
|
@@ -61,23 +63,23 @@ module.exports = function (RED)
|
|
|
61
63
|
if (invert_output ? !result : result)
|
|
62
64
|
{
|
|
63
65
|
result = out_true;
|
|
64
|
-
result
|
|
66
|
+
if (result !== null)
|
|
67
|
+
result.payload = true;
|
|
65
68
|
}
|
|
66
69
|
else
|
|
67
70
|
{
|
|
68
71
|
result = out_false;
|
|
69
|
-
result
|
|
72
|
+
if (result !== null)
|
|
73
|
+
result.payload = false;
|
|
70
74
|
}
|
|
71
75
|
|
|
72
|
-
if (
|
|
73
|
-
{
|
|
74
|
-
nodeSettings.last_message = result;
|
|
75
|
-
|
|
76
|
+
if (result !== null && node_settings.last_message?.payload != result.payload)
|
|
76
77
|
node.send(result);
|
|
77
|
-
|
|
78
|
+
|
|
79
|
+
node_settings.last_message = result;
|
|
78
80
|
|
|
79
81
|
if (config.save_state)
|
|
80
|
-
|
|
82
|
+
smart_context.set(node.id, node_settings);
|
|
81
83
|
});
|
|
82
84
|
|
|
83
85
|
node.on("close", function ()
|
|
@@ -94,7 +96,7 @@ module.exports = function (RED)
|
|
|
94
96
|
result = true;
|
|
95
97
|
for (let i = 0; i < logic_inputs; i++)
|
|
96
98
|
{
|
|
97
|
-
const element =
|
|
99
|
+
const element = node_settings.input_states[i];
|
|
98
100
|
if (element == false)
|
|
99
101
|
{
|
|
100
102
|
result = false;
|
|
@@ -107,7 +109,7 @@ module.exports = function (RED)
|
|
|
107
109
|
result = false;
|
|
108
110
|
for (let i = 0; i < logic_inputs; i++)
|
|
109
111
|
{
|
|
110
|
-
const element =
|
|
112
|
+
const element = node_settings.input_states[i];
|
|
111
113
|
if (element == true)
|
|
112
114
|
{
|
|
113
115
|
result = true;
|
|
@@ -122,7 +124,7 @@ module.exports = function (RED)
|
|
|
122
124
|
|
|
123
125
|
for (let i = 0; i < logic_inputs; i++)
|
|
124
126
|
{
|
|
125
|
-
const element =
|
|
127
|
+
const element = node_settings.input_states[i];
|
|
126
128
|
if (element && oneTrue)
|
|
127
129
|
{
|
|
128
130
|
result = false;
|
|
@@ -145,7 +147,7 @@ module.exports = function (RED)
|
|
|
145
147
|
for (let i = 0; i < logic_inputs; i++)
|
|
146
148
|
{
|
|
147
149
|
let invert = inverts.includes(i + 1);
|
|
148
|
-
const element =
|
|
150
|
+
const element = node_settings.input_states[i];
|
|
149
151
|
|
|
150
152
|
state.push((invert ? "!" + (!element) : "" + element));
|
|
151
153
|
}
|
|
@@ -153,14 +155,14 @@ module.exports = function (RED)
|
|
|
153
155
|
let result = getResult();
|
|
154
156
|
let resultText = (invert_output ? "!" : "") + result;
|
|
155
157
|
|
|
156
|
-
node.status({ fill: "yellow", shape: "ring", text:
|
|
158
|
+
node.status({ fill: "yellow", shape: "ring", text: helper.getCurrentTimeForStatus() + ": [" + state.join(", ") + "] => " + resultText });
|
|
157
159
|
}
|
|
158
160
|
|
|
159
|
-
if (config.save_state && config.resend_on_start &&
|
|
161
|
+
if (config.save_state && config.resend_on_start && node_settings.last_message != null)
|
|
160
162
|
{
|
|
161
163
|
setTimeout(() =>
|
|
162
164
|
{
|
|
163
|
-
node.send(
|
|
165
|
+
node.send(node_settings.last_message);
|
|
164
166
|
}, 10000);
|
|
165
167
|
}
|
|
166
168
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
module.exports = function (RED)
|
|
2
2
|
{
|
|
3
|
+
"use strict";
|
|
4
|
+
|
|
3
5
|
function LongPressControlNode(config)
|
|
4
6
|
{
|
|
5
7
|
const node = this;
|
|
@@ -22,7 +24,7 @@ module.exports = function (RED)
|
|
|
22
24
|
{
|
|
23
25
|
if (msg.payload)
|
|
24
26
|
{
|
|
25
|
-
node.status({ fill: "yellow", shape: "ring", text:
|
|
27
|
+
node.status({ fill: "yellow", shape: "ring", text: helper.getCurrentTimeForStatus() + ": Wait for button release..." });
|
|
26
28
|
on_time = Date.now();
|
|
27
29
|
startAutoLongPress();
|
|
28
30
|
}
|
|
@@ -36,13 +38,13 @@ module.exports = function (RED)
|
|
|
36
38
|
|
|
37
39
|
if (pressTime < long_press_ms)
|
|
38
40
|
{
|
|
39
|
-
node.status({ fill: "green", shape: "dot", text:
|
|
41
|
+
node.status({ fill: "green", shape: "dot", text: helper.getCurrentTimeForStatus() + ": Last was short" });
|
|
40
42
|
if (short)
|
|
41
43
|
node.send([short, null]);
|
|
42
44
|
}
|
|
43
45
|
else
|
|
44
46
|
{
|
|
45
|
-
node.status({ fill: "green", shape: "dot", text:
|
|
47
|
+
node.status({ fill: "green", shape: "dot", text: helper.getCurrentTimeForStatus() + ": Last was long" });
|
|
46
48
|
if (long)
|
|
47
49
|
node.send([null, long]);
|
|
48
50
|
}
|
|
@@ -55,7 +57,7 @@ module.exports = function (RED)
|
|
|
55
57
|
max_time_on_timeout = setTimeout(() =>
|
|
56
58
|
{
|
|
57
59
|
on_time = null;
|
|
58
|
-
node.status({ fill: "green", shape: "dot", text:
|
|
60
|
+
node.status({ fill: "green", shape: "dot", text: helper.getCurrentTimeForStatus() + ": Last was long" });
|
|
59
61
|
node.send([null, long]);
|
|
60
62
|
}, long_press_ms);
|
|
61
63
|
};
|