zigbee-herdsman-converters 14.0.292 → 14.0.296
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 +118 -6
- package/converters/toZigbee.js +87 -4
- package/devices/adeo.js +9 -0
- package/devices/danfoss.js +129 -0
- package/devices/ikea.js +4 -4
- package/devices/lupus.js +1 -1
- package/devices/philips.js +18 -0
- package/devices/sercomm.js +1 -1
- package/devices/shinasystem.js +118 -8
- package/devices/the_light_group.js +15 -0
- package/devices/tuya.js +23 -14
- package/devices/yale.js +7 -0
- package/lib/constants.js +43 -0
- package/lib/exposes.js +1 -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
|
},
|
|
@@ -3007,6 +3027,62 @@ const converters = {
|
|
|
3007
3027
|
if (msg.data.hasOwnProperty('danfossLoadEstimate')) {
|
|
3008
3028
|
result[postfixWithEndpointName('load_estimate', msg, model)] = msg.data['danfossLoadEstimate'];
|
|
3009
3029
|
}
|
|
3030
|
+
// Danfoss Icon Converters
|
|
3031
|
+
if (msg.data.hasOwnProperty('danfossRoomStatusCode')) {
|
|
3032
|
+
result[postfixWithEndpointName('room_status_code', msg, model)] =
|
|
3033
|
+
constants.danfossRoomStatusCode.hasOwnProperty(msg.data['danfossRoomStatusCode']) ?
|
|
3034
|
+
constants.danfossRoomStatusCode[msg.data['danfossRoomStatusCode']] :
|
|
3035
|
+
msg.data['danfossRoomStatusCode'];
|
|
3036
|
+
}
|
|
3037
|
+
if (msg.data.hasOwnProperty('danfossOutputStatus')) {
|
|
3038
|
+
result[postfixWithEndpointName('output_status', msg, model)] =
|
|
3039
|
+
constants.danfossOutputStatus.hasOwnProperty(msg.data['danfossOutputStatus']) ?
|
|
3040
|
+
constants.danfossOutputStatus[msg.data['danfossOutputStatus']] :
|
|
3041
|
+
msg.data['danfossOutputStatus'];
|
|
3042
|
+
}
|
|
3043
|
+
return result;
|
|
3044
|
+
},
|
|
3045
|
+
},
|
|
3046
|
+
danfoss_icon_battery: {
|
|
3047
|
+
cluster: 'genPowerCfg',
|
|
3048
|
+
type: ['attributeReport', 'readResponse'],
|
|
3049
|
+
convert: (model, msg, publish, options, meta) => {
|
|
3050
|
+
const result = {};
|
|
3051
|
+
if (msg.data.hasOwnProperty('batteryPercentageRemaining')) {
|
|
3052
|
+
// Some devices do not comply to the ZCL and report a
|
|
3053
|
+
// batteryPercentageRemaining of 100 when the battery is full (should be 200).
|
|
3054
|
+
const dontDividePercentage = model.meta && model.meta.battery && model.meta.battery.dontDividePercentage;
|
|
3055
|
+
let percentage = msg.data['batteryPercentageRemaining'];
|
|
3056
|
+
percentage = dontDividePercentage ? percentage : percentage / 2;
|
|
3057
|
+
|
|
3058
|
+
result[postfixWithEndpointName('battery', msg, model)] = precisionRound(percentage, 2);
|
|
3059
|
+
}
|
|
3060
|
+
return result;
|
|
3061
|
+
},
|
|
3062
|
+
},
|
|
3063
|
+
danfoss_icon_regulator: {
|
|
3064
|
+
cluster: 'haDiagnostic',
|
|
3065
|
+
type: ['attributeReport', 'readResponse'],
|
|
3066
|
+
convert: (model, msg, publish, options, meta) => {
|
|
3067
|
+
const result = {};
|
|
3068
|
+
if (msg.data.hasOwnProperty('danfossSystemStatusCode')) {
|
|
3069
|
+
result[postfixWithEndpointName('system_status_code', msg, model)] =
|
|
3070
|
+
constants.danfossSystemStatusCode.hasOwnProperty(msg.data['danfossSystemStatusCode']) ?
|
|
3071
|
+
constants.danfossSystemStatusCode[msg.data['danfossSystemStatusCode']] :
|
|
3072
|
+
msg.data['danfossSystemStatusCode'];
|
|
3073
|
+
}
|
|
3074
|
+
if (msg.data.hasOwnProperty('danfossSystemStatusWater')) {
|
|
3075
|
+
result[postfixWithEndpointName('system_status_water', msg, model)] =
|
|
3076
|
+
constants.danfossSystemStatusWater.hasOwnProperty(msg.data['danfossSystemStatusWater']) ?
|
|
3077
|
+
constants.danfossSystemStatusWater[msg.data['danfossSystemStatusWater']] :
|
|
3078
|
+
msg.data['danfossSystemStatusWater'];
|
|
3079
|
+
}
|
|
3080
|
+
if (msg.data.hasOwnProperty('danfossMultimasterRole')) {
|
|
3081
|
+
result[postfixWithEndpointName('multimaster_role', msg, model)] =
|
|
3082
|
+
constants.danfossMultimasterRole.hasOwnProperty(msg.data['danfossMultimasterRole']) ?
|
|
3083
|
+
constants.danfossMultimasterRole[msg.data['danfossMultimasterRole']] :
|
|
3084
|
+
msg.data['danfossMultimasterRole'];
|
|
3085
|
+
}
|
|
3010
3086
|
return result;
|
|
3011
3087
|
},
|
|
3012
3088
|
},
|
|
@@ -5366,22 +5442,30 @@ const converters = {
|
|
|
5366
5442
|
tradfri_occupancy: {
|
|
5367
5443
|
cluster: 'genOnOff',
|
|
5368
5444
|
type: 'commandOnWithTimedOff',
|
|
5369
|
-
options: [exposes.options.occupancy_timeout()],
|
|
5445
|
+
options: [exposes.options.occupancy_timeout(), exposes.options.illuminance_below_threshold_check()],
|
|
5370
5446
|
convert: (model, msg, publish, options, meta) => {
|
|
5371
|
-
|
|
5447
|
+
const onlyWhenOnFlag = (msg.data.ctrlbits & 1) != 0;
|
|
5448
|
+
if (onlyWhenOnFlag &&
|
|
5449
|
+
(!options || !options.hasOwnProperty('illuminance_below_threshold_check') ||
|
|
5450
|
+
options.illuminance_below_threshold_check) &&
|
|
5451
|
+
!globalStore.hasValue(msg.endpoint, 'timer')) return;
|
|
5372
5452
|
|
|
5373
5453
|
const timeout = options && options.hasOwnProperty('occupancy_timeout') ?
|
|
5374
5454
|
options.occupancy_timeout : msg.data.ontime / 10;
|
|
5375
5455
|
|
|
5376
5456
|
// Stop existing timer because motion is detected and set a new one.
|
|
5377
5457
|
clearTimeout(globalStore.getValue(msg.endpoint, 'timer'));
|
|
5458
|
+
globalStore.clearValue(msg.endpoint, 'timer');
|
|
5378
5459
|
|
|
5379
5460
|
if (timeout !== 0) {
|
|
5380
|
-
const timer = setTimeout(() =>
|
|
5461
|
+
const timer = setTimeout(() => {
|
|
5462
|
+
publish({occupancy: false});
|
|
5463
|
+
globalStore.clearValue(msg.endpoint, 'timer');
|
|
5464
|
+
}, timeout * 1000);
|
|
5381
5465
|
globalStore.putValue(msg.endpoint, 'timer', timer);
|
|
5382
5466
|
}
|
|
5383
5467
|
|
|
5384
|
-
return {occupancy: true};
|
|
5468
|
+
return {occupancy: true, illuminance_above_threshold: onlyWhenOnFlag};
|
|
5385
5469
|
},
|
|
5386
5470
|
},
|
|
5387
5471
|
almond_click: {
|
|
@@ -6865,10 +6949,10 @@ const converters = {
|
|
|
6865
6949
|
}
|
|
6866
6950
|
break;
|
|
6867
6951
|
case tuya.dataPoints.tvWindowDetection:
|
|
6868
|
-
result = {window_detection: {1:
|
|
6952
|
+
result = {window_detection: {1: true, 0: false}[value]};
|
|
6869
6953
|
break;
|
|
6870
6954
|
case tuya.dataPoints.tvFrostDetection:
|
|
6871
|
-
result = {frost_detection: {1:
|
|
6955
|
+
result = {frost_detection: {1: true, 0: false}[value]};
|
|
6872
6956
|
break;
|
|
6873
6957
|
case tuya.dataPoints.tvHeatingSetpoint:
|
|
6874
6958
|
result = {current_heating_setpoint: (value / 10).toFixed(1)};
|
|
@@ -6931,6 +7015,23 @@ const converters = {
|
|
|
6931
7015
|
return {people: msg.data.presentValue};
|
|
6932
7016
|
},
|
|
6933
7017
|
},
|
|
7018
|
+
sihas_action: {
|
|
7019
|
+
cluster: 'genOnOff',
|
|
7020
|
+
type: ['commandOn', 'commandOff', 'commandToggle'],
|
|
7021
|
+
convert: (model, msg, publish, options, meta) => {
|
|
7022
|
+
const lookup = {'commandToggle': 'long', 'commandOn': 'double', 'commandOff': 'single'};
|
|
7023
|
+
let buttonMapping = null;
|
|
7024
|
+
if (model.model === 'SBM300ZB2') {
|
|
7025
|
+
buttonMapping = {1: '1', 2: '2'};
|
|
7026
|
+
} else if (model.model === 'SBM300ZB3') {
|
|
7027
|
+
buttonMapping = {1: '1', 2: '2', 3: '3'};
|
|
7028
|
+
} else if (model.model === 'MSM-300ZB') {
|
|
7029
|
+
buttonMapping = {1: '1', 2: '2', 3: '3', 4: '4'};
|
|
7030
|
+
}
|
|
7031
|
+
const button = buttonMapping ? `${buttonMapping[msg.endpoint.ID]}_` : '';
|
|
7032
|
+
return {action: `${button}${lookup[msg.type]}`};
|
|
7033
|
+
},
|
|
7034
|
+
},
|
|
6934
7035
|
hoch_din: {
|
|
6935
7036
|
cluster: 'manuSpecificTuya',
|
|
6936
7037
|
type: ['commandGetData', 'commandSetDataResponse'],
|
|
@@ -7035,6 +7136,17 @@ const converters = {
|
|
|
7035
7136
|
return result;
|
|
7036
7137
|
},
|
|
7037
7138
|
},
|
|
7139
|
+
tuya_operation_mode: {
|
|
7140
|
+
cluster: 'genOnOff',
|
|
7141
|
+
type: ['attributeReport', 'readResponse'],
|
|
7142
|
+
convert: (model, msg, publish, options, meta) => {
|
|
7143
|
+
if (msg.data.hasOwnProperty('tuyaOperationMode')) {
|
|
7144
|
+
const value = msg.data['tuyaOperationMode'];
|
|
7145
|
+
const lookup = {0: 'command', 1: 'event'};
|
|
7146
|
+
return {operation_mode: lookup[value]};
|
|
7147
|
+
}
|
|
7148
|
+
},
|
|
7149
|
+
},
|
|
7038
7150
|
// #endregion
|
|
7039
7151
|
|
|
7040
7152
|
// #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) => {
|
|
@@ -2484,6 +2516,36 @@ const converters = {
|
|
|
2484
2516
|
await entity.read('hvacThermostat', ['danfossLoadEstimate'], manufacturerOptions.danfoss);
|
|
2485
2517
|
},
|
|
2486
2518
|
},
|
|
2519
|
+
danfoss_output_status: {
|
|
2520
|
+
key: ['output_status'],
|
|
2521
|
+
convertGet: async (entity, key, meta) => {
|
|
2522
|
+
await entity.read('hvacThermostat', ['danfossOutputStatus'], manufacturerOptions.danfoss);
|
|
2523
|
+
},
|
|
2524
|
+
},
|
|
2525
|
+
danfoss_room_status_code: {
|
|
2526
|
+
key: ['room_status_code'],
|
|
2527
|
+
convertGet: async (entity, key, meta) => {
|
|
2528
|
+
await entity.read('hvacThermostat', ['danfossRoomStatusCode'], manufacturerOptions.danfoss);
|
|
2529
|
+
},
|
|
2530
|
+
},
|
|
2531
|
+
danfoss_system_status_code: {
|
|
2532
|
+
key: ['system_status_code'],
|
|
2533
|
+
convertGet: async (entity, key, meta) => {
|
|
2534
|
+
await entity.read('haDiagnostic', ['danfossSystemStatusCode'], manufacturerOptions.danfoss);
|
|
2535
|
+
},
|
|
2536
|
+
},
|
|
2537
|
+
danfoss_system_status_water: {
|
|
2538
|
+
key: ['system_status_water'],
|
|
2539
|
+
convertGet: async (entity, key, meta) => {
|
|
2540
|
+
await entity.read('haDiagnostic', ['danfossSystemStatusWater'], manufacturerOptions.danfoss);
|
|
2541
|
+
},
|
|
2542
|
+
},
|
|
2543
|
+
danfoss_multimaster_role: {
|
|
2544
|
+
key: ['multimaster_role'],
|
|
2545
|
+
convertGet: async (entity, key, meta) => {
|
|
2546
|
+
await entity.read('haDiagnostic', ['danfossMultimasterRole'], manufacturerOptions.danfoss);
|
|
2547
|
+
},
|
|
2548
|
+
},
|
|
2487
2549
|
ZMCSW032D_cover_position: {
|
|
2488
2550
|
key: ['position', 'tilt'],
|
|
2489
2551
|
convertSet: async (entity, key, value, meta) => {
|
|
@@ -5868,7 +5930,7 @@ const converters = {
|
|
|
5868
5930
|
key: [
|
|
5869
5931
|
'system_mode', 'window_detection', 'frost_detection', 'child_lock',
|
|
5870
5932
|
'current_heating_setpoint', 'local_temperature_calibration',
|
|
5871
|
-
'holiday_temperature', 'comfort_temperature', 'eco_temperature',
|
|
5933
|
+
'holiday_temperature', 'comfort_temperature', 'eco_temperature',
|
|
5872
5934
|
'open_window_temperature', 'heating_stop', 'preset',
|
|
5873
5935
|
],
|
|
5874
5936
|
convertSet: async (entity, key, value, meta) => {
|
|
@@ -5882,13 +5944,18 @@ const converters = {
|
|
|
5882
5944
|
}
|
|
5883
5945
|
break;
|
|
5884
5946
|
case 'window_detection':
|
|
5885
|
-
await tuya.
|
|
5947
|
+
await tuya.sendDataPointBool(entity, tuya.dataPoints.tvWindowDetection, value);
|
|
5886
5948
|
break;
|
|
5887
5949
|
case 'frost_detection':
|
|
5888
|
-
|
|
5950
|
+
if (value == false) {
|
|
5951
|
+
await tuya.sendDataPointBool(entity, tuya.dataPoints.tvFrostDetection, 0);
|
|
5952
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.tvMode, 1);
|
|
5953
|
+
} else {
|
|
5954
|
+
await tuya.sendDataPointBool(entity, tuya.dataPoints.tvFrostDetection, 1);
|
|
5955
|
+
}
|
|
5889
5956
|
break;
|
|
5890
5957
|
case 'child_lock':
|
|
5891
|
-
await tuya.
|
|
5958
|
+
await tuya.sendDataPointBool(entity, tuya.dataPoints.tvChildLock, value === 'LOCK');
|
|
5892
5959
|
break;
|
|
5893
5960
|
case 'local_temperature_calibration':
|
|
5894
5961
|
value = Math.round(value * 10);
|
|
@@ -5949,6 +6016,22 @@ const converters = {
|
|
|
5949
6016
|
await endpoint.read('genAnalogInput', ['presentValue']);
|
|
5950
6017
|
},
|
|
5951
6018
|
},
|
|
6019
|
+
tuya_operation_mode: {
|
|
6020
|
+
key: ['operation_mode'],
|
|
6021
|
+
convertSet: async (entity, key, value, meta) => {
|
|
6022
|
+
// modes:
|
|
6023
|
+
// 0 - 'command' mode. keys send commands. useful for group control
|
|
6024
|
+
// 1 - 'event' mode. keys send events. useful for handling
|
|
6025
|
+
const lookup = {command: 0, event: 1};
|
|
6026
|
+
const endpoint = meta.device.getEndpoint(1);
|
|
6027
|
+
await endpoint.write('genOnOff', {'tuyaOperationMode': lookup[value.toLowerCase()]});
|
|
6028
|
+
return {state: {operation_mode: value.toLowerCase()}};
|
|
6029
|
+
},
|
|
6030
|
+
convertGet: async (entity, key, meta) => {
|
|
6031
|
+
const endpoint = meta.device.getEndpoint(1);
|
|
6032
|
+
await endpoint.read('genOnOff', ['tuyaOperationMode']);
|
|
6033
|
+
},
|
|
6034
|
+
},
|
|
5952
6035
|
// #endregion
|
|
5953
6036
|
|
|
5954
6037
|
// #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
|
@@ -122,4 +122,133 @@ module.exports = [
|
|
|
122
122
|
endpoint.write('genTime', values);
|
|
123
123
|
},
|
|
124
124
|
},
|
|
125
|
+
{
|
|
126
|
+
fingerprint: [
|
|
127
|
+
{modelID: '0x8020', manufacturerName: 'Danfoss'}, // RT24V Display
|
|
128
|
+
{modelID: '0x8021', manufacturerName: 'Danfoss'}, // RT24V Display Floor sensor
|
|
129
|
+
{modelID: '0x8030', manufacturerName: 'Danfoss'}, // RTbattery Display
|
|
130
|
+
{modelID: '0x8031', manufacturerName: 'Danfoss'}, // RTbattery Display Infrared
|
|
131
|
+
{modelID: '0x8034', manufacturerName: 'Danfoss'}, // RTbattery Dial
|
|
132
|
+
{modelID: '0x8035', manufacturerName: 'Danfoss'}], // RTbattery Dial Infrared
|
|
133
|
+
model: 'Icon',
|
|
134
|
+
vendor: 'Danfoss',
|
|
135
|
+
description: 'Icon floor heating (regulator, Zigbee module & thermostats)',
|
|
136
|
+
fromZigbee: [
|
|
137
|
+
fz.danfoss_icon_regulator,
|
|
138
|
+
fz.danfoss_thermostat,
|
|
139
|
+
fz.danfoss_icon_battery,
|
|
140
|
+
fz.thermostat],
|
|
141
|
+
toZigbee: [
|
|
142
|
+
tz.thermostat_local_temperature,
|
|
143
|
+
tz.thermostat_occupied_heating_setpoint,
|
|
144
|
+
tz.thermostat_system_mode,
|
|
145
|
+
tz.thermostat_min_heat_setpoint_limit,
|
|
146
|
+
tz.thermostat_max_heat_setpoint_limit,
|
|
147
|
+
tz.danfoss_output_status,
|
|
148
|
+
tz.danfoss_room_status_code,
|
|
149
|
+
tz.danfoss_system_status_water,
|
|
150
|
+
tz.danfoss_system_status_code,
|
|
151
|
+
tz.danfoss_multimaster_role,
|
|
152
|
+
],
|
|
153
|
+
meta: {multiEndpoint: true},
|
|
154
|
+
// ota: ota.zigbeeOTA,
|
|
155
|
+
endpoint: (device) => {
|
|
156
|
+
return {
|
|
157
|
+
'l1': 1, 'l2': 2, 'l3': 3, 'l4': 4, 'l5': 5,
|
|
158
|
+
'l6': 6, 'l7': 7, 'l8': 8, 'l9': 9, 'l10': 10,
|
|
159
|
+
'l11': 11, 'l12': 12, 'l13': 13, 'l14': 14, 'l15': 15, 'l16': 232,
|
|
160
|
+
};
|
|
161
|
+
},
|
|
162
|
+
exposes: [].concat(((endpointsCount) => {
|
|
163
|
+
const features = [];
|
|
164
|
+
for (let i = 1; i <= endpointsCount; i++) {
|
|
165
|
+
const epName = `l${i}`;
|
|
166
|
+
if (i!=16) {
|
|
167
|
+
features.push(e.battery().withEndpoint(epName));
|
|
168
|
+
features.push(exposes.climate().withSetpoint('occupied_heating_setpoint', 4, 30, 0.5)
|
|
169
|
+
.withLocalTemperature().withSystemMode(['heat']).withEndpoint(epName));
|
|
170
|
+
features.push(exposes.numeric('abs_min_heat_setpoint_limit', ea.STATE)
|
|
171
|
+
.withUnit('°C').withEndpoint(epName)
|
|
172
|
+
.withDescription('Absolute min temperature allowed on the device'));
|
|
173
|
+
features.push(exposes.numeric('abs_max_heat_setpoint_limit', ea.STATE)
|
|
174
|
+
.withUnit('°C').withEndpoint(epName)
|
|
175
|
+
.withDescription('Absolute max temperature allowed on the device'));
|
|
176
|
+
features.push(exposes.numeric('min_heat_setpoint_limit', ea.ALL)
|
|
177
|
+
.withValueMin(4).withValueMax(30).withValueStep(0.5).withUnit('°C')
|
|
178
|
+
.withEndpoint(epName).withDescription('Min temperature limit set on the device'));
|
|
179
|
+
features.push(exposes.numeric('max_heat_setpoint_limit', ea.ALL)
|
|
180
|
+
.withValueMin(4).withValueMax(30).withValueStep(0.5).withUnit('°C')
|
|
181
|
+
.withEndpoint(epName).withDescription('Max temperature limit set on the device'));
|
|
182
|
+
features.push(exposes.enum('setpoint_change_source', ea.STATE, ['manual', 'schedule', 'externally'])
|
|
183
|
+
.withEndpoint(epName));
|
|
184
|
+
features.push(exposes.enum('output_status', ea.STATE_GET, ['inactive', 'active'])
|
|
185
|
+
.withEndpoint(epName).withDescription('Danfoss Output Status [Active vs Inactive])'));
|
|
186
|
+
features.push(exposes.enum('room_status_code', ea.STATE_GET, ['no_error', 'missing_rt',
|
|
187
|
+
'rt_touch_error', 'floor_sensor_short_circuit', 'floor_sensor_disconnected'])
|
|
188
|
+
.withEndpoint(epName).withDescription('Thermostat status'));
|
|
189
|
+
} else {
|
|
190
|
+
features.push(exposes.enum('system_status_code', ea.STATE_GET, ['no_error', 'missing_expansion_board',
|
|
191
|
+
'missing_radio_module', 'missing_command_module', 'missing_master_rail', 'missing_slave_rail_no_1',
|
|
192
|
+
'missing_slave_rail_no_2', 'pt1000_input_short_circuit', 'pt1000_input_open_circuit',
|
|
193
|
+
'error_on_one_or_more_output']).withEndpoint('l16').withDescription('Regulator Status'));
|
|
194
|
+
features.push(exposes.enum('system_status_water', ea.STATE_GET, ['hot_water_flow_in_pipes', 'cool_water_flow_in_pipes'])
|
|
195
|
+
.withEndpoint('l16').withDescription('Water Status of Regulator'));
|
|
196
|
+
features.push(exposes.enum('multimaster_role', ea.STATE_GET, ['invalid_unused', 'master', 'slave_1', 'slave_2'])
|
|
197
|
+
.withEndpoint('l16').withDescription('Regulator role (Master vs Slave)'));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return features;
|
|
202
|
+
})(16)),
|
|
203
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
204
|
+
const options = {manufacturerCode: 0x1246};
|
|
205
|
+
|
|
206
|
+
for (let i = 1; i <= 15; i++) {
|
|
207
|
+
const endpoint = device.getEndpoint(i);
|
|
208
|
+
if (typeof endpoint !== 'undefined') {
|
|
209
|
+
await reporting.bind(endpoint, coordinatorEndpoint,
|
|
210
|
+
['genPowerCfg', 'hvacThermostat', 'hvacUserInterfaceCfg']);
|
|
211
|
+
await reporting.batteryPercentageRemaining(endpoint,
|
|
212
|
+
{min: constants.repInterval.HOUR, max: 43200, change: 1});
|
|
213
|
+
await reporting.thermostatTemperature(endpoint,
|
|
214
|
+
{min: 0, max: constants.repInterval.MINUTES_10, change: 10});
|
|
215
|
+
await reporting.thermostatOccupiedHeatingSetpoint(endpoint,
|
|
216
|
+
{min: 0, max: constants.repInterval.MINUTES_10, change: 10});
|
|
217
|
+
|
|
218
|
+
await endpoint.configureReporting('hvacThermostat', [{
|
|
219
|
+
attribute: 'danfossOutputStatus',
|
|
220
|
+
minimumReportInterval: constants.repInterval.MINUTE,
|
|
221
|
+
maximumReportInterval: constants.repInterval.MINUTES_10,
|
|
222
|
+
reportableChange: 1,
|
|
223
|
+
}], options);
|
|
224
|
+
|
|
225
|
+
// Danfoss Icon Thermostat Specific
|
|
226
|
+
await endpoint.read('hvacThermostat', [
|
|
227
|
+
'danfossOutputStatus',
|
|
228
|
+
'danfossRoomStatusCode'], options);
|
|
229
|
+
|
|
230
|
+
// Standard Thermostat
|
|
231
|
+
await endpoint.read('hvacThermostat', ['localTemp']);
|
|
232
|
+
await endpoint.read('hvacThermostat', ['occupiedHeatingSetpoint']);
|
|
233
|
+
await endpoint.read('hvacThermostat', ['systemMode']);
|
|
234
|
+
await endpoint.read('hvacThermostat', ['setpointChangeSource']);
|
|
235
|
+
await endpoint.read('hvacThermostat', ['absMinHeatSetpointLimit']);
|
|
236
|
+
await endpoint.read('hvacThermostat', ['absMaxHeatSetpointLimit']);
|
|
237
|
+
await endpoint.read('hvacThermostat', ['minHeatSetpointLimit']);
|
|
238
|
+
await endpoint.read('hvacThermostat', ['maxHeatSetpointLimit']);
|
|
239
|
+
await endpoint.read('genPowerCfg', ['batteryPercentageRemaining']);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Danfoss Icon Regulator Specific
|
|
244
|
+
const endpoint232 = device.getEndpoint(232);
|
|
245
|
+
|
|
246
|
+
await reporting.bind(endpoint232, coordinatorEndpoint, ['haDiagnostic']);
|
|
247
|
+
|
|
248
|
+
await endpoint232.read('haDiagnostic', [
|
|
249
|
+
'danfossSystemStatusCode',
|
|
250
|
+
'danfossSystemStatusWater',
|
|
251
|
+
'danfossMultimasterRole'], options);
|
|
252
|
+
},
|
|
253
|
+
},
|
|
125
254
|
];
|
package/devices/ikea.js
CHANGED
|
@@ -194,10 +194,8 @@ module.exports = [
|
|
|
194
194
|
model: 'LED1624G9',
|
|
195
195
|
vendor: 'IKEA',
|
|
196
196
|
description: 'TRADFRI LED bulb E14/E26/E27 600 lumen, dimmable, color, opal white',
|
|
197
|
-
extend:
|
|
198
|
-
ota: ota.tradfri,
|
|
197
|
+
extend: tradfriExtend.light_onoff_brightness_colortemp_color(),
|
|
199
198
|
meta: {supportsHueAndSaturation: false},
|
|
200
|
-
onEvent: bulbOnEvent,
|
|
201
199
|
},
|
|
202
200
|
{
|
|
203
201
|
zigbeeModel: ['TRADFRI bulb E26 CWS 800lm', 'TRADFRI bulb E27 CWS 806lm'],
|
|
@@ -488,7 +486,9 @@ module.exports = [
|
|
|
488
486
|
toZigbee: [],
|
|
489
487
|
exposes: [e.battery(), e.occupancy(),
|
|
490
488
|
exposes.numeric('requested_brightness_level', ea.STATE).withValueMin(76).withValueMax(254),
|
|
491
|
-
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)')],
|
|
492
492
|
ota: ota.tradfri,
|
|
493
493
|
meta: {battery: {dontDividePercentage: true}},
|
|
494
494
|
configure: async (device, coordinatorEndpoint, logger) => {
|
package/devices/lupus.js
CHANGED
|
@@ -54,7 +54,7 @@ module.exports = [
|
|
|
54
54
|
},
|
|
55
55
|
},
|
|
56
56
|
{
|
|
57
|
-
zigbeeModel: ['PRS3CH2_00.00.05.10TC', 'PRS3CH2_00.00.05.11TC'],
|
|
57
|
+
zigbeeModel: ['PRS3CH2_00.00.05.10TC', 'PRS3CH2_00.00.05.11TC', 'PRS3CH2_00.00.05.12TC'],
|
|
58
58
|
model: '12127',
|
|
59
59
|
vendor: 'Lupus',
|
|
60
60
|
description: '2 chanel relay',
|
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/sercomm.js
CHANGED
|
@@ -70,7 +70,7 @@ module.exports = [
|
|
|
70
70
|
exposes: [e.contact(), e.battery_low(), e.tamper(), e.temperature(), e.battery()],
|
|
71
71
|
},
|
|
72
72
|
{
|
|
73
|
-
zigbeeModel: ['SZ-DWS08N'],
|
|
73
|
+
zigbeeModel: ['SZ-DWS08N', 'SZ-DWS08'],
|
|
74
74
|
model: 'SZ-DWS08',
|
|
75
75
|
vendor: 'Sercomm',
|
|
76
76
|
description: 'Magnetic door & window contact sensor',
|
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,6 +103,7 @@ 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'},
|
|
@@ -423,6 +424,7 @@ module.exports = [
|
|
|
423
424
|
{
|
|
424
425
|
fingerprint: [
|
|
425
426
|
{modelID: 'TS0502B', manufacturerName: '_TZ3210_s1x7gcq0'},
|
|
427
|
+
{modelID: 'TS0502B', manufacturerName: '_TZ3000_muqovqv0'},
|
|
426
428
|
{modelID: 'TS0502B', manufacturerName: '_TZ3210_hi1ym4bl'},
|
|
427
429
|
{modelID: 'TS0502B', manufacturerName: '_TZ3210_psgq7ysz'},
|
|
428
430
|
{modelID: 'TS0502B', manufacturerName: '_TZ3000_zw7wr5uo'},
|
|
@@ -744,13 +746,12 @@ module.exports = [
|
|
|
744
746
|
{
|
|
745
747
|
zigbeeModel: ['kud7u2l'],
|
|
746
748
|
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'}],
|
|
749
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_cwnjrr72'}, {modelID: 'TS0601', manufacturerName: '_TZE200_chyvmhay'}],
|
|
749
750
|
model: 'TS0601_thermostat',
|
|
750
751
|
vendor: 'TuYa',
|
|
751
752
|
description: 'Radiator valve with thermostat',
|
|
752
753
|
whiteLabel: [{vendor: 'Moes', model: 'HY368'}, {vendor: 'Moes', model: 'HY369RT'}, {vendor: 'SHOJZJ', model: '378RT'},
|
|
753
|
-
{vendor: 'Silvercrest', model: 'TVR01'}
|
|
754
|
+
{vendor: 'Silvercrest', model: 'TVR01'}],
|
|
754
755
|
meta: {tuyaThermostatPreset: tuya.thermostatPresets, tuyaThermostatSystemMode: tuya.thermostatSystemModes3},
|
|
755
756
|
ota: ota.zigbeeOTA,
|
|
756
757
|
onEvent: tuya.onEventSetLocalTime,
|
|
@@ -865,7 +866,7 @@ module.exports = [
|
|
|
865
866
|
extend: extend.switch(),
|
|
866
867
|
},
|
|
867
868
|
{
|
|
868
|
-
fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_cphmq0q7'},
|
|
869
|
+
fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_cphmq0q7', applicationVersion: 67},
|
|
869
870
|
{modelID: 'TS011F', manufacturerName: '_TZ3000_ew3ldmgx'},
|
|
870
871
|
{modelID: 'TS011F', manufacturerName: '_TZ3000_ps3dmato'},
|
|
871
872
|
{modelID: 'TS011F', manufacturerName: '_TZ3000_mraovvmm'},
|
|
@@ -906,7 +907,8 @@ module.exports = [
|
|
|
906
907
|
.withDescription('Recover state after power outage')],
|
|
907
908
|
},
|
|
908
909
|
{
|
|
909
|
-
fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_dpo1ysak'}
|
|
910
|
+
fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_dpo1ysak'},
|
|
911
|
+
{modelID: 'TS011F', manufacturerName: '_TZ3000_cphmq0q7', applicationVersion: 69}],
|
|
910
912
|
model: 'TS011F_plug_3',
|
|
911
913
|
description: 'Smart plug (with power monitoring by polling)',
|
|
912
914
|
vendor: 'TuYa',
|
|
@@ -914,6 +916,7 @@ module.exports = [
|
|
|
914
916
|
toZigbee: [tz.on_off, tz.tuya_switch_power_outage_memory],
|
|
915
917
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
916
918
|
const endpoint = device.getEndpoint(1);
|
|
919
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff']);
|
|
917
920
|
endpoint.saveClusterAttributeKeyValue('haElectricalMeasurement', {acCurrentDivisor: 1000, acCurrentMultiplier: 1});
|
|
918
921
|
endpoint.saveClusterAttributeKeyValue('seMetering', {divisor: 100, multiplier: 1});
|
|
919
922
|
device.save();
|
|
@@ -1411,20 +1414,26 @@ module.exports = [
|
|
|
1411
1414
|
model: 'YSR-MINI-Z',
|
|
1412
1415
|
vendor: 'TuYa',
|
|
1413
1416
|
description: '2 in 1 dimming remote control and scene control',
|
|
1414
|
-
exposes: [
|
|
1415
|
-
|
|
1416
|
-
'
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1417
|
+
exposes: [
|
|
1418
|
+
e.battery(),
|
|
1419
|
+
e.action(['on', 'off',
|
|
1420
|
+
'brightness_move_up', 'brightness_step_up', 'brightness_step_down', 'brightness_move_down', 'brightness_stop',
|
|
1421
|
+
'color_temperature_step_down', 'color_temperature_step_up',
|
|
1422
|
+
'1_single', '1_double', '1_hold', '2_single', '2_double', '2_hold',
|
|
1423
|
+
'3_single', '3_double', '3_hold', '4_single', '4_double', '4_hold',
|
|
1424
|
+
]),
|
|
1425
|
+
exposes.enum('operation_mode', ea.ALL, ['command', 'event']).withDescription(
|
|
1426
|
+
'Operation mode: "command" - for group control, "event" - for clicks'),
|
|
1427
|
+
],
|
|
1421
1428
|
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: [],
|
|
1429
|
+
fz.command_step_color_temperature, fz.tuya_on_off_action, fz.tuya_operation_mode],
|
|
1430
|
+
toZigbee: [tz.tuya_operation_mode],
|
|
1431
|
+
onEvent: tuya.onEventSetLocalTime,
|
|
1424
1432
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
1425
1433
|
const endpoint = device.getEndpoint(1);
|
|
1426
1434
|
await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg']);
|
|
1427
1435
|
await reporting.batteryPercentageRemaining(endpoint);
|
|
1436
|
+
await endpoint.read('genOnOff', ['tuyaOperationMode']);
|
|
1428
1437
|
},
|
|
1429
1438
|
},
|
|
1430
1439
|
{
|
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/npm-shrinkwrap.json
CHANGED