zigbee-herdsman-converters 14.0.513 → 14.0.514

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.
@@ -532,6 +532,24 @@ const converters = {
532
532
  }
533
533
  }
534
534
 
535
+ // onLevel - range 0x00 to 0xff - optional
536
+ // Any value outside of MinLevel to MaxLevel, including 0xff and 0x00, is interpreted as "previous".
537
+ if (msg.data.hasOwnProperty('onLevel') && (msg.data['onLevel'] !== undefined)) {
538
+ result.level_config.on_level = Number(msg.data['onLevel']);
539
+ if (result.level_config.on_level === 255) {
540
+ result.level_config.on_level = 'previous';
541
+ }
542
+ }
543
+
544
+ // options - 8-bit map
545
+ // bit 0: ExecuteIfOff - when 0, Move commands are ignored if the device is off;
546
+ // when 1, CurrentLevel can be changed while the device is off.
547
+ // bit 1: CoupleColorTempToLevel - when 1, changes to level also change color temperature.
548
+ // (What this means is not defined, but it's most likely to be "dim to warm".)
549
+ if (msg.data.hasOwnProperty('options') && msg.data['options'] !== undefined) {
550
+ result.level_config.execute_if_off = !!(Number(msg.data['options']) & 1);
551
+ }
552
+
535
553
  if (Object.keys(result.level_config).length > 0) {
536
554
  return result;
537
555
  }
@@ -8528,6 +8546,41 @@ const converters = {
8528
8546
  return result;
8529
8547
  },
8530
8548
  },
8549
+ moes_cover: {
8550
+ cluster: 'manuSpecificTuya',
8551
+ type: ['commandDataResponse', 'commandDataReport'],
8552
+ options: [exposes.options.invert_cover()],
8553
+ convert: (model, msg, publish, options, meta) => {
8554
+ const dpValue = tuya.firstDpValue(msg, meta, 'moes_cover');
8555
+ const dp = dpValue.dp;
8556
+ const value = tuya.getDataValue(dpValue);
8557
+ let result = null;
8558
+ switch (dp) {
8559
+ case tuya.dataPoints.coverPosition: {
8560
+ const invert = !tuya.isCoverInverted(meta.device.manufacturerName) ?
8561
+ !options.invert_cover : options.invert_cover;
8562
+ const position = invert ? 100 - value : value;
8563
+ result = {position: position};
8564
+ break;
8565
+ }
8566
+ case tuya.dataPoints.state:
8567
+ result = {state: {0: 'OPEN', 1: 'STOP', 2: 'CLOSE'}[value], running: {0: true, 1: false, 2: true}[value]};
8568
+ break;
8569
+ case tuya.dataPoints.moesCoverBacklight:
8570
+ result = {backlight: {false: 'OFF', true: 'ON'}[value]};
8571
+ break;
8572
+ case tuya.dataPoints.moesCoverCalibration:
8573
+ result = {calibration: {0: 'ON', 1: 'OFF'}[value]};
8574
+ break;
8575
+ case tuya.dataPoints.moesCoverMotorReversal:
8576
+ result = {motor_reversal: {0: 'OFF', 1: 'ON'}[value]};
8577
+ break;
8578
+ default:
8579
+ meta.logger.warn(`fromZigbee.moes_cover: NOT RECOGNIZED DP ${dp} with data ${JSON.stringify(dpValue)}`);
8580
+ }
8581
+ return result;
8582
+ },
8583
+ },
8531
8584
  // #endregion
8532
8585
 
8533
8586
  // #region Ignore converters (these message dont need parsing).
@@ -535,12 +535,41 @@ const converters = {
535
535
  Object.assign(state, {current_level_startup: startUpCurrentLevelValue});
536
536
  }
537
537
 
538
+ // onLevel - range 0x00 to 0xff - optional
539
+ // Any value outside of MinLevel to MaxLevel, including 0xff and 0x00, is interpreted as "previous".
540
+ if (value.hasOwnProperty('on_level')) {
541
+ let onLevel = value.on_level;
542
+ if (typeof onLevel === 'string' && onLevel.toLowerCase() == 'previous') {
543
+ onLevel = 255;
544
+ } else {
545
+ onLevel = Number(onLevel);
546
+ }
547
+ if (onLevel > 255) onLevel = 254;
548
+ if (onLevel < 1) onLevel = 1;
549
+ await entity.write('genLevelCtrl', {onLevel}, utils.getOptions(meta.mapped, entity));
550
+ Object.assign(state, {on_level: onLevel == 255 ? 'previous' : onLevel});
551
+ }
552
+
553
+ // options - 8-bit map
554
+ // bit 0: ExecuteIfOff - when 0, Move commands are ignored if the device is off;
555
+ // when 1, CurrentLevel can be changed while the device is off.
556
+ // bit 1: CoupleColorTempToLevel - when 1, changes to level also change color temperature.
557
+ // (What this means is not defined, but it's most likely to be "dim to warm".)
558
+ if (value.hasOwnProperty('execute_if_off')) {
559
+ const executeIfOffValue = !!value.execute_if_off;
560
+ await entity.write('genLevelCtrl', {options: executeIfOffValue ? 1 : 0}, utils.getOptions(meta.mapped, entity));
561
+ Object.assign(state, {execute_if_off: executeIfOffValue});
562
+ }
563
+
538
564
  if (Object.keys(state).length > 0) {
539
565
  return {state: {level_config: state}};
540
566
  }
541
567
  },
542
568
  convertGet: async (entity, key, meta) => {
543
- for (const attribute of ['onOffTransitionTime', 'onTransitionTime', 'offTransitionTime', 'startUpCurrentLevel']) {
569
+ for (const attribute of [
570
+ 'onOffTransitionTime', 'onTransitionTime', 'offTransitionTime', 'startUpCurrentLevel',
571
+ 'onLevel', 'options',
572
+ ]) {
544
573
  try {
545
574
  await entity.read('genLevelCtrl', [attribute]);
546
575
  } catch (ex) {
@@ -7463,6 +7492,43 @@ const converters = {
7463
7492
  }
7464
7493
  },
7465
7494
  },
7495
+ moes_cover: {
7496
+ key: ['backlight', 'calibration', 'motor_reversal', 'state', 'position'],
7497
+ options: [exposes.options.invert_cover()],
7498
+ convertSet: async (entity, key, value, meta) => {
7499
+ switch (key) {
7500
+ case 'position':
7501
+ if (value >= 0 && value <= 100) {
7502
+ const invert = !tuya.isCoverInverted(meta.device.manufacturerName) ?
7503
+ !meta.options.invert_cover : meta.options.invert_cover;
7504
+ const position = invert ? 100 - value : value;
7505
+ await tuya.sendDataPointValue(entity, tuya.dataPoints.coverPosition, position);
7506
+ return {position: value};
7507
+ }
7508
+ break;
7509
+ case 'state': {
7510
+ const state = {'OPEN': 0, 'STOP': 1, 'CLOSE': 2}[value.toUpperCase()];
7511
+ await tuya.sendDataPointEnum(entity, tuya.dataPoints.state, state);
7512
+ break;
7513
+ }
7514
+ case 'backlight': {
7515
+ const backlight = value.toUpperCase() === 'ON' ? true : false;
7516
+ await tuya.sendDataPointBool(entity, tuya.dataPoints.moesCoverBacklight, backlight);
7517
+ return {backlight: value};
7518
+ }
7519
+ case 'calibration': {
7520
+ const calibration = value.toUpperCase() === 'ON' ? 0 : 1;
7521
+ await tuya.sendDataPointEnum(entity, tuya.dataPoints.moesCoverCalibration, calibration);
7522
+ break;
7523
+ }
7524
+ case 'motor_reversal': {
7525
+ const motorReversal = value.toUpperCase() === 'ON' ? 1 : 0;
7526
+ await tuya.sendDataPointEnum(entity, tuya.dataPoints.moesCoverMotorReversal, motorReversal);
7527
+ return {motor_reversal: value};
7528
+ }
7529
+ }
7530
+ },
7531
+ },
7466
7532
  // #endregion
7467
7533
 
7468
7534
  // #region Ignore converters
@@ -22,5 +22,6 @@ module.exports = [
22
22
  exposes: [e.lock(), e.battery(), e.sound_volume(),
23
23
  e.action(['zigbee_unlock', 'lock', 'rfid_unlock', 'keypad_unlock']),
24
24
  exposes.binary('auto_relock', ea.STATE_SET, true, false).withDescription('Auto relock after 7 seconds.')],
25
+ whiteLabel: [{vendor: 'Datek Wireless', model: 'EasyCode903G2.1'}],
25
26
  },
26
27
  ];
package/devices/ikea.js CHANGED
@@ -36,9 +36,12 @@ const bulbOnEvent = async (type, data, device, options, state) => {
36
36
 
37
37
  // NOTE: execute_if_off default is false
38
38
  // we only restore if true, to save unneeded network writes
39
- if (state.color_options.execute_if_off === true) {
39
+ if (state.color_options !== undefined && state.color_options.execute_if_off === true) {
40
40
  device.endpoints[0].write('lightingColorCtrl', {'options': 1});
41
41
  }
42
+ if (state.level_config !== undefined && state.level_config.execute_if_off === true) {
43
+ device.endpoints[0].write('genLevelCtrl', {'options': 1});
44
+ }
42
45
  }
43
46
  };
44
47