zigbee-herdsman-converters 14.0.368 → 14.0.372
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 +175 -16
- package/converters/toZigbee.js +130 -3
- package/devices/aldi.js +0 -8
- package/devices/awox.js +5 -0
- package/devices/bticino.js +11 -2
- package/devices/centralite.js +10 -6
- package/devices/ecodim.js +7 -0
- package/devices/innr.js +8 -0
- package/devices/iris.js +1 -1
- package/devices/konke.js +9 -0
- package/devices/nodon.js +2 -0
- package/devices/nous.js +9 -0
- package/devices/nue_3a.js +12 -1
- package/devices/osram.js +2 -2
- package/devices/owon.js +5 -6
- package/devices/philips.js +21 -3
- package/devices/schneider_electric.js +20 -0
- package/devices/shinasystem.js +1 -0
- package/devices/skydance.js +74 -0
- package/devices/sunricher.js +16 -0
- package/devices/tuya.js +34 -4
- package/devices/xiaomi.js +35 -16
- package/devices/zemismart.js +1 -1
- package/lib/exposes.js +1 -1
- package/lib/ota/zigbeeOTA.js +43 -1
- package/lib/tuya.js +25 -11
- package/npm-shrinkwrap.json +1 -1
- package/package.json +1 -1
package/converters/fromZigbee.js
CHANGED
|
@@ -1164,7 +1164,8 @@ const converters = {
|
|
|
1164
1164
|
|
|
1165
1165
|
if (options.simulated_brightness) {
|
|
1166
1166
|
globalStore.putValue(msg.endpoint, 'simulated_brightness_brightness', msg.data.level);
|
|
1167
|
-
|
|
1167
|
+
const property = postfixWithEndpointName('brightness', msg, model);
|
|
1168
|
+
payload[property] = msg.data.level;
|
|
1168
1169
|
}
|
|
1169
1170
|
|
|
1170
1171
|
return payload;
|
|
@@ -1195,7 +1196,8 @@ const converters = {
|
|
|
1195
1196
|
brightness += delta;
|
|
1196
1197
|
brightness = numberWithinRange(brightness, 0, 255);
|
|
1197
1198
|
globalStore.putValue(msg.endpoint, 'simulated_brightness_brightness', brightness);
|
|
1198
|
-
|
|
1199
|
+
const property = postfixWithEndpointName('brightness', msg, model);
|
|
1200
|
+
publish({[property]: brightness});
|
|
1199
1201
|
}, intervalOpts);
|
|
1200
1202
|
|
|
1201
1203
|
globalStore.putValue(msg.endpoint, 'simulated_brightness_timer', timer);
|
|
@@ -1225,7 +1227,8 @@ const converters = {
|
|
|
1225
1227
|
brightness += delta;
|
|
1226
1228
|
brightness = numberWithinRange(brightness, 0, 255);
|
|
1227
1229
|
globalStore.putValue(msg.endpoint, 'simulated_brightness_brightness', brightness);
|
|
1228
|
-
|
|
1230
|
+
const property = postfixWithEndpointName('brightness', msg, model);
|
|
1231
|
+
payload[property] = brightness;
|
|
1229
1232
|
}
|
|
1230
1233
|
|
|
1231
1234
|
return payload;
|
|
@@ -2574,6 +2577,28 @@ const converters = {
|
|
|
2574
2577
|
}
|
|
2575
2578
|
},
|
|
2576
2579
|
},
|
|
2580
|
+
wls100z_water_leak: {
|
|
2581
|
+
cluster: 'manuSpecificTuya',
|
|
2582
|
+
type: ['commandDataResponse', 'commandDataReport'],
|
|
2583
|
+
convert: (model, msg, publish, options, meta) => {
|
|
2584
|
+
const result = {};
|
|
2585
|
+
for (const dpValue of msg.data.dpValues) {
|
|
2586
|
+
const value = tuya.getDataValue(dpValue);
|
|
2587
|
+
switch (dpValue.dp) {
|
|
2588
|
+
case tuya.dataPoints.wlsWaterLeak:
|
|
2589
|
+
result.water_leak = value < 1;
|
|
2590
|
+
break;
|
|
2591
|
+
case tuya.dataPoints.wlsBatteryPercentage:
|
|
2592
|
+
result.battery = value;
|
|
2593
|
+
break;
|
|
2594
|
+
default:
|
|
2595
|
+
meta.logger.warn(`zigbee-herdsman-converters:wls100z_water_leak:` +
|
|
2596
|
+
`NOT RECOGNIZED DP #${dpValue.dp} with data ${JSON.stringify(dpValue)}`);
|
|
2597
|
+
}
|
|
2598
|
+
}
|
|
2599
|
+
return result;
|
|
2600
|
+
},
|
|
2601
|
+
},
|
|
2577
2602
|
livolo_switch_state: {
|
|
2578
2603
|
cluster: 'genOnOff',
|
|
2579
2604
|
type: ['attributeReport', 'readResponse'],
|
|
@@ -4679,17 +4704,21 @@ const converters = {
|
|
|
4679
4704
|
},
|
|
4680
4705
|
tuya_smoke: {
|
|
4681
4706
|
cluster: 'manuSpecificTuya',
|
|
4682
|
-
type: ['commandDataResponse'],
|
|
4707
|
+
type: ['commandDataResponse', 'commandDataReport'],
|
|
4683
4708
|
convert: (model, msg, publish, options, meta) => {
|
|
4684
|
-
const
|
|
4685
|
-
const
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4709
|
+
const result = {};
|
|
4710
|
+
for (const dpValue of msg.data.dpValues) {
|
|
4711
|
+
const dp = dpValue.dp;
|
|
4712
|
+
const value = tuya.getDataValue(dpValue);
|
|
4713
|
+
switch (dp) {
|
|
4714
|
+
case tuya.dataPoints.state:
|
|
4715
|
+
result.smoke = value === 0;
|
|
4716
|
+
break;
|
|
4717
|
+
default:
|
|
4718
|
+
meta.logger.warn(`zigbee-herdsman-converters:tuya_smoke: Unrecognized DP #${ dp} with data ${JSON.stringify(dpValue)}`);
|
|
4719
|
+
}
|
|
4692
4720
|
}
|
|
4721
|
+
return result;
|
|
4693
4722
|
},
|
|
4694
4723
|
},
|
|
4695
4724
|
tuya_woox_smoke: {
|
|
@@ -4988,7 +5017,8 @@ const converters = {
|
|
|
4988
5017
|
aqara_opple: {
|
|
4989
5018
|
cluster: 'aqaraOpple',
|
|
4990
5019
|
type: ['attributeReport', 'readResponse'],
|
|
4991
|
-
options: [exposes.options.precision('temperature'), exposes.options.calibration('temperature')
|
|
5020
|
+
options: [exposes.options.precision('temperature'), exposes.options.calibration('temperature'),
|
|
5021
|
+
exposes.options.precision('illuminance'), exposes.options.calibration('illuminance', 'percentual')],
|
|
4992
5022
|
convert: (model, msg, publish, options, meta) => {
|
|
4993
5023
|
const payload = {};
|
|
4994
5024
|
if (msg.data.hasOwnProperty('247')) {
|
|
@@ -5113,6 +5143,8 @@ const converters = {
|
|
|
5113
5143
|
if (['QBKG19LM', 'QBKG20LM', 'QBKG39LM', 'QBKG41LM', 'QBCZ15LM'].includes(model.model)) {
|
|
5114
5144
|
const mapping = model.model === 'QBCZ15LM' ? 'usb' : 'right';
|
|
5115
5145
|
payload[`state_${mapping}`] = value === 1 ? 'ON' : 'OFF';
|
|
5146
|
+
} else if (['RTCGQ12LM'].includes(model.model)) {
|
|
5147
|
+
payload.illuminance = calibrateAndPrecisionRoundOptions(value, options, 'illuminance');
|
|
5116
5148
|
}
|
|
5117
5149
|
} else if (index === 149) {
|
|
5118
5150
|
payload.energy = precisionRound(value, 2); // 0x95
|
|
@@ -5128,7 +5160,7 @@ const converters = {
|
|
|
5128
5160
|
if (msg.data.hasOwnProperty('0')) payload.detection_period = msg.data['0'];
|
|
5129
5161
|
if (msg.data.hasOwnProperty('4')) payload.mode_switch = {4: 'anti_flicker_mode', 1: 'quick_mode'}[msg.data['4']];
|
|
5130
5162
|
if (msg.data.hasOwnProperty('10')) payload.switch_type = {1: 'toggle', 2: 'momentary'}[msg.data['10']];
|
|
5131
|
-
if (msg.data.hasOwnProperty('258')) payload.
|
|
5163
|
+
if (msg.data.hasOwnProperty('258')) payload.occupancy_timeout = msg.data['258'];
|
|
5132
5164
|
if (msg.data.hasOwnProperty('268')) payload.motion_sensitivity = {1: 'low', 2: 'medium', 3: 'high'}[msg.data['268']];
|
|
5133
5165
|
if (msg.data.hasOwnProperty('512')) {
|
|
5134
5166
|
if (['ZNCZ15LM', 'QBCZ14LM', 'QBCZ15LM'].includes(model.model)) {
|
|
@@ -5281,6 +5313,65 @@ const converters = {
|
|
|
5281
5313
|
return payload;
|
|
5282
5314
|
},
|
|
5283
5315
|
},
|
|
5316
|
+
RTCGQ12LM_occupancy_illuminance: {
|
|
5317
|
+
cluster: 'aqaraOpple',
|
|
5318
|
+
type: ['attributeReport', 'readResponse'],
|
|
5319
|
+
options: [exposes.options.precision('illuminance'), exposes.options.calibration('illuminance', 'percentual')],
|
|
5320
|
+
convert: (model, msg, publish, options, meta) => {
|
|
5321
|
+
if (msg.data.hasOwnProperty('illuminance')) {
|
|
5322
|
+
// The occupancy sensor only sends a message when motion detected.
|
|
5323
|
+
// Therefore we need to publish the no_motion detected by ourselves.
|
|
5324
|
+
const timeout = meta && meta.state && meta.state.hasOwnProperty('occupancy_timeout') ? meta.state.occupancy_timeout : 60;
|
|
5325
|
+
|
|
5326
|
+
// Stop existing timers because motion is detected and set a new one.
|
|
5327
|
+
globalStore.getValue(msg.endpoint, 'timers', []).forEach((t) => clearTimeout(t));
|
|
5328
|
+
globalStore.putValue(msg.endpoint, 'timers', []);
|
|
5329
|
+
|
|
5330
|
+
if (timeout !== 0) {
|
|
5331
|
+
const timer = setTimeout(() => {
|
|
5332
|
+
publish({occupancy: false});
|
|
5333
|
+
}, timeout * 1000);
|
|
5334
|
+
|
|
5335
|
+
globalStore.getValue(msg.endpoint, 'timers').push(timer);
|
|
5336
|
+
}
|
|
5337
|
+
|
|
5338
|
+
const illuminance = msg.data['illuminance'] - 65536;
|
|
5339
|
+
return {occupancy: true, illuminance: calibrateAndPrecisionRoundOptions(illuminance, options, 'illuminance')};
|
|
5340
|
+
}
|
|
5341
|
+
},
|
|
5342
|
+
},
|
|
5343
|
+
RTCGQ13LM_occupancy: {
|
|
5344
|
+
// This is for occupancy sensor that only send a message when motion detected,
|
|
5345
|
+
// but do not send a motion stop.
|
|
5346
|
+
// Therefore we need to publish the no_motion detected by ourselves.
|
|
5347
|
+
cluster: 'msOccupancySensing',
|
|
5348
|
+
type: ['attributeReport', 'readResponse'],
|
|
5349
|
+
convert: (model, msg, publish, options, meta) => {
|
|
5350
|
+
if (msg.data.occupancy !== 1) {
|
|
5351
|
+
// In case of 0 no occupancy is reported.
|
|
5352
|
+
// https://github.com/Koenkk/zigbee2mqtt/issues/467
|
|
5353
|
+
return;
|
|
5354
|
+
}
|
|
5355
|
+
|
|
5356
|
+
// The occupancy sensor only sends a message when motion detected.
|
|
5357
|
+
// Therefore we need to publish the no_motion detected by ourselves.
|
|
5358
|
+
const timeout = meta && meta.state && meta.state.hasOwnProperty('occupancy_timeout') ? meta.state.occupancy_timeout : 60;
|
|
5359
|
+
|
|
5360
|
+
// Stop existing timers because motion is detected and set a new one.
|
|
5361
|
+
globalStore.getValue(msg.endpoint, 'timers', []).forEach((t) => clearTimeout(t));
|
|
5362
|
+
globalStore.putValue(msg.endpoint, 'timers', []);
|
|
5363
|
+
|
|
5364
|
+
if (timeout !== 0) {
|
|
5365
|
+
const timer = setTimeout(() => {
|
|
5366
|
+
publish({occupancy: false});
|
|
5367
|
+
}, timeout * 1000);
|
|
5368
|
+
|
|
5369
|
+
globalStore.getValue(msg.endpoint, 'timers').push(timer);
|
|
5370
|
+
}
|
|
5371
|
+
|
|
5372
|
+
return {occupancy: true};
|
|
5373
|
+
},
|
|
5374
|
+
},
|
|
5284
5375
|
xiaomi_WXKG01LM_action: {
|
|
5285
5376
|
cluster: 'genOnOff',
|
|
5286
5377
|
type: ['attributeReport', 'readResponse'],
|
|
@@ -5943,7 +6034,13 @@ const converters = {
|
|
|
5943
6034
|
ZMCSW032D_cover_position: {
|
|
5944
6035
|
cluster: 'closuresWindowCovering',
|
|
5945
6036
|
type: ['attributeReport', 'readResponse'],
|
|
5946
|
-
options: [
|
|
6037
|
+
options: [
|
|
6038
|
+
exposes.options.invert_cover(),
|
|
6039
|
+
exposes.numeric('time_close')
|
|
6040
|
+
.withDescription(`Set the full closing time of the roller shutter (e.g. set it to 20) (value is in s).`),
|
|
6041
|
+
exposes.numeric('time_open')
|
|
6042
|
+
.withDescription(`Set the full opening time of the roller shutter (e.g. set it to 21) (value is in s).`),
|
|
6043
|
+
],
|
|
5947
6044
|
convert: (model, msg, publish, options, meta) => {
|
|
5948
6045
|
const result = {};
|
|
5949
6046
|
const timeCoverSetMiddle = 60;
|
|
@@ -7437,6 +7534,25 @@ const converters = {
|
|
|
7437
7534
|
}
|
|
7438
7535
|
},
|
|
7439
7536
|
},
|
|
7537
|
+
tuya_smart_vibration_sensor: {
|
|
7538
|
+
cluster: 'manuSpecificTuya',
|
|
7539
|
+
type: ['commandGetData', 'commandDataResponse', 'raw'],
|
|
7540
|
+
convert: (model, msg, publish, options, meta) => {
|
|
7541
|
+
const dp = msg.data.dp;
|
|
7542
|
+
const value = tuya.getDataValue(msg.data.datatype, msg.data.data);
|
|
7543
|
+
switch (dp) {
|
|
7544
|
+
case tuya.dataPoints.state:
|
|
7545
|
+
return {contact: Boolean(value)};
|
|
7546
|
+
case tuya.dataPoints.thitBatteryPercentage:
|
|
7547
|
+
return {battery: value};
|
|
7548
|
+
case tuya.dataPoints.tuyaVibration:
|
|
7549
|
+
return {vibration: Boolean(value)};
|
|
7550
|
+
default:
|
|
7551
|
+
meta.logger.warn(`zigbee-herdsman-converters:tuya_smart_vibration_sensor: NOT RECOGNIZED ` +
|
|
7552
|
+
`DP #${dp} with data ${JSON.stringify(msg.data)}`);
|
|
7553
|
+
}
|
|
7554
|
+
},
|
|
7555
|
+
},
|
|
7440
7556
|
moes_thermostat_tv: {
|
|
7441
7557
|
cluster: 'manuSpecificTuya',
|
|
7442
7558
|
type: ['commandDataResponse', 'commandDataReport', 'raw'],
|
|
@@ -7527,7 +7643,11 @@ const converters = {
|
|
|
7527
7643
|
cluster: 'genAnalogInput',
|
|
7528
7644
|
type: ['attributeReport', 'readResponse'],
|
|
7529
7645
|
convert: (model, msg, publish, options, meta) => {
|
|
7530
|
-
|
|
7646
|
+
const lookup = {'0': 'idle', '1': 'in', '2': 'out'};
|
|
7647
|
+
const value = precisionRound(parseFloat(msg.data['presentValue']), 1);
|
|
7648
|
+
let result = null;
|
|
7649
|
+
result = {people: precisionRound(msg.data.presentValue, 0), status: lookup[value*10%10]};
|
|
7650
|
+
return result;
|
|
7531
7651
|
},
|
|
7532
7652
|
},
|
|
7533
7653
|
sihas_action: {
|
|
@@ -7712,6 +7832,40 @@ const converters = {
|
|
|
7712
7832
|
};
|
|
7713
7833
|
},
|
|
7714
7834
|
},
|
|
7835
|
+
tuya_light_wz5: {
|
|
7836
|
+
cluster: 'manuSpecificTuya',
|
|
7837
|
+
type: ['commandDataResponse', 'commandDataReport'],
|
|
7838
|
+
convert: (model, msg, publish, options, meta) => {
|
|
7839
|
+
const separateWhite = (model.meta && model.meta.separateWhite);
|
|
7840
|
+
const result = {};
|
|
7841
|
+
// eslint-disable-next-line no-unused-vars
|
|
7842
|
+
for (const [i, dpValue] of msg.data.dpValues.entries()) {
|
|
7843
|
+
const dp = dpValue.dp;
|
|
7844
|
+
const value = tuya.getDataValue(dpValue);
|
|
7845
|
+
if (dp === tuya.dataPoints.state) {
|
|
7846
|
+
result.state = value ? 'ON': 'OFF';
|
|
7847
|
+
} else if (dp === tuya.dataPoints.silvercrestSetBrightness) {
|
|
7848
|
+
const brightness = mapNumberRange(value, 0, 1000, 0, 255);
|
|
7849
|
+
if (separateWhite) {
|
|
7850
|
+
result.white_brightness = brightness;
|
|
7851
|
+
} else {
|
|
7852
|
+
result.brightness = brightness;
|
|
7853
|
+
}
|
|
7854
|
+
} else if (dp === tuya.dataPoints.silvercrestSetColor) {
|
|
7855
|
+
const h = parseInt(value.substring(0, 4), 16);
|
|
7856
|
+
const s = parseInt(value.substring(4, 8), 16);
|
|
7857
|
+
const b = parseInt(value.substring(8, 12), 16);
|
|
7858
|
+
result.color_mode = 'hs';
|
|
7859
|
+
result.color = {hue: h, saturation: mapNumberRange(s, 0, 1000, 0, 100)};
|
|
7860
|
+
result.brightness = mapNumberRange(b, 0, 1000, 0, 255);
|
|
7861
|
+
} else if (dp === tuya.dataPoints.silvercrestSetColorTemp) {
|
|
7862
|
+
const [colorTempMin, colorTempMax] = [250, 454];
|
|
7863
|
+
result.color_temp = mapNumberRange(value, 0, 1000, colorTempMax, colorTempMin);
|
|
7864
|
+
}
|
|
7865
|
+
}
|
|
7866
|
+
return result;
|
|
7867
|
+
},
|
|
7868
|
+
},
|
|
7715
7869
|
// #endregion
|
|
7716
7870
|
|
|
7717
7871
|
// #region Ignore converters (these message dont need parsing).
|
|
@@ -7865,6 +8019,11 @@ const converters = {
|
|
|
7865
8019
|
type: ['commandMcuSyncTime'],
|
|
7866
8020
|
convert: (model, msg, publish, options, meta) => null,
|
|
7867
8021
|
},
|
|
8022
|
+
ignore_tuya_raw: {
|
|
8023
|
+
cluster: 'manuSpecificTuya',
|
|
8024
|
+
type: ['raw'],
|
|
8025
|
+
convert: (model, msg, publish, options, meta) => null,
|
|
8026
|
+
},
|
|
7868
8027
|
// #endregion
|
|
7869
8028
|
};
|
|
7870
8029
|
|
package/converters/toZigbee.js
CHANGED
|
@@ -2076,12 +2076,12 @@ const converters = {
|
|
|
2076
2076
|
await entity.read('aqaraOpple', [0x0000], manufacturerOptions.xiaomi);
|
|
2077
2077
|
},
|
|
2078
2078
|
},
|
|
2079
|
-
|
|
2080
|
-
key: ['
|
|
2079
|
+
aqara_occupancy_timeout: {
|
|
2080
|
+
key: ['occupancy_timeout'],
|
|
2081
2081
|
convertSet: async (entity, key, value, meta) => {
|
|
2082
2082
|
value *= 1;
|
|
2083
2083
|
await entity.write('aqaraOpple', {0x0102: {value: [value], type: 0x20}}, manufacturerOptions.xiaomi);
|
|
2084
|
-
return {state: {
|
|
2084
|
+
return {state: {occupancy_timeout: value}};
|
|
2085
2085
|
},
|
|
2086
2086
|
convertGet: async (entity, key, meta) => {
|
|
2087
2087
|
await entity.read('aqaraOpple', [0x0102], manufacturerOptions.xiaomi);
|
|
@@ -6404,6 +6404,133 @@ const converters = {
|
|
|
6404
6404
|
return {state: {click_mode: value}};
|
|
6405
6405
|
},
|
|
6406
6406
|
},
|
|
6407
|
+
tuya_light_wz5: {
|
|
6408
|
+
key: ['color', 'color_temp', 'brightness', 'white_brightness'],
|
|
6409
|
+
convertSet: async (entity, key, value, meta) => {
|
|
6410
|
+
const separateWhite = (meta.mapped.meta && meta.mapped.meta.separateWhite);
|
|
6411
|
+
if (key == 'white_brightness' || (!separateWhite && (key == 'brightness'))) {
|
|
6412
|
+
// upscale to 1000
|
|
6413
|
+
let newValue;
|
|
6414
|
+
if (value >= 0 && value <= 255) {
|
|
6415
|
+
newValue = utils.mapNumberRange(value, 0, 255, 0, 1000);
|
|
6416
|
+
} else {
|
|
6417
|
+
throw new Error('Dimmer brightness is out of range 0..255');
|
|
6418
|
+
}
|
|
6419
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.silvercrestChangeMode, tuya.silvercrestModes.white);
|
|
6420
|
+
await tuya.sendDataPointValue(entity, tuya.dataPoints.dimmerLevel, newValue);
|
|
6421
|
+
|
|
6422
|
+
return {state: {white_brightness: value}};
|
|
6423
|
+
} else if (key == 'color_temp') {
|
|
6424
|
+
const [colorTempMin, colorTempMax] = [250, 454];
|
|
6425
|
+
const preset = {
|
|
6426
|
+
'warmest': colorTempMax,
|
|
6427
|
+
'warm': 454,
|
|
6428
|
+
'neutral': 370,
|
|
6429
|
+
'cool': 250,
|
|
6430
|
+
'coolest': colorTempMin,
|
|
6431
|
+
};
|
|
6432
|
+
if (typeof value === 'string' && isNaN(value)) {
|
|
6433
|
+
const presetName = value.toLowerCase();
|
|
6434
|
+
if (presetName in preset) {
|
|
6435
|
+
value = preset[presetName];
|
|
6436
|
+
} else {
|
|
6437
|
+
throw new Error(`Unknown preset '${value}'`);
|
|
6438
|
+
}
|
|
6439
|
+
} else {
|
|
6440
|
+
value = light.clampColorTemp(Number(value), colorTempMin, colorTempMax, meta.logger);
|
|
6441
|
+
}
|
|
6442
|
+
const data = utils.mapNumberRange(value, colorTempMax, colorTempMin, 0, 1000);
|
|
6443
|
+
|
|
6444
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.silvercrestChangeMode, tuya.silvercrestModes.white);
|
|
6445
|
+
await tuya.sendDataPointValue(entity, tuya.dataPoints.silvercrestSetColorTemp, data);
|
|
6446
|
+
|
|
6447
|
+
return {state: {color_temp: value}};
|
|
6448
|
+
} else if (key == 'color' || (separateWhite && (key == 'brightness'))) {
|
|
6449
|
+
const newState = {};
|
|
6450
|
+
if (key == 'brightness') {
|
|
6451
|
+
newState.brightness = value;
|
|
6452
|
+
} else if (key == 'color') {
|
|
6453
|
+
newState.color = value;
|
|
6454
|
+
newState.color_mode = 'hs';
|
|
6455
|
+
}
|
|
6456
|
+
|
|
6457
|
+
const make4sizedString = (v) => {
|
|
6458
|
+
if (v.length >= 4) {
|
|
6459
|
+
return v;
|
|
6460
|
+
} else if (v.length === 3) {
|
|
6461
|
+
return '0' + v;
|
|
6462
|
+
} else if (v.length === 2) {
|
|
6463
|
+
return '00' + v;
|
|
6464
|
+
} else if (v.length === 1) {
|
|
6465
|
+
return '000' + v;
|
|
6466
|
+
} else {
|
|
6467
|
+
return '0000';
|
|
6468
|
+
}
|
|
6469
|
+
};
|
|
6470
|
+
|
|
6471
|
+
const fillInHSB = (h, s, b, state) => {
|
|
6472
|
+
// Define default values. Device expects leading zero in string.
|
|
6473
|
+
const hsb = {
|
|
6474
|
+
h: '0168', // 360
|
|
6475
|
+
s: '03e8', // 1000
|
|
6476
|
+
b: '03e8', // 1000
|
|
6477
|
+
};
|
|
6478
|
+
|
|
6479
|
+
if (h) {
|
|
6480
|
+
// The device expects 0-359
|
|
6481
|
+
if (h >= 360) {
|
|
6482
|
+
h = 359;
|
|
6483
|
+
}
|
|
6484
|
+
hsb.h = make4sizedString(h.toString(16));
|
|
6485
|
+
} else if (state.color && state.color.hue) {
|
|
6486
|
+
hsb.h = make4sizedString(state.color.hue.toString(16));
|
|
6487
|
+
}
|
|
6488
|
+
|
|
6489
|
+
// Device expects 0-1000, saturation normally is 0-100 so we expect that from the user
|
|
6490
|
+
// The device expects a round number, otherwise everything breaks
|
|
6491
|
+
if (s) {
|
|
6492
|
+
hsb.s = make4sizedString(utils.mapNumberRange(s, 0, 100, 0, 1000).toString(16));
|
|
6493
|
+
} else if (state.color && state.color.saturation) {
|
|
6494
|
+
hsb.s = make4sizedString(utils.mapNumberRange(state.color.saturation, 0, 100, 0, 1000).toString(16));
|
|
6495
|
+
}
|
|
6496
|
+
|
|
6497
|
+
// Scale 0-255 to 0-1000 what the device expects.
|
|
6498
|
+
if (b) {
|
|
6499
|
+
hsb.b = make4sizedString(utils.mapNumberRange(b, 0, 255, 0, 1000).toString(16));
|
|
6500
|
+
} else if (state.brightness) {
|
|
6501
|
+
hsb.b = make4sizedString(utils.mapNumberRange(state.brightness, 0, 255, 0, 1000).toString(16));
|
|
6502
|
+
}
|
|
6503
|
+
|
|
6504
|
+
return hsb;
|
|
6505
|
+
};
|
|
6506
|
+
|
|
6507
|
+
const hsb = fillInHSB(
|
|
6508
|
+
value.h || value.hue || null,
|
|
6509
|
+
value.s || value.saturation || null,
|
|
6510
|
+
value.b || value.brightness || (key == 'brightness') ? value : null,
|
|
6511
|
+
meta.state,
|
|
6512
|
+
);
|
|
6513
|
+
|
|
6514
|
+
|
|
6515
|
+
let data = [];
|
|
6516
|
+
data = data.concat(tuya.convertStringToHexArray(hsb.h));
|
|
6517
|
+
data = data.concat(tuya.convertStringToHexArray(hsb.s));
|
|
6518
|
+
data = data.concat(tuya.convertStringToHexArray(hsb.b));
|
|
6519
|
+
|
|
6520
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.silvercrestChangeMode, tuya.silvercrestModes.color);
|
|
6521
|
+
await tuya.sendDataPointStringBuffer(entity, tuya.dataPoints.silvercrestSetColor, data);
|
|
6522
|
+
|
|
6523
|
+
if (separateWhite && meta.state.white_brightness != undefined) {
|
|
6524
|
+
// restore white state
|
|
6525
|
+
const newValue = utils.mapNumberRange(meta.state.white_brightness, 0, 255, 0, 1000);
|
|
6526
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.silvercrestChangeMode, tuya.silvercrestModes.white);
|
|
6527
|
+
await tuya.sendDataPointValue(entity, tuya.dataPoints.dimmerLevel, newValue);
|
|
6528
|
+
}
|
|
6529
|
+
|
|
6530
|
+
return {state: newState};
|
|
6531
|
+
}
|
|
6532
|
+
},
|
|
6533
|
+
},
|
|
6407
6534
|
// #endregion
|
|
6408
6535
|
|
|
6409
6536
|
// #region Ignore converters
|
package/devices/aldi.js
CHANGED
|
@@ -12,14 +12,6 @@ module.exports = [
|
|
|
12
12
|
extend: extend.light_onoff_brightness_colortemp_color({disableColorTempStartup: true}),
|
|
13
13
|
meta: {applyRedFix: true},
|
|
14
14
|
},
|
|
15
|
-
{
|
|
16
|
-
fingerprint: [{modelID: 'TS0505B', manufacturerName: '_TZ3000_kohbva1f'}],
|
|
17
|
-
model: 'L122CB63H11A9.0W',
|
|
18
|
-
vendor: 'Aldi',
|
|
19
|
-
description: 'LIGHTWAY smart home LED-lamp - bulb',
|
|
20
|
-
extend: extend.light_onoff_brightness_colortemp_color({disableColorTempStartup: true}),
|
|
21
|
-
meta: {applyRedFix: true},
|
|
22
|
-
},
|
|
23
15
|
{
|
|
24
16
|
fingerprint: [{modelID: 'TS0505B', manufacturerName: '_TZ3000_iivsrikg'}],
|
|
25
17
|
model: 'L122AA63H11A6.5W',
|
package/devices/awox.js
CHANGED
|
@@ -10,6 +10,11 @@ module.exports = [
|
|
|
10
10
|
},
|
|
11
11
|
{
|
|
12
12
|
fingerprint: [
|
|
13
|
+
{type: 'Router', manufacturerName: 'AwoX', modelID: 'TLSR82xx', endpoints: [
|
|
14
|
+
{ID: 1, profileID: 260, deviceID: 269, inputClusters: [0, 3, 4, 5, 6, 8, 768, 4096, 64599, 10], outputClusters: [6]},
|
|
15
|
+
{ID: 3, profileID: 4751, deviceID: 269, inputClusters: [65360, 65361], outputClusters: [65360, 65361]},
|
|
16
|
+
{ID: 242, profileID: 41440, deviceID: 97, inputClusters: [], outputClusters: [33]},
|
|
17
|
+
]},
|
|
13
18
|
{type: 'Router', manufacturerName: 'AwoX', modelID: 'TLSR82xx', endpoints: [
|
|
14
19
|
{ID: 1, profileID: 260, deviceID: 258, inputClusters: [0, 3, 4, 5, 6, 8, 768, 4096], outputClusters: [6, 25]},
|
|
15
20
|
{ID: 3, profileID: 49152, deviceID: 258, inputClusters: [65360, 65361], outputClusters: [65360, 65361]},
|
package/devices/bticino.js
CHANGED
|
@@ -14,7 +14,11 @@ module.exports = [
|
|
|
14
14
|
description: 'Light switch with neutral',
|
|
15
15
|
fromZigbee: [fz.identify, fz.on_off, fz.K4003C_binary_input],
|
|
16
16
|
toZigbee: [tz.on_off, tz.legrand_settingAlwaysEnableLed, tz.legrand_settingEnableLedIfOn, tz.legrand_identify],
|
|
17
|
-
exposes: [
|
|
17
|
+
exposes: [
|
|
18
|
+
e.switch(), e.action(['identify', 'on', 'off']),
|
|
19
|
+
exposes.binary('permanent_led', ea.STATE_SET, 'ON', 'OFF').withDescription('Enable or disable the permanent blue LED'),
|
|
20
|
+
exposes.binary('led_when_on', ea.STATE_SET, 'ON', 'OFF').withDescription('Enables the LED when the light is on'),
|
|
21
|
+
],
|
|
18
22
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
19
23
|
const endpoint = device.getEndpoint(1);
|
|
20
24
|
await reporting.bind(endpoint, coordinatorEndpoint, ['genIdentify', 'genOnOff', 'genBinaryInput']);
|
|
@@ -26,7 +30,12 @@ module.exports = [
|
|
|
26
30
|
vendor: 'BTicino',
|
|
27
31
|
description: 'Dimmer switch with neutral',
|
|
28
32
|
extend: extend.light_onoff_brightness({noConfigure: true}),
|
|
29
|
-
exposes: [
|
|
33
|
+
exposes: [
|
|
34
|
+
e.light_brightness(),
|
|
35
|
+
exposes.binary('dimmer_enabled', ea.STATE_SET, 'ON', 'OFF').withDescription('Allow the device to change brightness'),
|
|
36
|
+
exposes.binary('permanent_led', ea.STATE_SET, 'ON', 'OFF').withDescription('Enable or disable the permanent blue LED'),
|
|
37
|
+
exposes.binary('led_when_on', ea.STATE_SET, 'ON', 'OFF').withDescription('Enables the LED when the light is on'),
|
|
38
|
+
],
|
|
30
39
|
fromZigbee: [fz.brightness, fz.identify, fz.on_off],
|
|
31
40
|
toZigbee: [tz.light_onoff_brightness, tz.legrand_settingAlwaysEnableLed, tz.legrand_settingEnableLedIfOn,
|
|
32
41
|
tz.legrand_settingEnableDimmer, tz.legrand_identify],
|
package/devices/centralite.js
CHANGED
|
@@ -196,12 +196,15 @@ module.exports = [
|
|
|
196
196
|
tz.thermostat_occupied_heating_setpoint, tz.thermostat_occupied_cooling_setpoint,
|
|
197
197
|
tz.thermostat_setpoint_raise_lower, tz.thermostat_remote_sensing,
|
|
198
198
|
tz.thermostat_control_sequence_of_operation, tz.thermostat_system_mode,
|
|
199
|
-
tz.thermostat_relay_status_log, tz.fan_mode, tz.thermostat_running_state],
|
|
200
|
-
exposes: [e.battery(),
|
|
201
|
-
.
|
|
202
|
-
|
|
203
|
-
.withSetpoint('
|
|
204
|
-
|
|
199
|
+
tz.thermostat_relay_status_log, tz.fan_mode, tz.thermostat_running_state, tz.thermostat_temperature_setpoint_hold],
|
|
200
|
+
exposes: [e.battery(),
|
|
201
|
+
exposes.binary('temperature_setpoint_hold', ea.ALL, true, false)
|
|
202
|
+
.withDescription('Prevent changes. `false` = run normally. `true` = prevent from making changes.'),
|
|
203
|
+
exposes.climate().withSetpoint('occupied_heating_setpoint', 10, 30, 1).withLocalTemperature()
|
|
204
|
+
.withSystemMode(['off', 'heat', 'cool', 'emergency_heating'])
|
|
205
|
+
.withRunningState(['idle', 'heat', 'cool', 'fan_only']).withFanMode(['auto', 'on'])
|
|
206
|
+
.withSetpoint('occupied_cooling_setpoint', 10, 30, 1)
|
|
207
|
+
.withLocalTemperatureCalibration(-30, 30, 0.1)],
|
|
205
208
|
meta: {battery: {voltageToPercentage: '3V_1500_2800'}},
|
|
206
209
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
207
210
|
const endpoint = device.getEndpoint(1);
|
|
@@ -210,6 +213,7 @@ module.exports = [
|
|
|
210
213
|
await reporting.thermostatRunningState(endpoint);
|
|
211
214
|
await reporting.thermostatTemperature(endpoint);
|
|
212
215
|
await reporting.fanMode(endpoint);
|
|
216
|
+
await reporting.thermostatTemperatureSetpointHold(endpoint);
|
|
213
217
|
},
|
|
214
218
|
},
|
|
215
219
|
{
|
package/devices/ecodim.js
CHANGED
|
@@ -121,4 +121,11 @@ module.exports = [
|
|
|
121
121
|
toZigbee: [],
|
|
122
122
|
meta: {multiEndpoint: true, battery: {dontDividePercentage: true}},
|
|
123
123
|
},
|
|
124
|
+
{
|
|
125
|
+
fingerprint: [{modelID: 'TS0501B', manufacturerName: '_TZ3210_yluvwhjc'}],
|
|
126
|
+
model: 'ED-10042',
|
|
127
|
+
vendor: 'EcoDim',
|
|
128
|
+
description: 'Zigbee LED filament light dimmable E27, globe G125, flame 2200K',
|
|
129
|
+
extend: extend.light_onoff_brightness(),
|
|
130
|
+
},
|
|
124
131
|
];
|
package/devices/innr.js
CHANGED
|
@@ -79,6 +79,14 @@ module.exports = [
|
|
|
79
79
|
extend: extend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 555], supportsHS: true}),
|
|
80
80
|
meta: {enhancedHue: false, applyRedFix: true, turnsOffAtBrightness1: true},
|
|
81
81
|
},
|
|
82
|
+
{
|
|
83
|
+
zigbeeModel: ['RB 251 C'],
|
|
84
|
+
model: 'RB 251 C',
|
|
85
|
+
vendor: 'Innr',
|
|
86
|
+
description: 'E14 bulb RGBW',
|
|
87
|
+
extend: extend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 555], supportsHS: true}),
|
|
88
|
+
meta: {enhancedHue: false, applyRedFix: true, turnsOffAtBrightness1: true},
|
|
89
|
+
},
|
|
82
90
|
{
|
|
83
91
|
zigbeeModel: ['RB 265'],
|
|
84
92
|
model: 'RB 265',
|
package/devices/iris.js
CHANGED
package/devices/konke.js
CHANGED
|
@@ -73,4 +73,13 @@ module.exports = [
|
|
|
73
73
|
toZigbee: [],
|
|
74
74
|
exposes: [e.water_leak(), e.battery_low(), e.tamper()],
|
|
75
75
|
},
|
|
76
|
+
{
|
|
77
|
+
fingerprint: [{modelID: 'TS0222', manufacturerName: '_TYZB01_fi5yftwv'}],
|
|
78
|
+
model: 'KK-ES-J01W',
|
|
79
|
+
vendor: 'Konke',
|
|
80
|
+
description: 'Room temperature, relative humidity and illuminance sensor',
|
|
81
|
+
fromZigbee: [fz.battery, fz.illuminance, fz.humidity, fz.temperature],
|
|
82
|
+
toZigbee: [],
|
|
83
|
+
exposes: [e.battery(), e.illuminance(), e.illuminance_lux().withUnit('lx'), e.humidity(), e.temperature()],
|
|
84
|
+
},
|
|
76
85
|
];
|
package/devices/nodon.js
CHANGED
|
@@ -16,6 +16,8 @@ module.exports = [
|
|
|
16
16
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
17
17
|
const endpoint = device.getEndpoint(1);
|
|
18
18
|
await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg', 'closuresWindowCovering']);
|
|
19
|
+
await reporting.currentPositionLiftPercentage(endpoint);
|
|
20
|
+
await reporting.currentPositionTiltPercentage(endpoint);
|
|
19
21
|
},
|
|
20
22
|
exposes: [e.cover_position()],
|
|
21
23
|
},
|
package/devices/nous.js
CHANGED
|
@@ -7,6 +7,15 @@ const e = exposes.presets;
|
|
|
7
7
|
const ea = exposes.access;
|
|
8
8
|
|
|
9
9
|
module.exports = [
|
|
10
|
+
{
|
|
11
|
+
fingerprint: [{modelID: 'TS0201', manufacturerName: '_TZ3000_lbtpiody'}],
|
|
12
|
+
model: 'E5',
|
|
13
|
+
vendor: 'Nous',
|
|
14
|
+
description: 'Temperature & humidity',
|
|
15
|
+
fromZigbee: [fz.temperature, fz.humidity, fz.battery],
|
|
16
|
+
toZigbee: [],
|
|
17
|
+
exposes: [e.temperature(), e.humidity(), e.battery()],
|
|
18
|
+
},
|
|
10
19
|
{
|
|
11
20
|
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_nnrfa68v'}],
|
|
12
21
|
model: 'E6',
|
package/devices/nue_3a.js
CHANGED
|
@@ -157,6 +157,12 @@ module.exports = [
|
|
|
157
157
|
},
|
|
158
158
|
},
|
|
159
159
|
{
|
|
160
|
+
fingerprint: [
|
|
161
|
+
{type: 'Router', manufacturerName: '3A Smart Home DE', modelID: 'LXN-2S27LX1.0', endpoints: [
|
|
162
|
+
{ID: 11, profileID: 49246, deviceID: 0, inputClusters: [0, 4, 3, 6, 5, 4096, 8], outputClusters: [25]},
|
|
163
|
+
{ID: 12, profileID: 49246, deviceID: 0, inputClusters: [0, 4, 3, 6, 5, 8], outputClusters: [25]},
|
|
164
|
+
]},
|
|
165
|
+
],
|
|
160
166
|
zigbeeModel: ['FNB56-ZSW02LX2.0'],
|
|
161
167
|
model: 'HGZB-42',
|
|
162
168
|
vendor: 'Nue / 3A',
|
|
@@ -283,7 +289,12 @@ module.exports = [
|
|
|
283
289
|
extend: extend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 370]}),
|
|
284
290
|
},
|
|
285
291
|
{
|
|
286
|
-
|
|
292
|
+
fingerprint: [
|
|
293
|
+
{type: 'Router', manufacturerName: '3A Smart Home DE', modelID: 'LXN-2S27LX1.0', endpoints: [
|
|
294
|
+
{ID: 1, profileID: 49246, deviceID: 0, inputClusters: [0, 4, 3, 6, 5, 4096, 8], outputClusters: [0]},
|
|
295
|
+
{ID: 2, profileID: 49246, deviceID: 0, inputClusters: [0, 4, 3, 6, 5, 4096, 8], outputClusters: [0]},
|
|
296
|
+
]},
|
|
297
|
+
],
|
|
287
298
|
model: 'NUE-AUWZO2',
|
|
288
299
|
vendor: 'Nue / 3A',
|
|
289
300
|
description: 'Smart Zigbee double power point',
|
package/devices/osram.js
CHANGED
|
@@ -178,11 +178,11 @@ module.exports = [
|
|
|
178
178
|
ota: ota.ledvance,
|
|
179
179
|
},
|
|
180
180
|
{
|
|
181
|
-
zigbeeModel: ['Surface Light TW'],
|
|
181
|
+
zigbeeModel: ['Surface Light TW', 'ZLO-CeilingTW-OS'],
|
|
182
182
|
model: 'AB401130055',
|
|
183
183
|
vendor: 'OSRAM',
|
|
184
184
|
description: 'LIGHTIFY Surface Light LED Tunable White',
|
|
185
|
-
extend: extend.ledvance.light_onoff_brightness_colortemp(),
|
|
185
|
+
extend: extend.ledvance.light_onoff_brightness_colortemp({colorTempRange: [153, 370]}),
|
|
186
186
|
ota: ota.ledvance,
|
|
187
187
|
},
|
|
188
188
|
{
|
package/devices/owon.js
CHANGED
|
@@ -106,15 +106,14 @@ module.exports = [
|
|
|
106
106
|
zigbeeModel: ['THS317-ET'],
|
|
107
107
|
model: 'THS317-ET',
|
|
108
108
|
vendor: 'OWON',
|
|
109
|
-
description: 'Temperature
|
|
110
|
-
fromZigbee: [fz.temperature, fz.
|
|
109
|
+
description: 'Temperature sensor',
|
|
110
|
+
fromZigbee: [fz.temperature, fz.battery],
|
|
111
111
|
toZigbee: [],
|
|
112
|
-
exposes: [e.battery(), e.temperature()
|
|
112
|
+
exposes: [e.battery(), e.temperature()],
|
|
113
113
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
114
|
-
const endpoint = device.getEndpoint(
|
|
115
|
-
await reporting.bind(endpoint, coordinatorEndpoint, ['msTemperatureMeasurement', '
|
|
114
|
+
const endpoint = device.getEndpoint(3);
|
|
115
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['msTemperatureMeasurement', 'genPowerCfg']);
|
|
116
116
|
await reporting.temperature(endpoint);
|
|
117
|
-
await reporting.humidity(endpoint);
|
|
118
117
|
await reporting.batteryVoltage(endpoint);
|
|
119
118
|
await reporting.batteryPercentageRemaining(endpoint);
|
|
120
119
|
device.powerSource = 'Battery';
|
package/devices/philips.js
CHANGED
|
@@ -29,6 +29,24 @@ const hueExtend = {
|
|
|
29
29
|
};
|
|
30
30
|
|
|
31
31
|
module.exports = [
|
|
32
|
+
{
|
|
33
|
+
zigbeeModel: ['929003047501'],
|
|
34
|
+
model: '929003047501',
|
|
35
|
+
vendor: 'Philips',
|
|
36
|
+
description: 'Centura recessed spotlight',
|
|
37
|
+
meta: {turnsOffAtBrightness1: true},
|
|
38
|
+
extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 500]}),
|
|
39
|
+
ota: ota.zigbeeOTA,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
zigbeeModel: ['915005996401'],
|
|
43
|
+
model: '915005996401',
|
|
44
|
+
vendor: 'Philips',
|
|
45
|
+
description: 'Hue white ambiance ceiling light Enrave S with Bluetooth',
|
|
46
|
+
meta: {turnsOffAtBrightness1: true},
|
|
47
|
+
extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
|
|
48
|
+
ota: ota.zigbeeOTA,
|
|
49
|
+
},
|
|
32
50
|
{
|
|
33
51
|
zigbeeModel: ['929003054001'],
|
|
34
52
|
model: '929003054001',
|
|
@@ -2315,7 +2333,7 @@ module.exports = [
|
|
|
2315
2333
|
ota: ota.zigbeeOTA,
|
|
2316
2334
|
},
|
|
2317
2335
|
{
|
|
2318
|
-
zigbeeModel: ['5309331P6'],
|
|
2336
|
+
zigbeeModel: ['5309331P6', '5309330P6'],
|
|
2319
2337
|
model: '5309331P6',
|
|
2320
2338
|
vendor: 'Philips',
|
|
2321
2339
|
description: 'Hue White ambiance Runner triple spotlight',
|
|
@@ -2324,7 +2342,7 @@ module.exports = [
|
|
|
2324
2342
|
ota: ota.zigbeeOTA,
|
|
2325
2343
|
},
|
|
2326
2344
|
{
|
|
2327
|
-
zigbeeModel: ['5309230P6'],
|
|
2345
|
+
zigbeeModel: ['5309230P6', '5309231P6'],
|
|
2328
2346
|
model: '5309230P6',
|
|
2329
2347
|
vendor: 'Philips',
|
|
2330
2348
|
description: 'Hue White ambiance Runner double spotlight',
|
|
@@ -2369,7 +2387,7 @@ module.exports = [
|
|
|
2369
2387
|
ota: ota.zigbeeOTA,
|
|
2370
2388
|
},
|
|
2371
2389
|
{
|
|
2372
|
-
zigbeeModel: ['5309030P9'],
|
|
2390
|
+
zigbeeModel: ['5309030P9', '5309031P9', '5309030P6', '5309031P6'],
|
|
2373
2391
|
model: '5309030P9',
|
|
2374
2392
|
vendor: 'Philips',
|
|
2375
2393
|
description: 'Hue White ambiance Runner single spotlight',
|
|
@@ -610,4 +610,24 @@ module.exports = [
|
|
|
610
610
|
await reporting.readMeteringMultiplierDivisor(endpoint);
|
|
611
611
|
},
|
|
612
612
|
},
|
|
613
|
+
{
|
|
614
|
+
zigbeeModel: ['LK/OUTLET/1'],
|
|
615
|
+
model: '545D6115',
|
|
616
|
+
vendor: 'Schneider Electric',
|
|
617
|
+
description: 'LK FUGA wiser wireless socket outlet',
|
|
618
|
+
fromZigbee: [fz.on_off, fz.electrical_measurement, fz.EKO09738_metering, fz.power_on_behavior],
|
|
619
|
+
toZigbee: [tz.on_off, tz.power_on_behavior],
|
|
620
|
+
exposes: [e.switch(), e.power(), e.energy(), e.current(), e.voltage(),
|
|
621
|
+
exposes.enum('power_on_behavior', ea.ALL, ['off', 'previous', 'on'])
|
|
622
|
+
.withDescription('Controls the behaviour when the device is powered on')],
|
|
623
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
624
|
+
const endpoint = device.getEndpoint(6);
|
|
625
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering']);
|
|
626
|
+
await reporting.onOff(endpoint);
|
|
627
|
+
// Unit supports acVoltage and acCurrent, but only acCurrent divisor/multiplier can be read
|
|
628
|
+
await endpoint.read('haElectricalMeasurement', ['acCurrentDivisor', 'acCurrentMultiplier']);
|
|
629
|
+
await reporting.readMeteringMultiplierDivisor(endpoint);
|
|
630
|
+
await reporting.currentSummDelivered(endpoint, {min: 60, change: 1});
|
|
631
|
+
},
|
|
632
|
+
},
|
|
613
633
|
];
|
package/devices/shinasystem.js
CHANGED
|
@@ -24,6 +24,7 @@ module.exports = [
|
|
|
24
24
|
await endpoint.configureReporting('genAnalogInput', payload);
|
|
25
25
|
},
|
|
26
26
|
exposes: [e.battery(), e.battery_voltage(),
|
|
27
|
+
exposes.enum('status', ea.STATE, ['idle', 'in', 'out']).withDescription('Currently status'),
|
|
27
28
|
exposes.numeric('people', ea.ALL).withValueMin(0).withValueMax(50).withDescription('People count')],
|
|
28
29
|
},
|
|
29
30
|
{
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
const exposes = require('../lib/exposes');
|
|
2
|
+
const fz = {...require('../converters/fromZigbee'), legacy: require('../lib/legacy').fromZigbee};
|
|
3
|
+
const tz = require('../converters/toZigbee');
|
|
4
|
+
const ea = exposes.access;
|
|
5
|
+
|
|
6
|
+
module.exports = [
|
|
7
|
+
{
|
|
8
|
+
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_6qoazbre'}],
|
|
9
|
+
model: 'WZ5_dim',
|
|
10
|
+
vendor: 'Skydance',
|
|
11
|
+
description: 'Zigbee & RF 5 in 1 LED controller (DIM mode)',
|
|
12
|
+
fromZigbee: [fz.tuya_light_wz5],
|
|
13
|
+
toZigbee: [tz.tuya_dimmer_state, tz.tuya_light_wz5],
|
|
14
|
+
exposes: [
|
|
15
|
+
exposes.light().withBrightness().setAccess('state',
|
|
16
|
+
ea.STATE_SET).setAccess('brightness', ea.STATE_SET),
|
|
17
|
+
],
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_gz3n0tzf'}],
|
|
21
|
+
model: 'WZ5_cct',
|
|
22
|
+
vendor: 'Skydance',
|
|
23
|
+
description: 'Zigbee & RF 5 in 1 LED controller (CCT mode)',
|
|
24
|
+
fromZigbee: [fz.tuya_light_wz5],
|
|
25
|
+
toZigbee: [tz.tuya_dimmer_state, tz.tuya_light_wz5],
|
|
26
|
+
exposes: [
|
|
27
|
+
exposes.light().withBrightness().setAccess('state',
|
|
28
|
+
ea.STATE_SET).setAccess('brightness', ea.STATE_SET).withColorTemp([250, 454]).setAccess('color_temp', ea.STATE_SET),
|
|
29
|
+
],
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_9hghastn'}],
|
|
33
|
+
model: 'WZ5_rgb',
|
|
34
|
+
vendor: 'Skydance',
|
|
35
|
+
description: 'Zigbee & RF 5 in 1 LED controller (RGB mode)',
|
|
36
|
+
fromZigbee: [fz.tuya_light_wz5],
|
|
37
|
+
toZigbee: [tz.tuya_dimmer_state, tz.tuya_light_wz5],
|
|
38
|
+
exposes: [
|
|
39
|
+
exposes.light().withBrightness().setAccess('state', ea.STATE_SET).setAccess('brightness',
|
|
40
|
+
ea.STATE_SET).withColor('hs'),
|
|
41
|
+
],
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_3thxjahu'}],
|
|
45
|
+
model: 'WZ5_rgbw',
|
|
46
|
+
vendor: 'Skydance',
|
|
47
|
+
description: 'Zigbee & RF 5 in 1 LED controller (RGBW mode)',
|
|
48
|
+
fromZigbee: [fz.tuya_light_wz5],
|
|
49
|
+
toZigbee: [tz.tuya_dimmer_state, tz.tuya_light_wz5],
|
|
50
|
+
exposes: [
|
|
51
|
+
exposes.light().withBrightness().setAccess('state', ea.STATE_SET).setAccess('brightness',
|
|
52
|
+
ea.STATE_SET).withColor('hs'),
|
|
53
|
+
exposes.numeric('white_brightness', ea.STATE_SET).withValueMin(0).withValueMax(254).withDescription(
|
|
54
|
+
'White brightness of this light'),
|
|
55
|
+
],
|
|
56
|
+
meta: {separateWhite: true},
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_mde0utnv'}],
|
|
60
|
+
model: 'WZ5_rgbcct',
|
|
61
|
+
vendor: 'Skydance',
|
|
62
|
+
description: 'Zigbee & RF 5 in 1 LED controller (RGB+CCT mode)',
|
|
63
|
+
fromZigbee: [fz.tuya_light_wz5],
|
|
64
|
+
toZigbee: [tz.tuya_dimmer_state, tz.tuya_light_wz5],
|
|
65
|
+
exposes: [
|
|
66
|
+
exposes.light().withBrightness().setAccess('state', ea.STATE_SET).setAccess('brightness',
|
|
67
|
+
ea.STATE_SET).withColor('hs').withColorTemp([250, 454]).setAccess('color_temp',
|
|
68
|
+
ea.STATE_SET),
|
|
69
|
+
exposes.numeric('white_brightness', ea.STATE_SET).withValueMin(0).withValueMax(254).withDescription(
|
|
70
|
+
'White brightness of this light'),
|
|
71
|
+
],
|
|
72
|
+
meta: {separateWhite: true},
|
|
73
|
+
},
|
|
74
|
+
];
|
package/devices/sunricher.js
CHANGED
|
@@ -6,6 +6,22 @@ const extend = require('../lib/extend');
|
|
|
6
6
|
const e = exposes.presets;
|
|
7
7
|
|
|
8
8
|
module.exports = [
|
|
9
|
+
{
|
|
10
|
+
zigbeeModel: ['ON/OFF(2CH)'],
|
|
11
|
+
model: 'UP-SA-9127D',
|
|
12
|
+
vendor: 'Sunricher',
|
|
13
|
+
description: 'LED-trading 2 channel AC switch',
|
|
14
|
+
extend: extend.switch(),
|
|
15
|
+
exposes: [e.switch().withEndpoint('l1'), e.switch().withEndpoint('l2')],
|
|
16
|
+
endpoint: (device) => {
|
|
17
|
+
return {'l1': 1, 'l2': 2};
|
|
18
|
+
},
|
|
19
|
+
meta: {multiEndpoint: true},
|
|
20
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
21
|
+
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ['genOnOff']);
|
|
22
|
+
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ['genOnOff']);
|
|
23
|
+
},
|
|
24
|
+
},
|
|
9
25
|
{
|
|
10
26
|
zigbeeModel: ['HK-ZD-CCT-A'],
|
|
11
27
|
model: 'HK-ZD-CCT-A',
|
package/devices/tuya.js
CHANGED
|
@@ -12,7 +12,7 @@ const utils = require('../lib/utils');
|
|
|
12
12
|
|
|
13
13
|
const TS011Fplugs = ['_TZ3000_5f43h46b', '_TZ3000_cphmq0q7', '_TZ3000_dpo1ysak', '_TZ3000_ew3ldmgx', '_TZ3000_gjnozsaz',
|
|
14
14
|
'_TZ3000_jvzvulen', '_TZ3000_mraovvmm', '_TZ3000_nfnmi125', '_TZ3000_ps3dmato', '_TZ3000_w0qqde0g', '_TZ3000_u5u4cakc',
|
|
15
|
-
'_TZ3000_rdtixbnu', '_TZ3000_typdpbpg', '_TZ3000_v1pdxuqq'];
|
|
15
|
+
'_TZ3000_rdtixbnu', '_TZ3000_typdpbpg', '_TZ3000_v1pdxuqq', '_TZ3000_bfn1w0mm'];
|
|
16
16
|
|
|
17
17
|
const tzLocal = {
|
|
18
18
|
TS0504B_color: {
|
|
@@ -158,6 +158,7 @@ module.exports = [
|
|
|
158
158
|
{modelID: 'TS0505B', manufacturerName: '_TZ3000_589kq4ul'},
|
|
159
159
|
{modelID: 'TS0505B', manufacturerName: '_TZ3000_1mtktxdk'},
|
|
160
160
|
{modelID: 'TS0505B', manufacturerName: '_TZ3210_remypqqm'},
|
|
161
|
+
{modelID: 'TS0505B', manufacturerName: '_TZ3000_kohbva1f'},
|
|
161
162
|
{modelID: 'TS0505B', manufacturerName: '_TZ3210_0rn9qhnu'},
|
|
162
163
|
{modelID: 'TS0505B', manufacturerName: '_TZ3210_bicjqpg4'},
|
|
163
164
|
{modelID: 'TS0505B', manufacturerName: '_TZ3000_cmaky9gq'},
|
|
@@ -166,7 +167,10 @@ module.exports = [
|
|
|
166
167
|
vendor: 'TuYa',
|
|
167
168
|
description: 'Zigbee RGB+CCT light',
|
|
168
169
|
whiteLabel: [{vendor: 'Mercator Ikuü', model: 'SMD4106W-RGB-ZB'},
|
|
169
|
-
{vendor: 'TuYa', model: 'A5C-21F7-01'}, {vendor: 'Mercator Ikuü', model: 'S9E27LED9W-RGB-Z'}
|
|
170
|
+
{vendor: 'TuYa', model: 'A5C-21F7-01'}, {vendor: 'Mercator Ikuü', model: 'S9E27LED9W-RGB-Z'},
|
|
171
|
+
{vendor: 'Aldi', model: 'L122CB63H11A9.0W', description: 'LIGHTWAY smart home LED-lamp - bulb'},
|
|
172
|
+
{vendor: 'Lidl', model: '14153706L', description: 'Livarno smart LED ceiling light'},
|
|
173
|
+
],
|
|
170
174
|
extend: extend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
|
|
171
175
|
meta: {applyRedFix: true, enhancedHue: false},
|
|
172
176
|
},
|
|
@@ -660,6 +664,20 @@ module.exports = [
|
|
|
660
664
|
toZigbee: [],
|
|
661
665
|
whiteLabel: [{vendor: 'Neo', model: 'NAS-WS02B0'}],
|
|
662
666
|
},
|
|
667
|
+
{
|
|
668
|
+
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_jthf7vb6'}],
|
|
669
|
+
model: 'WLS-100z',
|
|
670
|
+
vendor: 'TuYa',
|
|
671
|
+
description: 'Water leak sensor',
|
|
672
|
+
fromZigbee: [fz.ignore_basic_report, fz.ignore_tuya_raw, fz.wls100z_water_leak],
|
|
673
|
+
toZigbee: [],
|
|
674
|
+
onEvent: tuya.onEventSetTime,
|
|
675
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
676
|
+
const endpoint = device.getEndpoint(1);
|
|
677
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genBasic']);
|
|
678
|
+
},
|
|
679
|
+
exposes: [e.battery(), e.water_leak()],
|
|
680
|
+
},
|
|
663
681
|
{
|
|
664
682
|
zigbeeModel: ['TS0001'],
|
|
665
683
|
model: 'TS0001',
|
|
@@ -1151,7 +1169,8 @@ module.exports = [
|
|
|
1151
1169
|
},
|
|
1152
1170
|
{
|
|
1153
1171
|
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_byzdayie'},
|
|
1154
|
-
{modelID: 'TS0601', manufacturerName: '_TZE200_fsb6zw01'}
|
|
1172
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_fsb6zw01'},
|
|
1173
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_ewxhg6o9'}],
|
|
1155
1174
|
model: 'TS0601_din',
|
|
1156
1175
|
vendor: 'TuYa',
|
|
1157
1176
|
description: 'Zigbee smart energy meter DDS238-2 Zigbee',
|
|
@@ -1677,7 +1696,9 @@ module.exports = [
|
|
|
1677
1696
|
],
|
|
1678
1697
|
},
|
|
1679
1698
|
{
|
|
1680
|
-
fingerprint: [
|
|
1699
|
+
fingerprint: [
|
|
1700
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_vrfecyku'},
|
|
1701
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_lu01t0zl'}],
|
|
1681
1702
|
model: 'MIR-HE200-TY',
|
|
1682
1703
|
vendor: 'TuYa',
|
|
1683
1704
|
description: 'Human presence sensor',
|
|
@@ -1805,4 +1826,13 @@ module.exports = [
|
|
|
1805
1826
|
toZigbee: [],
|
|
1806
1827
|
exposes: [e.action(['toggle', 'brightness_step_up', 'brightness_step_down'])],
|
|
1807
1828
|
},
|
|
1829
|
+
{
|
|
1830
|
+
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_kzm5w4iz'}],
|
|
1831
|
+
model: 'TS0601_vibration_sensor',
|
|
1832
|
+
vendor: 'TuYa',
|
|
1833
|
+
description: 'Smart vibration sensor',
|
|
1834
|
+
fromZigbee: [fz.tuya_smart_vibration_sensor],
|
|
1835
|
+
toZigbee: [],
|
|
1836
|
+
exposes: [e.contact(), e.battery(), e.vibration()],
|
|
1837
|
+
},
|
|
1808
1838
|
];
|
package/devices/xiaomi.js
CHANGED
|
@@ -89,6 +89,22 @@ module.exports = [
|
|
|
89
89
|
e.power_outage_memory().withAccess(ea.STATE_SET)]),
|
|
90
90
|
ota: ota.zigbeeOTA,
|
|
91
91
|
},
|
|
92
|
+
{
|
|
93
|
+
zigbeeModel: ['lumi.light.acn003'],
|
|
94
|
+
model: 'ZNXDD01LM',
|
|
95
|
+
vendor: 'Xiaomi',
|
|
96
|
+
description: 'Aqara ceiling light L1-350',
|
|
97
|
+
extend: xiaomiExtend.light_onoff_brightness_colortemp({disableEffect: true, colorTempRange: [153, 370]}),
|
|
98
|
+
ota: ota.zigbeeOTA,
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
zigbeeModel: ['lumi.light.cwac02'],
|
|
102
|
+
model: 'ZNLDP13LM',
|
|
103
|
+
vendor: 'Xiaomi',
|
|
104
|
+
description: 'Aqara T1 smart LED bulb',
|
|
105
|
+
extend: xiaomiExtend.light_onoff_brightness_colortemp({disableEffect: true, colorTempRange: [153, 370]}),
|
|
106
|
+
ota: ota.zigbeeOTA,
|
|
107
|
+
},
|
|
92
108
|
{
|
|
93
109
|
zigbeeModel: ['lumi.light.cwopcn01'],
|
|
94
110
|
model: 'XDD11LM',
|
|
@@ -670,6 +686,11 @@ module.exports = [
|
|
|
670
686
|
exposes.enum('operation_mode', ea.ALL, ['control_relay', 'decoupled'])
|
|
671
687
|
.withDescription('Decoupled mode'),
|
|
672
688
|
],
|
|
689
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
690
|
+
device.type = 'Router';
|
|
691
|
+
device.powerSource = 'Mains (single phase)';
|
|
692
|
+
device.save();
|
|
693
|
+
},
|
|
673
694
|
},
|
|
674
695
|
{
|
|
675
696
|
zigbeeModel: ['lumi.switch.b2nacn02'],
|
|
@@ -852,19 +873,17 @@ module.exports = [
|
|
|
852
873
|
zigbeeModel: ['lumi.motion.agl02'],
|
|
853
874
|
model: 'RTCGQ12LM',
|
|
854
875
|
vendor: 'Xiaomi',
|
|
855
|
-
description: 'Aqara T1 human body movement and illuminance sensor
|
|
856
|
-
fromZigbee: [fz.
|
|
857
|
-
toZigbee: [tz.
|
|
858
|
-
exposes: [e.occupancy(), e.
|
|
859
|
-
exposes.numeric('occupancy_timeout',
|
|
860
|
-
.withDescription('Time in seconds till occupancy goes to false')],
|
|
876
|
+
description: 'Aqara T1 human body movement and illuminance sensor',
|
|
877
|
+
fromZigbee: [fz.RTCGQ12LM_occupancy_illuminance, fz.aqara_opple, fz.battery],
|
|
878
|
+
toZigbee: [tz.aqara_occupancy_timeout],
|
|
879
|
+
exposes: [e.occupancy(), e.illuminance().withUnit('lx').withDescription('Measured illuminance in lux'),
|
|
880
|
+
exposes.numeric('occupancy_timeout', ea.ALL).withValueMin(2).withValueMax(65535).withUnit('s')
|
|
881
|
+
.withDescription('Time in seconds till occupancy goes to false'), e.battery()],
|
|
861
882
|
meta: {battery: {voltageToPercentage: '3V_2100'}},
|
|
862
883
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
863
884
|
const endpoint = device.getEndpoint(1);
|
|
864
|
-
await
|
|
865
|
-
await
|
|
866
|
-
await reporting.batteryVoltage(endpoint);
|
|
867
|
-
await endpoint.read('msOccupancySensing', ['pirOToUDelay']);
|
|
885
|
+
await endpoint.read('genPowerCfg', ['batteryVoltage']);
|
|
886
|
+
await endpoint.read('aqaraOpple', [0x0102], {manufacturerCode: 0x115f});
|
|
868
887
|
},
|
|
869
888
|
},
|
|
870
889
|
{
|
|
@@ -872,15 +891,15 @@ module.exports = [
|
|
|
872
891
|
model: 'RTCGQ13LM',
|
|
873
892
|
vendor: 'Xiaomi',
|
|
874
893
|
description: 'Aqara high precision motion sensor',
|
|
875
|
-
fromZigbee: [fz.
|
|
876
|
-
toZigbee: [tz.
|
|
877
|
-
exposes: [e.occupancy(),
|
|
878
|
-
exposes.
|
|
879
|
-
|
|
880
|
-
.withDescription('Time interval for detecting actions')],
|
|
894
|
+
fromZigbee: [fz.RTCGQ13LM_occupancy, fz.aqara_opple, fz.battery],
|
|
895
|
+
toZigbee: [tz.aqara_occupancy_timeout, tz.RTCGQ13LM_motion_sensitivity],
|
|
896
|
+
exposes: [e.occupancy(), exposes.enum('motion_sensitivity', ea.ALL, ['low', 'medium', 'high']),
|
|
897
|
+
exposes.numeric('occupancy_timeout', ea.ALL).withValueMin(2).withValueMax(65535).withUnit('s')
|
|
898
|
+
.withDescription('Time in seconds till occupancy goes to false'), e.battery()],
|
|
881
899
|
meta: {battery: {voltageToPercentage: '3V_2100'}},
|
|
882
900
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
883
901
|
const endpoint = device.getEndpoint(1);
|
|
902
|
+
await endpoint.read('genPowerCfg', ['batteryVoltage']);
|
|
884
903
|
await endpoint.read('aqaraOpple', [0x0102], {manufacturerCode: 0x115f});
|
|
885
904
|
await endpoint.read('aqaraOpple', [0x010c], {manufacturerCode: 0x115f});
|
|
886
905
|
},
|
package/devices/zemismart.js
CHANGED
|
@@ -9,7 +9,7 @@ const tuya = require('../lib/tuya');
|
|
|
9
9
|
const fzLocal = {
|
|
10
10
|
ZMRM02: {
|
|
11
11
|
cluster: 'manuSpecificTuya',
|
|
12
|
-
type: ['commandGetData', 'commandSetDataResponse'],
|
|
12
|
+
type: ['commandGetData', 'commandSetDataResponse', 'commandDataResponse'],
|
|
13
13
|
convert: (model, msg, publish, options, meta) => {
|
|
14
14
|
const dpValue = tuya.firstDpValue(msg, meta, 'ZMRM02');
|
|
15
15
|
const button = dpValue.dp;
|
package/lib/exposes.js
CHANGED
|
@@ -527,7 +527,7 @@ module.exports = {
|
|
|
527
527
|
current: () => new Numeric('current', access.STATE).withUnit('A').withDescription('Instantaneous measured electrical current'),
|
|
528
528
|
current_phase_b: () => new Numeric('current_phase_b', access.STATE).withUnit('A').withDescription('Instantaneous measured electrical current on phase B'),
|
|
529
529
|
current_phase_c: () => new Numeric('current_phase_c', access.STATE).withUnit('A').withDescription('Instantaneous measured electrical current on phase C'),
|
|
530
|
-
deadzone_temperature: () => new Numeric('deadzone_temperature', access.STATE_SET).withUnit('°C').withDescription('The delta between local_temperature and current_heating_setpoint to trigger Heat').withValueMin(0
|
|
530
|
+
deadzone_temperature: () => new Numeric('deadzone_temperature', access.STATE_SET).withUnit('°C').withDescription('The delta between local_temperature and current_heating_setpoint to trigger Heat').withValueMin(0).withValueMax(5).withValueStep(1),
|
|
531
531
|
device_temperature: () => new Numeric('device_temperature', access.STATE).withUnit('°C').withDescription('Temperature of the device'),
|
|
532
532
|
eco2: () => new Numeric('eco2', access.STATE).withUnit('ppm').withDescription('Measured eCO2 value'),
|
|
533
533
|
eco_mode: () => new Binary('eco_mode', access.STATE_SET, 'ON', 'OFF').withDescription('ECO mode (energy saving mode)'),
|
package/lib/ota/zigbeeOTA.js
CHANGED
|
@@ -2,17 +2,56 @@ const url = 'https://raw.githubusercontent.com/Koenkk/zigbee-OTA/master/index.js
|
|
|
2
2
|
const assert = require('assert');
|
|
3
3
|
const common = require('./common');
|
|
4
4
|
const axios = common.getAxios();
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const URI = require('uri-js');
|
|
7
|
+
|
|
8
|
+
let overrideFileName = null;
|
|
5
9
|
|
|
6
10
|
/**
|
|
7
11
|
* Helper functions
|
|
8
12
|
*/
|
|
9
13
|
|
|
14
|
+
|
|
15
|
+
function isValidUrl(url) {
|
|
16
|
+
let parsed;
|
|
17
|
+
try {
|
|
18
|
+
parsed = URI.parse(url);
|
|
19
|
+
} catch (_) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
return parsed.scheme === 'http' || parsed.scheme === 'https';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function getFile(urlOrName) {
|
|
26
|
+
if (isValidUrl(urlOrName)) {
|
|
27
|
+
return (await axios.get(urlOrName)).data;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return JSON.parse(fs.readFileSync(urlOrName));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function getIndex(logger) {
|
|
34
|
+
const index = (await axios.get(url)).data;
|
|
35
|
+
|
|
36
|
+
logger.debug(`ZigbeeOTA: downloaded main index`);
|
|
37
|
+
|
|
38
|
+
if (overrideFileName) {
|
|
39
|
+
logger.debug(`ZigbeeOTA: Loading override index ${overrideFileName}`);
|
|
40
|
+
const localIndex = await getFile(overrideFileName);
|
|
41
|
+
|
|
42
|
+
// Resulting index will have overriden items first
|
|
43
|
+
return localIndex.concat(index);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return index;
|
|
47
|
+
}
|
|
48
|
+
|
|
10
49
|
async function getImageMeta(current, logger, device) {
|
|
11
50
|
const modelId = device.modelID;
|
|
12
51
|
const imageType = current.imageType;
|
|
13
52
|
const manufacturerCode = current.manufacturerCode;
|
|
14
53
|
const manufacturerName = device.manufacturerName;
|
|
15
|
-
const images =
|
|
54
|
+
const images = await getIndex(logger);
|
|
16
55
|
|
|
17
56
|
// NOTE: Officially an image can be determined with a combination of manufacturerCode and imageType.
|
|
18
57
|
// However Gledopto pro products use the same imageType (0) for every device while the image is different.
|
|
@@ -46,4 +85,7 @@ module.exports = {
|
|
|
46
85
|
getImageMeta,
|
|
47
86
|
isUpdateAvailable,
|
|
48
87
|
updateToLatest,
|
|
88
|
+
useIndexOverride: (indexFileName) => {
|
|
89
|
+
overrideFileName = indexFileName;
|
|
90
|
+
},
|
|
49
91
|
};
|
package/lib/tuya.js
CHANGED
|
@@ -86,6 +86,9 @@ async function onEventMeasurementPoll(type, data, device, options) {
|
|
|
86
86
|
try {
|
|
87
87
|
await endpoint.read('haElectricalMeasurement', ['rmsVoltage', 'rmsCurrent', 'activePower']);
|
|
88
88
|
await endpoint.read('seMetering', ['currentSummDelivered']);
|
|
89
|
+
if (device.manufacturerName === '_TZ3000_u5u4cakc') {
|
|
90
|
+
await endpoint.read('genOnOff', ['onOff']);
|
|
91
|
+
}
|
|
89
92
|
} catch (error) {/* Do nothing*/}
|
|
90
93
|
}, seconds*1000);
|
|
91
94
|
globalStore.putValue(device, 'interval', interval);
|
|
@@ -101,11 +104,14 @@ async function onEventSetTime(type, data, device) {
|
|
|
101
104
|
const localTime = utcTime - (new Date()).getTimezoneOffset() * 60;
|
|
102
105
|
const endpoint = device.getEndpoint(1);
|
|
103
106
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
const payload = {
|
|
108
|
+
payloadSize: 8,
|
|
109
|
+
payload: [
|
|
110
|
+
...convertDecimalValueTo4ByteHexArray(utcTime),
|
|
111
|
+
...convertDecimalValueTo4ByteHexArray(localTime),
|
|
112
|
+
],
|
|
113
|
+
};
|
|
114
|
+
await endpoint.command('manuSpecificTuya', 'mcuSyncTime', payload, {});
|
|
109
115
|
} catch (error) {
|
|
110
116
|
// endpoint.command can throw an error which needs to
|
|
111
117
|
// be caught or the zigbee-herdsman may crash
|
|
@@ -134,11 +140,14 @@ async function onEventSetLocalTime(type, data, device) {
|
|
|
134
140
|
const localTime = utcTime - (new Date()).getTimezoneOffset() * 60;
|
|
135
141
|
const endpoint = device.getEndpoint(1);
|
|
136
142
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
143
|
+
const payload = {
|
|
144
|
+
payloadSize: 8,
|
|
145
|
+
payload: [
|
|
146
|
+
...convertDecimalValueTo4ByteHexArray(utcTime),
|
|
147
|
+
...convertDecimalValueTo4ByteHexArray(localTime),
|
|
148
|
+
],
|
|
149
|
+
};
|
|
150
|
+
await endpoint.command('manuSpecificTuya', 'mcuSyncTime', payload, {});
|
|
142
151
|
} catch (error) {
|
|
143
152
|
// endpoint.command can throw an error which needs to
|
|
144
153
|
// be caught or the zigbee-herdsman may crash
|
|
@@ -375,6 +384,7 @@ const dataPoints = {
|
|
|
375
384
|
// Silvercrest
|
|
376
385
|
silvercrestChangeMode: 2,
|
|
377
386
|
silvercrestSetBrightness: 3,
|
|
387
|
+
silvercrestSetColorTemp: 4,
|
|
378
388
|
silvercrestSetColor: 5,
|
|
379
389
|
silvercrestSetEffect: 6,
|
|
380
390
|
// Fantem
|
|
@@ -515,12 +525,16 @@ const dataPoints = {
|
|
|
515
525
|
nousMinTemp: 11,
|
|
516
526
|
nousTempAlarm: 14,
|
|
517
527
|
nousTempSensitivity: 19,
|
|
518
|
-
|
|
519
528
|
// TUYA / HUMIDITY/ILLUMINANCE/TEMPERATURE SENSOR
|
|
520
529
|
thitBatteryPercentage: 3,
|
|
521
530
|
thitIlluminanceLux: 7,
|
|
522
531
|
thitHumidity: 9,
|
|
523
532
|
thitTemperature: 8,
|
|
533
|
+
// TUYA SMART VIBRATION SENSOR
|
|
534
|
+
tuyaVibration: 10,
|
|
535
|
+
// TUYA WLS-100z Water Leak Sensor
|
|
536
|
+
wlsWaterLeak: 1,
|
|
537
|
+
wlsBatteryPercentage: 4,
|
|
524
538
|
};
|
|
525
539
|
|
|
526
540
|
const thermostatWeekFormat = {
|
package/npm-shrinkwrap.json
CHANGED