smart-nodes 0.6.0 → 0.6.2

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
@@ -224,3 +224,12 @@
224
224
  - Reduced amount of messages sent by light node when it is in alarm mode.
225
225
  - Fixed forwarder node causing an error when no topic was sent.
226
226
  - Added Jest example for all nodes to be able to debug nodes in vscode.
227
+
228
+ ## Version 0.6.1:
229
+
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.
@@ -1 +1 @@
1
- {"idn1":{"temperature_outside":10,"last_flow_temperature":null}}
1
+ {"idn1":{"last_value":false,"last_value_before_alarm":false,"last_value_sended":false,"alarm_active":false,"enabled":false,"setpoint":20,"current_temperature":null,"last_position":50,"last_enabled_sended":null}}
@@ -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
 
@@ -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
 
@@ -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
 
@@ -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
  {
@@ -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
 
@@ -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
- }, smart_context.get(node.id));
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
- this.setpoint = parseFloat(this.setpoint ?? 10);
200
- this.hysteresis = parseFloat(this.hysteresis ?? 1);
201
- this.min = parseFloat(this.min ?? 10);
202
- this.max = parseFloat(this.max ?? 20);
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
 
@@ -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
- }, smart_context.get(node.id));
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({
@@ -302,7 +303,7 @@
302
303
  .css("max-width", "4rem")
303
304
  .spinner({
304
305
  min: 1,
305
- max: 40,
306
+ max: 100,
306
307
  change: function (event, ui)
307
308
  {
308
309
  var value = parseInt(this.value);
@@ -317,7 +318,7 @@
317
318
  .css("max-width", "4rem")
318
319
  .spinner({
319
320
  min: 1,
320
- max: 20,
321
+ max: 100,
321
322
  change: function (event, ui)
322
323
  {
323
324
  var value = parseInt(this.value);
@@ -332,7 +333,7 @@
332
333
  .css("max-width", "4rem")
333
334
  .spinner({
334
335
  min: 0,
335
- max: 2000,
336
+ max: 10000,
336
337
  step: 100,
337
338
  change: function (event, ui)
338
339
  {
@@ -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
- }, smart_context.get(node.id));
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
- min_change_time,
188
- min_temperature,
189
- min_temperature_position,
190
- max_temperature,
191
- max_temperature_position,
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
 
@@ -294,16 +252,6 @@ module.exports = function (RED)
294
252
  {
295
253
  case "HEATING":
296
254
  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
255
  node_settings.valve_mode = msg.payload;
308
256
  setStatus();
309
257
  break;
@@ -312,18 +260,16 @@ module.exports = function (RED)
312
260
  helper.warn(this, "Invalid valve_mode: " + msg.payload);
313
261
  return;
314
262
  }
315
-
316
- startSampling();
317
263
  break;
318
264
 
319
265
  case "current_temperature":
320
266
  let new_temp = parseFloat(msg.payload);
321
267
  if (isNaN(new_temp) || !isFinite(new_temp))
322
268
  {
323
- // helper.warn(this, "Invalid payload for current_temperature: " + msg.payload);
269
+ // helper.warn(this, "Invalid payload for node_settings.current_temperature: " + msg.payload);
324
270
  return;
325
271
  }
326
- current_temperature = new_temp;
272
+ node_settings.current_temperature = new_temp;
327
273
  break;
328
274
 
329
275
  case "calibrate":
@@ -344,7 +290,7 @@ module.exports = function (RED)
344
290
  switch (alarm_action)
345
291
  {
346
292
  case "OPEN":
347
- force_position = 100;;
293
+ force_position = 100;
348
294
  break;
349
295
 
350
296
  case "CLOSE":
@@ -467,10 +413,10 @@ module.exports = function (RED)
467
413
  let sample = () =>
468
414
  {
469
415
  // No current temperature available or in calibration => no action
470
- if (current_temperature === null || calibration_timeout !== null || !node_settings.enabled)
416
+ if (node_settings.current_temperature === null || calibration_timeout !== null || !node_settings.enabled)
471
417
  {
472
418
  helper.log(node, "No sample possible", {
473
- current_temperature,
419
+ current_temperature: node_settings.current_temperature,
474
420
  calibration_timeout,
475
421
  enabled: node_settings.enabled
476
422
  });
@@ -478,27 +424,9 @@ module.exports = function (RED)
478
424
  }
479
425
 
480
426
  // +/- 1°C => already good enough, do nothing
481
- let temp_diff = Math.abs(current_temperature - node_settings.setpoint);
427
+ let temp_diff = Math.abs(node_settings.current_temperature - node_settings.setpoint);
482
428
  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
429
  return;
501
- }
502
430
 
503
431
  // 0 °C diff => 0% change
504
432
  // for max_change_temp_difference (default: 20 °C) diff => max_change_percent (default: 2%) change
@@ -512,7 +440,7 @@ module.exports = function (RED)
512
440
 
513
441
  // calculate direction
514
442
  let adjustAction = ADJUST_CLOSE;
515
- if (current_temperature < node_settings.setpoint)
443
+ if (node_settings.current_temperature < node_settings.setpoint)
516
444
  {
517
445
  if (node_settings.valve_mode == "HEATING")
518
446
  adjustAction = ADJUST_OPEN;
@@ -705,29 +633,14 @@ module.exports = function (RED)
705
633
  }
706
634
  }
707
635
 
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
636
  let setStatus = () =>
724
637
  {
725
638
  if (calibration_timeout !== null)
726
639
  node.status({ fill: "yellow", shape: "ring", text: helper.getCurrentTimeForStatus() + ": In calibration" });
727
640
  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) + "%" });
641
+ 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
642
  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) + "%" });
643
+ 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
644
  }
732
645
 
733
646
  /**
@@ -749,22 +662,14 @@ module.exports = function (RED)
749
662
 
750
663
  if (node_settings.last_position === null)
751
664
  {
752
- if (output_mode === OUTPUT_MODE_OPEN_CLOSE)
753
- {
754
- // Start calibration after 10s
755
- setTimeout(calibrate, 10 * 1000);
756
- }
757
- else
758
- {
759
- node_settings.last_position = 0;
760
- }
665
+ node_settings.last_position = 50;
761
666
  }
762
667
  else if (node_settings.alarm_active)
763
668
  {
764
669
  switch (alarm_action)
765
670
  {
766
671
  case "OPEN":
767
- force_position = 100;;
672
+ force_position = 100;
768
673
  break;
769
674
 
770
675
  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
- this.mode_items = result.modes;
129
- this.outputs = this.mode_items.length;
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
- }, smart_context.get(node.id));
28
+ config_change_date: config.config_change_date,
29
+ }, smart_context.get(node.id, config.config_change_date));
29
30
 
30
31
 
31
32
  // ##################
@@ -119,7 +119,7 @@
119
119
  }
120
120
 
121
121
  showNeededMessages(node.max_presses);
122
- }
122
+ },
123
123
  });
124
124
 
125
125
  let showNeededMessages = value =>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smart-nodes",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
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",
@@ -48,11 +48,11 @@
48
48
  "hysteresis": "hysteresis/hysteresis.js",
49
49
  "statistic": "statistic/statistic.js",
50
50
  "counter": "counter/counter.js",
51
+ "mode-selector": "mode-selector/mode-selector.js",
51
52
  "scheduler": "scheduler/scheduler.js",
52
53
  "delay": "delay/delay.js",
53
54
  "central": "central/central.js",
54
55
  "mixing-valve": "mixing-valve/mixing-valve.js",
55
- "mode-selector": "mode-selector/mode-selector.js",
56
56
  "heating-curve": "heating-curve/heating-curve.js",
57
57
  "text-exec": "text-exec/text-exec.js"
58
58
  }
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 30 seconds if changes exists.
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
- }, 30 * 1000);
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,25 @@ 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
- return globalData["id" + id];
87
+ let data = globalData["id" + id];
88
+ if (id == "7e5e332f362a43fb")
89
+ {
90
+ log({
91
+ old_config_change_date: data.config_change_date,
92
+ new_config_change_date: config_change_date
93
+ });
94
+ }
95
+
96
+ if (data && data.config_change_date && data.config_change_date !== config_change_date)
97
+ {
98
+ console.log("id = " + id + " - config change date mismatch, ignoring stored data.");
99
+ return null;
100
+ }
101
+
102
+
103
+ return data;
86
104
  }
87
105
 
88
106
  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
- this.scenes = result.scenes;
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
- this.output_items = result.output_items;
436
- this.outputs = this.output_items.length;
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
- }, smart_context.get(node.id));
37
+ config_change_date: config.config_change_date,
38
+ }, smart_context.get(node.id, config.config_change_date));
38
39
 
39
40
 
40
41
  // ##################
@@ -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>
@@ -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
 
@@ -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
  })();
@@ -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
- }, smart_context.get(node.id));
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
- }, smart_context.get(node.id));
42
+ config_change_date: config.config_change_date,
43
+ }, smart_context.get(node.id, config.config_change_date));
43
44
 
44
45
 
45
46
  // ##########################
@@ -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
 
@@ -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