zigbee-herdsman-converters 14.0.293 → 14.0.297
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 +239 -6
- package/converters/toZigbee.js +171 -6
- package/devices/adeo.js +9 -0
- package/devices/danfoss.js +137 -1
- package/devices/eurotronic.js +4 -4
- package/devices/ikea.js +3 -1
- package/devices/philips.js +18 -0
- package/devices/shinasystem.js +118 -8
- package/devices/the_light_group.js +15 -0
- package/devices/tuya.js +67 -16
- package/devices/yale.js +7 -0
- package/lib/constants.js +43 -0
- package/lib/exposes.js +1 -0
- package/lib/tuya.js +24 -0
- package/npm-shrinkwrap.json +1 -1
- package/package.json +1 -1
package/converters/fromZigbee.js
CHANGED
|
@@ -108,6 +108,26 @@ const converters = {
|
|
|
108
108
|
if (msg.data.hasOwnProperty('tempSetpointHoldDuration')) {
|
|
109
109
|
result[postfixWithEndpointName('temperature_setpoint_hold_duration', msg, model)] = msg.data['tempSetpointHoldDuration'];
|
|
110
110
|
}
|
|
111
|
+
if (msg.data.hasOwnProperty('minHeatSetpointLimit')) {
|
|
112
|
+
let value = precisionRound(msg.data['minHeatSetpointLimit'], 2) / 100;
|
|
113
|
+
value = value < -250 ? 0 : value;
|
|
114
|
+
result[postfixWithEndpointName('min_heat_setpoint_limit', msg, model)] = value;
|
|
115
|
+
}
|
|
116
|
+
if (msg.data.hasOwnProperty('maxHeatSetpointLimit')) {
|
|
117
|
+
let value = precisionRound(msg.data['maxHeatSetpointLimit'], 2) / 100;
|
|
118
|
+
value = value < -250 ? 0 : value;
|
|
119
|
+
result[postfixWithEndpointName('max_heat_setpoint_limit', msg, model)] = value;
|
|
120
|
+
}
|
|
121
|
+
if (msg.data.hasOwnProperty('absMinHeatSetpointLimit')) {
|
|
122
|
+
let value = precisionRound(msg.data['absMinHeatSetpointLimit'], 2) / 100;
|
|
123
|
+
value = value < -250 ? 0 : value;
|
|
124
|
+
result[postfixWithEndpointName('abs_min_heat_setpoint_limit', msg, model)] = value;
|
|
125
|
+
}
|
|
126
|
+
if (msg.data.hasOwnProperty('absMaxHeatSetpointLimit')) {
|
|
127
|
+
let value = precisionRound(msg.data['absMaxHeatSetpointLimit'], 2) / 100;
|
|
128
|
+
value = value < -250 ? 0 : value;
|
|
129
|
+
result[postfixWithEndpointName('abs_max_heat_setpoint_limit', msg, model)] = value;
|
|
130
|
+
}
|
|
111
131
|
return result;
|
|
112
132
|
},
|
|
113
133
|
},
|
|
@@ -3004,9 +3024,71 @@ const converters = {
|
|
|
3004
3024
|
result[postfixWithEndpointName('running_state', msg, model)] = 'idle';
|
|
3005
3025
|
}
|
|
3006
3026
|
}
|
|
3027
|
+
if (msg.data.hasOwnProperty('danfossLoadBalancingEnable')) {
|
|
3028
|
+
result[postfixWithEndpointName('load_balancing_enable', msg, model)] = (msg.data['danfossLoadBalancingEnable'] === 1);
|
|
3029
|
+
}
|
|
3030
|
+
if (msg.data.hasOwnProperty('danfossLoadRoomMean')) {
|
|
3031
|
+
result[postfixWithEndpointName('load_room_mean', msg, model)] = msg.data['danfossLoadRoomMean'];
|
|
3032
|
+
}
|
|
3007
3033
|
if (msg.data.hasOwnProperty('danfossLoadEstimate')) {
|
|
3008
3034
|
result[postfixWithEndpointName('load_estimate', msg, model)] = msg.data['danfossLoadEstimate'];
|
|
3009
3035
|
}
|
|
3036
|
+
// Danfoss Icon Converters
|
|
3037
|
+
if (msg.data.hasOwnProperty('danfossRoomStatusCode')) {
|
|
3038
|
+
result[postfixWithEndpointName('room_status_code', msg, model)] =
|
|
3039
|
+
constants.danfossRoomStatusCode.hasOwnProperty(msg.data['danfossRoomStatusCode']) ?
|
|
3040
|
+
constants.danfossRoomStatusCode[msg.data['danfossRoomStatusCode']] :
|
|
3041
|
+
msg.data['danfossRoomStatusCode'];
|
|
3042
|
+
}
|
|
3043
|
+
if (msg.data.hasOwnProperty('danfossOutputStatus')) {
|
|
3044
|
+
result[postfixWithEndpointName('output_status', msg, model)] =
|
|
3045
|
+
constants.danfossOutputStatus.hasOwnProperty(msg.data['danfossOutputStatus']) ?
|
|
3046
|
+
constants.danfossOutputStatus[msg.data['danfossOutputStatus']] :
|
|
3047
|
+
msg.data['danfossOutputStatus'];
|
|
3048
|
+
}
|
|
3049
|
+
return result;
|
|
3050
|
+
},
|
|
3051
|
+
},
|
|
3052
|
+
danfoss_icon_battery: {
|
|
3053
|
+
cluster: 'genPowerCfg',
|
|
3054
|
+
type: ['attributeReport', 'readResponse'],
|
|
3055
|
+
convert: (model, msg, publish, options, meta) => {
|
|
3056
|
+
const result = {};
|
|
3057
|
+
if (msg.data.hasOwnProperty('batteryPercentageRemaining')) {
|
|
3058
|
+
// Some devices do not comply to the ZCL and report a
|
|
3059
|
+
// batteryPercentageRemaining of 100 when the battery is full (should be 200).
|
|
3060
|
+
const dontDividePercentage = model.meta && model.meta.battery && model.meta.battery.dontDividePercentage;
|
|
3061
|
+
let percentage = msg.data['batteryPercentageRemaining'];
|
|
3062
|
+
percentage = dontDividePercentage ? percentage : percentage / 2;
|
|
3063
|
+
|
|
3064
|
+
result[postfixWithEndpointName('battery', msg, model)] = precisionRound(percentage, 2);
|
|
3065
|
+
}
|
|
3066
|
+
return result;
|
|
3067
|
+
},
|
|
3068
|
+
},
|
|
3069
|
+
danfoss_icon_regulator: {
|
|
3070
|
+
cluster: 'haDiagnostic',
|
|
3071
|
+
type: ['attributeReport', 'readResponse'],
|
|
3072
|
+
convert: (model, msg, publish, options, meta) => {
|
|
3073
|
+
const result = {};
|
|
3074
|
+
if (msg.data.hasOwnProperty('danfossSystemStatusCode')) {
|
|
3075
|
+
result[postfixWithEndpointName('system_status_code', msg, model)] =
|
|
3076
|
+
constants.danfossSystemStatusCode.hasOwnProperty(msg.data['danfossSystemStatusCode']) ?
|
|
3077
|
+
constants.danfossSystemStatusCode[msg.data['danfossSystemStatusCode']] :
|
|
3078
|
+
msg.data['danfossSystemStatusCode'];
|
|
3079
|
+
}
|
|
3080
|
+
if (msg.data.hasOwnProperty('danfossSystemStatusWater')) {
|
|
3081
|
+
result[postfixWithEndpointName('system_status_water', msg, model)] =
|
|
3082
|
+
constants.danfossSystemStatusWater.hasOwnProperty(msg.data['danfossSystemStatusWater']) ?
|
|
3083
|
+
constants.danfossSystemStatusWater[msg.data['danfossSystemStatusWater']] :
|
|
3084
|
+
msg.data['danfossSystemStatusWater'];
|
|
3085
|
+
}
|
|
3086
|
+
if (msg.data.hasOwnProperty('danfossMultimasterRole')) {
|
|
3087
|
+
result[postfixWithEndpointName('multimaster_role', msg, model)] =
|
|
3088
|
+
constants.danfossMultimasterRole.hasOwnProperty(msg.data['danfossMultimasterRole']) ?
|
|
3089
|
+
constants.danfossMultimasterRole[msg.data['danfossMultimasterRole']] :
|
|
3090
|
+
msg.data['danfossMultimasterRole'];
|
|
3091
|
+
}
|
|
3010
3092
|
return result;
|
|
3011
3093
|
},
|
|
3012
3094
|
},
|
|
@@ -3456,6 +3538,121 @@ const converters = {
|
|
|
3456
3538
|
}
|
|
3457
3539
|
},
|
|
3458
3540
|
},
|
|
3541
|
+
haozee_thermostat: {
|
|
3542
|
+
cluster: 'manuSpecificTuya',
|
|
3543
|
+
type: ['commandGetData', 'commandSetDataResponse'],
|
|
3544
|
+
convert: (model, msg, publish, options, meta) => {
|
|
3545
|
+
const dp = msg.data.dp; // First we get the data point ID
|
|
3546
|
+
const value = tuya.getDataValue(msg.data.datatype, msg.data.data);
|
|
3547
|
+
const presetLookup = {0: 'auto', 1: 'manual', 2: 'off', 3: 'on'};
|
|
3548
|
+
switch (dp) {
|
|
3549
|
+
case tuya.dataPoints.haozeeSystemMode:
|
|
3550
|
+
return {preset: presetLookup[value]};
|
|
3551
|
+
case tuya.dataPoints.haozeeHeatingSetpoint:
|
|
3552
|
+
return {current_heating_setpoint: (value / 10).toFixed(1)};
|
|
3553
|
+
case tuya.dataPoints.haozeeLocalTemp:
|
|
3554
|
+
return {local_temperature: (value / 10).toFixed(1)};
|
|
3555
|
+
case tuya.dataPoints.haozeeBoostHeatingCountdown:
|
|
3556
|
+
// quick heating countdown
|
|
3557
|
+
return {boost_heating_countdown: value};
|
|
3558
|
+
case tuya.dataPoints.haozeeWindowDetection:
|
|
3559
|
+
// window check
|
|
3560
|
+
return {window_detection: value ? 'ON' : 'OFF'};
|
|
3561
|
+
case tuya.dataPoints.haozeeWindowState:
|
|
3562
|
+
// window state
|
|
3563
|
+
return {window: value ? 'OPEN' : 'CLOSED'};
|
|
3564
|
+
case tuya.dataPoints.haozeeChildLock:
|
|
3565
|
+
return {child_lock: value ? 'LOCK' : 'UNLOCK'};
|
|
3566
|
+
case tuya.dataPoints.haozeeBattery:
|
|
3567
|
+
// battery
|
|
3568
|
+
return {battery: value};
|
|
3569
|
+
case tuya.dataPoints.haozeeFaultAlarm:
|
|
3570
|
+
return {error: value ? 'ON': 'OFF'};
|
|
3571
|
+
case tuya.dataPoints.haozeeScheduleMonday:
|
|
3572
|
+
// Monday
|
|
3573
|
+
return {
|
|
3574
|
+
'monday_schedule': ' ' + value[1] + 'h:' + value[2] + 'm ' + value[4] / 10 + '°C' +
|
|
3575
|
+
', ' + value[5] + 'h:' + value[6] + 'm ' + value[8] / 10 + '°C' +
|
|
3576
|
+
', ' + value[9] + 'h:' + value[10] + 'm ' + value[12] / 10 + '°C' +
|
|
3577
|
+
', ' + value[13] + 'h:' + value[14] + 'm ' + value[16] / 10 + '°C ',
|
|
3578
|
+
};
|
|
3579
|
+
case tuya.dataPoints.haozeeScheduleTuesday:
|
|
3580
|
+
// Tuesday
|
|
3581
|
+
return {
|
|
3582
|
+
'tuesday_schedule': ' ' + value[1] + 'h:' + value[2] + 'm ' + value[4] / 10 + '°C' +
|
|
3583
|
+
', ' + value[5] + 'h:' + value[6] + 'm ' + value[8] / 10 + '°C' +
|
|
3584
|
+
', ' + value[9] + 'h:' + value[10] + 'm ' + value[12] / 10 + '°C' +
|
|
3585
|
+
', ' + value[13] + 'h:' + value[14] + 'm ' + value[16] / 10 + '°C ',
|
|
3586
|
+
};
|
|
3587
|
+
case tuya.dataPoints.haozeeScheduleWednesday:
|
|
3588
|
+
// wednesday
|
|
3589
|
+
return {
|
|
3590
|
+
'wednesday_schedule': ' ' + value[1] + 'h:' + value[2] + 'm ' + value[4] / 10 + '°C' +
|
|
3591
|
+
', ' + value[5] + 'h:' + value[6] + 'm ' + value[8] / 10 + '°C' +
|
|
3592
|
+
', ' + value[9] + 'h:' + value[10] + 'm ' + value[12] / 10 + '°C' +
|
|
3593
|
+
', ' + value[13] + 'h:' + value[14] + 'm ' + value[16] / 10 + '°C ',
|
|
3594
|
+
};
|
|
3595
|
+
case tuya.dataPoints.haozeeScheduleThursday:
|
|
3596
|
+
// Thursday
|
|
3597
|
+
return {
|
|
3598
|
+
'thursday_schedule': ' ' + value[1] + 'h:' + value[2] + 'm ' + value[4] / 10 + '°C' +
|
|
3599
|
+
', ' + value[5] + 'h:' + value[6] + 'm ' + value[8] / 10 + '°C' +
|
|
3600
|
+
', ' + value[9] + 'h:' + value[10] + 'm ' + value[12] / 10 + '°C' +
|
|
3601
|
+
', ' + value[13] + 'h:' + value[14] + 'm ' + value[16] / 10 + '°C ',
|
|
3602
|
+
};
|
|
3603
|
+
case tuya.dataPoints.haozeeScheduleFriday:
|
|
3604
|
+
// Friday
|
|
3605
|
+
return {
|
|
3606
|
+
'friday_schedule': ' ' + value[1] + 'h:' + value[2] + 'm ' + value[4] / 10 + '°C' +
|
|
3607
|
+
', ' + value[5] + 'h:' + value[6] + 'm ' + value[8] / 10 + '°C' +
|
|
3608
|
+
', ' + value[9] + 'h:' + value[10] + 'm ' + value[12] / 10 + '°C' +
|
|
3609
|
+
', ' + value[13] + 'h:' + value[14] + 'm ' + value[16] / 10 + '°C ',
|
|
3610
|
+
};
|
|
3611
|
+
case tuya.dataPoints.haozeeScheduleSaturday:
|
|
3612
|
+
// Saturday
|
|
3613
|
+
return {
|
|
3614
|
+
'saturday_schedule': ' ' + value[1] + 'h:' + value[2] + 'm ' + value[4] / 10 + '°C' +
|
|
3615
|
+
', ' + value[5] + 'h:' + value[6] + 'm ' + value[8] / 10 + '°C' +
|
|
3616
|
+
', ' + value[9] + 'h:' + value[10] + 'm ' + value[12] / 10 + '°C' +
|
|
3617
|
+
', ' + value[13] + 'h:' + value[14] + 'm ' + value[16] / 10 + '°C ',
|
|
3618
|
+
};
|
|
3619
|
+
case tuya.dataPoints.haozeeScheduleSunday:
|
|
3620
|
+
|
|
3621
|
+
// Sunday
|
|
3622
|
+
return {
|
|
3623
|
+
'sunday_schedule': ' ' + value[1] + 'h:' + value[2] + 'm ' + value[4] / 10 + '°C' +
|
|
3624
|
+
', ' + value[5] + 'h:' + value[6] + 'm ' + value[8] / 10 + '°C' +
|
|
3625
|
+
', ' + value[9] + 'h:' + value[10] + 'm ' + value[12] / 10 + '°C' +
|
|
3626
|
+
', ' + value[13] + 'h:' + value[14] + 'm ' + value[16] / 10 + '°C ',
|
|
3627
|
+
};
|
|
3628
|
+
|
|
3629
|
+
case tuya.dataPoints.haozeeRunningState:
|
|
3630
|
+
// working status 0 - pause 1 -working
|
|
3631
|
+
return {'heating': value ? 'ON' : 'OFF'};
|
|
3632
|
+
case tuya.dataPoints.haozeeBoostHeating:
|
|
3633
|
+
// rapid heating -> boolean
|
|
3634
|
+
break;
|
|
3635
|
+
case tuya.dataPoints.haozeeTempCalibration:
|
|
3636
|
+
// temperature calibration
|
|
3637
|
+
break;
|
|
3638
|
+
case tuya.dataPoints.haozeeValvePosition:
|
|
3639
|
+
// valve position
|
|
3640
|
+
return {'position': value};
|
|
3641
|
+
case tuya.dataPoints.haozeeMinTemp:
|
|
3642
|
+
// lower limit temperature
|
|
3643
|
+
return {'min_temperature': ( value/10 ).toFixed(1)};
|
|
3644
|
+
case tuya.dataPoints.haozeeMaxTemp:
|
|
3645
|
+
// max limit temperature
|
|
3646
|
+
return {'max_temperature': ( value/10 ).toFixed(1)};
|
|
3647
|
+
case tuya.dataPoints.haozeeSoftVersion:
|
|
3648
|
+
// software
|
|
3649
|
+
break;
|
|
3650
|
+
default:
|
|
3651
|
+
meta.logger.warn(`zigbee-herdsman-converters:haozee: NOT RECOGNIZED DP #${
|
|
3652
|
+
dp} with data ${JSON.stringify(msg.data)}`);
|
|
3653
|
+
}
|
|
3654
|
+
},
|
|
3655
|
+
},
|
|
3459
3656
|
tuya_air_quality: {
|
|
3460
3657
|
cluster: 'manuSpecificTuya',
|
|
3461
3658
|
type: ['commandSetDataResponse', 'commandGetData'],
|
|
@@ -5366,22 +5563,30 @@ const converters = {
|
|
|
5366
5563
|
tradfri_occupancy: {
|
|
5367
5564
|
cluster: 'genOnOff',
|
|
5368
5565
|
type: 'commandOnWithTimedOff',
|
|
5369
|
-
options: [exposes.options.occupancy_timeout()],
|
|
5566
|
+
options: [exposes.options.occupancy_timeout(), exposes.options.illuminance_below_threshold_check()],
|
|
5370
5567
|
convert: (model, msg, publish, options, meta) => {
|
|
5371
|
-
|
|
5568
|
+
const onlyWhenOnFlag = (msg.data.ctrlbits & 1) != 0;
|
|
5569
|
+
if (onlyWhenOnFlag &&
|
|
5570
|
+
(!options || !options.hasOwnProperty('illuminance_below_threshold_check') ||
|
|
5571
|
+
options.illuminance_below_threshold_check) &&
|
|
5572
|
+
!globalStore.hasValue(msg.endpoint, 'timer')) return;
|
|
5372
5573
|
|
|
5373
5574
|
const timeout = options && options.hasOwnProperty('occupancy_timeout') ?
|
|
5374
5575
|
options.occupancy_timeout : msg.data.ontime / 10;
|
|
5375
5576
|
|
|
5376
5577
|
// Stop existing timer because motion is detected and set a new one.
|
|
5377
5578
|
clearTimeout(globalStore.getValue(msg.endpoint, 'timer'));
|
|
5579
|
+
globalStore.clearValue(msg.endpoint, 'timer');
|
|
5378
5580
|
|
|
5379
5581
|
if (timeout !== 0) {
|
|
5380
|
-
const timer = setTimeout(() =>
|
|
5582
|
+
const timer = setTimeout(() => {
|
|
5583
|
+
publish({occupancy: false});
|
|
5584
|
+
globalStore.clearValue(msg.endpoint, 'timer');
|
|
5585
|
+
}, timeout * 1000);
|
|
5381
5586
|
globalStore.putValue(msg.endpoint, 'timer', timer);
|
|
5382
5587
|
}
|
|
5383
5588
|
|
|
5384
|
-
return {occupancy: true};
|
|
5589
|
+
return {occupancy: true, illuminance_above_threshold: onlyWhenOnFlag};
|
|
5385
5590
|
},
|
|
5386
5591
|
},
|
|
5387
5592
|
almond_click: {
|
|
@@ -6865,10 +7070,10 @@ const converters = {
|
|
|
6865
7070
|
}
|
|
6866
7071
|
break;
|
|
6867
7072
|
case tuya.dataPoints.tvWindowDetection:
|
|
6868
|
-
result = {window_detection: {1:
|
|
7073
|
+
result = {window_detection: {1: true, 0: false}[value]};
|
|
6869
7074
|
break;
|
|
6870
7075
|
case tuya.dataPoints.tvFrostDetection:
|
|
6871
|
-
result = {frost_detection: {1:
|
|
7076
|
+
result = {frost_detection: {1: true, 0: false}[value]};
|
|
6872
7077
|
break;
|
|
6873
7078
|
case tuya.dataPoints.tvHeatingSetpoint:
|
|
6874
7079
|
result = {current_heating_setpoint: (value / 10).toFixed(1)};
|
|
@@ -6931,6 +7136,23 @@ const converters = {
|
|
|
6931
7136
|
return {people: msg.data.presentValue};
|
|
6932
7137
|
},
|
|
6933
7138
|
},
|
|
7139
|
+
sihas_action: {
|
|
7140
|
+
cluster: 'genOnOff',
|
|
7141
|
+
type: ['commandOn', 'commandOff', 'commandToggle'],
|
|
7142
|
+
convert: (model, msg, publish, options, meta) => {
|
|
7143
|
+
const lookup = {'commandToggle': 'long', 'commandOn': 'double', 'commandOff': 'single'};
|
|
7144
|
+
let buttonMapping = null;
|
|
7145
|
+
if (model.model === 'SBM300ZB2') {
|
|
7146
|
+
buttonMapping = {1: '1', 2: '2'};
|
|
7147
|
+
} else if (model.model === 'SBM300ZB3') {
|
|
7148
|
+
buttonMapping = {1: '1', 2: '2', 3: '3'};
|
|
7149
|
+
} else if (model.model === 'MSM-300ZB') {
|
|
7150
|
+
buttonMapping = {1: '1', 2: '2', 3: '3', 4: '4'};
|
|
7151
|
+
}
|
|
7152
|
+
const button = buttonMapping ? `${buttonMapping[msg.endpoint.ID]}_` : '';
|
|
7153
|
+
return {action: `${button}${lookup[msg.type]}`};
|
|
7154
|
+
},
|
|
7155
|
+
},
|
|
6934
7156
|
hoch_din: {
|
|
6935
7157
|
cluster: 'manuSpecificTuya',
|
|
6936
7158
|
type: ['commandGetData', 'commandSetDataResponse'],
|
|
@@ -7035,6 +7257,17 @@ const converters = {
|
|
|
7035
7257
|
return result;
|
|
7036
7258
|
},
|
|
7037
7259
|
},
|
|
7260
|
+
tuya_operation_mode: {
|
|
7261
|
+
cluster: 'genOnOff',
|
|
7262
|
+
type: ['attributeReport', 'readResponse'],
|
|
7263
|
+
convert: (model, msg, publish, options, meta) => {
|
|
7264
|
+
if (msg.data.hasOwnProperty('tuyaOperationMode')) {
|
|
7265
|
+
const value = msg.data['tuyaOperationMode'];
|
|
7266
|
+
const lookup = {0: 'command', 1: 'event'};
|
|
7267
|
+
return {operation_mode: lookup[value]};
|
|
7268
|
+
}
|
|
7269
|
+
},
|
|
7270
|
+
},
|
|
7038
7271
|
// #endregion
|
|
7039
7272
|
|
|
7040
7273
|
// #region Ignore converters (these message dont need parsing).
|
package/converters/toZigbee.js
CHANGED
|
@@ -1327,6 +1327,38 @@ const converters = {
|
|
|
1327
1327
|
await entity.read('hvacThermostat', ['runningMode']);
|
|
1328
1328
|
},
|
|
1329
1329
|
},
|
|
1330
|
+
thermostat_min_heat_setpoint_limit: {
|
|
1331
|
+
key: ['min_heat_setpoint_limit'],
|
|
1332
|
+
convertSet: async (entity, key, value, meta) => {
|
|
1333
|
+
let result;
|
|
1334
|
+
if (meta.options.thermostat_unit === 'fahrenheit') {
|
|
1335
|
+
result = utils.normalizeCelsiusVersionOfFahrenheit(value) * 100;
|
|
1336
|
+
} else {
|
|
1337
|
+
result = (Math.round((value * 2).toFixed(1)) / 2).toFixed(1) * 100;
|
|
1338
|
+
}
|
|
1339
|
+
const minHeatSetpointLimit = result;
|
|
1340
|
+
await entity.write('hvacThermostat', {minHeatSetpointLimit});
|
|
1341
|
+
},
|
|
1342
|
+
convertGet: async (entity, key, meta) => {
|
|
1343
|
+
await entity.read('hvacThermostat', ['minHeatSetpointLimit']);
|
|
1344
|
+
},
|
|
1345
|
+
},
|
|
1346
|
+
thermostat_max_heat_setpoint_limit: {
|
|
1347
|
+
key: ['max_heat_setpoint_limit'],
|
|
1348
|
+
convertSet: async (entity, key, value, meta) => {
|
|
1349
|
+
let result;
|
|
1350
|
+
if (meta.options.thermostat_unit === 'fahrenheit') {
|
|
1351
|
+
result = utils.normalizeCelsiusVersionOfFahrenheit(value) * 100;
|
|
1352
|
+
} else {
|
|
1353
|
+
result = (Math.round((value * 2).toFixed(1)) / 2).toFixed(1) * 100;
|
|
1354
|
+
}
|
|
1355
|
+
const maxHeatSetpointLimit = result;
|
|
1356
|
+
await entity.write('hvacThermostat', {maxHeatSetpointLimit});
|
|
1357
|
+
},
|
|
1358
|
+
convertGet: async (entity, key, meta) => {
|
|
1359
|
+
await entity.read('hvacThermostat', ['maxHeatSetpointLimit']);
|
|
1360
|
+
},
|
|
1361
|
+
},
|
|
1330
1362
|
electrical_measurement_power: {
|
|
1331
1363
|
key: ['power'],
|
|
1332
1364
|
convertGet: async (entity, key, meta) => {
|
|
@@ -2478,12 +2510,62 @@ const converters = {
|
|
|
2478
2510
|
await entity.read('hvacThermostat', ['danfossWindowOpenExternal'], manufacturerOptions.danfoss);
|
|
2479
2511
|
},
|
|
2480
2512
|
},
|
|
2513
|
+
danfoss_load_balancing_enable: {
|
|
2514
|
+
key: ['load_balancing_enable'],
|
|
2515
|
+
convertSet: async (entity, key, value, meta) => {
|
|
2516
|
+
await entity.write('hvacThermostat', {'danfossLoadBalancingEnable': value}, manufacturerOptions.danfoss);
|
|
2517
|
+
return {readAfterWriteTime: 200, state: {'load_balancing_enable': value}};
|
|
2518
|
+
},
|
|
2519
|
+
convertGet: async (entity, key, meta) => {
|
|
2520
|
+
await entity.read('hvacThermostat', ['danfossLoadBalancingEnable'], manufacturerOptions.danfoss);
|
|
2521
|
+
},
|
|
2522
|
+
},
|
|
2523
|
+
danfoss_load_room_mean: {
|
|
2524
|
+
key: ['load_room_mean'],
|
|
2525
|
+
convertSet: async (entity, key, value, meta) => {
|
|
2526
|
+
await entity.write('hvacThermostat', {'danfossLoadRoomMean': value}, manufacturerOptions.danfoss);
|
|
2527
|
+
return {readAfterWriteTime: 200, state: {'load_room_mean': value}};
|
|
2528
|
+
},
|
|
2529
|
+
convertGet: async (entity, key, meta) => {
|
|
2530
|
+
await entity.read('hvacThermostat', ['danfossLoadRoomMean'], manufacturerOptions.danfoss);
|
|
2531
|
+
},
|
|
2532
|
+
},
|
|
2481
2533
|
danfoss_load_estimate: {
|
|
2482
2534
|
key: ['load_estimate'],
|
|
2483
2535
|
convertGet: async (entity, key, meta) => {
|
|
2484
2536
|
await entity.read('hvacThermostat', ['danfossLoadEstimate'], manufacturerOptions.danfoss);
|
|
2485
2537
|
},
|
|
2486
2538
|
},
|
|
2539
|
+
danfoss_output_status: {
|
|
2540
|
+
key: ['output_status'],
|
|
2541
|
+
convertGet: async (entity, key, meta) => {
|
|
2542
|
+
await entity.read('hvacThermostat', ['danfossOutputStatus'], manufacturerOptions.danfoss);
|
|
2543
|
+
},
|
|
2544
|
+
},
|
|
2545
|
+
danfoss_room_status_code: {
|
|
2546
|
+
key: ['room_status_code'],
|
|
2547
|
+
convertGet: async (entity, key, meta) => {
|
|
2548
|
+
await entity.read('hvacThermostat', ['danfossRoomStatusCode'], manufacturerOptions.danfoss);
|
|
2549
|
+
},
|
|
2550
|
+
},
|
|
2551
|
+
danfoss_system_status_code: {
|
|
2552
|
+
key: ['system_status_code'],
|
|
2553
|
+
convertGet: async (entity, key, meta) => {
|
|
2554
|
+
await entity.read('haDiagnostic', ['danfossSystemStatusCode'], manufacturerOptions.danfoss);
|
|
2555
|
+
},
|
|
2556
|
+
},
|
|
2557
|
+
danfoss_system_status_water: {
|
|
2558
|
+
key: ['system_status_water'],
|
|
2559
|
+
convertGet: async (entity, key, meta) => {
|
|
2560
|
+
await entity.read('haDiagnostic', ['danfossSystemStatusWater'], manufacturerOptions.danfoss);
|
|
2561
|
+
},
|
|
2562
|
+
},
|
|
2563
|
+
danfoss_multimaster_role: {
|
|
2564
|
+
key: ['multimaster_role'],
|
|
2565
|
+
convertGet: async (entity, key, meta) => {
|
|
2566
|
+
await entity.read('haDiagnostic', ['danfossMultimasterRole'], manufacturerOptions.danfoss);
|
|
2567
|
+
},
|
|
2568
|
+
},
|
|
2487
2569
|
ZMCSW032D_cover_position: {
|
|
2488
2570
|
key: ['position', 'tilt'],
|
|
2489
2571
|
convertSet: async (entity, key, value, meta) => {
|
|
@@ -2650,6 +2732,68 @@ const converters = {
|
|
|
2650
2732
|
await tuya.sendDataPointValue(entity, tuya.dataPoints.moesSminTempSet, temp);
|
|
2651
2733
|
},
|
|
2652
2734
|
},
|
|
2735
|
+
haozee_thermostat_system_mode: {
|
|
2736
|
+
key: ['preset'],
|
|
2737
|
+
convertSet: async (entity, key, value, meta) => {
|
|
2738
|
+
const lookup = {0: 'auto', 1: 'manual', 2: 'off', 3: 'on'};
|
|
2739
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.haozeeSystemMode, lookup[value]);
|
|
2740
|
+
},
|
|
2741
|
+
},
|
|
2742
|
+
haozee_thermostat_current_heating_setpoint: {
|
|
2743
|
+
key: ['current_heating_setpoint'],
|
|
2744
|
+
convertSet: async (entity, key, value, meta) => {
|
|
2745
|
+
const temp = Math.round(value*10);
|
|
2746
|
+
await tuya.sendDataPointValue(entity, tuya.dataPoints.haozeeHeatingSetpoint, temp);
|
|
2747
|
+
},
|
|
2748
|
+
},
|
|
2749
|
+
haozee_thermostat_boost_heating: {
|
|
2750
|
+
key: ['boost_heating'],
|
|
2751
|
+
convertSet: async (entity, key, value, meta) => {
|
|
2752
|
+
await tuya.sendDataPointBool(entity, tuya.dataPoints.haozeeBoostHeating, value === 'ON');
|
|
2753
|
+
},
|
|
2754
|
+
},
|
|
2755
|
+
haozee_thermostat_boost_heating_countdown: {
|
|
2756
|
+
key: ['boost_heating_countdown'],
|
|
2757
|
+
convertSet: async (entity, key, value, meta) => {
|
|
2758
|
+
await tuya.sendDataPointValue(entity, tuya.dataPoints.haozeeBoostHeatingCountdown, value);
|
|
2759
|
+
},
|
|
2760
|
+
},
|
|
2761
|
+
haozee_thermostat_window_detection: {
|
|
2762
|
+
key: ['window_detection'],
|
|
2763
|
+
convertSet: async (entity, key, value, meta) => {
|
|
2764
|
+
await tuya.sendDataPointBool(entity, tuya.dataPoints.haozeeWindowDetection, value === 'ON');
|
|
2765
|
+
},
|
|
2766
|
+
},
|
|
2767
|
+
haozee_thermostat_child_lock: {
|
|
2768
|
+
key: ['child_lock'],
|
|
2769
|
+
convertSet: async (entity, key, value, meta) => {
|
|
2770
|
+
await tuya.sendDataPointBool(entity, tuya.dataPoints.haozeeChildLock, value === 'LOCK');
|
|
2771
|
+
},
|
|
2772
|
+
},
|
|
2773
|
+
haozee_thermostat_temperature_calibration: {
|
|
2774
|
+
key: ['local_temperature_calibration'],
|
|
2775
|
+
convertSet: async (entity, key, value, meta) => {
|
|
2776
|
+
let temp = Math.round(value * 1);
|
|
2777
|
+
if (temp < 0) {
|
|
2778
|
+
temp = 0xFFFFFFFF + temp + 1;
|
|
2779
|
+
}
|
|
2780
|
+
await tuya.sendDataPointValue(entity, tuya.dataPoints.haozeeTempCalibration, temp);
|
|
2781
|
+
},
|
|
2782
|
+
},
|
|
2783
|
+
haozee_thermostat_max_temperature: {
|
|
2784
|
+
key: ['max_temperature'],
|
|
2785
|
+
convertSet: async (entity, key, value, meta) => {
|
|
2786
|
+
const temp = Math.round(value*10);
|
|
2787
|
+
await tuya.sendDataPointValue(entity, tuya.dataPoints.haozeeMaxTemp, temp);
|
|
2788
|
+
},
|
|
2789
|
+
},
|
|
2790
|
+
haozee_thermostat_min_temperature: {
|
|
2791
|
+
key: ['min_temperature'],
|
|
2792
|
+
convertSet: async (entity, key, value, meta) => {
|
|
2793
|
+
const temp = Math.round(value*10);
|
|
2794
|
+
await tuya.sendDataPointValue(entity, tuya.dataPoints.haozeeMinTemp, temp);
|
|
2795
|
+
},
|
|
2796
|
+
},
|
|
2653
2797
|
hgkg_thermostat_standby: {
|
|
2654
2798
|
key: ['system_mode'],
|
|
2655
2799
|
convertSet: async (entity, key, value, meta) => {
|
|
@@ -3144,7 +3288,7 @@ const converters = {
|
|
|
3144
3288
|
},
|
|
3145
3289
|
},
|
|
3146
3290
|
eurotronic_valve_position: {
|
|
3147
|
-
key: ['eurotronic_valve_position'],
|
|
3291
|
+
key: ['eurotronic_valve_position', 'valve_position'],
|
|
3148
3292
|
convertSet: async (entity, key, value, meta) => {
|
|
3149
3293
|
const payload = {0x4001: {value, type: 0x20}};
|
|
3150
3294
|
await entity.write('hvacThermostat', payload, manufacturerOptions.eurotronic);
|
|
@@ -3154,7 +3298,7 @@ const converters = {
|
|
|
3154
3298
|
},
|
|
3155
3299
|
},
|
|
3156
3300
|
eurotronic_trv_mode: {
|
|
3157
|
-
key: ['eurotronic_trv_mode'],
|
|
3301
|
+
key: ['eurotronic_trv_mode', 'trv_mode'],
|
|
3158
3302
|
convertSet: async (entity, key, value, meta) => {
|
|
3159
3303
|
const payload = {0x4000: {value, type: 0x30}};
|
|
3160
3304
|
await entity.write('hvacThermostat', payload, manufacturerOptions.eurotronic);
|
|
@@ -5868,7 +6012,7 @@ const converters = {
|
|
|
5868
6012
|
key: [
|
|
5869
6013
|
'system_mode', 'window_detection', 'frost_detection', 'child_lock',
|
|
5870
6014
|
'current_heating_setpoint', 'local_temperature_calibration',
|
|
5871
|
-
'holiday_temperature', 'comfort_temperature', 'eco_temperature',
|
|
6015
|
+
'holiday_temperature', 'comfort_temperature', 'eco_temperature',
|
|
5872
6016
|
'open_window_temperature', 'heating_stop', 'preset',
|
|
5873
6017
|
],
|
|
5874
6018
|
convertSet: async (entity, key, value, meta) => {
|
|
@@ -5882,13 +6026,18 @@ const converters = {
|
|
|
5882
6026
|
}
|
|
5883
6027
|
break;
|
|
5884
6028
|
case 'window_detection':
|
|
5885
|
-
await tuya.
|
|
6029
|
+
await tuya.sendDataPointBool(entity, tuya.dataPoints.tvWindowDetection, value);
|
|
5886
6030
|
break;
|
|
5887
6031
|
case 'frost_detection':
|
|
5888
|
-
|
|
6032
|
+
if (value == false) {
|
|
6033
|
+
await tuya.sendDataPointBool(entity, tuya.dataPoints.tvFrostDetection, 0);
|
|
6034
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.tvMode, 1);
|
|
6035
|
+
} else {
|
|
6036
|
+
await tuya.sendDataPointBool(entity, tuya.dataPoints.tvFrostDetection, 1);
|
|
6037
|
+
}
|
|
5889
6038
|
break;
|
|
5890
6039
|
case 'child_lock':
|
|
5891
|
-
await tuya.
|
|
6040
|
+
await tuya.sendDataPointBool(entity, tuya.dataPoints.tvChildLock, value === 'LOCK');
|
|
5892
6041
|
break;
|
|
5893
6042
|
case 'local_temperature_calibration':
|
|
5894
6043
|
value = Math.round(value * 10);
|
|
@@ -5949,6 +6098,22 @@ const converters = {
|
|
|
5949
6098
|
await endpoint.read('genAnalogInput', ['presentValue']);
|
|
5950
6099
|
},
|
|
5951
6100
|
},
|
|
6101
|
+
tuya_operation_mode: {
|
|
6102
|
+
key: ['operation_mode'],
|
|
6103
|
+
convertSet: async (entity, key, value, meta) => {
|
|
6104
|
+
// modes:
|
|
6105
|
+
// 0 - 'command' mode. keys send commands. useful for group control
|
|
6106
|
+
// 1 - 'event' mode. keys send events. useful for handling
|
|
6107
|
+
const lookup = {command: 0, event: 1};
|
|
6108
|
+
const endpoint = meta.device.getEndpoint(1);
|
|
6109
|
+
await endpoint.write('genOnOff', {'tuyaOperationMode': lookup[value.toLowerCase()]});
|
|
6110
|
+
return {state: {operation_mode: value.toLowerCase()}};
|
|
6111
|
+
},
|
|
6112
|
+
convertGet: async (entity, key, meta) => {
|
|
6113
|
+
const endpoint = meta.device.getEndpoint(1);
|
|
6114
|
+
await endpoint.read('genOnOff', ['tuyaOperationMode']);
|
|
6115
|
+
},
|
|
6116
|
+
},
|
|
5952
6117
|
// #endregion
|
|
5953
6118
|
|
|
5954
6119
|
// #region Ignore converters
|
package/devices/adeo.js
CHANGED
|
@@ -76,4 +76,13 @@ module.exports = [
|
|
|
76
76
|
},
|
|
77
77
|
exposes: [e.power(), e.switch(), e.energy()],
|
|
78
78
|
},
|
|
79
|
+
{
|
|
80
|
+
zigbeeModel: ['LDSENK10'],
|
|
81
|
+
model: 'LDSENK10',
|
|
82
|
+
vendor: 'ADEO',
|
|
83
|
+
description: 'LEXMAN motion sensor',
|
|
84
|
+
fromZigbee: [fz.ias_occupancy_alarm_1],
|
|
85
|
+
toZigbee: [],
|
|
86
|
+
exposes: [e.occupancy(), e.battery_low(), e.tamper()],
|
|
87
|
+
},
|
|
79
88
|
];
|
package/devices/danfoss.js
CHANGED
|
@@ -20,7 +20,7 @@ module.exports = [
|
|
|
20
20
|
tz.danfoss_heat_available, tz.danfoss_heat_required, tz.danfoss_day_of_week, tz.danfoss_trigger_time,
|
|
21
21
|
tz.danfoss_window_open_internal, tz.danfoss_window_open_external, tz.danfoss_load_estimate,
|
|
22
22
|
tz.danfoss_viewing_direction, tz.danfoss_external_measured_room_sensor, tz.thermostat_keypad_lockout,
|
|
23
|
-
tz.thermostat_system_mode],
|
|
23
|
+
tz.thermostat_system_mode, tz.danfoss_load_balancing_enable, tz.danfoss_load_room_mean],
|
|
24
24
|
exposes: [e.battery(), e.keypad_lockout(),
|
|
25
25
|
exposes.binary('mounted_mode_active', ea.STATE_GET, true, false)
|
|
26
26
|
.withDescription('Is the unit in mounting mode. This is set to `false` for mounted (already on ' +
|
|
@@ -57,6 +57,11 @@ module.exports = [
|
|
|
57
57
|
exposes.numeric('algorithm_scale_factor', ea.ALL).withValueMin(1).withValueMax(10)
|
|
58
58
|
.withDescription('Scale factor of setpoint filter timeconstant ("aggressiveness" of control algorithm) '+
|
|
59
59
|
'1= Quick ... 5=Moderate ... 10=Slow'),
|
|
60
|
+
exposes.binary('load_balancing_enable', ea.ALL, true, false)
|
|
61
|
+
.withDescription('Whether or not the thermostat acts as standalone thermostat or shares load with other ' +
|
|
62
|
+
'thermostats in the room. The gateway must update load_room_mean if enabled.'),
|
|
63
|
+
exposes.numeric('load_room_mean', ea.ALL)
|
|
64
|
+
.withDescription('Mean radiator load for room calculated by gateway for load balancing purposes'),
|
|
60
65
|
exposes.numeric('load_estimate', ea.STATE_GET)
|
|
61
66
|
.withDescription('Load estimate on this radiator')],
|
|
62
67
|
ota: ota.zigbeeOTA,
|
|
@@ -106,6 +111,8 @@ module.exports = [
|
|
|
106
111
|
'danfossMountedModeControl',
|
|
107
112
|
'danfossMountedModeActive',
|
|
108
113
|
'danfossExternalMeasuredRoomSensor',
|
|
114
|
+
'danfossLoadBalancingEnable',
|
|
115
|
+
'danfossLoadRoomMean',
|
|
109
116
|
], options);
|
|
110
117
|
|
|
111
118
|
// read systemMode to have an initial value
|
|
@@ -122,4 +129,133 @@ module.exports = [
|
|
|
122
129
|
endpoint.write('genTime', values);
|
|
123
130
|
},
|
|
124
131
|
},
|
|
132
|
+
{
|
|
133
|
+
fingerprint: [
|
|
134
|
+
{modelID: '0x8020', manufacturerName: 'Danfoss'}, // RT24V Display
|
|
135
|
+
{modelID: '0x8021', manufacturerName: 'Danfoss'}, // RT24V Display Floor sensor
|
|
136
|
+
{modelID: '0x8030', manufacturerName: 'Danfoss'}, // RTbattery Display
|
|
137
|
+
{modelID: '0x8031', manufacturerName: 'Danfoss'}, // RTbattery Display Infrared
|
|
138
|
+
{modelID: '0x8034', manufacturerName: 'Danfoss'}, // RTbattery Dial
|
|
139
|
+
{modelID: '0x8035', manufacturerName: 'Danfoss'}], // RTbattery Dial Infrared
|
|
140
|
+
model: 'Icon',
|
|
141
|
+
vendor: 'Danfoss',
|
|
142
|
+
description: 'Icon floor heating (regulator, Zigbee module & thermostats)',
|
|
143
|
+
fromZigbee: [
|
|
144
|
+
fz.danfoss_icon_regulator,
|
|
145
|
+
fz.danfoss_thermostat,
|
|
146
|
+
fz.danfoss_icon_battery,
|
|
147
|
+
fz.thermostat],
|
|
148
|
+
toZigbee: [
|
|
149
|
+
tz.thermostat_local_temperature,
|
|
150
|
+
tz.thermostat_occupied_heating_setpoint,
|
|
151
|
+
tz.thermostat_system_mode,
|
|
152
|
+
tz.thermostat_min_heat_setpoint_limit,
|
|
153
|
+
tz.thermostat_max_heat_setpoint_limit,
|
|
154
|
+
tz.danfoss_output_status,
|
|
155
|
+
tz.danfoss_room_status_code,
|
|
156
|
+
tz.danfoss_system_status_water,
|
|
157
|
+
tz.danfoss_system_status_code,
|
|
158
|
+
tz.danfoss_multimaster_role,
|
|
159
|
+
],
|
|
160
|
+
meta: {multiEndpoint: true},
|
|
161
|
+
// ota: ota.zigbeeOTA,
|
|
162
|
+
endpoint: (device) => {
|
|
163
|
+
return {
|
|
164
|
+
'l1': 1, 'l2': 2, 'l3': 3, 'l4': 4, 'l5': 5,
|
|
165
|
+
'l6': 6, 'l7': 7, 'l8': 8, 'l9': 9, 'l10': 10,
|
|
166
|
+
'l11': 11, 'l12': 12, 'l13': 13, 'l14': 14, 'l15': 15, 'l16': 232,
|
|
167
|
+
};
|
|
168
|
+
},
|
|
169
|
+
exposes: [].concat(((endpointsCount) => {
|
|
170
|
+
const features = [];
|
|
171
|
+
for (let i = 1; i <= endpointsCount; i++) {
|
|
172
|
+
const epName = `l${i}`;
|
|
173
|
+
if (i!=16) {
|
|
174
|
+
features.push(e.battery().withEndpoint(epName));
|
|
175
|
+
features.push(exposes.climate().withSetpoint('occupied_heating_setpoint', 4, 30, 0.5)
|
|
176
|
+
.withLocalTemperature().withSystemMode(['heat']).withEndpoint(epName));
|
|
177
|
+
features.push(exposes.numeric('abs_min_heat_setpoint_limit', ea.STATE)
|
|
178
|
+
.withUnit('°C').withEndpoint(epName)
|
|
179
|
+
.withDescription('Absolute min temperature allowed on the device'));
|
|
180
|
+
features.push(exposes.numeric('abs_max_heat_setpoint_limit', ea.STATE)
|
|
181
|
+
.withUnit('°C').withEndpoint(epName)
|
|
182
|
+
.withDescription('Absolute max temperature allowed on the device'));
|
|
183
|
+
features.push(exposes.numeric('min_heat_setpoint_limit', ea.ALL)
|
|
184
|
+
.withValueMin(4).withValueMax(30).withValueStep(0.5).withUnit('°C')
|
|
185
|
+
.withEndpoint(epName).withDescription('Min temperature limit set on the device'));
|
|
186
|
+
features.push(exposes.numeric('max_heat_setpoint_limit', ea.ALL)
|
|
187
|
+
.withValueMin(4).withValueMax(30).withValueStep(0.5).withUnit('°C')
|
|
188
|
+
.withEndpoint(epName).withDescription('Max temperature limit set on the device'));
|
|
189
|
+
features.push(exposes.enum('setpoint_change_source', ea.STATE, ['manual', 'schedule', 'externally'])
|
|
190
|
+
.withEndpoint(epName));
|
|
191
|
+
features.push(exposes.enum('output_status', ea.STATE_GET, ['inactive', 'active'])
|
|
192
|
+
.withEndpoint(epName).withDescription('Danfoss Output Status [Active vs Inactive])'));
|
|
193
|
+
features.push(exposes.enum('room_status_code', ea.STATE_GET, ['no_error', 'missing_rt',
|
|
194
|
+
'rt_touch_error', 'floor_sensor_short_circuit', 'floor_sensor_disconnected'])
|
|
195
|
+
.withEndpoint(epName).withDescription('Thermostat status'));
|
|
196
|
+
} else {
|
|
197
|
+
features.push(exposes.enum('system_status_code', ea.STATE_GET, ['no_error', 'missing_expansion_board',
|
|
198
|
+
'missing_radio_module', 'missing_command_module', 'missing_master_rail', 'missing_slave_rail_no_1',
|
|
199
|
+
'missing_slave_rail_no_2', 'pt1000_input_short_circuit', 'pt1000_input_open_circuit',
|
|
200
|
+
'error_on_one_or_more_output']).withEndpoint('l16').withDescription('Regulator Status'));
|
|
201
|
+
features.push(exposes.enum('system_status_water', ea.STATE_GET, ['hot_water_flow_in_pipes', 'cool_water_flow_in_pipes'])
|
|
202
|
+
.withEndpoint('l16').withDescription('Water Status of Regulator'));
|
|
203
|
+
features.push(exposes.enum('multimaster_role', ea.STATE_GET, ['invalid_unused', 'master', 'slave_1', 'slave_2'])
|
|
204
|
+
.withEndpoint('l16').withDescription('Regulator role (Master vs Slave)'));
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return features;
|
|
209
|
+
})(16)),
|
|
210
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
211
|
+
const options = {manufacturerCode: 0x1246};
|
|
212
|
+
|
|
213
|
+
for (let i = 1; i <= 15; i++) {
|
|
214
|
+
const endpoint = device.getEndpoint(i);
|
|
215
|
+
if (typeof endpoint !== 'undefined') {
|
|
216
|
+
await reporting.bind(endpoint, coordinatorEndpoint,
|
|
217
|
+
['genPowerCfg', 'hvacThermostat', 'hvacUserInterfaceCfg']);
|
|
218
|
+
await reporting.batteryPercentageRemaining(endpoint,
|
|
219
|
+
{min: constants.repInterval.HOUR, max: 43200, change: 1});
|
|
220
|
+
await reporting.thermostatTemperature(endpoint,
|
|
221
|
+
{min: 0, max: constants.repInterval.MINUTES_10, change: 10});
|
|
222
|
+
await reporting.thermostatOccupiedHeatingSetpoint(endpoint,
|
|
223
|
+
{min: 0, max: constants.repInterval.MINUTES_10, change: 10});
|
|
224
|
+
|
|
225
|
+
await endpoint.configureReporting('hvacThermostat', [{
|
|
226
|
+
attribute: 'danfossOutputStatus',
|
|
227
|
+
minimumReportInterval: constants.repInterval.MINUTE,
|
|
228
|
+
maximumReportInterval: constants.repInterval.MINUTES_10,
|
|
229
|
+
reportableChange: 1,
|
|
230
|
+
}], options);
|
|
231
|
+
|
|
232
|
+
// Danfoss Icon Thermostat Specific
|
|
233
|
+
await endpoint.read('hvacThermostat', [
|
|
234
|
+
'danfossOutputStatus',
|
|
235
|
+
'danfossRoomStatusCode'], options);
|
|
236
|
+
|
|
237
|
+
// Standard Thermostat
|
|
238
|
+
await endpoint.read('hvacThermostat', ['localTemp']);
|
|
239
|
+
await endpoint.read('hvacThermostat', ['occupiedHeatingSetpoint']);
|
|
240
|
+
await endpoint.read('hvacThermostat', ['systemMode']);
|
|
241
|
+
await endpoint.read('hvacThermostat', ['setpointChangeSource']);
|
|
242
|
+
await endpoint.read('hvacThermostat', ['absMinHeatSetpointLimit']);
|
|
243
|
+
await endpoint.read('hvacThermostat', ['absMaxHeatSetpointLimit']);
|
|
244
|
+
await endpoint.read('hvacThermostat', ['minHeatSetpointLimit']);
|
|
245
|
+
await endpoint.read('hvacThermostat', ['maxHeatSetpointLimit']);
|
|
246
|
+
await endpoint.read('genPowerCfg', ['batteryPercentageRemaining']);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Danfoss Icon Regulator Specific
|
|
251
|
+
const endpoint232 = device.getEndpoint(232);
|
|
252
|
+
|
|
253
|
+
await reporting.bind(endpoint232, coordinatorEndpoint, ['haDiagnostic']);
|
|
254
|
+
|
|
255
|
+
await endpoint232.read('haDiagnostic', [
|
|
256
|
+
'danfossSystemStatusCode',
|
|
257
|
+
'danfossSystemStatusWater',
|
|
258
|
+
'danfossMultimasterRole'], options);
|
|
259
|
+
},
|
|
260
|
+
},
|
|
125
261
|
];
|
package/devices/eurotronic.js
CHANGED
|
@@ -21,13 +21,13 @@ module.exports = [
|
|
|
21
21
|
exposes: [e.battery(), exposes.climate().withSetpoint('occupied_heating_setpoint', 5, 30, 0.5).withLocalTemperature()
|
|
22
22
|
.withSystemMode(['off', 'auto', 'heat']).withRunningState(['idle', 'heat']).withLocalTemperatureCalibration()
|
|
23
23
|
.withPiHeatingDemand(),
|
|
24
|
-
exposes.enum('
|
|
25
|
-
.withDescription('Select between direct control of the valve via the `
|
|
24
|
+
exposes.enum('trv_mode', exposes.access.ALL, [1, 2])
|
|
25
|
+
.withDescription('Select between direct control of the valve via the `valve_position` or automatic control of the '+
|
|
26
26
|
'valve based on the `current_heating_setpoint`. For manual control set the value to 1, for automatic control set the value '+
|
|
27
27
|
'to 2 (the default). When switched to manual mode the display shows a value from 0 (valve closed) to 100 (valve fully open) '+
|
|
28
28
|
'and the buttons on the device are disabled.'),
|
|
29
|
-
exposes.numeric('
|
|
30
|
-
.withDescription('Directly control the radiator valve when `
|
|
29
|
+
exposes.numeric('valve_position', exposes.access.ALL).withValueMin(0).withValueMax(255)
|
|
30
|
+
.withDescription('Directly control the radiator valve when `trv_mode` is set to 1. The values range from 0 (valve '+
|
|
31
31
|
'closed) to 255 (valve fully open)')],
|
|
32
32
|
ota: ota.zigbeeOTA,
|
|
33
33
|
configure: async (device, coordinatorEndpoint, logger) => {
|
package/devices/ikea.js
CHANGED
|
@@ -486,7 +486,9 @@ module.exports = [
|
|
|
486
486
|
toZigbee: [],
|
|
487
487
|
exposes: [e.battery(), e.occupancy(),
|
|
488
488
|
exposes.numeric('requested_brightness_level', ea.STATE).withValueMin(76).withValueMax(254),
|
|
489
|
-
exposes.numeric('requested_brightness_percent', ea.STATE).withValueMin(30).withValueMax(100)
|
|
489
|
+
exposes.numeric('requested_brightness_percent', ea.STATE).withValueMin(30).withValueMax(100),
|
|
490
|
+
exposes.binary('illuminance_above_threshold', ea.STATE, true, false)
|
|
491
|
+
.withDescription('Indicates whether the device detected bright light (works only in night mode)')],
|
|
490
492
|
ota: ota.tradfri,
|
|
491
493
|
meta: {battery: {dontDividePercentage: true}},
|
|
492
494
|
configure: async (device, coordinatorEndpoint, logger) => {
|
package/devices/philips.js
CHANGED
|
@@ -2165,4 +2165,22 @@ module.exports = [
|
|
|
2165
2165
|
meta: {turnsOffAtBrightness1: true},
|
|
2166
2166
|
ota: ota.zigbeeOTA,
|
|
2167
2167
|
},
|
|
2168
|
+
{
|
|
2169
|
+
zigbeeModel: ['LTF001'],
|
|
2170
|
+
model: '6109231C5',
|
|
2171
|
+
vendor: 'Philips',
|
|
2172
|
+
description: 'Hue white ambiance Apogee square',
|
|
2173
|
+
meta: {turnsOffAtBrightness1: true},
|
|
2174
|
+
extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
|
|
2175
|
+
ota: ota.zigbeeOTA,
|
|
2176
|
+
},
|
|
2177
|
+
{
|
|
2178
|
+
zigbeeModel: ['LTF002'],
|
|
2179
|
+
model: '6109331C5',
|
|
2180
|
+
vendor: 'Philips',
|
|
2181
|
+
description: 'Hue white ambiance Apogee round',
|
|
2182
|
+
meta: {turnsOffAtBrightness1: true},
|
|
2183
|
+
extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
|
|
2184
|
+
ota: ota.zigbeeOTA,
|
|
2185
|
+
},
|
|
2168
2186
|
];
|
package/devices/shinasystem.js
CHANGED
|
@@ -11,7 +11,7 @@ module.exports = [
|
|
|
11
11
|
zigbeeModel: ['CSM-300Z'],
|
|
12
12
|
model: 'CSM-300ZB',
|
|
13
13
|
vendor: 'ShinaSystem',
|
|
14
|
-
description: '
|
|
14
|
+
description: 'SiHAS multipurpose sensor',
|
|
15
15
|
meta: {battery: {voltageToPercentage: '3V_2100'}},
|
|
16
16
|
fromZigbee: [fz.battery, fz.sihas_people_cnt],
|
|
17
17
|
toZigbee: [tz.sihas_set_people],
|
|
@@ -30,7 +30,7 @@ module.exports = [
|
|
|
30
30
|
zigbeeModel: ['USM-300Z'],
|
|
31
31
|
model: 'USM-300ZB',
|
|
32
32
|
vendor: 'ShinaSystem',
|
|
33
|
-
description: '
|
|
33
|
+
description: 'SiHAS multipurpose sensor',
|
|
34
34
|
meta: {battery: {voltageToPercentage: '3V_2100'}},
|
|
35
35
|
fromZigbee: [fz.battery, fz.temperature, fz.humidity, fz.occupancy, fz.illuminance],
|
|
36
36
|
toZigbee: [],
|
|
@@ -51,7 +51,7 @@ module.exports = [
|
|
|
51
51
|
zigbeeModel: ['SBM300Z1'],
|
|
52
52
|
model: 'SBM300Z1',
|
|
53
53
|
vendor: 'ShinaSystem',
|
|
54
|
-
description: 'IOT smart switch 1 gang',
|
|
54
|
+
description: 'SiHAS IOT smart switch 1 gang',
|
|
55
55
|
extend: extend.switch(),
|
|
56
56
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
57
57
|
const endpoint = device.getEndpoint(1);
|
|
@@ -63,7 +63,7 @@ module.exports = [
|
|
|
63
63
|
zigbeeModel: ['SBM300Z2'],
|
|
64
64
|
model: 'SBM300Z2',
|
|
65
65
|
vendor: 'ShinaSystem',
|
|
66
|
-
description: 'IOT smart switch 2 gang',
|
|
66
|
+
description: 'SiHAS IOT smart switch 2 gang',
|
|
67
67
|
extend: extend.switch(),
|
|
68
68
|
exposes: [e.switch().withEndpoint('top'), e.switch().withEndpoint('bottom')],
|
|
69
69
|
endpoint: (device) => {
|
|
@@ -81,7 +81,7 @@ module.exports = [
|
|
|
81
81
|
zigbeeModel: ['SBM300Z3'],
|
|
82
82
|
model: 'SBM300Z3',
|
|
83
83
|
vendor: 'ShinaSystem',
|
|
84
|
-
description: 'IOT smart switch 3 gang',
|
|
84
|
+
description: 'SiHAS IOT smart switch 3 gang',
|
|
85
85
|
extend: extend.switch(),
|
|
86
86
|
exposes: [e.switch().withEndpoint('top'), e.switch().withEndpoint('center'), e.switch().withEndpoint('bottom')],
|
|
87
87
|
endpoint: (device) => {
|
|
@@ -101,7 +101,7 @@ module.exports = [
|
|
|
101
101
|
zigbeeModel: ['SBM300Z4'],
|
|
102
102
|
model: 'SBM300Z4',
|
|
103
103
|
vendor: 'ShinaSystem',
|
|
104
|
-
description: 'IOT smart switch 4 gang',
|
|
104
|
+
description: 'SiHAS IOT smart switch 4 gang',
|
|
105
105
|
extend: extend.switch(),
|
|
106
106
|
exposes: [e.switch().withEndpoint('top_left'), e.switch().withEndpoint('bottom_left'),
|
|
107
107
|
e.switch().withEndpoint('top_right'), e.switch().withEndpoint('bottom_right')],
|
|
@@ -124,7 +124,7 @@ module.exports = [
|
|
|
124
124
|
zigbeeModel: ['SBM300Z5'],
|
|
125
125
|
model: 'SBM300Z5',
|
|
126
126
|
vendor: 'ShinaSystem',
|
|
127
|
-
description: 'IOT smart switch 5 gang',
|
|
127
|
+
description: 'SiHAS IOT smart switch 5 gang',
|
|
128
128
|
extend: extend.switch(),
|
|
129
129
|
exposes: [e.switch().withEndpoint('top_left'), e.switch().withEndpoint('top_right'), e.switch().withEndpoint('center_left'),
|
|
130
130
|
e.switch().withEndpoint('bottom_left'), e.switch().withEndpoint('bottom_right')],
|
|
@@ -149,7 +149,7 @@ module.exports = [
|
|
|
149
149
|
zigbeeModel: ['SBM300Z6'],
|
|
150
150
|
model: 'SBM300Z6',
|
|
151
151
|
vendor: 'ShinaSystem',
|
|
152
|
-
description: 'IOT smart switch 6 gang',
|
|
152
|
+
description: 'SiHAS IOT smart switch 6 gang',
|
|
153
153
|
extend: extend.switch(),
|
|
154
154
|
exposes: [e.switch().withEndpoint('top_left'), e.switch().withEndpoint('bottom_left'), e.switch().withEndpoint('center_left'),
|
|
155
155
|
e.switch().withEndpoint('center_right'), e.switch().withEndpoint('top_right'), e.switch().withEndpoint('bottom_right')],
|
|
@@ -172,4 +172,114 @@ module.exports = [
|
|
|
172
172
|
await reporting.onOff(device.getEndpoint(6));
|
|
173
173
|
},
|
|
174
174
|
},
|
|
175
|
+
{
|
|
176
|
+
zigbeeModel: ['BSM-300Z'],
|
|
177
|
+
model: 'BSM-300ZB',
|
|
178
|
+
vendor: 'ShinaSystem',
|
|
179
|
+
description: 'SiHAS remote control',
|
|
180
|
+
meta: {battery: {voltageToPercentage: '3V_2100'}},
|
|
181
|
+
fromZigbee: [fz.battery, fz.sihas_action],
|
|
182
|
+
toZigbee: [],
|
|
183
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
184
|
+
const endpoint = device.getEndpoint(1);
|
|
185
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg']);
|
|
186
|
+
await reporting.batteryVoltage(endpoint);
|
|
187
|
+
},
|
|
188
|
+
exposes: [e.battery(), e.battery_voltage(), e.action(['single', 'double', 'long'])],
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
zigbeeModel: ['TSM-300Z'],
|
|
192
|
+
model: 'TSM-300ZB',
|
|
193
|
+
vendor: 'ShinaSystem',
|
|
194
|
+
description: 'SiHAS temperature/humidity sensor',
|
|
195
|
+
meta: {battery: {voltageToPercentage: '3V_2100'}},
|
|
196
|
+
fromZigbee: [fz.temperature, fz.humidity, fz.battery],
|
|
197
|
+
toZigbee: [],
|
|
198
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
199
|
+
const endpoint = device.getEndpoint(1);
|
|
200
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['msTemperatureMeasurement', 'msRelativeHumidity', 'genPowerCfg']);
|
|
201
|
+
await reporting.temperature(endpoint, {min: 30, max: 300, change: 30});
|
|
202
|
+
await reporting.humidity(endpoint, {min: 30, max: 3600, change: 50});
|
|
203
|
+
await reporting.batteryVoltage(endpoint, {min: 30, max: 21600, change: 1});
|
|
204
|
+
},
|
|
205
|
+
exposes: [e.temperature(), e.humidity(), e.battery(), e.battery_voltage()],
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
zigbeeModel: ['DSM-300Z'],
|
|
209
|
+
model: 'DSM-300ZB',
|
|
210
|
+
vendor: 'ShinaSystem',
|
|
211
|
+
description: 'SiHAS contact sensor',
|
|
212
|
+
meta: {battery: {voltageToPercentage: '3V_2100'}},
|
|
213
|
+
fromZigbee: [fz.ias_contact_alarm_1, fz.battery],
|
|
214
|
+
toZigbee: [],
|
|
215
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
216
|
+
const endpoint = device.getEndpoint(1);
|
|
217
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['ssIasZone', 'genPowerCfg']);
|
|
218
|
+
await endpoint.read('ssIasZone', ['iasCieAddr', 'zoneState', 'zoneId']);
|
|
219
|
+
await reporting.batteryVoltage(endpoint, {min: 30, max: 21600, change: 1});
|
|
220
|
+
},
|
|
221
|
+
exposes: [e.contact(), e.battery(), e.battery_voltage()],
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
zigbeeModel: ['MSM-300Z'],
|
|
225
|
+
model: 'MSM-300ZB',
|
|
226
|
+
vendor: 'ShinaSystem',
|
|
227
|
+
description: 'SiHAS remote control 4 button',
|
|
228
|
+
fromZigbee: [fz.sihas_action, fz.battery],
|
|
229
|
+
toZigbee: [],
|
|
230
|
+
exposes: [e.action(['1_single', '1_double', '1_long', '2_single', '2_double', '2_long',
|
|
231
|
+
'3_single', '3_double', '3_long', '4_single', '4_double', '4_long']), e.battery(), e.battery_voltage()],
|
|
232
|
+
meta: {battery: {voltageToPercentage: '3V_2100'}},
|
|
233
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
234
|
+
const endpoint = device.getEndpoint(1);
|
|
235
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg']);
|
|
236
|
+
await reporting.batteryVoltage(endpoint, {min: 30, max: 21600, change: 1});
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
zigbeeModel: ['SBM300ZB1'],
|
|
241
|
+
model: 'SBM300ZB1',
|
|
242
|
+
vendor: 'ShinaSystem',
|
|
243
|
+
description: 'SiHAS remote control',
|
|
244
|
+
meta: {battery: {voltageToPercentage: '3V_2100'}},
|
|
245
|
+
fromZigbee: [fz.battery, fz.sihas_action],
|
|
246
|
+
toZigbee: [],
|
|
247
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
248
|
+
const endpoint = device.getEndpoint(1);
|
|
249
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg']);
|
|
250
|
+
await reporting.batteryVoltage(endpoint);
|
|
251
|
+
},
|
|
252
|
+
exposes: [e.battery(), e.battery_voltage(), e.action(['single', 'double', 'long'])],
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
zigbeeModel: ['SBM300ZB2'],
|
|
256
|
+
model: 'SBM300ZB2',
|
|
257
|
+
vendor: 'ShinaSystem',
|
|
258
|
+
description: 'SiHAS remote control 2 button',
|
|
259
|
+
fromZigbee: [fz.sihas_action, fz.battery],
|
|
260
|
+
toZigbee: [],
|
|
261
|
+
exposes: [e.action(['1_single', '1_double', '1_long', '2_single', '2_double', '2_long']), e.battery(), e.battery_voltage()],
|
|
262
|
+
meta: {battery: {voltageToPercentage: '3V_2100'}},
|
|
263
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
264
|
+
const endpoint = device.getEndpoint(1);
|
|
265
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg']);
|
|
266
|
+
await reporting.batteryVoltage(endpoint, {min: 30, max: 21600, change: 1});
|
|
267
|
+
},
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
zigbeeModel: ['SBM300ZB3'],
|
|
271
|
+
model: 'SBM300ZB3',
|
|
272
|
+
vendor: 'ShinaSystem',
|
|
273
|
+
description: 'SiHAS remote control 3 button',
|
|
274
|
+
fromZigbee: [fz.sihas_action, fz.battery],
|
|
275
|
+
toZigbee: [],
|
|
276
|
+
exposes: [e.action(['1_single', '1_double', '1_long', '2_single', '2_double', '2_long',
|
|
277
|
+
'3_single', '3_double', '3_long']), e.battery(), e.battery_voltage()],
|
|
278
|
+
meta: {battery: {voltageToPercentage: '3V_2100'}},
|
|
279
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
280
|
+
const endpoint = device.getEndpoint(1);
|
|
281
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg']);
|
|
282
|
+
await reporting.batteryVoltage(endpoint, {min: 30, max: 21600, change: 1});
|
|
283
|
+
},
|
|
284
|
+
},
|
|
175
285
|
];
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
const exposes = require('../lib/exposes');
|
|
2
2
|
const fz = {...require('../converters/fromZigbee'), legacy: require('../lib/legacy').fromZigbee};
|
|
3
|
+
const reporting = require('../lib/reporting');
|
|
4
|
+
const extend = require('../lib/extend');
|
|
3
5
|
const e = exposes.presets;
|
|
4
6
|
|
|
5
7
|
module.exports = [
|
|
@@ -21,4 +23,17 @@ module.exports = [
|
|
|
21
23
|
return {l1: 1, l2: 2, l3: 3, l4: 4};
|
|
22
24
|
},
|
|
23
25
|
},
|
|
26
|
+
{
|
|
27
|
+
zigbeeModel: ['S24013'],
|
|
28
|
+
model: 'S24013',
|
|
29
|
+
vendor: 'The Light Group',
|
|
30
|
+
description: 'SLC SmartOne AC dimmer mini 200W Zigbee LN',
|
|
31
|
+
extend: extend.light_onoff_brightness({noConfigure: true}),
|
|
32
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
33
|
+
await extend.light_onoff_brightness().configure(device, coordinatorEndpoint, logger);
|
|
34
|
+
const endpoint = device.getEndpoint(1);
|
|
35
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'genLevelCtrl']);
|
|
36
|
+
await reporting.onOff(endpoint);
|
|
37
|
+
},
|
|
38
|
+
},
|
|
24
39
|
];
|
package/devices/tuya.js
CHANGED
|
@@ -103,12 +103,15 @@ module.exports = [
|
|
|
103
103
|
{
|
|
104
104
|
fingerprint: [{modelID: 'TS0505B', manufacturerName: '_TZ3000_qqjaziws'},
|
|
105
105
|
{modelID: 'TS0505B', manufacturerName: '_TZ3000_jtmhndw2'},
|
|
106
|
+
{modelID: 'TS0505B', manufacturerName: '_TZ3000_ezlg0pht'},
|
|
106
107
|
{modelID: 'TS0505B', manufacturerName: '_TZ3210_5snkkrxw'},
|
|
107
108
|
{modelID: 'TS0505B', manufacturerName: '_TZ3000_12sxjap4'},
|
|
108
109
|
{modelID: 'TS0505B', manufacturerName: '_TZ3000_x2fqbdun'},
|
|
109
110
|
{modelID: 'TS0505B', manufacturerName: '_TZ3000_589kq4ul'},
|
|
110
111
|
{modelID: 'TS0505B', manufacturerName: '_TZ3000_1mtktxdk'},
|
|
111
|
-
{modelID: 'TS0505B', manufacturerName: '_TZ3210_bicjqpg4'}
|
|
112
|
+
{modelID: 'TS0505B', manufacturerName: '_TZ3210_bicjqpg4'},
|
|
113
|
+
{modelID: 'TS0505B', manufacturerName: '_TZ3000_cmaky9gq'},
|
|
114
|
+
{modelID: 'TS0505B', manufacturerName: '_TZ3000_tza2vjxx'}],
|
|
112
115
|
model: 'TS0505B',
|
|
113
116
|
vendor: 'TuYa',
|
|
114
117
|
description: 'Zigbee RGB+CCT light',
|
|
@@ -423,6 +426,7 @@ module.exports = [
|
|
|
423
426
|
{
|
|
424
427
|
fingerprint: [
|
|
425
428
|
{modelID: 'TS0502B', manufacturerName: '_TZ3210_s1x7gcq0'},
|
|
429
|
+
{modelID: 'TS0502B', manufacturerName: '_TZ3000_muqovqv0'},
|
|
426
430
|
{modelID: 'TS0502B', manufacturerName: '_TZ3210_hi1ym4bl'},
|
|
427
431
|
{modelID: 'TS0502B', manufacturerName: '_TZ3210_psgq7ysz'},
|
|
428
432
|
{modelID: 'TS0502B', manufacturerName: '_TZ3000_zw7wr5uo'},
|
|
@@ -606,7 +610,7 @@ module.exports = [
|
|
|
606
610
|
},
|
|
607
611
|
},
|
|
608
612
|
{
|
|
609
|
-
fingerprint: [{modelID: 'TS0002', manufacturerName: '_TZ3000_01gpyda5'}],
|
|
613
|
+
fingerprint: [{modelID: 'TS0002', manufacturerName: '_TZ3000_01gpyda5'}, {modelID: 'TS0002', manufacturerName: '_TZ3000_bvrlqyj7'}],
|
|
610
614
|
model: 'TS0002_switch_module',
|
|
611
615
|
vendor: 'TuYa',
|
|
612
616
|
description: '2 gang switch module',
|
|
@@ -744,13 +748,12 @@ module.exports = [
|
|
|
744
748
|
{
|
|
745
749
|
zigbeeModel: ['kud7u2l'],
|
|
746
750
|
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_ckud7u2l'}, {modelID: 'TS0601', manufacturerName: '_TZE200_ywdxldoj'},
|
|
747
|
-
{modelID: 'TS0601', manufacturerName: '_TZE200_cwnjrr72'}, {modelID: 'TS0601', manufacturerName: '_TZE200_chyvmhay'},
|
|
748
|
-
{modelID: 'TS0601', manufacturerName: '_TZE200_a4bpgplm'}],
|
|
751
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_cwnjrr72'}, {modelID: 'TS0601', manufacturerName: '_TZE200_chyvmhay'}],
|
|
749
752
|
model: 'TS0601_thermostat',
|
|
750
753
|
vendor: 'TuYa',
|
|
751
754
|
description: 'Radiator valve with thermostat',
|
|
752
755
|
whiteLabel: [{vendor: 'Moes', model: 'HY368'}, {vendor: 'Moes', model: 'HY369RT'}, {vendor: 'SHOJZJ', model: '378RT'},
|
|
753
|
-
{vendor: 'Silvercrest', model: 'TVR01'}
|
|
756
|
+
{vendor: 'Silvercrest', model: 'TVR01'}],
|
|
754
757
|
meta: {tuyaThermostatPreset: tuya.thermostatPresets, tuyaThermostatSystemMode: tuya.thermostatSystemModes3},
|
|
755
758
|
ota: ota.zigbeeOTA,
|
|
756
759
|
onEvent: tuya.onEventSetLocalTime,
|
|
@@ -819,6 +822,46 @@ module.exports = [
|
|
|
819
822
|
.withSystemMode(['off', 'heat', 'auto'], ea.STATE_SET).withRunningState(['idle', 'heat'], ea.STATE),
|
|
820
823
|
],
|
|
821
824
|
},
|
|
825
|
+
{
|
|
826
|
+
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_a4bpgplm'}],
|
|
827
|
+
model: 'TS0601',
|
|
828
|
+
vendor: 'TS0601_thermostat_1',
|
|
829
|
+
description: 'Thermostatic radiator valve',
|
|
830
|
+
onEvent: tuya.onEventSetLocalTime,
|
|
831
|
+
fromZigbee: [fz.ignore_basic_report, fz.ignore_tuya_set_time, fz.haozee_thermostat],
|
|
832
|
+
toZigbee: [
|
|
833
|
+
tz.haozee_thermostat_system_mode, tz.haozee_thermostat_current_heating_setpoint, tz.haozee_thermostat_boost_heating,
|
|
834
|
+
tz.haozee_thermostat_boost_heating_countdown, tz.haozee_thermostat_window_detection,
|
|
835
|
+
tz.haozee_thermostat_child_lock, tz.haozee_thermostat_temperature_calibration, tz.haozee_thermostat_max_temperature,
|
|
836
|
+
tz.haozee_thermostat_min_temperature,
|
|
837
|
+
],
|
|
838
|
+
exposes: [
|
|
839
|
+
e.battery(), e.child_lock(), e.max_temperature(), e.min_temperature(),
|
|
840
|
+
e.position(), e.window_detection(),
|
|
841
|
+
exposes.binary('window', ea.STATE, 'CLOSED', 'OPEN').withDescription('Window status closed or open '),
|
|
842
|
+
exposes.binary('heating', ea.STATE, 'ON', 'OFF').withDescription('Device valve is open or closed (heating or not)'),
|
|
843
|
+
exposes.climate()
|
|
844
|
+
.withLocalTemperature(ea.STATE).withSetpoint('current_heating_setpoint', 5, 35, 0.5, ea.STATE_SET)
|
|
845
|
+
.withLocalTemperatureCalibration(ea.STATE_SET).withPreset(['auto', 'manual', 'off', 'on'],
|
|
846
|
+
'MANUAL MODE ☝ - In this mode, the device executes manual temperature setting. ' +
|
|
847
|
+
'When the set temperature is lower than the "minimum temperature", the valve is closed (forced closed). ' +
|
|
848
|
+
'AUTO MODE ⏱ - In this mode, the device executes a preset week programming temperature time and temperature. ' +
|
|
849
|
+
'ON - In this mode, the thermostat stays open ' +
|
|
850
|
+
'OFF - In this mode, the thermostat stays closed'),
|
|
851
|
+
exposes.composite('programming_mode').withDescription('Auto MODE ⏱ - In this mode, ' +
|
|
852
|
+
'the device executes a preset week programming temperature time and temperature. ')
|
|
853
|
+
.withFeature(exposes.text('monday_schedule', ea.STATE))
|
|
854
|
+
.withFeature(exposes.text('tuesday_schedule', ea.STATE))
|
|
855
|
+
.withFeature(exposes.text('wednesday_schedule', ea.STATE))
|
|
856
|
+
.withFeature(exposes.text('thursday_schedule', ea.STATE))
|
|
857
|
+
.withFeature(exposes.text('friday_schedule', ea.STATE))
|
|
858
|
+
.withFeature(exposes.text('saturday_schedule', ea.STATE))
|
|
859
|
+
.withFeature(exposes.text('sunday_schedule', ea.STATE)),
|
|
860
|
+
exposes.binary('boost_heating', ea.STATE_SET, 'ON', 'OFF').withDescription('Boost Heating: press and hold "+" for 3 seconds, ' +
|
|
861
|
+
'the device will enter the boost heating mode, and the ▷╵◁ will flash. The countdown will be displayed in the APP'),
|
|
862
|
+
exposes.numeric('boost_heating_countdown', ea.STATE_SET).withUnit('min').withDescription('Countdown in minutes'),
|
|
863
|
+
],
|
|
864
|
+
},
|
|
822
865
|
{
|
|
823
866
|
zigbeeModel: ['TS0121'],
|
|
824
867
|
model: 'TS0121_plug',
|
|
@@ -865,7 +908,7 @@ module.exports = [
|
|
|
865
908
|
extend: extend.switch(),
|
|
866
909
|
},
|
|
867
910
|
{
|
|
868
|
-
fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_cphmq0q7'},
|
|
911
|
+
fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_cphmq0q7', applicationVersion: 67},
|
|
869
912
|
{modelID: 'TS011F', manufacturerName: '_TZ3000_ew3ldmgx'},
|
|
870
913
|
{modelID: 'TS011F', manufacturerName: '_TZ3000_ps3dmato'},
|
|
871
914
|
{modelID: 'TS011F', manufacturerName: '_TZ3000_mraovvmm'},
|
|
@@ -906,7 +949,8 @@ module.exports = [
|
|
|
906
949
|
.withDescription('Recover state after power outage')],
|
|
907
950
|
},
|
|
908
951
|
{
|
|
909
|
-
fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_dpo1ysak'}
|
|
952
|
+
fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_dpo1ysak'},
|
|
953
|
+
{modelID: 'TS011F', manufacturerName: '_TZ3000_cphmq0q7', applicationVersion: 69}],
|
|
910
954
|
model: 'TS011F_plug_3',
|
|
911
955
|
description: 'Smart plug (with power monitoring by polling)',
|
|
912
956
|
vendor: 'TuYa',
|
|
@@ -914,6 +958,7 @@ module.exports = [
|
|
|
914
958
|
toZigbee: [tz.on_off, tz.tuya_switch_power_outage_memory],
|
|
915
959
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
916
960
|
const endpoint = device.getEndpoint(1);
|
|
961
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff']);
|
|
917
962
|
endpoint.saveClusterAttributeKeyValue('haElectricalMeasurement', {acCurrentDivisor: 1000, acCurrentMultiplier: 1});
|
|
918
963
|
endpoint.saveClusterAttributeKeyValue('seMetering', {divisor: 100, multiplier: 1});
|
|
919
964
|
device.save();
|
|
@@ -1411,20 +1456,26 @@ module.exports = [
|
|
|
1411
1456
|
model: 'YSR-MINI-Z',
|
|
1412
1457
|
vendor: 'TuYa',
|
|
1413
1458
|
description: '2 in 1 dimming remote control and scene control',
|
|
1414
|
-
exposes: [
|
|
1415
|
-
|
|
1416
|
-
'
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1459
|
+
exposes: [
|
|
1460
|
+
e.battery(),
|
|
1461
|
+
e.action(['on', 'off',
|
|
1462
|
+
'brightness_move_up', 'brightness_step_up', 'brightness_step_down', 'brightness_move_down', 'brightness_stop',
|
|
1463
|
+
'color_temperature_step_down', 'color_temperature_step_up',
|
|
1464
|
+
'1_single', '1_double', '1_hold', '2_single', '2_double', '2_hold',
|
|
1465
|
+
'3_single', '3_double', '3_hold', '4_single', '4_double', '4_hold',
|
|
1466
|
+
]),
|
|
1467
|
+
exposes.enum('operation_mode', ea.ALL, ['command', 'event']).withDescription(
|
|
1468
|
+
'Operation mode: "command" - for group control, "event" - for clicks'),
|
|
1469
|
+
],
|
|
1421
1470
|
fromZigbee: [fz.battery, fz.command_on, fz.command_off, fz.command_step, fz.command_move, fz.command_stop,
|
|
1422
|
-
fz.command_step_color_temperature, fz.tuya_on_off_action],
|
|
1423
|
-
toZigbee: [],
|
|
1471
|
+
fz.command_step_color_temperature, fz.tuya_on_off_action, fz.tuya_operation_mode],
|
|
1472
|
+
toZigbee: [tz.tuya_operation_mode],
|
|
1473
|
+
onEvent: tuya.onEventSetLocalTime,
|
|
1424
1474
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
1425
1475
|
const endpoint = device.getEndpoint(1);
|
|
1426
1476
|
await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg']);
|
|
1427
1477
|
await reporting.batteryPercentageRemaining(endpoint);
|
|
1478
|
+
await endpoint.read('genOnOff', ['tuyaOperationMode']);
|
|
1428
1479
|
},
|
|
1429
1480
|
},
|
|
1430
1481
|
{
|
package/devices/yale.js
CHANGED
|
@@ -100,6 +100,13 @@ module.exports = [
|
|
|
100
100
|
description: 'Assure lock SL',
|
|
101
101
|
extend: lockExtend(),
|
|
102
102
|
},
|
|
103
|
+
{
|
|
104
|
+
zigbeeModel: ['YRL226 TS'],
|
|
105
|
+
model: 'YRL226 TS',
|
|
106
|
+
vendor: 'Yale',
|
|
107
|
+
description: 'Assure lock SL',
|
|
108
|
+
extend: lockExtend(),
|
|
109
|
+
},
|
|
103
110
|
{
|
|
104
111
|
// Appears to be a slightly rebranded Assure lock SL
|
|
105
112
|
// Just with Lockwood | Assa Abloy branding instead of Yale
|
package/lib/constants.js
CHANGED
|
@@ -91,6 +91,44 @@ const danfossWindowOpen = {
|
|
|
91
91
|
4: 'external_open',
|
|
92
92
|
};
|
|
93
93
|
|
|
94
|
+
const danfossRoomStatusCode = {
|
|
95
|
+
0x0000: 'no_error',
|
|
96
|
+
0x0101: 'missing_rt',
|
|
97
|
+
0x0201: 'rt_touch_error',
|
|
98
|
+
0x0401: 'floor_sensor_short_circuit',
|
|
99
|
+
0x0801: 'floor_sensor_disconnected',
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const danfossOutputStatus = {
|
|
103
|
+
0: 'inactive',
|
|
104
|
+
1: 'active',
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const danfossSystemStatusWater = {
|
|
108
|
+
0: 'hot_water_flow_in_pipes',
|
|
109
|
+
1: 'cool_water_flow_in_pipes',
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const danfossSystemStatusCode = {
|
|
113
|
+
0x0000: 'no_error',
|
|
114
|
+
0x0101: 'missing_expansion_board',
|
|
115
|
+
0x0201: 'missing_radio_module',
|
|
116
|
+
0x0401: 'missing_command_module',
|
|
117
|
+
0x0801: 'missing_master_rail',
|
|
118
|
+
0x1001: 'missing_slave_rail_no_1',
|
|
119
|
+
0x2001: 'missing_slave_rail_no_2',
|
|
120
|
+
0x4001: 'pt1000_input_short_circuit',
|
|
121
|
+
0x8001: 'pt1000_input_open_circuit',
|
|
122
|
+
0x0102: 'error_on_one_or_more_output',
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const danfossMultimasterRole = {
|
|
126
|
+
0: 'invalid_unused',
|
|
127
|
+
1: 'master',
|
|
128
|
+
2: 'slave_1',
|
|
129
|
+
3: 'slave_2',
|
|
130
|
+
};
|
|
131
|
+
|
|
94
132
|
const keypadLockoutMode = {
|
|
95
133
|
0: 'unlock',
|
|
96
134
|
1: 'lock1',
|
|
@@ -196,6 +234,11 @@ module.exports = {
|
|
|
196
234
|
fanMode,
|
|
197
235
|
temperatureDisplayMode,
|
|
198
236
|
danfossWindowOpen,
|
|
237
|
+
danfossRoomStatusCode,
|
|
238
|
+
danfossOutputStatus,
|
|
239
|
+
danfossSystemStatusWater,
|
|
240
|
+
danfossSystemStatusCode,
|
|
241
|
+
danfossMultimasterRole,
|
|
199
242
|
keypadLockoutMode,
|
|
200
243
|
lockSourceName,
|
|
201
244
|
armMode,
|
package/lib/exposes.js
CHANGED
|
@@ -486,6 +486,7 @@ module.exports = {
|
|
|
486
486
|
transition: () => new Numeric(`transition`, access.SET).withValueMin(0).withDescription('Controls the transition time (in seconds) of on/off, brightness, color temperature (if applicable) and color (if applicable) changes. Defaults to `0` (no transition).'),
|
|
487
487
|
legacy: () => new Binary(`legacy`, access.SET, true, false).withDescription(`Set to false to disable the legacy integration (highly recommended), will change structure of the published payload (default true).`),
|
|
488
488
|
measurement_poll_interval: () => new Numeric(`measurement_poll_interval`, access.SET).withValueMin(0).withDescription(`This device does not support reporting electric measurements so it is polled instead. The default poll interval is 60 seconds.`),
|
|
489
|
+
illuminance_below_threshold_check: () => new Binary(`illuminance_below_threshold_check`, access.SET, true, false).withDescription(`Set to false to also send messages when illuminance is above threshold in night mode (default true).`),
|
|
489
490
|
},
|
|
490
491
|
presets: {
|
|
491
492
|
action: (values) => new Enum('action', access.STATE, values).withDescription('Triggered action (e.g. a button click)'),
|
package/lib/tuya.js
CHANGED
|
@@ -423,6 +423,30 @@ const dataPoints = {
|
|
|
423
423
|
tvThursdaySchedule: 113,
|
|
424
424
|
tvSaturdaySchedule: 114,
|
|
425
425
|
tvBoostMode: 115,
|
|
426
|
+
// Haozee TS0601 TRV
|
|
427
|
+
haozeeSystemMode: 1,
|
|
428
|
+
haozeeHeatingSetpoint: 2,
|
|
429
|
+
haozeeLocalTemp: 3,
|
|
430
|
+
haozeeBoostHeating: 4,
|
|
431
|
+
haozeeBoostHeatingCountdown: 5,
|
|
432
|
+
haozeeRunningState: 6,
|
|
433
|
+
haozeeWindowState: 7,
|
|
434
|
+
haozeeWindowDetection: 8,
|
|
435
|
+
haozeeChildLock: 12,
|
|
436
|
+
haozeeBattery: 13,
|
|
437
|
+
haozeeFaultAlarm: 14,
|
|
438
|
+
haozeeMinTemp: 15,
|
|
439
|
+
haozeeMaxTemp: 16,
|
|
440
|
+
haozeeScheduleMonday: 17,
|
|
441
|
+
haozeeScheduleTuesday: 18,
|
|
442
|
+
haozeeScheduleWednesday: 19,
|
|
443
|
+
haozeeScheduleThursday: 20,
|
|
444
|
+
haozeeScheduleFriday: 21,
|
|
445
|
+
haozeeScheduleSaturday: 22,
|
|
446
|
+
haozeeScheduleSunday: 23,
|
|
447
|
+
haozeeTempCalibration: 101,
|
|
448
|
+
haozeeValvePosition: 102,
|
|
449
|
+
haozeeSoftVersion: 150,
|
|
426
450
|
// HOCH / WDYK DIN Rail
|
|
427
451
|
hochCountdownTimer: 9,
|
|
428
452
|
hochFaultCode: 26,
|
package/npm-shrinkwrap.json
CHANGED