zigbee-herdsman-converters 14.0.646 → 14.0.648
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/converters/fromZigbee.js +0 -154
- package/converters/toZigbee.js +1 -85
- package/devices/awox.js +1 -1
- package/devices/develco.js +65 -41
- package/devices/hornbach.js +1 -1
- package/devices/immax.js +1 -1
- package/devices/lonsonho.js +4 -1
- package/devices/moes.js +6 -4
- package/devices/perenio.js +0 -1
- package/devices/philips.js +1 -1
- package/devices/shinasystem.js +34 -0
- package/devices/tuya.js +86 -30
- package/devices/zemismart.js +1 -1
- package/lib/tuya.js +166 -6
- package/package.json +2 -2
package/converters/fromZigbee.js
CHANGED
|
@@ -4090,160 +4090,6 @@ const converters = {
|
|
|
4090
4090
|
}
|
|
4091
4091
|
},
|
|
4092
4092
|
},
|
|
4093
|
-
tvtwo_thermostat: {
|
|
4094
|
-
cluster: 'manuSpecificTuya',
|
|
4095
|
-
type: ['commandDataResponse', 'commandDataReport'],
|
|
4096
|
-
convert: (model, msg, publish, options, meta) => {
|
|
4097
|
-
const dpValue = tuya.firstDpValue(msg, meta, 'tvtwo_thermostat');
|
|
4098
|
-
const dp = dpValue.dp;
|
|
4099
|
-
const value = tuya.getDataValue(dpValue);
|
|
4100
|
-
const presetLookup = {0: 'auto', 1: 'manual', 2: 'holiday'};
|
|
4101
|
-
switch (dp) {
|
|
4102
|
-
case tuya.dataPoints.tvMode:
|
|
4103
|
-
return {preset: presetLookup[value]};
|
|
4104
|
-
case tuya.dataPoints.tvChildLock:
|
|
4105
|
-
return {child_lock: value ? 'LOCK' : 'UNLOCK'};
|
|
4106
|
-
case tuya.dataPoints.tvHolidayTemp:
|
|
4107
|
-
return {holiday_temperature: (value / 10).toFixed(1)};
|
|
4108
|
-
case tuya.dataPoints.tvHeatingSetpoint:
|
|
4109
|
-
return {current_heating_setpoint: (value / 10).toFixed(1)};
|
|
4110
|
-
case tuya.dataPoints.tvFrostDetection:
|
|
4111
|
-
return {frost_protection: value ? 'ON' : 'OFF'};
|
|
4112
|
-
case tuya.dataPoints.tvWindowDetection:
|
|
4113
|
-
return {open_window: value ? 'ON' : 'OFF'};
|
|
4114
|
-
case tuya.dataPoints.tvHeatingStop:
|
|
4115
|
-
return {heating_stop: value ? 'ON' : 'OFF'};
|
|
4116
|
-
case tuya.dataPoints.tvLocalTemp:
|
|
4117
|
-
return {local_temperature: (value / 10).toFixed(1)};
|
|
4118
|
-
case tuya.dataPoints.tvBattery:
|
|
4119
|
-
return {battery_low: value === 0 ? true : false};
|
|
4120
|
-
case tuya.dataPoints.tvTempCalibration:
|
|
4121
|
-
return {local_temperature_calibration: value > 55 ?
|
|
4122
|
-
((value - 0x100000000)/10).toFixed(1): (value/ 10).toFixed(1)};
|
|
4123
|
-
case tuya.dataPoints.tvBoostTime:
|
|
4124
|
-
// Setting minimum 0 - maximum 465 seconds
|
|
4125
|
-
return {boost_timeset_countdown: value};
|
|
4126
|
-
case tuya.dataPoints.tvComfortTemp:
|
|
4127
|
-
return {comfort_temperature: (value / 10).toFixed(1)};
|
|
4128
|
-
case tuya.dataPoints.tvEcoTemp:
|
|
4129
|
-
return {eco_temperature: (value / 10).toFixed(1)};
|
|
4130
|
-
case tuya.dataPoints.tvOpenWindowTemp:
|
|
4131
|
-
return {open_window_temperature: (value / 10).toFixed(1)};
|
|
4132
|
-
case tuya.dataPoints.tvErrorStatus:
|
|
4133
|
-
return {fault_alarm: value};
|
|
4134
|
-
case tuya.dataPoints.tvHolidayMode: {
|
|
4135
|
-
const sy = value.slice(0, 4); const sm = value.slice(4, 6); const sd = value.slice(6, 8);
|
|
4136
|
-
const sh = value.slice(8, 10); const smi = value.slice(10, 12); const ey = value.slice(12, 16);
|
|
4137
|
-
const em = value.slice(16, 18); const ed = value.slice(18, 20); const eh = value.slice(20, 22);
|
|
4138
|
-
const emi = value.slice(22, 24);
|
|
4139
|
-
const hMode = 'start --> ' + sy + ' - ' + sm + ' - ' + sd + ' ' + sh + ' : ' + smi +
|
|
4140
|
-
' stop --> ' + ey + ' - ' + em + ' - ' + ed + ' ' + eh + ' : ' + emi;
|
|
4141
|
-
return {holiday_start_stop: hMode};
|
|
4142
|
-
}
|
|
4143
|
-
case tuya.dataPoints.tvBoostMode:
|
|
4144
|
-
// 115 online / Is the device online
|
|
4145
|
-
return {online: value ? 'ON' : 'OFF'};
|
|
4146
|
-
case tuya.dataPoints.tvWorkingDay:
|
|
4147
|
-
// DP-31, Send and Report, ENUM, Week select 0 - 5 days, 1 - 6 days, 2 - 7 days
|
|
4148
|
-
return {working_day: value};
|
|
4149
|
-
case tuya.dataPoints.tvMondaySchedule:
|
|
4150
|
-
return {schedule_monday:
|
|
4151
|
-
' ' + value[0] / 6 + 'h:' + value[1] + 'm ' + value[2] / 10 + '°C' +
|
|
4152
|
-
', ' + value[3] / 6 + 'h:' + value[4] + 'm ' + value[5] / 10 + '°C' +
|
|
4153
|
-
', ' + value[6] / 6 + 'h:' + value[7] + 'm ' + value[8] / 10 + '°C' +
|
|
4154
|
-
', ' + value[9] / 6 + 'h:' + value[10] + 'm ' + value[11] / 10 + '°C' +
|
|
4155
|
-
', ' + value[12] / 6 + 'h:' + value[13] + 'm ' + value[14] / 10 + '°C ' +
|
|
4156
|
-
', ' + value[15] / 6 + 'h:' + value[16] + 'm ' + value[17] / 10 + '°C ' +
|
|
4157
|
-
', ' + value[18] / 6 + 'h:' + value[19] + 'm ' + value[20] / 10 + '°C ' +
|
|
4158
|
-
', ' + value[21] / 6 + 'h:' + value[22] + 'm ' + value[23] / 10 + '°C ' +
|
|
4159
|
-
', ' + value[24] / 6 + 'h:' + value[25] + 'm ' + value[26] / 10 + '°C ' +
|
|
4160
|
-
', ' + value[27] / 6 + 'h:' + value[28] + 'm ' + value[29] / 10 + '°C ',
|
|
4161
|
-
};
|
|
4162
|
-
case tuya.dataPoints.tvTuesdaySchedule:
|
|
4163
|
-
return {schedule_tuesday:
|
|
4164
|
-
' ' + value[0] / 6 + 'h:' + value[1] + 'm ' + value[2] / 10 + '°C' +
|
|
4165
|
-
', ' + value[3] / 6 + 'h:' + value[4] + 'm ' + value[5] / 10 + '°C' +
|
|
4166
|
-
', ' + value[6] / 6 + 'h:' + value[7] + 'm ' + value[8] / 10 + '°C' +
|
|
4167
|
-
', ' + value[9] / 6 + 'h:' + value[10] + 'm ' + value[11] / 10 + '°C' +
|
|
4168
|
-
', ' + value[12] / 6 + 'h:' + value[13] + 'm ' + value[14] / 10 + '°C ' +
|
|
4169
|
-
', ' + value[15] / 6 + 'h:' + value[16] + 'm ' + value[17] / 10 + '°C ' +
|
|
4170
|
-
', ' + value[18] / 6 + 'h:' + value[19] + 'm ' + value[20] / 10 + '°C ' +
|
|
4171
|
-
', ' + value[21] / 6 + 'h:' + value[22] + 'm ' + value[23] / 10 + '°C ' +
|
|
4172
|
-
', ' + value[24] / 6 + 'h:' + value[25] + 'm ' + value[26] / 10 + '°C ' +
|
|
4173
|
-
', ' + value[27] / 6 + 'h:' + value[28] + 'm ' + value[29] / 10 + '°C ',
|
|
4174
|
-
};
|
|
4175
|
-
case tuya.dataPoints.tvWednesdaySchedule:
|
|
4176
|
-
return {schedule_wednesday:
|
|
4177
|
-
' ' + value[0] / 6 + 'h:' + value[1] + 'm ' + value[2] / 10 + '°C' +
|
|
4178
|
-
', ' + value[3] / 6 + 'h:' + value[4] + 'm ' + value[5] / 10 + '°C' +
|
|
4179
|
-
', ' + value[6] / 6 + 'h:' + value[7] + 'm ' + value[8] / 10 + '°C' +
|
|
4180
|
-
', ' + value[9] / 6 + 'h:' + value[10] + 'm ' + value[11] / 10 + '°C' +
|
|
4181
|
-
', ' + value[12] / 6 + 'h:' + value[13] + 'm ' + value[14] / 10 + '°C ' +
|
|
4182
|
-
', ' + value[15] / 6 + 'h:' + value[16] + 'm ' + value[17] / 10 + '°C ' +
|
|
4183
|
-
', ' + value[18] / 6 + 'h:' + value[19] + 'm ' + value[20] / 10 + '°C ' +
|
|
4184
|
-
', ' + value[21] / 6 + 'h:' + value[22] + 'm ' + value[23] / 10 + '°C ' +
|
|
4185
|
-
', ' + value[24] / 6 + 'h:' + value[25] + 'm ' + value[26] / 10 + '°C ' +
|
|
4186
|
-
', ' + value[27] / 6 + 'h:' + value[28] + 'm ' + value[29] / 10 + '°C ',
|
|
4187
|
-
};
|
|
4188
|
-
case tuya.dataPoints.tvThursdaySchedule:
|
|
4189
|
-
return {schedule_thursday:
|
|
4190
|
-
' ' + value[0] / 6 + 'h:' + value[1] + 'm ' + value[2] / 10 + '°C' +
|
|
4191
|
-
', ' + value[3] / 6 + 'h:' + value[4] + 'm ' + value[5] / 10 + '°C' +
|
|
4192
|
-
', ' + value[6] / 6 + 'h:' + value[7] + 'm ' + value[8] / 10 + '°C' +
|
|
4193
|
-
', ' + value[9] / 6 + 'h:' + value[10] + 'm ' + value[11] / 10 + '°C' +
|
|
4194
|
-
', ' + value[12] / 6 + 'h:' + value[13] + 'm ' + value[14] / 10 + '°C ' +
|
|
4195
|
-
', ' + value[15] / 6 + 'h:' + value[16] + 'm ' + value[17] / 10 + '°C ' +
|
|
4196
|
-
', ' + value[18] / 6 + 'h:' + value[19] + 'm ' + value[20] / 10 + '°C ' +
|
|
4197
|
-
', ' + value[21] / 6 + 'h:' + value[22] + 'm ' + value[23] / 10 + '°C ' +
|
|
4198
|
-
', ' + value[24] / 6 + 'h:' + value[25] + 'm ' + value[26] / 10 + '°C ' +
|
|
4199
|
-
', ' + value[27] / 6 + 'h:' + value[28] + 'm ' + value[29] / 10 + '°C ',
|
|
4200
|
-
};
|
|
4201
|
-
case tuya.dataPoints.tvFridaySchedule:
|
|
4202
|
-
return {schedule_friday:
|
|
4203
|
-
' ' + value[0] / 6 + 'h:' + value[1] + 'm ' + value[2] / 10 + '°C' +
|
|
4204
|
-
', ' + value[3] / 6 + 'h:' + value[4] + 'm ' + value[5] / 10 + '°C' +
|
|
4205
|
-
', ' + value[6] / 6 + 'h:' + value[7] + 'm ' + value[8] / 10 + '°C' +
|
|
4206
|
-
', ' + value[9] / 6 + 'h:' + value[10] + 'm ' + value[11] / 10 + '°C' +
|
|
4207
|
-
', ' + value[12] / 6 + 'h:' + value[13] + 'm ' + value[14] / 10 + '°C ' +
|
|
4208
|
-
', ' + value[15] / 6 + 'h:' + value[16] + 'm ' + value[17] / 10 + '°C ' +
|
|
4209
|
-
', ' + value[18] / 6 + 'h:' + value[19] + 'm ' + value[20] / 10 + '°C ' +
|
|
4210
|
-
', ' + value[21] / 6 + 'h:' + value[22] + 'm ' + value[23] / 10 + '°C ' +
|
|
4211
|
-
', ' + value[24] / 6 + 'h:' + value[25] + 'm ' + value[26] / 10 + '°C ' +
|
|
4212
|
-
', ' + value[27] / 6 + 'h:' + value[28] + 'm ' + value[29] / 10 + '°C ',
|
|
4213
|
-
};
|
|
4214
|
-
case tuya.dataPoints.tvSaturdaySchedule:
|
|
4215
|
-
return {schedule_saturday:
|
|
4216
|
-
' ' + value[0] / 6 + 'h:' + value[1] + 'm ' + value[2] / 10 + '°C' +
|
|
4217
|
-
', ' + value[3] / 6 + 'h:' + value[4] + 'm ' + value[5] / 10 + '°C' +
|
|
4218
|
-
', ' + value[6] / 6 + 'h:' + value[7] + 'm ' + value[8] / 10 + '°C' +
|
|
4219
|
-
', ' + value[9] / 6 + 'h:' + value[10] + 'm ' + value[11] / 10 + '°C' +
|
|
4220
|
-
', ' + value[12] / 6 + 'h:' + value[13] + 'm ' + value[14] / 10 + '°C ' +
|
|
4221
|
-
', ' + value[15] / 6 + 'h:' + value[16] + 'm ' + value[17] / 10 + '°C ' +
|
|
4222
|
-
', ' + value[18] / 6 + 'h:' + value[19] + 'm ' + value[20] / 10 + '°C ' +
|
|
4223
|
-
', ' + value[21] / 6 + 'h:' + value[22] + 'm ' + value[23] / 10 + '°C ' +
|
|
4224
|
-
', ' + value[24] / 6 + 'h:' + value[25] + 'm ' + value[26] / 10 + '°C ' +
|
|
4225
|
-
', ' + value[27] / 6 + 'h:' + value[28] + 'm ' + value[29] / 10 + '°C ',
|
|
4226
|
-
};
|
|
4227
|
-
case tuya.dataPoints.tvSundaySchedule:
|
|
4228
|
-
return {schedule_sunday:
|
|
4229
|
-
' ' + value[0] / 6 + 'h:' + value[1] + 'm ' + value[2] / 10 + '°C' +
|
|
4230
|
-
', ' + value[3] / 6 + 'h:' + value[4] + 'm ' + value[5] / 10 + '°C' +
|
|
4231
|
-
', ' + value[6] / 6 + 'h:' + value[7] + 'm ' + value[8] / 10 + '°C' +
|
|
4232
|
-
', ' + value[9] / 6 + 'h:' + value[10] + 'm ' + value[11] / 10 + '°C' +
|
|
4233
|
-
', ' + value[12] / 6 + 'h:' + value[13] + 'm ' + value[14] / 10 + '°C ' +
|
|
4234
|
-
', ' + value[15] / 6 + 'h:' + value[16] + 'm ' + value[17] / 10 + '°C ' +
|
|
4235
|
-
', ' + value[18] / 6 + 'h:' + value[19] + 'm ' + value[20] / 10 + '°C ' +
|
|
4236
|
-
', ' + value[21] / 6 + 'h:' + value[22] + 'm ' + value[23] / 10 + '°C ' +
|
|
4237
|
-
', ' + value[24] / 6 + 'h:' + value[25] + 'm ' + value[26] / 10 + '°C ' +
|
|
4238
|
-
', ' + value[27] / 6 + 'h:' + value[28] + 'm ' + value[29] / 10 + '°C ',
|
|
4239
|
-
};
|
|
4240
|
-
|
|
4241
|
-
default:
|
|
4242
|
-
meta.logger.warn(`zigbee-herdsman-converters:tvtwo_thermostat: NOT RECOGNIZED DP #${
|
|
4243
|
-
dp} with data ${JSON.stringify(dpValue)}`);
|
|
4244
|
-
}
|
|
4245
|
-
},
|
|
4246
|
-
},
|
|
4247
4093
|
haozee_thermostat: {
|
|
4248
4094
|
cluster: 'manuSpecificTuya',
|
|
4249
4095
|
type: ['commandDataResponse', 'commandDataReport'],
|
package/converters/toZigbee.js
CHANGED
|
@@ -3518,91 +3518,6 @@ const converters = {
|
|
|
3518
3518
|
return tuya.sendDataPointRaw(entity, tuya.dataPoints.moesSschedule, payload);
|
|
3519
3519
|
},
|
|
3520
3520
|
},
|
|
3521
|
-
tvtwo_thermostat: {
|
|
3522
|
-
key: [
|
|
3523
|
-
'child_lock', 'open_window', 'open_window_temperature', 'frost_protection', 'heating_stop',
|
|
3524
|
-
'current_heating_setpoint', 'local_temperature_calibration', 'preset', 'boost_timeset_countdown',
|
|
3525
|
-
'holiday_start_stop', 'holiday_temperature', 'comfort_temperature', 'eco_temperature',
|
|
3526
|
-
'working_day', 'week_schedule_programming', 'online', 'holiday_mode_date',
|
|
3527
|
-
],
|
|
3528
|
-
convertSet: async (entity, key, value, meta) => {
|
|
3529
|
-
switch (key) {
|
|
3530
|
-
case 'preset': {
|
|
3531
|
-
const presetLookup = {'auto': 0, 'manual': 1, 'holiday': 3};
|
|
3532
|
-
await tuya.sendDataPointEnum(entity, tuya.dataPoints.tvMode, presetLookup[value]);
|
|
3533
|
-
return {state: {preset: value}};}
|
|
3534
|
-
case 'heating_stop':
|
|
3535
|
-
if (value == 'ON') {
|
|
3536
|
-
await tuya.sendDataPointBool(entity, tuya.dataPoints.tvHeatingStop, 1);
|
|
3537
|
-
} else {
|
|
3538
|
-
await tuya.sendDataPointEnum(entity, tuya.dataPoints.tvMode, 1 /* manual */);
|
|
3539
|
-
}
|
|
3540
|
-
break;
|
|
3541
|
-
case 'frost_protection':
|
|
3542
|
-
if (value == 'ON') {
|
|
3543
|
-
await tuya.sendDataPointBool(entity, tuya.dataPoints.tvFrostDetection, 1);
|
|
3544
|
-
} else {
|
|
3545
|
-
await tuya.sendDataPointEnum(entity, tuya.dataPoints.tvMode, 1 /* manual */);
|
|
3546
|
-
}
|
|
3547
|
-
break;
|
|
3548
|
-
case 'open_window':
|
|
3549
|
-
await tuya.sendDataPointBool(entity, tuya.dataPoints.tvWindowDetection, value === 'ON');
|
|
3550
|
-
break;
|
|
3551
|
-
case 'child_lock':
|
|
3552
|
-
await tuya.sendDataPointBool(entity, tuya.dataPoints.tvChildLock, value === 'LOCK');
|
|
3553
|
-
break;
|
|
3554
|
-
case 'local_temperature_calibration':
|
|
3555
|
-
if (value > 0) value = value*10;
|
|
3556
|
-
if (value < 0) value = value*10 + 0x100000000;
|
|
3557
|
-
await tuya.sendDataPointValue(entity, tuya.dataPoints.tvTempCalibration, value);
|
|
3558
|
-
break;
|
|
3559
|
-
case 'current_heating_setpoint':
|
|
3560
|
-
await tuya.sendDataPointValue(entity, tuya.dataPoints.tvHeatingSetpoint, value * 10);
|
|
3561
|
-
await utils.sleep(500);
|
|
3562
|
-
await tuya.sendDataPointEnum(entity, tuya.dataPoints.tvMode, 1 /* manual */);
|
|
3563
|
-
break;
|
|
3564
|
-
case 'holiday_temperature':
|
|
3565
|
-
await tuya.sendDataPointValue(entity, tuya.dataPoints.tvHolidayTemp, value * 10);
|
|
3566
|
-
break;
|
|
3567
|
-
case 'comfort_temperature':
|
|
3568
|
-
await tuya.sendDataPointValue(entity, tuya.dataPoints.tvComfortTemp, value * 10);
|
|
3569
|
-
break;
|
|
3570
|
-
case 'eco_temperature':
|
|
3571
|
-
await tuya.sendDataPointValue(entity, tuya.dataPoints.tvEcoTemp, value * 10);
|
|
3572
|
-
break;
|
|
3573
|
-
case 'boost_timeset_countdown':
|
|
3574
|
-
// set min 0 - max 465 sec boost time
|
|
3575
|
-
await tuya.sendDataPointValue(entity, tuya.dataPoints.tvBoostTime, value);
|
|
3576
|
-
break;
|
|
3577
|
-
case 'open_window_temperature':
|
|
3578
|
-
await tuya.sendDataPointValue(entity, tuya.dataPoints.tvOpenWindowTemp, value * 10);
|
|
3579
|
-
break;
|
|
3580
|
-
case 'holiday_start_stop': {
|
|
3581
|
-
const numberPattern = /\d+/g;
|
|
3582
|
-
value = value.match(numberPattern).join([]).toString();
|
|
3583
|
-
return tuya.sendDataPointStringBuffer(entity, tuya.dataPoints.tvHolidayMode, value);
|
|
3584
|
-
}
|
|
3585
|
-
case 'online':
|
|
3586
|
-
// 115 online / Is the device online
|
|
3587
|
-
await tuya.sendDataPointBool(entity, tuya.dataPoints.tvBoostMode, value === 'ON');
|
|
3588
|
-
break;
|
|
3589
|
-
case 'working_day': {
|
|
3590
|
-
// DP-31, Send and Report, ENUM, Week select 0 - 5 days, 1 - 6 days, 2 - 7 days
|
|
3591
|
-
const workLookup = {'0': 0, '1': 1, '2': 2, '3': 3};
|
|
3592
|
-
const workDay = workLookup[value];
|
|
3593
|
-
await tuya.sendDataPointEnum(entity, tuya.dataPoints.tvWorkingDay, workDay);
|
|
3594
|
-
return {state: {working_day: value}};
|
|
3595
|
-
}
|
|
3596
|
-
case 'week_schedule_programming':
|
|
3597
|
-
// DP-106, Send Only, raw, week_program3_day
|
|
3598
|
-
await tuya.sendDataPointRaw(entity, tuya.dataPoints.tvWeekSchedule, value);
|
|
3599
|
-
break;
|
|
3600
|
-
|
|
3601
|
-
default: // Unknown key
|
|
3602
|
-
meta.logger.warn(`toZigbee.tvtwo_thermostat: Unhandled key ${key}`);
|
|
3603
|
-
}
|
|
3604
|
-
},
|
|
3605
|
-
},
|
|
3606
3521
|
haozee_thermostat_system_mode: {
|
|
3607
3522
|
key: ['preset'],
|
|
3608
3523
|
convertSet: async (entity, key, value, meta) => {
|
|
@@ -4346,6 +4261,7 @@ const converters = {
|
|
|
4346
4261
|
convertSet: async (entity, key, value, meta) => {
|
|
4347
4262
|
const payload = {0x4000: {value, type: 0x30}};
|
|
4348
4263
|
await entity.write('hvacThermostat', payload, manufacturerOptions.eurotronic);
|
|
4264
|
+
return {state: {[key]: value}};
|
|
4349
4265
|
},
|
|
4350
4266
|
convertGet: async (entity, key, meta) => {
|
|
4351
4267
|
await entity.read('hvacThermostat', [0x4000], manufacturerOptions.eurotronic);
|
package/devices/awox.js
CHANGED
|
@@ -155,7 +155,7 @@ module.exports = [
|
|
|
155
155
|
model: '33957',
|
|
156
156
|
vendor: 'AwoX',
|
|
157
157
|
description: 'LED light with color temperature',
|
|
158
|
-
extend: extend.light_onoff_brightness_colortemp({colorTempRange: [153,
|
|
158
|
+
extend: extend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
|
|
159
159
|
whiteLabel: [{vendor: 'EGLO', model: '12239'}],
|
|
160
160
|
},
|
|
161
161
|
{
|
package/devices/develco.js
CHANGED
|
@@ -27,6 +27,27 @@ const develcoLedControlMap = {
|
|
|
27
27
|
|
|
28
28
|
// develco specific convertors
|
|
29
29
|
const develco = {
|
|
30
|
+
configure: {
|
|
31
|
+
read_sw_hw_version: async (device, logger) => {
|
|
32
|
+
for (const ep of device.endpoints) {
|
|
33
|
+
if (ep.supportsInputCluster('genBasic')) {
|
|
34
|
+
try {
|
|
35
|
+
const data = await ep.read('genBasic', ['develcoPrimarySwVersion', 'develcoPrimaryHwVersion'],
|
|
36
|
+
manufacturerOptions);
|
|
37
|
+
|
|
38
|
+
if (data.hasOwnProperty('develcoPrimarySwVersion')) {
|
|
39
|
+
device.softwareBuildID = data.develcoPrimarySwVersion.join('.');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (data.hasOwnProperty('develcoPrimaryHwVersion')) {
|
|
43
|
+
device.hardwareVersion = data.develcoPrimaryHwVersion.join('.');
|
|
44
|
+
}
|
|
45
|
+
} catch (error) {/* catch timeouts of sleeping devices */}
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
},
|
|
30
51
|
fz: {
|
|
31
52
|
// SPLZB-134 and SPLZB-131 reports strange values sometimes
|
|
32
53
|
// https://github.com/Koenkk/zigbee2mqtt/issues/13329
|
|
@@ -86,24 +107,6 @@ const develco = {
|
|
|
86
107
|
return result;
|
|
87
108
|
},
|
|
88
109
|
},
|
|
89
|
-
firmware_version: {
|
|
90
|
-
cluster: 'genBasic',
|
|
91
|
-
type: ['attributeReport', 'readResponse'],
|
|
92
|
-
convert: (model, msg, publish, options, meta) => {
|
|
93
|
-
const result = {};
|
|
94
|
-
if (msg.data.hasOwnProperty('develcoPrimarySwVersion')) {
|
|
95
|
-
const firmware = msg.data.develcoPrimarySwVersion.join('.');
|
|
96
|
-
result.current_firmware = firmware;
|
|
97
|
-
meta.device.softwareBuildID = firmware;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (msg.data.hasOwnProperty('develcoPrimaryHwVersion')) {
|
|
101
|
-
meta.device.hardwareVersion = msg.data.develcoPrimaryHwVersion.join('.');
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return result;
|
|
105
|
-
},
|
|
106
|
-
},
|
|
107
110
|
fault_status: {
|
|
108
111
|
cluster: 'genBinaryInput',
|
|
109
112
|
type: ['attributeReport', 'readResponse'],
|
|
@@ -374,12 +377,11 @@ module.exports = [
|
|
|
374
377
|
model: 'EMIZB-132',
|
|
375
378
|
vendor: 'Develco',
|
|
376
379
|
description: 'Wattle AMS HAN power-meter sensor',
|
|
377
|
-
fromZigbee: [develco.fz.metering, develco.fz.electrical_measurement
|
|
380
|
+
fromZigbee: [develco.fz.metering, develco.fz.electrical_measurement],
|
|
378
381
|
toZigbee: [tz.EMIZB_132_mode],
|
|
379
382
|
ota: ota.zigbeeOTA,
|
|
380
383
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
381
384
|
const endpoint = device.getEndpoint(2);
|
|
382
|
-
await endpoint.read('genBasic', ['develcoPrimarySwVersion', 'develcoPrimaryHwVersion'], manufacturerOptions);
|
|
383
385
|
await reporting.bind(endpoint, coordinatorEndpoint, ['haElectricalMeasurement', 'seMetering']);
|
|
384
386
|
|
|
385
387
|
try {
|
|
@@ -398,6 +400,7 @@ module.exports = [
|
|
|
398
400
|
await reporting.instantaneousDemand(endpoint);
|
|
399
401
|
await reporting.currentSummDelivered(endpoint);
|
|
400
402
|
await reporting.currentSummReceived(endpoint);
|
|
403
|
+
await develco.configure.read_sw_hw_version(device, logger);
|
|
401
404
|
},
|
|
402
405
|
exposes: [e.power(), e.energy(), e.current(), e.voltage(), e.current_phase_b(), e.voltage_phase_b(), e.current_phase_c(),
|
|
403
406
|
e.voltage_phase_c()],
|
|
@@ -415,7 +418,7 @@ module.exports = [
|
|
|
415
418
|
vendor: 'Develco',
|
|
416
419
|
description: 'Smoke detector with siren',
|
|
417
420
|
fromZigbee: [fz.temperature, fz.battery, fz.ias_smoke_alarm_1_develco, fz.ignore_basic_report,
|
|
418
|
-
|
|
421
|
+
fz.ias_enroll, fz.ias_wd, develco.fz.fault_status],
|
|
419
422
|
toZigbee: [tz.warning, tz.ias_max_duration, tz.warning_simple],
|
|
420
423
|
ota: ota.zigbeeOTA,
|
|
421
424
|
meta: {battery: {voltageToPercentage: '3V_2500'}},
|
|
@@ -424,7 +427,6 @@ module.exports = [
|
|
|
424
427
|
|
|
425
428
|
await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg', 'ssIasZone', 'ssIasWd', 'genBasic', 'genBinaryInput']);
|
|
426
429
|
await reporting.batteryVoltage(endpoint);
|
|
427
|
-
await endpoint.read('genBasic', ['develcoPrimarySwVersion', 'develcoPrimaryHwVersion'], manufacturerOptions);
|
|
428
430
|
await endpoint.read('ssIasZone', ['iasCieAddr', 'zoneState', 'zoneId']);
|
|
429
431
|
await endpoint.read('genBinaryInput', ['reliability', 'statusFlags']);
|
|
430
432
|
await endpoint.read('ssIasWd', ['maxDuration']);
|
|
@@ -432,6 +434,8 @@ module.exports = [
|
|
|
432
434
|
const endpoint2 = device.getEndpoint(38);
|
|
433
435
|
await reporting.bind(endpoint2, coordinatorEndpoint, ['msTemperatureMeasurement']);
|
|
434
436
|
await reporting.temperature(endpoint2, {min: constants.repInterval.MINUTE, max: constants.repInterval.MINUTES_10, change: 10});
|
|
437
|
+
|
|
438
|
+
await develco.configure.read_sw_hw_version(device, logger);
|
|
435
439
|
},
|
|
436
440
|
endpoint: (device) => {
|
|
437
441
|
return {default: 35};
|
|
@@ -449,7 +453,7 @@ module.exports = [
|
|
|
449
453
|
vendor: 'Develco',
|
|
450
454
|
description: 'Fire detector with siren',
|
|
451
455
|
fromZigbee: [fz.temperature, fz.battery, fz.ias_smoke_alarm_1_develco, fz.ignore_basic_report,
|
|
452
|
-
|
|
456
|
+
fz.ias_enroll, fz.ias_wd, develco.fz.fault_status],
|
|
453
457
|
toZigbee: [tz.warning, tz.ias_max_duration, tz.warning_simple],
|
|
454
458
|
meta: {battery: {voltageToPercentage: '3V_2500'}},
|
|
455
459
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
@@ -457,7 +461,6 @@ module.exports = [
|
|
|
457
461
|
|
|
458
462
|
await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg', 'ssIasZone', 'ssIasWd', 'genBasic', 'genBinaryInput']);
|
|
459
463
|
await reporting.batteryVoltage(endpoint);
|
|
460
|
-
await endpoint.read('genBasic', ['develcoPrimarySwVersion'], manufacturerOptions);
|
|
461
464
|
await endpoint.read('ssIasZone', ['iasCieAddr', 'zoneState', 'zoneId']);
|
|
462
465
|
await endpoint.read('genBinaryInput', ['reliability', 'statusFlags']);
|
|
463
466
|
await endpoint.read('ssIasWd', ['maxDuration']);
|
|
@@ -465,6 +468,8 @@ module.exports = [
|
|
|
465
468
|
const endpoint2 = device.getEndpoint(38);
|
|
466
469
|
await reporting.bind(endpoint2, coordinatorEndpoint, ['msTemperatureMeasurement']);
|
|
467
470
|
await reporting.temperature(endpoint2, {min: constants.repInterval.MINUTE, max: constants.repInterval.MINUTES_10, change: 10});
|
|
471
|
+
|
|
472
|
+
await develco.configure.read_sw_hw_version(device, logger);
|
|
468
473
|
},
|
|
469
474
|
endpoint: (device) => {
|
|
470
475
|
return {default: 35};
|
|
@@ -492,6 +497,8 @@ module.exports = [
|
|
|
492
497
|
await reporting.bind(endpoint38, coordinatorEndpoint, ['msTemperatureMeasurement']);
|
|
493
498
|
await reporting.batteryVoltage(endpoint35);
|
|
494
499
|
await reporting.temperature(endpoint38);
|
|
500
|
+
|
|
501
|
+
await develco.configure.read_sw_hw_version(device, logger);
|
|
495
502
|
},
|
|
496
503
|
},
|
|
497
504
|
{
|
|
@@ -519,16 +526,28 @@ module.exports = [
|
|
|
519
526
|
description: 'Motion sensor',
|
|
520
527
|
fromZigbee: [
|
|
521
528
|
fz.temperature, fz.illuminance, fz.ias_occupancy_alarm_1, fz.battery,
|
|
522
|
-
develco.fz.led_control, develco.fz.ias_occupancy_timeout,
|
|
529
|
+
develco.fz.led_control, develco.fz.ias_occupancy_timeout,
|
|
523
530
|
],
|
|
524
531
|
toZigbee: [develco.tz.led_control, develco.tz.ias_occupancy_timeout],
|
|
525
|
-
exposes:
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
+
exposes: (device, options) => {
|
|
533
|
+
const dynExposes = [];
|
|
534
|
+
dynExposes.push(e.occupancy());
|
|
535
|
+
if (device && device.softwareBuildID && device.softwareBuildID.split('.')[0] >= 3) {
|
|
536
|
+
dynExposes.push(exposes.numeric('occupancy_timeout', ea.ALL).withUnit('second').
|
|
537
|
+
withValueMin(20).withValueMax(65535));
|
|
538
|
+
}
|
|
539
|
+
dynExposes.push(e.temperature());
|
|
540
|
+
dynExposes.push(e.illuminance_lux());
|
|
541
|
+
dynExposes.push(e.tamper());
|
|
542
|
+
dynExposes.push(e.battery_low());
|
|
543
|
+
dynExposes.push(e.battery());
|
|
544
|
+
if (device && device.softwareBuildID && device.softwareBuildID.split('.')[0] >= 4) {
|
|
545
|
+
dynExposes.push(exposes.enum('led_control', ea.ALL, ['off', 'fault_only', 'motion_only', 'both']).
|
|
546
|
+
withDescription('Control LED indicator usage.'));
|
|
547
|
+
}
|
|
548
|
+
dynExposes.push(e.linkquality());
|
|
549
|
+
return dynExposes;
|
|
550
|
+
},
|
|
532
551
|
meta: {battery: {voltageToPercentage: '3V_2500'}},
|
|
533
552
|
endpoint: (device) => {
|
|
534
553
|
return {default: 35};
|
|
@@ -547,12 +566,15 @@ module.exports = [
|
|
|
547
566
|
const endpoint35 = device.getEndpoint(35);
|
|
548
567
|
await reporting.bind(endpoint35, coordinatorEndpoint, ['genPowerCfg']);
|
|
549
568
|
await reporting.batteryVoltage(endpoint35, {min: constants.repInterval.HOUR, max: 43200, change: 100});
|
|
550
|
-
await endpoint35.read('genBasic', ['develcoPrimarySwVersion', 'develcoPrimaryHwVersion'], manufacturerOptions);
|
|
551
569
|
|
|
552
|
-
|
|
570
|
+
// zigbee2mqtt#14277 some features are not available on older firmwares
|
|
571
|
+
await develco.configure.read_sw_hw_version(device, logger);
|
|
572
|
+
if (device && device.softwareBuildID && device.softwareBuildID.split('.')[0] >= 3) {
|
|
553
573
|
await endpoint35.read('ssIasZone', ['develcoAlarmOffDelay'], manufacturerOptions);
|
|
574
|
+
}
|
|
575
|
+
if (device && device.softwareBuildID && device.softwareBuildID.split('.')[0] >= 4) {
|
|
554
576
|
await endpoint35.read('genBasic', ['develcoLedControl'], manufacturerOptions);
|
|
555
|
-
}
|
|
577
|
+
}
|
|
556
578
|
},
|
|
557
579
|
},
|
|
558
580
|
{
|
|
@@ -670,6 +692,8 @@ module.exports = [
|
|
|
670
692
|
await reporting.temperature(endpoint, {min: constants.repInterval.MINUTE, max: constants.repInterval.MINUTES_10, change: 10});
|
|
671
693
|
await reporting.humidity(endpoint, {min: constants.repInterval.MINUTE, max: constants.repInterval.MINUTES_10, change: 300});
|
|
672
694
|
await reporting.batteryVoltage(endpoint, {min: constants.repInterval.HOUR, max: 43200, change: 100});
|
|
695
|
+
|
|
696
|
+
await develco.configure.read_sw_hw_version(device, logger);
|
|
673
697
|
},
|
|
674
698
|
},
|
|
675
699
|
{
|
|
@@ -677,19 +701,20 @@ module.exports = [
|
|
|
677
701
|
model: 'SIRZB-110',
|
|
678
702
|
vendor: 'Develco',
|
|
679
703
|
description: 'Customizable siren',
|
|
680
|
-
fromZigbee: [fz.temperature, fz.battery, fz.ias_enroll, fz.ias_wd,
|
|
704
|
+
fromZigbee: [fz.temperature, fz.battery, fz.ias_enroll, fz.ias_wd, fz.ias_siren],
|
|
681
705
|
toZigbee: [tz.warning, tz.warning_simple, tz.ias_max_duration, tz.squawk],
|
|
682
706
|
meta: {battery: {voltageToPercentage: '3V_2500'}},
|
|
683
707
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
684
708
|
const endpoint = device.getEndpoint(43);
|
|
685
709
|
await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg', 'ssIasZone', 'ssIasWd', 'genBasic']);
|
|
686
710
|
await reporting.batteryVoltage(endpoint);
|
|
687
|
-
await endpoint.read('genBasic', ['develcoPrimarySwVersion', 'develcoPrimaryHwVersion'], manufacturerOptions);
|
|
688
711
|
await endpoint.read('ssIasZone', ['iasCieAddr', 'zoneState', 'zoneId']);
|
|
689
712
|
await endpoint.read('ssIasWd', ['maxDuration']);
|
|
690
713
|
|
|
691
714
|
const endpoint2 = device.getEndpoint(1);
|
|
692
715
|
await reporting.bind(endpoint2, coordinatorEndpoint, ['genOnOff']);
|
|
716
|
+
|
|
717
|
+
await develco.configure.read_sw_hw_version(device, logger);
|
|
693
718
|
},
|
|
694
719
|
endpoint: (device) => {
|
|
695
720
|
return {default: 43};
|
|
@@ -743,7 +768,7 @@ module.exports = [
|
|
|
743
768
|
model: 'IOMZB-110',
|
|
744
769
|
vendor: 'Develco',
|
|
745
770
|
description: 'IO module',
|
|
746
|
-
fromZigbee: [fz.on_off, develco.fz.input
|
|
771
|
+
fromZigbee: [fz.on_off, develco.fz.input],
|
|
747
772
|
toZigbee: [tz.on_off, develco.tz.input],
|
|
748
773
|
meta: {multiEndpoint: true},
|
|
749
774
|
exposes: [
|
|
@@ -755,12 +780,9 @@ module.exports = [
|
|
|
755
780
|
exposes.switch().withState('state', true, 'On/off state of switch 2').withEndpoint('l12'),
|
|
756
781
|
],
|
|
757
782
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
758
|
-
const options = {manufacturerCode: 4117};
|
|
759
|
-
|
|
760
783
|
const ep2 = device.getEndpoint(112);
|
|
761
784
|
await reporting.bind(ep2, coordinatorEndpoint, ['genBinaryInput', 'genBasic']);
|
|
762
785
|
await reporting.presentValue(ep2, {min: 0});
|
|
763
|
-
await ep2.read('genBasic', ['develcoPrimarySwVersion', 'develcoPrimaryHwVersion'], options);
|
|
764
786
|
|
|
765
787
|
const ep3 = device.getEndpoint(113);
|
|
766
788
|
await reporting.bind(ep3, coordinatorEndpoint, ['genBinaryInput']);
|
|
@@ -781,6 +803,8 @@ module.exports = [
|
|
|
781
803
|
const ep7 = device.getEndpoint(117);
|
|
782
804
|
await reporting.bind(ep7, coordinatorEndpoint, ['genOnOff']);
|
|
783
805
|
await reporting.onOff(ep7);
|
|
806
|
+
|
|
807
|
+
await develco.configure.read_sw_hw_version(device, logger);
|
|
784
808
|
},
|
|
785
809
|
|
|
786
810
|
endpoint: (device) => {
|
package/devices/hornbach.js
CHANGED
|
@@ -20,7 +20,7 @@ module.exports = [
|
|
|
20
20
|
model: '10011723',
|
|
21
21
|
vendor: 'HORNBACH',
|
|
22
22
|
description: 'FLAIR Viyu Smart LED bulb CCT E27',
|
|
23
|
-
extend: extend.light_onoff_brightness_colortemp(),
|
|
23
|
+
extend: extend.light_onoff_brightness_colortemp({colorTempRange: [153, 370]}),
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
zigbeeModel: ['VIYU-C35-470-CCT-10011722'],
|
package/devices/immax.js
CHANGED
|
@@ -23,7 +23,7 @@ module.exports = [
|
|
|
23
23
|
model: '07089L',
|
|
24
24
|
vendor: 'Immax',
|
|
25
25
|
description: 'NEO SMART LED E27 5W',
|
|
26
|
-
extend: extend.light_onoff_brightness_colortemp(),
|
|
26
|
+
extend: extend.light_onoff_brightness_colortemp({colorTempRange: [153, 370]}),
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
29
|
zigbeeModel: ['E27-filament-Dim-ZB3.0'],
|
package/devices/lonsonho.js
CHANGED
|
@@ -84,7 +84,10 @@ module.exports = [
|
|
|
84
84
|
exposes: [
|
|
85
85
|
exposes.enum('moving', ea.STATE, ['UP', 'STOP', 'DOWN']).withEndpoint('left'),
|
|
86
86
|
exposes.enum('moving', ea.STATE, ['UP', 'STOP', 'DOWN']).withEndpoint('right'),
|
|
87
|
-
exposes.numeric('calibration_time', ea.STATE).withUnit('S').withDescription('Calibration time')
|
|
87
|
+
exposes.numeric('calibration_time', ea.STATE).withUnit('S').withDescription('Calibration time')
|
|
88
|
+
.withEndpoint('left'),
|
|
89
|
+
exposes.numeric('calibration_time', ea.STATE).withUnit('S').withDescription('Calibration time')
|
|
90
|
+
.withEndpoint('right'),
|
|
88
91
|
e.cover_position().withEndpoint('left'), exposes.binary('calibration', ea.ALL, 'ON', 'OFF')
|
|
89
92
|
.withEndpoint('left'), exposes.binary('motor_reversal', ea.ALL, 'ON', 'OFF').withEndpoint('left'),
|
|
90
93
|
e.cover_position().withEndpoint('right'), exposes.binary('calibration', ea.ALL, 'ON', 'OFF')
|
package/devices/moes.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const exposes = require('../lib/exposes');
|
|
2
|
-
const fz =
|
|
2
|
+
const fz = require('../converters/fromZigbee');
|
|
3
3
|
const tz = require('../converters/toZigbee');
|
|
4
4
|
const ota = require('../lib/ota');
|
|
5
5
|
const tuya = require('../lib/tuya');
|
|
@@ -26,11 +26,13 @@ module.exports = [
|
|
|
26
26
|
model: 'ZP-LZ-FR2U',
|
|
27
27
|
vendor: 'Moes',
|
|
28
28
|
description: 'Zigbee 3.0 dual USB wireless socket plug',
|
|
29
|
-
fromZigbee: [fz.on_off, fz.tuya_switch_power_outage_memory, fz.ts011f_plug_child_mode],
|
|
30
|
-
toZigbee: [tz.on_off, tz.tuya_switch_power_outage_memory, tz.ts011f_plug_child_mode],
|
|
29
|
+
fromZigbee: [fz.on_off, fz.tuya_switch_power_outage_memory, fz.ts011f_plug_indicator_mode, fz.ts011f_plug_child_mode],
|
|
30
|
+
toZigbee: [tz.on_off, tz.tuya_switch_power_outage_memory, tz.ts011f_plug_indicator_mode, tz.ts011f_plug_child_mode],
|
|
31
31
|
exposes: [e.switch().withEndpoint('l1'), e.switch().withEndpoint('l2'),
|
|
32
32
|
exposes.enum('power_outage_memory', ea.ALL, ['on', 'off', 'restore'])
|
|
33
|
-
.withDescription('Recover state after power outage'),
|
|
33
|
+
.withDescription('Recover state after power outage'),
|
|
34
|
+
exposes.enum('indicator_mode', ea.ALL, ['off', 'off/on', 'on/off', 'on'])
|
|
35
|
+
.withDescription('Plug LED indicator mode'), e.child_lock()],
|
|
34
36
|
endpoint: (device) => {
|
|
35
37
|
return {'l1': 1, 'l2': 2};
|
|
36
38
|
},
|
package/devices/perenio.js
CHANGED
|
@@ -247,7 +247,6 @@ module.exports = [
|
|
|
247
247
|
vendor: 'Perenio',
|
|
248
248
|
description: 'Flood alarm device',
|
|
249
249
|
fromZigbee: [fz.ias_water_leak_alarm_1, fz.ignore_basic_report, fz.battery],
|
|
250
|
-
meta: {battery: {dontDividePercentage: true}},
|
|
251
250
|
toZigbee: [],
|
|
252
251
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
253
252
|
const endpoint = device.getEndpoint(1);
|
package/devices/philips.js
CHANGED
|
@@ -932,7 +932,7 @@ module.exports = [
|
|
|
932
932
|
extend: hueExtend.light_onoff_brightness_colortemp_color(),
|
|
933
933
|
},
|
|
934
934
|
{
|
|
935
|
-
zigbeeModel: ['LCL001'],
|
|
935
|
+
zigbeeModel: ['LCL001', 'LCL006'],
|
|
936
936
|
model: '8718699703424',
|
|
937
937
|
vendor: 'Philips',
|
|
938
938
|
description: 'Hue white and color ambiance LightStrip plus',
|
package/devices/shinasystem.js
CHANGED
|
@@ -537,6 +537,40 @@ module.exports = [
|
|
|
537
537
|
}]);
|
|
538
538
|
},
|
|
539
539
|
},
|
|
540
|
+
{
|
|
541
|
+
zigbeeModel: ['PMM-300Z3'],
|
|
542
|
+
model: 'PMM-300Z3',
|
|
543
|
+
vendor: 'ShinaSystem',
|
|
544
|
+
description: 'SiHAS 3phase energy monitor',
|
|
545
|
+
fromZigbee: [fz.electrical_measurement, fz.metering, fz.temperature],
|
|
546
|
+
toZigbee: [tz.metering_power, tz.currentsummdelivered, tz.frequency, tz.powerfactor, tz.acvoltage, tz.accurrent, tz.temperature],
|
|
547
|
+
exposes: [e.power().withAccess(ea.STATE_GET), e.energy().withAccess(ea.STATE_GET),
|
|
548
|
+
e.current().withAccess(ea.STATE_GET), e.voltage().withAccess(ea.STATE_GET),
|
|
549
|
+
e.temperature().withAccess(ea.STATE_GET).withDescription('temperature of device internal mcu'),
|
|
550
|
+
exposes.numeric('power_factor', ea.STATE_GET).withDescription('Measured electrical power factor'),
|
|
551
|
+
exposes.numeric('ac_frequency', ea.STATE_GET).withUnit('Hz').withDescription('Measured electrical ac frequency')],
|
|
552
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
553
|
+
const endpoint = device.getEndpoint(1);
|
|
554
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['haElectricalMeasurement', 'seMetering', 'msTemperatureMeasurement']);
|
|
555
|
+
await endpoint.read('haElectricalMeasurement', ['acVoltageMultiplier', 'acVoltageDivisor', 'acCurrentMultiplier',
|
|
556
|
+
'acCurrentDivisor']);
|
|
557
|
+
await endpoint.read('seMetering', ['multiplier', 'divisor']);
|
|
558
|
+
// await reporting.activePower(endpoint, {min: 1, max: 600, change: 5}); // no need, duplicate for power value.
|
|
559
|
+
await reporting.instantaneousDemand(endpoint, {min: 1, max: 600, change: 5});
|
|
560
|
+
await reporting.powerFactor(endpoint, {min: 10, max: 600, change: 1});
|
|
561
|
+
await reporting.rmsVoltage(endpoint, {min: 5, max: 600, change: 1});
|
|
562
|
+
await reporting.rmsCurrent(endpoint, {min: 5, max: 600, change: 1});
|
|
563
|
+
await reporting.currentSummDelivered(endpoint, {min: 1, max: 600, change: 5});
|
|
564
|
+
await reporting.temperature(endpoint, {min: 20, max: 300, change: 10});
|
|
565
|
+
endpoint.saveClusterAttributeKeyValue('haElectricalMeasurement', {acFrequencyMultiplier: 1, acFrequencyDivisor: 10});
|
|
566
|
+
await endpoint.configureReporting('haElectricalMeasurement', [{
|
|
567
|
+
attribute: 'acFrequency',
|
|
568
|
+
minimumReportInterval: 10,
|
|
569
|
+
maximumReportInterval: 600,
|
|
570
|
+
reportableChange: 3,
|
|
571
|
+
}]);
|
|
572
|
+
},
|
|
573
|
+
},
|
|
540
574
|
{
|
|
541
575
|
zigbeeModel: ['DLM-300Z'],
|
|
542
576
|
model: 'DLM-300Z',
|
package/devices/tuya.js
CHANGED
|
@@ -22,7 +22,7 @@ const TS011Fplugs = ['_TZ3000_5f43h46b', '_TZ3000_cphmq0q7', '_TZ3000_dpo1ysak',
|
|
|
22
22
|
'_TZ3000_zloso4jk', '_TZ3000_r6buo8ba', '_TZ3000_iksasdbv', '_TZ3000_idrffznf', '_TZ3000_okaz9tjs', '_TZ3210_q7oryllx',
|
|
23
23
|
'_TZ3000_ss98ec5d', '_TZ3000_gznh2xla', '_TZ3000_hdopuwv6', '_TZ3000_gvn91tmx', '_TZ3000_dksbtrzs', '_TZ3000_b28wrpvx',
|
|
24
24
|
'_TZ3000_aim0ztek', '_TZ3000_mlswgkc3', '_TZ3000_7dndcnnb', '_TZ3000_waho4jtj', '_TZ3000_nmsciidq', '_TZ3000_jtgxgmks',
|
|
25
|
-
'_TZ3000_rdfh8cfs', '_TZ3000_yujkchbz'];
|
|
25
|
+
'_TZ3000_rdfh8cfs', '_TZ3000_yujkchbz', '_TZ3000_fgwhjm9j'];
|
|
26
26
|
|
|
27
27
|
const tzLocal = {
|
|
28
28
|
SA12IZL_silence_siren: {
|
|
@@ -1079,7 +1079,7 @@ module.exports = [
|
|
|
1079
1079
|
},
|
|
1080
1080
|
},
|
|
1081
1081
|
{
|
|
1082
|
-
fingerprint:
|
|
1082
|
+
fingerprint: tuya.fingerprint('TS0202', ['_TZ3000_mcxw5ehu', '_TZ3040_6ygjfyll']),
|
|
1083
1083
|
model: 'IH012-RT01',
|
|
1084
1084
|
vendor: 'TuYa',
|
|
1085
1085
|
description: 'Motion sensor',
|
|
@@ -2014,7 +2014,6 @@ module.exports = [
|
|
|
2014
2014
|
{modelID: 'TS0601', manufacturerName: '_TZE200_cpmgn2cf'},
|
|
2015
2015
|
{modelID: 'TS0601', manufacturerName: '_TZE200_4eeyebrt'}, // Immax 07732B
|
|
2016
2016
|
{modelID: 'TS0601', manufacturerName: '_TZE200_8whxpsiw'}, // EVOLVEO
|
|
2017
|
-
{modelID: 'TS0601', manufacturerName: '_TZE200_bvu2wnxz'}, /* model: 'TRV06', vendor: 'AVATTO' */
|
|
2018
2017
|
],
|
|
2019
2018
|
model: 'TS0601_thermostat',
|
|
2020
2019
|
vendor: 'TuYa',
|
|
@@ -2059,15 +2058,16 @@ module.exports = [
|
|
|
2059
2058
|
.withFeature(exposes.text('holidays_schedule', ea.STATE_SET))],
|
|
2060
2059
|
},
|
|
2061
2060
|
{
|
|
2062
|
-
fingerprint: [
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2061
|
+
fingerprint: tuya.fingerprint('TS0601', [
|
|
2062
|
+
'_TZE200_hue3yfsn', /* model: 'TV02-Zigbee', vendor: 'TuYa' */
|
|
2063
|
+
'_TZE200_e9ba97vf', /* model: 'TV01-ZB', vendor: 'Moes' */
|
|
2064
|
+
'_TZE200_husqqvux', /* model: 'TSL-TRV-TV01ZG', vendor: 'Tesla Smart' */
|
|
2065
|
+
'_TZE200_lnbfnyxd', /* model: 'TSL-TRV-TV01ZG', vendor: 'Tesla Smart' */
|
|
2066
|
+
'_TZE200_lllliz3p', /* model: 'TV02-Zigbee', vendor: 'TuYa' */
|
|
2067
|
+
'_TZE200_mudxchsu', /* model: 'TV05-ZG curve', vendor: 'TuYa' */
|
|
2068
|
+
'_TZE200_7yoranx2', /* model: 'TV01-ZB', vendor: 'Moes' */
|
|
2069
|
+
'_TZE200_kds0pmmv', /* model: 'TV01-ZB', vendor: 'Moes' */
|
|
2070
|
+
]),
|
|
2071
2071
|
model: 'TV02-Zigbee',
|
|
2072
2072
|
vendor: 'TuYa',
|
|
2073
2073
|
description: 'Thermostat radiator valve',
|
|
@@ -2078,30 +2078,49 @@ module.exports = [
|
|
|
2078
2078
|
{vendor: 'Unknown/id3.pl', model: 'GTZ08'},
|
|
2079
2079
|
],
|
|
2080
2080
|
ota: ota.zigbeeOTA,
|
|
2081
|
-
fromZigbee: [
|
|
2082
|
-
toZigbee: [
|
|
2081
|
+
fromZigbee: [tuya.fzDataPoints],
|
|
2082
|
+
toZigbee: [tuya.tzDataPoints],
|
|
2083
2083
|
onEvent: tuya.onEventSetLocalTime,
|
|
2084
|
+
configure: tuya.configureMagicPacket,
|
|
2084
2085
|
exposes: [
|
|
2085
|
-
e.
|
|
2086
|
-
e.comfort_temperature().withValueMin(
|
|
2087
|
-
exposes.climate().
|
|
2088
|
-
|
|
2086
|
+
e.battery(), e.child_lock(), e.open_window(), e.open_window_temperature().withValueMin(5).withValueMax(30),
|
|
2087
|
+
e.comfort_temperature().withValueMin(5).withValueMax(30), e.eco_temperature().withValueMin(5).withValueMax(30),
|
|
2088
|
+
exposes.climate().withSystemMode(['off', 'heat'], ea.STATE_SET, 'When switched to the "off" mode, the device will display ' +
|
|
2089
|
+
'"HS" and the valve will be fully closed. Press the pair button to cancel or switch back to "heat" mode. Battery life ' +
|
|
2090
|
+
'can be prolonged by switching the heating off. After switching to `heat` mode, `preset` will be reset to `auto` and ' +
|
|
2091
|
+
'after changing `preset` to `manual` temperature setpoint will be 20 degrees.').withPreset(['auto', 'manual', 'holiday'],
|
|
2092
|
+
'`auto` uses schedule properties, check them. `manual` allows you to control the device, `holiday` uses ' +
|
|
2093
|
+
'`holiday_start_stop` and `holiday_temperature` properties.').withLocalTemperatureCalibration(-5, 5, 0.1, ea.STATE_SET)
|
|
2094
|
+
.withLocalTemperature(ea.STATE).withSetpoint('current_heating_setpoint', 5, 30, 0.5, ea.STATE_SET),
|
|
2089
2095
|
exposes.numeric('boost_timeset_countdown', ea.STATE_SET).withUnit('second').withDescription('Setting '+
|
|
2090
2096
|
'minimum 0 - maximum 465 seconds boost time. The boost (♨) function is activated. The remaining '+
|
|
2091
2097
|
'time for the function will be counted down in seconds ( 465 to 0 ).').withValueMin(0).withValueMax(465),
|
|
2092
2098
|
exposes.binary('frost_protection', ea.STATE_SET, 'ON', 'OFF').withDescription('When Anti-Freezing function'+
|
|
2093
2099
|
' is activated, the temperature in the house is kept at 8 °C, the device display "AF".press the '+
|
|
2094
2100
|
'pair button to cancel.'),
|
|
2095
|
-
exposes.binary('heating_stop', ea.STATE_SET, 'ON', 'OFF').withDescription('
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2101
|
+
exposes.binary('heating_stop', ea.STATE_SET, 'ON', 'OFF').withDescription('Same as `system_mode`. Left for compatibility.'),
|
|
2102
|
+
exposes.numeric('holiday_temperature', ea.STATE_SET).withUnit('°C').withDescription('Holiday temperature')
|
|
2103
|
+
.withValueMin(5).withValueMax(30),
|
|
2104
|
+
exposes.text('holiday_start_stop', ea.STATE_SET).withDescription('The holiday mode will automatically start ' +
|
|
2105
|
+
'at the set time starting point and run the holiday temperature. Can be defined in the following format: ' +
|
|
2106
|
+
'`startYear/startMonth/startDay startHours:startMinutes | endYear/endMonth/endDay endHours:endMinutes`. ' +
|
|
2107
|
+
'For example: `2022/10/01 16:30 | 2022/10/21 18:10`. After the end of holiday mode, it switches to "auto" ' +
|
|
2108
|
+
'mode and uses schedule.'),
|
|
2109
|
+
exposes.enum('working_day', ea.STATE_SET, ['mon_sun', 'mon_fri+sat+sun', 'separate']).withDescription('`mon_sun` ' +
|
|
2110
|
+
'- schedule for Monday used for each day (define it only for Monday). `mon_fri+sat+sun` - schedule for ' +
|
|
2111
|
+
'workdays used from Monday (define it only for Monday), Saturday and Sunday are defined separately. `separate` ' +
|
|
2112
|
+
'- schedule for each day is defined separately.'),
|
|
2113
|
+
exposes.composite('schedule', 'schedule').withFeature(exposes.enum('week_day', ea.SET, ['monday', 'tuesday',
|
|
2114
|
+
'wednesday', 'thursday', 'friday', 'saturday', 'sunday'])).withFeature(exposes.text('schedule', ea.SET))
|
|
2115
|
+
.withDescription('Schedule will work with "auto" preset. In this mode, the device executes ' +
|
|
2116
|
+
'a preset week programming temperature time and temperature. Before using these properties, check `working_day` ' +
|
|
2117
|
+
'property. Each day can contain up to 10 segments. At least 1 segment should be defined. Different count of segments ' +
|
|
2118
|
+
'can be defined for each day, e.g., 3 segments for Monday, 5 segments for Thursday, etc. It should be defined in the ' +
|
|
2119
|
+
'following format: `hours:minutes/temperature`. Minutes can be only tens, i.e., 00, 10, 20, 30, 40, 50. Segments should ' +
|
|
2120
|
+
'be divided by space symbol. Each day should end with the last segment of 24:00. Examples: `04:00/20 08:30/22 10:10/18 ' +
|
|
2121
|
+
'18:40/24 22:50/19.5`; `06:00/21.5 17:20/26 24:00/18`. The temperature will be set from the beginning/start of one ' +
|
|
2122
|
+
'period and until the next period, e.g., `04:00/20 24:00/22` means that from 00:00 to 04:00 temperature will be 20 ' +
|
|
2123
|
+
'degrees and from 04:00 to 00:00 temperature will be 22 degrees.'),
|
|
2105
2124
|
exposes.text('schedule_monday', ea.STATE),
|
|
2106
2125
|
exposes.text('schedule_tuesday', ea.STATE),
|
|
2107
2126
|
exposes.text('schedule_wednesday', ea.STATE),
|
|
@@ -2109,9 +2128,44 @@ module.exports = [
|
|
|
2109
2128
|
exposes.text('schedule_friday', ea.STATE),
|
|
2110
2129
|
exposes.text('schedule_saturday', ea.STATE),
|
|
2111
2130
|
exposes.text('schedule_sunday', ea.STATE),
|
|
2112
|
-
exposes.binary('online', ea.STATE_SET, 'ON', 'OFF').withDescription('
|
|
2131
|
+
exposes.binary('online', ea.STATE_SET, 'ON', 'OFF').withDescription('Turn on this property to poll current data from the ' +
|
|
2132
|
+
'device. It can be used to periodically fetch a new local temperature since the device doesn\'t update itself. ' +
|
|
2133
|
+
'Setting this property doesn\'t turn on the display.'),
|
|
2113
2134
|
exposes.numeric('error_status', ea.STATE).withDescription('Error status'),
|
|
2114
2135
|
],
|
|
2136
|
+
meta: {
|
|
2137
|
+
tuyaDatapoints: [
|
|
2138
|
+
[2, 'preset', tuya.valueConverterBasic.lookup({'auto': tuya.enum(0), 'manual': tuya.enum(1), 'holiday': tuya.enum(3)})],
|
|
2139
|
+
[8, 'open_window', tuya.valueConverter.onOff],
|
|
2140
|
+
[10, 'frost_protection', tuya.valueConverter.onOff],
|
|
2141
|
+
[16, 'current_heating_setpoint', tuya.valueConverter.divideBy10],
|
|
2142
|
+
[24, 'local_temperature', tuya.valueConverter.divideBy10],
|
|
2143
|
+
[27, 'local_temperature_calibration', tuya.valueConverter.localTempCalibration],
|
|
2144
|
+
[31, 'working_day', tuya.valueConverterBasic.lookup({'mon_sun': tuya.enum(0), 'mon_fri+sat+sun': tuya.enum(1),
|
|
2145
|
+
'separate': tuya.enum(2)})],
|
|
2146
|
+
[32, 'holiday_temperature', tuya.valueConverter.divideBy10],
|
|
2147
|
+
[35, 'battery_low', tuya.valueConverter.true0ElseFalse],
|
|
2148
|
+
[40, 'child_lock', tuya.valueConverter.lockUnlock],
|
|
2149
|
+
[45, 'error_status', tuya.valueConverter.raw],
|
|
2150
|
+
[46, 'holiday_start_stop', tuya.valueConverter.thermostatHolidayStartStop],
|
|
2151
|
+
[101, 'boost_timeset_countdown', tuya.valueConverter.raw],
|
|
2152
|
+
[102, 'open_window_temperature', tuya.valueConverter.divideBy10],
|
|
2153
|
+
[104, 'comfort_temperature', tuya.valueConverter.divideBy10],
|
|
2154
|
+
[105, 'eco_temperature', tuya.valueConverter.divideBy10],
|
|
2155
|
+
[106, 'schedule', tuya.valueConverter.thermostatScheduleDay],
|
|
2156
|
+
[107, null, tuya.valueConverter.TV02SystemMode],
|
|
2157
|
+
[107, 'system_mode', tuya.valueConverterBasic.lookup({'heat': false, 'off': true})],
|
|
2158
|
+
[107, 'heating_stop', tuya.valueConverter.onOff],
|
|
2159
|
+
[115, 'online', tuya.valueConverter.onOffNotStrict],
|
|
2160
|
+
[108, 'schedule_monday', tuya.valueConverter.thermostatScheduleDay],
|
|
2161
|
+
[112, 'schedule_tuesday', tuya.valueConverter.thermostatScheduleDay],
|
|
2162
|
+
[109, 'schedule_wednesday', tuya.valueConverter.thermostatScheduleDay],
|
|
2163
|
+
[113, 'schedule_thursday', tuya.valueConverter.thermostatScheduleDay],
|
|
2164
|
+
[110, 'schedule_friday', tuya.valueConverter.thermostatScheduleDay],
|
|
2165
|
+
[114, 'schedule_saturday', tuya.valueConverter.thermostatScheduleDay],
|
|
2166
|
+
[111, 'schedule_sunday', tuya.valueConverter.thermostatScheduleDay],
|
|
2167
|
+
],
|
|
2168
|
+
},
|
|
2115
2169
|
},
|
|
2116
2170
|
{
|
|
2117
2171
|
fingerprint: [
|
|
@@ -2935,7 +2989,9 @@ module.exports = [
|
|
|
2935
2989
|
exposes: [e.battery(), e.vibration(), exposes.enum('sensitivity', exposes.access.STATE_SET, ['low', 'medium', 'high'])],
|
|
2936
2990
|
},
|
|
2937
2991
|
{
|
|
2938
|
-
fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_8bxrzyxz'},
|
|
2992
|
+
fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_8bxrzyxz'},
|
|
2993
|
+
{modelID: 'TS011F', manufacturerName: '_TZ3000_ky0fq4ho'},
|
|
2994
|
+
{modelID: 'TS011F', manufacturerName: '_TZ3000_qeuvnohg'}],
|
|
2939
2995
|
model: 'TS011F_din_smart_relay',
|
|
2940
2996
|
description: 'Din smart relay (with power monitoring)',
|
|
2941
2997
|
vendor: 'TuYa',
|
package/devices/zemismart.js
CHANGED
|
@@ -235,7 +235,7 @@ module.exports = [
|
|
|
235
235
|
},
|
|
236
236
|
},
|
|
237
237
|
{
|
|
238
|
-
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_9mahtqtg'}],
|
|
238
|
+
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_9mahtqtg'}, {modelID: 'TS0601', manufacturerName: '_TZE200_r731zlxk'}],
|
|
239
239
|
model: 'TB26-6',
|
|
240
240
|
vendor: 'Zemismart',
|
|
241
241
|
description: '6-gang smart wall switch',
|
package/lib/tuya.js
CHANGED
|
@@ -1178,6 +1178,27 @@ const fingerprint = (modelID, manufacturerNames) => {
|
|
|
1178
1178
|
});
|
|
1179
1179
|
};
|
|
1180
1180
|
|
|
1181
|
+
class Base {
|
|
1182
|
+
constructor(value) {
|
|
1183
|
+
this.value = value;
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
valueOf() {
|
|
1187
|
+
return this.value;
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
class Enum extends Base {
|
|
1191
|
+
constructor(value) {
|
|
1192
|
+
super(value);
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
class Bitmap extends Base {
|
|
1197
|
+
constructor(value) {
|
|
1198
|
+
super(value);
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1181
1202
|
const valueConverterBasic = {
|
|
1182
1203
|
lookup: (map) => {
|
|
1183
1204
|
return {
|
|
@@ -1186,7 +1207,7 @@ const valueConverterBasic = {
|
|
|
1186
1207
|
return map[v];
|
|
1187
1208
|
},
|
|
1188
1209
|
from: (v) => {
|
|
1189
|
-
const value = Object.entries(map).find((i) => i[1] === v);
|
|
1210
|
+
const value = Object.entries(map).find((i) => i[1].valueOf() === v);
|
|
1190
1211
|
if (!value) throw new Error(`Value '${v}' is not allowed, expected one of ${Object.values(map)}`);
|
|
1191
1212
|
return value[0];
|
|
1192
1213
|
},
|
|
@@ -1222,11 +1243,140 @@ const valueConverter = {
|
|
|
1222
1243
|
},
|
|
1223
1244
|
true0ElseFalse: {from: (v) => v === 0},
|
|
1224
1245
|
selfTestResult: valueConverterBasic.lookup({'checking': 0, 'success': 1, 'failure': 2, 'others': 3}),
|
|
1246
|
+
lockUnlock: valueConverterBasic.lookup({'LOCK': true, 'UNLOCK': false}),
|
|
1247
|
+
localTempCalibration: {
|
|
1248
|
+
from: (v) => {
|
|
1249
|
+
if (v > 55) v -= 0x100000000;
|
|
1250
|
+
return v / 10;
|
|
1251
|
+
},
|
|
1252
|
+
to: (v) => {
|
|
1253
|
+
if (v > 0) return v * 10;
|
|
1254
|
+
if (v < 0) return v * 10 + 0x100000000;
|
|
1255
|
+
return v;
|
|
1256
|
+
},
|
|
1257
|
+
},
|
|
1258
|
+
thermostatHolidayStartStop: {
|
|
1259
|
+
from: (v) => {
|
|
1260
|
+
const start = {
|
|
1261
|
+
year: v.slice(0, 4), month: v.slice(4, 6), day: v.slice(6, 8),
|
|
1262
|
+
hours: v.slice(8, 10), minutes: v.slice(10, 12),
|
|
1263
|
+
};
|
|
1264
|
+
const end = {
|
|
1265
|
+
year: v.slice(12, 16), month: v.slice(16, 18), day: v.slice(18, 20),
|
|
1266
|
+
hours: v.slice(20, 22), minutes: v.slice(22, 24),
|
|
1267
|
+
};
|
|
1268
|
+
const startStr = `${start.year}/${start.month}/${start.day} ${start.hours}:${start.minutes}`;
|
|
1269
|
+
const endStr = `${end.year}/${end.month}/${end.day} ${end.hours}:${end.minutes}`;
|
|
1270
|
+
return `${startStr} | ${endStr}`;
|
|
1271
|
+
},
|
|
1272
|
+
to: (v) => {
|
|
1273
|
+
const numberPattern = /\d+/g;
|
|
1274
|
+
return v.match(numberPattern).join([]).toString();
|
|
1275
|
+
},
|
|
1276
|
+
},
|
|
1277
|
+
thermostatScheduleDay: {
|
|
1278
|
+
from: (v) => {
|
|
1279
|
+
// day splitted to 10 min segments = total 144 segments
|
|
1280
|
+
const maxPeriodsInDay = 10;
|
|
1281
|
+
const periodSize = 3;
|
|
1282
|
+
const schedule = [];
|
|
1283
|
+
|
|
1284
|
+
for (let i = 0; i < maxPeriodsInDay; i++) {
|
|
1285
|
+
const time = v[i * periodSize];
|
|
1286
|
+
const totalMinutes = time * 10;
|
|
1287
|
+
const hours = totalMinutes / 60;
|
|
1288
|
+
const rHours = Math.floor(hours);
|
|
1289
|
+
const minutes = (hours - rHours) * 60;
|
|
1290
|
+
const rMinutes = Math.round(minutes);
|
|
1291
|
+
const strHours = rHours.toString().padStart(2, '0');
|
|
1292
|
+
const strMinutes = rMinutes.toString().padStart(2, '0');
|
|
1293
|
+
const temp = parseFloat(v[i * periodSize + 2] / 10);
|
|
1294
|
+
schedule.push(`${strHours}:${strMinutes}/${temp}`);
|
|
1295
|
+
if (rHours === 24) break;
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
return schedule.join(' ');
|
|
1299
|
+
},
|
|
1300
|
+
to: (v, meta) => {
|
|
1301
|
+
const dayByte = {
|
|
1302
|
+
monday: 1, tuesday: 2, wednesday: 4, thursday: 8,
|
|
1303
|
+
friday: 16, saturday: 32, sunday: 64,
|
|
1304
|
+
};
|
|
1305
|
+
const weekDay = v.week_day;
|
|
1306
|
+
if (Object.keys(dayByte).indexOf(weekDay) === -1) {
|
|
1307
|
+
throw new Error('Invalid "week_day" property value: ' + weekDay);
|
|
1308
|
+
}
|
|
1309
|
+
let weekScheduleType;
|
|
1310
|
+
if (meta.state && meta.state.working_day) weekScheduleType = meta.state.working_day;
|
|
1311
|
+
const payload = [];
|
|
1312
|
+
|
|
1313
|
+
switch (weekScheduleType) {
|
|
1314
|
+
case 'mon_sun':
|
|
1315
|
+
payload.push(127);
|
|
1316
|
+
break;
|
|
1317
|
+
case 'mon_fri+sat+sun':
|
|
1318
|
+
if (['saturday', 'sunday'].indexOf(weekDay) === -1) {
|
|
1319
|
+
payload.push(31);
|
|
1320
|
+
break;
|
|
1321
|
+
}
|
|
1322
|
+
payload.push(dayByte[weekDay]);
|
|
1323
|
+
break;
|
|
1324
|
+
case 'separate':
|
|
1325
|
+
payload.push(dayByte[weekDay]);
|
|
1326
|
+
break;
|
|
1327
|
+
default:
|
|
1328
|
+
throw new Error('Invalid "working_day" property, need to set it before');
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
// day splitted to 10 min segments = total 144 segments
|
|
1332
|
+
const maxPeriodsInDay = 10;
|
|
1333
|
+
const schedule = v.schedule.split(' ');
|
|
1334
|
+
const schedulePeriods = schedule.length;
|
|
1335
|
+
if (schedulePeriods > 10) throw new Error('There cannot be more than 10 periods in the schedule: ' + v);
|
|
1336
|
+
if (schedulePeriods < 2) throw new Error('There cannot be less than 2 periods in the schedule: ' + v);
|
|
1337
|
+
let prevHour;
|
|
1338
|
+
|
|
1339
|
+
for (const period of schedule) {
|
|
1340
|
+
const timeTemp = period.split('/');
|
|
1341
|
+
const hm = timeTemp[0].split(':', 2);
|
|
1342
|
+
const h = parseInt(hm[0]);
|
|
1343
|
+
const m = parseInt(hm[1]);
|
|
1344
|
+
const temp = parseFloat(timeTemp[1]);
|
|
1345
|
+
if (h < 0 || h > 24 || m < 0 || m >= 60 || m % 10 !== 0 || temp < 5 || temp > 30 || temp % 0.5 !== 0) {
|
|
1346
|
+
throw new Error('Invalid hour, minute or temperature of: ' + period);
|
|
1347
|
+
} else if (prevHour > h) {
|
|
1348
|
+
throw new Error(`The hour of the next segment can't be less than the previous one: ${prevHour} > ${h}`);
|
|
1349
|
+
}
|
|
1350
|
+
prevHour = h;
|
|
1351
|
+
const segment = (h * 60 + m) / 10;
|
|
1352
|
+
payload.push(segment, 0, temp * 10);
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
// Add "technical" periods to be valid payload
|
|
1356
|
+
for (let i = 0; i < maxPeriodsInDay - schedulePeriods; i++) {
|
|
1357
|
+
// by default it sends 9000b2, it's 24 hours and 18 degrees
|
|
1358
|
+
payload.push(144, 0, 180);
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
return payload;
|
|
1362
|
+
},
|
|
1363
|
+
},
|
|
1364
|
+
TV02SystemMode: {
|
|
1365
|
+
from: (v) => {
|
|
1366
|
+
return {system_mode: v === false ? 'heat' : 'off', heating_stop: v === false ? 'OFF' : 'ON'};
|
|
1367
|
+
},
|
|
1368
|
+
},
|
|
1369
|
+
onOffNotStrict: {from: (v) => v ? 'ON' : 'OFF', to: (v) => v === 'ON'},
|
|
1225
1370
|
};
|
|
1226
1371
|
|
|
1227
1372
|
const tzDataPoints = {
|
|
1228
|
-
key: [
|
|
1229
|
-
'
|
|
1373
|
+
key: [
|
|
1374
|
+
'state', 'brightness', 'min_brightness', 'max_brightness', 'power_on_behavior',
|
|
1375
|
+
'countdown', 'light_type', 'silence', 'self_test', 'child_lock', 'open_window', 'open_window_temperature', 'frost_protection',
|
|
1376
|
+
'system_mode', 'heating_stop', 'current_heating_setpoint', 'local_temperature_calibration', 'preset', 'boost_timeset_countdown',
|
|
1377
|
+
'holiday_start_stop', 'holiday_temperature', 'comfort_temperature', 'eco_temperature', 'working_day', 'week_schedule_programming',
|
|
1378
|
+
'online', 'holiday_mode_date', 'schedule',
|
|
1379
|
+
],
|
|
1230
1380
|
convertSet: async (entity, key, value, meta) => {
|
|
1231
1381
|
// A set converter is only called once; therefore we need to loop
|
|
1232
1382
|
const state = {};
|
|
@@ -1240,11 +1390,19 @@ const tzDataPoints = {
|
|
|
1240
1390
|
}
|
|
1241
1391
|
if (dpEntry[3] && dpEntry[3].skip && dpEntry[3].skip(meta)) continue;
|
|
1242
1392
|
const dpId = dpEntry[0];
|
|
1243
|
-
const convertedValue = dpEntry[2].to(value);
|
|
1393
|
+
const convertedValue = dpEntry[2].to(value, meta);
|
|
1244
1394
|
if (typeof convertedValue === 'boolean') {
|
|
1245
1395
|
await sendDataPointBool(entity, dpId, convertedValue, 'dataRequest', 1);
|
|
1246
1396
|
} else if (typeof convertedValue === 'number') {
|
|
1247
1397
|
await sendDataPointValue(entity, dpId, convertedValue, 'dataRequest', 1);
|
|
1398
|
+
} else if (typeof convertedValue === 'string') {
|
|
1399
|
+
await sendDataPointStringBuffer(entity, dpId, convertedValue, 'dataRequest', 1);
|
|
1400
|
+
} else if (Array.isArray(convertedValue)) {
|
|
1401
|
+
await sendDataPointRaw(entity, dpId, convertedValue, 'dataRequest', 1);
|
|
1402
|
+
} else if (convertedValue instanceof Enum) {
|
|
1403
|
+
await sendDataPointEnum(entity, dpId, convertedValue.valueOf(), 'dataRequest', 1);
|
|
1404
|
+
} else if (convertedValue instanceof Bitmap) {
|
|
1405
|
+
await sendDataPointBitmap(entity, dpId, convertedValue.valueOf(), 'dataRequest', 1);
|
|
1248
1406
|
} else {
|
|
1249
1407
|
throw new Error(`Don't know how to send type '${typeof convertedValue}'`);
|
|
1250
1408
|
}
|
|
@@ -1267,9 +1425,9 @@ const fzDataPoints = {
|
|
|
1267
1425
|
if (dpEntry) {
|
|
1268
1426
|
const value = getDataValue(dpValue);
|
|
1269
1427
|
if (dpEntry[1]) {
|
|
1270
|
-
result[dpEntry[1]] = dpEntry[2].from(value);
|
|
1428
|
+
result[dpEntry[1]] = dpEntry[2].from(value, meta);
|
|
1271
1429
|
} else if (dpEntry[2]) {
|
|
1272
|
-
result = {...result, ...dpEntry[2].from(value)};
|
|
1430
|
+
result = {...result, ...dpEntry[2].from(value, meta)};
|
|
1273
1431
|
}
|
|
1274
1432
|
} else {
|
|
1275
1433
|
meta.logger.warn(`Datapoint ${dpId} not defined for '${meta.device.manufacturerName}' ` +
|
|
@@ -1285,6 +1443,8 @@ module.exports = {
|
|
|
1285
1443
|
skip,
|
|
1286
1444
|
configureMagicPacket,
|
|
1287
1445
|
fingerprint,
|
|
1446
|
+
enum: (value) => new Enum(value),
|
|
1447
|
+
bitmap: (value) => new Bitmap(value),
|
|
1288
1448
|
valueConverter,
|
|
1289
1449
|
valueConverterBasic,
|
|
1290
1450
|
tzDataPoints,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zigbee-herdsman-converters",
|
|
3
|
-
"version": "14.0.
|
|
3
|
+
"version": "14.0.648",
|
|
4
4
|
"description": "Collection of device converters to be used with zigbee-herdsman",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"buffer-crc32": "^0.2.13",
|
|
39
39
|
"https-proxy-agent": "^5.0.1",
|
|
40
40
|
"tar-stream": "^2.2.0",
|
|
41
|
-
"zigbee-herdsman": "^0.14.
|
|
41
|
+
"zigbee-herdsman": "^0.14.66"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"eslint": "*",
|