smart-nodes 0.5.1 → 0.5.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
@@ -213,4 +213,8 @@
213
213
 
214
214
  ## Version 0.5.1:
215
215
 
216
- - To be more compatible, topic "set" is also possible instead of "set_state". Same for "set_inverted" instead of "set_state_inverted".
216
+ - To be more compatible, topic "set" is also possible instead of "set_state". Same for "set_inverted" instead of "set_state_inverted".
217
+
218
+ ## Version 0.5.2:
219
+
220
+ - Added alarm mode to mixing-valve.
@@ -63,6 +63,12 @@
63
63
  <td><code>current_temperature</code></td>
64
64
  <td>Setzt die aktuelle Temperatur auf <code>msg.payload</code> °C.</td>
65
65
  </tr>
66
+ <tr>
67
+ <td><code>alarm</code></td>
68
+ <td>
69
+ Setzt den aktuellen Alarmzustand auf den Wert von <code>msg.payload</code> und löst die konfigurierte Alarmaktion aus (Öffnen / Schließen).
70
+ </td>
71
+ </tr>
66
72
  <tr>
67
73
  <td><code>calibrate</code></td>
68
74
  <td>Erzwingt eine Kalibrierungsfahrt.</td>
@@ -15,6 +15,8 @@
15
15
 
16
16
  "nothing": "Nichts",
17
17
  "open": "Öffnen (100%)",
18
+ "alarm_on": "Alarm Ein",
19
+ "no_action": "Keine Aktion",
18
20
  "close": "Schließen (0%)",
19
21
  "heating": "Heizen (normal)",
20
22
  "cooling": "Kühlen (invertiert)",
@@ -63,6 +63,12 @@
63
63
  <td><code>current_temperature</code></td>
64
64
  <td>Sets the current temperature to <code>msg.payload</code> °C.</td>
65
65
  </tr>
66
+ <tr>
67
+ <td><code>alarm</code></td>
68
+ <td>
69
+ Sets the current alarm state to the value of <code>msg.payload</code> and triggers the configured alarm action (Open / Close).
70
+ </td>
71
+ </tr>
66
72
  <tr>
67
73
  <td><code>calibrate</code></td>
68
74
  <td>Forces a calibration run.</td>
@@ -15,6 +15,8 @@
15
15
 
16
16
  "nothing": "Nothing",
17
17
  "open": "Open (100%)",
18
+ "alarm_on": "Alarm on",
19
+ "no_action": "No action",
18
20
  "close": "Close (0%)",
19
21
  "heating": "Heating (normal)",
20
22
  "cooling": "Cooling (inverted)",
@@ -150,7 +150,8 @@
150
150
  max_change_percent: { value: 1 },
151
151
  max_change_temp_difference: { value: 20 },
152
152
  min_change_time: { value: 100 },
153
- links: { value: [], type: "smart_central-control[]" }
153
+ links: { value: [], type: "smart_central-control[]" },
154
+ alarm_action: { value: "NOTHING" }, // NOTHING | OPEN | CLOSE
154
155
  },
155
156
  inputs: 1,
156
157
  outputs: 1,
@@ -266,7 +267,20 @@
266
267
  ],
267
268
  }],
268
269
  });
269
-
270
+
271
+ $("#node-input-alarm_action")
272
+ .css("max-width", "70%")
273
+ .typedInput({
274
+ types: [{
275
+ value: "alarm_action",
276
+ default: "NOTHING",
277
+ options: [
278
+ { value: "NOTHING", label: node._("mixing-valve.ui.no_action") },
279
+ { value: "OPEN", label: node._("mixing-valve.ui.open") },
280
+ { value: "CLOSE", label: node._("mixing-valve.ui.close") }
281
+ ],
282
+ }],
283
+ });
270
284
 
271
285
  $("#node-input-precision")
272
286
  .css("max-width", "4rem")
@@ -372,6 +386,10 @@
372
386
  <label for="node-input-valve_mode"><i class="fa fa-fire"></i> <span data-i18n="mixing-valve.ui.mode"></span></label>
373
387
  <input id="node-input-valve_mode" />
374
388
  </div>
389
+ <div class="form-row">
390
+ <label for="node-input-alarm_action"><i class="fa fa-exclamation-triangle"></i> <span data-i18n="mixing-valve.ui.alarm_on"></span></label>
391
+ <input id="node-input-alarm_action"/>
392
+ </div>
375
393
  <div class="form-row">
376
394
  <label for="node-input-precision" style="width: 250px;"><i class="fa fa-sliders"></i> <span data-i18n="mixing-valve.ui.precision"></span></label>
377
395
  <input id="node-input-precision" value="1.0" /> °C
@@ -33,11 +33,9 @@ module.exports = function (RED)
33
33
  setpoint: config.setpoint,
34
34
  off_mode: config.off_mode,
35
35
  valve_mode: config.valve_mode,
36
- precision: config.precision || 1,
37
- max_change_percent: config.max_change_percent || 2,
38
- max_change_temp_difference: config.max_change_temp_difference || 20,
39
- min_change_time: config.min_change_time || 0,
40
36
  last_position: null,
37
+ last_enabled_sended: null,
38
+ alarm_active: false
41
39
  }, smart_context.get(node.id));
42
40
 
43
41
  // Ensure correct types
@@ -45,10 +43,13 @@ module.exports = function (RED)
45
43
  node_settings.setpoint = parseFloat(node_settings.setpoint);
46
44
  if (isNaN(node_settings.setpoint) || !isFinite(node_settings.setpoint))
47
45
  node_settings.setpoint = 20;
48
- node_settings.precision = parseInt(node_settings.precision, 10);
49
- node_settings.max_change_percent = parseInt(node_settings.max_change_percent, 10);
50
- node_settings.max_change_temp_difference = parseInt(node_settings.max_change_temp_difference, 10);
51
- node_settings.min_change_time = parseInt(node_settings.min_change_time, 10);
46
+
47
+ // Remove old settings
48
+ delete node_settings.precision;
49
+ delete node_settings.max_change_percent;
50
+ delete node_settings.max_change_temp_difference;
51
+ delete node_settings.min_change_time;
52
+
52
53
 
53
54
  // ##################
54
55
  // # Dynamic config #
@@ -57,11 +58,17 @@ module.exports = function (RED)
57
58
  let time_sampling_s = config.time_sampling;
58
59
  let output_mode = config.output_mode || OUTPUT_MODE_OPEN_CLOSE;
59
60
  let force_position = null;
61
+ let alarm_action = config.alarm_action || "NOTHING"; // NOTHING | OPEN | CLOSE
60
62
  let min_temperature = null;
61
63
  let min_temperature_position = null;
62
64
  let max_temperature = null;
63
65
  let max_temperature_position = null;
64
66
  let temp_save_date = Date.now();
67
+ let precision = parseInt(config.precision || 1, 10);
68
+ let max_change_percent = parseInt(config.max_change_percent || 2, 10);
69
+ let max_change_temp_difference = parseInt(config.max_change_temp_difference || 20, 10);
70
+ let min_change_time = parseInt(config.min_change_time || 0, 10);
71
+
65
72
 
66
73
  // ##################
67
74
  // # Runtime values #
@@ -171,6 +178,10 @@ module.exports = function (RED)
171
178
  heating_mode: node_settings.valve_mode,
172
179
  current_temperature,
173
180
  output_mode,
181
+ precision,
182
+ max_change_percent,
183
+ max_change_temp_difference,
184
+ min_change_time,
174
185
  min_temperature,
175
186
  min_temperature_position,
176
187
  max_temperature,
@@ -187,6 +198,11 @@ module.exports = function (RED)
187
198
  }
188
199
 
189
200
  node_settings.enabled = true;
201
+
202
+ // If in alarm mode, just save enabled state, but don't start changing
203
+ if (node_settings.alarm_active)
204
+ return;
205
+
190
206
  stopChanging();
191
207
 
192
208
  // Set the most probable position
@@ -233,6 +249,10 @@ module.exports = function (RED)
233
249
 
234
250
  node_settings.enabled = false;
235
251
 
252
+ // If in alarm mode, just save enabled state, but don't start changing
253
+ if (node_settings.alarm_active)
254
+ return;
255
+
236
256
  stopSampling();
237
257
  doOffMode();
238
258
  break;
@@ -307,6 +327,45 @@ module.exports = function (RED)
307
327
  calibrate();
308
328
  break;
309
329
 
330
+ case "alarm":
331
+ // Make sure it is bool
332
+ msg.payload = !!msg.payload;
333
+
334
+ // No alarm change -> nothing to do
335
+ if (node_settings.alarm_active == msg.payload)
336
+ break;
337
+
338
+ node_settings.alarm_active = msg.payload;
339
+ if (node_settings.alarm_active)
340
+ {
341
+ switch (alarm_action)
342
+ {
343
+ case "OPEN":
344
+ force_position = 100;;
345
+ break;
346
+
347
+ case "CLOSE":
348
+ force_position = 0;
349
+ break;
350
+
351
+ default:
352
+ case "NOTHING":
353
+ // Don't use alarm mode
354
+ node_settings.alarm_active = false;
355
+ return;
356
+ }
357
+ }
358
+ else
359
+ {
360
+ force_position = null;
361
+ if (!node_settings.enabled)
362
+ doOffMode();
363
+ }
364
+
365
+ stopSampling();
366
+ startSampling();
367
+ break;
368
+
310
369
  default:
311
370
  helper.warn(this, "Invalid topic: " + real_topic);
312
371
  return;
@@ -317,7 +376,7 @@ module.exports = function (RED)
317
376
 
318
377
  let startSampling = () =>
319
378
  {
320
- if (!node_settings.enabled)
379
+ if (!node_settings.enabled && !node_settings.alarm_active)
321
380
  {
322
381
  helper.log(node, "Node is disabled, cannot start sampling");
323
382
  return;
@@ -349,7 +408,7 @@ module.exports = function (RED)
349
408
  helper.log(node, "Force position to " + force_position.toFixed(1) + "%");
350
409
 
351
410
  // Under precision % difference => do nothing
352
- if (Math.abs(node_settings.last_position - force_position) <= node_settings.precision)
411
+ if (Math.abs(node_settings.last_position - force_position) <= precision)
353
412
  {
354
413
  helper.log(node, "No Force position needed");
355
414
  force_position = null;
@@ -368,6 +427,7 @@ module.exports = function (RED)
368
427
  case OUTPUT_MODE_PERCENTAGE:
369
428
  // Output mode percentage
370
429
  node_settings.last_position = force_position;
430
+ force_position = null;
371
431
  node.send({ payload: node_settings.last_position });
372
432
  smart_context.set(node.id, node_settings);
373
433
  setStatus();
@@ -411,20 +471,23 @@ module.exports = function (RED)
411
471
 
412
472
  // +/- 1°C => already good enough, do nothing
413
473
  let temp_diff = Math.abs(current_temperature - node_settings.setpoint);
414
- if (temp_diff < node_settings.precision)
474
+ if (temp_diff < precision)
415
475
  {
416
- // Found a good position for the current setpoint
417
- // Update min/max temperature
418
- if (min_temperature === null || current_temperature < min_temperature)
476
+ if (!node_settings.alarm_active)
419
477
  {
420
- min_temperature = current_temperature;
421
- min_temperature_position = node_settings.last_position;
422
- }
478
+ // Found a good position for the current setpoint
479
+ // Update min/max temperature
480
+ if (min_temperature === null || current_temperature < min_temperature)
481
+ {
482
+ min_temperature = current_temperature;
483
+ min_temperature_position = node_settings.last_position;
484
+ }
423
485
 
424
- if (max_temperature === null || current_temperature > max_temperature)
425
- {
426
- max_temperature = current_temperature;
427
- max_temperature_position = node_settings.last_position;
486
+ if (max_temperature === null || current_temperature > max_temperature)
487
+ {
488
+ max_temperature = current_temperature;
489
+ max_temperature_position = node_settings.last_position;
490
+ }
428
491
  }
429
492
  return;
430
493
  }
@@ -432,11 +495,11 @@ module.exports = function (RED)
432
495
  // 0 °C diff => 0% change
433
496
  // for max_change_temp_difference (default: 20 °C) diff => max_change_percent (default: 2%) change
434
497
  let change_percentage = helper.scale(
435
- Math.min(temp_diff, node_settings.max_change_temp_difference),
498
+ Math.min(temp_diff, max_change_temp_difference),
436
499
  0,
437
- node_settings.max_change_temp_difference,
500
+ max_change_temp_difference,
438
501
  0,
439
- node_settings.max_change_percent
502
+ max_change_percent
440
503
  );
441
504
 
442
505
  // calculate direction
@@ -476,8 +539,8 @@ module.exports = function (RED)
476
539
  // Change time in ms
477
540
  let moving_time = (time_total_s * 1000 / 100) * change_percentage;
478
541
 
479
- if (moving_time < node_settings.min_change_time)
480
- moving_time = node_settings.min_change_time;
542
+ if (moving_time < min_change_time)
543
+ moving_time = min_change_time;
481
544
 
482
545
  // start moving
483
546
  startChanging(adjustAction, moving_time);
@@ -654,9 +717,9 @@ module.exports = function (RED)
654
717
  if (calibration_timeout !== null)
655
718
  node.status({ fill: "yellow", shape: "ring", text: helper.getCurrentTimeForStatus() + ": In calibration" });
656
719
  else if (changing_timeout != null)
657
- node.status({ fill: node_settings.enabled ? "green" : "red", shape: "ring", text: helper.getCurrentTimeForStatus() + ": " + (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) + "%" });
720
+ 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) + "%" });
658
721
  else
659
- node.status({ fill: node_settings.enabled ? "green" : "red", shape: "dot", text: helper.getCurrentTimeForStatus() + ": " + (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) + "%" });
722
+ 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) + "%" });
660
723
  }
661
724
 
662
725
  /**
@@ -688,10 +751,30 @@ module.exports = function (RED)
688
751
  node_settings.last_position = 0;
689
752
  }
690
753
  }
754
+ else if (node_settings.alarm_active)
755
+ {
756
+ switch (alarm_action)
757
+ {
758
+ case "OPEN":
759
+ force_position = 100;;
760
+ break;
761
+
762
+ case "CLOSE":
763
+ force_position = 0;
764
+ break;
765
+
766
+ default:
767
+ case "NOTHING":
768
+ // Don't use alarm mode
769
+ node_settings.alarm_active = false;
770
+ return;
771
+ }
772
+
773
+ startSampling();
774
+ }
691
775
  else if (node_settings.enabled)
692
776
  {
693
777
  startSampling();
694
- node.send([null, null, { payload: helper.toFixed(node_settings.last_position, 1) }]);
695
778
  }
696
779
 
697
780
  setStatus();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smart-nodes",
3
- "version": "0.5.1",
3
+ "version": "0.5.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",