iobroker.zigbee2mqtt 0.1.0 → 1.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.
package/lib/exposes.js CHANGED
@@ -7,6 +7,8 @@ const rgb = require('./rgb');
7
7
  const utils = require('./utils');
8
8
  const colors = require('./colors');
9
9
 
10
+ const blacklistSimulatedBrightness = ['MFKZQ01LM'];
11
+
10
12
  function genState(expose, role, name, desc) {
11
13
  let state;
12
14
  const readable = true; //expose.access > 0;
@@ -87,6 +89,7 @@ function genState(expose, role, name, desc) {
87
89
 
88
90
  for (const val of expose.values) {
89
91
  state.states[val] = val;
92
+ state.type = typeof (val);
90
93
  }
91
94
 
92
95
  if (expose.endpoint) {
@@ -118,7 +121,7 @@ function genState(expose, role, name, desc) {
118
121
  return state;
119
122
  }
120
123
 
121
- function createFromExposes(deviceID, ieee_address, definitions, power_source) {
124
+ function createFromExposes(deviceID, ieee_address, definitions, power_source, scenes, useKelvin) {
122
125
  const states = [];
123
126
  // make the different (set and get) part of state is updatable if different exposes is used for get and set
124
127
  // as example:
@@ -282,6 +285,7 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source) {
282
285
  min: 0, // ignore expose.value_min
283
286
  max: 100, // ignore expose.value_max
284
287
  inOptions: true,
288
+ unit: '%',
285
289
  getter: (value) => {
286
290
  return utils.bulbLevelToAdapterLevel(value[stateNameB]);
287
291
  },
@@ -318,10 +322,9 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source) {
318
322
  write: true,
319
323
  read: true,
320
324
  type: 'number',
321
- // Ignore min and max value, so setting mireds and Kelvin with conversion to mireds works.
322
- // https://github.com/ioBroker/ioBroker.zigbee/pull/1433#issuecomment-1113837035
323
- min: undefined,
324
- max: undefined,
325
+ min: undefined, //useKelvin == true ? expose.value_min : utils.miredKelvinConversion(expose.value_min),
326
+ max: undefined, //useKelvin == true ? expose.value_min : utils.miredKelvinConversion(expose.value_max),
327
+ unit: useKelvin == true ? 'K' : 'mired',
325
328
  setter: (value) => {
326
329
  return utils.toMired(value);
327
330
  },
@@ -330,6 +333,14 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source) {
330
333
  const transitionTime = hasTransitionTime ? options.transition_time : 0;
331
334
  return { ...options, transition: transitionTime };
332
335
  },
336
+ getter: (payload) => {
337
+ if (useKelvin == true) {
338
+ return utils.miredKelvinConversion(payload.color_temp);
339
+ }
340
+ else {
341
+ return payload.color_temp;
342
+ }
343
+ },
333
344
  epname: expose.endpoint,
334
345
  setattr: 'color_temp',
335
346
  }, prop.access);
@@ -377,163 +388,164 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source) {
377
388
  }, 2);
378
389
  break;
379
390
  }
380
- case 'color_hs': {
381
- const stateNameH = expose.endpoint ? `color_${expose.endpoint}` : 'color';
382
- pushToStates({
383
- id: stateNameH,
384
- prop: expose.endpoint ? `color_${expose.endpoint}` : 'color',
385
- name: `Color ${expose.endpoint ? expose.endpoint : ''}`.trim(),
386
- icon: undefined,
387
- role: 'level.color.rgb',
388
- write: true,
389
- read: true,
390
- type: 'string',
391
- setter: (value) => {
392
- const _rgb = colors.ParseColor(value);
393
- const hsv = rgb.rgbToHSV(_rgb.r, _rgb.g, _rgb.b, true);
394
- return {
395
- hue: Math.min(Math.max(hsv.h, 1), 359),
396
- saturation: hsv.s,
397
- // brightness: Math.floor(hsv.v * 2.55),
398
-
399
- };
400
- },
401
- setterOpt: (_value, options) => {
402
- const hasTransitionTime = options && options.hasOwnProperty('transition_time');
403
- const transitionTime = hasTransitionTime ? options.transition_time : 0;
404
- return { ...options, transition: transitionTime };
405
- },
406
- epname: expose.endpoint,
407
- setattr: 'color',
408
- }, prop.access);
409
- pushToStates({
410
- id: expose.endpoint ? `hue_${expose.endpoint}` : 'hue',
411
- prop: expose.endpoint ? `color_${expose.endpoint}` : 'color',
412
- name: `Hue ${expose.endpoint ? expose.endpoint : ''}`.trim(),
413
- icon: undefined,
414
- role: 'level.color.hue',
415
- write: true,
416
- read: false,
417
- type: 'number',
418
- min: 0,
419
- max: 360,
420
- inOptions: true,
421
- setter: (value, options) => {
422
- return {
423
- hue: value,
424
- saturation: options.saturation,
425
- };
426
- },
427
- setterOpt: (_value, options) => {
428
- const hasTransitionTime = options && options.hasOwnProperty('transition_time');
429
- const transitionTime = hasTransitionTime ? options.transition_time : 0;
430
- const hasHueCalibrationTable = options && options.hasOwnProperty('hue_calibration');
431
- if (hasHueCalibrationTable)
432
- try {
433
- return { ...options, transition: transitionTime, hue_correction: JSON.parse(options.hue_calibration) };
434
- }
435
- catch (err) {
436
- const hue_correction_table = [];
437
- options.hue_calibration.split(',').forEach(element => {
438
- const match = /([0-9]+):([0-9]+)/.exec(element);
439
- if (match && match.length == 3)
440
- hue_correction_table.push({ in: Number(match[1]), out: Number(match[2]) });
441
- });
442
- if (hue_correction_table.length > 0)
443
- return { ...options, transition: transitionTime, hue_correction: hue_correction_table };
444
- }
445
- return { ...options, transition: transitionTime };
446
- },
447
-
448
- }, prop.access);
449
- pushToStates({
450
- id: expose.endpoint ? `saturation_${expose.endpoint}` : 'saturation',
451
- prop: expose.endpoint ? `color_${expose.endpoint}` : 'color',
452
- name: `Saturation ${expose.endpoint ? expose.endpoint : ''}`.trim(),
453
- icon: undefined,
454
- role: 'level.color.saturation',
455
- write: true,
456
- read: false,
457
- type: 'number',
458
- min: 0,
459
- max: 100,
460
- inOptions: true,
461
- setter: (value, options) => {
462
- return {
463
- hue: options.hue,
464
- saturation: value,
465
- };
466
- },
467
- setterOpt: (_value, options) => {
468
- const hasTransitionTime = options && options.hasOwnProperty('transition_time');
469
- const transitionTime = hasTransitionTime ? options.transition_time : 0;
470
- const hasHueCalibrationTable = options && options.hasOwnProperty('hue_calibration');
471
- if (hasHueCalibrationTable)
472
- try {
473
- return { ...options, transition: transitionTime, hue_correction: JSON.parse(options.hue_calibration) };
474
- }
475
- catch (err) {
476
- const hue_correction_table = [];
477
- options.hue_calibration.split(',').forEach(element => {
478
- const match = /([0-9]+):([0-9]+)/.exec(element);
479
- if (match && match.length == 3)
480
- hue_correction_table.push({ in: Number(match[1]), out: Number(match[2]) });
481
- });
482
- if (hue_correction_table.length > 0)
483
- return { ...options, transition: transitionTime, hue_correction: hue_correction_table };
484
- }
485
- return { ...options, transition: transitionTime };
486
- },
487
-
488
- }, prop.access);
489
- pushToStates(statesDefs.hue_move, prop.access);
490
- pushToStates(statesDefs.saturation_move, prop.access);
491
- pushToStates({
492
- id: 'hue_calibration',
493
- prop: 'color',
494
- name: 'Hue color calibration table',
495
- icon: undefined,
496
- role: 'table',
497
- write: true,
498
- read: false,
499
- type: 'string',
500
- inOptions: true,
501
- setter: (_value, options) => {
502
- return {
503
- hue: options.hue,
504
- saturation: options.saturation,
505
- };
506
- },
507
- setterOpt: (_value, options) => {
508
- const hasTransitionTime = options && options.hasOwnProperty('transition_time');
509
- const transitionTime = hasTransitionTime ? options.transition_time : 0;
510
- const hasHueCalibrationTable = options && options.hasOwnProperty('hue_calibration');
511
- if (hasHueCalibrationTable)
512
- try {
513
- return { ...options, transition: transitionTime, hue_correction: JSON.parse(options.hue_calibration) };
514
- }
515
- catch (err) {
516
- const hue_correction_table = [];
517
- options.hue_calibration.split(',').forEach(element => {
518
- const match = /([0-9]+):([0-9]+)/.exec(element);
519
- if (match && match.length == 3)
520
- hue_correction_table.push({ in: Number(match[1]), out: Number(match[2]) });
521
- });
522
- if (hue_correction_table.length > 0)
523
- return { ...options, transition: transitionTime, hue_correction: hue_correction_table };
524
- }
525
- return { ...options, transition: transitionTime };
526
- },
527
-
528
- }, prop.access);
529
- break;
530
- }
391
+ // case 'color_hs': {
392
+ // const stateNameH = expose.endpoint ? `color_${expose.endpoint}` : 'color';
393
+ // pushToStates({
394
+ // id: stateNameH,
395
+ // prop: expose.endpoint ? `color_${expose.endpoint}` : 'color',
396
+ // name: `Color ${expose.endpoint ? expose.endpoint : ''}`.trim(),
397
+ // icon: undefined,
398
+ // role: 'level.color.rgb',
399
+ // write: true,
400
+ // read: true,
401
+ // type: 'string',
402
+ // setter: (value) => {
403
+ // const _rgb = colors.ParseColor(value);
404
+ // const hsv = rgb.rgbToHSV(_rgb.r, _rgb.g, _rgb.b, true);
405
+ // return {
406
+ // hue: Math.min(Math.max(hsv.h, 1), 359),
407
+ // saturation: hsv.s,
408
+ // // brightness: Math.floor(hsv.v * 2.55),
409
+
410
+ // };
411
+ // },
412
+ // setterOpt: (_value, options) => {
413
+ // const hasTransitionTime = options && options.hasOwnProperty('transition_time');
414
+ // const transitionTime = hasTransitionTime ? options.transition_time : 0;
415
+ // return { ...options, transition: transitionTime };
416
+ // },
417
+ // epname: expose.endpoint,
418
+ // setattr: 'color',
419
+ // }, prop.access);
420
+ // pushToStates({
421
+ // id: expose.endpoint ? `hue_${expose.endpoint}` : 'hue',
422
+ // prop: expose.endpoint ? `color_${expose.endpoint}` : 'color',
423
+ // name: `Hue ${expose.endpoint ? expose.endpoint : ''}`.trim(),
424
+ // icon: undefined,
425
+ // role: 'level.color.hue',
426
+ // write: true,
427
+ // read: false,
428
+ // type: 'number',
429
+ // min: 0,
430
+ // max: 360,
431
+ // inOptions: true,
432
+ // setter: (value, options) => {
433
+ // return {
434
+ // hue: value,
435
+ // saturation: options.saturation,
436
+ // };
437
+ // },
438
+ // setterOpt: (_value, options) => {
439
+ // const hasTransitionTime = options && options.hasOwnProperty('transition_time');
440
+ // const transitionTime = hasTransitionTime ? options.transition_time : 0;
441
+ // const hasHueCalibrationTable = options && options.hasOwnProperty('hue_calibration');
442
+ // if (hasHueCalibrationTable)
443
+ // try {
444
+ // return { ...options, transition: transitionTime, hue_correction: JSON.parse(options.hue_calibration) };
445
+ // }
446
+ // catch (err) {
447
+ // const hue_correction_table = [];
448
+ // options.hue_calibration.split(',').forEach(element => {
449
+ // const match = /([0-9]+):([0-9]+)/.exec(element);
450
+ // if (match && match.length == 3)
451
+ // hue_correction_table.push({ in: Number(match[1]), out: Number(match[2]) });
452
+ // });
453
+ // if (hue_correction_table.length > 0)
454
+ // return { ...options, transition: transitionTime, hue_correction: hue_correction_table };
455
+ // }
456
+ // return { ...options, transition: transitionTime };
457
+ // },
458
+
459
+ // }, prop.access);
460
+ // pushToStates({
461
+ // id: expose.endpoint ? `saturation_${expose.endpoint}` : 'saturation',
462
+ // prop: expose.endpoint ? `color_${expose.endpoint}` : 'color',
463
+ // name: `Saturation ${expose.endpoint ? expose.endpoint : ''}`.trim(),
464
+ // icon: undefined,
465
+ // role: 'level.color.saturation',
466
+ // write: true,
467
+ // read: false,
468
+ // type: 'number',
469
+ // min: 0,
470
+ // max: 100,
471
+ // inOptions: true,
472
+ // setter: (value, options) => {
473
+ // return {
474
+ // hue: options.hue,
475
+ // saturation: value,
476
+ // };
477
+ // },
478
+ // setterOpt: (_value, options) => {
479
+ // const hasTransitionTime = options && options.hasOwnProperty('transition_time');
480
+ // const transitionTime = hasTransitionTime ? options.transition_time : 0;
481
+ // const hasHueCalibrationTable = options && options.hasOwnProperty('hue_calibration');
482
+ // if (hasHueCalibrationTable)
483
+ // try {
484
+ // return { ...options, transition: transitionTime, hue_correction: JSON.parse(options.hue_calibration) };
485
+ // }
486
+ // catch (err) {
487
+ // const hue_correction_table = [];
488
+ // options.hue_calibration.split(',').forEach(element => {
489
+ // const match = /([0-9]+):([0-9]+)/.exec(element);
490
+ // if (match && match.length == 3)
491
+ // hue_correction_table.push({ in: Number(match[1]), out: Number(match[2]) });
492
+ // });
493
+ // if (hue_correction_table.length > 0)
494
+ // return { ...options, transition: transitionTime, hue_correction: hue_correction_table };
495
+ // }
496
+ // return { ...options, transition: transitionTime };
497
+ // },
498
+
499
+ // }, prop.access);
500
+ // pushToStates(statesDefs.hue_move, prop.access);
501
+ // pushToStates(statesDefs.saturation_move, prop.access);
502
+ // pushToStates({
503
+ // id: 'hue_calibration',
504
+ // prop: 'color',
505
+ // name: 'Hue color calibration table',
506
+ // icon: undefined,
507
+ // role: 'table',
508
+ // write: true,
509
+ // read: false,
510
+ // type: 'string',
511
+ // inOptions: true,
512
+ // setter: (_value, options) => {
513
+ // return {
514
+ // hue: options.hue,
515
+ // saturation: options.saturation,
516
+ // };
517
+ // },
518
+ // setterOpt: (_value, options) => {
519
+ // const hasTransitionTime = options && options.hasOwnProperty('transition_time');
520
+ // const transitionTime = hasTransitionTime ? options.transition_time : 0;
521
+ // const hasHueCalibrationTable = options && options.hasOwnProperty('hue_calibration');
522
+ // if (hasHueCalibrationTable)
523
+ // try {
524
+ // return { ...options, transition: transitionTime, hue_correction: JSON.parse(options.hue_calibration) };
525
+ // }
526
+ // catch (err) {
527
+ // const hue_correction_table = [];
528
+ // options.hue_calibration.split(',').forEach(element => {
529
+ // const match = /([0-9]+):([0-9]+)/.exec(element);
530
+ // if (match && match.length == 3)
531
+ // hue_correction_table.push({ in: Number(match[1]), out: Number(match[2]) });
532
+ // });
533
+ // if (hue_correction_table.length > 0)
534
+ // return { ...options, transition: transitionTime, hue_correction: hue_correction_table };
535
+ // }
536
+ // return { ...options, transition: transitionTime };
537
+ // },
538
+
539
+ // }, prop.access);
540
+ // break;
541
+ // }
531
542
  default:
532
543
  pushToStates(genState(prop), prop.access);
533
544
  break;
534
545
  }
535
546
  }
536
- pushToStates(statesDefs.transition_time, 2);
547
+ // First don't create a transition_time datapoint, this will be set in the backend
548
+ //pushToStates(statesDefs.transition_time, 2);
537
549
  break;
538
550
 
539
551
  case 'switch':
@@ -612,7 +624,6 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source) {
612
624
  if (hasHold && hasRelease && actionName.includes('release')) continue;
613
625
  // is hold state ?
614
626
  if (hasHold && hasRelease && actionName.includes('hold')) {
615
- const releaseActionName = actionName.replace('hold', 'release');
616
627
  state = {
617
628
  id: actionName.replace(/\*/g, ''),
618
629
  prop: 'action',
@@ -621,8 +632,20 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source) {
621
632
  role: 'button',
622
633
  write: false,
623
634
  read: true,
635
+ def: false,
624
636
  type: 'boolean',
625
- getter: payload => (payload.action === actionName) ? true : (payload.action === releaseActionName) ? false : undefined,
637
+ getter: (payload) => {
638
+ if (payload.action === actionName) {
639
+ return true;
640
+ }
641
+ if (payload.action === actionName.replace('hold', 'release')) {
642
+ return false;
643
+ }
644
+ if (payload.action === `${actionName}_release`) {
645
+ return false;
646
+ }
647
+ return undefined;
648
+ },
626
649
  };
627
650
  } else {
628
651
  state = {
@@ -634,12 +657,30 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source) {
634
657
  write: false,
635
658
  read: true,
636
659
  type: 'boolean',
637
- getter: payload => (payload.action === actionName) ? true : undefined,
660
+ def: false,
638
661
  isEvent: true,
662
+ getter: payload => (payload.action === actionName) ? true : undefined,
639
663
  };
640
664
  }
641
665
  pushToStates(state, expose.access);
642
666
  }
667
+ if (!blacklistSimulatedBrightness.includes(definitions.model)) {
668
+ pushToStates({
669
+ id: 'simulated_brightness',
670
+ prop: 'brightness',
671
+ name: 'Simulated brightness',
672
+ icon: undefined,
673
+ role: 'level.dimmer',
674
+ write: true,
675
+ read: true,
676
+ type: 'number',
677
+ unit: '%',
678
+ def: 0,
679
+ getter: payload => {
680
+ return utils.bulbLevelToAdapterLevel(payload.brightness);
681
+ },
682
+ }, 1);
683
+ }
643
684
  state = null;
644
685
  break;
645
686
  }
@@ -720,8 +761,13 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source) {
720
761
  case 'running_mode':
721
762
  pushToStates(statesDefs.climate_running_mode, prop.access);
722
763
  break;
723
- default:
724
- pushToStates(genState(prop), prop.access);
764
+ default: {
765
+ if (prop.name.includes('heating_setpoint')) {
766
+ pushToStates(genState(prop, 'level.temperature'), prop.access);
767
+ } else {
768
+ pushToStates(genState(prop), prop.access);
769
+ }
770
+ }
725
771
  break;
726
772
  }
727
773
  }
@@ -776,7 +822,7 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source) {
776
822
  // Add default states
777
823
  pushToStates(statesDefs.available, 1);
778
824
 
779
- const newDev = {
825
+ const newDevice = {
780
826
  id: deviceID,
781
827
  ieee_address: ieee_address,
782
828
  icon: icon,
@@ -784,14 +830,31 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source) {
784
830
  states: states,
785
831
  };
786
832
 
787
- return newDev;
833
+ // Create buttons for scenes
834
+ for (const scene of scenes) {
835
+ const sceneSate = {
836
+ id: `scene_${scene.id}`,
837
+ prop: `scene_recall`,
838
+ name: scene.name,
839
+ icon: undefined,
840
+ role: 'button',
841
+ write: true,
842
+ read: true,
843
+ type: 'boolean',
844
+ setter: (value) => (value) ? scene.id : undefined
845
+ };
846
+ // @ts-ignore
847
+ newDevice.states.push(sceneSate);
848
+ }
849
+
850
+ return newDevice;
788
851
  }
789
852
 
790
- function defineDeviceFromExposes(devices, deviceID, ieee_address, definitions, power_source) {
853
+ function defineDeviceFromExposes(devices, deviceID, ieee_address, definitions, power_source, scenes, useKelvin) {
791
854
  // if the device is already present in the cache, remove it
792
855
  utils.removeDeviceByIeee(devices, ieee_address);
793
856
  if (definitions.hasOwnProperty('exposes')) {
794
- const newDevice = createFromExposes(deviceID, ieee_address, definitions, power_source);
857
+ const newDevice = createFromExposes(deviceID, ieee_address, definitions, power_source, scenes, useKelvin);
795
858
  devices.push(newDevice);
796
859
  }
797
860
  }
@@ -0,0 +1,18 @@
1
+ async function adapterInfo(config, log) {
2
+ log.info(`Zigbee2MQTT Frontend Server: ${config.server}`);
3
+ log.info(`Zigbee2MQTT Frontend Port: ${config.port}`);
4
+ log.info(`Zigbee2MQTT Debug Log: ${config.debugLogEnabled ? 'activated' : 'deactivated'}`);
5
+ log.info(`Proxy Zigbee2MQTT Logs to ioBroker Logs: ${config.proxyZ2MLogs ? 'activated' : 'deactivated'}`);
6
+ log.info(`Use Kelvin: ${config.useKelvin ? 'yes' : 'no'}`);
7
+ }
8
+
9
+ async function zigbee2mqttInfo(payload, log) {
10
+ log.info(`Zigbee2MQTT Version: ${payload.version} `);
11
+ log.info(`Coordinator type: ${payload.coordinator.type} Version: ${payload.coordinator.meta.revision} Serial: ${payload.config.serial.port}`);
12
+ log.info(`Network panid ${payload.network.pan_id} channel: ${payload.network.channel} ext_pan_id: ${payload.network.extended_pan_id}`);
13
+ }
14
+
15
+ module.exports = {
16
+ adapterInfo: adapterInfo,
17
+ zigbee2mqttInfo: zigbee2mqttInfo,
18
+ };