smart-nodes 0.6.1 → 0.6.3
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 +14 -5
- package/SmartNodesContext.json +1 -1
- package/compare/compare.html +7 -1
- package/compare/compare.js +2 -1
- package/counter/counter.html +8 -2
- package/counter/counter.js +2 -1
- package/delay/delay.html +7 -1
- package/delay/delay.js +2 -1
- package/forwarder/forwarder.html +7 -1
- package/forwarder/forwarder.js +3 -2
- package/heating-curve/heating-curve.html +6 -0
- package/heating-curve/heating-curve.js +3 -2
- package/hysteresis/hysteresis.html +9 -6
- package/hysteresis/hysteresis.js +3 -2
- package/light/light.html +7 -1
- package/light/light.js +2 -1
- package/logic/logic.html +8 -2
- package/logic/logic.js +2 -1
- package/mixing-valve/mixing-valve.html +7 -1
- package/mixing-valve/mixing-valve.js +22 -116
- package/mode-selector/mode-selector.html +6 -3
- package/mode-selector/mode-selector.js +2 -1
- package/multi-press/multi-press.html +1 -1
- package/package.json +1 -1
- package/persistence.js +10 -4
- package/scene/scene.html +7 -4
- package/scene/scene.js +2 -1
- package/scheduler/scheduler.html +4 -2
- package/scheduler/scheduler.js +2 -1
- package/shutter/shutter.html +7 -1
- package/shutter/shutter.js +2 -1
- package/shutter-complex/shutter-complex.html +7 -1
- package/shutter-complex/shutter-complex.js +2 -1
- package/statistic/statistic.html +8 -2
- package/statistic/statistic.js +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -151,7 +151,7 @@
|
|
|
151
151
|
|
|
152
152
|
## Version 0.4.17:
|
|
153
153
|
|
|
154
|
-
- Fixed mixing
|
|
154
|
+
- Fixed mixing-valve position calculation.
|
|
155
155
|
- Fixed up_down message for central node.
|
|
156
156
|
|
|
157
157
|
## Version 0.4.18:
|
|
@@ -160,7 +160,7 @@
|
|
|
160
160
|
|
|
161
161
|
## Version 0.4.19:
|
|
162
162
|
|
|
163
|
-
- Added min_change_time option to mixing
|
|
163
|
+
- Added min_change_time option to mixing-valve node.
|
|
164
164
|
|
|
165
165
|
## Version 0.4.20:
|
|
166
166
|
|
|
@@ -206,8 +206,8 @@
|
|
|
206
206
|
|
|
207
207
|
- Improved light control percentage status text.
|
|
208
208
|
- Fixed logic node when common outputs is configured but one value is set to "send nothing".
|
|
209
|
-
-
|
|
210
|
-
-
|
|
209
|
+
- mixing-valve can now output as percentage directly or with open/close impulses.
|
|
210
|
+
- mixing-valve tries to guess the best position, when getting enabled.
|
|
211
211
|
- Added debug topic to all nodes, to see current values.
|
|
212
212
|
- Added new node "mode-selector".
|
|
213
213
|
|
|
@@ -227,4 +227,13 @@
|
|
|
227
227
|
|
|
228
228
|
## Version 0.6.1:
|
|
229
229
|
|
|
230
|
-
- Removed some ui limits of mixing
|
|
230
|
+
- Removed some ui limits of mixing-valve.
|
|
231
|
+
|
|
232
|
+
## Version 0.6.2:
|
|
233
|
+
|
|
234
|
+
- Cached runtime config is revoked now, when new settings are applied in the web frontend.
|
|
235
|
+
- Removed feature from mixing-valve to automatically start with the best known position, because it hadn't worked as expected.
|
|
236
|
+
|
|
237
|
+
## Version 0.6.3:
|
|
238
|
+
|
|
239
|
+
- Fixed bug, when disabling mixing-valve while it is opening, the off mode close was not handled. Same for closing and off mode open.
|
package/SmartNodesContext.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"idn1":{"
|
|
1
|
+
{"idn1":{"value":null,"last_message":null}}
|
package/compare/compare.html
CHANGED
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
send_only_change: { value: true },
|
|
18
18
|
outputs: { value: 1 },
|
|
19
19
|
save_state: { value: false },
|
|
20
|
-
resend_on_start: { value: false }
|
|
20
|
+
resend_on_start: { value: false },
|
|
21
|
+
config_change_date: { value: "" },
|
|
21
22
|
},
|
|
22
23
|
inputs: 1,
|
|
23
24
|
outputs: 1,
|
|
@@ -158,6 +159,11 @@
|
|
|
158
159
|
$("#node-input-value2_type").val("NOTHING");
|
|
159
160
|
}
|
|
160
161
|
},
|
|
162
|
+
oneditsave: function ()
|
|
163
|
+
{
|
|
164
|
+
let node = this;
|
|
165
|
+
node.config_change_date = (new Date()).toISOString();
|
|
166
|
+
},
|
|
161
167
|
});
|
|
162
168
|
</script>
|
|
163
169
|
|
package/compare/compare.js
CHANGED
|
@@ -29,11 +29,12 @@ module.exports = function (RED)
|
|
|
29
29
|
],
|
|
30
30
|
last_result: null,
|
|
31
31
|
last_message: null,
|
|
32
|
+
config_change_date: config.config_change_date,
|
|
32
33
|
};
|
|
33
34
|
|
|
34
35
|
// load or delete saved values
|
|
35
36
|
if (config.save_state)
|
|
36
|
-
node_settings = Object.assign(node_settings, smart_context.get(node.id));
|
|
37
|
+
node_settings = Object.assign(node_settings, smart_context.get(node.id, config.config_change_date));
|
|
37
38
|
else
|
|
38
39
|
smart_context.del(node.id);
|
|
39
40
|
|
package/counter/counter.html
CHANGED
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
out_message: { value: '{"topic": ""}' },
|
|
13
13
|
out_message_type: { value: 'json' },
|
|
14
14
|
save_state: { value: false },
|
|
15
|
-
resend_on_start: { value: false }
|
|
15
|
+
resend_on_start: { value: false },
|
|
16
|
+
config_change_date: { value: "" },
|
|
16
17
|
},
|
|
17
18
|
inputs: 1,
|
|
18
19
|
outputs: 1,
|
|
@@ -98,7 +99,12 @@
|
|
|
98
99
|
this.out_message_type = "NOTHING";
|
|
99
100
|
$("#node-input-out_message_type").val("NOTHING");
|
|
100
101
|
}
|
|
101
|
-
}
|
|
102
|
+
},
|
|
103
|
+
oneditsave: function ()
|
|
104
|
+
{
|
|
105
|
+
let node = this;
|
|
106
|
+
node.config_change_date = (new Date()).toISOString();
|
|
107
|
+
},
|
|
102
108
|
});
|
|
103
109
|
</script>
|
|
104
110
|
|
package/counter/counter.js
CHANGED
|
@@ -24,11 +24,12 @@ module.exports = function (RED)
|
|
|
24
24
|
var node_settings = {
|
|
25
25
|
value: null,
|
|
26
26
|
last_message: null,
|
|
27
|
+
config_change_date: config.config_change_date,
|
|
27
28
|
};
|
|
28
29
|
|
|
29
30
|
// load or delete saved values
|
|
30
31
|
if (config.save_state)
|
|
31
|
-
node_settings = Object.assign(node_settings, smart_context.get(node.id));
|
|
32
|
+
node_settings = Object.assign(node_settings, smart_context.get(node.id, config.config_change_date));
|
|
32
33
|
else
|
|
33
34
|
smart_context.del(node.id);
|
|
34
35
|
|
package/delay/delay.html
CHANGED
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
off_delay_unit: { value: "s" },
|
|
12
12
|
delay_only_on_change: { value: true },
|
|
13
13
|
save_state: { value: false },
|
|
14
|
-
resend_on_start: { value: false }
|
|
14
|
+
resend_on_start: { value: false },
|
|
15
|
+
config_change_date: { value: "" },
|
|
15
16
|
},
|
|
16
17
|
inputs: 1,
|
|
17
18
|
outputs: 1,
|
|
@@ -93,6 +94,11 @@
|
|
|
93
94
|
});
|
|
94
95
|
$("#node-input-save_state").trigger("change");
|
|
95
96
|
},
|
|
97
|
+
oneditsave: function ()
|
|
98
|
+
{
|
|
99
|
+
let node = this;
|
|
100
|
+
node.config_change_date = (new Date()).toISOString();
|
|
101
|
+
},
|
|
96
102
|
});
|
|
97
103
|
</script>
|
|
98
104
|
|
package/delay/delay.js
CHANGED
|
@@ -29,12 +29,13 @@ module.exports = function (RED)
|
|
|
29
29
|
on_delay_ms: helper.getTimeInMs(config.on_delay, config.on_delay_unit),
|
|
30
30
|
off_delay_ms: helper.getTimeInMs(config.off_delay, config.off_delay_unit),
|
|
31
31
|
last_message: null,
|
|
32
|
+
config_change_date: config.config_change_date,
|
|
32
33
|
};
|
|
33
34
|
|
|
34
35
|
if (config.save_state)
|
|
35
36
|
{
|
|
36
37
|
// load old saved values
|
|
37
|
-
node_settings = Object.assign(node_settings, smart_context.get(node.id));
|
|
38
|
+
node_settings = Object.assign(node_settings, smart_context.get(node.id, config.config_change_date));
|
|
38
39
|
|
|
39
40
|
switch (node_settings.last_message?.payload)
|
|
40
41
|
{
|
package/forwarder/forwarder.html
CHANGED
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
always_forward_false: { value: false },
|
|
11
11
|
forward_last_on_enable: { value: false },
|
|
12
12
|
save_state: { value: false },
|
|
13
|
-
resend_on_start: { value: false }
|
|
13
|
+
resend_on_start: { value: false },
|
|
14
|
+
config_change_date: { value: "" },
|
|
14
15
|
},
|
|
15
16
|
inputs: 1,
|
|
16
17
|
outputs: 1,
|
|
@@ -32,6 +33,11 @@
|
|
|
32
33
|
});
|
|
33
34
|
$("#node-input-save_state").trigger("change");
|
|
34
35
|
},
|
|
36
|
+
oneditsave: function ()
|
|
37
|
+
{
|
|
38
|
+
let node = this;
|
|
39
|
+
node.config_change_date = (new Date()).toISOString();
|
|
40
|
+
},
|
|
35
41
|
});
|
|
36
42
|
</script>
|
|
37
43
|
|
package/forwarder/forwarder.js
CHANGED
|
@@ -26,12 +26,13 @@ module.exports = function (RED)
|
|
|
26
26
|
var node_settings = {
|
|
27
27
|
enabled: config.enabled,
|
|
28
28
|
last_message: null,
|
|
29
|
-
last_msg_was_sended: true
|
|
29
|
+
last_msg_was_sended: true,
|
|
30
|
+
config_change_date: config.config_change_date,
|
|
30
31
|
};
|
|
31
32
|
|
|
32
33
|
// load or delete saved values
|
|
33
34
|
if (config.save_state)
|
|
34
|
-
node_settings = Object.assign(node_settings, smart_context.get(node.id));
|
|
35
|
+
node_settings = Object.assign(node_settings, smart_context.get(node.id, config.config_change_date));
|
|
35
36
|
else
|
|
36
37
|
smart_context.del(node.id);
|
|
37
38
|
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
offset: { value: 0 },
|
|
13
13
|
flow_max: { value: 75 },
|
|
14
14
|
flow_min: { value: 20 },
|
|
15
|
+
config_change_date: { value: "" },
|
|
15
16
|
},
|
|
16
17
|
inputs: 1,
|
|
17
18
|
outputs: 1,
|
|
@@ -109,6 +110,11 @@
|
|
|
109
110
|
drawCanvas();
|
|
110
111
|
|
|
111
112
|
},
|
|
113
|
+
oneditsave: function ()
|
|
114
|
+
{
|
|
115
|
+
let node = this;
|
|
116
|
+
node.config_change_date = (new Date()).toISOString();
|
|
117
|
+
},
|
|
112
118
|
});
|
|
113
119
|
|
|
114
120
|
let drawCanvas = () =>
|
|
@@ -27,8 +27,9 @@ module.exports = function (RED)
|
|
|
27
27
|
flow_min: config.flow_min,
|
|
28
28
|
flow_max: config.flow_max,
|
|
29
29
|
temperature_outside: 10,
|
|
30
|
-
last_flow_temperature: null
|
|
31
|
-
|
|
30
|
+
last_flow_temperature: null,
|
|
31
|
+
config_change_date: config.config_change_date,
|
|
32
|
+
}, smart_context.get(node.id, config.config_change_date));
|
|
32
33
|
|
|
33
34
|
|
|
34
35
|
// ##################
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
send_only_change: { value: true },
|
|
18
18
|
outputs: { value: 1 },
|
|
19
19
|
save_state: { value: false },
|
|
20
|
-
resend_on_start: { value: false }
|
|
20
|
+
resend_on_start: { value: false },
|
|
21
|
+
config_change_date: { value: "" },
|
|
21
22
|
},
|
|
22
23
|
inputs: 1,
|
|
23
24
|
outputs: 2,
|
|
@@ -196,11 +197,13 @@
|
|
|
196
197
|
{
|
|
197
198
|
let node = this;
|
|
198
199
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
200
|
+
node.setpoint = parseFloat(node.setpoint ?? 10);
|
|
201
|
+
node.hysteresis = parseFloat(node.hysteresis ?? 1);
|
|
202
|
+
node.min = parseFloat(node.min ?? 10);
|
|
203
|
+
node.max = parseFloat(node.max ?? 20);
|
|
204
|
+
|
|
205
|
+
node.config_change_date = (new Date()).toISOString();
|
|
206
|
+
},
|
|
204
207
|
});
|
|
205
208
|
</script>
|
|
206
209
|
|
package/hysteresis/hysteresis.js
CHANGED
|
@@ -30,13 +30,14 @@ module.exports = function (RED)
|
|
|
30
30
|
setpoint: parseFloat(config.setpoint ?? 10),
|
|
31
31
|
hysteresis: parseFloat(config.hysteresis ?? 1),
|
|
32
32
|
min: parseFloat(config.min ?? 10),
|
|
33
|
-
max: parseFloat(config.max ?? 20)
|
|
33
|
+
max: parseFloat(config.max ?? 20),
|
|
34
|
+
config_change_date: config.config_change_date,
|
|
34
35
|
};
|
|
35
36
|
|
|
36
37
|
if (config.save_state)
|
|
37
38
|
{
|
|
38
39
|
// load old saved values
|
|
39
|
-
node_settings = Object.assign(node_settings, smart_context.get(node.id));
|
|
40
|
+
node_settings = Object.assign(node_settings, smart_context.get(node.id, config.config_change_date));
|
|
40
41
|
|
|
41
42
|
switch (node_settings.last_result)
|
|
42
43
|
{
|
package/light/light.html
CHANGED
|
@@ -144,7 +144,8 @@
|
|
|
144
144
|
max_time_on_unit: { value: "s" },
|
|
145
145
|
alarm_action: { value: 'NOTHING' }, // NOTHING | ON | OFF
|
|
146
146
|
alarm_off_action: { value: 'NOTHING' }, // NOTHING | ON | OFF | LAST | LAST_SENDED
|
|
147
|
-
links: { value: [], type: "smart_central-control[]" }
|
|
147
|
+
links: { value: [], type: "smart_central-control[]" },
|
|
148
|
+
config_change_date: { value: "" },
|
|
148
149
|
},
|
|
149
150
|
inputs: 1,
|
|
150
151
|
outputs: 1,
|
|
@@ -236,6 +237,11 @@
|
|
|
236
237
|
{
|
|
237
238
|
this.links = [];
|
|
238
239
|
},
|
|
240
|
+
oneditsave: function ()
|
|
241
|
+
{
|
|
242
|
+
let node = this;
|
|
243
|
+
node.config_change_date = (new Date()).toISOString();
|
|
244
|
+
},
|
|
239
245
|
oneditresize: resizeNodeList
|
|
240
246
|
});
|
|
241
247
|
})();
|
package/light/light.js
CHANGED
|
@@ -36,7 +36,8 @@ module.exports = function (RED)
|
|
|
36
36
|
last_value_before_alarm: false,
|
|
37
37
|
last_value_sended: false,
|
|
38
38
|
alarm_active: false,
|
|
39
|
-
|
|
39
|
+
config_change_date: config.config_change_date,
|
|
40
|
+
}, smart_context.get(node.id, config.config_change_date));
|
|
40
41
|
|
|
41
42
|
|
|
42
43
|
// ##################
|
package/logic/logic.html
CHANGED
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
send_only_change: { value: true },
|
|
17
17
|
outputs: { value: 1 },
|
|
18
18
|
save_state: { value: false },
|
|
19
|
-
resend_on_start: { value: false }
|
|
19
|
+
resend_on_start: { value: false },
|
|
20
|
+
config_change_date: { value: "" },
|
|
20
21
|
},
|
|
21
22
|
inputs: 1,
|
|
22
23
|
outputs: 1,
|
|
@@ -139,7 +140,12 @@
|
|
|
139
140
|
$("#resend_on_start_row").hide();
|
|
140
141
|
});
|
|
141
142
|
$("#node-input-save_state").trigger("change");
|
|
142
|
-
}
|
|
143
|
+
},
|
|
144
|
+
oneditsave: function ()
|
|
145
|
+
{
|
|
146
|
+
let node = this;
|
|
147
|
+
node.config_change_date = (new Date()).toISOString();
|
|
148
|
+
},
|
|
143
149
|
});
|
|
144
150
|
|
|
145
151
|
let refreshInverts = inputs =>
|
package/logic/logic.js
CHANGED
|
@@ -26,12 +26,13 @@ module.exports = function (RED)
|
|
|
26
26
|
input_states: Array.from({ length: config.logic_inputs }).fill(false),
|
|
27
27
|
last_result: null,
|
|
28
28
|
last_message: null,
|
|
29
|
+
config_change_date: config.config_change_date,
|
|
29
30
|
};
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
// load or delete saved values
|
|
33
34
|
if (config.save_state)
|
|
34
|
-
node_settings = Object.assign(node_settings, smart_context.get(node.id));
|
|
35
|
+
node_settings = Object.assign(node_settings, smart_context.get(node.id, config.config_change_date));
|
|
35
36
|
else
|
|
36
37
|
smart_context.del(node.id);
|
|
37
38
|
|
|
@@ -152,6 +152,7 @@
|
|
|
152
152
|
min_change_time: { value: 100 },
|
|
153
153
|
links: { value: [], type: "smart_central-control[]" },
|
|
154
154
|
alarm_action: { value: "NOTHING" }, // NOTHING | OPEN | CLOSE
|
|
155
|
+
config_change_date: { value: "" },
|
|
155
156
|
},
|
|
156
157
|
inputs: 1,
|
|
157
158
|
outputs: 1,
|
|
@@ -267,7 +268,7 @@
|
|
|
267
268
|
],
|
|
268
269
|
}],
|
|
269
270
|
});
|
|
270
|
-
|
|
271
|
+
|
|
271
272
|
$("#node-input-alarm_action")
|
|
272
273
|
.css("max-width", "70%")
|
|
273
274
|
.typedInput({
|
|
@@ -348,6 +349,11 @@
|
|
|
348
349
|
{
|
|
349
350
|
this.links = [];
|
|
350
351
|
},
|
|
352
|
+
oneditsave: function ()
|
|
353
|
+
{
|
|
354
|
+
let node = this;
|
|
355
|
+
node.config_change_date = (new Date()).toISOString();
|
|
356
|
+
},
|
|
351
357
|
oneditresize: resizeNodeList
|
|
352
358
|
});
|
|
353
359
|
})();
|
|
@@ -33,10 +33,12 @@ module.exports = function (RED)
|
|
|
33
33
|
setpoint: config.setpoint,
|
|
34
34
|
off_mode: config.off_mode,
|
|
35
35
|
valve_mode: config.valve_mode,
|
|
36
|
+
current_temperature: null,
|
|
36
37
|
last_position: null,
|
|
37
38
|
last_enabled_sended: null,
|
|
38
|
-
alarm_active: false
|
|
39
|
-
|
|
39
|
+
alarm_active: false,
|
|
40
|
+
config_change_date: config.config_change_date,
|
|
41
|
+
}, smart_context.get(node.id, config.config_change_date));
|
|
40
42
|
|
|
41
43
|
// Ensure correct types
|
|
42
44
|
node_settings.enabled = !!node_settings.enabled;
|
|
@@ -59,11 +61,6 @@ module.exports = function (RED)
|
|
|
59
61
|
let output_mode = config.output_mode || OUTPUT_MODE_OPEN_CLOSE;
|
|
60
62
|
let force_position = null;
|
|
61
63
|
let alarm_action = config.alarm_action || "NOTHING"; // NOTHING | OPEN | CLOSE
|
|
62
|
-
let min_temperature = null;
|
|
63
|
-
let min_temperature_position = null;
|
|
64
|
-
let max_temperature = null;
|
|
65
|
-
let max_temperature_position = null;
|
|
66
|
-
let temp_save_date = Date.now();
|
|
67
64
|
let precision = parseInt(config.precision || 1, 10);
|
|
68
65
|
let max_change_percent = parseInt(config.max_change_percent || 2, 10);
|
|
69
66
|
let max_change_temp_difference = parseInt(config.max_change_temp_difference || 20, 10);
|
|
@@ -86,9 +83,6 @@ module.exports = function (RED)
|
|
|
86
83
|
// Store the direction of the adjustment
|
|
87
84
|
let adjusting = null;
|
|
88
85
|
|
|
89
|
-
// Stores the current temperature which is used to determine the adjusting direction
|
|
90
|
-
let current_temperature = null;
|
|
91
|
-
|
|
92
86
|
// The start time of the adjustment to count the change
|
|
93
87
|
let adjusting_start_time = null;
|
|
94
88
|
|
|
@@ -112,7 +106,6 @@ module.exports = function (RED)
|
|
|
112
106
|
handleTopic(msg);
|
|
113
107
|
|
|
114
108
|
setStatus();
|
|
115
|
-
resetSavedTemperatures();
|
|
116
109
|
smart_context.set(node.id, node_settings);
|
|
117
110
|
});
|
|
118
111
|
|
|
@@ -179,16 +172,16 @@ module.exports = function (RED)
|
|
|
179
172
|
current_mode: calibration_timeout !== null ? "CALIBRATION" : (changing_timeout !== null ? (adjusting == ADJUST_OPEN ? "OPENING" : "CLOSING") : "IDLE"),
|
|
180
173
|
enabled: (node_settings.enabled ? "ENABLED" : "DISABLED"),
|
|
181
174
|
heating_mode: node_settings.valve_mode,
|
|
182
|
-
current_temperature,
|
|
175
|
+
current_temperature: node_settings.current_temperature,
|
|
183
176
|
output_mode,
|
|
184
177
|
precision,
|
|
185
178
|
max_change_percent,
|
|
186
179
|
max_change_temp_difference,
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
180
|
+
sampling_interval,
|
|
181
|
+
calibration_timeout,
|
|
182
|
+
changing_timeout,
|
|
183
|
+
adjusting,
|
|
184
|
+
adjusting_start_time,
|
|
192
185
|
});
|
|
193
186
|
break;
|
|
194
187
|
|
|
@@ -207,41 +200,6 @@ module.exports = function (RED)
|
|
|
207
200
|
return;
|
|
208
201
|
|
|
209
202
|
stopChanging();
|
|
210
|
-
|
|
211
|
-
// Set the most probable position
|
|
212
|
-
if (
|
|
213
|
-
min_temperature !== null &&
|
|
214
|
-
max_temperature !== null &&
|
|
215
|
-
min_temperature_position !== null &&
|
|
216
|
-
max_temperature_position !== null
|
|
217
|
-
)
|
|
218
|
-
{
|
|
219
|
-
let temp_range = max_temperature - min_temperature;
|
|
220
|
-
let pos_range = max_temperature_position - min_temperature_position;
|
|
221
|
-
|
|
222
|
-
if (
|
|
223
|
-
temp_range > 0 &&
|
|
224
|
-
pos_range !== 0 &&
|
|
225
|
-
node_settings.setpoint >= min_temperature &&
|
|
226
|
-
node_settings.setpoint <= max_temperature
|
|
227
|
-
)
|
|
228
|
-
{
|
|
229
|
-
let rel_pos;
|
|
230
|
-
if (node_settings.valve_mode === "HEATING")
|
|
231
|
-
{
|
|
232
|
-
// For HEATING, min_temperature_position is closed, max_temperature_position is open
|
|
233
|
-
rel_pos = min_temperature_position + ((node_settings.setpoint - min_temperature) / temp_range) * pos_range;
|
|
234
|
-
}
|
|
235
|
-
else
|
|
236
|
-
{
|
|
237
|
-
// For COOLING, max_temperature_position is closed, min_temperature_position is open
|
|
238
|
-
rel_pos = max_temperature_position + ((node_settings.setpoint - max_temperature) / -temp_range) * pos_range;
|
|
239
|
-
}
|
|
240
|
-
force_position = Math.min(Math.max(rel_pos, 0), 100);
|
|
241
|
-
helper.log(node, "Set force position to " + force_position.toFixed(1) + "% based on previous min/max temperature positions");
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
203
|
startSampling();
|
|
246
204
|
break;
|
|
247
205
|
|
|
@@ -256,6 +214,7 @@ module.exports = function (RED)
|
|
|
256
214
|
if (node_settings.alarm_active)
|
|
257
215
|
return;
|
|
258
216
|
|
|
217
|
+
stopChanging();
|
|
259
218
|
stopSampling();
|
|
260
219
|
doOffMode();
|
|
261
220
|
break;
|
|
@@ -294,16 +253,6 @@ module.exports = function (RED)
|
|
|
294
253
|
{
|
|
295
254
|
case "HEATING":
|
|
296
255
|
case "COOLING":
|
|
297
|
-
|
|
298
|
-
if (node_settings.valve_mode != msg.payload)
|
|
299
|
-
{
|
|
300
|
-
// When changing the mode, reset min/max temperature
|
|
301
|
-
min_temperature = null;
|
|
302
|
-
max_temperature = null;
|
|
303
|
-
min_temperature_position = null;
|
|
304
|
-
max_temperature_position = null;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
256
|
node_settings.valve_mode = msg.payload;
|
|
308
257
|
setStatus();
|
|
309
258
|
break;
|
|
@@ -312,18 +261,16 @@ module.exports = function (RED)
|
|
|
312
261
|
helper.warn(this, "Invalid valve_mode: " + msg.payload);
|
|
313
262
|
return;
|
|
314
263
|
}
|
|
315
|
-
|
|
316
|
-
startSampling();
|
|
317
264
|
break;
|
|
318
265
|
|
|
319
266
|
case "current_temperature":
|
|
320
267
|
let new_temp = parseFloat(msg.payload);
|
|
321
268
|
if (isNaN(new_temp) || !isFinite(new_temp))
|
|
322
269
|
{
|
|
323
|
-
// helper.warn(this, "Invalid payload for current_temperature: " + msg.payload);
|
|
270
|
+
// helper.warn(this, "Invalid payload for node_settings.current_temperature: " + msg.payload);
|
|
324
271
|
return;
|
|
325
272
|
}
|
|
326
|
-
current_temperature = new_temp;
|
|
273
|
+
node_settings.current_temperature = new_temp;
|
|
327
274
|
break;
|
|
328
275
|
|
|
329
276
|
case "calibrate":
|
|
@@ -344,7 +291,7 @@ module.exports = function (RED)
|
|
|
344
291
|
switch (alarm_action)
|
|
345
292
|
{
|
|
346
293
|
case "OPEN":
|
|
347
|
-
force_position = 100
|
|
294
|
+
force_position = 100;
|
|
348
295
|
break;
|
|
349
296
|
|
|
350
297
|
case "CLOSE":
|
|
@@ -467,10 +414,10 @@ module.exports = function (RED)
|
|
|
467
414
|
let sample = () =>
|
|
468
415
|
{
|
|
469
416
|
// No current temperature available or in calibration => no action
|
|
470
|
-
if (current_temperature === null || calibration_timeout !== null || !node_settings.enabled)
|
|
417
|
+
if (node_settings.current_temperature === null || calibration_timeout !== null || !node_settings.enabled)
|
|
471
418
|
{
|
|
472
419
|
helper.log(node, "No sample possible", {
|
|
473
|
-
current_temperature,
|
|
420
|
+
current_temperature: node_settings.current_temperature,
|
|
474
421
|
calibration_timeout,
|
|
475
422
|
enabled: node_settings.enabled
|
|
476
423
|
});
|
|
@@ -478,27 +425,9 @@ module.exports = function (RED)
|
|
|
478
425
|
}
|
|
479
426
|
|
|
480
427
|
// +/- 1°C => already good enough, do nothing
|
|
481
|
-
let temp_diff = Math.abs(current_temperature - node_settings.setpoint);
|
|
428
|
+
let temp_diff = Math.abs(node_settings.current_temperature - node_settings.setpoint);
|
|
482
429
|
if (temp_diff < precision)
|
|
483
|
-
{
|
|
484
|
-
if (!node_settings.alarm_active)
|
|
485
|
-
{
|
|
486
|
-
// Found a good position for the current setpoint
|
|
487
|
-
// Update min/max temperature
|
|
488
|
-
if (min_temperature === null || current_temperature < min_temperature)
|
|
489
|
-
{
|
|
490
|
-
min_temperature = current_temperature;
|
|
491
|
-
min_temperature_position = node_settings.last_position;
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
if (max_temperature === null || current_temperature > max_temperature)
|
|
495
|
-
{
|
|
496
|
-
max_temperature = current_temperature;
|
|
497
|
-
max_temperature_position = node_settings.last_position;
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
430
|
return;
|
|
501
|
-
}
|
|
502
431
|
|
|
503
432
|
// 0 °C diff => 0% change
|
|
504
433
|
// for max_change_temp_difference (default: 20 °C) diff => max_change_percent (default: 2%) change
|
|
@@ -512,7 +441,7 @@ module.exports = function (RED)
|
|
|
512
441
|
|
|
513
442
|
// calculate direction
|
|
514
443
|
let adjustAction = ADJUST_CLOSE;
|
|
515
|
-
if (current_temperature < node_settings.setpoint)
|
|
444
|
+
if (node_settings.current_temperature < node_settings.setpoint)
|
|
516
445
|
{
|
|
517
446
|
if (node_settings.valve_mode == "HEATING")
|
|
518
447
|
adjustAction = ADJUST_OPEN;
|
|
@@ -705,29 +634,14 @@ module.exports = function (RED)
|
|
|
705
634
|
}
|
|
706
635
|
}
|
|
707
636
|
|
|
708
|
-
let resetSavedTemperatures = () =>
|
|
709
|
-
{
|
|
710
|
-
let now = Date.now();
|
|
711
|
-
|
|
712
|
-
// Reset saved temperatures after 7 days, to avoid using too old data
|
|
713
|
-
if (now - temp_save_date >= 7 * 24 * 60 * 60 * 1000)
|
|
714
|
-
{
|
|
715
|
-
temp_save_date = now;
|
|
716
|
-
min_temperature = null;
|
|
717
|
-
min_temperature_position = null;
|
|
718
|
-
max_temperature = null;
|
|
719
|
-
max_temperature_position = null;
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
|
|
723
637
|
let setStatus = () =>
|
|
724
638
|
{
|
|
725
639
|
if (calibration_timeout !== null)
|
|
726
640
|
node.status({ fill: "yellow", shape: "ring", text: helper.getCurrentTimeForStatus() + ": In calibration" });
|
|
727
641
|
else if (changing_timeout != null)
|
|
728
|
-
node.status({ fill: node_settings.enabled ? "green" : "red", shape: "ring", text: helper.getCurrentTimeForStatus() + ": " + (node_settings.alarm_active ? "ALARM - " : "") + (node_settings.valve_mode == "HEATING" ? "🔥" : "❄️") + " " + (adjusting == ADJUST_OPEN ? "Opening" : "Closing") + ", Set: " + helper.toFixed(node_settings.setpoint, 1) + "°C, Cur: " + helper.toFixed(current_temperature, 1) + "°C, Pos: " + helper.toFixed(node_settings.last_position, 1) + "%" });
|
|
642
|
+
node.status({ fill: node_settings.enabled ? "green" : "red", shape: "ring", text: helper.getCurrentTimeForStatus() + ": " + (node_settings.alarm_active ? "ALARM - " : "") + (node_settings.valve_mode == "HEATING" ? "🔥" : "❄️") + " " + (adjusting == ADJUST_OPEN ? "Opening" : "Closing") + ", Set: " + helper.toFixed(node_settings.setpoint, 1) + "°C, Cur: " + helper.toFixed(node_settings.current_temperature, 1) + "°C, Pos: " + helper.toFixed(node_settings.last_position, 1) + "%" });
|
|
729
643
|
else
|
|
730
|
-
node.status({ fill: node_settings.enabled ? "green" : "red", shape: "dot", text: helper.getCurrentTimeForStatus() + ": " + (node_settings.alarm_active ? "ALARM - " : "") + (node_settings.valve_mode == "HEATING" ? "🔥" : "❄️") + " Set: " + helper.toFixed(node_settings.setpoint, 1) + "°C, Cur: " + helper.toFixed(current_temperature, 1) + "°C, Pos: " + helper.toFixed(node_settings.last_position, 1) + "%" });
|
|
644
|
+
node.status({ fill: node_settings.enabled ? "green" : "red", shape: "dot", text: helper.getCurrentTimeForStatus() + ": " + (node_settings.alarm_active ? "ALARM - " : "") + (node_settings.valve_mode == "HEATING" ? "🔥" : "❄️") + " Set: " + helper.toFixed(node_settings.setpoint, 1) + "°C, Cur: " + helper.toFixed(node_settings.current_temperature, 1) + "°C, Pos: " + helper.toFixed(node_settings.last_position, 1) + "%" });
|
|
731
645
|
}
|
|
732
646
|
|
|
733
647
|
/**
|
|
@@ -749,22 +663,14 @@ module.exports = function (RED)
|
|
|
749
663
|
|
|
750
664
|
if (node_settings.last_position === null)
|
|
751
665
|
{
|
|
752
|
-
|
|
753
|
-
{
|
|
754
|
-
// Start calibration after 10s
|
|
755
|
-
setTimeout(calibrate, 10 * 1000);
|
|
756
|
-
}
|
|
757
|
-
else
|
|
758
|
-
{
|
|
759
|
-
node_settings.last_position = 0;
|
|
760
|
-
}
|
|
666
|
+
node_settings.last_position = 50;
|
|
761
667
|
}
|
|
762
668
|
else if (node_settings.alarm_active)
|
|
763
669
|
{
|
|
764
670
|
switch (alarm_action)
|
|
765
671
|
{
|
|
766
672
|
case "OPEN":
|
|
767
|
-
force_position = 100
|
|
673
|
+
force_position = 100;
|
|
768
674
|
break;
|
|
769
675
|
|
|
770
676
|
case "CLOSE":
|
|
@@ -41,7 +41,8 @@
|
|
|
41
41
|
outputs: { value: 1 },
|
|
42
42
|
mode_items: { value: ["MODE1", "MODE2"] },
|
|
43
43
|
update_only_changed_outputs: { value: true },
|
|
44
|
-
resend_on_start: { value: false }
|
|
44
|
+
resend_on_start: { value: false },
|
|
45
|
+
config_change_date: { value: "" },
|
|
45
46
|
},
|
|
46
47
|
inputs: 1,
|
|
47
48
|
outputs: 1,
|
|
@@ -125,8 +126,10 @@
|
|
|
125
126
|
// Set modes
|
|
126
127
|
var items = $("#node-input-property-modes").editableList("items");
|
|
127
128
|
var result = getModes(items);
|
|
128
|
-
|
|
129
|
-
|
|
129
|
+
node.mode_items = result.modes;
|
|
130
|
+
node.outputs = node.mode_items.length;
|
|
131
|
+
|
|
132
|
+
node.config_change_date = (new Date()).toISOString();
|
|
130
133
|
},
|
|
131
134
|
oneditresize: resizeDialog
|
|
132
135
|
});
|
|
@@ -25,7 +25,8 @@ module.exports = function (RED)
|
|
|
25
25
|
// #####################
|
|
26
26
|
var node_settings = helper.cloneObject({
|
|
27
27
|
last_mode: null,
|
|
28
|
-
|
|
28
|
+
config_change_date: config.config_change_date,
|
|
29
|
+
}, smart_context.get(node.id, config.config_change_date));
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
// ##################
|
package/package.json
CHANGED
package/persistence.js
CHANGED
|
@@ -21,6 +21,8 @@ module.exports = function (_RED)
|
|
|
21
21
|
const userDir = (_RED.settings && _RED.settings.userDir) ? _RED.settings.userDir : process.cwd();
|
|
22
22
|
const filePath = pathLib.join(userDir, 'SmartNodesContext.json');
|
|
23
23
|
|
|
24
|
+
// console.log(filePath);
|
|
25
|
+
|
|
24
26
|
let globalData = {};
|
|
25
27
|
|
|
26
28
|
if (fs.existsSync(filePath))
|
|
@@ -39,13 +41,13 @@ module.exports = function (_RED)
|
|
|
39
41
|
}
|
|
40
42
|
}
|
|
41
43
|
|
|
42
|
-
// Autosave each
|
|
44
|
+
// Autosave each 15 seconds if changes exists.
|
|
43
45
|
let interval = setInterval(() =>
|
|
44
46
|
{
|
|
45
47
|
if (hasChanges)
|
|
46
48
|
save();
|
|
47
49
|
|
|
48
|
-
},
|
|
50
|
+
}, 15 * 1000);
|
|
49
51
|
|
|
50
52
|
// Prevent the interval from keeping the process alive (important for Jest)
|
|
51
53
|
if (interval && typeof interval.unref === "function")
|
|
@@ -80,9 +82,13 @@ module.exports = function (_RED)
|
|
|
80
82
|
save();
|
|
81
83
|
}
|
|
82
84
|
|
|
83
|
-
function get(id)
|
|
85
|
+
function get(id, config_change_date)
|
|
84
86
|
{
|
|
85
|
-
|
|
87
|
+
let data = globalData["id" + id];
|
|
88
|
+
if (data && data.config_change_date && data.config_change_date !== config_change_date)
|
|
89
|
+
return null;
|
|
90
|
+
|
|
91
|
+
return data;
|
|
86
92
|
}
|
|
87
93
|
|
|
88
94
|
function del(id)
|
package/scene/scene.html
CHANGED
|
@@ -226,7 +226,8 @@
|
|
|
226
226
|
scenes: {
|
|
227
227
|
value: [{ name: "", outputs: "" }],
|
|
228
228
|
},
|
|
229
|
-
links: { value: [], type: "smart_central-control[]" }
|
|
229
|
+
links: { value: [], type: "smart_central-control[]" },
|
|
230
|
+
config_change_date: { value: "" },
|
|
230
231
|
},
|
|
231
232
|
inputs: 1,
|
|
232
233
|
outputs: 1,
|
|
@@ -427,13 +428,15 @@
|
|
|
427
428
|
// Set scenes
|
|
428
429
|
var items = $("#node-input-property-scenes").editableList("items");
|
|
429
430
|
var result = getScenes(items);
|
|
430
|
-
|
|
431
|
+
node.scenes = result.scenes;
|
|
431
432
|
|
|
432
433
|
// Set outputs
|
|
433
434
|
var items = $("#node-input-property-outputs").editableList("items");
|
|
434
435
|
var result = getOutputs(items);
|
|
435
|
-
|
|
436
|
-
|
|
436
|
+
node.output_items = result.output_items;
|
|
437
|
+
node.outputs = node.output_items.length;
|
|
438
|
+
|
|
439
|
+
node.config_change_date = (new Date()).toISOString();
|
|
437
440
|
},
|
|
438
441
|
onadd: function ()
|
|
439
442
|
{
|
package/scene/scene.js
CHANGED
|
@@ -34,7 +34,8 @@ module.exports = function (RED)
|
|
|
34
34
|
// #####################
|
|
35
35
|
var node_settings = helper.cloneObject({
|
|
36
36
|
last_values: [], // light is on or off for a scene
|
|
37
|
-
|
|
37
|
+
config_change_date: config.config_change_date,
|
|
38
|
+
}, smart_context.get(node.id, config.config_change_date));
|
|
38
39
|
|
|
39
40
|
|
|
40
41
|
// ##################
|
package/scheduler/scheduler.html
CHANGED
|
@@ -100,7 +100,8 @@
|
|
|
100
100
|
},
|
|
101
101
|
},
|
|
102
102
|
save_state: { value: false },
|
|
103
|
-
resend_on_start: { value: false }
|
|
103
|
+
resend_on_start: { value: false },
|
|
104
|
+
config_change_date: { value: "" },
|
|
104
105
|
},
|
|
105
106
|
inputs: 1,
|
|
106
107
|
outputs: 1,
|
|
@@ -266,7 +267,6 @@
|
|
|
266
267
|
return s;
|
|
267
268
|
}
|
|
268
269
|
},
|
|
269
|
-
|
|
270
270
|
oneditsave: function ()
|
|
271
271
|
{
|
|
272
272
|
let node = this;
|
|
@@ -298,6 +298,8 @@
|
|
|
298
298
|
node.schedules.push(schedule);
|
|
299
299
|
}
|
|
300
300
|
});
|
|
301
|
+
|
|
302
|
+
node.config_change_date = (new Date()).toISOString();
|
|
301
303
|
},
|
|
302
304
|
});
|
|
303
305
|
</script>
|
package/scheduler/scheduler.js
CHANGED
|
@@ -26,12 +26,13 @@ module.exports = function (RED)
|
|
|
26
26
|
var node_settings = {
|
|
27
27
|
enabled: config.enabled,
|
|
28
28
|
last_message: null,
|
|
29
|
+
config_change_date: config.config_change_date,
|
|
29
30
|
};
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
// load or delete saved values
|
|
33
34
|
if (config.save_state)
|
|
34
|
-
node_settings = Object.assign(node_settings, smart_context.get(node.id));
|
|
35
|
+
node_settings = Object.assign(node_settings, smart_context.get(node.id, config.config_change_date));
|
|
35
36
|
else
|
|
36
37
|
smart_context.del(node.id);
|
|
37
38
|
|
package/shutter/shutter.html
CHANGED
|
@@ -140,7 +140,8 @@
|
|
|
140
140
|
name: { value: "" },
|
|
141
141
|
exec_text_names: { value: "" },
|
|
142
142
|
short_time_on_ms: { value: 200 },
|
|
143
|
-
links: { value: [], type: "smart_central-control[]" }
|
|
143
|
+
links: { value: [], type: "smart_central-control[]" },
|
|
144
|
+
config_change_date: { value: "" },
|
|
144
145
|
},
|
|
145
146
|
inputs: 1,
|
|
146
147
|
outputs: 3,
|
|
@@ -176,6 +177,11 @@
|
|
|
176
177
|
{
|
|
177
178
|
this.links = [];
|
|
178
179
|
},
|
|
180
|
+
oneditsave: function ()
|
|
181
|
+
{
|
|
182
|
+
let node = this;
|
|
183
|
+
node.config_change_date = (new Date()).toISOString();
|
|
184
|
+
},
|
|
179
185
|
oneditresize: resizeNodeList
|
|
180
186
|
});
|
|
181
187
|
})();
|
package/shutter/shutter.js
CHANGED
|
@@ -34,7 +34,8 @@ module.exports = function (RED)
|
|
|
34
34
|
var node_settings = helper.cloneObject({
|
|
35
35
|
last_position: 0, // 0 = opened, 100 = closed
|
|
36
36
|
last_direction_up: true, // remember last direction for toggle action
|
|
37
|
-
|
|
37
|
+
config_change_date: config.config_change_date,
|
|
38
|
+
}, smart_context.get(node.id, config.config_change_date));
|
|
38
39
|
|
|
39
40
|
|
|
40
41
|
// ##################
|
|
@@ -145,7 +145,8 @@
|
|
|
145
145
|
revert_time_ms: { value: 100 },
|
|
146
146
|
alarm_action: { value: 'NOTHING' }, // NOTHING | UP | DOWN
|
|
147
147
|
alarm_off_action: { value: 'NOTHING' }, // NOTHING | ON | OFF | LAST
|
|
148
|
-
links: { value: [], type: "smart_central-control[]" }
|
|
148
|
+
links: { value: [], type: "smart_central-control[]" },
|
|
149
|
+
config_change_date: { value: "" },
|
|
149
150
|
},
|
|
150
151
|
inputs: 1,
|
|
151
152
|
outputs: 3,
|
|
@@ -250,6 +251,11 @@
|
|
|
250
251
|
{
|
|
251
252
|
this.links = [];
|
|
252
253
|
},
|
|
254
|
+
oneditsave: function ()
|
|
255
|
+
{
|
|
256
|
+
let node = this;
|
|
257
|
+
node.config_change_date = (new Date()).toISOString();
|
|
258
|
+
},
|
|
253
259
|
oneditresize: resizeNodeList
|
|
254
260
|
});
|
|
255
261
|
})();
|
|
@@ -39,7 +39,8 @@ module.exports = function (RED)
|
|
|
39
39
|
last_direction_up: true, // remember last direction for toggle action
|
|
40
40
|
last_position_before_alarm: 0, // remember position to restore on alarm off event
|
|
41
41
|
alarm_active: false, // remember if alarm is on or off
|
|
42
|
-
|
|
42
|
+
config_change_date: config.config_change_date,
|
|
43
|
+
}, smart_context.get(node.id, config.config_change_date));
|
|
43
44
|
|
|
44
45
|
|
|
45
46
|
// ##########################
|
package/statistic/statistic.html
CHANGED
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
out_message: { value: '{"topic": ""}' },
|
|
11
11
|
out_message_type: { value: 'json' },
|
|
12
12
|
save_state: { value: false },
|
|
13
|
-
resend_on_start: { value: false }
|
|
13
|
+
resend_on_start: { value: false },
|
|
14
|
+
config_change_date: { value: "" },
|
|
14
15
|
},
|
|
15
16
|
inputs: 1,
|
|
16
17
|
outputs: 1,
|
|
@@ -93,7 +94,12 @@
|
|
|
93
94
|
this.out_message_type = "NOTHING";
|
|
94
95
|
$("#node-input-out_message_type").val("NOTHING");
|
|
95
96
|
}
|
|
96
|
-
}
|
|
97
|
+
},
|
|
98
|
+
oneditsave: function ()
|
|
99
|
+
{
|
|
100
|
+
let node = this;
|
|
101
|
+
node.config_change_date = (new Date()).toISOString();
|
|
102
|
+
},
|
|
97
103
|
});
|
|
98
104
|
</script>
|
|
99
105
|
|
package/statistic/statistic.js
CHANGED
|
@@ -25,12 +25,13 @@ module.exports = function (RED)
|
|
|
25
25
|
var node_settings = {
|
|
26
26
|
values: [],
|
|
27
27
|
last_message: null,
|
|
28
|
+
config_change_date: config.config_change_date,
|
|
28
29
|
};
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
// load or delete saved values
|
|
32
33
|
if (config.save_state)
|
|
33
|
-
node_settings = Object.assign(node_settings, smart_context.get(node.id));
|
|
34
|
+
node_settings = Object.assign(node_settings, smart_context.get(node.id, config.config_change_date));
|
|
34
35
|
else
|
|
35
36
|
smart_context.del(node.id);
|
|
36
37
|
|