@evilbunny/node-red-contrib-zigbee2mqtt 0.0.0 → 3.2.8

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 (68) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +62 -43
  3. package/api.html +22 -0
  4. package/api.js +176 -0
  5. package/examples/Basic usage.json +316 -0
  6. package/icons/homekit-logo.png +0 -0
  7. package/icons/icon-color.png +0 -0
  8. package/icons/icon.png +0 -0
  9. package/icons/icon.pxd/QuickLook/Icon.tiff +0 -0
  10. package/icons/icon.pxd/QuickLook/Thumbnail.tiff +0 -0
  11. package/icons/icon.pxd/data/15644CBE-CB2C-4054-AAB1-064FBC3F72DB +0 -0
  12. package/icons/icon.pxd/data/2D35D9CD-316A-4D5B-A1D9-1C09DB37FAC9 +0 -0
  13. package/icons/icon.pxd/data/BF7855C2-D304-4F39-84A3-141656F5E18C +0 -0
  14. package/icons/icon.pxd/data/selection/meta +33 -0
  15. package/icons/icon.pxd/data/selection/shapeSelection/meta +12 -0
  16. package/icons/icon.pxd/data/selection/shapeSelection/path +0 -0
  17. package/icons/icon.pxd/data/selectionForContentTransform/meta +33 -0
  18. package/icons/icon.pxd/data/selectionForContentTransform/shapeSelection/meta +12 -0
  19. package/icons/icon.pxd/data/selectionForContentTransform/shapeSelection/path +0 -0
  20. package/icons/icon.pxd/metadata.info +0 -0
  21. package/nodes/bridge.html +523 -0
  22. package/nodes/bridge.js +124 -0
  23. package/nodes/get.html +106 -0
  24. package/nodes/get.js +47 -0
  25. package/nodes/in.html +125 -0
  26. package/nodes/in.js +123 -0
  27. package/nodes/locales/en-US/bridge.html +23 -0
  28. package/nodes/locales/en-US/bridge.json +84 -0
  29. package/nodes/locales/en-US/get.html +19 -0
  30. package/nodes/locales/en-US/get.json +23 -0
  31. package/nodes/locales/en-US/in.html +24 -0
  32. package/nodes/locales/en-US/in.json +43 -0
  33. package/nodes/locales/en-US/out.html +24 -0
  34. package/nodes/locales/en-US/out.json +31 -0
  35. package/nodes/locales/en-US/server.html +12 -0
  36. package/nodes/locales/en-US/server.json +36 -0
  37. package/nodes/locales/sk-SK/bridge.html +23 -0
  38. package/nodes/locales/sk-SK/bridge.json +84 -0
  39. package/nodes/locales/sk-SK/get.html +18 -0
  40. package/nodes/locales/sk-SK/get.json +21 -0
  41. package/nodes/locales/sk-SK/in.html +23 -0
  42. package/nodes/locales/sk-SK/in.json +43 -0
  43. package/nodes/locales/sk-SK/out.html +23 -0
  44. package/nodes/locales/sk-SK/out.json +21 -0
  45. package/nodes/locales/sk-SK/server.html +12 -0
  46. package/nodes/locales/sk-SK/server.json +36 -0
  47. package/nodes/out.html +300 -0
  48. package/nodes/out.js +361 -0
  49. package/nodes/server.html +96 -0
  50. package/nodes/server.js +854 -0
  51. package/package.json +42 -6
  52. package/readme/1.png +0 -0
  53. package/readme/2.png +0 -0
  54. package/readme/3.png +0 -0
  55. package/readme/4.png +0 -0
  56. package/readme/5.png +0 -0
  57. package/readme/options.gif +0 -0
  58. package/resources/Zigbee2mqttHelper.js +470 -0
  59. package/resources/css/common.css +56 -0
  60. package/resources/css/multiple-select.css +183 -0
  61. package/resources/js/multiple-select.js +10 -0
  62. package/resources/js/multiple-select.min.js +10 -0
  63. package/resources/js/node-red-contrib-zigbee2mqtt-helpers.js +416 -0
  64. package/resources/js/zigbee2mqtt-helpers.js +416 -0
  65. package/resources/tokeninput/jquery.tokeninput.js +861 -0
  66. package/resources/tokeninput/token-input-facebook.css +134 -0
  67. package/resources/tokeninput/token-input-mac.css +204 -0
  68. package/resources/tokeninput/token-input.css +113 -0
@@ -0,0 +1,416 @@
1
+ class Zigbee2MqttEditor {
2
+ constructor(node, config = {}) {
3
+ this.node = node;
4
+ this.devices = null;
5
+ this.config = Object.assign( {
6
+ allow_empty:false
7
+ }, config);
8
+ this.device_id = node.device_id||null;
9
+ this.property = node.state||null;
10
+ this.optionsValue = node.optionsValue||null;
11
+ this.optionsType = node.optionsType||null;
12
+ this.refresh = false;
13
+
14
+ return this;
15
+ }
16
+
17
+ bind() {
18
+ let that = this;
19
+ that.getRefreshBtn().off('click').on('click', () => {
20
+ that.refresh = true;
21
+ that.build();
22
+ });
23
+ that.getServerInput().off('change').on('change', (e) => {
24
+ // console.log('bind: getServerInput');
25
+ that.property = null;
26
+ that.refresh = true;
27
+ that.build();
28
+ });
29
+ that.getDeviceIdInput().off('change').on('change', () => {
30
+ that.device_id = that.getDeviceIdInput().multipleSelect('getSelects', 'value');
31
+ if (!that.isMultiple()) { //no need to build for multiple
32
+ // console.log('bind: getDeviceIdInput');
33
+ that.build();
34
+ } else {
35
+ that.setFriendlyName();
36
+ }
37
+ });
38
+ if (that.getDeviceOptionsInput()) {
39
+ that.getDeviceOptionsInput().off('change').on('change', (event, type, value) => {
40
+ // console.log('bind: getDeviceOptionsInput');
41
+ that.optionsValue = value;
42
+ that.optionsType = type;
43
+ that.buildDeviceOptionsHelpBlock();
44
+ });
45
+ }
46
+ that.getEnableMultipleCheckbox().off('change').on('change', (e) => {
47
+ // that.property = null;
48
+ // that.refresh = true;
49
+ // console.log('bind: getEnableMultipleCheckbox');
50
+ that.build();
51
+ });
52
+ }
53
+
54
+ async build() {
55
+ let that = this;
56
+ // console.log('build : '+(this.refresh?'true':false));
57
+ await that.buildDeviceIdInput().then(()=>{
58
+ that.buildDevicePropertyInput();
59
+ that.buildDeviceOptionsInput();
60
+ });
61
+ that.bind();
62
+ }
63
+
64
+ async buildDeviceIdInput() {
65
+ let that = this;
66
+ that.getFilterChanges().closest('.form-row').toggle(!that.isMultiple());
67
+ // console.log('BUILD buildDeviceIdInput');
68
+
69
+ let params = {
70
+ single: !that.isMultiple(),
71
+ minimumCountSelected: !that.isMultiple()?1:0,
72
+ numberDisplayed: 1,
73
+ maxHeight: 300,
74
+ dropWidth: 320,
75
+ width: 320,
76
+ filter: true,
77
+ formatAllSelected:function(){return RED._("@evilbunny/zigbee2mqtt/server:editor.select_device")}
78
+ };
79
+ if (that.config.allow_empty && !that.isMultiple()) {
80
+ params.formatAllSelected = function(){return RED._("@evilbunny/zigbee2mqtt/server:editor.msg_topic")};
81
+ }
82
+
83
+ that.getDeviceIdInput().children().remove();
84
+ that.getDeviceIdInput().multipleSelect('destroy').multipleSelect(params).multipleSelect('disable');
85
+
86
+ let data = await that.getDevices();
87
+
88
+ if (that.config.allow_empty && !that.isMultiple()) {
89
+ that.getDeviceIdInput().html('<option value="msg.topic">msg.topic</option>');
90
+ }
91
+
92
+ let html = '';
93
+
94
+ //groups
95
+ let groups = data[1];
96
+ groups.sort(function(a, b) {
97
+ return (a.friendly_name || '').localeCompare(b.friendly_name || '', undefined, {sensitivity: 'base'});
98
+ });
99
+ if (groups.length) {
100
+ html = $('<optgroup/>', {label: RED._("@evilbunny/zigbee2mqtt/server:editor.groups")});
101
+ html.appendTo(that.getDeviceIdInput());
102
+ $.each(groups, function(index, value) {
103
+ let text = '';
104
+ if ("devices" in value && typeof (value.devices) != 'undefined' && value.devices.length > 0) {
105
+ text = ' (' + value.devices.length + ')';
106
+ }
107
+ $('<option value="' + value.id + '" data-friendly_name="' + value.friendly_name + '">' + value.friendly_name + text + '</option>')
108
+ .appendTo(html);
109
+ });
110
+ }
111
+
112
+ //devices
113
+ let devices = data[0];
114
+ devices.sort(function(a, b) {
115
+ return (a.friendly_name || '').localeCompare(b.friendly_name || '', undefined, {sensitivity: 'base'});
116
+ });
117
+ if (devices.length) {
118
+ html = $('<optgroup/>', {label: RED._("@evilbunny/zigbee2mqtt/server:editor.devices")});
119
+ html.appendTo(that.getDeviceIdInput());
120
+ $.each(devices, function(index, value) {
121
+ var model = '';
122
+ if ("definition" in value && value.definition && "model" in value.definition && typeof (value.definition.model) !== undefined) {
123
+ model = ' (' + value.definition.model + ')';
124
+ }
125
+ $('<option value="' + value.ieee_address + '" data-friendly_name="' + value.friendly_name + '">' + value.friendly_name + model + '</option>')
126
+ .appendTo(html);
127
+ });
128
+ }
129
+
130
+ that.getDeviceIdInput().multipleSelect('enable');
131
+ that.getDeviceIdInput().multipleSelect('refresh');
132
+
133
+ that.setDeviceValue();
134
+ that.setFriendlyName();
135
+ return this;
136
+ }
137
+
138
+ async buildDevicePropertyInput() {
139
+ let that = this;
140
+ if (!that.getDevicePropertyInput()) return;
141
+ that.getDevicePropertyInput().closest('.form-row').toggle(!that.isMultiple());
142
+ if (that.isMultiple()) return;
143
+
144
+ // console.log('BUILD buildDevicePropertyInput');
145
+
146
+ that.getDevicePropertyInput().children().remove();
147
+ that.getDevicePropertyInput().multipleSelect('destroy').multipleSelect({
148
+ numberDisplayed: 1,
149
+ dropWidth: 320,
150
+ width: 320,
151
+ single: !(typeof $(this).attr('multiple') !== typeof undefined && $(this).attr('multiple') !== false)
152
+ }).multipleSelect('disable');
153
+
154
+ that.getDevicePropertyInput().html('<option value="0">'+ RED._("@evilbunny/zigbee2mqtt/server:editor.complete_payload")+'</option>');
155
+
156
+ let html = '';
157
+ let device = that.getDevice();
158
+
159
+ if (device && 'definition' in device && device.definition && 'exposes' in device.definition) {
160
+ html = $('<optgroup/>', {label: RED._("@evilbunny/zigbee2mqtt/server:editor.zigbee2mqtt")});
161
+ html.appendTo(that.getDevicePropertyInput());
162
+
163
+ $.each(device.definition.exposes, function(index, value) {
164
+ if ('features' in value) {
165
+ $.each(value.features, function(index2, value2) {
166
+ if ('property' in value2) {
167
+ let endpoint = value.endpoint || value2.endpoint;
168
+ let label = value2.property + (value2.unit ? ', ' + value2.unit : '');
169
+ $('<option value="' + value2.property + '">' + label + '</option>')
170
+ .appendTo(html);
171
+ }
172
+ });
173
+ } else if ('property' in value) {
174
+ let label = value.property + (value.unit ? ', ' + value.unit : '');
175
+ $('<option value="' + value.property + '">' + label + '</option>')
176
+ .appendTo(html);
177
+ }
178
+ });
179
+ }
180
+
181
+ if (device && 'homekit' in device && device.homekit && Object.keys(device.homekit).length) {
182
+ html = $('<optgroup/>', {label: RED._("@evilbunny/zigbee2mqtt/server:editor.homekit")});
183
+ html.appendTo(that.getDevicePropertyInput());
184
+
185
+ $.each(device.homekit, function (index, value) {
186
+ $('<option value="homekit_' + index + '">' + index + '</option>').appendTo(html);
187
+ });
188
+ }
189
+ that.getDevicePropertyInput().multipleSelect('enable');
190
+ if (that.getDevicePropertyInput().find('option[value='+that.property+']').length) {
191
+ that.getDevicePropertyInput().val(that.property);
192
+ } else {
193
+ that.getDevicePropertyInput().val(that.getDevicePropertyInput().find('option').eq(0).attr('value'));
194
+ }
195
+ that.getDevicePropertyInput().multipleSelect('refresh');
196
+ }
197
+
198
+ buildLabel(name, property, unit) {
199
+ let label = name + (unit ? ', ' + unit : '');
200
+ if (property !== name) {
201
+ // e.g. property "state_l1" vs name "state" -> suffix "l1"
202
+ // or property "inching_control_1" vs name "inching_control" -> suffix "1"
203
+ let suffix = property.slice(name.length).replace(/^_/, '');
204
+ if (suffix) {
205
+ label += ' (' + suffix + ')';
206
+ }
207
+ }
208
+ return label;
209
+ }
210
+
211
+ buildDeviceOptionsInput() {
212
+ let that = this;
213
+ if (!that.getDeviceOptionsInput()) return;
214
+ that.getDeviceOptionsTypeHelpBlock().hide().find('div').text('').closest('.form-tips').find('span').text('');
215
+ that.getDeviceOptionsInput().closest('.form-row').toggle(!that.isMultiple());
216
+ if (that.isMultiple()) return;
217
+
218
+ // console.log('BUILD buildDeviceOptionsInput');
219
+ let device = that.getDevice();
220
+ let options = [];
221
+ options.push({'value': 'nothing', 'label': RED._("@evilbunny/zigbee2mqtt/server:editor.nothing"), options:['']});
222
+ options.push('msg');
223
+ options.push('json');
224
+ if (device && 'definition' in device && device.definition && 'options' in device.definition) {
225
+ $.each(device.definition.options, function(k, v) {
226
+ options.push({'value': v.property, 'label': v.name});
227
+ });
228
+ }
229
+ that.getDeviceOptionsInput().typedInput({
230
+ default: 'nothing',
231
+ value: that.optionsType,
232
+ typeField: that.getDeviceOptionsTypeInput(),
233
+ });
234
+ that.getDeviceOptionsInput().typedInput('types', options);
235
+ that.getDeviceOptionsInput().typedInput('type', that.optionsType || 'nothing');
236
+ that.getDeviceOptionsInput().typedInput('value', that.optionsValue || '');
237
+ that.buildDeviceOptionsHelpBlock();
238
+ }
239
+
240
+ buildDeviceOptionsHelpBlock() {
241
+ let that = this;
242
+ if (!that.getDeviceOptionsTypeHelpBlock()) return;
243
+
244
+ that.getDeviceOptionsTypeHelpBlock().hide().find('div').text('').closest('.form-tips').find('span').text('');
245
+ if (that.isMultiple()) return;
246
+
247
+ // console.log('BUILD buildDeviceOptionsHelpBlock');
248
+
249
+ let device = that.getDevice();
250
+ let selectedOption = null;
251
+ if (device && 'definition' in device && device.definition && 'options' in device.definition) {
252
+ $.each(device.definition.options, function(k, v) {
253
+ if ('json' === that.optionsType) {
254
+ let json = {};
255
+ $.each(device.definition.options, function(k, v2) {
256
+ if ('property' in v2) {
257
+ let defaultVal = '';
258
+ if ('type' in v2) {
259
+ if (v2.type==='numeric') {
260
+ defaultVal = 0;
261
+ if ('value_min' in v2) {
262
+ defaultVal = v2.value_min;
263
+ }
264
+ } else if (v2.type==='binary') {
265
+ defaultVal = false;
266
+ }
267
+ }
268
+ json[v2.property] = defaultVal;
269
+ }
270
+ });
271
+ selectedOption = {'name':'JSON', 'description':JSON.stringify(json, null, 4)};
272
+ return false;
273
+ }
274
+ if (v.property === that.optionsType) {
275
+ selectedOption = v;
276
+ return false;
277
+ }
278
+ });
279
+ }
280
+
281
+ if (selectedOption && 'description' in selectedOption && selectedOption.description) {
282
+ that.getDeviceOptionsTypeHelpBlock().show().find('div').text(selectedOption.name).closest('.form-tips').find('span').text(selectedOption.description);
283
+ }
284
+ }
285
+
286
+ async getDevices() {
287
+ let that = this;
288
+ if (that.devices === null || that.refresh) {
289
+ const response = await fetch('/zigbee2mqtt-eb/getDevices?' + new URLSearchParams({
290
+ controllerID: that.getServerInput().val()
291
+ }).toString(), {
292
+ method: 'GET',
293
+ cache: 'no-cache',
294
+ headers: {
295
+ 'Content-Type': 'application/json'
296
+ }
297
+ });
298
+ that.refresh = false;
299
+ that.devices = await response.json();
300
+ return that.devices;
301
+ } else {
302
+ return await new Promise(function(resolve, reject) {
303
+ resolve(that.devices);
304
+ });
305
+ }
306
+ }
307
+
308
+ getDevice() {
309
+ let that = this;
310
+ let devices = that.devices[0];
311
+ let device = null;
312
+
313
+ if (devices.length && that.device_id) {
314
+ let selectedDevice = typeof(that.device_id) === 'object' ? that.device_id[0] : that.device_id;
315
+ $.each(devices, function (index, item) {
316
+ if (item.ieee_address === selectedDevice) {
317
+ device = item;
318
+ return false;
319
+ }
320
+ });
321
+ }
322
+ return device;
323
+ }
324
+
325
+ getDeviceIdInput() {
326
+ return $('#node-input-device_id');
327
+ }
328
+
329
+ getDevicePropertyInput() {
330
+ let $elem = $('#node-input-state');
331
+ return $elem.length?$elem:null;
332
+ }
333
+
334
+ getDeviceOptionsInput() {
335
+ let $elem = $('#node-input-optionsValue');
336
+ return $elem.length?$elem:null;
337
+ }
338
+
339
+ getDeviceOptionsTypeInput() {
340
+ let $elem = $('#node-input-optionsType');
341
+ return $elem.length?$elem:null;
342
+ }
343
+
344
+ getDeviceOptionsTypeHelpBlock() {
345
+ return $('.optionsType_description');
346
+ }
347
+
348
+ getDeviceFriendlyNameInput() {
349
+ return $('#node-input-friendly_name');
350
+ }
351
+
352
+ getServerInput() {
353
+ return $('#node-input-server');
354
+ }
355
+
356
+ getRefreshBtn() {
357
+ return $('#force-refresh');
358
+ }
359
+
360
+ getFilterChanges() {
361
+ return $('#node-input-filterChanges');
362
+ }
363
+
364
+ getEnableMultipleCheckbox() {
365
+ return $('#node-input-enableMultiple');
366
+ }
367
+
368
+ isMultiple() {
369
+ return this.getEnableMultipleCheckbox().is(':checked');
370
+ }
371
+
372
+ setDeviceValue() {
373
+ let that = this;
374
+ if (that.isMultiple()) {
375
+ if (typeof(that.device_id) == 'string') {
376
+ that.device_id = [that.device_id];
377
+ }
378
+ if (that.device_id) {
379
+ that.getDeviceIdInput().multipleSelect('setSelects', that.device_id);
380
+ }
381
+ } else if (that.device_id && that.device_id.length) {
382
+ if (typeof(that.device_id) == 'object') {
383
+ that.device_id = that.device_id[0]; //get the first device
384
+ }
385
+ if (that.getDeviceIdInput().find('option[value="'+that.device_id+'"]').length) {
386
+ that.getDeviceIdInput().val(that.device_id);
387
+ }
388
+ // that.getDeviceIdInput().multipleSelect('check', that.device_id); //does not work
389
+ that.getDeviceIdInput().multipleSelect('refresh');
390
+ } else {
391
+ that.device_id = null;
392
+ }
393
+ }
394
+
395
+ setFriendlyName() {
396
+ let that = this;
397
+ if (that.isMultiple()) {
398
+ if (typeof(that.device_id) == 'string') {
399
+ that.device_id = [that.device_id];
400
+ }
401
+ if (!that.device_id) {
402
+ that.device_id = [];
403
+ }
404
+ that.getDeviceFriendlyNameInput().val(that.device_id.length + ' ' + RED._("@evilbunny/zigbee2mqtt/server:editor.selected"));
405
+ } else if (that.device_id && that.device_id.length) {
406
+ if (typeof(that.device_id) == 'object') {
407
+ that.device_id = that.device_id[0]; //get the first device
408
+ }
409
+ if (that.getDeviceIdInput().find('option[value="'+that.device_id+'"]').length) {
410
+ that.getDeviceFriendlyNameInput().val(that.getDeviceIdInput().multipleSelect('getSelects', 'text'));
411
+ }
412
+ } else {
413
+ that.getDeviceFriendlyNameInput().val('');
414
+ }
415
+ }
416
+ }