zigbee-herdsman-converters 14.0.378 → 14.0.382
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 +40 -2
- package/converters/toZigbee.js +18 -12
- package/devices/adeo.js +12 -0
- package/devices/aurora_lighting.js +1 -1
- package/devices/danalock.js +4 -3
- package/devices/philips.js +19 -1
- package/devices/rgb_genie.js +2 -1
- package/devices/skydance.js +20 -5
- package/devices/tuya.js +38 -10
- package/devices/xiaomi.js +2 -1
- package/lib/ota/common.js +6 -1
- package/lib/ota/zigbeeOTA.js +33 -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,16 @@ const converters = {
|
|
|
8086
8114
|
type: ['raw'],
|
|
8087
8115
|
convert: (model, msg, publish, options, meta) => null,
|
|
8088
8116
|
},
|
|
8117
|
+
ignore_metering: {
|
|
8118
|
+
cluster: 'seMetering',
|
|
8119
|
+
type: ['attributeReport', 'readResponse'],
|
|
8120
|
+
convert: (model, msg, publish, options, meta) => null,
|
|
8121
|
+
},
|
|
8122
|
+
ignore_electrical_measurement: {
|
|
8123
|
+
cluster: 'haElectricalMeasurement',
|
|
8124
|
+
type: ['attributeReport', 'readResponse'],
|
|
8125
|
+
convert: (model, msg, publish, options, meta) => null,
|
|
8126
|
+
},
|
|
8089
8127
|
// #endregion
|
|
8090
8128
|
};
|
|
8091
8129
|
|
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',
|
|
@@ -68,7 +68,7 @@ module.exports = [
|
|
|
68
68
|
extend: extend.light_onoff_brightness_colortemp_color(),
|
|
69
69
|
},
|
|
70
70
|
{
|
|
71
|
-
zigbeeModel: ['RGBBulb01UK', 'RGBBulb02UK'],
|
|
71
|
+
zigbeeModel: ['RGBBulb01UK', 'RGBBulb02UK', 'RGBBulb51AU'],
|
|
72
72
|
model: 'AU-A1GSZ9RGBW_HV-GSCXZB269K',
|
|
73
73
|
vendor: 'Aurora Lighting',
|
|
74
74
|
description: 'AOne 9.5W smart RGBW GLS E27/B22',
|
package/devices/danalock.js
CHANGED
|
@@ -10,14 +10,15 @@ module.exports = [
|
|
|
10
10
|
model: 'V3-BTZB/V3-BTZBE',
|
|
11
11
|
vendor: 'Danalock',
|
|
12
12
|
description: 'BT/ZB smartlock',
|
|
13
|
-
fromZigbee: [fz.lock, fz.lock_operation_event, fz.battery],
|
|
14
|
-
toZigbee: [tz.lock],
|
|
13
|
+
fromZigbee: [fz.lock, fz.lock_operation_event, fz.battery, fz.lock_programming_event, fz.lock_pin_code_response],
|
|
14
|
+
toZigbee: [tz.lock, tz.pincode_lock, tz.lock_userstatus],
|
|
15
|
+
meta: {pinCodeCount: 20},
|
|
15
16
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
16
17
|
const endpoint = device.getEndpoint(1);
|
|
17
18
|
await reporting.bind(endpoint, coordinatorEndpoint, ['closuresDoorLock', 'genPowerCfg']);
|
|
18
19
|
await reporting.lockState(endpoint);
|
|
19
20
|
await reporting.batteryPercentageRemaining(endpoint);
|
|
20
21
|
},
|
|
21
|
-
exposes: [e.lock(), e.battery()],
|
|
22
|
+
exposes: [e.lock(), e.battery(), e.pincode()],
|
|
22
23
|
},
|
|
23
24
|
];
|
package/devices/philips.js
CHANGED
|
@@ -29,6 +29,24 @@ const hueExtend = {
|
|
|
29
29
|
};
|
|
30
30
|
|
|
31
31
|
module.exports = [
|
|
32
|
+
{
|
|
33
|
+
zigbeeModel: ['LWA018'],
|
|
34
|
+
model: '9290024693',
|
|
35
|
+
vendor: 'Philips',
|
|
36
|
+
description: 'Hue white A60 bulb B22 1055lm with Bluetooth',
|
|
37
|
+
meta: {turnsOffAtBrightness1: true},
|
|
38
|
+
extend: extend.light_onoff_brightness(),
|
|
39
|
+
ota: ota.zigbeeOTA,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
zigbeeModel: ['LCX004'],
|
|
43
|
+
model: '929002994901',
|
|
44
|
+
vendor: 'Philips',
|
|
45
|
+
description: 'Hue gradient lightstrip',
|
|
46
|
+
meta: {turnsOffAtBrightness1: true},
|
|
47
|
+
extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
|
|
48
|
+
ota: ota.zigbeeOTA,
|
|
49
|
+
},
|
|
32
50
|
{
|
|
33
51
|
zigbeeModel: ['929003047501'],
|
|
34
52
|
model: '929003047501',
|
|
@@ -911,7 +929,7 @@ module.exports = [
|
|
|
911
929
|
vendor: 'Philips',
|
|
912
930
|
description: 'Hue white ambiance E14 (with Bluetooth)',
|
|
913
931
|
meta: {turnsOffAtBrightness1: true},
|
|
914
|
-
extend: hueExtend.light_onoff_brightness_colortemp(),
|
|
932
|
+
extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
|
|
915
933
|
ota: ota.zigbeeOTA,
|
|
916
934
|
},
|
|
917
935
|
{
|
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',
|
|
@@ -216,6 +221,7 @@ module.exports = [
|
|
|
216
221
|
{modelID: 'TS0202', manufacturerName: '_TZ3000_kmh5qpmb'},
|
|
217
222
|
{modelID: 'TS0202', manufacturerName: '_TYZB01_zwvaj5wy'},
|
|
218
223
|
{modelID: 'TS0202', manufacturerName: '_TZ3000_mcxw5ehu'},
|
|
224
|
+
{modelID: 'TS0202', manufacturerName: '_TZ3000_bsvqrxru'},
|
|
219
225
|
{modelID: 'TS0202', manufacturerName: '_TZ3000_msl6wxk9'},
|
|
220
226
|
{modelID: 'TS0202', manufacturerName: '_TYZB01_tv3wxhcz'},
|
|
221
227
|
{modelID: 'TS0202', manufacturerName: '_TYZB01_hqbdru35'},
|
|
@@ -309,7 +315,8 @@ module.exports = [
|
|
|
309
315
|
],
|
|
310
316
|
},
|
|
311
317
|
{
|
|
312
|
-
fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_oiymh3qu'}
|
|
318
|
+
fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_oiymh3qu'},
|
|
319
|
+
{modelID: 'TS011F', manufacturerName: '_TZ3000_o1jzcxou'}],
|
|
313
320
|
model: 'TS011F_socket_module',
|
|
314
321
|
vendor: 'TuYa',
|
|
315
322
|
description: 'Socket module',
|
|
@@ -901,7 +908,7 @@ module.exports = [
|
|
|
901
908
|
'Mode of this device, in the `heat` mode the TS0601 will remain continuously heating, i.e. it does not regulate ' +
|
|
902
909
|
'to the desired temperature. If you want TRV to properly regulate the temperature you need to use mode `auto` ' +
|
|
903
910
|
'instead setting the desired temperature.')
|
|
904
|
-
.withLocalTemperatureCalibration(-
|
|
911
|
+
.withLocalTemperatureCalibration(-9, 9, 1, ea.STATE_SET)
|
|
905
912
|
.withAwayMode().withPreset(['schedule', 'manual', 'boost', 'complex', 'comfort', 'eco']),
|
|
906
913
|
e.auto_lock(), e.away_mode(), e.away_preset_days(), e.boost_time(), e.comfort_temperature(), e.eco_temperature(), e.force(),
|
|
907
914
|
e.max_temperature(), e.min_temperature(), e.away_preset_temperature(),
|
|
@@ -1116,7 +1123,8 @@ module.exports = [
|
|
|
1116
1123
|
{
|
|
1117
1124
|
fingerprint: [
|
|
1118
1125
|
{modelID: 'TS011F', manufacturerName: '_TZ3000_hyfvrar3'},
|
|
1119
|
-
{modelID: 'TS011F', manufacturerName: '_TZ3000_cymsnfvf'}
|
|
1126
|
+
{modelID: 'TS011F', manufacturerName: '_TZ3000_cymsnfvf'},
|
|
1127
|
+
{modelID: 'TS011F', manufacturerName: '_TZ3000_bfn1w0mm'}],
|
|
1120
1128
|
model: 'TS011F_plug_2',
|
|
1121
1129
|
description: 'Smart plug (without power monitoring)',
|
|
1122
1130
|
vendor: 'TuYa',
|
|
@@ -1831,9 +1839,29 @@ module.exports = [
|
|
|
1831
1839
|
model: 'ERS-10TZBVK-AA',
|
|
1832
1840
|
vendor: 'TuYa',
|
|
1833
1841
|
description: 'Smart knob',
|
|
1834
|
-
fromZigbee: [
|
|
1835
|
-
|
|
1836
|
-
|
|
1842
|
+
fromZigbee: [
|
|
1843
|
+
fz.command_step, fz.command_toggle, fz.command_move_hue, fz.command_step_color_temperature, fz.command_stop_move_raw,
|
|
1844
|
+
fz.tuya_multi_action, fz.tuya_operation_mode, fz.battery,
|
|
1845
|
+
],
|
|
1846
|
+
toZigbee: [tz.tuya_operation_mode],
|
|
1847
|
+
exposes: [
|
|
1848
|
+
e.action([
|
|
1849
|
+
'toggle', 'brightness_step_up', 'brightness_step_down', 'color_temperature_step_up', 'color_temperature_step_down',
|
|
1850
|
+
'saturation_move', 'hue_move', 'hue_stop', 'single', 'double', 'hold', 'rotate_left', 'rotate_right',
|
|
1851
|
+
]),
|
|
1852
|
+
exposes.numeric('action_step_size', ea.STATE).withValueMin(0).withValueMax(255),
|
|
1853
|
+
exposes.numeric('action_transition_time', ea.STATE).withUnit('s'),
|
|
1854
|
+
exposes.numeric('action_rate', ea.STATE).withValueMin(0).withValueMax(255),
|
|
1855
|
+
e.battery(),
|
|
1856
|
+
exposes.enum('operation_mode', ea.ALL, ['command', 'event']).withDescription(
|
|
1857
|
+
'Operation mode: "command" - for group control, "event" - for clicks'),
|
|
1858
|
+
],
|
|
1859
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
1860
|
+
const endpoint = device.getEndpoint(1);
|
|
1861
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg']);
|
|
1862
|
+
await reporting.batteryPercentageRemaining(endpoint);
|
|
1863
|
+
await endpoint.read('genOnOff', ['tuyaOperationMode']);
|
|
1864
|
+
},
|
|
1837
1865
|
},
|
|
1838
1866
|
{
|
|
1839
1867
|
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.device_temperature, fz.aqara_opple, fz.ignore_metering, fz.ignore_electrical_measurement],
|
|
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/lib/ota/common.js
CHANGED
|
@@ -265,6 +265,11 @@ async function isNewImageAvailable(current, logger, device, getImageMeta) {
|
|
|
265
265
|
const meta = await getImageMeta(current, logger, device);
|
|
266
266
|
const [currentS, metaS] = [JSON.stringify(current), JSON.stringify(meta)];
|
|
267
267
|
logger.debug(`Is new image available for '${device.ieeeAddr}', current '${currentS}', latest meta '${metaS}'`);
|
|
268
|
+
|
|
269
|
+
if (meta.force) {
|
|
270
|
+
return -1; // Negative number means the new firmware is 'newer' than current one
|
|
271
|
+
}
|
|
272
|
+
|
|
268
273
|
return Math.sign(current.fileVersion - meta.fileVersion);
|
|
269
274
|
}
|
|
270
275
|
|
|
@@ -411,7 +416,7 @@ async function updateToLatest(device, logger, onProgress, getNewImage, getImageM
|
|
|
411
416
|
async function getNewImage(current, logger, device, getImageMeta, downloadImage) {
|
|
412
417
|
const meta = await getImageMeta(current, logger, device);
|
|
413
418
|
logger.debug(`getNewImage for '${device.ieeeAddr}', meta ${JSON.stringify(meta)}`);
|
|
414
|
-
assert(meta.fileVersion > current.fileVersion, 'No new image available');
|
|
419
|
+
assert(meta.fileVersion > current.fileVersion || meta.force, 'No new image available');
|
|
415
420
|
|
|
416
421
|
const download = downloadImage ? await downloadImage(meta, logger) :
|
|
417
422
|
await getAxios().get(meta.url, {responseType: 'arraybuffer'});
|
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}'`);
|
|
@@ -66,6 +88,7 @@ async function getImageMeta(current, logger, device) {
|
|
|
66
88
|
fileSize: image.fileSize,
|
|
67
89
|
url: image.url,
|
|
68
90
|
sha512: image.sha512,
|
|
91
|
+
force: image.force,
|
|
69
92
|
};
|
|
70
93
|
}
|
|
71
94
|
|
|
@@ -78,7 +101,7 @@ async function isUpdateAvailable(device, logger, requestPayload=null) {
|
|
|
78
101
|
}
|
|
79
102
|
|
|
80
103
|
async function updateToLatest(device, logger, onProgress) {
|
|
81
|
-
return common.updateToLatest(device, logger, onProgress, common.getNewImage, getImageMeta);
|
|
104
|
+
return common.updateToLatest(device, logger, onProgress, common.getNewImage, getImageMeta, getFirmwareFile);
|
|
82
105
|
}
|
|
83
106
|
|
|
84
107
|
module.exports = {
|
|
@@ -86,6 +109,9 @@ module.exports = {
|
|
|
86
109
|
isUpdateAvailable,
|
|
87
110
|
updateToLatest,
|
|
88
111
|
useIndexOverride: (indexFileName) => {
|
|
89
|
-
|
|
112
|
+
overrideIndexFileName = indexFileName;
|
|
113
|
+
},
|
|
114
|
+
setDataDir: (dir) => {
|
|
115
|
+
dataDir = dir;
|
|
90
116
|
},
|
|
91
117
|
};
|
package/npm-shrinkwrap.json
CHANGED