zigbee-herdsman-converters 14.0.309 → 14.0.314

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]
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: {
3873
4025
  // 6:00 - 20*, 8:00 - 15*, 11:30 - 15*, 12:30 - 15*, 17:30 - 20*, 22:00 - 15*
3874
4026
  // 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]
3886
- // 6:00 - 20*, 8:00 - 15*, 11:30 - 15*, 12:30 - 15*, 17:30 - 20*, 22:00 - 15*
3887
- // 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:
@@ -6047,12 +6199,34 @@ const converters = {
6047
6199
  DJT11LM_vibration: {
6048
6200
  cluster: 'closuresDoorLock',
6049
6201
  type: ['attributeReport', 'readResponse'],
6202
+ options: [exposes.options.vibration_timeout()],
6050
6203
  convert: (model, msg, publish, options, meta) => {
6051
6204
  const result = {};
6052
6205
 
6053
6206
  if (msg.data['85']) {
6054
6207
  const vibrationLookup = {1: 'vibration', 2: 'tilt', 3: 'drop'};
6055
6208
  result.action = vibrationLookup[msg.data['85']];
6209
+
6210
+ // Device only sends a message when vibration is detected.
6211
+ // Therefore we need to publish a no_vibration message on our own.
6212
+ if (result.action === 'vibration') {
6213
+ result.vibration = true;
6214
+
6215
+ const timeout = options && options.hasOwnProperty('vibration_timeout') ? options.vibration_timeout : 90;
6216
+
6217
+ // Stop any existing timer cause vibration detected
6218
+ clearTimeout(globalStore.getValue(msg.endpoint, 'vibration_timer', null));
6219
+ globalStore.putValue(msg.endpoint, 'vibration_timer', null);
6220
+
6221
+ // Set new timer to publish no_vibration message
6222
+ if (timeout !== 0) {
6223
+ const timer = setTimeout(() => {
6224
+ publish({vibration: false});
6225
+ }, timeout * 1000);
6226
+
6227
+ globalStore.putValue(msg.endpoint, 'vibration_timer', timer);
6228
+ }
6229
+ }
6056
6230
  }
6057
6231
 
6058
6232
  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) => {
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',
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/lidl.js CHANGED
@@ -133,6 +133,17 @@ module.exports = [
133
133
  device.getEndpoint(1).saveClusterAttributeKeyValue('lightingColorCtrl', {colorCapabilities: 29});
134
134
  },
135
135
  },
136
+ {
137
+ fingerprint: [{modelID: 'TS0505B', manufacturerName: '_TZ3000_th6zqqy6'}],
138
+ model: 'HG07834B',
139
+ vendor: 'Lidl',
140
+ description: 'Livarno Lux E14 candle 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
+ },
136
147
  {
137
148
  fingerprint: [{modelID: 'TS0505A', manufacturerName: '_TZ3000_kdpxju99'}],
138
149
  model: 'HG06106A',
@@ -155,6 +166,17 @@ module.exports = [
155
166
  device.getEndpoint(1).saveClusterAttributeKeyValue('lightingColorCtrl', {colorCapabilities: 29});
156
167
  },
157
168
  },
169
+ {
170
+ fingerprint: [{modelID: 'TS0505B', manufacturerName: '_TZ3000_qd7hej8u'}],
171
+ model: 'HG07834C',
172
+ vendor: 'Lidl',
173
+ description: 'Livarno Lux E27 bulb RGB',
174
+ ...extend.light_onoff_brightness_colortemp_color({disableColorTempStartup: true, colorTempRange: [153, 500]}),
175
+ meta: {applyRedFix: true, enhancedHue: false},
176
+ configure: async (device, coordinatorEndpoint, logger) => {
177
+ device.getEndpoint(1).saveClusterAttributeKeyValue('lightingColorCtrl', {colorCapabilities: 29});
178
+ },
179
+ },
158
180
  {
159
181
  fingerprint: [{modelID: 'TS0502A', manufacturerName: '_TZ3000_el5kt5im'}],
160
182
  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'}],
@@ -350,6 +350,15 @@ module.exports = [
350
350
  extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
351
351
  ota: ota.zigbeeOTA,
352
352
  },
353
+ {
354
+ zigbeeModel: ['1742330P7'],
355
+ model: '1742330P7',
356
+ vendor: 'Philips',
357
+ description: 'Hue Calla outdoor',
358
+ meta: {turnsOffAtBrightness1: true},
359
+ extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
360
+ ota: ota.zigbeeOTA,
361
+ },
353
362
  {
354
363
  zigbeeModel: ['1744130P7'],
355
364
  model: '1744130P7',
@@ -555,6 +564,15 @@ module.exports = [
555
564
  extend: hueExtend.light_onoff_brightness_colortemp(),
556
565
  ota: ota.zigbeeOTA,
557
566
  },
567
+ {
568
+ zigbeeModel: ['LTA004'],
569
+ model: '8719514328242',
570
+ vendor: 'Philips',
571
+ description: 'Hue white ambiance E27 800lm with Bluetooth',
572
+ meta: {turnsOffAtBrightness1: true},
573
+ extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
574
+ ota: ota.zigbeeOTA,
575
+ },
558
576
  {
559
577
  zigbeeModel: ['LTA009'],
560
578
  model: '9290024684',
@@ -573,6 +591,15 @@ module.exports = [
573
591
  extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
574
592
  ota: ota.zigbeeOTA,
575
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
+ },
576
603
  {
577
604
  zigbeeModel: ['LTA008'],
578
605
  model: '9290022267A',
@@ -2215,4 +2242,13 @@ module.exports = [
2215
2242
  extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
2216
2243
  ota: ota.zigbeeOTA,
2217
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
+ },
2218
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',
@@ -216,4 +216,11 @@ module.exports = [
216
216
  description: 'Vintage LED edison bulb (ST19)',
217
217
  extend: extend.light_onoff_brightness(),
218
218
  },
219
+ {
220
+ zigbeeModel: ['E1F-N9G'],
221
+ model: 'E1F-N9G',
222
+ vendor: 'Sengled',
223
+ description: 'Smart LED filament candle (E12)',
224
+ extend: extend.light_onoff_brightness(),
225
+ },
219
226
  ];