zigbee-herdsman-converters 14.0.310 → 14.0.315

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.
@@ -3539,6 +3539,157 @@ const converters = {
3539
3539
  }
3540
3540
  },
3541
3541
  },
3542
+ tvtwo_thermostat: {
3543
+ cluster: 'manuSpecificTuya',
3544
+ type: ['commandGetData', 'commandSetDataResponse'],
3545
+ convert: (model, msg, publish, options, meta) => {
3546
+ const dp = msg.data.dp;
3547
+ const value = tuya.getDataValue(msg.data.datatype, msg.data.data);
3548
+ const presetLookup = {0: 'auto', 1: 'manual', 2: 'holiday'};
3549
+ switch (dp) {
3550
+ case tuya.dataPoints.tvMode:
3551
+ return {preset: presetLookup[value]};
3552
+ case tuya.dataPoints.tvChildLock:
3553
+ return {child_lock: value ? 'LOCK' : 'UNLOCK'};
3554
+ case tuya.dataPoints.tvHolidayTemp:
3555
+ return {holiday_temperature: (value / 10).toFixed(1)};
3556
+ case tuya.dataPoints.tvHeatingSetpoint:
3557
+ return {current_heating_setpoint: (value / 10).toFixed(1)};
3558
+ case tuya.dataPoints.tvFrostDetection:
3559
+ return {frost_protection: value ? 'ON' : 'OFF'};
3560
+ case tuya.dataPoints.tvWindowDetection:
3561
+ return {window_detection: value ? 'ON' : 'OFF'};
3562
+ case tuya.dataPoints.tvHeatingStop:
3563
+ return {heating_stop: value ? 'ON' : 'OFF'};
3564
+ case tuya.dataPoints.tvLocalTemp:
3565
+ return {local_temperature: (value / 10).toFixed(1)};
3566
+ case tuya.dataPoints.tvBattery:
3567
+ return {battery_low: value === 0 ? true : false};
3568
+ case tuya.dataPoints.tvTempCalibration:
3569
+ return {local_temperature_calibration: value > 55 ?
3570
+ ((value - 0x100000000)/10).toFixed(1): (value/ 10).toFixed(1)};
3571
+ case tuya.dataPoints.tvBoostTime:
3572
+ // Setting minimum 0 - maximum 465 seconds
3573
+ return {boost_timeset_countdown: value};
3574
+ case tuya.dataPoints.tvComfortTemp:
3575
+ return {comfort_temperature: (value / 10).toFixed(1)};
3576
+ case tuya.dataPoints.tvEcoTemp:
3577
+ return {eco_temperature: (value / 10).toFixed(1)};
3578
+ case tuya.dataPoints.tvOpenWindowTemp:
3579
+ return {open_window_temperature: (value / 10).toFixed(1)};
3580
+ case tuya.dataPoints.tvErrorStatus:
3581
+ return {fault_alarm: value};
3582
+ case tuya.dataPoints.tvHolidayMode:
3583
+ return {holiday_mode_date: value};
3584
+
3585
+ case tuya.dataPoints.tvBoostMode:
3586
+ // Online ?
3587
+ return {online: value ? 'ON' : 'OFF'};
3588
+ case tuya.dataPoints.tvWorkingDay:
3589
+ // tvWorkingDay: 31,
3590
+ return {working_day: value};
3591
+ case tuya.dataPoints.tvWeekSchedule:
3592
+ // tvWeekSchedule: 106, Week select 0 - 5 days, 1 - 6 days, 2 - 7 days
3593
+ return {week_schedule: value};
3594
+
3595
+ case tuya.dataPoints.tvMondaySchedule:
3596
+ return {schedule_monday:
3597
+ ' ' + value[0] / 6 + 'h:' + value[1] + 'm ' + value[2] / 10 + '°C' +
3598
+ ', ' + value[3] / 6 + 'h:' + value[4] + 'm ' + value[5] / 10 + '°C' +
3599
+ ', ' + value[6] / 6 + 'h:' + value[7] + 'm ' + value[8] / 10 + '°C' +
3600
+ ', ' + value[9] / 6 + 'h:' + value[10] + 'm ' + value[11] / 10 + '°C' +
3601
+ ', ' + value[12] / 6 + 'h:' + value[13] + 'm ' + value[14] / 10 + '°C ' +
3602
+ ', ' + value[15] / 6 + 'h:' + value[16] + 'm ' + value[17] / 10 + '°C ' +
3603
+ ', ' + value[18] / 6 + 'h:' + value[19] + 'm ' + value[20] / 10 + '°C ' +
3604
+ ', ' + value[21] / 6 + 'h:' + value[22] + 'm ' + value[23] / 10 + '°C ' +
3605
+ ', ' + value[24] / 6 + 'h:' + value[25] + 'm ' + value[26] / 10 + '°C ' +
3606
+ ', ' + value[27] / 6 + 'h:' + value[28] + 'm ' + value[29] / 10 + '°C ',
3607
+ };
3608
+ case tuya.dataPoints.tvTuesdaySchedule:
3609
+ return {schedule_tuesday:
3610
+ ' ' + value[0] / 6 + 'h:' + value[1] + 'm ' + value[2] / 10 + '°C' +
3611
+ ', ' + value[3] / 6 + 'h:' + value[4] + 'm ' + value[5] / 10 + '°C' +
3612
+ ', ' + value[6] / 6 + 'h:' + value[7] + 'm ' + value[8] / 10 + '°C' +
3613
+ ', ' + value[9] / 6 + 'h:' + value[10] + 'm ' + value[11] / 10 + '°C' +
3614
+ ', ' + value[12] / 6 + 'h:' + value[13] + 'm ' + value[14] / 10 + '°C ' +
3615
+ ', ' + value[15] / 6 + 'h:' + value[16] + 'm ' + value[17] / 10 + '°C ' +
3616
+ ', ' + value[18] / 6 + 'h:' + value[19] + 'm ' + value[20] / 10 + '°C ' +
3617
+ ', ' + value[21] / 6 + 'h:' + value[22] + 'm ' + value[23] / 10 + '°C ' +
3618
+ ', ' + value[24] / 6 + 'h:' + value[25] + 'm ' + value[26] / 10 + '°C ' +
3619
+ ', ' + value[27] / 6 + 'h:' + value[28] + 'm ' + value[29] / 10 + '°C ',
3620
+ };
3621
+ case tuya.dataPoints.tvWednesdaySchedule:
3622
+ return {schedule_wednesday:
3623
+ ' ' + value[0] / 6 + 'h:' + value[1] + 'm ' + value[2] / 10 + '°C' +
3624
+ ', ' + value[3] / 6 + 'h:' + value[4] + 'm ' + value[5] / 10 + '°C' +
3625
+ ', ' + value[6] / 6 + 'h:' + value[7] + 'm ' + value[8] / 10 + '°C' +
3626
+ ', ' + value[9] / 6 + 'h:' + value[10] + 'm ' + value[11] / 10 + '°C' +
3627
+ ', ' + value[12] / 6 + 'h:' + value[13] + 'm ' + value[14] / 10 + '°C ' +
3628
+ ', ' + value[15] / 6 + 'h:' + value[16] + 'm ' + value[17] / 10 + '°C ' +
3629
+ ', ' + value[18] / 6 + 'h:' + value[19] + 'm ' + value[20] / 10 + '°C ' +
3630
+ ', ' + value[21] / 6 + 'h:' + value[22] + 'm ' + value[23] / 10 + '°C ' +
3631
+ ', ' + value[24] / 6 + 'h:' + value[25] + 'm ' + value[26] / 10 + '°C ' +
3632
+ ', ' + value[27] / 6 + 'h:' + value[28] + 'm ' + value[29] / 10 + '°C ',
3633
+ };
3634
+ case tuya.dataPoints.tvThursdaySchedule:
3635
+ return {schedule_thursday:
3636
+ ' ' + value[0] / 6 + 'h:' + value[1] + 'm ' + value[2] / 10 + '°C' +
3637
+ ', ' + value[3] / 6 + 'h:' + value[4] + 'm ' + value[5] / 10 + '°C' +
3638
+ ', ' + value[6] / 6 + 'h:' + value[7] + 'm ' + value[8] / 10 + '°C' +
3639
+ ', ' + value[9] / 6 + 'h:' + value[10] + 'm ' + value[11] / 10 + '°C' +
3640
+ ', ' + value[12] / 6 + 'h:' + value[13] + 'm ' + value[14] / 10 + '°C ' +
3641
+ ', ' + value[15] / 6 + 'h:' + value[16] + 'm ' + value[17] / 10 + '°C ' +
3642
+ ', ' + value[18] / 6 + 'h:' + value[19] + 'm ' + value[20] / 10 + '°C ' +
3643
+ ', ' + value[21] / 6 + 'h:' + value[22] + 'm ' + value[23] / 10 + '°C ' +
3644
+ ', ' + value[24] / 6 + 'h:' + value[25] + 'm ' + value[26] / 10 + '°C ' +
3645
+ ', ' + value[27] / 6 + 'h:' + value[28] + 'm ' + value[29] / 10 + '°C ',
3646
+ };
3647
+ case tuya.dataPoints.tvFridaySchedule:
3648
+ return {schedule_friday:
3649
+ ' ' + value[0] / 6 + 'h:' + value[1] + 'm ' + value[2] / 10 + '°C' +
3650
+ ', ' + value[3] / 6 + 'h:' + value[4] + 'm ' + value[5] / 10 + '°C' +
3651
+ ', ' + value[6] / 6 + 'h:' + value[7] + 'm ' + value[8] / 10 + '°C' +
3652
+ ', ' + value[9] / 6 + 'h:' + value[10] + 'm ' + value[11] / 10 + '°C' +
3653
+ ', ' + value[12] / 6 + 'h:' + value[13] + 'm ' + value[14] / 10 + '°C ' +
3654
+ ', ' + value[15] / 6 + 'h:' + value[16] + 'm ' + value[17] / 10 + '°C ' +
3655
+ ', ' + value[18] / 6 + 'h:' + value[19] + 'm ' + value[20] / 10 + '°C ' +
3656
+ ', ' + value[21] / 6 + 'h:' + value[22] + 'm ' + value[23] / 10 + '°C ' +
3657
+ ', ' + value[24] / 6 + 'h:' + value[25] + 'm ' + value[26] / 10 + '°C ' +
3658
+ ', ' + value[27] / 6 + 'h:' + value[28] + 'm ' + value[29] / 10 + '°C ',
3659
+ };
3660
+ case tuya.dataPoints.tvSaturdaySchedule:
3661
+ return {schedule_saturday:
3662
+ ' ' + value[0] / 6 + 'h:' + value[1] + 'm ' + value[2] / 10 + '°C' +
3663
+ ', ' + value[3] / 6 + 'h:' + value[4] + 'm ' + value[5] / 10 + '°C' +
3664
+ ', ' + value[6] / 6 + 'h:' + value[7] + 'm ' + value[8] / 10 + '°C' +
3665
+ ', ' + value[9] / 6 + 'h:' + value[10] + 'm ' + value[11] / 10 + '°C' +
3666
+ ', ' + value[12] / 6 + 'h:' + value[13] + 'm ' + value[14] / 10 + '°C ' +
3667
+ ', ' + value[15] / 6 + 'h:' + value[16] + 'm ' + value[17] / 10 + '°C ' +
3668
+ ', ' + value[18] / 6 + 'h:' + value[19] + 'm ' + value[20] / 10 + '°C ' +
3669
+ ', ' + value[21] / 6 + 'h:' + value[22] + 'm ' + value[23] / 10 + '°C ' +
3670
+ ', ' + value[24] / 6 + 'h:' + value[25] + 'm ' + value[26] / 10 + '°C ' +
3671
+ ', ' + value[27] / 6 + 'h:' + value[28] + 'm ' + value[29] / 10 + '°C ',
3672
+ };
3673
+ case tuya.dataPoints.tvSundaySchedule:
3674
+ return {schedule_sunday:
3675
+ ' ' + value[0] / 6 + 'h:' + value[1] + 'm ' + value[2] / 10 + '°C' +
3676
+ ', ' + value[3] / 6 + 'h:' + value[4] + 'm ' + value[5] / 10 + '°C' +
3677
+ ', ' + value[6] / 6 + 'h:' + value[7] + 'm ' + value[8] / 10 + '°C' +
3678
+ ', ' + value[9] / 6 + 'h:' + value[10] + 'm ' + value[11] / 10 + '°C' +
3679
+ ', ' + value[12] / 6 + 'h:' + value[13] + 'm ' + value[14] / 10 + '°C ' +
3680
+ ', ' + value[15] / 6 + 'h:' + value[16] + 'm ' + value[17] / 10 + '°C ' +
3681
+ ', ' + value[18] / 6 + 'h:' + value[19] + 'm ' + value[20] / 10 + '°C ' +
3682
+ ', ' + value[21] / 6 + 'h:' + value[22] + 'm ' + value[23] / 10 + '°C ' +
3683
+ ', ' + value[24] / 6 + 'h:' + value[25] + 'm ' + value[26] / 10 + '°C ' +
3684
+ ', ' + value[27] / 6 + 'h:' + value[28] + 'm ' + value[29] / 10 + '°C ',
3685
+ };
3686
+
3687
+ default:
3688
+ meta.logger.warn(`zigbee-herdsman-converters:tvtwo_thermostat: NOT RECOGNIZED DP #${
3689
+ dp} with data ${JSON.stringify(msg.data)}`);
3690
+ }
3691
+ },
3692
+ },
3542
3693
  haozee_thermostat: {
3543
3694
  cluster: 'manuSpecificTuya',
3544
3695
  type: ['commandGetData', 'commandSetDataResponse'],
@@ -3554,7 +3705,7 @@ const converters = {
3554
3705
  case tuya.dataPoints.haozeeLocalTemp:
3555
3706
  return {local_temperature: (value / 10).toFixed(1)};
3556
3707
  case tuya.dataPoints.haozeeBoostHeatingCountdown:
3557
- // quick heating countdown
3708
+ // quick heating countdown - not supported by this device
3558
3709
  return {boost_heating_countdown: value};
3559
3710
  case tuya.dataPoints.haozeeWindowDetection:
3560
3711
  // window check
@@ -3631,11 +3782,11 @@ const converters = {
3631
3782
  // working status 0 - pause 1 -working
3632
3783
  return {'heating': value ? 'ON' : 'OFF'};
3633
3784
  case tuya.dataPoints.haozeeBoostHeating:
3634
- // rapid heating -> boolean
3635
- break;
3785
+ // rapid heating -> boolean - not supported by this device
3786
+ return {'boost_heating': value ? 'ON' : 'OFF'};
3636
3787
  case tuya.dataPoints.haozeeTempCalibration:
3637
3788
  // temperature calibration
3638
- break;
3789
+ return {'local_temperature_calibration': ( value/10 ).toFixed(1)};
3639
3790
  case tuya.dataPoints.haozeeValvePosition:
3640
3791
  // valve position
3641
3792
  return {'position': value};
@@ -3869,32 +4020,33 @@ const converters = {
3869
4020
  minutes: value[2],
3870
4021
  },
3871
4022
  };
3872
- case tuya.dataPoints.scheduleWorkday: // set schedule for workdays [6,0,20,8,0,15,11,30,15,12,30,15,17,30,20,22,0,15]
3873
- // 6:00 - 20*, 8:00 - 15*, 11:30 - 15*, 12:30 - 15*, 17:30 - 20*, 22:00 - 15*
3874
- // Top bits in hours have special meaning
3875
- // 8: ??
3876
- // 7: Current schedule indicator
3877
- return {workdays: [
3878
- {hour: value[0] & 0x3F, minute: value[1], temperature: value[2]},
3879
- {hour: value[3] & 0x3F, minute: value[4], temperature: value[5]},
3880
- {hour: value[6] & 0x3F, minute: value[7], temperature: value[8]},
3881
- {hour: value[9] & 0x3F, minute: value[10], temperature: value[11]},
3882
- {hour: value[12] & 0x3F, minute: value[13], temperature: value[14]},
3883
- {hour: value[15] & 0x3F, minute: value[16], temperature: value[17]},
3884
- ]};
3885
- case tuya.dataPoints.scheduleHoliday: // set schedule for holidays [6,0,20,8,0,15,11,30,15,12,30,15,17,30,20,22,0,15]
4023
+ case tuya.dataPoints.scheduleWorkday: // set schedule for workdays/holidays [6,0,20,8,0,15,11,30,15,12,30,15,17,30,20,22,0,15]
4024
+ case tuya.dataPoints.scheduleHoliday: {
3886
4025
  // 6:00 - 20*, 8:00 - 15*, 11:30 - 15*, 12:30 - 15*, 17:30 - 20*, 22:00 - 15*
3887
4026
  // Top bits in hours have special meaning
3888
- // 8: ??
3889
- // 7: Current schedule indicator
3890
- return {holidays: [
3891
- {hour: value[0] & 0x3F, minute: value[1], temperature: value[2]},
3892
- {hour: value[3] & 0x3F, minute: value[4], temperature: value[5]},
3893
- {hour: value[6] & 0x3F, minute: value[7], temperature: value[8]},
3894
- {hour: value[9] & 0x3F, minute: value[10], temperature: value[11]},
3895
- {hour: value[12] & 0x3F, minute: value[13], temperature: value[14]},
3896
- {hour: value[15] & 0x3F, minute: value[16], temperature: value[17]},
3897
- ]};
4027
+ // 6: Current schedule indicator
4028
+ const items = [];
4029
+ const programmingMode = [];
4030
+
4031
+ for (let i = 0; i < 6; i++) {
4032
+ const item = {hour: value[i*3] & 0x3F, minute: value[i*3+1], temperature: value[i*3+2]};
4033
+ if (value[i*3] & 0x40) {
4034
+ item['current'] = true;
4035
+ }
4036
+
4037
+ items[i] = item;
4038
+ programmingMode[i] =
4039
+ item['hour'].toString().padStart(2, '0') + ':' +
4040
+ item['minute'].toString().padStart(2, '0') + '/' +
4041
+ item['temperature'] + '°C';
4042
+ }
4043
+
4044
+ if (dp == tuya.dataPoints.scheduleWorkday) {
4045
+ return {workdays: items, workdays_schedule: programmingMode.join(' ')};
4046
+ } else {
4047
+ return {holidays: items, holidays_schedule: programmingMode.join(' ')};
4048
+ }
4049
+ }
3898
4050
  case tuya.dataPoints.childLock:
3899
4051
  return {child_lock: value ? 'LOCK' : 'UNLOCK'};
3900
4052
  case tuya.dataPoints.siterwellWindowDetection:
@@ -5810,6 +5962,11 @@ const converters = {
5810
5962
  };
5811
5963
 
5812
5964
  const data = utf8FromStr(msg['data']['16896']);
5965
+
5966
+ clearTimeout(globalStore.getValue(msg.endpoint, 'timer'));
5967
+ const timer = setTimeout(() => publish({action: 'lock', state: 'LOCK'}), 2 * 1000);
5968
+ globalStore.putValue(msg.endpoint, 'timer', timer);
5969
+
5813
5970
  return {
5814
5971
  action: 'unlock',
5815
5972
  action_user: data[3],
@@ -5818,6 +5975,77 @@ const converters = {
5818
5975
  };
5819
5976
  },
5820
5977
  },
5978
+ javis_microwave_sensor: {
5979
+ cluster: 'manuSpecificTuya',
5980
+ type: ['commandSetDataResponse', 'commandGetData'],
5981
+ convert: (model, msg, publish, options, meta) => {
5982
+ const dp = msg.data.dp;
5983
+ const value = tuya.getDataValue(msg.data.datatype, msg.data.data);
5984
+ const lookup = {
5985
+ 0: 'no_motion',
5986
+ 1: 'big_motion',
5987
+ 2: 'minor_motion',
5988
+ 3: 'breathing',
5989
+ 4: 'abnormal_state',
5990
+ 5: 'initializing',
5991
+ 6: 'initialization_completed',
5992
+ };
5993
+ switch (dp) {
5994
+ case 1:
5995
+ return {
5996
+ states: lookup[value],
5997
+ occupancy: (0 < value && value < 5) ? true: false,
5998
+ };
5999
+ case 2:
6000
+ return {
6001
+ sensitivity: value,
6002
+ };
6003
+ case 101:
6004
+ return {
6005
+ illuminance_lux: value,
6006
+ };
6007
+ case 102:
6008
+ if (meta.device.manufacturerName === '_TZE200_kagkgk0i') {
6009
+ return {
6010
+ illuminance_calibration: value,
6011
+ };
6012
+ } else {
6013
+ return {
6014
+ keep_time: value,
6015
+ };
6016
+ }
6017
+ case 103:
6018
+ return {
6019
+ led_enable: value == 1 ? true : false,
6020
+ };
6021
+ case 104:
6022
+ return {illuminance_lux: value};
6023
+ case 105:
6024
+ return {
6025
+ illuminance_calibration: value,
6026
+ };
6027
+ case 106:
6028
+ if (meta.device.manufacturerName === '_TZE200_kagkgk0i') {
6029
+ return {
6030
+ keep_time: value,
6031
+ };
6032
+ } else {
6033
+ break;
6034
+ }
6035
+ case 107:
6036
+ if (meta.device.manufacturerName === '_TZE200_kagkgk0i') {
6037
+ return {
6038
+ led_enable: value == 1 ? true : false,
6039
+ };
6040
+ } else {
6041
+ break;
6042
+ }
6043
+ default:
6044
+ meta.logger.warn(`zigbee-herdsman-converters:javis_microwave_sensor: NOT RECOGNIZED ` +
6045
+ `DP #${dp} with data ${JSON.stringify(msg.data)}`);
6046
+ }
6047
+ },
6048
+ },
5821
6049
  diyruz_freepad_config: {
5822
6050
  cluster: 'genOnOffSwitchCfg',
5823
6051
  type: ['readResponse'],
@@ -6047,12 +6275,34 @@ const converters = {
6047
6275
  DJT11LM_vibration: {
6048
6276
  cluster: 'closuresDoorLock',
6049
6277
  type: ['attributeReport', 'readResponse'],
6278
+ options: [exposes.options.vibration_timeout()],
6050
6279
  convert: (model, msg, publish, options, meta) => {
6051
6280
  const result = {};
6052
6281
 
6053
6282
  if (msg.data['85']) {
6054
6283
  const vibrationLookup = {1: 'vibration', 2: 'tilt', 3: 'drop'};
6055
6284
  result.action = vibrationLookup[msg.data['85']];
6285
+
6286
+ // Device only sends a message when vibration is detected.
6287
+ // Therefore we need to publish a no_vibration message on our own.
6288
+ if (result.action === 'vibration') {
6289
+ result.vibration = true;
6290
+
6291
+ const timeout = options && options.hasOwnProperty('vibration_timeout') ? options.vibration_timeout : 90;
6292
+
6293
+ // Stop any existing timer cause vibration detected
6294
+ clearTimeout(globalStore.getValue(msg.endpoint, 'vibration_timer', null));
6295
+ globalStore.putValue(msg.endpoint, 'vibration_timer', null);
6296
+
6297
+ // Set new timer to publish no_vibration message
6298
+ if (timeout !== 0) {
6299
+ const timer = setTimeout(() => {
6300
+ publish({vibration: false});
6301
+ }, timeout * 1000);
6302
+
6303
+ globalStore.putValue(msg.endpoint, 'vibration_timer', timer);
6304
+ }
6305
+ }
6056
6306
  }
6057
6307
 
6058
6308
  if (msg.data['1283']) {
@@ -2735,10 +2735,79 @@ const converters = {
2735
2735
  await tuya.sendDataPointValue(entity, tuya.dataPoints.moesSminTempSet, temp);
2736
2736
  },
2737
2737
  },
2738
+ tvtwo_thermostat: {
2739
+ key: [
2740
+ 'window_detection', 'frost_protection', 'child_lock',
2741
+ 'current_heating_setpoint', 'local_temperature_calibration',
2742
+ 'holiday_temperature', 'comfort_temperature', 'eco_temperature',
2743
+ 'open_window_temperature', 'heating_stop', 'preset', 'boost_timeset_countdown',
2744
+ 'holiday_mode_date', 'working_day', 'week_schedule', 'week', 'online',
2745
+ ],
2746
+ convertSet: async (entity, key, value, meta) => {
2747
+ switch (key) {
2748
+ case 'preset': {
2749
+ const presetLookup = {'auto': 0, 'manual': 1, 'holiday': 3};
2750
+ await tuya.sendDataPointEnum(entity, tuya.dataPoints.tvMode, presetLookup[value]);
2751
+ return {state: {preset: value}};}
2752
+ case 'frost_protection':
2753
+ await tuya.sendDataPointBool(entity, tuya.dataPoints.tvFrostDetection, value === 'ON');
2754
+ break;
2755
+ case 'heating_stop':
2756
+ await tuya.sendDataPointBool(entity, tuya.dataPoints.tvHeatingStop, value === 'ON');
2757
+ break;
2758
+ case 'window_detection':
2759
+ await tuya.sendDataPointBool(entity, tuya.dataPoints.tvWindowDetection, value === 'ON');
2760
+ break;
2761
+ case 'child_lock':
2762
+ await tuya.sendDataPointBool(entity, tuya.dataPoints.tvChildLock, value === 'LOCK');
2763
+ break;
2764
+ case 'local_temperature_calibration':
2765
+ // value = Math.round(value);
2766
+ value = (value < 0) ? 0xFFFFFFFF + value + 1 : value;
2767
+ await tuya.sendDataPointValue(entity, tuya.dataPoints.tvTempCalibration, value * 10);
2768
+ break;
2769
+ case 'current_heating_setpoint':
2770
+ await tuya.sendDataPointValue(entity, tuya.dataPoints.tvHeatingSetpoint, value * 10);
2771
+ break;
2772
+ case 'holiday_temperature':
2773
+ await tuya.sendDataPointValue(entity, tuya.dataPoints.tvHolidayTemp, value * 10);
2774
+ break;
2775
+ case 'comfort_temperature':
2776
+ await tuya.sendDataPointValue(entity, tuya.dataPoints.tvComfortTemp, value * 10);
2777
+ break;
2778
+ case 'eco_temperature':
2779
+ await tuya.sendDataPointValue(entity, tuya.dataPoints.tvEcoTemp, value * 10);
2780
+ break;
2781
+ case 'boost_timeset_countdown':
2782
+ // set min 0 - max 465 sec boost time
2783
+ await tuya.sendDataPointValue(entity, tuya.dataPoints.tvBoostTime, value);
2784
+ break;
2785
+ case 'open_window_temperature':
2786
+ await tuya.sendDataPointValue(entity, tuya.dataPoints.tvOpenWindowTemp, value * 10);
2787
+ break;
2788
+ case 'holiday_mode_date':
2789
+ await tuya.sendDataPointBitmap(entity, tuya.dataPoints.tvWorkingDayTimetvHolidayMode, value);
2790
+ break;
2791
+
2792
+ case 'online':
2793
+ // 115 ????? online
2794
+ await tuya.sendDataPointBool(entity, tuya.dataPoints.tvBoostMode, value === 'ON');
2795
+ break;
2796
+ case 'week': {
2797
+ const weekLookup = {'5+2': 0, '6+1': 1, '7': 2};
2798
+ const week = weekLookup[value];
2799
+ await tuya.sendDataPointEnum(entity, tuya.dataPoints.tvWorkingDay, week);
2800
+ return {state: {week: value}};}
2801
+
2802
+ default: // Unknown key
2803
+ meta.logger.warn(`toZigbee.tvtwo_thermostat: Unhandled key ${key}`);
2804
+ }
2805
+ },
2806
+ },
2738
2807
  haozee_thermostat_system_mode: {
2739
2808
  key: ['preset'],
2740
2809
  convertSet: async (entity, key, value, meta) => {
2741
- const lookup = {0: 'auto', 1: 'manual', 2: 'off', 3: 'on'};
2810
+ const lookup = {'auto': 0, 'manual': 1, 'off': 2, 'on': 3};
2742
2811
  await tuya.sendDataPointEnum(entity, tuya.dataPoints.haozeeSystemMode, lookup[value]);
2743
2812
  },
2744
2813
  },
@@ -2776,7 +2845,7 @@ const converters = {
2776
2845
  haozee_thermostat_temperature_calibration: {
2777
2846
  key: ['local_temperature_calibration'],
2778
2847
  convertSet: async (entity, key, value, meta) => {
2779
- let temp = Math.round(value * 1);
2848
+ let temp = Math.round(value * 10);
2780
2849
  if (temp < 0) {
2781
2850
  temp = 0xFFFFFFFF + temp + 1;
2782
2851
  }
@@ -4488,6 +4557,34 @@ const converters = {
4488
4557
  }
4489
4558
  },
4490
4559
  },
4560
+ tuya_thermostat_schedule_programming_mode: { // payload example "00:20/5°C 01:20/5°C 6:59/15°C 18:00/5°C 20:00/5°C 23:30/5°C"
4561
+ key: ['workdays_schedule', 'holidays_schedule'],
4562
+ convertSet: async (entity, key, value, meta) => {
4563
+ const dpId =
4564
+ (key === 'workdays_schedule') ?
4565
+ tuya.dataPoints.scheduleWorkday :
4566
+ tuya.dataPoints.scheduleHoliday;
4567
+ const payload = [];
4568
+ const items = value.split(' ');
4569
+
4570
+ for (let i = 0; i < 6; i++) {
4571
+ const hourTemperature = items[i].split('/');
4572
+ const hourMinute = hourTemperature[0].split(':', 2);
4573
+ const hour = parseInt(hourMinute[0]);
4574
+ const minute = parseInt(hourMinute[1]);
4575
+ const temperature = parseInt(hourTemperature[1]);
4576
+
4577
+ if (hour < 0 || hour >= 24 || minute < 0 || minute >= 60 || temperature < 5 || temperature >= 35) {
4578
+ throw new Error('Invalid hour, minute or temperature of:' + items[i]);
4579
+ }
4580
+
4581
+ payload[i*3] = hour;
4582
+ payload[i*3+1] = minute;
4583
+ payload[i*3+2] = temperature;
4584
+ }
4585
+ tuya.sendDataPointRaw(entity, dpId, payload);
4586
+ },
4587
+ },
4491
4588
  tuya_thermostat_week: {
4492
4589
  key: ['week'],
4493
4590
  convertSet: async (entity, key, value, meta) => {
@@ -6011,6 +6108,46 @@ const converters = {
6011
6108
  }
6012
6109
  },
6013
6110
  },
6111
+ javis_microwave_sensor: {
6112
+ key: [
6113
+ 'illuminance_calibration', 'led_enable',
6114
+ 'sensitivity', 'keep_time',
6115
+ ],
6116
+ convertSet: async (entity, key, value, meta) => {
6117
+ switch (key) {
6118
+ case 'illuminance_calibration':// (10--100) sensor illuminance sensitivity
6119
+ if (meta.device.manufacturerName === '_TZE200_kagkgk0i') {
6120
+ await tuya.sendDataPointRaw(entity, 102, [value]);
6121
+ break;
6122
+ } else {
6123
+ tuya.sendDataPointRaw(entity, 105, [value]);
6124
+ break;
6125
+ }
6126
+ case 'led_enable':// OK (value true/false or 1/0)
6127
+ if (meta.device.manufacturerName === '_TZE200_kagkgk0i') {
6128
+ await tuya.sendDataPointRaw(entity, 107, [value ? 1 : 0]);
6129
+ break;
6130
+ } else {
6131
+ await tuya.sendDataPointRaw(entity, 103, [value ? 1 : 0]);
6132
+ break;
6133
+ }
6134
+
6135
+ case 'sensitivity':// value: 25, 50, 75, 100
6136
+ await tuya.sendDataPointRaw(entity, 2, [value]);
6137
+ break;
6138
+ case 'keep_time': // value 0 --> 7 corresponding 5s, 30s, 1, 3, 5, 10, 20, 30 min
6139
+ if (meta.device.manufacturerName === '_TZE200_kagkgk0i') {
6140
+ await tuya.sendDataPointRaw(entity, 106, [value]);
6141
+ break;
6142
+ } else {
6143
+ await tuya.sendDataPointRaw(entity, 102, [value]);
6144
+ break;
6145
+ }
6146
+ default: // Unknown key
6147
+ throw new Error(`Unhandled key ${key}`);
6148
+ }
6149
+ },
6150
+ },
6014
6151
  moes_thermostat_tv: {
6015
6152
  key: [
6016
6153
  'system_mode', 'window_detection', 'frost_detection', 'child_lock',
package/devices/candeo.js CHANGED
@@ -13,7 +13,12 @@ module.exports = [
13
13
  const endpoint = device.getEndpoint(1);
14
14
  await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'genLevelCtrl']);
15
15
  await reporting.onOff(endpoint);
16
- await reporting.brightness(endpoint);
16
+
17
+ // The default reporting from the Candeo dimmer can result in a lot of Zigbee traffic
18
+ // to the extent that reported brighness values can arrive at the endpoint out of order
19
+ // giving the appearance that the values are jumping around.
20
+ // Limit the reporting to once a second to give a smoother reporting of brightness.
21
+ await reporting.brightness(endpoint, {min: 1});
17
22
  },
18
23
  },
19
24
  ];
@@ -1,6 +1,6 @@
1
1
  const reporting = require('../lib/reporting');
2
2
  const extend = require('../lib/extend');
3
- const exposes = require('zigbee-herdsman-converters/lib/exposes');
3
+ const exposes = require('../lib/exposes');
4
4
  const e = exposes.presets;
5
5
 
6
6
  module.exports = [
package/devices/hive.js CHANGED
@@ -332,6 +332,37 @@ module.exports = [
332
332
  await reporting.thermostatTemperatureSetpointHoldDuration(endpoint);
333
333
  },
334
334
  },
335
+ {
336
+ zigbeeModel: ['SLR1c'],
337
+ model: 'SLR1c',
338
+ vendor: 'Hive',
339
+ description: 'Heating thermostat',
340
+ fromZigbee: [fz.thermostat, fz.thermostat_weekly_schedule],
341
+ toZigbee: [tz.thermostat_local_temperature, tz.thermostat_system_mode, tz.thermostat_running_state,
342
+ tz.thermostat_occupied_heating_setpoint, tz.thermostat_control_sequence_of_operation, tz.thermostat_weekly_schedule,
343
+ tz.thermostat_clear_weekly_schedule, tz.thermostat_temperature_setpoint_hold, tz.thermostat_temperature_setpoint_hold_duration],
344
+ exposes: [
345
+ exposes.climate().withSetpoint('occupied_heating_setpoint', 5, 32, 0.5).withLocalTemperature()
346
+ .withSystemMode(['off', 'auto', 'heat']).withRunningState(['idle', 'heat']),
347
+ exposes.binary('temperature_setpoint_hold', ea.ALL, true, false)
348
+ .withDescription('Prevent changes. `false` = run normally. `true` = prevent from making changes.' +
349
+ ' Must be set to `false` when system_mode = off or `true` for heat'),
350
+ exposes.numeric('temperature_setpoint_hold_duration', ea.ALL).withValueMin(0).withValueMax(65535)
351
+ .withDescription('Period in minutes for which the setpoint hold will be active. 65535 = attribute not' +
352
+ ' used. 0 to 360 to match the remote display')],
353
+ meta: {disableDefaultResponse: true},
354
+ configure: async (device, coordinatorEndpoint, logger) => {
355
+ const endpoint = device.getEndpoint(5);
356
+ const binds = ['genBasic', 'genIdentify', 'genAlarms', 'genTime', 'hvacThermostat'];
357
+ await reporting.bind(endpoint, coordinatorEndpoint, binds);
358
+ await reporting.thermostatTemperature(endpoint);
359
+ await reporting.thermostatRunningState(endpoint);
360
+ await reporting.thermostatSystemMode(endpoint);
361
+ await reporting.thermostatOccupiedHeatingSetpoint(endpoint);
362
+ await reporting.thermostatTemperatureSetpointHold(endpoint);
363
+ await reporting.thermostatTemperatureSetpointHoldDuration(endpoint);
364
+ },
365
+ },
335
366
  {
336
367
  zigbeeModel: ['SLR2'],
337
368
  model: 'SLR2',
@@ -434,6 +465,57 @@ module.exports = [
434
465
  .withDescription('Period in minutes for which the setpoint hold will be active. 65535 = attribute not' +
435
466
  ' used. 0 to 360 to match the remote display').withEndpoint('water')],
436
467
  },
468
+ {
469
+ zigbeeModel: ['SLR2c'],
470
+ model: 'SLR2c',
471
+ vendor: 'Hive',
472
+ description: 'Dual channel heating and hot water thermostat',
473
+ fromZigbee: [fz.thermostat, fz.thermostat_weekly_schedule],
474
+ toZigbee: [tz.thermostat_local_temperature, tz.thermostat_system_mode, tz.thermostat_running_state,
475
+ tz.thermostat_occupied_heating_setpoint, tz.thermostat_control_sequence_of_operation, tz.thermostat_weekly_schedule,
476
+ tz.thermostat_clear_weekly_schedule, tz.thermostat_temperature_setpoint_hold, tz.thermostat_temperature_setpoint_hold_duration],
477
+ endpoint: (device) => {
478
+ return {'heat': 5, 'water': 6};
479
+ },
480
+ meta: {disableDefaultResponse: true, multiEndpoint: true},
481
+ configure: async (device, coordinatorEndpoint, logger) => {
482
+ const heatEndpoint = device.getEndpoint(5);
483
+ const waterEndpoint = device.getEndpoint(6);
484
+ const binds = [
485
+ 'genBasic', 'genIdentify', 'genAlarms', 'genTime', 'hvacThermostat',
486
+ ];
487
+ await reporting.bind(heatEndpoint, coordinatorEndpoint, binds);
488
+ await reporting.thermostatTemperature(heatEndpoint);
489
+ await reporting.thermostatRunningState(heatEndpoint);
490
+ await reporting.thermostatSystemMode(heatEndpoint);
491
+ await reporting.thermostatOccupiedHeatingSetpoint(heatEndpoint);
492
+ await reporting.thermostatTemperatureSetpointHold(heatEndpoint);
493
+ await reporting.thermostatTemperatureSetpointHoldDuration(heatEndpoint);
494
+ await reporting.bind(waterEndpoint, coordinatorEndpoint, binds);
495
+ await reporting.thermostatRunningState(waterEndpoint);
496
+ await reporting.thermostatSystemMode(waterEndpoint);
497
+ await reporting.thermostatOccupiedHeatingSetpoint(waterEndpoint);
498
+ await reporting.thermostatTemperatureSetpointHold(waterEndpoint);
499
+ await reporting.thermostatTemperatureSetpointHoldDuration(waterEndpoint);
500
+ },
501
+ exposes: [
502
+ exposes.climate().withSetpoint('occupied_heating_setpoint', 5, 32, 0.5).withLocalTemperature()
503
+ .withSystemMode(['off', 'auto', 'heat']).withRunningState(['idle', 'heat']).withEndpoint('heat'),
504
+ exposes.binary('temperature_setpoint_hold', ea.ALL, true, false)
505
+ .withDescription('Prevent changes. `false` = run normally. `true` = prevent from making changes.' +
506
+ ' Must be set to `false` when system_mode = off or `true` for heat').withEndpoint('heat'),
507
+ exposes.numeric('temperature_setpoint_hold_duration', ea.ALL).withValueMin(0).withValueMax(65535)
508
+ .withDescription('Period in minutes for which the setpoint hold will be active. 65535 = attribute not' +
509
+ ' used. 0 to 360 to match the remote display').withEndpoint('heat'),
510
+ exposes.climate().withSetpoint('occupied_heating_setpoint', 22, 22, 1).withLocalTemperature()
511
+ .withSystemMode(['off', 'auto', 'heat']).withRunningState(['idle', 'heat']).withEndpoint('water'),
512
+ exposes.binary('temperature_setpoint_hold', ea.ALL, true, false)
513
+ .withDescription('Prevent changes. `false` = run normally. `true` = prevent from making changes.' +
514
+ ' Must be set to `false` when system_mode = off or `true` for heat').withEndpoint('water'),
515
+ exposes.numeric('temperature_setpoint_hold_duration', ea.ALL).withValueMin(0).withValueMax(65535)
516
+ .withDescription('Period in minutes for which the setpoint hold will be active. 65535 = attribute not' +
517
+ ' used. 0 to 360 to match the remote display').withEndpoint('water')],
518
+ },
437
519
  {
438
520
  zigbeeModel: ['WPT1'],
439
521
  model: 'WPT1',
package/devices/ikea.js CHANGED
@@ -621,7 +621,7 @@ module.exports = [
621
621
  extend: tradfriExtend.light_onoff_brightness_colortemp(),
622
622
  },
623
623
  {
624
- zigbeeModel: ['STARKVIND Air purifier'],
624
+ zigbeeModel: ['STARKVIND Air purifier', 'STARKVIND Air purifier table'],
625
625
  model: 'E2007',
626
626
  vendor: 'IKEA',
627
627
  description: 'STARKVIND air purifier',
package/devices/javis.js CHANGED
@@ -1,11 +1,14 @@
1
1
  const exposes = require('../lib/exposes');
2
2
  const fz = {...require('../converters/fromZigbee'), legacy: require('../lib/legacy').fromZigbee};
3
+ const tz = require('../converters/toZigbee');
3
4
  const e = exposes.presets;
5
+ const ea = exposes.access;
4
6
 
5
7
  module.exports = [
6
8
  {
7
9
  zigbeeModel: ['JAVISLOCK'],
8
- fingerprint: [{modelID: 'doorlock_5001', manufacturerName: 'Lmiot'}],
10
+ fingerprint: [{modelID: 'doorlock_5001', manufacturerName: 'Lmiot'},
11
+ {modelID: 'E321V000A03', manufacturerName: 'Vensi'}],
9
12
  model: 'JS-SLK2-ZB',
10
13
  vendor: 'JAVIS',
11
14
  description: 'Intelligent biometric digital lock',
@@ -13,4 +16,21 @@ module.exports = [
13
16
  toZigbee: [],
14
17
  exposes: [e.battery(), e.action(['unlock'])],
15
18
  },
19
+ {
20
+ zigbeeModel: ['JAVISSENSOR'],
21
+ fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_lgstepha'},
22
+ {modelID: 'TS0601', manufacturerName: '_TZE200_kagkgk0i'},
23
+ {modelID: 'TS0601', manufacturerName: '_TZE200_i0b1dbqu'}],
24
+ model: 'JS-MC-SENSOR-ZB',
25
+ vendor: 'JAVIS',
26
+ description: 'Microwave sensor',
27
+ fromZigbee: [fz.javis_microwave_sensor, fz.ignore_basic_report],
28
+ toZigbee: [tz.javis_microwave_sensor],
29
+ exposes: [e.occupancy(), e.illuminance_lux(),
30
+ exposes.binary('led_enable', ea.STATE_SET, true, false).withDescription('Enabled LED'),
31
+ exposes.enum('keep_time', ea.STATE_SET, ['0', '1', '2', '3', '4', '5', '6', '7'])
32
+ .withDescription('PIR keep time 0:5s|1:30s|2:60s|3:180s|4:300s|5:600s|6:1200s|7:1800s'),
33
+ exposes.enum('sensitivity', ea.STATE_SET, ['25', '50', '75', '100']),
34
+ exposes.numeric('illuminance_calibration', ea.STATE_SET).withDescription('Illuminance calibration')],
35
+ },
16
36
  ];
@@ -10,7 +10,7 @@ module.exports = [
10
10
  model: 'ZM350STW1TCF',
11
11
  vendor: 'Leedarson',
12
12
  description: 'LED PAR16 50 GU10 tunable white',
13
- extend: extend.light_onoff_brightness_colortemp(),
13
+ extend: extend.light_onoff_brightness_colortemp({disableColorTempStartup: true}),
14
14
  },
15
15
  {
16
16
  zigbeeModel: ['M350ST-W1R-01', 'A470S-A7R-04'],
package/devices/lidl.js CHANGED
@@ -133,6 +133,28 @@ module.exports = [
133
133
  device.getEndpoint(1).saveClusterAttributeKeyValue('lightingColorCtrl', {colorCapabilities: 29});
134
134
  },
135
135
  },
136
+ {
137
+ fingerprint: [{modelID: 'TS0505B', manufacturerName: '_TZ3000_quqaeew6'}],
138
+ model: 'HG07834A',
139
+ vendor: 'Lidl',
140
+ description: 'Livarno Lux GU10 spot RGB',
141
+ ...extend.light_onoff_brightness_colortemp_color({disableColorTempStartup: true, colorTempRange: [153, 500]}),
142
+ meta: {applyRedFix: true, enhancedHue: false},
143
+ configure: async (device, coordinatorEndpoint, logger) => {
144
+ device.getEndpoint(1).saveClusterAttributeKeyValue('lightingColorCtrl', {colorCapabilities: 29});
145
+ },
146
+ },
147
+ {
148
+ fingerprint: [{modelID: 'TS0505B', manufacturerName: '_TZ3000_th6zqqy6'}],
149
+ model: 'HG07834B',
150
+ vendor: 'Lidl',
151
+ description: 'Livarno Lux E14 candle RGB',
152
+ ...extend.light_onoff_brightness_colortemp_color({disableColorTempStartup: true, colorTempRange: [153, 500]}),
153
+ meta: {applyRedFix: true, enhancedHue: false},
154
+ configure: async (device, coordinatorEndpoint, logger) => {
155
+ device.getEndpoint(1).saveClusterAttributeKeyValue('lightingColorCtrl', {colorCapabilities: 29});
156
+ },
157
+ },
136
158
  {
137
159
  fingerprint: [{modelID: 'TS0505A', manufacturerName: '_TZ3000_kdpxju99'}],
138
160
  model: 'HG06106A',
@@ -155,6 +177,17 @@ module.exports = [
155
177
  device.getEndpoint(1).saveClusterAttributeKeyValue('lightingColorCtrl', {colorCapabilities: 29});
156
178
  },
157
179
  },
180
+ {
181
+ fingerprint: [{modelID: 'TS0505B', manufacturerName: '_TZ3000_qd7hej8u'}],
182
+ model: 'HG07834C',
183
+ vendor: 'Lidl',
184
+ description: 'Livarno Lux E27 bulb RGB',
185
+ ...extend.light_onoff_brightness_colortemp_color({disableColorTempStartup: true, colorTempRange: [153, 500]}),
186
+ meta: {applyRedFix: true, enhancedHue: false},
187
+ configure: async (device, coordinatorEndpoint, logger) => {
188
+ device.getEndpoint(1).saveClusterAttributeKeyValue('lightingColorCtrl', {colorCapabilities: 29});
189
+ },
190
+ },
158
191
  {
159
192
  fingerprint: [{modelID: 'TS0502A', manufacturerName: '_TZ3000_el5kt5im'}],
160
193
  model: 'HG06492A',
package/devices/neo.js CHANGED
@@ -27,6 +27,12 @@ module.exports = [
27
27
  exposes.enum('volume', ea.STATE_SET, ['low', 'medium', 'high']),
28
28
  exposes.enum('power_type', ea.STATE, ['battery_full', 'battery_high', 'battery_medium', 'battery_low', 'usb']),
29
29
  ],
30
+ onEvent: tuya.onEventSetLocalTime,
31
+ configure: async (device, coordinatorEndpoint, logger) => {
32
+ const endpoint = device.getEndpoint(1);
33
+ await endpoint.command('manuSpecificTuya', 'resetDevice', {});
34
+ await endpoint.command('manuSpecificTuya', 'unknown0x10', {'data': [0x00, 0x02]});
35
+ },
30
36
  },
31
37
  {
32
38
  fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_7hfcudw5'}],
@@ -591,6 +591,15 @@ module.exports = [
591
591
  extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
592
592
  ota: ota.zigbeeOTA,
593
593
  },
594
+ {
595
+ zigbeeModel: ['LTA011'],
596
+ model: '929002471901',
597
+ vendor: 'Philips',
598
+ description: 'Hue white ambiance E27 1600lm with Bluetooth',
599
+ meta: {turnsOffAtBrightness1: true},
600
+ extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
601
+ ota: ota.zigbeeOTA,
602
+ },
594
603
  {
595
604
  zigbeeModel: ['LTA008'],
596
605
  model: '9290022267A',
@@ -2233,4 +2242,13 @@ module.exports = [
2233
2242
  extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
2234
2243
  ota: ota.zigbeeOTA,
2235
2244
  },
2245
+ {
2246
+ zigbeeModel: ['1746547P7'],
2247
+ model: '1746547P7',
2248
+ vendor: 'Philips',
2249
+ description: 'Hue White and color ambiance Daylo outdoor wall lamp',
2250
+ meta: {turnsOffAtBrightness1: true},
2251
+ extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
2252
+ ota: ota.zigbeeOTA,
2253
+ },
2236
2254
  ];
@@ -1,9 +1,17 @@
1
1
  const exposes = require('../lib/exposes');
2
2
  const fz = {...require('../converters/fromZigbee'), legacy: require('../lib/legacy').fromZigbee};
3
3
  const reporting = require('../lib/reporting');
4
+ const extend = require('../lib/extend');
4
5
  const e = exposes.presets;
5
6
 
6
7
  module.exports = [
8
+ {
9
+ zigbeeModel: ['RGBgenie ZB-1026'],
10
+ model: 'ZB-1026',
11
+ vendor: 'RGB Genie',
12
+ description: 'Zigbee LED dimmer controller',
13
+ extend: extend.light_onoff_brightness(),
14
+ },
7
15
  {
8
16
  zigbeeModel: ['RGBgenie ZB-5001'],
9
17
  model: 'ZB-5001',
package/devices/tuya.js CHANGED
@@ -634,7 +634,8 @@ module.exports = [
634
634
  },
635
635
  },
636
636
  {
637
- fingerprint: [{modelID: 'TS0003', manufacturerName: '_TZ3000_vsasbzkf'}],
637
+ fingerprint: [{modelID: 'TS0003', manufacturerName: '_TZ3000_vsasbzkf'},
638
+ {modelID: 'TS0003', manufacturerName: '_TZ3000_odzoiovu'}],
638
639
  model: 'TS0003_switch_module',
639
640
  vendor: 'TuYa',
640
641
  description: '3 gang switch module',
@@ -775,7 +776,8 @@ module.exports = [
775
776
  tz.tuya_thermostat_calibration, tz.tuya_thermostat_min_temp, tz.tuya_thermostat_max_temp,
776
777
  tz.tuya_thermostat_boost_time, tz.tuya_thermostat_comfort_temp, tz.tuya_thermostat_eco_temp,
777
778
  tz.tuya_thermostat_force_to_mode, tz.tuya_thermostat_force, tz.tuya_thermostat_preset, tz.tuya_thermostat_away_mode,
778
- tz.tuya_thermostat_window_detect, tz.tuya_thermostat_schedule, tz.tuya_thermostat_week, tz.tuya_thermostat_away_preset],
779
+ tz.tuya_thermostat_window_detect, tz.tuya_thermostat_schedule, tz.tuya_thermostat_week, tz.tuya_thermostat_away_preset,
780
+ tz.tuya_thermostat_schedule_programming_mode],
779
781
  exposes: [
780
782
  e.child_lock(), e.window_detection(), e.battery_low(), e.valve_detection(), e.position(),
781
783
  exposes.climate().withSetpoint('current_heating_setpoint', 5, 35, 0.5, ea.STATE_SET)
@@ -783,7 +785,54 @@ module.exports = [
783
785
  .withLocalTemperatureCalibration(ea.STATE_SET)
784
786
  .withAwayMode().withPreset(['schedule', 'manual', 'boost', 'complex', 'comfort', 'eco']),
785
787
  e.auto_lock(), e.away_mode(), e.away_preset_days(), e.boost_time(), e.comfort_temperature(), e.eco_temperature(), e.force(),
786
- e.max_temperature(), e.min_temperature(), e.week(), e.away_preset_temperature()],
788
+ e.max_temperature(), e.min_temperature(), e.away_preset_temperature(),
789
+ exposes.composite('programming_mode').withDescription('Schedule MODE ⏱ - In this mode, ' +
790
+ 'the device executes a preset week programming temperature time and temperature.')
791
+ .withFeature(e.week())
792
+ .withFeature(exposes.text('workdays_schedule', ea.STATE_SET))
793
+ .withFeature(exposes.text('holidays_schedule', ea.STATE_SET))],
794
+ },
795
+ {
796
+ fingerprint: [
797
+ {/* model: 'TV02-Zigbee', vendor: 'TuYa', */modelID: 'TS0601', manufacturerName: '_TZE200_hue3yfsn'}],
798
+ model: 'TV02-Zigbee',
799
+ vendor: 'TuYa',
800
+ description: 'Thermostat radiator valve',
801
+ ota: ota.zigbeeOTA,
802
+ fromZigbee: [fz.ignore_basic_report, fz.ignore_tuya_set_time, fz.tvtwo_thermostat],
803
+ toZigbee: [tz.tvtwo_thermostat],
804
+ onEvent: tuya.onEventSetLocalTime,
805
+ exposes: [
806
+ e.battery_low(), e.window_detection(), e.child_lock(), e.comfort_temperature(), e.eco_temperature(),
807
+ e.open_window_temperature(), e.holiday_temperature(),
808
+ exposes.climate().withPreset(['auto', 'manual', 'holiday']).withLocalTemperatureCalibration(ea.STATE_SET)
809
+ .withLocalTemperature(ea.STATE).withSetpoint('current_heating_setpoint', 0, 30, 0.5, ea.STATE_SET),
810
+ exposes.numeric('boost_timeset_countdown', ea.STATE_SET).withUnit('second').withDescription('Setting '+
811
+ 'minimum 0 - maximum 465 seconds boost time. The boost (♨) function is activated. The remaining '+
812
+ 'time for the function will be counted down in seconds ( 465 to 0 ).'),
813
+ exposes.binary('frost_protection', ea.STATE_SET, 'ON', 'OFF').withDescription('When Anti-Freezing function'+
814
+ ' is activated, the temperature in the house is kept at 8 °C ‚the device display "AF".press the '+
815
+ 'pair button to cancel.'),
816
+ exposes.binary('heating_stop', ea.STATE_SET, 'ON', 'OFF').withDescription('Battery life can be prolonged'+
817
+ ' by switching the heating off. To achieve this, the valve is closed fully. To activate the '+
818
+ 'heating stop, the device display "HS" ‚press the pair button to cancel.'),
819
+ exposes.binary('online', ea.STATE_SET, 'ON', 'OFF').withDescription('Is the device online'),
820
+ exposes.numeric('holiday_mode_date', ea.STATE_SET).withDescription('The holiday mode( ⛱ ) will '+
821
+ 'automatically start at the set time starting point and run the holiday temperature.'),
822
+ exposes.composite('programming', 'programming').withDescription('Auto Mode ⏱ - In this mode,'+
823
+ ' the device executes a preset week programming temperature time and temperature. ')
824
+ .withFeature(exposes.text('schedule_monday', ea.STATE))
825
+ .withFeature(exposes.text('schedule_tuesday', ea.STATE))
826
+ .withFeature(exposes.text('schedule_wednesday', ea.STATE))
827
+ .withFeature(exposes.text('schedule_thursday', ea.STATE))
828
+ .withFeature(exposes.text('schedule_friday', ea.STATE))
829
+ .withFeature(exposes.text('schedule_saturday', ea.STATE))
830
+ .withFeature(exposes.text('schedule_sunday', ea.STATE)),
831
+ exposes.numeric('error_status', ea.STATE).withDescription('Error status'),
832
+ // exposes.numeric('week_schedule', ea.STATE).withDescription('week_schedule'),
833
+ // exposes.numeric('working_day', ea.STATE).withDescription('working_day'),
834
+ // e.week(),
835
+ ],
787
836
  },
788
837
  {
789
838
  fingerprint: [
@@ -999,7 +1048,7 @@ module.exports = [
999
1048
  },
1000
1049
  {
1001
1050
  zigbeeModel: ['5p1vj8r'],
1002
- fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_t5p1vj8r'}],
1051
+ fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_t5p1vj8r'}, {modelID: 'TS0601', manufacturerName: '_TZE200_uebojraa'}],
1003
1052
  model: 'TS0601_smoke',
1004
1053
  vendor: 'TuYa',
1005
1054
  description: 'Smoke sensor',
@@ -1026,7 +1075,8 @@ module.exports = [
1026
1075
  exposes: [e.switch().setAccess('state', ea.STATE_SET), e.voltage(), e.power(), e.current(), e.energy()],
1027
1076
  },
1028
1077
  {
1029
- fingerprint: [{modelID: 'TS1101', manufacturerName: '_TZ3000_7ysdnebc'}],
1078
+ fingerprint: [{modelID: 'TS1101', manufacturerName: '_TZ3000_7ysdnebc'},
1079
+ {modelID: 'TS1101', manufacturerName: '_TZ3000_xfs39dbf'}],
1030
1080
  model: 'TS1101_dimmer_module',
1031
1081
  vendor: 'TuYa',
1032
1082
  description: '2CH Zigbee dimmer module',
@@ -1079,9 +1129,11 @@ module.exports = [
1079
1129
  model: 'TS0115',
1080
1130
  vendor: 'TuYa',
1081
1131
  description: 'Multiprise with 4 AC outlets and 2 USB super charging ports (10A or 16A)',
1132
+ toZigbee: extend.switch().toZigbee.concat([tz.moes_power_on_behavior]),
1133
+ fromZigbee: extend.switch().fromZigbee.concat([fz.moes_power_on_behavior]),
1082
1134
  extend: extend.switch(),
1083
1135
  exposes: [e.switch().withEndpoint('l1'), e.switch().withEndpoint('l2'), e.switch().withEndpoint('l3'),
1084
- e.switch().withEndpoint('l4'), e.switch().withEndpoint('l5')],
1136
+ e.switch().withEndpoint('l4'), e.switch().withEndpoint('l5'), e.power_on_behavior()],
1085
1137
  whiteLabel: [{vendor: 'UseeLink', model: 'SM-SO306E/K/M'}],
1086
1138
  endpoint: (device) => {
1087
1139
  return {l1: 1, l2: 2, l3: 3, l4: 4, l5: 7};
@@ -1093,6 +1145,11 @@ module.exports = [
1093
1145
  await reporting.bind(device.getEndpoint(3), coordinatorEndpoint, ['genOnOff']);
1094
1146
  await reporting.bind(device.getEndpoint(4), coordinatorEndpoint, ['genOnOff']);
1095
1147
  await reporting.bind(device.getEndpoint(7), coordinatorEndpoint, ['genOnOff']);
1148
+ await device.getEndpoint(1).read('genOnOff', ['onOff', 'moesStartUpOnOff']);
1149
+ await device.getEndpoint(2).read('genOnOff', ['onOff']);
1150
+ await device.getEndpoint(3).read('genOnOff', ['onOff']);
1151
+ await device.getEndpoint(4).read('genOnOff', ['onOff']);
1152
+ await device.getEndpoint(7).read('genOnOff', ['onOff']);
1096
1153
  },
1097
1154
  },
1098
1155
  {
@@ -1110,7 +1167,9 @@ module.exports = [
1110
1167
  model: 'TS0011',
1111
1168
  vendor: 'TuYa',
1112
1169
  description: 'Smart light switch - 1 gang',
1113
- extend: extend.switch(),
1170
+ toZigbee: extend.switch().toZigbee.concat([tz.tuya_switch_type]),
1171
+ fromZigbee: extend.switch().fromZigbee.concat([fz.tuya_switch_type]),
1172
+ exposes: [e.switch(), exposes.presets.switch_type_2()],
1114
1173
  whiteLabel: [
1115
1174
  {vendor: 'Vrey', model: 'VR-X712U-0013'},
1116
1175
  {vendor: 'TUYATEC', model: 'GDKES-01TZXD'},
@@ -1131,8 +1190,9 @@ module.exports = [
1131
1190
  description: 'Smart light switch - 2 gang',
1132
1191
  whiteLabel: [{vendor: 'Vrey', model: 'VR-X712U-0013'}, {vendor: 'TUYATEC', model: 'GDKES-02TZXD'},
1133
1192
  {vendor: 'Earda', model: 'ESW-2ZAA-EU'}],
1134
- extend: extend.switch(),
1135
- exposes: [e.switch().withEndpoint('left'), e.switch().withEndpoint('right')],
1193
+ toZigbee: extend.switch().toZigbee.concat([tz.tuya_switch_type]),
1194
+ fromZigbee: extend.switch().fromZigbee.concat([fz.tuya_switch_type]),
1195
+ exposes: [e.switch().withEndpoint('left'), e.switch().withEndpoint('right'), exposes.presets.switch_type_2()],
1136
1196
  endpoint: (device) => {
1137
1197
  return {'left': 1, 'right': 2};
1138
1198
  },
@@ -1149,8 +1209,10 @@ module.exports = [
1149
1209
  model: 'TS0013',
1150
1210
  vendor: 'TuYa',
1151
1211
  description: 'Smart light switch - 3 gang without neutral wire',
1152
- extend: extend.switch(),
1153
- exposes: [e.switch().withEndpoint('left'), e.switch().withEndpoint('center'), e.switch().withEndpoint('right')],
1212
+ toZigbee: extend.switch().toZigbee.concat([tz.tuya_switch_type]),
1213
+ fromZigbee: extend.switch().fromZigbee.concat([fz.tuya_switch_type]),
1214
+ exposes: [e.switch().withEndpoint('left'), e.switch().withEndpoint('center'), e.switch().withEndpoint('right'),
1215
+ exposes.presets.switch_type_2()],
1154
1216
  endpoint: (device) => {
1155
1217
  return {'left': 1, 'center': 2, 'right': 3};
1156
1218
  },
@@ -1176,9 +1238,10 @@ module.exports = [
1176
1238
  model: 'TS0014',
1177
1239
  vendor: 'TuYa',
1178
1240
  description: 'Smart light switch - 4 gang without neutral wire',
1179
- extend: extend.switch(),
1241
+ toZigbee: extend.switch().toZigbee.concat([tz.tuya_switch_type]),
1242
+ fromZigbee: extend.switch().fromZigbee.concat([fz.tuya_switch_type]),
1180
1243
  exposes: [e.switch().withEndpoint('l1'), e.switch().withEndpoint('l2'), e.switch().withEndpoint('l3'),
1181
- e.switch().withEndpoint('l4')],
1244
+ e.switch().withEndpoint('l4'), exposes.presets.switch_type_2()],
1182
1245
  endpoint: (device) => {
1183
1246
  return {'l1': 1, 'l2': 2, 'l3': 3, 'l4': 4};
1184
1247
  },
package/devices/xiaomi.js CHANGED
@@ -1127,7 +1127,7 @@ module.exports = [
1127
1127
  fromZigbee: [fz.xiaomi_battery, fz.DJT11LM_vibration],
1128
1128
  toZigbee: [tz.DJT11LM_vibration_sensitivity],
1129
1129
  exposes: [
1130
- e.battery(), e.action(['vibration', 'tilt', 'drop']),
1130
+ e.battery(), e.vibration(), e.action(['vibration', 'tilt', 'drop']),
1131
1131
  exposes.numeric('strength', ea.STATE), exposes.enum('sensitivity', ea.STATE_SET, ['low', 'medium', 'high']),
1132
1132
  e.angle_axis('angle_x'), e.angle_axis('angle_y'), e.angle_axis('angle_z'), e.battery_voltage(),
1133
1133
  ],
package/devices/zen.js CHANGED
@@ -16,7 +16,7 @@ module.exports = [
16
16
  tz.thermostat_remote_sensing, tz.thermostat_control_sequence_of_operation, tz.thermostat_system_mode,
17
17
  tz.thermostat_weekly_schedule, tz.thermostat_clear_weekly_schedule, tz.thermostat_relay_status_log],
18
18
  exposes: [exposes.climate().withSetpoint('occupied_heating_setpoint', 10, 30, 0.5).withLocalTemperature()
19
- .withSystemMode(['off', 'auto', 'heat']).withRunningState(['idle', 'heat', 'cool'])
19
+ .withSystemMode(['off', 'auto', 'heat', 'cool']).withRunningState(['idle', 'heat', 'cool'])
20
20
  .withLocalTemperatureCalibration().withPiHeatingDemand()],
21
21
  configure: async (device, coordinatorEndpoint, logger) => {
22
22
  const endpoint = device.getEndpoint(3) || device.getEndpoint(1);
package/lib/exposes.js CHANGED
@@ -530,6 +530,7 @@ module.exports = {
530
530
  formaldehyd: () => new Numeric('formaldehyd', access.STATE).withDescription('The measured formaldehyd value'),
531
531
  gas: () => new Binary('gas', access.STATE, true, false).withDescription('Indicates whether the device detected gas'),
532
532
  hcho: () => new Numeric('hcho', access.STATE).withUnit('mg/m³').withDescription('Measured Hcho value'),
533
+ holiday_temperature: () => new Numeric('holiday_temperature', access.STATE_SET).withUnit('°C').withDescription('Holiday temperature'),
533
534
  humidity: () => new Numeric('humidity', access.STATE).withUnit('%').withDescription('Measured relative humidity'),
534
535
  illuminance: () => new Numeric('illuminance', access.STATE).withDescription('Raw measured illuminance'),
535
536
  illuminance_lux: () => new Numeric('illuminance_lux', access.STATE).withUnit('lx').withDescription('Measured illuminance in lux'),
@@ -551,6 +552,7 @@ module.exports = {
551
552
  max_temperature_limit: () => new Numeric('max_temperature_limit', access.STATE_SET).withUnit('°C').withDescription('Maximum temperature limit'),
552
553
  min_temperature: () => new Numeric('min_temperature', access.STATE_SET).withUnit('°C').withDescription('Minimum temperature'),
553
554
  occupancy: () => new Binary('occupancy', access.STATE, true, false).withDescription('Indicates whether the device detected occupancy'),
555
+ open_window_temperature: () => new Numeric('open_window_temperature', access.STATE_SET).withUnit('°C').withDescription('Open window temperature'),
554
556
  pm10: () => new Numeric('pm10', access.STATE).withUnit('µg/m³').withDescription('Measured PM10 (particulate matter) concentration'),
555
557
  pm25: () => new Numeric('pm25', access.STATE).withUnit('µg/m³').withDescription('Measured PM2.5 (particulate matter) concentration'),
556
558
  position: () => new Numeric('position', access.STATE).withUnit('%').withDescription('Position'),
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zigbee-herdsman-converters",
3
- "version": "14.0.310",
3
+ "version": "14.0.315",
4
4
  "lockfileVersion": 1,
5
5
  "requires": true,
6
6
  "dependencies": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zigbee-herdsman-converters",
3
- "version": "14.0.310",
3
+ "version": "14.0.315",
4
4
  "description": "Collection of device converters to be used with zigbee-herdsman",
5
5
  "main": "index.js",
6
6
  "files": [