zigbee-herdsman-converters 14.0.465 → 14.0.468
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 +35 -18
- package/converters/toZigbee.js +41 -14
- package/devices/datek.js +16 -10
- package/devices/legrand.js +18 -0
- package/devices/lidl.js +11 -0
- package/devices/moes.js +1 -0
- package/devices/niko.js +67 -4
- package/devices/orvibo.js +1 -1
- package/devices/paul_neuhaus.js +1 -1
- package/devices/philips.js +9 -0
- package/devices/spotmau.js +3 -0
- package/devices/tuya.js +15 -7
- package/devices/xiaomi.js +38 -4
- package/lib/exposes.js +6 -0
- package/lib/tuya.js +63 -0
- package/lib/xiaomi.js +68 -16
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/converters/fromZigbee.js
CHANGED
|
@@ -3820,7 +3820,12 @@ const converters = {
|
|
|
3820
3820
|
return {deadzone_temperature: value};
|
|
3821
3821
|
case tuya.dataPoints.moesLocalTemp:
|
|
3822
3822
|
temperature = value & 1<<15 ? value - (1<<16) + 1 : value;
|
|
3823
|
-
|
|
3823
|
+
if (meta.device.manufacturerName === '_TZE200_ye5jkfsb') {
|
|
3824
|
+
// https://github.com/Koenkk/zigbee2mqtt/issues/11980
|
|
3825
|
+
temperature = temperature / 10;
|
|
3826
|
+
}
|
|
3827
|
+
|
|
3828
|
+
return {local_temperature: parseFloat(temperature.toFixed(1))};
|
|
3824
3829
|
case tuya.dataPoints.moesTempCalibration:
|
|
3825
3830
|
temperature = value;
|
|
3826
3831
|
// for negative values produce complimentary hex (equivalent to negative values)
|
|
@@ -4193,6 +4198,7 @@ const converters = {
|
|
|
4193
4198
|
const dpValue = tuya.firstDpValue(msg, meta, 'tuya_air_quality');
|
|
4194
4199
|
const dp = dpValue.dp;
|
|
4195
4200
|
const value = tuya.getDataValue(dpValue);
|
|
4201
|
+
const swapPM25CO2 = ['_TZE200_ryfmq5rl', '_TZE200_dwcarsat'];
|
|
4196
4202
|
switch (dp) {
|
|
4197
4203
|
case tuya.dataPoints.tuyaSabTemp:
|
|
4198
4204
|
return {temperature: calibrateAndPrecisionRoundOptions(value / 10, options, 'temperature')};
|
|
@@ -4200,14 +4206,14 @@ const converters = {
|
|
|
4200
4206
|
return {humidity: calibrateAndPrecisionRoundOptions(value / 10, options, 'humidity')};
|
|
4201
4207
|
// DP22: Smart Air Box: Formaldehyd, Smart Air Housekeeper: co2
|
|
4202
4208
|
case tuya.dataPoints.tuyaSabFormaldehyd:
|
|
4203
|
-
if (meta.device.manufacturerName
|
|
4209
|
+
if (swapPM25CO2.includes(meta.device.manufacturerName)) {
|
|
4204
4210
|
return {co2: calibrateAndPrecisionRoundOptions(value, options, 'co2')};
|
|
4205
4211
|
} else {
|
|
4206
4212
|
return {formaldehyd: calibrateAndPrecisionRoundOptions(value, options, 'formaldehyd')};
|
|
4207
4213
|
}
|
|
4208
4214
|
// DP2: Smart Air Box: co2, Smart Air Housekeeper: MP25
|
|
4209
4215
|
case tuya.dataPoints.tuyaSabCO2:
|
|
4210
|
-
if (meta.device.manufacturerName
|
|
4216
|
+
if (swapPM25CO2.includes(meta.device.manufacturerName)) {
|
|
4211
4217
|
return {pm25: calibrateAndPrecisionRoundOptions(value, options, 'pm25')};
|
|
4212
4218
|
} else {
|
|
4213
4219
|
return {co2: calibrateAndPrecisionRoundOptions(value, options, 'co2')};
|
|
@@ -4580,10 +4586,33 @@ const converters = {
|
|
|
4580
4586
|
} else if (meta.device.manufacturerName === '_TZE200_swaamsoy') {
|
|
4581
4587
|
// https://github.com/Koenkk/zigbee-herdsman-converters/pull/3004
|
|
4582
4588
|
if (dpValue.dp === 2) {
|
|
4589
|
+
if (value < 10) {
|
|
4590
|
+
tuya.logUnexpectedDataValue('tuya_dimmer', msg, dpValue, meta, 'brightness', 10, 1000);
|
|
4591
|
+
}
|
|
4583
4592
|
return {brightness: mapNumberRange(value, 10, 1000, 0, 254)};
|
|
4584
4593
|
}
|
|
4585
|
-
} else
|
|
4586
|
-
|
|
4594
|
+
} else if (meta.device.manufacturerName === '_TZE200_3p5ydos3') {
|
|
4595
|
+
if (dpValue.dp === tuya.dataPoints.eardaDimmerLevel) {
|
|
4596
|
+
return {brightness: mapNumberRange(value, 0, 1000, 0, 254)};
|
|
4597
|
+
} else if (dpValue.dp === tuya.dataPoints.dimmerMinLevel) {
|
|
4598
|
+
return {min_brightness: mapNumberRange(value, 0, 1000, 1, 255)};
|
|
4599
|
+
} else if (dpValue.dp === tuya.dataPoints.dimmerMaxLevel) {
|
|
4600
|
+
return {max_brightness: mapNumberRange(value, 0, 1000, 1, 255)};
|
|
4601
|
+
} else {
|
|
4602
|
+
tuya.logUnexpectedDataPoint('tuya_dimmer', msg, dpValue, meta);
|
|
4603
|
+
}
|
|
4604
|
+
} else {
|
|
4605
|
+
if (dpValue.dp !== tuya.dataPoints.dimmerLevel) {
|
|
4606
|
+
tuya.logUnexpectedDataPoint('tuya_dimmer', msg, dpValue, meta);
|
|
4607
|
+
}
|
|
4608
|
+
if (dpValue.datatype !== tuya.dataTypes.value) {
|
|
4609
|
+
tuya.logUnexpectedDataType('tuya_dimmer', msg, dpValue, meta);
|
|
4610
|
+
} else {
|
|
4611
|
+
if (value < 10) {
|
|
4612
|
+
tuya.logUnexpectedDataValue('tuya_dimmer', msg, dpValue, meta, 'brightness', 10, 1000);
|
|
4613
|
+
}
|
|
4614
|
+
return {brightness: mapNumberRange(value, 10, 1000, 0, 254), level: value};
|
|
4615
|
+
}
|
|
4587
4616
|
}
|
|
4588
4617
|
},
|
|
4589
4618
|
},
|
|
@@ -4593,14 +4622,6 @@ const converters = {
|
|
|
4593
4622
|
convert: (model, msg, publis, options, meta) => {
|
|
4594
4623
|
// Don't use in production!
|
|
4595
4624
|
// Used in: https://www.zigbee2mqtt.io/how_tos/how_to_support_new_tuya_devices.html
|
|
4596
|
-
const getType = (datatype) => {
|
|
4597
|
-
const entry = Object.entries(tuya.dataTypes).find(([typeName, typeId]) => typeId === datatype);
|
|
4598
|
-
return (entry ? entry[0] : 'unknown');
|
|
4599
|
-
};
|
|
4600
|
-
const getAllDpIds = (dp) => {
|
|
4601
|
-
const entries = Object.entries(tuya.dataPoints).filter(([dpName, dpId]) => dpId === dp);
|
|
4602
|
-
return entries.map(([dpName, dpId]) => dpName);
|
|
4603
|
-
};
|
|
4604
4625
|
const getHex = (value) => {
|
|
4605
4626
|
let hex = value.toString(16);
|
|
4606
4627
|
if (hex.length < 2) {
|
|
@@ -4611,11 +4632,7 @@ const converters = {
|
|
|
4611
4632
|
const now = Date.now().toString();
|
|
4612
4633
|
let dataStr = '';
|
|
4613
4634
|
for (const [i, dpValue] of msg.data.dpValues.entries()) {
|
|
4614
|
-
|
|
4615
|
-
meta.logger.info(`zigbee-herdsman-converters:tuya_data_point_dump: Received DP #${
|
|
4616
|
-
dpValue.dp} from ${meta.device.ieeeAddr} with raw data '${JSON.stringify(dpValue)}': type='${msg.type}', datatype='${
|
|
4617
|
-
getType(dpValue.datatype)}', value='${value}', known DP# usage: ${JSON.stringify(getAllDpIds(dpValue.dp))}`);
|
|
4618
|
-
|
|
4635
|
+
tuya.logDataPoint('tuya_data_point_dump', msg, dpValue, meta);
|
|
4619
4636
|
dataStr +=
|
|
4620
4637
|
now + ' ' +
|
|
4621
4638
|
meta.device.ieeeAddr + ' ' +
|
package/converters/toZigbee.js
CHANGED
|
@@ -2584,14 +2584,14 @@ const converters = {
|
|
|
2584
2584
|
await entity.write('ssIasZone', {0xFFF1: {value: 0x03010000, type: 0x23}}, options);
|
|
2585
2585
|
},
|
|
2586
2586
|
},
|
|
2587
|
-
|
|
2588
|
-
key: ['gas'],
|
|
2587
|
+
aqara_alarm: {
|
|
2588
|
+
key: ['gas', 'smoke'],
|
|
2589
2589
|
convertGet: async (entity, key, meta) => {
|
|
2590
2590
|
await entity.read('aqaraOpple', [0x013a], manufacturerOptions.xiaomi);
|
|
2591
2591
|
},
|
|
2592
2592
|
},
|
|
2593
|
-
|
|
2594
|
-
key: ['gas_density'],
|
|
2593
|
+
aqara_density: {
|
|
2594
|
+
key: ['gas_density', 'smoke_density'],
|
|
2595
2595
|
convertGet: async (entity, key, meta) => {
|
|
2596
2596
|
await entity.read('aqaraOpple', [0x013b], manufacturerOptions.xiaomi);
|
|
2597
2597
|
},
|
|
@@ -2608,26 +2608,39 @@ const converters = {
|
|
|
2608
2608
|
await entity.read('aqaraOpple', [0x010c], manufacturerOptions.xiaomi);
|
|
2609
2609
|
},
|
|
2610
2610
|
},
|
|
2611
|
-
|
|
2611
|
+
aqara_selftest: {
|
|
2612
2612
|
key: ['selftest'],
|
|
2613
2613
|
convertSet: async (entity, key, value, meta) => {
|
|
2614
2614
|
await entity.write('aqaraOpple', {0x0127: {value: true, type: 0x10}}, manufacturerOptions.xiaomi);
|
|
2615
2615
|
},
|
|
2616
2616
|
},
|
|
2617
|
-
|
|
2617
|
+
aqara_mute_buzzer: {
|
|
2618
2618
|
key: ['mute_buzzer'],
|
|
2619
2619
|
convertSet: async (entity, key, value, meta) => {
|
|
2620
|
-
|
|
2620
|
+
let attribute = 0x013f;
|
|
2621
|
+
if (['JY-GZ-01AQ'].includes(meta.mapped.model)) attribute = 0x013e;
|
|
2622
|
+
await entity.write('aqaraOpple', {[`${attribute}`]: {value: 15360, type: 0x23}}, manufacturerOptions.xiaomi);
|
|
2621
2623
|
await entity.write('aqaraOpple', {0x0126: {value: 1, type: 0x20}}, manufacturerOptions.xiaomi);
|
|
2622
2624
|
},
|
|
2623
2625
|
},
|
|
2624
|
-
|
|
2626
|
+
aqara_mute: {
|
|
2625
2627
|
key: ['mute'],
|
|
2626
2628
|
convertGet: async (entity, key, meta) => {
|
|
2627
2629
|
await entity.read('aqaraOpple', [0x0126], manufacturerOptions.xiaomi);
|
|
2628
2630
|
},
|
|
2629
2631
|
},
|
|
2630
|
-
|
|
2632
|
+
JYGZ01AQ_heartbeat_indicator: {
|
|
2633
|
+
key: ['heartbeat_indicator'],
|
|
2634
|
+
convertSet: async (entity, key, value, meta) => {
|
|
2635
|
+
const lookup = {true: 1, false: 0};
|
|
2636
|
+
await entity.write('aqaraOpple', {0x013c: {value: lookup[value], type: 0x20}}, manufacturerOptions.xiaomi);
|
|
2637
|
+
return {state: {heartbeat_indicator: value}};
|
|
2638
|
+
},
|
|
2639
|
+
convertGet: async (entity, key, meta) => {
|
|
2640
|
+
await entity.read('aqaraOpple', [0x013c], manufacturerOptions.xiaomi);
|
|
2641
|
+
},
|
|
2642
|
+
},
|
|
2643
|
+
aqara_linkage_alarm: {
|
|
2631
2644
|
key: ['linkage_alarm'],
|
|
2632
2645
|
convertSet: async (entity, key, value, meta) => {
|
|
2633
2646
|
const lookup = {true: 1, false: 0};
|
|
@@ -3516,7 +3529,7 @@ const converters = {
|
|
|
3516
3529
|
},
|
|
3517
3530
|
},
|
|
3518
3531
|
tuya_dimmer_level: {
|
|
3519
|
-
key: ['brightness_min', 'brightness', 'brightness_percent', 'level'],
|
|
3532
|
+
key: ['brightness_min', 'min_brightness', 'max_brightness', 'brightness', 'brightness_percent', 'level'],
|
|
3520
3533
|
convertSet: async (entity, key, value, meta) => {
|
|
3521
3534
|
// upscale to 1000
|
|
3522
3535
|
let newValue;
|
|
@@ -3531,6 +3544,20 @@ const converters = {
|
|
|
3531
3544
|
} else {
|
|
3532
3545
|
throw new Error('Dimmer brightness_min is out of range 0..100');
|
|
3533
3546
|
}
|
|
3547
|
+
} else if (key === 'min_brightness') {
|
|
3548
|
+
if (value >= 1 && value <= 255) {
|
|
3549
|
+
newValue = utils.mapNumberRange(value, 1, 255, 0, 1000);
|
|
3550
|
+
dp = tuya.dataPoints.dimmerMinLevel;
|
|
3551
|
+
} else {
|
|
3552
|
+
throw new Error('Dimmer min_brightness is out of range 1..255');
|
|
3553
|
+
}
|
|
3554
|
+
} else if (key === 'max_brightness') {
|
|
3555
|
+
if (value >= 1 && value <= 255) {
|
|
3556
|
+
newValue = utils.mapNumberRange(value, 1, 255, 0, 1000);
|
|
3557
|
+
dp = tuya.dataPoints.dimmerMaxLevel;
|
|
3558
|
+
} else {
|
|
3559
|
+
throw new Error('Dimmer min_brightness is out of range 1..255');
|
|
3560
|
+
}
|
|
3534
3561
|
} else if (key === 'level') {
|
|
3535
3562
|
if (value >= 0 && value <= 1000) {
|
|
3536
3563
|
newValue = Math.round(Number(value));
|
|
@@ -3543,11 +3570,11 @@ const converters = {
|
|
|
3543
3570
|
} else {
|
|
3544
3571
|
throw new Error('Dimmer brightness_percent is out of range 0..100');
|
|
3545
3572
|
}
|
|
3546
|
-
} else {
|
|
3547
|
-
if (value >= 0 && value <=
|
|
3548
|
-
newValue = utils.mapNumberRange(value, 0,
|
|
3573
|
+
} else { // brightness
|
|
3574
|
+
if (value >= 0 && value <= 254) {
|
|
3575
|
+
newValue = utils.mapNumberRange(value, 0, 254, 0, 1000);
|
|
3549
3576
|
} else {
|
|
3550
|
-
throw new Error('Dimmer brightness is out of range 0..
|
|
3577
|
+
throw new Error('Dimmer brightness is out of range 0..254');
|
|
3551
3578
|
}
|
|
3552
3579
|
}
|
|
3553
3580
|
// Always use same transid as tuya_dimmer_state (https://github.com/Koenkk/zigbee2mqtt/issues/6366)
|
package/devices/datek.js
CHANGED
|
@@ -41,39 +41,45 @@ module.exports = [
|
|
|
41
41
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
42
42
|
const endpoint = device.getEndpoint(1);
|
|
43
43
|
await reporting.bind(endpoint, coordinatorEndpoint, ['haElectricalMeasurement', 'seMetering', 'msTemperatureMeasurement']);
|
|
44
|
-
await reporting.readEletricalMeasurementMultiplierDivisors(endpoint);
|
|
45
44
|
await reporting.readMeteringMultiplierDivisor(endpoint);
|
|
45
|
+
try {
|
|
46
|
+
await reporting.readEletricalMeasurementMultiplierDivisors(endpoint);
|
|
47
|
+
} catch (error) {
|
|
48
|
+
/* fails for some: https://github.com/Koenkk/zigbee2mqtt/issues/11867 */
|
|
49
|
+
}
|
|
46
50
|
const payload = [{
|
|
47
51
|
attribute: 'rmsVoltagePhB',
|
|
48
|
-
minimumReportInterval:
|
|
52
|
+
minimumReportInterval: 60,
|
|
49
53
|
maximumReportInterval: 3600,
|
|
50
54
|
reportableChange: 0,
|
|
51
55
|
},
|
|
52
56
|
{
|
|
53
57
|
attribute: 'rmsVoltagePhC',
|
|
54
|
-
minimumReportInterval:
|
|
58
|
+
minimumReportInterval: 60,
|
|
55
59
|
maximumReportInterval: 3600,
|
|
56
60
|
reportableChange: 0,
|
|
57
61
|
},
|
|
58
62
|
{
|
|
59
63
|
attribute: 'rmsCurrentPhB',
|
|
60
|
-
minimumReportInterval:
|
|
64
|
+
minimumReportInterval: 60,
|
|
61
65
|
maximumReportInterval: 3600,
|
|
62
66
|
reportableChange: 0,
|
|
63
67
|
},
|
|
64
68
|
{
|
|
65
69
|
attribute: 'rmsCurrentPhC',
|
|
66
|
-
minimumReportInterval:
|
|
70
|
+
minimumReportInterval: 60,
|
|
67
71
|
maximumReportInterval: 3600,
|
|
68
72
|
reportableChange: 0,
|
|
69
73
|
}];
|
|
70
74
|
await endpoint.configureReporting('haElectricalMeasurement', payload);
|
|
71
|
-
await reporting.rmsVoltage(endpoint, {min:
|
|
72
|
-
await reporting.rmsCurrent(endpoint, {min:
|
|
73
|
-
await reporting.instantaneousDemand(endpoint, {min:
|
|
74
|
-
await reporting.currentSummDelivered(endpoint, {min:
|
|
75
|
+
await reporting.rmsVoltage(endpoint, {min: 60, max: 3600, change: 0});
|
|
76
|
+
await reporting.rmsCurrent(endpoint, {min: 60, max: 3600, change: 0});
|
|
77
|
+
await reporting.instantaneousDemand(endpoint, {min: 60, max: 3600, change: 0});
|
|
78
|
+
await reporting.currentSummDelivered(endpoint, {min: 60, max: 3600, change: [1, 1]});
|
|
75
79
|
await reporting.currentSummReceived(endpoint);
|
|
76
|
-
await reporting.temperature(endpoint);
|
|
80
|
+
await reporting.temperature(endpoint, {min: 60, max: 3600, change: 0});
|
|
81
|
+
device.powerSource = 'DC source';
|
|
82
|
+
device.save();
|
|
77
83
|
},
|
|
78
84
|
exposes: [e.power(), e.energy(), e.current(), e.voltage(), e.current_phase_b(), e.voltage_phase_b(), e.current_phase_c(),
|
|
79
85
|
e.voltage_phase_c(), e.temperature()],
|
package/devices/legrand.js
CHANGED
|
@@ -341,4 +341,22 @@ module.exports = [
|
|
|
341
341
|
return {left: 2, right: 1};
|
|
342
342
|
},
|
|
343
343
|
},
|
|
344
|
+
{
|
|
345
|
+
zigbeeModel: [' Mobile outlet\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000'+
|
|
346
|
+
'\u0000\u0000\u0000\u0000\u0000\u0000\u0000'],
|
|
347
|
+
model: 'WNRR15/WNRR20',
|
|
348
|
+
vendor: 'Legrand',
|
|
349
|
+
ota: ota.zigbeeOTA,
|
|
350
|
+
description: 'Outlet with power consumption monitoring',
|
|
351
|
+
fromZigbee: [fz.identify, fz.on_off, fz.electrical_measurement],
|
|
352
|
+
toZigbee: [tz.on_off, tz.legrand_settingAlwaysEnableLed, tz.legrand_identify],
|
|
353
|
+
exposes: [e.switch(), e.action(['identify']), e.power()],
|
|
354
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
355
|
+
const endpoint = device.getEndpoint(1);
|
|
356
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genIdentify', 'genOnOff', 'haElectricalMeasurement']);
|
|
357
|
+
await reporting.onOff(endpoint);
|
|
358
|
+
await reporting.readEletricalMeasurementMultiplierDivisors(endpoint);
|
|
359
|
+
await reporting.activePower(endpoint);
|
|
360
|
+
},
|
|
361
|
+
},
|
|
344
362
|
];
|
package/devices/lidl.js
CHANGED
|
@@ -507,6 +507,17 @@ module.exports = [
|
|
|
507
507
|
device.getEndpoint(1).saveClusterAttributeKeyValue('lightingColorCtrl', {colorCapabilities: 29});
|
|
508
508
|
},
|
|
509
509
|
},
|
|
510
|
+
{
|
|
511
|
+
fingerprint: [{modelID: 'TS0505B', manufacturerName: '_TZ3210_z1vlyufu'}],
|
|
512
|
+
model: '14158704L',
|
|
513
|
+
vendor: 'Lidl',
|
|
514
|
+
description: 'Livarno Home LED floor lamp, RGBW',
|
|
515
|
+
...extend.light_onoff_brightness_colortemp_color({disableColorTempStartup: true, colorTempRange: [153, 500]}),
|
|
516
|
+
meta: {applyRedFix: true, enhancedHue: false},
|
|
517
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
518
|
+
device.getEndpoint(1).saveClusterAttributeKeyValue('lightingColorCtrl', {colorCapabilities: 29});
|
|
519
|
+
},
|
|
520
|
+
},
|
|
510
521
|
{
|
|
511
522
|
fingerprint: [{modelID: 'TS0505B', manufacturerName: '_TZ3000_quqaeew6'}],
|
|
512
523
|
model: 'HG07834A',
|
package/devices/moes.js
CHANGED
|
@@ -99,6 +99,7 @@ module.exports = [
|
|
|
99
99
|
{
|
|
100
100
|
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_aoclfnxz'},
|
|
101
101
|
{modelID: 'TS0601', manufacturerName: '_TZE200_ztvwu4nk'},
|
|
102
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_ye5jkfsb'},
|
|
102
103
|
{modelID: 'TS0601', manufacturerName: '_TZE200_u9bfwha0'}],
|
|
103
104
|
model: 'BHT-002-GCLZB',
|
|
104
105
|
vendor: 'Moes',
|
package/devices/niko.js
CHANGED
|
@@ -5,6 +5,60 @@ const reporting = require('../lib/reporting');
|
|
|
5
5
|
const e = exposes.presets;
|
|
6
6
|
const ea = exposes.access;
|
|
7
7
|
|
|
8
|
+
const fzLocal = {
|
|
9
|
+
fz: {
|
|
10
|
+
switch_operation_mode: {
|
|
11
|
+
cluster: 'manuSpecificNikoSwitchSetup',
|
|
12
|
+
type: ['attributeReport', 'readResponse'],
|
|
13
|
+
convert: (model, msg, publish, options, meta) => {
|
|
14
|
+
const state = {};
|
|
15
|
+
if (msg.data.hasOwnProperty('operationMode')) {
|
|
16
|
+
const operationModeProperty = `operation_mode${meta.endpoint_name ? `_${meta.endpoint_name}` : ''}`;
|
|
17
|
+
const operationModeMap = {0x02: 'control_relay', 0x01: 'decoupled', 0x00: 'unknown'};
|
|
18
|
+
state[operationModeProperty] = operationModeMap[msg.data.operationMode];
|
|
19
|
+
}
|
|
20
|
+
return state;
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
switch_action: {
|
|
24
|
+
cluster: 'manuSpecificNikoSwitch',
|
|
25
|
+
type: ['attributeReport', 'readResponse'],
|
|
26
|
+
convert: (model, msg, publish, options, meta) => {
|
|
27
|
+
const state = {};
|
|
28
|
+
|
|
29
|
+
if (msg.data.hasOwnProperty('action')) {
|
|
30
|
+
// NOTE: a single press = two seperate values reported, 16 followed by 64
|
|
31
|
+
// a hold/release cyle = three seperate values, 16, 32, and 48
|
|
32
|
+
const actionProperty = `action${meta.endpoint_name ? `_${meta.endpoint_name}` : ''}`;
|
|
33
|
+
const actionMap = {16: null, 64: 'single', 32: 'hold', 48: 'release'};
|
|
34
|
+
state[actionProperty] = actionMap[msg.data.action];
|
|
35
|
+
}
|
|
36
|
+
return state;
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
tz: {
|
|
41
|
+
switch_operation_mode: {
|
|
42
|
+
key: ['operation_mode'],
|
|
43
|
+
convertSet: async (entity, key, value, meta) => {
|
|
44
|
+
// WARN: while we can technically write 0x00 to the operationMode attribute
|
|
45
|
+
// this seems to brick the device and it will need to be rejoined
|
|
46
|
+
const operationModeLookup = {control_relay: 0x02, decoupled: 0x01};
|
|
47
|
+
if (!operationModeLookup.hasOwnProperty(value)) {
|
|
48
|
+
throw new Error(`operation_mode was called with an invalid value (${value})`);
|
|
49
|
+
} else {
|
|
50
|
+
const operationModeProperty = `operation_mode${meta.endpoint_name ? `_${meta.endpoint_name}` : ''}`;
|
|
51
|
+
await entity.write('manuSpecificNikoSwitchSetup', {'operationMode': operationModeLookup[value]});
|
|
52
|
+
return {state: {[operationModeProperty]: value.toLowerCase()}};
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
convertGet: async (entity, key, meta) => {
|
|
56
|
+
await entity.read('manuSpecificNikoSwitchSetup', ['operationMode']);
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
8
62
|
module.exports = [
|
|
9
63
|
{
|
|
10
64
|
zigbeeModel: ['Connected socket outlet'],
|
|
@@ -80,15 +134,18 @@ module.exports = [
|
|
|
80
134
|
model: '552-721X1',
|
|
81
135
|
vendor: 'Niko',
|
|
82
136
|
description: 'Single connectable switch',
|
|
83
|
-
fromZigbee: [fz.on_off],
|
|
84
|
-
toZigbee: [tz.on_off],
|
|
137
|
+
fromZigbee: [fz.on_off, fzLocal.fz.switch_operation_mode, fzLocal.fz.switch_action],
|
|
138
|
+
toZigbee: [tz.on_off, fzLocal.tz.switch_operation_mode],
|
|
85
139
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
86
140
|
const endpoint = device.getEndpoint(1);
|
|
87
141
|
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff']);
|
|
88
142
|
await reporting.onOff(endpoint);
|
|
143
|
+
await endpoint.read('manuSpecificNikoSwitchSetup', ['operationMode']);
|
|
89
144
|
},
|
|
90
145
|
exposes: [
|
|
91
146
|
e.switch(),
|
|
147
|
+
e.action(['single', 'hold', 'release']),
|
|
148
|
+
exposes.enum('operation_mode', ea.ALL, ['control_relay', 'decoupled']),
|
|
92
149
|
],
|
|
93
150
|
},
|
|
94
151
|
{
|
|
@@ -96,8 +153,8 @@ module.exports = [
|
|
|
96
153
|
model: '552-721X2',
|
|
97
154
|
vendor: 'Niko',
|
|
98
155
|
description: 'Double connectable switch',
|
|
99
|
-
fromZigbee: [fz.on_off],
|
|
100
|
-
toZigbee: [tz.on_off],
|
|
156
|
+
fromZigbee: [fz.on_off, fzLocal.fz.switch_operation_mode, fzLocal.fz.switch_action],
|
|
157
|
+
toZigbee: [tz.on_off, fzLocal.tz.switch_operation_mode],
|
|
101
158
|
endpoint: (device) => {
|
|
102
159
|
return {'l1': 1, 'l2': 2};
|
|
103
160
|
},
|
|
@@ -109,9 +166,15 @@ module.exports = [
|
|
|
109
166
|
await reporting.bind(ep2, coordinatorEndpoint, ['genOnOff']);
|
|
110
167
|
await reporting.onOff(ep1);
|
|
111
168
|
await reporting.onOff(ep2);
|
|
169
|
+
await ep1.read('manuSpecificNikoSwitchSetup', ['operationMode']);
|
|
170
|
+
await ep2.read('manuSpecificNikoSwitchSetup', ['operationMode']);
|
|
112
171
|
},
|
|
113
172
|
exposes: [
|
|
114
173
|
e.switch().withEndpoint('l1'), e.switch().withEndpoint('l2'),
|
|
174
|
+
e.action(['single', 'hold', 'release']).withEndpoint('l1'),
|
|
175
|
+
e.action(['single', 'hold', 'release']).withEndpoint('l2'),
|
|
176
|
+
exposes.enum('operation_mode', ea.ALL, ['control_relay', 'decoupled']).withEndpoint('l1'),
|
|
177
|
+
exposes.enum('operation_mode', ea.ALL, ['control_relay', 'decoupled']).withEndpoint('l2'),
|
|
115
178
|
],
|
|
116
179
|
},
|
|
117
180
|
];
|
package/devices/orvibo.js
CHANGED
package/devices/paul_neuhaus.js
CHANGED
|
@@ -43,7 +43,7 @@ module.exports = [
|
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
45
|
zigbeeModel: ['NLG-RGBW light'],
|
|
46
|
-
model: 'NLG-
|
|
46
|
+
model: 'NLG-RGBW__light',
|
|
47
47
|
vendor: 'Paul Neuhaus',
|
|
48
48
|
description: 'Various RGBW lights (e.g. 100.111.57)',
|
|
49
49
|
extend: extend.light_onoff_brightness_colortemp_color(),
|
package/devices/philips.js
CHANGED
|
@@ -2714,6 +2714,15 @@ module.exports = [
|
|
|
2714
2714
|
meta: {turnsOffAtBrightness1: true},
|
|
2715
2715
|
ota: ota.zigbeeOTA,
|
|
2716
2716
|
},
|
|
2717
|
+
{
|
|
2718
|
+
zigbeeModel: ['5060930P7_01', '5060930P7_02', '5060930P7_03', '5060930P7_04'],
|
|
2719
|
+
model: '5060930P7',
|
|
2720
|
+
vendor: 'Philips',
|
|
2721
|
+
description: 'Hue White & Color Ambiance Centris ceiling light (3 spots)',
|
|
2722
|
+
extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
|
|
2723
|
+
meta: {turnsOffAtBrightness1: true},
|
|
2724
|
+
ota: ota.zigbeeOTA,
|
|
2725
|
+
},
|
|
2717
2726
|
{
|
|
2718
2727
|
zigbeeModel: ['5060931P7_01', '5060931P7_02', '5060931P7_03', '5060931P7_04'],
|
|
2719
2728
|
model: '5060931P7',
|
package/devices/spotmau.js
CHANGED
|
@@ -10,6 +10,9 @@ module.exports = [
|
|
|
10
10
|
vendor: 'Spotmau',
|
|
11
11
|
description: 'Smart wall switch - 1 gang',
|
|
12
12
|
extend: extend.switch(),
|
|
13
|
+
endpoint: (device) => {
|
|
14
|
+
return {default: 16};
|
|
15
|
+
},
|
|
13
16
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
14
17
|
await reporting.bind(device.getEndpoint(16), coordinatorEndpoint, ['genOnOff', 'genBasic']);
|
|
15
18
|
},
|
package/devices/tuya.js
CHANGED
|
@@ -450,7 +450,9 @@ module.exports = [
|
|
|
450
450
|
const endpoint = device.getEndpoint(1);
|
|
451
451
|
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'genLevelCtrl']);
|
|
452
452
|
},
|
|
453
|
-
exposes: [e.light_brightness().
|
|
453
|
+
exposes: [e.light_brightness().withMinBrightness().withMaxBrightness().setAccess(
|
|
454
|
+
'state', ea.STATE_SET).setAccess('brightness', ea.STATE_SET).setAccess(
|
|
455
|
+
'min_brightness', ea.STATE_SET).setAccess('max_brightness', ea.STATE_SET)],
|
|
454
456
|
whiteLabel: [
|
|
455
457
|
{vendor: 'Larkkey', model: 'ZSTY-SM-1DMZG-EU'},
|
|
456
458
|
{vendor: 'Earda', model: 'EDM-1ZAA-EU'},
|
|
@@ -703,10 +705,7 @@ module.exports = [
|
|
|
703
705
|
extend: extend.light_onoff_brightness_colortemp_color(),
|
|
704
706
|
},
|
|
705
707
|
{
|
|
706
|
-
fingerprint: [
|
|
707
|
-
{type: 'EndDevice', manufacturerID: 4098, endpoints: [{ID: 1, inputClusters: [], outputClusters: []}]},
|
|
708
|
-
{manufacturerName: '_TZ2000_a476raq2'},
|
|
709
|
-
],
|
|
708
|
+
fingerprint: [{manufacturerName: '_TZ2000_a476raq2'}],
|
|
710
709
|
zigbeeModel: ['TS0201', 'SNTZ003'],
|
|
711
710
|
model: 'TS0201',
|
|
712
711
|
vendor: 'TuYa',
|
|
@@ -715,6 +714,10 @@ module.exports = [
|
|
|
715
714
|
fromZigbee: [fzLocal.TS0201_battery, fz.temperature, fz.humidity],
|
|
716
715
|
toZigbee: [],
|
|
717
716
|
exposes: [e.battery(), e.temperature(), e.humidity(), e.battery_voltage()],
|
|
717
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
718
|
+
const endpoint = device.getEndpoint(1);
|
|
719
|
+
await endpoint.read('genBasic', ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
|
|
720
|
+
},
|
|
718
721
|
},
|
|
719
722
|
{
|
|
720
723
|
fingerprint: [{modelID: 'TS0201', manufacturerName: '_TZ3000_bguser20'}],
|
|
@@ -1045,6 +1048,7 @@ module.exports = [
|
|
|
1045
1048
|
{modelID: 'TS0601', manufacturerName: '_TZE200_3i3exuay'},
|
|
1046
1049
|
{modelID: 'TS0601', manufacturerName: '_TZE200_tvrvdj6o'},
|
|
1047
1050
|
{modelID: 'zo2pocs\u0000', manufacturerName: '_TYST11_fzo2pocs'},
|
|
1051
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_cf1sl3tj'},
|
|
1048
1052
|
// Roller blinds:
|
|
1049
1053
|
{modelID: 'TS0601', manufacturerName: '_TZE200_sbordckq'},
|
|
1050
1054
|
{modelID: 'TS0601', manufacturerName: '_TZE200_fctwhugx'},
|
|
@@ -1073,6 +1077,7 @@ module.exports = [
|
|
|
1073
1077
|
{vendor: 'TuYa', model: 'ZD82TN', description: 'Curtain motor'},
|
|
1074
1078
|
{vendor: 'Moes', model: 'AM43-0.45/40-ES-EB'},
|
|
1075
1079
|
{vendor: 'Larkkey', model: 'ZSTY-SM-1SRZG-EU'},
|
|
1080
|
+
{vendor: 'Zemismart', model: 'ZM85EL-2Z', description: 'Roman Rod I type curtains track'},
|
|
1076
1081
|
{vendor: 'Zemismart', model: 'ZM25TQ', description: 'Tubular motor'},
|
|
1077
1082
|
{vendor: 'Zemismart', model: 'AM43', description: 'Roller blind motor'},
|
|
1078
1083
|
{vendor: 'Zemismart', model: 'M2805EGBZTN', description: 'Tubular motor'},
|
|
@@ -1100,6 +1105,7 @@ module.exports = [
|
|
|
1100
1105
|
{modelID: 'TS0601', manufacturerName: '_TZE200_9sfg7gm0'}, // HomeCloud
|
|
1101
1106
|
{modelID: 'TS0601', manufacturerName: '_TZE200_2atgpdho'}, // HY367
|
|
1102
1107
|
{modelID: 'TS0601', manufacturerName: '_TZE200_cpmgn2cf'},
|
|
1108
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_4eeyebrt'}, // Immax 07732B
|
|
1103
1109
|
],
|
|
1104
1110
|
model: 'TS0601_thermostat',
|
|
1105
1111
|
vendor: 'TuYa',
|
|
@@ -1109,6 +1115,7 @@ module.exports = [
|
|
|
1109
1115
|
{vendor: 'Moes', model: 'HY369RT'},
|
|
1110
1116
|
{vendor: 'SHOJZJ', model: '378RT'},
|
|
1111
1117
|
{vendor: 'Silvercrest', model: 'TVR01'},
|
|
1118
|
+
{vendor: 'Immax', model: '07732B'},
|
|
1112
1119
|
],
|
|
1113
1120
|
meta: {tuyaThermostatPreset: tuya.thermostatPresets, tuyaThermostatSystemMode: tuya.thermostatSystemModes3},
|
|
1114
1121
|
ota: ota.zigbeeOTA,
|
|
@@ -1702,7 +1709,7 @@ module.exports = [
|
|
|
1702
1709
|
},
|
|
1703
1710
|
},
|
|
1704
1711
|
{
|
|
1705
|
-
zigbeeModel: ['HY0017', '
|
|
1712
|
+
zigbeeModel: ['HY0017', '005f0c3b'],
|
|
1706
1713
|
model: 'U86KCJ-ZP',
|
|
1707
1714
|
vendor: 'TuYa',
|
|
1708
1715
|
description: 'Smart 6 key scene wall switch',
|
|
@@ -2176,7 +2183,8 @@ module.exports = [
|
|
|
2176
2183
|
exposes: [e.illuminance_lux(), e.brightness_state()],
|
|
2177
2184
|
},
|
|
2178
2185
|
{
|
|
2179
|
-
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_kltffuzl'}, {modelID: 'TS0601', manufacturerName: '_TZE200_fwoorn8y'}
|
|
2186
|
+
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_kltffuzl'}, {modelID: 'TS0601', manufacturerName: '_TZE200_fwoorn8y'},
|
|
2187
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_pay2byax'}],
|
|
2180
2188
|
model: 'TM001-ZA/TM081',
|
|
2181
2189
|
vendor: 'TuYa',
|
|
2182
2190
|
description: 'Door and window sensor',
|
package/devices/xiaomi.js
CHANGED
|
@@ -1170,9 +1170,9 @@ module.exports = [
|
|
|
1170
1170
|
vendor: 'Xiaomi',
|
|
1171
1171
|
description: 'Aqara smart natural gas detector',
|
|
1172
1172
|
fromZigbee: [fz.aqara_opple],
|
|
1173
|
-
toZigbee: [tz.
|
|
1174
|
-
tz.
|
|
1175
|
-
exposes: [e.gas().withAccess(ea.STATE_GET),
|
|
1173
|
+
toZigbee: [tz.aqara_alarm, tz.aqara_density, tz.JTBZ01AQA_gas_sensitivity, tz.aqara_selftest, tz.aqara_mute_buzzer,
|
|
1174
|
+
tz.aqara_mute, tz.aqara_linkage_alarm, tz.JTBZ01AQA_state, tz.aqara_power_outage_count],
|
|
1175
|
+
exposes: [e.gas().withAccess(ea.STATE_GET),
|
|
1176
1176
|
exposes.numeric('gas_density', ea.STATE_GET).withUnit('%LEL').withDescription('Value of gas concentration'),
|
|
1177
1177
|
exposes.enum('gas_sensitivity', ea.ALL, ['10%LEL', '15%LEL']).withDescription('Gas concentration value at which ' +
|
|
1178
1178
|
'an alarm is triggered ("10%LEL" is more sensitive than "15%LEL")'),
|
|
@@ -1186,7 +1186,7 @@ module.exports = [
|
|
|
1186
1186
|
'is detected, other detectors with this option enabled will also sound the alarm buzzer'),
|
|
1187
1187
|
exposes.binary('state', ea.STATE_GET, 'preparation', 'work').withDescription('"Preparation" or "work" ' +
|
|
1188
1188
|
'(measurement of the gas concentration value and triggering of an alarm are only performed in the "work" state)'),
|
|
1189
|
-
|
|
1189
|
+
e.power_outage_count().withAccess(ea.STATE_GET)],
|
|
1190
1190
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
1191
1191
|
const endpoint = device.getEndpoint(1);
|
|
1192
1192
|
await endpoint.read('aqaraOpple', [0x013a], {manufacturerCode: 0x115f});
|
|
@@ -1199,6 +1199,40 @@ module.exports = [
|
|
|
1199
1199
|
},
|
|
1200
1200
|
ota: ota.zigbeeOTA,
|
|
1201
1201
|
},
|
|
1202
|
+
{
|
|
1203
|
+
zigbeeModel: ['lumi.sensor_smoke.acn03'],
|
|
1204
|
+
model: 'JY-GZ-01AQ',
|
|
1205
|
+
vendor: 'Xiaomi',
|
|
1206
|
+
description: 'Aqara smart smoke detector',
|
|
1207
|
+
fromZigbee: [fz.aqara_opple, fz.battery],
|
|
1208
|
+
toZigbee: [tz.aqara_alarm, tz.aqara_density, tz.aqara_selftest, tz.aqara_mute_buzzer, tz.aqara_mute,
|
|
1209
|
+
tz.JYGZ01AQ_heartbeat_indicator, tz.aqara_linkage_alarm],
|
|
1210
|
+
exposes: [e.smoke().withAccess(ea.STATE_GET),
|
|
1211
|
+
exposes.numeric('smoke_density', ea.STATE_GET).withDescription('Value of smoke concentration'),
|
|
1212
|
+
exposes.numeric('smoke_density_dbm', ea.STATE).withUnit('dB/m').withDescription('Value of smoke concentration in dB/m'),
|
|
1213
|
+
exposes.enum('selftest', ea.SET, ['Test']).withDescription('Starts the self-test process (checking the indicator ' +
|
|
1214
|
+
'light and buzzer work properly)'),
|
|
1215
|
+
exposes.binary('test', ea.STATE, true, false).withDescription('Self-test in progress'),
|
|
1216
|
+
exposes.enum('mute_buzzer', ea.SET, ['Mute']).withDescription('Mute the buzzer for 80 seconds (buzzer cannot be ' +
|
|
1217
|
+
'pre-muted, because this function only works when the alarm is triggered)'),
|
|
1218
|
+
exposes.binary('mute', ea.STATE_GET, true, false).withDescription('Buzzer muted'),
|
|
1219
|
+
exposes.binary('heartbeat_indicator', ea.ALL, true, false).withDescription('When this option is enabled then in ' +
|
|
1220
|
+
'the normal monitoring state, the green indicator light flashes every 60 seconds'),
|
|
1221
|
+
exposes.binary('linkage_alarm', ea.ALL, true, false).withDescription('When this option is enabled and a smoke ' +
|
|
1222
|
+
'is detected, other detectors with this option enabled will also sound the alarm buzzer'),
|
|
1223
|
+
e.temperature(), e.battery()],
|
|
1224
|
+
meta: {battery: {voltageToPercentage: '3V_2850_3000_log'}},
|
|
1225
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
1226
|
+
const endpoint = device.getEndpoint(1);
|
|
1227
|
+
await endpoint.read('genPowerCfg', ['batteryVoltage']);
|
|
1228
|
+
await endpoint.read('aqaraOpple', [0x013a], {manufacturerCode: 0x115f});
|
|
1229
|
+
await endpoint.read('aqaraOpple', [0x013b], {manufacturerCode: 0x115f});
|
|
1230
|
+
await endpoint.read('aqaraOpple', [0x013c], {manufacturerCode: 0x115f});
|
|
1231
|
+
await endpoint.read('aqaraOpple', [0x0126], {manufacturerCode: 0x115f});
|
|
1232
|
+
await endpoint.read('aqaraOpple', [0x014b], {manufacturerCode: 0x115f});
|
|
1233
|
+
},
|
|
1234
|
+
ota: ota.zigbeeOTA,
|
|
1235
|
+
},
|
|
1202
1236
|
{
|
|
1203
1237
|
zigbeeModel: ['lumi.lock.v1'],
|
|
1204
1238
|
model: 'A6121',
|
package/lib/exposes.js
CHANGED
|
@@ -218,6 +218,12 @@ class Light extends Base {
|
|
|
218
218
|
return this;
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
+
withMaxBrightness() {
|
|
222
|
+
assert(!this.endpoint, 'Cannot add feature after adding endpoint');
|
|
223
|
+
this.features.push(new Numeric('max_brightness', access.ALL).withValueMin(1).withValueMax(255).withDescription('Maximum light brightness'));
|
|
224
|
+
return this;
|
|
225
|
+
}
|
|
226
|
+
|
|
221
227
|
withLevelConfig() {
|
|
222
228
|
assert(!this.endpoint, 'Cannot add feature after adding endpoint');
|
|
223
229
|
const levelConfig = new Composite('level_config', 'level_config')
|
package/lib/tuya.js
CHANGED
|
@@ -58,6 +58,61 @@ function getDataValue(dpValue) {
|
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
function getTypeName(dpValue) {
|
|
62
|
+
const entry = Object.entries(dataTypes).find(([typeName, typeId]) => typeId === dpValue.datatype);
|
|
63
|
+
return (entry ? entry[0] : 'unknown');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function getDataPointNames(dpValue) {
|
|
67
|
+
const entries = Object.entries(dataPoints).filter(([dpName, dpId]) => dpId === dpValue.dp);
|
|
68
|
+
return entries.map(([dpName, dpId]) => dpName);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function logDataPoint(where, msg, dpValue, meta) {
|
|
72
|
+
meta.logger.info(`zigbee-herdsman-converters:${where}: Received Tuya DataPoint #${
|
|
73
|
+
dpValue.dp} from ${meta.device.ieeeAddr} with raw data '${JSON.stringify(dpValue)}': type='${
|
|
74
|
+
msg.type}', datatype='${getTypeName(dpValue)}', value='${
|
|
75
|
+
getDataValue(dpValue)}', known DP# usage: ${JSON.stringify(getDataPointNames(dpValue))}`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function logUnexpectedDataPoint(where, msg, dpValue, meta) {
|
|
79
|
+
meta.logger.warn(`zigbee-herdsman-converters:${where}: Received unexpected Tuya DataPoint #${
|
|
80
|
+
dpValue.dp} from ${meta.device.ieeeAddr} with raw data '${JSON.stringify(dpValue)}': type='${
|
|
81
|
+
msg.type}', datatype='${getTypeName(dpValue)}', value='${
|
|
82
|
+
getDataValue(dpValue)}', known DP# usage: ${JSON.stringify(getDataPointNames(dpValue))}`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function logUnexpectedDataType(where, msg, dpValue, meta, expectedDataType) {
|
|
86
|
+
meta.logger.warn(`zigbee-herdsman-converters:${where}: Received Tuya DataPoint #${
|
|
87
|
+
dpValue.dp} with unexpected datatype from ${meta.device.ieeeAddr} with raw data '${
|
|
88
|
+
JSON.stringify(dpValue)}': type='${msg.type}', datatype='${
|
|
89
|
+
getTypeName(dpValue)}' (instead of '${expectedDataType}'), value='${
|
|
90
|
+
getDataValue(dpValue)}', known DP# usage: ${JSON.stringify(getDataPointNames(dpValue))}`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function logUnexpectedDataValue(where, msg, dpValue, meta, valueKind, expectedMinValue=null, expectedMaxValue=null) {
|
|
94
|
+
if (expectedMinValue === null) {
|
|
95
|
+
if (expectedMaxValue === null) {
|
|
96
|
+
meta.logger.warn(`zigbee-herdsman-converters:${where}: Received Tuya DataPoint #${dpValue.dp
|
|
97
|
+
} with invalid value ${getDataValue(dpValue)} for ${valueKind} from ${meta.device.ieeeAddr}`);
|
|
98
|
+
} else {
|
|
99
|
+
meta.logger.warn(`zigbee-herdsman-converters:${where}: Received Tuya DataPoint #${dpValue.dp
|
|
100
|
+
} with invalid value ${getDataValue(dpValue)} for ${valueKind} from ${meta.device.ieeeAddr
|
|
101
|
+
} which is higher than the expected maximum of ${expectedMaxValue}`);
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
if (expectedMaxValue === null) {
|
|
105
|
+
meta.logger.warn(`zigbee-herdsman-converters:${where}: Received Tuya DataPoint #${dpValue.dp
|
|
106
|
+
} with invalid value ${getDataValue(dpValue)} for ${valueKind} from ${meta.device.ieeeAddr
|
|
107
|
+
} which is lower than the expected minimum of ${expectedMinValue}`);
|
|
108
|
+
} else {
|
|
109
|
+
meta.logger.warn(`zigbee-herdsman-converters:${where}: Received Tuya DataPoint #${dpValue.dp
|
|
110
|
+
} with invalid value ${getDataValue(dpValue)} for ${valueKind} from ${meta.device.ieeeAddr
|
|
111
|
+
} which is outside the expected range from ${expectedMinValue} to ${expectedMaxValue}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
61
116
|
function convertDecimalValueTo4ByteHexArray(value) {
|
|
62
117
|
const hexValue = Number(value).toString(16).padStart(8, '0');
|
|
63
118
|
const chunk1 = hexValue.substr(0, 2);
|
|
@@ -229,11 +284,13 @@ const dataPoints = {
|
|
|
229
284
|
heatingSetpoint: 2,
|
|
230
285
|
coverPosition: 2,
|
|
231
286
|
dimmerLevel: 3,
|
|
287
|
+
dimmerMinLevel: 3,
|
|
232
288
|
localTemp: 3,
|
|
233
289
|
coverArrived: 3,
|
|
234
290
|
occupancy: 3,
|
|
235
291
|
mode: 4,
|
|
236
292
|
fanMode: 5,
|
|
293
|
+
dimmerMaxLevel: 5,
|
|
237
294
|
motorDirection: 5,
|
|
238
295
|
config: 5,
|
|
239
296
|
childLock: 7,
|
|
@@ -873,6 +930,12 @@ module.exports = {
|
|
|
873
930
|
sendDataPointStringBuffer,
|
|
874
931
|
firstDpValue,
|
|
875
932
|
getDataValue,
|
|
933
|
+
getTypeName,
|
|
934
|
+
getDataPointNames,
|
|
935
|
+
logDataPoint,
|
|
936
|
+
logUnexpectedDataPoint,
|
|
937
|
+
logUnexpectedDataType,
|
|
938
|
+
logUnexpectedDataValue,
|
|
876
939
|
dataTypes,
|
|
877
940
|
dataPoints,
|
|
878
941
|
dpValueFromIntValue,
|
package/lib/xiaomi.js
CHANGED
|
@@ -174,9 +174,11 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
|
|
|
174
174
|
payload.switch_type = {1: 'toggle', 2: 'momentary'}[value];
|
|
175
175
|
break;
|
|
176
176
|
case '11':
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
177
|
+
if (!['JT-BZ-01AQ/A'].includes(model.model)) {
|
|
178
|
+
payload.illuminance = calibrateAndPrecisionRoundOptions(value, options, 'illuminance');
|
|
179
|
+
// DEPRECATED: remove illuminance_lux here.
|
|
180
|
+
payload.illuminance_lux = calibrateAndPrecisionRoundOptions(value, options, 'illuminance_lux');
|
|
181
|
+
}
|
|
180
182
|
break;
|
|
181
183
|
case '100':
|
|
182
184
|
if (['QBKG20LM', 'QBKG31LM', 'QBKG39LM', 'QBKG41LM', 'QBCZ15LM', 'LLKZMK11LM', 'QBKG12LM', 'QBKG03LM'].includes(model.model)) {
|
|
@@ -300,25 +302,52 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
|
|
|
300
302
|
}
|
|
301
303
|
break;
|
|
302
304
|
case '159':
|
|
303
|
-
|
|
305
|
+
if (['JT-BZ-01AQ/A'].includes(model.model)) {
|
|
306
|
+
payload.gas_sensitivity = {1: '15%LEL', 2: '10%LEL'}[value];
|
|
307
|
+
}
|
|
304
308
|
break;
|
|
305
309
|
case '160':
|
|
306
|
-
|
|
310
|
+
if (['JT-BZ-01AQ/A'].includes(model.model)) {
|
|
311
|
+
payload.gas = value === 1;
|
|
312
|
+
} else if (['JY-GZ-01AQ'].includes(model.model)) {
|
|
313
|
+
payload.smoke = value === 1;
|
|
314
|
+
}
|
|
307
315
|
break;
|
|
308
316
|
case '161':
|
|
309
|
-
|
|
317
|
+
if (['JT-BZ-01AQ/A'].includes(model.model)) {
|
|
318
|
+
payload.gas_density = value;
|
|
319
|
+
} else if (['JY-GZ-01AQ'].includes(model.model)) {
|
|
320
|
+
payload.smoke_density = value;
|
|
321
|
+
payload.smoke_density_dbm = {0: 0, 1: 0.085, 2: 0.088, 3: 0.093, 4: 0.095, 5: 0.100, 6: 0.105, 7: 0.110,
|
|
322
|
+
8: 0.115, 9: 0.120, 10: 0.125}[value];
|
|
323
|
+
}
|
|
310
324
|
break;
|
|
311
325
|
case '162':
|
|
312
|
-
|
|
326
|
+
if (['JT-BZ-01AQ/A', 'JY-GZ-01AQ'].includes(model.model)) {
|
|
327
|
+
payload.test = value === 1;
|
|
328
|
+
}
|
|
313
329
|
break;
|
|
314
330
|
case '163':
|
|
315
|
-
|
|
331
|
+
if (['JT-BZ-01AQ/A', 'JY-GZ-01AQ'].includes(model.model)) {
|
|
332
|
+
payload.mute = value === 1;
|
|
333
|
+
}
|
|
316
334
|
break;
|
|
317
335
|
case '164':
|
|
318
|
-
|
|
336
|
+
if (['JT-BZ-01AQ/A'].includes(model.model)) {
|
|
337
|
+
payload.state = {0: 'work', 1: 'preparation'}[value];
|
|
338
|
+
} else if (['JY-GZ-01AQ'].includes(model.model)) {
|
|
339
|
+
payload.heartbeat_indicator = value === 1;
|
|
340
|
+
}
|
|
341
|
+
break;
|
|
342
|
+
case '165':
|
|
343
|
+
if (['JY-GZ-01AQ'].includes(model.model)) {
|
|
344
|
+
payload.linkage_alarm = value === 1;
|
|
345
|
+
}
|
|
319
346
|
break;
|
|
320
347
|
case '166':
|
|
321
|
-
|
|
348
|
+
if (['JT-BZ-01AQ/A'].includes(model.model)) {
|
|
349
|
+
payload.linkage_alarm = value === 1;
|
|
350
|
+
}
|
|
322
351
|
break;
|
|
323
352
|
case '240':
|
|
324
353
|
payload.flip_indicator_light = value === 1 ? 'ON' : 'OFF';
|
|
@@ -344,19 +373,40 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
|
|
|
344
373
|
payload.click_mode = {1: 'fast', 2: 'multi'}[value];
|
|
345
374
|
break;
|
|
346
375
|
case '294':
|
|
347
|
-
|
|
376
|
+
if (['JT-BZ-01AQ/A', 'JY-GZ-01AQ'].includes(model.model)) {
|
|
377
|
+
payload.mute = value === 1;
|
|
378
|
+
}
|
|
348
379
|
break;
|
|
349
380
|
case '295':
|
|
350
|
-
|
|
381
|
+
if (['JT-BZ-01AQ/A', 'JY-GZ-01AQ'].includes(model.model)) {
|
|
382
|
+
payload.test = value === 1;
|
|
383
|
+
}
|
|
351
384
|
break;
|
|
352
385
|
case '313':
|
|
353
|
-
|
|
386
|
+
if (['JT-BZ-01AQ/A'].includes(model.model)) {
|
|
387
|
+
payload.state = {0: 'work', 1: 'preparation'}[value];
|
|
388
|
+
}
|
|
354
389
|
break;
|
|
355
390
|
case '314':
|
|
356
|
-
|
|
391
|
+
if (['JT-BZ-01AQ/A'].includes(model.model)) {
|
|
392
|
+
payload.gas = value === 1;
|
|
393
|
+
} else if (['JY-GZ-01AQ'].includes(model.model)) {
|
|
394
|
+
payload.smoke = value === 1;
|
|
395
|
+
}
|
|
357
396
|
break;
|
|
358
397
|
case '315':
|
|
359
|
-
|
|
398
|
+
if (['JT-BZ-01AQ/A'].includes(model.model)) {
|
|
399
|
+
payload.gas_density = value;
|
|
400
|
+
} else if (['JY-GZ-01AQ'].includes(model.model)) {
|
|
401
|
+
payload.smoke_density = value;
|
|
402
|
+
payload.smoke_density_dbm = {0: 0, 1: 0.085, 2: 0.088, 3: 0.093, 4: 0.095, 5: 0.100, 6: 0.105, 7: 0.110,
|
|
403
|
+
8: 0.115, 9: 0.120, 10: 0.125}[value];
|
|
404
|
+
}
|
|
405
|
+
break;
|
|
406
|
+
case '316':
|
|
407
|
+
if (['JY-GZ-01AQ'].includes(model.model)) {
|
|
408
|
+
payload.heartbeat_indicator = value === 1;
|
|
409
|
+
}
|
|
360
410
|
break;
|
|
361
411
|
case '322':
|
|
362
412
|
if (['RTCZCGQ11LM'].includes(model.model)) {
|
|
@@ -380,7 +430,9 @@ const numericAttributes2Payload = (msg, meta, model, options, dataObject) => {
|
|
|
380
430
|
}
|
|
381
431
|
break;
|
|
382
432
|
case '331':
|
|
383
|
-
|
|
433
|
+
if (['JT-BZ-01AQ/A', 'JY-GZ-01AQ'].includes(model.model)) {
|
|
434
|
+
payload.linkage_alarm = value === 1;
|
|
435
|
+
}
|
|
384
436
|
break;
|
|
385
437
|
case '512':
|
|
386
438
|
if (['ZNCZ15LM', 'QBCZ14LM', 'QBCZ15LM'].includes(model.model)) {
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zigbee-herdsman-converters",
|
|
3
|
-
"version": "14.0.
|
|
3
|
+
"version": "14.0.468",
|
|
4
4
|
"lockfileVersion": 2,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "zigbee-herdsman-converters",
|
|
9
|
-
"version": "14.0.
|
|
9
|
+
"version": "14.0.468",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"axios": "^0.26.1",
|