zigbee-herdsman-converters 14.0.377 → 14.0.381
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 +39 -2
- package/converters/toZigbee.js +18 -12
- package/devices/adeo.js +12 -0
- package/devices/philips.js +9 -0
- package/devices/rgb_genie.js +2 -1
- package/devices/skydance.js +20 -5
- package/devices/tuya.js +37 -10
- package/devices/xiaomi.js +2 -1
- package/index.js +1 -1
- package/lib/ota/zigbeeOTA.js +32 -7
- package/npm-shrinkwrap.json +1 -1
- package/package.json +1 -1
package/converters/fromZigbee.js
CHANGED
|
@@ -1380,8 +1380,8 @@ const converters = {
|
|
|
1380
1380
|
const payload = {
|
|
1381
1381
|
action: postfixWithEndpointName(`color_move`, msg, model),
|
|
1382
1382
|
action_color: {
|
|
1383
|
-
x: precisionRound(msg.data.colorx /
|
|
1384
|
-
y: precisionRound(msg.data.colory /
|
|
1383
|
+
x: precisionRound(msg.data.colorx / 65536, 3),
|
|
1384
|
+
y: precisionRound(msg.data.colory / 65536, 3),
|
|
1385
1385
|
},
|
|
1386
1386
|
action_transition_time: msg.data.transtime,
|
|
1387
1387
|
};
|
|
@@ -7928,6 +7928,34 @@ const converters = {
|
|
|
7928
7928
|
return result;
|
|
7929
7929
|
},
|
|
7930
7930
|
},
|
|
7931
|
+
command_stop_move_raw: {
|
|
7932
|
+
cluster: 'lightingColorCtrl',
|
|
7933
|
+
type: 'raw',
|
|
7934
|
+
convert: (model, msg, publish, options, meta) => {
|
|
7935
|
+
// commandStopMove without params
|
|
7936
|
+
if (msg.data[2] !== 71) return;
|
|
7937
|
+
if (hasAlreadyProcessedMessage(msg)) return;
|
|
7938
|
+
const movestop = 'stop';
|
|
7939
|
+
const action = postfixWithEndpointName(`hue_${movestop}`, msg, model);
|
|
7940
|
+
const payload = {action};
|
|
7941
|
+
addActionGroup(payload, msg, model);
|
|
7942
|
+
return payload;
|
|
7943
|
+
},
|
|
7944
|
+
},
|
|
7945
|
+
tuya_multi_action: {
|
|
7946
|
+
cluster: 'genOnOff',
|
|
7947
|
+
type: 'raw',
|
|
7948
|
+
convert: (model, msg, publish, options, meta) => {
|
|
7949
|
+
if (hasAlreadyProcessedMessage(msg, msg.data[2])) return;
|
|
7950
|
+
let action;
|
|
7951
|
+
if (msg.data[2] == 253) {
|
|
7952
|
+
action = {0: 'single', 1: 'double', 2: 'hold'}[msg.data[3]];
|
|
7953
|
+
} else if (msg.data[2] == 252) {
|
|
7954
|
+
action = {0: 'rotate_right', 1: 'rotate_left'}[msg.data[3]];
|
|
7955
|
+
}
|
|
7956
|
+
return {action};
|
|
7957
|
+
},
|
|
7958
|
+
},
|
|
7931
7959
|
// #endregion
|
|
7932
7960
|
|
|
7933
7961
|
// #region Ignore converters (these message dont need parsing).
|
|
@@ -8086,6 +8114,15 @@ const converters = {
|
|
|
8086
8114
|
type: ['raw'],
|
|
8087
8115
|
convert: (model, msg, publish, options, meta) => null,
|
|
8088
8116
|
},
|
|
8117
|
+
ignore_metering: {
|
|
8118
|
+
/**
|
|
8119
|
+
* When using this converter also add the following to the configure method of the device:
|
|
8120
|
+
* await readMeteringPowerConverterAttributes(endpoint);
|
|
8121
|
+
*/
|
|
8122
|
+
cluster: 'seMetering',
|
|
8123
|
+
type: ['attributeReport', 'readResponse'],
|
|
8124
|
+
convert: (model, msg, publish, options, meta) => null,
|
|
8125
|
+
},
|
|
8089
8126
|
// #endregion
|
|
8090
8127
|
};
|
|
8091
8128
|
|
package/converters/toZigbee.js
CHANGED
|
@@ -6471,10 +6471,12 @@ const converters = {
|
|
|
6471
6471
|
} else {
|
|
6472
6472
|
throw new Error('Dimmer brightness is out of range 0..255');
|
|
6473
6473
|
}
|
|
6474
|
-
await tuya.
|
|
6475
|
-
|
|
6474
|
+
await tuya.sendDataPoints(entity, [
|
|
6475
|
+
tuya.dpValueFromEnum(tuya.dataPoints.silvercrestChangeMode, tuya.silvercrestModes.white),
|
|
6476
|
+
tuya.dpValueFromIntValue(tuya.dataPoints.dimmerLevel, newValue),
|
|
6477
|
+
], 'dataRequest', 1);
|
|
6476
6478
|
|
|
6477
|
-
return {state: {white_brightness: value}};
|
|
6479
|
+
return {state: (key == 'white_brightness') ? {white_brightness: value} : {brightness: value}};
|
|
6478
6480
|
} else if (key == 'color_temp') {
|
|
6479
6481
|
const [colorTempMin, colorTempMax] = [250, 454];
|
|
6480
6482
|
const preset = {
|
|
@@ -6496,8 +6498,10 @@ const converters = {
|
|
|
6496
6498
|
}
|
|
6497
6499
|
const data = utils.mapNumberRange(value, colorTempMax, colorTempMin, 0, 1000);
|
|
6498
6500
|
|
|
6499
|
-
await tuya.
|
|
6500
|
-
|
|
6501
|
+
await tuya.sendDataPoints(entity, [
|
|
6502
|
+
tuya.dpValueFromEnum(tuya.dataPoints.silvercrestChangeMode, tuya.silvercrestModes.white),
|
|
6503
|
+
tuya.dpValueFromIntValue(tuya.dataPoints.silvercrestSetColorTemp, data),
|
|
6504
|
+
], 'dataRequest', 1);
|
|
6501
6505
|
|
|
6502
6506
|
return {state: {color_temp: value}};
|
|
6503
6507
|
} else if (key == 'color' || (separateWhite && (key == 'brightness'))) {
|
|
@@ -6550,12 +6554,11 @@ const converters = {
|
|
|
6550
6554
|
}
|
|
6551
6555
|
|
|
6552
6556
|
// Scale 0-255 to 0-1000 what the device expects.
|
|
6553
|
-
if (b) {
|
|
6557
|
+
if (b != null) {
|
|
6554
6558
|
hsb.b = make4sizedString(utils.mapNumberRange(b, 0, 255, 0, 1000).toString(16));
|
|
6555
|
-
} else if (state.brightness) {
|
|
6559
|
+
} else if (state.brightness != null) {
|
|
6556
6560
|
hsb.b = make4sizedString(utils.mapNumberRange(state.brightness, 0, 255, 0, 1000).toString(16));
|
|
6557
6561
|
}
|
|
6558
|
-
|
|
6559
6562
|
return hsb;
|
|
6560
6563
|
};
|
|
6561
6564
|
|
|
@@ -6572,15 +6575,18 @@ const converters = {
|
|
|
6572
6575
|
data = data.concat(tuya.convertStringToHexArray(hsb.s));
|
|
6573
6576
|
data = data.concat(tuya.convertStringToHexArray(hsb.b));
|
|
6574
6577
|
|
|
6575
|
-
|
|
6576
|
-
|
|
6578
|
+
const commands = [
|
|
6579
|
+
tuya.dpValueFromEnum(tuya.dataPoints.silvercrestChangeMode, tuya.silvercrestModes.color),
|
|
6580
|
+
tuya.dpValueFromStringBuffer(tuya.dataPoints.silvercrestSetColor, data),
|
|
6581
|
+
];
|
|
6577
6582
|
|
|
6578
6583
|
if (separateWhite && meta.state.white_brightness != undefined) {
|
|
6579
6584
|
// restore white state
|
|
6580
6585
|
const newValue = utils.mapNumberRange(meta.state.white_brightness, 0, 255, 0, 1000);
|
|
6581
|
-
|
|
6582
|
-
|
|
6586
|
+
commands.push(tuya.dpValueFromEnum(tuya.dataPoints.silvercrestChangeMode, tuya.silvercrestModes.white));
|
|
6587
|
+
commands.push(tuya.dpValueFromIntValue(tuya.dataPoints.dimmerLevel, newValue));
|
|
6583
6588
|
}
|
|
6589
|
+
await tuya.sendDataPoints(entity, commands, 'dataRequest', 1);
|
|
6584
6590
|
|
|
6585
6591
|
return {state: newState};
|
|
6586
6592
|
}
|
package/devices/adeo.js
CHANGED
|
@@ -6,6 +6,18 @@ const tz = require('../converters/toZigbee');
|
|
|
6
6
|
const e = exposes.presets;
|
|
7
7
|
|
|
8
8
|
module.exports = [
|
|
9
|
+
{
|
|
10
|
+
zigbeeModel: ['LDSENK01F'],
|
|
11
|
+
model: 'LDSENK01F',
|
|
12
|
+
vendor: 'ADEO',
|
|
13
|
+
description: '10A EU smart plug',
|
|
14
|
+
extend: extend.switch(),
|
|
15
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
16
|
+
const endpoint = device.getEndpoint(1);
|
|
17
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff']);
|
|
18
|
+
await reporting.onOff(endpoint);
|
|
19
|
+
},
|
|
20
|
+
},
|
|
9
21
|
{
|
|
10
22
|
zigbeeModel: ['LXEK-5'],
|
|
11
23
|
model: 'HR-C99C-Z-C045',
|
package/devices/philips.js
CHANGED
|
@@ -29,6 +29,15 @@ const hueExtend = {
|
|
|
29
29
|
};
|
|
30
30
|
|
|
31
31
|
module.exports = [
|
|
32
|
+
{
|
|
33
|
+
zigbeeModel: ['LCX004'],
|
|
34
|
+
model: '929002994901',
|
|
35
|
+
vendor: 'Philips',
|
|
36
|
+
description: 'Hue gradient lightstrip',
|
|
37
|
+
meta: {turnsOffAtBrightness1: true},
|
|
38
|
+
extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
|
|
39
|
+
ota: ota.zigbeeOTA,
|
|
40
|
+
},
|
|
32
41
|
{
|
|
33
42
|
zigbeeModel: ['929003047501'],
|
|
34
43
|
model: '929003047501',
|
package/devices/rgb_genie.js
CHANGED
|
@@ -71,7 +71,8 @@ module.exports = [
|
|
|
71
71
|
fromZigbee: [fz.battery, fz.command_on, fz.command_off, fz.command_step, fz.command_move, fz.command_stop, fz.command_recall,
|
|
72
72
|
fz.command_move_hue, fz.command_move_to_color, fz.command_move_to_color_temp],
|
|
73
73
|
exposes: [e.battery(), e.action(['on', 'off', 'brightness_step_up', 'brightness_step_down', 'brightness_move_up',
|
|
74
|
-
'brightness_move_down', 'brightness_stop', 'recall_1', 'recall_2', 'recall_3'
|
|
74
|
+
'brightness_move_down', 'brightness_stop', 'recall_1', 'recall_2', 'recall_3', 'hue_move', 'color_temperature_move',
|
|
75
|
+
'color_move', 'hue_stop'])],
|
|
75
76
|
toZigbee: [],
|
|
76
77
|
meta: {multiEndpoint: true, battery: {dontDividePercentage: true}},
|
|
77
78
|
configure: async (device, coordinatorEndpoint) => {
|
package/devices/skydance.js
CHANGED
|
@@ -5,7 +5,10 @@ const ea = exposes.access;
|
|
|
5
5
|
|
|
6
6
|
module.exports = [
|
|
7
7
|
{
|
|
8
|
-
fingerprint: [
|
|
8
|
+
fingerprint: [
|
|
9
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_6qoazbre'},
|
|
10
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_fcooykb4'},
|
|
11
|
+
],
|
|
9
12
|
model: 'WZ5_dim',
|
|
10
13
|
vendor: 'Skydance',
|
|
11
14
|
description: 'Zigbee & RF 5 in 1 LED controller (DIM mode)',
|
|
@@ -17,7 +20,10 @@ module.exports = [
|
|
|
17
20
|
],
|
|
18
21
|
},
|
|
19
22
|
{
|
|
20
|
-
fingerprint: [
|
|
23
|
+
fingerprint: [
|
|
24
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_gz3n0tzf'},
|
|
25
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_nthosjmx'},
|
|
26
|
+
],
|
|
21
27
|
model: 'WZ5_cct',
|
|
22
28
|
vendor: 'Skydance',
|
|
23
29
|
description: 'Zigbee & RF 5 in 1 LED controller (CCT mode)',
|
|
@@ -29,7 +35,10 @@ module.exports = [
|
|
|
29
35
|
],
|
|
30
36
|
},
|
|
31
37
|
{
|
|
32
|
-
fingerprint: [
|
|
38
|
+
fingerprint: [
|
|
39
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_9hghastn'},
|
|
40
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_9mt3kgn0'},
|
|
41
|
+
],
|
|
33
42
|
model: 'WZ5_rgb',
|
|
34
43
|
vendor: 'Skydance',
|
|
35
44
|
description: 'Zigbee & RF 5 in 1 LED controller (RGB mode)',
|
|
@@ -41,7 +50,10 @@ module.exports = [
|
|
|
41
50
|
],
|
|
42
51
|
},
|
|
43
52
|
{
|
|
44
|
-
fingerprint: [
|
|
53
|
+
fingerprint: [
|
|
54
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_3thxjahu'},
|
|
55
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_g9jdneiu'},
|
|
56
|
+
],
|
|
45
57
|
model: 'WZ5_rgbw',
|
|
46
58
|
vendor: 'Skydance',
|
|
47
59
|
description: 'Zigbee & RF 5 in 1 LED controller (RGBW mode)',
|
|
@@ -56,7 +68,10 @@ module.exports = [
|
|
|
56
68
|
meta: {separateWhite: true},
|
|
57
69
|
},
|
|
58
70
|
{
|
|
59
|
-
fingerprint: [
|
|
71
|
+
fingerprint: [
|
|
72
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_mde0utnv'},
|
|
73
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_aa9awrng'},
|
|
74
|
+
],
|
|
60
75
|
model: 'WZ5_rgbcct',
|
|
61
76
|
vendor: 'Skydance',
|
|
62
77
|
description: 'Zigbee & RF 5 in 1 LED controller (RGB+CCT mode)',
|
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'];
|
|
16
16
|
|
|
17
17
|
const tzLocal = {
|
|
18
18
|
TS0504B_color: {
|
|
@@ -162,7 +162,8 @@ module.exports = [
|
|
|
162
162
|
{modelID: 'TS0505B', manufacturerName: '_TZ3210_0rn9qhnu'},
|
|
163
163
|
{modelID: 'TS0505B', manufacturerName: '_TZ3210_bicjqpg4'},
|
|
164
164
|
{modelID: 'TS0505B', manufacturerName: '_TZ3000_cmaky9gq'},
|
|
165
|
-
{modelID: 'TS0505B', manufacturerName: '_TZ3000_tza2vjxx'}
|
|
165
|
+
{modelID: 'TS0505B', manufacturerName: '_TZ3000_tza2vjxx'},
|
|
166
|
+
{modelID: 'TS0505B', manufacturerName: '_TZ3210_bfwvfyx1'}],
|
|
166
167
|
model: 'TS0505B',
|
|
167
168
|
vendor: 'TuYa',
|
|
168
169
|
description: 'Zigbee RGB+CCT light',
|
|
@@ -177,6 +178,7 @@ module.exports = [
|
|
|
177
178
|
{
|
|
178
179
|
fingerprint: [{modelID: 'TS0503B', manufacturerName: '_TZ3000_i8l0nqdu'},
|
|
179
180
|
{modelID: 'TS0503B', manufacturerName: '_TZ3210_a5fxguxr'},
|
|
181
|
+
{modelID: 'TS0503B', manufacturerName: '_TZ3210_778drfdt'},
|
|
180
182
|
{modelID: 'TS0503B', manufacturerName: '_TZ3000_g5xawfcq'}],
|
|
181
183
|
model: 'TS0503B',
|
|
182
184
|
vendor: 'TuYa',
|
|
@@ -187,7 +189,9 @@ module.exports = [
|
|
|
187
189
|
},
|
|
188
190
|
{
|
|
189
191
|
fingerprint: [{modelID: 'TS0504B', manufacturerName: '_TZ3000_ukuvyhaa'},
|
|
190
|
-
{modelID: 'TS0504B', manufacturerName: '_TZ3210_bfvybixd'},
|
|
192
|
+
{modelID: 'TS0504B', manufacturerName: '_TZ3210_bfvybixd'},
|
|
193
|
+
{modelID: 'TS0504B', manufacturerName: '_TZ3210_sroezl0s'},
|
|
194
|
+
{modelID: 'TS0504B', manufacturerName: '_TZ3210_1elppmba'}],
|
|
191
195
|
model: 'TS0504B',
|
|
192
196
|
vendor: 'TuYa',
|
|
193
197
|
description: 'Zigbee RGBW light',
|
|
@@ -199,7 +203,8 @@ module.exports = [
|
|
|
199
203
|
fingerprint: [{modelID: 'TS0501B', manufacturerName: '_TZ3000_4whigl8i'},
|
|
200
204
|
{modelID: 'TS0501B', manufacturerName: '_TZ3210_4whigl8i'},
|
|
201
205
|
{modelID: 'TS0501B', manufacturerName: '_TZ3210_9q49basr'},
|
|
202
|
-
{modelID: 'TS0501B', manufacturerName: '_TZ3210_grnwgegn'}
|
|
206
|
+
{modelID: 'TS0501B', manufacturerName: '_TZ3210_grnwgegn'},
|
|
207
|
+
{modelID: 'TS0501B', manufacturerName: '_TZ3210_wuheofsg'}],
|
|
203
208
|
model: 'TS0501B',
|
|
204
209
|
description: 'Zigbee light',
|
|
205
210
|
vendor: 'TuYa',
|
|
@@ -309,7 +314,8 @@ module.exports = [
|
|
|
309
314
|
],
|
|
310
315
|
},
|
|
311
316
|
{
|
|
312
|
-
fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_oiymh3qu'}
|
|
317
|
+
fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_oiymh3qu'},
|
|
318
|
+
{modelID: 'TS011F', manufacturerName: '_TZ3000_o1jzcxou'}],
|
|
313
319
|
model: 'TS011F_socket_module',
|
|
314
320
|
vendor: 'TuYa',
|
|
315
321
|
description: 'Socket module',
|
|
@@ -901,7 +907,7 @@ module.exports = [
|
|
|
901
907
|
'Mode of this device, in the `heat` mode the TS0601 will remain continuously heating, i.e. it does not regulate ' +
|
|
902
908
|
'to the desired temperature. If you want TRV to properly regulate the temperature you need to use mode `auto` ' +
|
|
903
909
|
'instead setting the desired temperature.')
|
|
904
|
-
.withLocalTemperatureCalibration(-
|
|
910
|
+
.withLocalTemperatureCalibration(-9, 9, 1, ea.STATE_SET)
|
|
905
911
|
.withAwayMode().withPreset(['schedule', 'manual', 'boost', 'complex', 'comfort', 'eco']),
|
|
906
912
|
e.auto_lock(), e.away_mode(), e.away_preset_days(), e.boost_time(), e.comfort_temperature(), e.eco_temperature(), e.force(),
|
|
907
913
|
e.max_temperature(), e.min_temperature(), e.away_preset_temperature(),
|
|
@@ -1116,7 +1122,8 @@ module.exports = [
|
|
|
1116
1122
|
{
|
|
1117
1123
|
fingerprint: [
|
|
1118
1124
|
{modelID: 'TS011F', manufacturerName: '_TZ3000_hyfvrar3'},
|
|
1119
|
-
{modelID: 'TS011F', manufacturerName: '_TZ3000_cymsnfvf'}
|
|
1125
|
+
{modelID: 'TS011F', manufacturerName: '_TZ3000_cymsnfvf'},
|
|
1126
|
+
{modelID: 'TS011F', manufacturerName: '_TZ3000_bfn1w0mm'}],
|
|
1120
1127
|
model: 'TS011F_plug_2',
|
|
1121
1128
|
description: 'Smart plug (without power monitoring)',
|
|
1122
1129
|
vendor: 'TuYa',
|
|
@@ -1831,9 +1838,29 @@ module.exports = [
|
|
|
1831
1838
|
model: 'ERS-10TZBVK-AA',
|
|
1832
1839
|
vendor: 'TuYa',
|
|
1833
1840
|
description: 'Smart knob',
|
|
1834
|
-
fromZigbee: [
|
|
1835
|
-
|
|
1836
|
-
|
|
1841
|
+
fromZigbee: [
|
|
1842
|
+
fz.command_step, fz.command_toggle, fz.command_move_hue, fz.command_step_color_temperature, fz.command_stop_move_raw,
|
|
1843
|
+
fz.tuya_multi_action, fz.tuya_operation_mode, fz.battery,
|
|
1844
|
+
],
|
|
1845
|
+
toZigbee: [tz.tuya_operation_mode],
|
|
1846
|
+
exposes: [
|
|
1847
|
+
e.action([
|
|
1848
|
+
'toggle', 'brightness_step_up', 'brightness_step_down', 'color_temperature_step_up', 'color_temperature_step_down',
|
|
1849
|
+
'saturation_move', 'hue_move', 'hue_stop', 'single', 'double', 'hold', 'rotate_left', 'rotate_right',
|
|
1850
|
+
]),
|
|
1851
|
+
exposes.numeric('action_step_size', ea.STATE).withValueMin(0).withValueMax(255),
|
|
1852
|
+
exposes.numeric('action_transition_time', ea.STATE).withUnit('s'),
|
|
1853
|
+
exposes.numeric('action_rate', ea.STATE).withValueMin(0).withValueMax(255),
|
|
1854
|
+
e.battery(),
|
|
1855
|
+
exposes.enum('operation_mode', ea.ALL, ['command', 'event']).withDescription(
|
|
1856
|
+
'Operation mode: "command" - for group control, "event" - for clicks'),
|
|
1857
|
+
],
|
|
1858
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
1859
|
+
const endpoint = device.getEndpoint(1);
|
|
1860
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg']);
|
|
1861
|
+
await reporting.batteryPercentageRemaining(endpoint);
|
|
1862
|
+
await endpoint.read('genOnOff', ['tuyaOperationMode']);
|
|
1863
|
+
},
|
|
1837
1864
|
},
|
|
1838
1865
|
{
|
|
1839
1866
|
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_kzm5w4iz'}],
|
package/devices/xiaomi.js
CHANGED
|
@@ -1402,7 +1402,8 @@ module.exports = [
|
|
|
1402
1402
|
model: 'SSM-U01',
|
|
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.electrical_measurement, fz.device_temperature, fz.aqara_opple, fz.ignore_metering],
|
|
1406
1407
|
exposes: [e.switch(), e.energy(), e.power(), e.device_temperature(), e.power_outage_memory(), e.switch_type()],
|
|
1407
1408
|
toZigbee: [tz.xiaomi_switch_type, tz.on_off, tz.xiaomi_switch_power_outage_memory],
|
|
1408
1409
|
configure: async (device, coordinatorEndpoint, logger) => {
|
package/index.js
CHANGED
|
@@ -77,7 +77,7 @@ function addDefinition(definition) {
|
|
|
77
77
|
|
|
78
78
|
definition.toZigbee.push(tz.scene_store, tz.scene_recall, tz.scene_add, tz.scene_remove, tz.scene_remove_all, tz.read, tz.write);
|
|
79
79
|
|
|
80
|
-
if (definition.exposes && Array.isArray(definition.exposes)) {
|
|
80
|
+
if (definition.exposes && Array.isArray(definition.exposes) && !definition.exposes.find((e) => e.name === 'linkquality')) {
|
|
81
81
|
definition.exposes = definition.exposes.concat([exposes.presets.linkquality()]);
|
|
82
82
|
}
|
|
83
83
|
|
package/lib/ota/zigbeeOTA.js
CHANGED
|
@@ -4,8 +4,10 @@ const common = require('./common');
|
|
|
4
4
|
const axios = common.getAxios();
|
|
5
5
|
const fs = require('fs');
|
|
6
6
|
const URI = require('uri-js');
|
|
7
|
+
const path = require('path');
|
|
7
8
|
|
|
8
|
-
let
|
|
9
|
+
let overrideIndexFileName = null;
|
|
10
|
+
let dataDir = null;
|
|
9
11
|
|
|
10
12
|
/**
|
|
11
13
|
* Helper functions
|
|
@@ -22,7 +24,7 @@ function isValidUrl(url) {
|
|
|
22
24
|
return parsed.scheme === 'http' || parsed.scheme === 'https';
|
|
23
25
|
}
|
|
24
26
|
|
|
25
|
-
async function
|
|
27
|
+
async function getIndexFile(urlOrName) {
|
|
26
28
|
if (isValidUrl(urlOrName)) {
|
|
27
29
|
return (await axios.get(urlOrName)).data;
|
|
28
30
|
}
|
|
@@ -30,14 +32,33 @@ async function getFile(urlOrName) {
|
|
|
30
32
|
return JSON.parse(fs.readFileSync(urlOrName));
|
|
31
33
|
}
|
|
32
34
|
|
|
35
|
+
async function getFirmwareFile(image, logger) {
|
|
36
|
+
let urlOrName = image.url;
|
|
37
|
+
|
|
38
|
+
// First try to download firmware file with the URL provided
|
|
39
|
+
if (isValidUrl(urlOrName)) {
|
|
40
|
+
logger.debug(`ZigbeeOTA: downloading firmware image from ${urlOrName}`);
|
|
41
|
+
return await axios.get(urlOrName, {responseType: 'arraybuffer'});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// If the file name is not a full path, then treat it as a relative to the data directory
|
|
45
|
+
if (!path.isAbsolute(urlOrName) && dataDir) {
|
|
46
|
+
urlOrName = path.join(dataDir, urlOrName);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
logger.debug(`ZigbeeOTA: getting local firmware file ${urlOrName}`);
|
|
50
|
+
return {data: fs.readFileSync(urlOrName)};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
33
54
|
async function getIndex(logger) {
|
|
34
55
|
const index = (await axios.get(url)).data;
|
|
35
56
|
|
|
36
57
|
logger.debug(`ZigbeeOTA: downloaded main index`);
|
|
37
58
|
|
|
38
|
-
if (
|
|
39
|
-
logger.debug(`ZigbeeOTA: Loading override index ${
|
|
40
|
-
const localIndex = await
|
|
59
|
+
if (overrideIndexFileName) {
|
|
60
|
+
logger.debug(`ZigbeeOTA: Loading override index ${overrideIndexFileName}`);
|
|
61
|
+
const localIndex = await getIndexFile(overrideIndexFileName);
|
|
41
62
|
|
|
42
63
|
// Resulting index will have overriden items first
|
|
43
64
|
return localIndex.concat(index);
|
|
@@ -58,6 +79,7 @@ async function getImageMeta(current, logger, device) {
|
|
|
58
79
|
// For this case additional identification through the modelId is done.
|
|
59
80
|
// In the case of Tuya and Moes, additional identification is carried out through the manufacturerName.
|
|
60
81
|
const image = images.find((i) => i.imageType === imageType && i.manufacturerCode === manufacturerCode &&
|
|
82
|
+
(!i.minFileVersion || current.fileVersion >= i.minFileVersion) && (!i.maxFileVersion || current.fileVersion <= i.maxFileVersion) &&
|
|
61
83
|
(!i.modelId || i.modelId === modelId) && (!i.manufacturerName || i.manufacturerName.includes(manufacturerName)));
|
|
62
84
|
|
|
63
85
|
assert(image !== undefined, `No image available for imageType '${imageType}'`);
|
|
@@ -78,7 +100,7 @@ async function isUpdateAvailable(device, logger, requestPayload=null) {
|
|
|
78
100
|
}
|
|
79
101
|
|
|
80
102
|
async function updateToLatest(device, logger, onProgress) {
|
|
81
|
-
return common.updateToLatest(device, logger, onProgress, common.getNewImage, getImageMeta);
|
|
103
|
+
return common.updateToLatest(device, logger, onProgress, common.getNewImage, getImageMeta, getFirmwareFile);
|
|
82
104
|
}
|
|
83
105
|
|
|
84
106
|
module.exports = {
|
|
@@ -86,6 +108,9 @@ module.exports = {
|
|
|
86
108
|
isUpdateAvailable,
|
|
87
109
|
updateToLatest,
|
|
88
110
|
useIndexOverride: (indexFileName) => {
|
|
89
|
-
|
|
111
|
+
overrideIndexFileName = indexFileName;
|
|
112
|
+
},
|
|
113
|
+
setDataDir: (dir) => {
|
|
114
|
+
dataDir = dir;
|
|
90
115
|
},
|
|
91
116
|
};
|
package/npm-shrinkwrap.json
CHANGED