zigbee-herdsman-converters 14.0.382 → 14.0.386
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 +75 -0
- package/converters/toZigbee.js +27 -0
- package/devices/cleode.js +20 -0
- package/devices/gledopto.js +7 -0
- package/devices/ikea.js +1 -1
- package/devices/miboxer.js +4 -1
- package/devices/philips.js +18 -0
- package/devices/tubeszb.js +20 -0
- package/devices/tuya.js +5 -2
- package/devices/xiaomi.js +6 -10
- package/devices/zemismart.js +44 -0
- package/lib/ota/zigbeeOTA.js +36 -8
- package/lib/reporting.js +1 -1
- package/lib/tuya.js +49 -0
- package/npm-shrinkwrap.json +380 -396
- package/package.json +2 -2
package/converters/fromZigbee.js
CHANGED
|
@@ -7956,6 +7956,81 @@ const converters = {
|
|
|
7956
7956
|
return {action};
|
|
7957
7957
|
},
|
|
7958
7958
|
},
|
|
7959
|
+
ZMAM02: {
|
|
7960
|
+
cluster: 'manuSpecificTuya',
|
|
7961
|
+
type: ['commandDataResponse', 'commandDataReport', 'commandSetDataresponse'],
|
|
7962
|
+
convert: (model, msg, publish, options, meta) => {
|
|
7963
|
+
const result = {};
|
|
7964
|
+
// let value = tuya.getDataValue(dpValue);
|
|
7965
|
+
// let result = null;
|
|
7966
|
+
for (const dpValue of msg.data.dpValues) {
|
|
7967
|
+
const value = tuya.getDataValue(dpValue);
|
|
7968
|
+
switch (dpValue.dp) {
|
|
7969
|
+
case tuya.dataPoints.AM02Control:
|
|
7970
|
+
result.control = tuya.ZMAM02.AM02Control[value];
|
|
7971
|
+
break;
|
|
7972
|
+
case tuya.dataPoints.AM02PercentControl:
|
|
7973
|
+
result.percent_control = value;
|
|
7974
|
+
break;
|
|
7975
|
+
case tuya.dataPoints.AM02ControlBackMode:
|
|
7976
|
+
result.control_back_mode = tuya.ZMAM02.AM02Direction[value];
|
|
7977
|
+
break;
|
|
7978
|
+
case tuya.dataPoints.AM02MotorWorkingMode:
|
|
7979
|
+
switch (value) {
|
|
7980
|
+
case 0: // continuous 1
|
|
7981
|
+
result.motor_working_mode = 'continuous';
|
|
7982
|
+
break;
|
|
7983
|
+
case 1: // intermittently
|
|
7984
|
+
result.motor_working_mode = 'intermittently';
|
|
7985
|
+
break;
|
|
7986
|
+
default:
|
|
7987
|
+
meta.logger.warn('zigbee-herdsman-converters:ZM_AM_02: ' +
|
|
7988
|
+
`Mode ${value} is not recognized.`);
|
|
7989
|
+
break;
|
|
7990
|
+
}
|
|
7991
|
+
break;
|
|
7992
|
+
case tuya.dataPoints.AM02Border:
|
|
7993
|
+
switch (value) {
|
|
7994
|
+
case 0: // up
|
|
7995
|
+
result.border = 'up';
|
|
7996
|
+
break;
|
|
7997
|
+
case 1: // down
|
|
7998
|
+
result.border = 'down';
|
|
7999
|
+
break;
|
|
8000
|
+
case 2: // down_delete
|
|
8001
|
+
result.border = 'down_delete';
|
|
8002
|
+
break;
|
|
8003
|
+
default:
|
|
8004
|
+
meta.logger.warn('zigbee-herdsman-converters:ZM_AM_02: ' +
|
|
8005
|
+
`Mode ${value} is not recognized.`);
|
|
8006
|
+
break;
|
|
8007
|
+
}
|
|
8008
|
+
break;
|
|
8009
|
+
case tuya.dataPoints.AM02PercentState:
|
|
8010
|
+
result.percent_state = value;
|
|
8011
|
+
break;
|
|
8012
|
+
case tuya.dataPoints.AM02Mode:
|
|
8013
|
+
switch (value) {
|
|
8014
|
+
case 0: // morning
|
|
8015
|
+
result.mode = 'morning';
|
|
8016
|
+
break;
|
|
8017
|
+
case 1: // night
|
|
8018
|
+
result.mode = 'night';
|
|
8019
|
+
break;
|
|
8020
|
+
default:
|
|
8021
|
+
meta.logger.warn('zigbee-herdsman-converters:ZM_AM_02: ' +
|
|
8022
|
+
`Mode ${value} is not recognized.`);
|
|
8023
|
+
break;
|
|
8024
|
+
}
|
|
8025
|
+
break;
|
|
8026
|
+
default:
|
|
8027
|
+
meta.logger.warn(`fromZigbee.Zemismart Shader Konverter (Zm_AM02): NOT RECOGNIZED ` +
|
|
8028
|
+
`DP #${dpValue.dp} with data ${JSON.stringify(dpValue)}`);
|
|
8029
|
+
}
|
|
8030
|
+
}
|
|
8031
|
+
return result;
|
|
8032
|
+
},
|
|
8033
|
+
},
|
|
7959
8034
|
// #endregion
|
|
7960
8035
|
|
|
7961
8036
|
// #region Ignore converters (these message dont need parsing).
|
package/converters/toZigbee.js
CHANGED
|
@@ -6592,6 +6592,33 @@ const converters = {
|
|
|
6592
6592
|
}
|
|
6593
6593
|
},
|
|
6594
6594
|
},
|
|
6595
|
+
ZMAM02: {
|
|
6596
|
+
key: ['control', 'percent_control', 'mode', 'control_back_mode', 'border', 'motor_working_mode'],
|
|
6597
|
+
convertSet: async (entity, key, value, meta) => {
|
|
6598
|
+
switch (key) {
|
|
6599
|
+
case 'control':
|
|
6600
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.AM02Control, utils.getKey(tuya.ZMAM02.AM02Control, value));
|
|
6601
|
+
break;
|
|
6602
|
+
case 'percent_control':
|
|
6603
|
+
await tuya.sendDataPointValue(entity, tuya.dataPoints.AM02PercentState, value);
|
|
6604
|
+
break;
|
|
6605
|
+
case 'mode':
|
|
6606
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.AM02Mode, utils.getKey(tuya.ZMAM02.AM02Mode, value));
|
|
6607
|
+
break;
|
|
6608
|
+
case 'control_back_mode':
|
|
6609
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.AM02ControlBackMode, utils.getKey(tuya.ZMAM02.AM02Direction, value));
|
|
6610
|
+
break;
|
|
6611
|
+
case 'border':
|
|
6612
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.AM02Border, utils.getKey(tuya.ZMAM02.AM02Border, value));
|
|
6613
|
+
break;
|
|
6614
|
+
case 'motor_working_mode':
|
|
6615
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.AM02MotorWorkingMode, utils.getKey(tuya.ZMAM02.AM02MotorMode, value));
|
|
6616
|
+
break;
|
|
6617
|
+
default: // Unknown Key
|
|
6618
|
+
meta.logger.warn(`toZigbee.ZMAM02: Unhandled Key ${key}`);
|
|
6619
|
+
}
|
|
6620
|
+
},
|
|
6621
|
+
},
|
|
6595
6622
|
// #endregion
|
|
6596
6623
|
|
|
6597
6624
|
// #region Ignore converters
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const exposes = require('../lib/exposes');
|
|
2
|
+
const reporting = require('../lib/reporting');
|
|
3
|
+
const e = exposes.presets;
|
|
4
|
+
const extend = require('../lib/extend');
|
|
5
|
+
|
|
6
|
+
module.exports = [
|
|
7
|
+
{
|
|
8
|
+
zigbeeModel: ['ZPLUG'],
|
|
9
|
+
model: 'ZPLUG_Boost',
|
|
10
|
+
vendor: 'CLEODE',
|
|
11
|
+
description: 'ZPlug boost',
|
|
12
|
+
extend: extend.switch(),
|
|
13
|
+
exposes: [e.switch(), e.power()],
|
|
14
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
15
|
+
const endpoint = device.getEndpoint(1);
|
|
16
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'seMetering']);
|
|
17
|
+
await reporting.readMeteringMultiplierDivisor(endpoint);
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
];
|
package/devices/gledopto.js
CHANGED
|
@@ -508,6 +508,13 @@ module.exports = [
|
|
|
508
508
|
description: 'Zigbee 10W Floodlight RGB+CCT',
|
|
509
509
|
extend: gledoptoExtend.light_onoff_brightness_colortemp_color(),
|
|
510
510
|
},
|
|
511
|
+
{
|
|
512
|
+
zigbeeModel: ['GL-B-003P'],
|
|
513
|
+
model: 'GL-B-003P',
|
|
514
|
+
vendor: 'Gledopto',
|
|
515
|
+
description: 'Zigbee 7W E26/E27 Bulb RGB+CCT (pro)',
|
|
516
|
+
extend: extend.light_onoff_brightness_colortemp({colorTempRange: [155, 495]}),
|
|
517
|
+
},
|
|
511
518
|
{
|
|
512
519
|
zigbeeModel: ['GL-FL-004TZS'],
|
|
513
520
|
model: 'GL-FL-004TZS',
|
package/devices/ikea.js
CHANGED
|
@@ -252,7 +252,7 @@ module.exports = [
|
|
|
252
252
|
extend: tradfriExtend.light_onoff_brightness_colortemp(),
|
|
253
253
|
},
|
|
254
254
|
{
|
|
255
|
-
zigbeeModel: ['TRADFRI bulb E27 WS clear 950lm', 'TRADFRI bulb E26 WS clear 950lm'],
|
|
255
|
+
zigbeeModel: ['TRADFRI bulb E27 WS clear 950lm', 'TRADFRI bulb E26 WS clear 950lm', 'TRADFRI bulb E27 WS\uFFFDclear 950lm'],
|
|
256
256
|
model: 'LED1546G12',
|
|
257
257
|
vendor: 'IKEA',
|
|
258
258
|
description: 'TRADFRI LED bulb E26/E27 950 lumen, dimmable, white spectrum, clear',
|
package/devices/miboxer.js
CHANGED
|
@@ -4,6 +4,7 @@ const tz = require('../converters/toZigbee');
|
|
|
4
4
|
const e = exposes.presets;
|
|
5
5
|
const ea = exposes.access;
|
|
6
6
|
const extend = require('../lib/extend');
|
|
7
|
+
const tuya = require('../lib/tuya');
|
|
7
8
|
|
|
8
9
|
module.exports = [
|
|
9
10
|
{
|
|
@@ -21,11 +22,13 @@ module.exports = [
|
|
|
21
22
|
],
|
|
22
23
|
},
|
|
23
24
|
{
|
|
24
|
-
fingerprint: [{modelID: 'TS0501B', manufacturerName: '_TZ3210_dxroobu3'}
|
|
25
|
+
fingerprint: [{modelID: 'TS0501B', manufacturerName: '_TZ3210_dxroobu3'},
|
|
26
|
+
{modelID: 'TS0501B', manufacturerName: '_TZ3210_dbilpfqk'}],
|
|
25
27
|
model: 'FUT036Z',
|
|
26
28
|
description: 'Single color LED controller',
|
|
27
29
|
vendor: 'Miboxer',
|
|
28
30
|
extend: extend.light_onoff_brightness(),
|
|
31
|
+
onEvent: tuya.onEventSetTime,
|
|
29
32
|
},
|
|
30
33
|
{
|
|
31
34
|
fingerprint: [{modelID: 'TS0502B', manufacturerName: '_TZ3210_frm6149r'}],
|
package/devices/philips.js
CHANGED
|
@@ -29,6 +29,15 @@ const hueExtend = {
|
|
|
29
29
|
};
|
|
30
30
|
|
|
31
31
|
module.exports = [
|
|
32
|
+
{
|
|
33
|
+
zigbeeModel: ['929003056901'],
|
|
34
|
+
model: '929003056901',
|
|
35
|
+
vendor: 'Philips',
|
|
36
|
+
description: 'Hue Struana 27W',
|
|
37
|
+
meta: {turnsOffAtBrightness1: true},
|
|
38
|
+
extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
|
|
39
|
+
ota: ota.zigbeeOTA,
|
|
40
|
+
},
|
|
32
41
|
{
|
|
33
42
|
zigbeeModel: ['LWA018'],
|
|
34
43
|
model: '9290024693',
|
|
@@ -1534,6 +1543,15 @@ module.exports = [
|
|
|
1534
1543
|
extend: hueExtend.light_onoff_brightness_colortemp_color(),
|
|
1535
1544
|
ota: ota.zigbeeOTA,
|
|
1536
1545
|
},
|
|
1546
|
+
{
|
|
1547
|
+
zigbeeModel: ['LCF003', '4080248P7'],
|
|
1548
|
+
model: '4080248P7',
|
|
1549
|
+
vendor: 'Philips',
|
|
1550
|
+
description: 'Hue Signe floor light',
|
|
1551
|
+
meta: {turnsOffAtBrightness1: true},
|
|
1552
|
+
extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
|
|
1553
|
+
ota: ota.zigbeeOTA,
|
|
1554
|
+
},
|
|
1537
1555
|
{
|
|
1538
1556
|
zigbeeModel: ['4080248U9'],
|
|
1539
1557
|
model: '4080248U9',
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const fz = {...require('../converters/fromZigbee'), legacy: require('../lib/legacy').fromZigbee};
|
|
2
|
+
const reporting = require('../lib/reporting');
|
|
3
|
+
|
|
4
|
+
module.exports = [
|
|
5
|
+
{
|
|
6
|
+
zigbeeModel: ['tubeszb.router'],
|
|
7
|
+
model: 'tubeszb.router',
|
|
8
|
+
vendor: 'TubesZB',
|
|
9
|
+
description: '[CC2652 Router](https://github.com/tube0013/tube_gateways/tree/main/tube_cc_router)',
|
|
10
|
+
fromZigbee: [fz.linkquality_from_basic],
|
|
11
|
+
toZigbee: [],
|
|
12
|
+
exposes: [],
|
|
13
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
14
|
+
const endpoint = device.getEndpoint(8);
|
|
15
|
+
const payload = [{attribute: 'zclVersion', minimumReportInterval: 0, maximumReportInterval: 3600, reportableChange: 0}];
|
|
16
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genBasic']);
|
|
17
|
+
await endpoint.configureReporting('genBasic', payload);
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
];
|
package/devices/tuya.js
CHANGED
|
@@ -163,6 +163,7 @@ module.exports = [
|
|
|
163
163
|
{modelID: 'TS0505B', manufacturerName: '_TZ3210_bicjqpg4'},
|
|
164
164
|
{modelID: 'TS0505B', manufacturerName: '_TZ3000_cmaky9gq'},
|
|
165
165
|
{modelID: 'TS0505B', manufacturerName: '_TZ3000_tza2vjxx'},
|
|
166
|
+
{modelID: 'TS0505B', manufacturerName: '_TZ3210_k1pe6ibm'},
|
|
166
167
|
{modelID: 'TS0505B', manufacturerName: '_TZ3210_bfwvfyx1'}],
|
|
167
168
|
model: 'TS0505B',
|
|
168
169
|
vendor: 'TuYa',
|
|
@@ -179,7 +180,8 @@ module.exports = [
|
|
|
179
180
|
fingerprint: [{modelID: 'TS0503B', manufacturerName: '_TZ3000_i8l0nqdu'},
|
|
180
181
|
{modelID: 'TS0503B', manufacturerName: '_TZ3210_a5fxguxr'},
|
|
181
182
|
{modelID: 'TS0503B', manufacturerName: '_TZ3210_778drfdt'},
|
|
182
|
-
{modelID: 'TS0503B', manufacturerName: '_TZ3000_g5xawfcq'}
|
|
183
|
+
{modelID: 'TS0503B', manufacturerName: '_TZ3000_g5xawfcq'},
|
|
184
|
+
{modelID: 'TS0503B', manufacturerName: '_TZ3210_trm3l2aw'}],
|
|
183
185
|
model: 'TS0503B',
|
|
184
186
|
vendor: 'TuYa',
|
|
185
187
|
description: 'Zigbee RGB light',
|
|
@@ -225,6 +227,7 @@ module.exports = [
|
|
|
225
227
|
{modelID: 'TS0202', manufacturerName: '_TZ3000_msl6wxk9'},
|
|
226
228
|
{modelID: 'TS0202', manufacturerName: '_TYZB01_tv3wxhcz'},
|
|
227
229
|
{modelID: 'TS0202', manufacturerName: '_TYZB01_hqbdru35'},
|
|
230
|
+
{modelID: 'TS0202', manufacturerName: '_TZ3000_tiwq83wk'},
|
|
228
231
|
{modelID: 'WHD02', manufacturerName: '_TZ3000_hktqahrq'}],
|
|
229
232
|
model: 'TS0202',
|
|
230
233
|
vendor: 'TuYa',
|
|
@@ -505,6 +508,7 @@ module.exports = [
|
|
|
505
508
|
{modelID: 'TS0502B', manufacturerName: '_TZ3210_psgq7ysz'},
|
|
506
509
|
{modelID: 'TS0502B', manufacturerName: '_TZ3000_zw7wr5uo'},
|
|
507
510
|
{modelID: 'TS0502B', manufacturerName: '_TZ3210_pz9zmxjj'},
|
|
511
|
+
{modelID: 'TS0502B', manufacturerName: '_TZ3000_fzwhym79'},
|
|
508
512
|
],
|
|
509
513
|
model: 'TS0502B',
|
|
510
514
|
vendor: 'TuYa',
|
|
@@ -841,7 +845,6 @@ module.exports = [
|
|
|
841
845
|
{modelID: 'TS0601', manufacturerName: '_TZE200_fzo2pocs'},
|
|
842
846
|
{modelID: 'TS0601', manufacturerName: '_TZE200_5sbebbzs'},
|
|
843
847
|
{modelID: 'TS0601', manufacturerName: '_TZE200_zuz7f94z'},
|
|
844
|
-
{modelID: 'TS0601', manufacturerName: '_TZE200_iossyxra'},
|
|
845
848
|
],
|
|
846
849
|
model: 'TS0601_cover',
|
|
847
850
|
vendor: 'TuYa',
|
package/devices/xiaomi.js
CHANGED
|
@@ -81,11 +81,11 @@ module.exports = [
|
|
|
81
81
|
model: 'ZNLDP12LM',
|
|
82
82
|
vendor: 'Xiaomi',
|
|
83
83
|
description: 'Aqara smart LED bulb',
|
|
84
|
-
toZigbee: xiaomiExtend.light_onoff_brightness_colortemp().toZigbee.concat([
|
|
84
|
+
toZigbee: xiaomiExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 370]}).toZigbee.concat([
|
|
85
85
|
tz.xiaomi_light_power_outage_memory]),
|
|
86
|
-
fromZigbee: xiaomiExtend.light_onoff_brightness_colortemp().fromZigbee,
|
|
86
|
+
fromZigbee: xiaomiExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 370]}).fromZigbee,
|
|
87
87
|
// power_on_behavior 'toggle' does not seem to be supported
|
|
88
|
-
exposes: xiaomiExtend.light_onoff_brightness_colortemp().exposes.concat([
|
|
88
|
+
exposes: xiaomiExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 370]}).exposes.concat([
|
|
89
89
|
e.power_outage_memory().withAccess(ea.STATE_SET)]),
|
|
90
90
|
ota: ota.zigbeeOTA,
|
|
91
91
|
},
|
|
@@ -1403,18 +1403,14 @@ module.exports = [
|
|
|
1403
1403
|
vendor: 'Xiaomi',
|
|
1404
1404
|
description: 'Aqara single switch module T1 (with neutral)',
|
|
1405
1405
|
// Ignore energy metering reports, rely on aqara_opple: https://github.com/Koenkk/zigbee2mqtt/issues/10709
|
|
1406
|
-
fromZigbee: [fz.on_off, fz.device_temperature, fz.aqara_opple, fz.ignore_metering, fz.ignore_electrical_measurement
|
|
1406
|
+
fromZigbee: [fz.on_off, fz.device_temperature, fz.aqara_opple, fz.ignore_metering, fz.ignore_electrical_measurement,
|
|
1407
|
+
fz.xiaomi_power],
|
|
1407
1408
|
exposes: [e.switch(), e.energy(), e.power(), e.device_temperature(), e.power_outage_memory(), e.switch_type()],
|
|
1408
1409
|
toZigbee: [tz.xiaomi_switch_type, tz.on_off, tz.xiaomi_switch_power_outage_memory],
|
|
1409
1410
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
1410
1411
|
const endpoint = device.getEndpoint(1);
|
|
1411
|
-
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', '
|
|
1412
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'genDeviceTempCfg']);
|
|
1412
1413
|
await reporting.onOff(endpoint);
|
|
1413
|
-
// Gives UNSUPPORTED_ATTRIBUTE on reporting.readEletricalMeasurementMultiplierDivisors.
|
|
1414
|
-
await endpoint.read('haElectricalMeasurement', ['acPowerMultiplier', 'acPowerDivisor']);
|
|
1415
|
-
await reporting.readMeteringMultiplierDivisor(endpoint);
|
|
1416
|
-
await reporting.currentSummDelivered(endpoint);
|
|
1417
|
-
await reporting.activePower(endpoint, {min: 5, max: 600, change: 10});
|
|
1418
1414
|
await reporting.deviceTemperature(endpoint);
|
|
1419
1415
|
device.powerSource = 'Mains (single phase)';
|
|
1420
1416
|
device.save();
|
package/devices/zemismart.js
CHANGED
|
@@ -5,6 +5,7 @@ const reporting = require('../lib/reporting');
|
|
|
5
5
|
const extend = require('../lib/extend');
|
|
6
6
|
const e = exposes.presets;
|
|
7
7
|
const tuya = require('../lib/tuya');
|
|
8
|
+
const ea = exposes.access;
|
|
8
9
|
|
|
9
10
|
const fzLocal = {
|
|
10
11
|
ZMRM02: {
|
|
@@ -102,4 +103,47 @@ module.exports = [
|
|
|
102
103
|
'button_5_hold', 'button_5_single', 'button_5_double',
|
|
103
104
|
'button_6_hold', 'button_6_single', 'button_6_double'])],
|
|
104
105
|
},
|
|
106
|
+
{
|
|
107
|
+
fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_zigisuyh'}],
|
|
108
|
+
model: 'ZIGBEE-B09-UK',
|
|
109
|
+
vendor: 'Zemismart',
|
|
110
|
+
description: 'Zigbee smart outlet universal socket with USB port',
|
|
111
|
+
fromZigbee: [fz.on_off, fz.tuya_switch_power_outage_memory],
|
|
112
|
+
toZigbee: [tz.on_off, tz.tuya_switch_power_outage_memory],
|
|
113
|
+
exposes: [e.switch().withEndpoint('l1'), e.switch().withEndpoint('l2'),
|
|
114
|
+
exposes.enum('power_outage_memory', ea.STATE_SET, ['on', 'off', 'restore'])
|
|
115
|
+
.withDescription('Recover state after power outage')],
|
|
116
|
+
endpoint: (device) => {
|
|
117
|
+
return {'l1': 1, 'l2': 2};
|
|
118
|
+
},
|
|
119
|
+
meta: {multiEndpoint: true},
|
|
120
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
121
|
+
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ['genOnOff']);
|
|
122
|
+
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ['genOnOff']);
|
|
123
|
+
await reporting.onOff(device.getEndpoint(1));
|
|
124
|
+
await reporting.onOff(device.getEndpoint(2));
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_iossyxra'}],
|
|
129
|
+
model: 'ZM-AM02',
|
|
130
|
+
vendor: 'Zemismart',
|
|
131
|
+
description: 'Zigbee/RF curtain converter',
|
|
132
|
+
fromZigbee: [fz.ZMAM02],
|
|
133
|
+
toZigbee: [tz.ZMAM02],
|
|
134
|
+
exposes: [exposes.enum('motor_working_mode', ea.STATE_SET, Object.values(tuya.ZMAM02.AM02MotorMode)),
|
|
135
|
+
exposes.enum('control', ea.STATE_SET, Object.values(tuya.ZMAM02.AM02Control)),
|
|
136
|
+
exposes.numeric('percent_state', ea.STATE).withValueMin(0).withValueMax(100).withValueStep(1).withUnit('%'),
|
|
137
|
+
exposes.enum('mode', ea.STATE_SET, Object.values(tuya.ZMAM02.AM02Mode)),
|
|
138
|
+
exposes.enum('control_back_mode', ea.STATE_SET, Object.values(tuya.ZMAM02.AM02Direction)),
|
|
139
|
+
exposes.enum('border', ea.STATE_SET, Object.values(tuya.ZMAM02.AM02Border)),
|
|
140
|
+
// ---------------------------------------------------------------------------------
|
|
141
|
+
// DP exists, but not used at the moment
|
|
142
|
+
// exposes.numeric('percent_control', ea.STATE_SET).withValueMin(0).withValueMax(100).withValueStep(1).withUnit('%'),
|
|
143
|
+
// exposes.enum('work_state', ea.STATE, Object.values(tuya.ZMAM02.AM02WorkState)),
|
|
144
|
+
// exposes.numeric('countdown_left', ea.STATE).withUnit('s'),
|
|
145
|
+
// exposes.numeric('time_total', ea.STATE).withUnit('ms'),
|
|
146
|
+
// exposes.enum('situation_set', ea.STATE, Object.values(tuya.ZMAM02.AM02Situation)),
|
|
147
|
+
],
|
|
148
|
+
},
|
|
105
149
|
];
|
package/lib/ota/zigbeeOTA.js
CHANGED
|
@@ -32,8 +32,18 @@ async function getIndexFile(urlOrName) {
|
|
|
32
32
|
return JSON.parse(fs.readFileSync(urlOrName));
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
function readLocalFile(fileName, logger) {
|
|
36
|
+
// If the file name is not a full path, then treat it as a relative to the data directory
|
|
37
|
+
if (!path.isAbsolute(fileName) && dataDir) {
|
|
38
|
+
fileName = path.join(dataDir, fileName);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
logger.debug(`ZigbeeOTA: getting local firmware file ${fileName}`);
|
|
42
|
+
return fs.readFileSync(fileName);
|
|
43
|
+
}
|
|
44
|
+
|
|
35
45
|
async function getFirmwareFile(image, logger) {
|
|
36
|
-
|
|
46
|
+
const urlOrName = image.url;
|
|
37
47
|
|
|
38
48
|
// First try to download firmware file with the URL provided
|
|
39
49
|
if (isValidUrl(urlOrName)) {
|
|
@@ -41,15 +51,33 @@ async function getFirmwareFile(image, logger) {
|
|
|
41
51
|
return await axios.get(urlOrName, {responseType: 'arraybuffer'});
|
|
42
52
|
}
|
|
43
53
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
54
|
+
return {data: readLocalFile(urlOrName, logger)};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function fillImageInfo(meta, logger) {
|
|
58
|
+
// Web-hosted images must come with all fields filled already
|
|
59
|
+
if (isValidUrl(meta.url)) {
|
|
60
|
+
return meta;
|
|
47
61
|
}
|
|
48
62
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
63
|
+
// Nothing to do if needed fields were filled already
|
|
64
|
+
if (meta.hasOwnProperty('imageType') &&
|
|
65
|
+
meta.hasOwnProperty('manufacturerCode') &&
|
|
66
|
+
meta.hasOwnProperty('fileVersion')) {
|
|
67
|
+
return meta;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// If no fields provided - get them from the image file
|
|
71
|
+
const buffer = readLocalFile(meta.url, logger);
|
|
72
|
+
const start = buffer.indexOf(common.upgradeFileIdentifier);
|
|
73
|
+
const image = common.parseImage(buffer.slice(start));
|
|
52
74
|
|
|
75
|
+
// Will fill only those fields that were absent
|
|
76
|
+
if (!meta.hasOwnProperty('imageType')) meta.imageType = image.header.imageType;
|
|
77
|
+
if (!meta.hasOwnProperty('manufacturerCode')) meta.manufacturerCode = image.header.manufacturerCode;
|
|
78
|
+
if (!meta.hasOwnProperty('fileVersion')) meta.fileVersion = image.header.fileVersion;
|
|
79
|
+
return meta;
|
|
80
|
+
}
|
|
53
81
|
|
|
54
82
|
async function getIndex(logger) {
|
|
55
83
|
const index = (await axios.get(url)).data;
|
|
@@ -61,7 +89,7 @@ async function getIndex(logger) {
|
|
|
61
89
|
const localIndex = await getIndexFile(overrideIndexFileName);
|
|
62
90
|
|
|
63
91
|
// Resulting index will have overriden items first
|
|
64
|
-
return localIndex.concat(index);
|
|
92
|
+
return localIndex.concat(index).map((item) => isValidUrl(item.url) ? item : fillImageInfo(item, logger));
|
|
65
93
|
}
|
|
66
94
|
|
|
67
95
|
return index;
|
package/lib/reporting.js
CHANGED
|
@@ -84,7 +84,7 @@ module.exports = {
|
|
|
84
84
|
await endpoint.configureReporting('msTemperatureMeasurement', p);
|
|
85
85
|
},
|
|
86
86
|
deviceTemperature: async (endpoint, overrides) => {
|
|
87
|
-
const p = payload('currentTemperature',
|
|
87
|
+
const p = payload('currentTemperature', 300, repInterval.HOUR, 1, overrides);
|
|
88
88
|
await endpoint.configureReporting('genDeviceTempCfg', p);
|
|
89
89
|
},
|
|
90
90
|
pressure: async (endpoint, overrides) => {
|
package/lib/tuya.js
CHANGED
|
@@ -537,6 +537,20 @@ const dataPoints = {
|
|
|
537
537
|
evanellLocalTemp: 5,
|
|
538
538
|
evanellBattery: 6,
|
|
539
539
|
evanellChildLock: 8,
|
|
540
|
+
// ZMAM02 Zemismart RF Courtain Converter
|
|
541
|
+
AM02Control: 1,
|
|
542
|
+
AM02PercentControl: 2,
|
|
543
|
+
AM02PercentState: 3,
|
|
544
|
+
AM02Mode: 4,
|
|
545
|
+
AM02ControlBackMode: 5,
|
|
546
|
+
AM02WorkState: 7,
|
|
547
|
+
AM02CountdownLeft: 9,
|
|
548
|
+
AM02TimeTotal: 10,
|
|
549
|
+
AM02SituationSet: 11,
|
|
550
|
+
AM02Fault: 12,
|
|
551
|
+
AM02Border: 16,
|
|
552
|
+
AM02MotorWorkingMode: 20,
|
|
553
|
+
AM02AddRemoter: 101,
|
|
540
554
|
};
|
|
541
555
|
|
|
542
556
|
const thermostatWeekFormat = {
|
|
@@ -650,6 +664,40 @@ const tvThermostatPreset = {
|
|
|
650
664
|
1: 'manual',
|
|
651
665
|
3: 'holiday',
|
|
652
666
|
};
|
|
667
|
+
// Zemismart ZM_AM02 Roller Shade Converter
|
|
668
|
+
const ZMAM02 = {
|
|
669
|
+
AM02Mode: {
|
|
670
|
+
0: 'morning',
|
|
671
|
+
1: 'night',
|
|
672
|
+
},
|
|
673
|
+
AM02Control: {
|
|
674
|
+
0: 'open',
|
|
675
|
+
1: 'stop',
|
|
676
|
+
2: 'close',
|
|
677
|
+
3: 'continue',
|
|
678
|
+
},
|
|
679
|
+
AM02Direction: {
|
|
680
|
+
0: 'forward',
|
|
681
|
+
1: 'back',
|
|
682
|
+
},
|
|
683
|
+
AM02WorkState: {
|
|
684
|
+
0: 'opening',
|
|
685
|
+
1: 'closing',
|
|
686
|
+
},
|
|
687
|
+
AM02Border: {
|
|
688
|
+
0: 'up',
|
|
689
|
+
1: 'down',
|
|
690
|
+
2: 'down_delete',
|
|
691
|
+
},
|
|
692
|
+
AM02Situation: {
|
|
693
|
+
0: 'fully_open',
|
|
694
|
+
1: 'fully_close',
|
|
695
|
+
},
|
|
696
|
+
AM02MotorMode: {
|
|
697
|
+
0: 'continuous',
|
|
698
|
+
1: 'intermittently',
|
|
699
|
+
},
|
|
700
|
+
};
|
|
653
701
|
|
|
654
702
|
// Return `seq` - transaction ID for handling concrete response
|
|
655
703
|
async function sendDataPoints(entity, dpValues, cmd, seq=undefined) {
|
|
@@ -800,4 +848,5 @@ module.exports = {
|
|
|
800
848
|
tvThermostatMode,
|
|
801
849
|
tvThermostatPreset,
|
|
802
850
|
tuyaRadar,
|
|
851
|
+
ZMAM02,
|
|
803
852
|
};
|