node-red-contrib-huemagic 2.8.2 → 4.0.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.
Files changed (165) hide show
  1. package/CHANGELOG.md +229 -0
  2. package/README.md +806 -729
  3. package/examples/Hue Bridge.json +189 -35
  4. package/examples/Hue Brightness.json +124 -14
  5. package/examples/Hue Buttons.json +88 -0
  6. package/examples/Hue Group.json +575 -63
  7. package/examples/Hue Light.json +805 -58
  8. package/examples/Hue Magic.json +69 -24
  9. package/examples/Hue Motion.json +110 -42
  10. package/examples/Hue Rules.json +105 -37
  11. package/examples/Hue Scene.json +145 -28
  12. package/examples/Hue Temperature.json +124 -14
  13. package/huemagic/animations/001-sunny.json +22 -22
  14. package/huemagic/animations/002-cloudy.json +46 -46
  15. package/huemagic/animations/003-nightsky.json +20 -20
  16. package/huemagic/animations/004-sunrise.json +54 -54
  17. package/huemagic/animations/005-sunset.json +46 -46
  18. package/huemagic/animations/006-fireplace.json +74 -74
  19. package/huemagic/animations/007-spring.json +31 -31
  20. package/huemagic/animations/008-autmn.json +23 -23
  21. package/huemagic/animations/009-winter.json +23 -23
  22. package/huemagic/animations/010-dirtyfog.json +23 -23
  23. package/huemagic/animations/011-lgbt.json +49 -50
  24. package/huemagic/animations/012-rasta.json +28 -29
  25. package/huemagic/animations/013-strobo.json +30 -31
  26. package/huemagic/animations/014-randomrainbow.json +30 -31
  27. package/huemagic/animations/015-sos.json +158 -159
  28. package/huemagic/animations/016-milkyway.json +83 -0
  29. package/huemagic/animations/017-beach.json +40 -0
  30. package/huemagic/animations/018-forest.json +43 -0
  31. package/huemagic/animations/019-christmas.json +30 -0
  32. package/huemagic/animations/020-superhero.json +56 -0
  33. package/huemagic/animations/021-neoncity.json +52 -0
  34. package/huemagic/animations/previews/001-sunny.gif +0 -0
  35. package/huemagic/animations/previews/002-cloudy.gif +0 -0
  36. package/huemagic/animations/previews/003-nightsky.gif +0 -0
  37. package/huemagic/animations/previews/004-sunrise.gif +0 -0
  38. package/huemagic/animations/previews/005-sunset.gif +0 -0
  39. package/huemagic/animations/previews/006-fireplace.gif +0 -0
  40. package/huemagic/animations/previews/007-spring.gif +0 -0
  41. package/huemagic/animations/previews/008-autmn.gif +0 -0
  42. package/huemagic/animations/previews/009-winter.gif +0 -0
  43. package/huemagic/animations/previews/010-dirtyfog.gif +0 -0
  44. package/huemagic/animations/previews/011-lgbt.gif +0 -0
  45. package/huemagic/animations/previews/012-rasta.gif +0 -0
  46. package/huemagic/animations/previews/013-strobo.gif +0 -0
  47. package/huemagic/animations/previews/014-randomrainbow.gif +0 -0
  48. package/huemagic/animations/previews/015-sos.gif +0 -0
  49. package/huemagic/animations/previews/016-milkyway.gif +0 -0
  50. package/huemagic/animations/previews/017-beach.gif +0 -0
  51. package/huemagic/animations/previews/018-forest.gif +0 -0
  52. package/huemagic/animations/previews/019-christmas.gif +0 -0
  53. package/huemagic/animations/previews/020-superhero.gif +0 -0
  54. package/huemagic/animations/previews/021-neoncity.gif +0 -0
  55. package/huemagic/hue-bridge-config.html +105 -61
  56. package/huemagic/hue-bridge-config.js +629 -319
  57. package/huemagic/hue-bridge.html +41 -21
  58. package/huemagic/hue-bridge.js +191 -398
  59. package/huemagic/hue-brightness.html +130 -49
  60. package/huemagic/hue-brightness.js +131 -35
  61. package/huemagic/hue-buttons.html +197 -0
  62. package/huemagic/hue-buttons.js +152 -0
  63. package/huemagic/hue-group.html +137 -60
  64. package/huemagic/hue-group.js +394 -367
  65. package/huemagic/hue-light.html +133 -59
  66. package/huemagic/hue-light.js +551 -336
  67. package/huemagic/hue-magic.html +91 -237
  68. package/huemagic/hue-magic.js +57 -27
  69. package/huemagic/hue-motion.html +128 -50
  70. package/huemagic/hue-motion.js +116 -87
  71. package/huemagic/hue-rules.html +121 -50
  72. package/huemagic/hue-rules.js +84 -64
  73. package/huemagic/hue-scene.html +96 -115
  74. package/huemagic/hue-scene.js +65 -96
  75. package/huemagic/hue-temperature.html +130 -49
  76. package/huemagic/hue-temperature.js +136 -32
  77. package/huemagic/icons/hue-bridge.png +0 -0
  78. package/huemagic/icons/hue-bridge.svg +3 -0
  79. package/huemagic/icons/hue-brightness.png +0 -0
  80. package/huemagic/icons/hue-brightness.svg +11 -0
  81. package/huemagic/icons/hue-buttons.png +0 -0
  82. package/huemagic/icons/hue-buttons.svg +4 -0
  83. package/huemagic/icons/hue-group.png +0 -0
  84. package/huemagic/icons/hue-group.svg +12 -0
  85. package/huemagic/icons/hue-light.png +0 -0
  86. package/huemagic/icons/hue-light.svg +3 -0
  87. package/huemagic/icons/hue-magic.png +0 -0
  88. package/huemagic/icons/hue-magic.svg +3 -0
  89. package/huemagic/icons/hue-motion.png +0 -0
  90. package/huemagic/icons/hue-motion.svg +9 -0
  91. package/huemagic/icons/hue-rules.png +0 -0
  92. package/huemagic/icons/hue-rules.svg +4 -0
  93. package/huemagic/icons/hue-scene.png +0 -0
  94. package/huemagic/icons/hue-scene.svg +5 -0
  95. package/huemagic/icons/hue-temperature.png +0 -0
  96. package/huemagic/icons/hue-temperature.svg +7 -0
  97. package/huemagic/locales/de/hue-bridge-config.html +17 -12
  98. package/huemagic/locales/de/hue-bridge-config.json +7 -5
  99. package/huemagic/locales/de/hue-bridge.html +64 -145
  100. package/huemagic/locales/de/hue-bridge.json +6 -17
  101. package/huemagic/locales/de/hue-brightness.html +52 -38
  102. package/huemagic/locales/de/hue-brightness.json +7 -2
  103. package/huemagic/locales/de/hue-buttons.html +58 -0
  104. package/huemagic/locales/de/hue-buttons.json +28 -0
  105. package/huemagic/locales/de/hue-group.html +46 -122
  106. package/huemagic/locales/de/hue-group.json +4 -2
  107. package/huemagic/locales/de/hue-light.html +68 -116
  108. package/huemagic/locales/de/hue-light.json +5 -2
  109. package/huemagic/locales/de/hue-magic.html +65 -57
  110. package/huemagic/locales/de/hue-magic.json +2 -1
  111. package/huemagic/locales/de/hue-motion.html +48 -44
  112. package/huemagic/locales/de/hue-motion.json +6 -3
  113. package/huemagic/locales/de/hue-rules.html +68 -73
  114. package/huemagic/locales/de/hue-rules.json +5 -2
  115. package/huemagic/locales/de/hue-scene.html +23 -32
  116. package/huemagic/locales/de/hue-scene.json +5 -2
  117. package/huemagic/locales/de/hue-temperature.html +53 -36
  118. package/huemagic/locales/de/hue-temperature.json +7 -2
  119. package/huemagic/locales/en-US/hue-bridge-config.html +17 -12
  120. package/huemagic/locales/en-US/hue-bridge-config.json +5 -3
  121. package/huemagic/locales/en-US/hue-bridge.html +64 -145
  122. package/huemagic/locales/en-US/hue-bridge.json +5 -16
  123. package/huemagic/locales/en-US/hue-brightness.html +52 -38
  124. package/huemagic/locales/en-US/hue-brightness.json +10 -3
  125. package/huemagic/locales/en-US/hue-buttons.html +58 -0
  126. package/huemagic/locales/en-US/hue-buttons.json +34 -0
  127. package/huemagic/locales/en-US/hue-group.html +46 -122
  128. package/huemagic/locales/en-US/hue-group.json +7 -3
  129. package/huemagic/locales/en-US/hue-light.html +68 -116
  130. package/huemagic/locales/en-US/hue-light.json +8 -3
  131. package/huemagic/locales/en-US/hue-magic.html +65 -57
  132. package/huemagic/locales/en-US/hue-magic.json +3 -1
  133. package/huemagic/locales/en-US/hue-motion.html +48 -44
  134. package/huemagic/locales/en-US/hue-motion.json +9 -4
  135. package/huemagic/locales/en-US/hue-rules.html +68 -73
  136. package/huemagic/locales/en-US/hue-rules.json +5 -2
  137. package/huemagic/locales/en-US/hue-scene.html +23 -32
  138. package/huemagic/locales/en-US/hue-scene.json +5 -2
  139. package/huemagic/locales/en-US/hue-temperature.html +53 -36
  140. package/huemagic/locales/en-US/hue-temperature.json +10 -3
  141. package/huemagic/utils/api.js +290 -0
  142. package/huemagic/utils/color.js +382 -0
  143. package/{utils → huemagic/utils}/merge.js +9 -6
  144. package/huemagic/utils/messages.js +447 -0
  145. package/package.json +12 -12
  146. package/examples/Hue Switch.json +0 -40
  147. package/examples/Hue Tap.json +0 -40
  148. package/huemagic/assets/anime.js +0 -8
  149. package/huemagic/hue-switch.html +0 -119
  150. package/huemagic/hue-switch.js +0 -113
  151. package/huemagic/hue-tap.html +0 -119
  152. package/huemagic/hue-tap.js +0 -74
  153. package/huemagic/icons/hue-button.png +0 -0
  154. package/huemagic/icons/hue-switch.png +0 -0
  155. package/huemagic/icons/hue-tap.png +0 -0
  156. package/huemagic/locales/de/hue-switch.html +0 -50
  157. package/huemagic/locales/de/hue-switch.json +0 -31
  158. package/huemagic/locales/de/hue-tap.html +0 -41
  159. package/huemagic/locales/de/hue-tap.json +0 -23
  160. package/huemagic/locales/en-US/hue-switch.html +0 -50
  161. package/huemagic/locales/en-US/hue-switch.json +0 -31
  162. package/huemagic/locales/en-US/hue-tap.html +0 -41
  163. package/huemagic/locales/en-US/hue-tap.json +0 -23
  164. package/utils/messages.js +0 -571
  165. package/utils/rgb.js +0 -188
@@ -1,27 +1,34 @@
1
1
  <script type="text/x-red" data-template-name="hue-motion">
2
2
  <div class="form-row">
3
3
  <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="hue-motion.config.name"></span></label>
4
- <input type="text" id="node-input-name" data-i18n="[placeholder]hue-motion.config.input-name">
4
+ <input type="text" id="node-input-name" data-i18n="[placeholder]hue-motion.config.input-name" style="width: calc(100% - 105px)">
5
5
  </div>
6
6
  <div class="form-row">
7
7
  <label for="node-input-bridge"><i class="fa fa-server"></i> Bridge</label>
8
- <input type="text" id="node-input-bridge">
8
+ <input type="text" id="node-input-bridge" style="width: calc(100% - 105px)">
9
9
  </div>
10
10
  <div class="form-row">
11
11
  <label for="node-input-sensorid"><i class="fa fa-eye"></i> <span data-i18n="hue-motion.config.sensor"></span></label>
12
- <div style="display: inline-block; position: relative; width: 70%; height: 20px;">
13
- <div style="position: absolute; left: 0px; right: 40px;">
14
- <input type="text" id="node-input-sensorid" placeholder="1" style="width: 100%"/>
12
+ <div style="display: inline-flex; width: calc(100% - 105px)">
13
+ <div id="input-select-toggle" style="flex-grow: 1;">
14
+ <input type="text" id="node-input-sensorid" placeholder="00000000-0000-0000-0000-000000000000" style="width: 100%"/>
15
15
  </div>
16
- <a id="node-config-input-scan-sensors" class="editor-button" style="position: absolute; right: 0px; top: 0px;">
16
+ <button id="node-config-input-scan-sensors" type="button" class="red-ui-button" style="margin-left: 10px;">
17
17
  <i class="fa fa-search"></i>
18
- </a>
18
+ </button>
19
+ </div>
20
+ </div>
21
+ <div class="form-row" style="margin-top: 30px">
22
+ <div style="display: inline-flex; width: calc(100% - 105px)">
23
+ <input type="checkbox" id="node-input-skipevents" style="flex: 15px;">
24
+ <span data-i18n="hue-motion.config.skipevents-node" style="width: 100%; margin-left: 10px;"></span>
19
25
  </div>
20
26
  </div>
21
27
  <div class="form-row">
22
- <label for="node-input-skipevents"><i class="fa fa-sign-out"></i> <span data-i18n="hue-motion.config.skipevents"></span></label>
23
- <input type="checkbox" id="node-input-skipevents" style="display:inline-block; width:22px; vertical-align:baseline;"><span data-i18n="hue-motion.config.skipevents-node"></span>
24
- </label>
28
+ <div style="display: inline-flex; width: calc(100% - 105px)">
29
+ <input type="checkbox" id="node-input-initevents" style="flex: 15px;">
30
+ <span data-i18n="hue-motion.config.sendinitevents-node" style="width: 100%; margin-left: 10px;"></span>
31
+ </div>
25
32
  </div>
26
33
  </script>
27
34
 
@@ -30,90 +37,161 @@
30
37
  category: 'HueMagic',
31
38
  color: '#9876d3',
32
39
  defaults: {
33
- name: {value:""},
34
- bridge: {type: "hue-bridge", required: true},
35
- sensorid: {value:"", required: true, validate: RED.validators.number()},
36
- skipevents: {value: false}
40
+ name: { value:"" },
41
+ bridge: { type: "hue-bridge", required: true },
42
+ sensorid: { value:"", required: false },
43
+ skipevents: { value: false },
44
+ initevents: { value: false }
37
45
  },
46
+ align: 'left',
47
+ icon: "hue-motion.png",
38
48
  inputs: 1,
39
49
  outputs: 1,
50
+ label: function() {
51
+ return this.name || this._("hue-motion.node.title");
52
+ },
53
+ paletteLabel: function() {
54
+ return this._("hue-motion.node.title");
55
+ },
40
56
  inputLabels: function() {
41
57
  return this._("hue-motion.node.input");
42
58
  },
43
59
  outputLabels: function() {
44
60
  return this._("hue-motion.node.output");
45
61
  },
46
- align: 'right',
47
- icon: "bridge.png",
48
- paletteLabel: function() {
49
- return this._("hue-motion.node.title");
50
- },
51
- label: function() {
52
- return this.name || this._("hue-motion.node.title");
53
- },
54
62
  oneditprepare: function()
55
63
  {
56
- var scope = this;
64
+ const scope = this;
65
+ let options = [];
57
66
 
58
- function manualMotionSensorID()
67
+ function manualInput()
59
68
  {
69
+ // GET CURRENT SELECTED VALUE
60
70
  var current = $('#node-input-sensorid').val();
61
- $('#node-input-sensorid').replaceWith('<input type="text" id="node-input-sensorid" style="width: 100%"/>');
62
- $('#node-input-sensorid').val(current);
71
+
72
+ // REMOVE SELECT FIELD
73
+ $('#input-select-toggle').empty();
74
+
75
+ // CREATE NEW INPUT FIELD
76
+ $('#input-select-toggle').append('<input type="text" id="node-input-sensorid" placeholder="00000000-0000-0000-0000-000000000000" style="width: 100%" value="'+current+'" />');
77
+
78
+ // CHANGE BUTTON ICON
79
+ var button = $("#node-config-input-scan-sensors");
80
+ var buttonIcon = button.find("i");
81
+ buttonIcon.removeClass("fa-pencil");
82
+ buttonIcon.addClass("fa-search");
63
83
  }
64
84
 
65
- function searchAndSelectMotionSensor()
85
+ function searchAndSelect()
66
86
  {
87
+ // GET CURRENT BRIDGE CONFIGURATION
88
+ var bridgeConfig = RED.nodes.node($('#node-input-bridge option:selected').val());
89
+ if(!bridgeConfig) { return false; }
90
+
91
+ // GET CURRENT SELECTED VALUE
67
92
  var current = $('#node-input-sensorid').val();
68
- $('#node-input-sensorid').replaceWith('<select id="node-input-sensorid" style="width: 100%"></select>');
69
- $('#node-input-sensorid').append('<option selected="selected" value="null">'+scope._("hue-motion.config.searching")+'</option>');
70
93
 
71
- var bridgeConfig = RED.nodes.node($('#node-input-bridge option:selected').val());
72
- $.get('hue/sensors', {bridge: bridgeConfig.bridge, key: bridgeConfig.key, type: "ZLLPresence"})
73
- .done(function(data) {
74
- var motionSensors = JSON.parse(data);
94
+ // TRIGGER SEARCHING NOTIFICATION
95
+ var notification = RED.notify(scope._("hue-motion.config.searching"), { type: "compact", modal: true, fixed: true });
75
96
 
76
- if(motionSensors.length <= 0)
97
+ // GET THE SENSORS
98
+ $.get('hue/ressources', { bridge: bridgeConfig.bridge, key: bridgeConfig.key, type: "motion" })
99
+ .done( function(data) {
100
+ var allRessources = JSON.parse(data);
101
+ if(allRessources.length <= 0)
77
102
  {
78
- RED.notify(scope._("hue-motion.config.none-found"), "error");
103
+ notification.close();
104
+ RED.notify(scope._("hue-motion.config.none-found"), { type: "error" });
105
+ return false;
79
106
  }
80
107
 
81
- // RESET OPTIONS
82
- $('#node-input-sensorid').empty();
83
-
84
- // SET MOTION SENSORS AS OPTIONS
85
- motionSensors.forEach(function(sensor)
108
+ // SET OPTIONS
109
+ allRessources.forEach(function(ressource)
86
110
  {
87
- $('#node-input-sensorid').append('<option value="' + sensor.id + '">' + sensor.name + '</option>');
111
+ if(ressource.model)
112
+ {
113
+ options[ressource.id] = { value: ressource.id, label: ressource.name + " ("+ressource.model+")" };
114
+ }
115
+ else
116
+ {
117
+ options[ressource.id] = { value: ressource.id, label: ressource.name };
118
+ }
88
119
  });
89
120
 
90
121
  // SELECT CURRENT VALUE
91
- $('#node-input-sensorid').val(current);
122
+ $("#node-input-sensorid").typedInput({
123
+ types: [
124
+ {
125
+ value: current,
126
+ options: Object.values(options)
127
+ }
128
+ ]
129
+ });
130
+
131
+ // CHANGE BUTTON ICON
132
+ var button = $("#node-config-input-scan-sensors");
133
+ var buttonIcon = button.find("i");
134
+ buttonIcon.removeClass("fa-search");
135
+ buttonIcon.addClass("fa-pencil");
136
+
137
+ // CLOSE SEARCH NOTIFICATION
138
+ notification.close();
92
139
  })
93
140
  .fail(function()
94
141
  {
142
+ notification.close();
95
143
  RED.notify(scope._("hue-motion.config.unknown-error"), "error");
96
144
  });
97
145
  }
98
146
 
99
- $(document).on('change', '#node-input-sensorid', function()
147
+ // CHANGED SENSOR ID? -> REPLACE NAME (IF POSSIBLE)
148
+ $(document).on('change', '#node-input-sensorid', function(e)
100
149
  {
101
- var sensorName = $('#node-input-sensorid option:selected').text();
102
- if(sensorName.length > 0)
150
+ let currentSelectedOptionID = $(e.currentTarget).val();
151
+ let currentSelectedOptionValue = (currentSelectedOptionID.length > 0 && options[currentSelectedOptionID]) ? options[currentSelectedOptionID].label : false;
152
+
153
+ if(currentSelectedOptionValue !== false)
103
154
  {
104
- $('#node-input-name').val(sensorName);
155
+ $('#node-input-name').val(currentSelectedOptionValue.split(" (")[0]);
105
156
  }
106
157
  });
107
158
 
159
+ // TOGGLE SELECT/INPUT FIELD
108
160
  $('#node-config-input-scan-sensors').click(function()
109
161
  {
110
- if($('#node-input-sensorid').prop("tagName") === "INPUT")
162
+ if($('#input-select-toggle').find(".red-ui-typedInput-container").length > 0)
111
163
  {
112
- searchAndSelectMotionSensor();
113
- } else {
114
- manualMotionSensorID();
164
+ manualInput();
165
+ }
166
+ else
167
+ {
168
+ searchAndSelect();
115
169
  }
116
170
  });
171
+ },
172
+ button: {
173
+ enabled: function() {
174
+ return (this.sensorid && this.sensorid.length > 1)
175
+ },
176
+ visible: function() {
177
+ return (this.sensorid && this.sensorid.length > 1)
178
+ },
179
+ onclick: function()
180
+ {
181
+ const node = this;
182
+ if(node.bridge)
183
+ {
184
+ $.ajax({
185
+ url: "inject/" + node.id,
186
+ type: "POST",
187
+ data: JSON.stringify({ __user_inject_props__: "status"}),
188
+ contentType: "application/json; charset=utf-8",
189
+ success: function (resp) {
190
+ RED.notify(node.name + ": " + node._("hue-motion.node.statusmsg"), { type: "success", id: "status", timeout: 2000 });
191
+ }
192
+ });
193
+ }
194
+ }
117
195
  }
118
196
  });
119
197
  </script>
@@ -5,134 +5,163 @@ module.exports = function(RED)
5
5
  function HueMotion(config)
6
6
  {
7
7
  RED.nodes.createNode(this, config);
8
- var scope = this;
9
- let bridge = RED.nodes.getNode(config.bridge);
10
- let { HueMotionMessage } = require('../utils/messages');
11
8
 
12
- // SAVE LAST STATE
13
- var lastState = false;
9
+ const scope = this;
10
+ const bridge = RED.nodes.getNode(config.bridge);
11
+
12
+ // SAVE LAST COMMAND
13
+ this.lastCommand = null;
14
14
 
15
15
  //
16
16
  // CHECK CONFIG
17
- if(!config.sensorid || bridge == null)
17
+ if(bridge == null)
18
18
  {
19
19
  this.status({fill: "red", shape: "ring", text: "hue-motion.node.not-configured"});
20
20
  return false;
21
21
  }
22
22
 
23
+ //
24
+ // UNIVERSAL MODE?
25
+ if(!config.sensorid)
26
+ {
27
+ this.status({fill: "grey", shape: "dot", text: "hue-motion.node.universal"});
28
+ }
29
+
23
30
  //
24
31
  // UPDATE STATE
25
- scope.status({fill: "grey", shape: "dot", text: "hue-motion.node.no-motion"});
32
+ if(config.sensorid)
33
+ {
34
+ this.status({fill: "grey", shape: "dot", text: "hue-motion.node.no-motion"});
35
+ }
26
36
 
27
37
  //
28
- // ON UPDATE
29
- bridge.events.on('sensor' + config.sensorid, function(sensor)
38
+ // SUBSCRIBE TO UPDATES FROM THE BRIDGE
39
+ bridge.subscribe("motion", config.sensorid, function(info)
30
40
  {
31
- if(sensor.config.reachable == false)
32
- {
33
- // SEND STATUS
34
- scope.status({fill: "red", shape: "ring", text: "hue-motion.node.not-reachable"});
35
- }
36
- else if(sensor.config.on == true)
37
- {
38
- // SEND STATUS
39
- if(sensor.state.presence)
40
- {
41
- scope.status({fill: "green", shape: "dot", text: "hue-motion.node.motion"});
42
- }
43
- else
44
- {
45
- scope.status({fill: "grey", shape: "dot", text: "hue-motion.node.activated"});
46
- }
41
+ let currentState = bridge.get("motion", info.id);
47
42
 
43
+ // RESSOURCE FOUND?
44
+ if(currentState !== false)
45
+ {
48
46
  // SEND MESSAGE
49
- var hueMotion = new HueMotionMessage(sensor, true, lastState);
50
- if(!config.skipevents) { scope.send(hueMotion.msg); }
47
+ if(!config.skipevents && (config.initevents || info.suppressMessage == false))
48
+ {
49
+ // SET LAST COMMAND
50
+ if(scope.lastCommand !== null)
51
+ {
52
+ currentState.command = scope.lastCommand;
53
+ }
51
54
 
52
- // SAVE LAST STATE
53
- lastState = sensor;
54
- }
55
- else if(sensor.config.on == false)
56
- {
57
- // SEND STATUS
58
- scope.status({fill: "red", shape: "ring", text: "hue-motion.node.deactivated"});
55
+ // SEND STATE
56
+ scope.send(currentState);
59
57
 
60
- // SEND MESSAGE
61
- var hueMotion = new HueMotionMessage(sensor, false, lastState);
62
- if(!config.skipevents) { scope.send(hueMotion.msg); }
58
+ // RESET LAST COMMAND
59
+ scope.lastCommand = null;
60
+ }
63
61
 
64
- // SAVE LAST STATE
65
- lastState = sensor;
62
+ // NOT IN UNIVERAL MODE? -> CHANGE UI STATES
63
+ if(config.sensorid)
64
+ {
65
+ if(currentState.payload.reachable == false)
66
+ {
67
+ scope.status({fill: "red", shape: "ring", text: "hue-motion.node.not-reachable"});
68
+ }
69
+ else if(currentState.payload.active == true)
70
+ {
71
+ if(currentState.payload.motion)
72
+ {
73
+ scope.status({fill: "green", shape: "dot", text: "hue-motion.node.motion"});
74
+ }
75
+ else
76
+ {
77
+ scope.status({fill: "grey", shape: "dot", text: "hue-motion.node.activated"});
78
+ }
79
+ }
80
+ else if(currentState.payload.active == false)
81
+ {
82
+ scope.status({fill: "red", shape: "ring", text: "hue-motion.node.deactivated"});
83
+ }
84
+ }
66
85
  }
67
86
  });
68
87
 
69
-
70
88
  //
71
- // DISABLE / ENABLE SENSOR
89
+ // CONTROL SENSOR
72
90
  this.on('input', function(msg, send, done)
73
91
  {
74
- // Node-RED < 1.0
92
+ // REDEFINE SEND AND DONE IF NOT AVAILABLE
75
93
  send = send || function() { scope.send.apply(scope,arguments); }
94
+ done = done || function() { scope.done.apply(scope,arguments); }
95
+
96
+ // SAVE LAST COMMAND
97
+ scope.lastCommand = msg;
98
+
99
+ // CREATE PATCH
100
+ let patchObject = {};
101
+
102
+ // DEFINE SENSOR ID & CURRENT STATE
103
+ const tempSensorID = (msg.topic != null) ? msg.topic : config.sensorid;
104
+ let currentState = bridge.get("motion", tempSensorID);
76
105
 
77
106
  // GET CURRENT STATE
78
- if(typeof msg.payload != 'undefined' && typeof msg.payload.status != 'undefined')
107
+ if( (typeof msg.payload != 'undefined' && typeof msg.payload.status != 'undefined') || (typeof msg.__user_inject_props__ != 'undefined' && msg.__user_inject_props__ == "status") )
79
108
  {
80
- bridge.client.sensors.getById(config.sensorid)
81
- .then(sensor => {
82
- var hueMotion = new HueMotionMessage(sensor, (sensor.config.on) ? true : false, lastState);
109
+ // SET LAST COMMAND
110
+ if(scope.lastCommand !== null)
111
+ {
112
+ currentState.command = scope.lastCommand;
113
+ }
83
114
 
84
- // SAVE LAST STATE
85
- lastState = sensor;
115
+ // SEND STATE
116
+ scope.send(currentState);
86
117
 
87
- return send(hueMotion.msg);
88
- });
118
+ // RESET LAST COMMAND
119
+ scope.lastCommand = null;
89
120
 
121
+ if(done) { done(); }
90
122
  return true;
91
123
  }
92
124
 
93
- // CONTROL
94
- if(msg.payload == true || msg.payload == false)
125
+ // TURN ON / OFF
126
+ if((msg.payload === true || msg.payload === false) && (msg.payload !== currentState.payload.active))
95
127
  {
96
- bridge.client.sensors.getById(config.sensorid)
97
- .then(sensor => {
98
- sensor.config.on = msg.payload;
99
- return bridge.client.sensors.save(sensor);
100
- })
101
- .then(sensor => {
102
- var hueMotion = new HueMotionMessage(sensor, msg.payload, lastState);
103
-
104
- // SEND STATUS
105
- if(msg.payload == false)
106
- {
107
- scope.status({fill: "red", shape: "ring", text: "hue-motion.node.deactivated"});
108
- }
109
- else
110
- {
111
- scope.status({fill: "green", shape: "dot", text: "hue-motion.node.activated"});
112
- }
128
+ // PREPARE PATCH
129
+ patchObject.enabled = msg.payload;
130
+ }
113
131
 
114
- // SEND MESSAGE
115
- if(!config.skipevents) { send(hueMotion.msg); }
116
- if(done) { done(); }
117
-
118
- // SAVE LAST STATE
119
- lastState = sensor;
120
- })
121
- .catch(error => {
122
- scope.error(error, msg);
123
- if(done) { done(error); }
124
- });
132
+ //
133
+ // SHOULD PATCH?
134
+ if(Object.values(patchObject).length > 0)
135
+ {
136
+ // CHANGE NODE UI STATE
137
+ if(config.sensorid)
138
+ {
139
+ scope.status({fill: "grey", shape: "ring", text: "hue-motion.node.command"});
140
+ }
141
+
142
+ // PATCH!
143
+ bridge.patch("motion", tempSensorID, patchObject)
144
+ .then(function() { if(done) { done(); }})
145
+ .catch(function(errors) { scope.error(errors); });
125
146
  }
126
- });
147
+ else
148
+ {
149
+ // SET LAST COMMAND
150
+ if(scope.lastCommand !== null)
151
+ {
152
+ currentState.command = scope.lastCommand;
153
+ }
127
154
 
155
+ // SEND STATE
156
+ scope.send(currentState);
128
157
 
129
- //
130
- // CLOSE NODE / REMOVE EVENT LISTENER
131
- this.on('close', function()
132
- {
133
- bridge.events.removeAllListeners('sensor' + config.sensorid);
158
+ // RESET LAST COMMAND
159
+ scope.lastCommand = null;
160
+
161
+ if(done) { done(); }
162
+ }
134
163
  });
135
164
  }
136
165
 
137
166
  RED.nodes.registerType("hue-motion", HueMotion);
138
- }
167
+ }