node-red-contrib-huemagic 2.8.6 → 4.0.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.
Files changed (170) hide show
  1. package/CHANGELOG.md +229 -0
  2. package/README.md +807 -766
  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 -320
  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 -368
  65. package/huemagic/hue-light.html +133 -59
  66. package/huemagic/hue-light.js +551 -337
  67. package/huemagic/hue-magic.html +91 -240
  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-button.json → hue-buttons.json} +8 -8
  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-button.json → hue-buttons.json} +11 -5
  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 +11 -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-button.html +0 -119
  150. package/huemagic/hue-button.js +0 -94
  151. package/huemagic/hue-switch.html +0 -119
  152. package/huemagic/hue-switch.js +0 -113
  153. package/huemagic/hue-tap.html +0 -119
  154. package/huemagic/hue-tap.js +0 -74
  155. package/huemagic/icons/hue-button.png +0 -0
  156. package/huemagic/icons/hue-switch.png +0 -0
  157. package/huemagic/icons/hue-tap.png +0 -0
  158. package/huemagic/locales/de/hue-button.html +0 -50
  159. package/huemagic/locales/de/hue-switch.html +0 -50
  160. package/huemagic/locales/de/hue-switch.json +0 -31
  161. package/huemagic/locales/de/hue-tap.html +0 -41
  162. package/huemagic/locales/de/hue-tap.json +0 -23
  163. package/huemagic/locales/en-US/hue-button.html +0 -50
  164. package/huemagic/locales/en-US/hue-switch.html +0 -50
  165. package/huemagic/locales/en-US/hue-switch.json +0 -31
  166. package/huemagic/locales/en-US/hue-tap.html +0 -41
  167. package/huemagic/locales/en-US/hue-tap.json +0 -23
  168. package/utils/color.js +0 -9
  169. package/utils/messages.js +0 -658
  170. package/utils/rgb.js +0 -188
@@ -1,27 +1,34 @@
1
1
  <script type="text/x-red" data-template-name="hue-brightness">
2
2
  <div class="form-row">
3
3
  <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="hue-brightness.config.name"></span></label>
4
- <input type="text" id="node-input-name" data-i18n="[placeholder]hue-brightness.config.input-name">
4
+ <input type="text" id="node-input-name" data-i18n="[placeholder]hue-brightness.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-sun-o"></i> <span data-i18n="hue-brightness.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-temp-sensors" class="editor-button" style="position: absolute; right: 0px; top: 0px;">
16
+ <button id="node-config-input-scan-temp-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-brightness.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-brightness.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-brightness.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-brightness.config.sendinitevents-node" style="width: 100%; margin-left: 10px;"></span>
31
+ </div>
25
32
  </div>
26
33
  </script>
27
34
 
@@ -30,87 +37,161 @@
30
37
  category: 'HueMagic',
31
38
  color: '#f1c40f',
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
  },
38
- inputs: 0,
46
+ align: 'left',
47
+ icon: "hue-brightness.png",
48
+ inputs: 1,
39
49
  outputs: 1,
40
- outputLabels: function() {
41
- return this._("hue-brightness.node.output");
50
+ label: function() {
51
+ return this.name || this._("hue-brightness.node.title");
42
52
  },
43
- align: 'right',
44
- icon: "hue-brightness.png",
45
53
  paletteLabel: function() {
46
54
  return this._("hue-brightness.node.title");
47
55
  },
48
- label: function() {
49
- return this.name || this._("hue-brightness.node.title");
56
+ inputLabels: function() {
57
+ return this._("hue-brightness.node.input");
58
+ },
59
+ outputLabels: function() {
60
+ return this._("hue-brightness.node.output");
50
61
  },
51
62
  oneditprepare: function()
52
63
  {
53
- var scope = this;
64
+ const scope = this;
65
+ let options = [];
54
66
 
55
- function manualLightSensorID()
67
+ function manualInput()
56
68
  {
69
+ // GET CURRENT SELECTED VALUE
57
70
  var current = $('#node-input-sensorid').val();
58
- $('#node-input-sensorid').replaceWith('<input type="text" id="node-input-sensorid" style="width: 100%"/>');
59
- $('#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-temp-sensors");
80
+ var buttonIcon = button.find("i");
81
+ buttonIcon.removeClass("fa-pencil");
82
+ buttonIcon.addClass("fa-search");
60
83
  }
61
84
 
62
- function searchAndSelectLightSensorID()
85
+ function searchAndSelect()
63
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
64
92
  var current = $('#node-input-sensorid').val();
65
- $('#node-input-sensorid').replaceWith('<select id="node-input-sensorid" style="width: 100%"></select>');
66
- $('#node-input-sensorid').append('<option selected="selected" value="null">'+scope._("hue-brightness.config.searching")+'</option>');
67
93
 
68
- var bridgeConfig = RED.nodes.node($('#node-input-bridge option:selected').val());
69
- $.get('hue/sensors', {bridge: bridgeConfig.bridge, key: bridgeConfig.key, type: "ZLLLightLevel"})
70
- .done( function(data) {
71
- var lightSensors = JSON.parse(data);
94
+ // TRIGGER SEARCHING NOTIFICATION
95
+ var notification = RED.notify(scope._("hue-brightness.config.searching"), { type: "compact", modal: true, fixed: true });
72
96
 
73
- if(lightSensors.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)
74
102
  {
75
- RED.notify(scope._("hue-brightness.config.none-found"), "error");
103
+ notification.close();
104
+ RED.notify(scope._("hue-brightness.config.none-found"), { type: "light_level" });
105
+ return false;
76
106
  }
77
107
 
78
- // RESET OPTIONS
79
- $('#node-input-sensorid').empty();
80
-
81
- // SET TEMPERATURE SENSORS AS OPTIONS
82
- lightSensors.forEach(function(sensor)
108
+ // SET OPTIONS
109
+ allRessources.forEach(function(ressource)
83
110
  {
84
- $('#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
+ }
85
119
  });
86
120
 
87
121
  // SELECT CURRENT VALUE
88
- $('#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-temp-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();
89
139
  })
90
140
  .fail(function()
91
141
  {
142
+ notification.close();
92
143
  RED.notify(scope._("hue-brightness.config.unknown-error"), "error");
93
144
  });
94
145
  }
95
146
 
96
- $(document).on('change', '#node-input-sensorid', function()
147
+ // CHANGED SENSOR ID? -> REPLACE NAME (IF POSSIBLE)
148
+ $(document).on('change', '#node-input-sensorid', function(e)
97
149
  {
98
- var sensorName = $('#node-input-sensorid option:selected').text();
99
- 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)
100
154
  {
101
- $('#node-input-name').val(sensorName);
155
+ $('#node-input-name').val(currentSelectedOptionValue.split(" (")[0]);
102
156
  }
103
157
  });
104
158
 
159
+ // TOGGLE SELECT/INPUT FIELD
105
160
  $('#node-config-input-scan-temp-sensors').click(function()
106
161
  {
107
- if($('#node-input-sensorid').prop("tagName") === "INPUT")
162
+ if($('#input-select-toggle').find(".red-ui-typedInput-container").length > 0)
108
163
  {
109
- searchAndSelectLightSensorID();
110
- } else {
111
- manualLightSensorID();
164
+ manualInput();
165
+ }
166
+ else
167
+ {
168
+ searchAndSelect();
112
169
  }
113
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-brightness.node.statusmsg"), { type: "success", id: "status", timeout: 2000 });
191
+ }
192
+ });
193
+ }
194
+ }
114
195
  }
115
196
  });
116
197
  </script>
@@ -6,70 +6,166 @@ module.exports = function(RED)
6
6
  {
7
7
  RED.nodes.createNode(this, config);
8
8
 
9
- var scope = this;
10
- let bridge = RED.nodes.getNode(config.bridge);
11
- let { HueBrightnessMessage } = require('../utils/messages');
9
+ const scope = this;
10
+ const bridge = RED.nodes.getNode(config.bridge);
12
11
 
13
- // SAVE LAST STATE
14
- var lastState = false;
12
+ // SAVE LAST COMMAND
13
+ this.lastCommand = null;
15
14
 
16
15
  //
17
16
  // CHECK CONFIG
18
- if(!config.sensorid || bridge == null)
17
+ if(bridge == null)
19
18
  {
20
19
  this.status({fill: "red", shape: "ring", text: "hue-brightness.node.not-configured"});
21
20
  return false;
22
21
  }
23
22
 
23
+ //
24
+ // UNIVERSAL MODE?
25
+ if(!config.sensorid)
26
+ {
27
+ this.status({fill: "grey", shape: "dot", text: "hue-brightness.node.universal"});
28
+ }
29
+
24
30
  //
25
31
  // UPDATE STATE
26
- if(typeof bridge.disableupdates != 'undefined'||bridge.disableupdates == false)
32
+ if(typeof bridge.disableupdates != 'undefined' || bridge.disableupdates == false)
27
33
  {
28
34
  this.status({fill: "grey", shape: "dot", text: "hue-brightness.node.init"});
29
35
  }
30
36
 
31
37
  //
32
- // ON UPDATE
33
- bridge.events.on('sensor' + config.sensorid, function(sensor)
38
+ // SUBSCRIBE TO UPDATES FROM THE BRIDGE
39
+ bridge.subscribe("light_level", config.sensorid, function(info)
34
40
  {
35
- if(sensor.config.reachable == false)
36
- {
37
- scope.status({fill: "red", shape: "ring", text: "hue-brightness.node.not-reachable"});
38
- }
39
- else
41
+ let currentState = bridge.get("light_level", info.id);
42
+
43
+ // RESSOURCE FOUND?
44
+ if(currentState !== false)
40
45
  {
41
- var hueBrightness = new HueBrightnessMessage(sensor, lastState);
42
- var realLUX = hueBrightness.msg.payload.lux;
43
- if(!config.skipevents) { scope.send(hueBrightness.msg); }
46
+ // SEND MESSAGE
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
+ }
44
54
 
45
- // SAVE LAST STATE
46
- lastState = sensor;
55
+ scope.send(currentState);
47
56
 
48
- if(sensor.state.dark)
49
- {
50
- var statusMessage = RED._("hue-brightness.node.lux-dark",{lux: realLUX});
51
- scope.status({fill: "blue", shape: "dot", text: statusMessage });
57
+ // RESET LAST COMMAND
58
+ scope.lastCommand = null;
52
59
  }
53
- else if(sensor.state.daylight)
54
- {
55
- var statusMessage = RED._("hue-brightness.node.lux-daylight",{lux: realLUX});
56
- scope.status({fill: "yellow", shape: "dot", text: statusMessage });
57
- }
58
- else
60
+
61
+ // NOT IN UNIVERAL MODE? -> CHANGE UI STATES
62
+ if(config.sensorid)
59
63
  {
60
- var statusMessage = RED._("hue-brightness.node.lux",{lux: realLUX});
61
- scope.status({fill: "grey", shape: "dot", text: statusMessage });
64
+ if(currentState.payload.reachable == false)
65
+ {
66
+ scope.status({fill: "red", shape: "ring", text: "hue-brightness.node.not-reachable"});
67
+ }
68
+ else if(currentState.payload.active == true)
69
+ {
70
+ if(currentState.payload.dark)
71
+ {
72
+ var statusMessage = RED._("hue-brightness.node.lux-dark", { lux: currentState.payload.lux });
73
+ scope.status({fill: "blue", shape: "dot", text: statusMessage });
74
+ }
75
+ else if(currentState.payload.daylight)
76
+ {
77
+ var statusMessage = RED._("hue-brightness.node.lux-daylight", { lux: currentState.payload.lux });
78
+ scope.status({fill: "yellow", shape: "dot", text: statusMessage });
79
+ }
80
+ else
81
+ {
82
+ var statusMessage = RED._("hue-brightness.node.lux", { lux: currentState.payload.lux });
83
+ scope.status({fill: "grey", shape: "dot", text: statusMessage });
84
+ }
85
+ }
86
+ else if(currentState.payload.active == false)
87
+ {
88
+ scope.status({fill: "red", shape: "ring", text: "hue-brightness.node.deactivated"});
89
+ }
62
90
  }
63
91
  }
64
92
  });
65
93
 
66
94
  //
67
- // CLOSE NODE / REMOVE EVENT LISTENER
68
- this.on('close', function()
95
+ // ON COMMAND
96
+ this.on('input', function(msg, send, done)
69
97
  {
70
- bridge.events.removeAllListeners('sensor' + config.sensorid);
98
+ // REDEFINE SEND AND DONE IF NOT AVAILABLE
99
+ send = send || function() { scope.send.apply(scope,arguments); }
100
+ done = done || function() { scope.done.apply(scope,arguments); }
101
+
102
+ // SET LAST COMMAND
103
+ scope.lastCommand = msg;
104
+
105
+ // CREATE PATCH
106
+ let patchObject = {};
107
+
108
+ // DEFINE SENSOR ID & CURRENT STATE
109
+ const tempSensorID = (typeof msg.topic != 'undefined' && msg.topic.length > 0) ? msg.topic : config.sensorid;
110
+ let currentState = bridge.get("light_level", tempSensorID);
111
+
112
+ // GET CURRENT STATE
113
+ if( (typeof msg.payload != 'undefined' && typeof msg.payload.status != 'undefined') || (typeof msg.__user_inject_props__ != 'undefined' && msg.__user_inject_props__ == "status") )
114
+ {
115
+ // SET LAST COMMAND
116
+ if(scope.lastCommand !== null)
117
+ {
118
+ currentState.command = scope.lastCommand;
119
+ }
120
+
121
+ // SEND STATE
122
+ scope.send(currentState);
123
+
124
+ // RESET LAST COMMAND
125
+ scope.lastCommand = null;
126
+
127
+ if(done) { done(); }
128
+ return true;
129
+ }
130
+
131
+ // TURN ON / OFF
132
+ if((msg.payload === true || msg.payload === false) && (msg.payload !== currentState.payload.active))
133
+ {
134
+ // PREPARE PATCH
135
+ patchObject.enabled = msg.payload;
136
+ }
137
+
138
+ //
139
+ // SHOULD PATCH?
140
+ if(Object.values(patchObject).length > 0)
141
+ {
142
+ // CHANGE NODE UI STATE
143
+ if(config.sensorid)
144
+ {
145
+ scope.status({fill: "grey", shape: "ring", text: "hue-brightness.node.command"});
146
+ }
147
+
148
+ // PATCH!
149
+ bridge.patch("light_level", tempSensorID, patchObject)
150
+ .then(function() { if(done) { done(); }})
151
+ .catch(function(errors) { scope.error(errors); });
152
+ }
153
+ else
154
+ {
155
+ // SET LAST COMMAND
156
+ if(scope.lastCommand !== null)
157
+ {
158
+ currentState.command = scope.lastCommand;
159
+ }
160
+
161
+ // SEND STATE
162
+ scope.send(currentState);
163
+
164
+ // RESET LAST COMMAND
165
+ scope.lastCommand = null;
166
+ }
71
167
  });
72
168
  }
73
169
 
74
170
  RED.nodes.registerType("hue-brightness", HueBrightness);
75
- }
171
+ }
@@ -0,0 +1,197 @@
1
+ <script type="text/x-red" data-template-name="hue-buttons">
2
+ <div class="form-row">
3
+ <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="hue-buttons.config.name"></span></label>
4
+ <input type="text" id="node-input-name" data-i18n="[placeholder]hue-buttons.config.input-name" style="width: calc(100% - 105px)">
5
+ </div>
6
+ <div class="form-row">
7
+ <label for="node-input-bridge"><i class="fa fa-server"></i> Bridge</label>
8
+ <input type="text" id="node-input-bridge" style="width: calc(100% - 105px)">
9
+ </div>
10
+ <div class="form-row">
11
+ <label for="node-input-sensorid"><i class="fa fa-hand-pointer-o"></i> <span data-i18n="hue-buttons.config.button"></span></label>
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
+ </div>
16
+ <button id="node-config-input-scan-buttons-sensors" type="button" class="red-ui-button" style="margin-left: 10px;">
17
+ <i class="fa fa-search"></i>
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-buttons.config.skipevents-node" style="width: 100%; margin-left: 10px;"></span>
25
+ </div>
26
+ </div>
27
+ <div class="form-row">
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-buttons.config.sendinitevents-node" style="width: 100%; margin-left: 10px;"></span>
31
+ </div>
32
+ </div>
33
+ </script>
34
+
35
+ <script type="text/javascript">
36
+ RED.nodes.registerType('hue-buttons',{
37
+ category: 'HueMagic',
38
+ color: '#347aeb',
39
+ defaults: {
40
+ name: { value:"" },
41
+ bridge: { type: "hue-bridge", required: true },
42
+ sensorid: { value:"", required: false },
43
+ skipevents: { value: false },
44
+ initevents: { value: false }
45
+ },
46
+ align: 'left',
47
+ icon: "hue-buttons.png",
48
+ inputs: 1,
49
+ outputs: 1,
50
+ label: function() {
51
+ return this.name || this._("hue-buttons.node.title");
52
+ },
53
+ paletteLabel: function() {
54
+ return this._("hue-buttons.node.title");
55
+ },
56
+ inputLabels: function() {
57
+ return this._("hue-buttons.node.input");
58
+ },
59
+ outputLabels: function() {
60
+ return this._("hue-buttons.node.output");
61
+ },
62
+ oneditprepare: function()
63
+ {
64
+ const scope = this;
65
+ let options = [];
66
+
67
+ function manualInput()
68
+ {
69
+ // GET CURRENT SELECTED VALUE
70
+ var current = $('#node-input-sensorid').val();
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-buttons-sensors");
80
+ var buttonIcon = button.find("i");
81
+ buttonIcon.removeClass("fa-pencil");
82
+ buttonIcon.addClass("fa-search");
83
+ }
84
+
85
+ function searchAndSelect()
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
92
+ var current = $('#node-input-sensorid').val();
93
+
94
+ // TRIGGER SEARCHING NOTIFICATION
95
+ var notification = RED.notify(scope._("hue-buttons.config.searching"), { type: "compact", modal: true, fixed: true });
96
+
97
+ // GET THE SENSORS
98
+ $.get('hue/ressources', { bridge: bridgeConfig.bridge, key: bridgeConfig.key, type: "button" })
99
+ .done( function(data) {
100
+ var allRessources = JSON.parse(data);
101
+ if(allRessources.length <= 0)
102
+ {
103
+ notification.close();
104
+ RED.notify(scope._("hue-buttons.config.none-found"), { type: "error" });
105
+ return false;
106
+ }
107
+
108
+ // SET OPTIONS
109
+ allRessources.forEach(function(ressource)
110
+ {
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
+ }
119
+ });
120
+
121
+ // SELECT CURRENT VALUE
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-buttons-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();
139
+ })
140
+ .fail(function()
141
+ {
142
+ notification.close();
143
+ RED.notify(scope._("hue-buttons.config.unknown-error"), "error");
144
+ });
145
+ }
146
+
147
+ // CHANGED SENSOR ID? -> REPLACE NAME (IF POSSIBLE)
148
+ $(document).on('change', '#node-input-sensorid', function(e)
149
+ {
150
+ let currentSelectedOptionID = $(e.currentTarget).val();
151
+ let currentSelectedOptionValue = (currentSelectedOptionID.length > 0 && options[currentSelectedOptionID]) ? options[currentSelectedOptionID].label : false;
152
+
153
+ if(currentSelectedOptionValue !== false)
154
+ {
155
+ $('#node-input-name').val(currentSelectedOptionValue.split(" (")[0]);
156
+ }
157
+ });
158
+
159
+ // TOGGLE SELECT/INPUT FIELD
160
+ $('#node-config-input-scan-buttons-sensors').click(function()
161
+ {
162
+ if($('#input-select-toggle').find(".red-ui-typedInput-container").length > 0)
163
+ {
164
+ manualInput();
165
+ }
166
+ else
167
+ {
168
+ searchAndSelect();
169
+ }
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-buttons.node.statusmsg"), { type: "success", id: "status", timeout: 2000 });
191
+ }
192
+ });
193
+ }
194
+ }
195
+ }
196
+ });
197
+ </script>