smart-nodes 0.5.2 → 0.6.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/CHANGELOG.md CHANGED
@@ -218,3 +218,9 @@
218
218
  ## Version 0.5.2:
219
219
 
220
220
  - Added alarm mode to mixing-valve.
221
+
222
+ ## Version 0.6.0:
223
+
224
+ - Reduced amount of messages sent by light node when it is in alarm mode.
225
+ - Fixed forwarder node causing an error when no topic was sent.
226
+ - Added Jest example for all nodes to be able to debug nodes in vscode.
@@ -0,0 +1 @@
1
+ {"idn1":{"temperature_outside":10,"last_flow_temperature":null}}
@@ -0,0 +1,57 @@
1
+ const th = require("./test-helper");
2
+ const helper = th.helper;
3
+ const nodeModule = require("../compare/compare.js");
4
+
5
+ const nodeType = "smart_compare";
6
+
7
+ th.init();
8
+
9
+ test("compare", (done) =>
10
+ {
11
+ const flow = [
12
+ {
13
+ id: "n1",
14
+ type: nodeType,
15
+ name: "test-compare",
16
+ comparator: "SMALLER",
17
+ value1: 5,
18
+ value2: 9,
19
+ wires: [["n2"]]
20
+ },
21
+ { id: "n2", type: "helper" }
22
+ ];
23
+
24
+ helper.load(nodeModule, flow, () =>
25
+ {
26
+ try
27
+ {
28
+ const n1 = helper.getNode("n1");
29
+ const n2 = helper.getNode("n2");
30
+
31
+ if (!n1) return done(new Error("Node n1 wurde nicht erstellt"));
32
+ if (!n2) return done(new Error("Helper-Node n2 fehlt"));
33
+
34
+ n2.on("input", (msg) =>
35
+ {
36
+ try
37
+ {
38
+ console.log("Received:", msg);
39
+ expect(msg).toBeDefined();
40
+ }
41
+ catch (err)
42
+ {
43
+ done(err);
44
+ }
45
+ });
46
+
47
+ n1.receive({ topic: "1", payload: 7 });
48
+ n1.receive({ topic: "1", payload: 17 });
49
+
50
+ setImmediate(() => { done(); });
51
+ }
52
+ catch (err)
53
+ {
54
+ done(err);
55
+ }
56
+ });
57
+ });
@@ -0,0 +1,54 @@
1
+ const th = require("./test-helper");
2
+ const helper = th.helper;
3
+ const nodeModule = require("../counter/counter.js");
4
+
5
+ const nodeType = "smart_counter";
6
+
7
+ th.init();
8
+
9
+ test("counter", (done) =>
10
+ {
11
+ const flow = [
12
+ {
13
+ id: "n1",
14
+ type: nodeType,
15
+ name: "test-counter",
16
+ wires: [["n2"]]
17
+ },
18
+ { id: "n2", type: "helper" }
19
+ ];
20
+
21
+ helper.load(nodeModule, flow, () =>
22
+ {
23
+ try
24
+ {
25
+ const n1 = helper.getNode("n1");
26
+ const n2 = helper.getNode("n2");
27
+
28
+ if (!n1) return done(new Error("Node n1 wurde nicht erstellt"));
29
+ if (!n2) return done(new Error("Helper-Node n2 fehlt"));
30
+
31
+ n2.on("input", (msg) =>
32
+ {
33
+ try
34
+ {
35
+ console.log("Received:", msg);
36
+ expect(msg).toBeDefined();
37
+ }
38
+ catch (err)
39
+ {
40
+ done(err);
41
+ }
42
+ });
43
+
44
+ n1.receive({ topic: "1", payload: 7 });
45
+ n1.receive({ topic: "1", payload: 17 });
46
+
47
+ setImmediate(() => { done(); });
48
+ }
49
+ catch (err)
50
+ {
51
+ done(err);
52
+ }
53
+ });
54
+ });
@@ -0,0 +1,54 @@
1
+ const th = require("./test-helper");
2
+ const helper = th.helper;
3
+ const nodeModule = require("../forwarder/forwarder.js");
4
+
5
+ const nodeType = "smart_forwarder";
6
+
7
+ th.init();
8
+
9
+ test("forwarder", (done) =>
10
+ {
11
+ const flow = [
12
+ {
13
+ id: "n1",
14
+ type: nodeType,
15
+ name: "test-forwarder",
16
+ wires: [["n2"]]
17
+ },
18
+ { id: "n2", type: "helper" }
19
+ ];
20
+
21
+ helper.load(nodeModule, flow, () =>
22
+ {
23
+ try
24
+ {
25
+ const n1 = helper.getNode("n1");
26
+ const n2 = helper.getNode("n2");
27
+
28
+ if (!n1) return done(new Error("Node n1 wurde nicht erstellt"));
29
+ if (!n2) return done(new Error("Helper-Node n2 fehlt"));
30
+
31
+ n2.on("input", (msg) =>
32
+ {
33
+ try
34
+ {
35
+ console.log("Received:", msg);
36
+ expect(msg).toBeDefined();
37
+ }
38
+ catch (err)
39
+ {
40
+ done(err);
41
+ }
42
+ });
43
+
44
+ n1.receive({ topic: "1", payload: 7 });
45
+ n1.receive({ topic: "1", payload: 17 });
46
+
47
+ setImmediate(() => { done(); });
48
+ }
49
+ catch (err)
50
+ {
51
+ done(err);
52
+ }
53
+ });
54
+ });
@@ -0,0 +1,54 @@
1
+ const th = require("./test-helper");
2
+ const helper = th.helper;
3
+ const nodeModule = require("../heating-curve/heating-curve.js");
4
+
5
+ const nodeType = "smart_heating-curve";
6
+
7
+ th.init();
8
+
9
+ test("heating-curve", (done) =>
10
+ {
11
+ const flow = [
12
+ {
13
+ id: "n1",
14
+ type: nodeType,
15
+ name: "test-heating-curve",
16
+ wires: [["n2"]]
17
+ },
18
+ { id: "n2", type: "helper" }
19
+ ];
20
+
21
+ helper.load(nodeModule, flow, () =>
22
+ {
23
+ try
24
+ {
25
+ const n1 = helper.getNode("n1");
26
+ const n2 = helper.getNode("n2");
27
+
28
+ if (!n1) return done(new Error("Node n1 wurde nicht erstellt"));
29
+ if (!n2) return done(new Error("Helper-Node n2 fehlt"));
30
+
31
+ n2.on("input", (msg) =>
32
+ {
33
+ try
34
+ {
35
+ console.log("Received:", msg);
36
+ expect(msg).toBeDefined();
37
+ }
38
+ catch (err)
39
+ {
40
+ done(err);
41
+ }
42
+ });
43
+
44
+ n1.receive({ topic: "1", payload: 7 });
45
+ n1.receive({ topic: "1", payload: 17 });
46
+
47
+ setImmediate(() => { done(); });
48
+ }
49
+ catch (err)
50
+ {
51
+ done(err);
52
+ }
53
+ });
54
+ });
@@ -0,0 +1,54 @@
1
+ const th = require("./test-helper");
2
+ const helper = th.helper;
3
+ const nodeModule = require("../hysteresis/hysteresis.js");
4
+
5
+ const nodeType = "smart_hysteresis";
6
+
7
+ th.init();
8
+
9
+ test("hysteresis", (done) =>
10
+ {
11
+ const flow = [
12
+ {
13
+ id: "n1",
14
+ type: nodeType,
15
+ name: "test-hysteresis",
16
+ wires: [["n2"]]
17
+ },
18
+ { id: "n2", type: "helper" }
19
+ ];
20
+
21
+ helper.load(nodeModule, flow, () =>
22
+ {
23
+ try
24
+ {
25
+ const n1 = helper.getNode("n1");
26
+ const n2 = helper.getNode("n2");
27
+
28
+ if (!n1) return done(new Error("Node n1 wurde nicht erstellt"));
29
+ if (!n2) return done(new Error("Helper-Node n2 fehlt"));
30
+
31
+ n2.on("input", (msg) =>
32
+ {
33
+ try
34
+ {
35
+ console.log("Received:", msg);
36
+ expect(msg).toBeDefined();
37
+ }
38
+ catch (err)
39
+ {
40
+ done(err);
41
+ }
42
+ });
43
+
44
+ n1.receive({ topic: "1", payload: 7 });
45
+ n1.receive({ topic: "1", payload: 17 });
46
+
47
+ setImmediate(() => { done(); });
48
+ }
49
+ catch (err)
50
+ {
51
+ done(err);
52
+ }
53
+ });
54
+ });
@@ -0,0 +1,49 @@
1
+ const th = require("./test-helper");
2
+ const helper = th.helper;
3
+ const nodeModule = require("../light/light.js");
4
+
5
+ const nodeType = "smart_light-control";
6
+
7
+ th.init();
8
+
9
+ test("light node", (done) =>
10
+ {
11
+ const flow = [
12
+ { id: "n1", type: nodeType, name: "test-light", wires: [["n2"]] },
13
+ { id: "n2", type: "helper" }
14
+ ];
15
+
16
+ helper.load(nodeModule, flow, () =>
17
+ {
18
+ try
19
+ {
20
+ const n1 = helper.getNode("n1");
21
+ const n2 = helper.getNode("n2");
22
+
23
+ if (!n1) return done(new Error("Node n1 wurde nicht erstellt"));
24
+ if (!n2) return done(new Error("Helper-Node n2 fehlt"));
25
+
26
+ n2.on("input", (msg) =>
27
+ {
28
+ try
29
+ {
30
+ console.log("Received:", msg);
31
+ expect(msg).toBeDefined();
32
+ }
33
+ catch (err)
34
+ {
35
+ done(err);
36
+ }
37
+ });
38
+
39
+ n1.receive({ topic: "toggle" });
40
+ n1.receive({ topic: "toggle" });
41
+
42
+ setImmediate(() => { done(); });
43
+ }
44
+ catch (err)
45
+ {
46
+ done(err);
47
+ }
48
+ });
49
+ });
@@ -0,0 +1,61 @@
1
+ const th = require("./test-helper");
2
+ const helper = th.helper;
3
+ const nodeModule = require("../logic/logic.js");
4
+
5
+ const nodeType = "smart_logic";
6
+
7
+ th.init();
8
+
9
+ test("logic", (done) =>
10
+ {
11
+ const flow = [
12
+ {
13
+ id: "n1",
14
+ type: nodeType,
15
+ name: "test-logic",
16
+ out_true: "{}",
17
+ out_true_type: "json",
18
+ out_false: "{}",
19
+ out_false_type: "json",
20
+ inverts: "",
21
+ send_only_change: true,
22
+ outputs: 1,
23
+ wires: [["n2"]]
24
+ },
25
+ { id: "n2", type: "helper" }
26
+ ];
27
+
28
+ helper.load(nodeModule, flow, () =>
29
+ {
30
+ try
31
+ {
32
+ const n1 = helper.getNode("n1");
33
+ const n2 = helper.getNode("n2");
34
+
35
+ if (!n1) return done(new Error("Node n1 wurde nicht erstellt"));
36
+ if (!n2) return done(new Error("Helper-Node n2 fehlt"));
37
+
38
+ n2.on("input", (msg) =>
39
+ {
40
+ try
41
+ {
42
+ console.log("Received:", msg);
43
+ expect(msg).toBeDefined();
44
+ }
45
+ catch (err)
46
+ {
47
+ done(err);
48
+ }
49
+ });
50
+
51
+ n1.receive({ topic: "1", payload: 7 });
52
+ n1.receive({ topic: "1", payload: 17 });
53
+
54
+ setImmediate(() => { done(); });
55
+ }
56
+ catch (err)
57
+ {
58
+ done(err);
59
+ }
60
+ });
61
+ });
@@ -0,0 +1,54 @@
1
+ const th = require("./test-helper");
2
+ const helper = th.helper;
3
+ const nodeModule = require("../long-press/long-press.js");
4
+
5
+ const nodeType = "smart_long-press-control";
6
+
7
+ th.init();
8
+
9
+ test("long-press", (done) =>
10
+ {
11
+ const flow = [
12
+ {
13
+ id: "n1",
14
+ type: nodeType,
15
+ name: "test-long-press",
16
+ wires: [["n2"]]
17
+ },
18
+ { id: "n2", type: "helper" }
19
+ ];
20
+
21
+ helper.load(nodeModule, flow, () =>
22
+ {
23
+ try
24
+ {
25
+ const n1 = helper.getNode("n1");
26
+ const n2 = helper.getNode("n2");
27
+
28
+ if (!n1) return done(new Error("Node n1 wurde nicht erstellt"));
29
+ if (!n2) return done(new Error("Helper-Node n2 fehlt"));
30
+
31
+ n2.on("input", (msg) =>
32
+ {
33
+ try
34
+ {
35
+ console.log("Received:", msg);
36
+ expect(msg).toBeDefined();
37
+ }
38
+ catch (err)
39
+ {
40
+ done(err);
41
+ }
42
+ });
43
+
44
+ n1.receive({ topic: "1", payload: 7 });
45
+ n1.receive({ topic: "1", payload: 17 });
46
+
47
+ setImmediate(() => { done(); });
48
+ }
49
+ catch (err)
50
+ {
51
+ done(err);
52
+ }
53
+ });
54
+ });
@@ -0,0 +1,54 @@
1
+ const th = require("./test-helper");
2
+ const helper = th.helper;
3
+ const nodeModule = require("../mixing-valve/mixing-valve.js");
4
+
5
+ const nodeType = "smart_mixing-valve";
6
+
7
+ th.init();
8
+
9
+ test("mixing-valve", (done) =>
10
+ {
11
+ const flow = [
12
+ {
13
+ id: "n1",
14
+ type: nodeType,
15
+ name: "test-mixing-valve",
16
+ wires: [["n2"]]
17
+ },
18
+ { id: "n2", type: "helper" }
19
+ ];
20
+
21
+ helper.load(nodeModule, flow, () =>
22
+ {
23
+ try
24
+ {
25
+ const n1 = helper.getNode("n1");
26
+ const n2 = helper.getNode("n2");
27
+
28
+ if (!n1) return done(new Error("Node n1 wurde nicht erstellt"));
29
+ if (!n2) return done(new Error("Helper-Node n2 fehlt"));
30
+
31
+ n2.on("input", (msg) =>
32
+ {
33
+ try
34
+ {
35
+ console.log("Received:", msg);
36
+ expect(msg).toBeDefined();
37
+ }
38
+ catch (err)
39
+ {
40
+ done(err);
41
+ }
42
+ });
43
+
44
+ n1.receive({ topic: "1", payload: 7 });
45
+ n1.receive({ topic: "1", payload: 17 });
46
+
47
+ setImmediate(() => { done(); });
48
+ }
49
+ catch (err)
50
+ {
51
+ done(err);
52
+ }
53
+ });
54
+ });
@@ -0,0 +1,54 @@
1
+ const th = require("./test-helper");
2
+ const helper = th.helper;
3
+ const nodeModule = require("../mode-selector/mode-selector.js");
4
+
5
+ const nodeType = "smart_mode-selector";
6
+
7
+ th.init();
8
+
9
+ test("mode-selector", (done) =>
10
+ {
11
+ const flow = [
12
+ {
13
+ id: "n1",
14
+ type: nodeType,
15
+ name: "test-mode-selector",
16
+ wires: [["n2"]]
17
+ },
18
+ { id: "n2", type: "helper" }
19
+ ];
20
+
21
+ helper.load(nodeModule, flow, () =>
22
+ {
23
+ try
24
+ {
25
+ const n1 = helper.getNode("n1");
26
+ const n2 = helper.getNode("n2");
27
+
28
+ if (!n1) return done(new Error("Node n1 wurde nicht erstellt"));
29
+ if (!n2) return done(new Error("Helper-Node n2 fehlt"));
30
+
31
+ n2.on("input", (msg) =>
32
+ {
33
+ try
34
+ {
35
+ console.log("Received:", msg);
36
+ expect(msg).toBeDefined();
37
+ }
38
+ catch (err)
39
+ {
40
+ done(err);
41
+ }
42
+ });
43
+
44
+ n1.receive({ topic: "1", payload: 7 });
45
+ n1.receive({ topic: "1", payload: 17 });
46
+
47
+ setImmediate(() => { done(); });
48
+ }
49
+ catch (err)
50
+ {
51
+ done(err);
52
+ }
53
+ });
54
+ });
@@ -0,0 +1,54 @@
1
+ const th = require("./test-helper");
2
+ const helper = th.helper;
3
+ const nodeModule = require("../multi-press/multi-press.js");
4
+
5
+ const nodeType = "smart_multi-press";
6
+
7
+ th.init();
8
+
9
+ test("multi-press", (done) =>
10
+ {
11
+ const flow = [
12
+ {
13
+ id: "n1",
14
+ type: nodeType,
15
+ name: "test-multi-press",
16
+ wires: [["n2"]]
17
+ },
18
+ { id: "n2", type: "helper" }
19
+ ];
20
+
21
+ helper.load(nodeModule, flow, () =>
22
+ {
23
+ try
24
+ {
25
+ const n1 = helper.getNode("n1");
26
+ const n2 = helper.getNode("n2");
27
+
28
+ if (!n1) return done(new Error("Node n1 wurde nicht erstellt"));
29
+ if (!n2) return done(new Error("Helper-Node n2 fehlt"));
30
+
31
+ n2.on("input", (msg) =>
32
+ {
33
+ try
34
+ {
35
+ console.log("Received:", msg);
36
+ expect(msg).toBeDefined();
37
+ }
38
+ catch (err)
39
+ {
40
+ done(err);
41
+ }
42
+ });
43
+
44
+ n1.receive({ topic: "1", payload: 7 });
45
+ n1.receive({ topic: "1", payload: 17 });
46
+
47
+ setImmediate(() => { done(); });
48
+ }
49
+ catch (err)
50
+ {
51
+ done(err);
52
+ }
53
+ });
54
+ });
@@ -0,0 +1,54 @@
1
+ const th = require("./test-helper");
2
+ const helper = th.helper;
3
+ const nodeModule = require("../scene/scene.js");
4
+
5
+ const nodeType = "smart_scene-control";
6
+
7
+ th.init();
8
+
9
+ test("scene", (done) =>
10
+ {
11
+ const flow = [
12
+ {
13
+ id: "n1",
14
+ type: nodeType,
15
+ name: "test-scene",
16
+ wires: [["n2"]]
17
+ },
18
+ { id: "n2", type: "helper" }
19
+ ];
20
+
21
+ helper.load(nodeModule, flow, () =>
22
+ {
23
+ try
24
+ {
25
+ const n1 = helper.getNode("n1");
26
+ const n2 = helper.getNode("n2");
27
+
28
+ if (!n1) return done(new Error("Node n1 wurde nicht erstellt"));
29
+ if (!n2) return done(new Error("Helper-Node n2 fehlt"));
30
+
31
+ n2.on("input", (msg) =>
32
+ {
33
+ try
34
+ {
35
+ console.log("Received:", msg);
36
+ expect(msg).toBeDefined();
37
+ }
38
+ catch (err)
39
+ {
40
+ done(err);
41
+ }
42
+ });
43
+
44
+ n1.receive({ topic: "1", payload: 7 });
45
+ n1.receive({ topic: "1", payload: 17 });
46
+
47
+ setImmediate(() => { done(); });
48
+ }
49
+ catch (err)
50
+ {
51
+ done(err);
52
+ }
53
+ });
54
+ });
@@ -0,0 +1,54 @@
1
+ const th = require("./test-helper");
2
+ const helper = th.helper;
3
+ const nodeModule = require("../scheduler/scheduler.js");
4
+
5
+ const nodeType = "smart_scheduler";
6
+
7
+ th.init();
8
+
9
+ test("scheduler", (done) =>
10
+ {
11
+ const flow = [
12
+ {
13
+ id: "n1",
14
+ type: nodeType,
15
+ name: "test-scheduler",
16
+ wires: [["n2"]]
17
+ },
18
+ { id: "n2", type: "helper" }
19
+ ];
20
+
21
+ helper.load(nodeModule, flow, () =>
22
+ {
23
+ try
24
+ {
25
+ const n1 = helper.getNode("n1");
26
+ const n2 = helper.getNode("n2");
27
+
28
+ if (!n1) return done(new Error("Node n1 wurde nicht erstellt"));
29
+ if (!n2) return done(new Error("Helper-Node n2 fehlt"));
30
+
31
+ n2.on("input", (msg) =>
32
+ {
33
+ try
34
+ {
35
+ console.log("Received:", msg);
36
+ expect(msg).toBeDefined();
37
+ }
38
+ catch (err)
39
+ {
40
+ done(err);
41
+ }
42
+ });
43
+
44
+ n1.receive({ topic: "1", payload: 7 });
45
+ n1.receive({ topic: "1", payload: 17 });
46
+
47
+ setImmediate(() => { done(); });
48
+ }
49
+ catch (err)
50
+ {
51
+ done(err);
52
+ }
53
+ });
54
+ });
@@ -0,0 +1,54 @@
1
+ const th = require("./test-helper");
2
+ const helper = th.helper;
3
+ const nodeModule = require("../shutter-complex/shutter-complex.js");
4
+
5
+ const nodeType = "smart_shutter-complex-control";
6
+
7
+ th.init();
8
+
9
+ test("shutter-complex", (done) =>
10
+ {
11
+ const flow = [
12
+ {
13
+ id: "n1",
14
+ type: nodeType,
15
+ name: "test-shutter-complex",
16
+ wires: [["n2"]]
17
+ },
18
+ { id: "n2", type: "helper" }
19
+ ];
20
+
21
+ helper.load(nodeModule, flow, () =>
22
+ {
23
+ try
24
+ {
25
+ const n1 = helper.getNode("n1");
26
+ const n2 = helper.getNode("n2");
27
+
28
+ if (!n1) return done(new Error("Node n1 wurde nicht erstellt"));
29
+ if (!n2) return done(new Error("Helper-Node n2 fehlt"));
30
+
31
+ n2.on("input", (msg) =>
32
+ {
33
+ try
34
+ {
35
+ console.log("Received:", msg);
36
+ expect(msg).toBeDefined();
37
+ }
38
+ catch (err)
39
+ {
40
+ done(err);
41
+ }
42
+ });
43
+
44
+ n1.receive({ topic: "1", payload: 7 });
45
+ n1.receive({ topic: "1", payload: 17 });
46
+
47
+ setImmediate(() => { done(); });
48
+ }
49
+ catch (err)
50
+ {
51
+ done(err);
52
+ }
53
+ });
54
+ });
@@ -0,0 +1,54 @@
1
+ const th = require("./test-helper");
2
+ const helper = th.helper;
3
+ const nodeModule = require("../shutter/shutter.js");
4
+
5
+ const nodeType = "smart_shutter-control";
6
+
7
+ th.init();
8
+
9
+ test("shutter", (done) =>
10
+ {
11
+ const flow = [
12
+ {
13
+ id: "n1",
14
+ type: nodeType,
15
+ name: "test-shutter",
16
+ wires: [["n2"]]
17
+ },
18
+ { id: "n2", type: "helper" }
19
+ ];
20
+
21
+ helper.load(nodeModule, flow, () =>
22
+ {
23
+ try
24
+ {
25
+ const n1 = helper.getNode("n1");
26
+ const n2 = helper.getNode("n2");
27
+
28
+ if (!n1) return done(new Error("Node n1 wurde nicht erstellt"));
29
+ if (!n2) return done(new Error("Helper-Node n2 fehlt"));
30
+
31
+ n2.on("input", (msg) =>
32
+ {
33
+ try
34
+ {
35
+ console.log("Received:", msg);
36
+ expect(msg).toBeDefined();
37
+ }
38
+ catch (err)
39
+ {
40
+ done(err);
41
+ }
42
+ });
43
+
44
+ n1.receive({ topic: "1", payload: 7 });
45
+ n1.receive({ topic: "1", payload: 17 });
46
+
47
+ setImmediate(() => { done(); });
48
+ }
49
+ catch (err)
50
+ {
51
+ done(err);
52
+ }
53
+ });
54
+ });
@@ -0,0 +1,54 @@
1
+ const th = require("./test-helper");
2
+ const helper = th.helper;
3
+ const nodeModule = require("../statistics/statistics.js");
4
+
5
+ const nodeType = "smart_statistics";
6
+
7
+ th.init();
8
+
9
+ test("statistics", (done) =>
10
+ {
11
+ const flow = [
12
+ {
13
+ id: "n1",
14
+ type: nodeType,
15
+ name: "test-statistics",
16
+ wires: [["n2"]]
17
+ },
18
+ { id: "n2", type: "helper" }
19
+ ];
20
+
21
+ helper.load(nodeModule, flow, () =>
22
+ {
23
+ try
24
+ {
25
+ const n1 = helper.getNode("n1");
26
+ const n2 = helper.getNode("n2");
27
+
28
+ if (!n1) return done(new Error("Node n1 wurde nicht erstellt"));
29
+ if (!n2) return done(new Error("Helper-Node n2 fehlt"));
30
+
31
+ n2.on("input", (msg) =>
32
+ {
33
+ try
34
+ {
35
+ console.log("Received:", msg);
36
+ expect(msg).toBeDefined();
37
+ }
38
+ catch (err)
39
+ {
40
+ done(err);
41
+ }
42
+ });
43
+
44
+ n1.receive({ topic: "1", payload: 7 });
45
+ n1.receive({ topic: "1", payload: 17 });
46
+
47
+ setImmediate(() => { done(); });
48
+ }
49
+ catch (err)
50
+ {
51
+ done(err);
52
+ }
53
+ });
54
+ });
@@ -0,0 +1,40 @@
1
+ const helper = require("node-red-node-test-helper");
2
+
3
+ module.exports = {
4
+ helper,
5
+
6
+ init: function ()
7
+ {
8
+ // init must be called once per test file before startServer
9
+ helper.init(require.resolve("node-red"));
10
+
11
+ beforeAll(() => this.startServer());
12
+ afterAll(() => this.stopServer());
13
+ afterEach(() => this.unload().then(() =>
14
+ {
15
+ process.removeAllListeners("uncaughtException");
16
+ process.removeAllListeners("unhandledRejection");
17
+ }));
18
+ },
19
+
20
+ startServer: function ()
21
+ {
22
+ return new Promise((resolve, reject) =>
23
+ {
24
+ helper.startServer((err) => (err ? reject(err) : resolve()));
25
+ });
26
+ },
27
+
28
+ stopServer: function ()
29
+ {
30
+ return new Promise((resolve) =>
31
+ {
32
+ helper.stopServer(() => resolve());
33
+ });
34
+ },
35
+
36
+ unload: function ()
37
+ {
38
+ return helper.unload().catch(() => { });
39
+ }
40
+ };
@@ -0,0 +1,54 @@
1
+ const th = require("./test-helper");
2
+ const helper = th.helper;
3
+ const nodeModule = require("../text-exec/text-exec.js");
4
+
5
+ const nodeType = "smart_text-exec";
6
+
7
+ th.init();
8
+
9
+ test("text-exec", (done) =>
10
+ {
11
+ const flow = [
12
+ {
13
+ id: "n1",
14
+ type: nodeType,
15
+ name: "test-text-exec",
16
+ wires: [["n2"]]
17
+ },
18
+ { id: "n2", type: "helper" }
19
+ ];
20
+
21
+ helper.load(nodeModule, flow, () =>
22
+ {
23
+ try
24
+ {
25
+ const n1 = helper.getNode("n1");
26
+ const n2 = helper.getNode("n2");
27
+
28
+ if (!n1) return done(new Error("Node n1 wurde nicht erstellt"));
29
+ if (!n2) return done(new Error("Helper-Node n2 fehlt"));
30
+
31
+ n2.on("input", (msg) =>
32
+ {
33
+ try
34
+ {
35
+ console.log("Received:", msg);
36
+ expect(msg).toBeDefined();
37
+ }
38
+ catch (err)
39
+ {
40
+ done(err);
41
+ }
42
+ });
43
+
44
+ n1.receive({ topic: "1", payload: 7 });
45
+ n1.receive({ topic: "1", payload: 17 });
46
+
47
+ setImmediate(() => { done(); });
48
+ }
49
+ catch (err)
50
+ {
51
+ done(err);
52
+ }
53
+ });
54
+ });
@@ -80,28 +80,31 @@ module.exports = function (RED)
80
80
  let handleTopic = msg =>
81
81
  {
82
82
  let real_topic = helper.getTopicName(msg.topic);
83
+ let new_state = null;
83
84
 
84
- if (real_topic.startsWith("set_state"))
85
- real_topic = real_topic.replace("set_state", "set");
86
-
87
- if (real_topic == "set_inverted")
85
+ if (real_topic != null)
88
86
  {
89
- real_topic = "set";
90
- msg.payload = !msg.payload;
87
+ if (real_topic.startsWith("set_state"))
88
+ real_topic = real_topic.replace("set_state", "set");
89
+
90
+ if (real_topic == "set_inverted")
91
+ {
92
+ real_topic = "set";
93
+ msg.payload = !msg.payload;
94
+ }
95
+
96
+ if (real_topic == "enable" || (real_topic == "set" && msg.payload))
97
+ new_state = true;
98
+ else if (real_topic == "disable" || (real_topic == "set" && !msg.payload))
99
+ new_state = false;
91
100
  }
92
101
 
93
- let new_state = null;
94
- if (real_topic == "enable" || (real_topic == "set" && msg.payload))
95
- new_state = true;
96
- else if (real_topic == "disable" || (real_topic == "set" && !msg.payload))
97
- new_state = false;
98
-
99
102
  switch (real_topic)
100
103
  {
101
104
  case "debug":
102
105
  helper.nodeDebug(node, {
103
106
  node_settings,
104
- forward_true,
107
+ forward_true,
105
108
  forward_false,
106
109
  forward_last_on_enable,
107
110
  });
@@ -27,8 +27,8 @@
27
27
  $("#node-input-room_setpoint")
28
28
  .css("max-width", "4rem")
29
29
  .spinner({
30
- min: 15,
31
- max: 25,
30
+ min: 5,
31
+ max: 100,
32
32
  step: 0.5,
33
33
  change: function (event, ui)
34
34
  {
@@ -77,8 +77,8 @@
77
77
  $("#node-input-flow_max")
78
78
  .css("max-width", "4rem")
79
79
  .spinner({
80
- min: 50,
81
- max: 85,
80
+ min: 5,
81
+ max: 100,
82
82
  change: function (event, ui)
83
83
  {
84
84
  var value = parseFloat(this.value);
@@ -94,7 +94,7 @@
94
94
  .css("max-width", "4rem")
95
95
  .spinner({
96
96
  min: 5,
97
- max: 30,
97
+ max: 100,
98
98
  change: function (event, ui)
99
99
  {
100
100
  var value = parseFloat(this.value);
package/jest.config.js ADDED
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ testEnvironment: 'node',
3
+ testMatch: ['**/__tests__/**/*.test.js'],
4
+ verbose: true,
5
+ };
package/light/light.js CHANGED
@@ -46,6 +46,7 @@ module.exports = function (RED)
46
46
  let alarm_action = config.alarm_action || "NOTHING";
47
47
  let alarm_off_action = config.alarm_off_action || "NOTHING";
48
48
  let mode = config.mode || "BOOL";
49
+ let current_output_state = null;
49
50
 
50
51
  // ##################
51
52
  // # Runtime values #
@@ -149,6 +150,7 @@ module.exports = function (RED)
149
150
  doRestartTimer = false;
150
151
 
151
152
  node_settings.last_value = msg.payload;
153
+ current_output_state = node_settings.last_value;
152
154
  break;
153
155
 
154
156
  case "off":
@@ -360,8 +362,11 @@ module.exports = function (RED)
360
362
  }
361
363
  }
362
364
 
363
- if (node_settings.alarm_active || helper.getTopicName(msg.topic) != "status")
365
+ if (real_topic != "status" && current_output_state !== node_settings.last_value)
366
+ {
364
367
  node.send({ payload: node_settings.last_value });
368
+ current_output_state = node_settings.last_value;
369
+ }
365
370
 
366
371
  // Output is on, now
367
372
  if (node_settings.last_value && doRestartTimer)
@@ -410,6 +415,7 @@ module.exports = function (RED)
410
415
  node_settings.last_value = 0;
411
416
 
412
417
  node.send({ payload: node_settings.last_value });
418
+ current_output_state = node_settings.last_value;
413
419
  notifyCentral(false);
414
420
 
415
421
  setStatus();
@@ -155,6 +155,9 @@ module.exports = function (RED)
155
155
 
156
156
  let real_topic = helper.getTopicName(msg.topic);
157
157
 
158
+ if (real_topic == null)
159
+ node.warn("No topic set");
160
+
158
161
  if (real_topic.startsWith("set_state"))
159
162
  real_topic = real_topic.replace("set_state", "set");
160
163
 
@@ -354,16 +357,21 @@ module.exports = function (RED)
354
357
  node_settings.alarm_active = false;
355
358
  return;
356
359
  }
360
+
361
+ stopSampling();
362
+ startSampling();
357
363
  }
358
364
  else
359
365
  {
360
366
  force_position = null;
361
- if (!node_settings.enabled)
367
+ stopSampling();
368
+ stopChanging();
369
+
370
+ if (node_settings.enabled)
371
+ startSampling();
372
+ else
362
373
  doOffMode();
363
374
  }
364
-
365
- stopSampling();
366
- startSampling();
367
375
  break;
368
376
 
369
377
  default:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smart-nodes",
3
- "version": "0.5.2",
3
+ "version": "0.6.0",
4
4
  "description": "Controls light, shutters and more. Includes common used logic and statistic nodes to control your home.",
5
5
  "keywords": [
6
6
  "node-red",
@@ -27,7 +27,9 @@
27
27
  "text execution"
28
28
  ],
29
29
  "scripts": {
30
- "test": "echo \"Error: no test specified\" && exit 1"
30
+ "test": "jest",
31
+ "test:watch": "jest --watch",
32
+ "test:debug": "node --inspect-brk node_modules/jest/bin/jest.js --runInBand"
31
33
  },
32
34
  "author": "Samuel Bergen",
33
35
  "license": "MIT",
@@ -59,9 +61,11 @@
59
61
  "type": "git",
60
62
  "url": "https://github.com/BergenSoft/smart-nodes"
61
63
  },
62
- "dependencies": {},
63
64
  "devDependencies": {
64
- "font-awesome": "^4.7.0"
65
+ "font-awesome": "^4.7.0",
66
+ "jest": "^27.5.1",
67
+ "node-red": "^4.1.1",
68
+ "node-red-node-test-helper": "^0.3.5"
65
69
  },
66
70
  "engines": {
67
71
  "node": ">=10"
package/persistence.js CHANGED
@@ -1,3 +1,5 @@
1
+ const { log } = require('console');
2
+
1
3
  let instance = null;
2
4
 
3
5
  module.exports = function (_RED)
@@ -5,21 +7,31 @@ module.exports = function (_RED)
5
7
  if (instance != null)
6
8
  return instance;
7
9
 
8
- let RED = _RED;
9
10
  let hasChanges = false;
11
+ let inTestMode = _RED.settings.userDir == null;
12
+
13
+ // used for local debugging
14
+ if (inTestMode)
15
+ console.log("####### Test Mode detected #######");
10
16
 
11
17
  const fs = require('fs');
12
- const path = RED.settings.userDir + '/SmartNodesContext.json';
18
+ const pathLib = require('path');
19
+
20
+ // Fallback, falls RED.settings.userDir in Tests nicht gesetzt ist
21
+ const userDir = (_RED.settings && _RED.settings.userDir) ? _RED.settings.userDir : process.cwd();
22
+ const filePath = pathLib.join(userDir, 'SmartNodesContext.json');
13
23
 
14
24
  let globalData = {};
15
25
 
16
- if (fs.existsSync(path))
26
+ if (fs.existsSync(filePath))
17
27
  {
18
28
  try
19
29
  {
20
- let fileContent = fs.readFileSync(path, "utf8");
30
+ let fileContent = fs.readFileSync(filePath, "utf8");
21
31
  globalData = Object.assign({}, JSON.parse(fileContent));
22
- // console.log("Loaded " + Object.keys(globalData).length + " smart_nodes config items");
32
+
33
+ if (inTestMode)
34
+ console.log("Loaded:", globalData);
23
35
  }
24
36
  catch (error)
25
37
  {
@@ -35,12 +47,18 @@ module.exports = function (_RED)
35
47
 
36
48
  }, 30 * 1000);
37
49
 
50
+ // Prevent the interval from keeping the process alive (important for Jest)
51
+ if (interval && typeof interval.unref === "function")
52
+ interval.unref();
53
+
38
54
  function save()
39
55
  {
40
56
  try
41
57
  {
42
- // console.log("Auto save");
43
- fs.writeFile(path, JSON.stringify(globalData), err =>
58
+ if (inTestMode)
59
+ console.log("Save SmartNodeContext", globalData);
60
+
61
+ fs.writeFile(filePath, JSON.stringify(globalData), err =>
44
62
  {
45
63
  if (err)
46
64
  console.error(err);
@@ -57,6 +75,9 @@ module.exports = function (_RED)
57
75
  {
58
76
  hasChanges = true;
59
77
  globalData["id" + id] = data;
78
+
79
+ if (inTestMode)
80
+ save();
60
81
  }
61
82
 
62
83
  function get(id)
@@ -70,6 +91,15 @@ module.exports = function (_RED)
70
91
  delete globalData["id" + id];
71
92
  }
72
93
 
73
- instance = { set, get, del };
94
+ function close()
95
+ {
96
+ if (interval)
97
+ {
98
+ clearInterval(interval);
99
+ interval = null;
100
+ }
101
+ }
102
+
103
+ instance = { set, get, del, close };
74
104
  return instance;
75
105
  };
package/smart_helper.js CHANGED
@@ -291,16 +291,16 @@ module.exports = {
291
291
  * Target range = 100 to 200
292
292
  *
293
293
  * current number = 0
294
- * scale(5, 0, 10, 100, 200) => 100
294
+ * scale(0, 0, 10, 100, 200) => 100
295
295
  *
296
296
  * current number = 5
297
297
  * scale(5, 0, 10, 100, 200) => 150
298
298
  *
299
299
  * current number = 10
300
- * scale(5, 0, 10, 100, 200) => 200
300
+ * scale(10, 0, 10, 100, 200) => 200
301
301
  *
302
- * current number = 20 (out of input range!)
303
- * scale(5, 0, 10, 100, 200) => 300 (out of output range!)
302
+ * current number = 20 (input out of range!)
303
+ * scale(20, 0, 10, 100, 200) => 300 (output out of range!)
304
304
  */
305
305
  scale(number, inMin, inMax, outMin, outMax)
306
306
  {