zigbee-herdsman-converters 14.0.379 → 14.0.383
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/cleode.js +23 -0
- package/devices/danalock.js +4 -3
- package/devices/gledopto.js +7 -0
- package/devices/philips.js +19 -1
- package/devices/rgb_genie.js +2 -1
- package/devices/skydance.js +20 -5
- package/devices/tubeszb.js +20 -0
- package/devices/tuya.js +38 -9
- package/devices/xiaomi.js +4 -7
- package/devices/zemismart.js +22 -0
- package/lib/ota/common.js +6 -1
- package/lib/ota/zigbeeOTA.js +38 -9
- package/lib/reporting.js +1 -1
- 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',
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const exposes = require('../lib/exposes');
|
|
2
|
+
const fz = {...require('../converters/fromZigbee'), legacy: require('../lib/legacy').fromZigbee};
|
|
3
|
+
const tz = require('../converters/toZigbee');
|
|
4
|
+
const reporting = require('../lib/reporting');
|
|
5
|
+
const e = exposes.presets;
|
|
6
|
+
|
|
7
|
+
module.exports = [
|
|
8
|
+
{
|
|
9
|
+
zigbeeModel: ['ZPLUG'],
|
|
10
|
+
model: 'ZPLUG_Boost',
|
|
11
|
+
vendor: 'CLEODE',
|
|
12
|
+
description: 'ZPlug boost',
|
|
13
|
+
meta: {multiEndpoint: true},
|
|
14
|
+
fromZigbee: [fz.on_off],
|
|
15
|
+
toZigbee: [tz.on_off],
|
|
16
|
+
exposes: [e.switch(), e.power()],
|
|
17
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
18
|
+
const endpoint = device.getEndpoint(1);
|
|
19
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'seMetering']);
|
|
20
|
+
await reporting.readMeteringMultiplierDivisor(endpoint);
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
];
|
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/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/philips.js
CHANGED
|
@@ -29,6 +29,24 @@ 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
|
+
},
|
|
41
|
+
{
|
|
42
|
+
zigbeeModel: ['LWA018'],
|
|
43
|
+
model: '9290024693',
|
|
44
|
+
vendor: 'Philips',
|
|
45
|
+
description: 'Hue white A60 bulb B22 1055lm with Bluetooth',
|
|
46
|
+
meta: {turnsOffAtBrightness1: true},
|
|
47
|
+
extend: extend.light_onoff_brightness(),
|
|
48
|
+
ota: ota.zigbeeOTA,
|
|
49
|
+
},
|
|
32
50
|
{
|
|
33
51
|
zigbeeModel: ['LCX004'],
|
|
34
52
|
model: '929002994901',
|
|
@@ -920,7 +938,7 @@ module.exports = [
|
|
|
920
938
|
vendor: 'Philips',
|
|
921
939
|
description: 'Hue white ambiance E14 (with Bluetooth)',
|
|
922
940
|
meta: {turnsOffAtBrightness1: true},
|
|
923
|
-
extend: hueExtend.light_onoff_brightness_colortemp(),
|
|
941
|
+
extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
|
|
924
942
|
ota: ota.zigbeeOTA,
|
|
925
943
|
},
|
|
926
944
|
{
|
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)',
|
|
@@ -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
|
@@ -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: {
|
|
@@ -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',
|
|
@@ -189,7 +191,9 @@ module.exports = [
|
|
|
189
191
|
},
|
|
190
192
|
{
|
|
191
193
|
fingerprint: [{modelID: 'TS0504B', manufacturerName: '_TZ3000_ukuvyhaa'},
|
|
192
|
-
{modelID: 'TS0504B', manufacturerName: '_TZ3210_bfvybixd'},
|
|
194
|
+
{modelID: 'TS0504B', manufacturerName: '_TZ3210_bfvybixd'},
|
|
195
|
+
{modelID: 'TS0504B', manufacturerName: '_TZ3210_sroezl0s'},
|
|
196
|
+
{modelID: 'TS0504B', manufacturerName: '_TZ3210_1elppmba'}],
|
|
193
197
|
model: 'TS0504B',
|
|
194
198
|
vendor: 'TuYa',
|
|
195
199
|
description: 'Zigbee RGBW light',
|
|
@@ -201,7 +205,8 @@ module.exports = [
|
|
|
201
205
|
fingerprint: [{modelID: 'TS0501B', manufacturerName: '_TZ3000_4whigl8i'},
|
|
202
206
|
{modelID: 'TS0501B', manufacturerName: '_TZ3210_4whigl8i'},
|
|
203
207
|
{modelID: 'TS0501B', manufacturerName: '_TZ3210_9q49basr'},
|
|
204
|
-
{modelID: 'TS0501B', manufacturerName: '_TZ3210_grnwgegn'}
|
|
208
|
+
{modelID: 'TS0501B', manufacturerName: '_TZ3210_grnwgegn'},
|
|
209
|
+
{modelID: 'TS0501B', manufacturerName: '_TZ3210_wuheofsg'}],
|
|
205
210
|
model: 'TS0501B',
|
|
206
211
|
description: 'Zigbee light',
|
|
207
212
|
vendor: 'TuYa',
|
|
@@ -218,9 +223,11 @@ module.exports = [
|
|
|
218
223
|
{modelID: 'TS0202', manufacturerName: '_TZ3000_kmh5qpmb'},
|
|
219
224
|
{modelID: 'TS0202', manufacturerName: '_TYZB01_zwvaj5wy'},
|
|
220
225
|
{modelID: 'TS0202', manufacturerName: '_TZ3000_mcxw5ehu'},
|
|
226
|
+
{modelID: 'TS0202', manufacturerName: '_TZ3000_bsvqrxru'},
|
|
221
227
|
{modelID: 'TS0202', manufacturerName: '_TZ3000_msl6wxk9'},
|
|
222
228
|
{modelID: 'TS0202', manufacturerName: '_TYZB01_tv3wxhcz'},
|
|
223
229
|
{modelID: 'TS0202', manufacturerName: '_TYZB01_hqbdru35'},
|
|
230
|
+
{modelID: 'TS0202', manufacturerName: '_TZ3000_tiwq83wk'},
|
|
224
231
|
{modelID: 'WHD02', manufacturerName: '_TZ3000_hktqahrq'}],
|
|
225
232
|
model: 'TS0202',
|
|
226
233
|
vendor: 'TuYa',
|
|
@@ -501,6 +508,7 @@ module.exports = [
|
|
|
501
508
|
{modelID: 'TS0502B', manufacturerName: '_TZ3210_psgq7ysz'},
|
|
502
509
|
{modelID: 'TS0502B', manufacturerName: '_TZ3000_zw7wr5uo'},
|
|
503
510
|
{modelID: 'TS0502B', manufacturerName: '_TZ3210_pz9zmxjj'},
|
|
511
|
+
{modelID: 'TS0502B', manufacturerName: '_TZ3000_fzwhym79'},
|
|
504
512
|
],
|
|
505
513
|
model: 'TS0502B',
|
|
506
514
|
vendor: 'TuYa',
|
|
@@ -904,7 +912,7 @@ module.exports = [
|
|
|
904
912
|
'Mode of this device, in the `heat` mode the TS0601 will remain continuously heating, i.e. it does not regulate ' +
|
|
905
913
|
'to the desired temperature. If you want TRV to properly regulate the temperature you need to use mode `auto` ' +
|
|
906
914
|
'instead setting the desired temperature.')
|
|
907
|
-
.withLocalTemperatureCalibration(-
|
|
915
|
+
.withLocalTemperatureCalibration(-9, 9, 1, ea.STATE_SET)
|
|
908
916
|
.withAwayMode().withPreset(['schedule', 'manual', 'boost', 'complex', 'comfort', 'eco']),
|
|
909
917
|
e.auto_lock(), e.away_mode(), e.away_preset_days(), e.boost_time(), e.comfort_temperature(), e.eco_temperature(), e.force(),
|
|
910
918
|
e.max_temperature(), e.min_temperature(), e.away_preset_temperature(),
|
|
@@ -1119,7 +1127,8 @@ module.exports = [
|
|
|
1119
1127
|
{
|
|
1120
1128
|
fingerprint: [
|
|
1121
1129
|
{modelID: 'TS011F', manufacturerName: '_TZ3000_hyfvrar3'},
|
|
1122
|
-
{modelID: 'TS011F', manufacturerName: '_TZ3000_cymsnfvf'}
|
|
1130
|
+
{modelID: 'TS011F', manufacturerName: '_TZ3000_cymsnfvf'},
|
|
1131
|
+
{modelID: 'TS011F', manufacturerName: '_TZ3000_bfn1w0mm'}],
|
|
1123
1132
|
model: 'TS011F_plug_2',
|
|
1124
1133
|
description: 'Smart plug (without power monitoring)',
|
|
1125
1134
|
vendor: 'TuYa',
|
|
@@ -1834,9 +1843,29 @@ module.exports = [
|
|
|
1834
1843
|
model: 'ERS-10TZBVK-AA',
|
|
1835
1844
|
vendor: 'TuYa',
|
|
1836
1845
|
description: 'Smart knob',
|
|
1837
|
-
fromZigbee: [
|
|
1838
|
-
|
|
1839
|
-
|
|
1846
|
+
fromZigbee: [
|
|
1847
|
+
fz.command_step, fz.command_toggle, fz.command_move_hue, fz.command_step_color_temperature, fz.command_stop_move_raw,
|
|
1848
|
+
fz.tuya_multi_action, fz.tuya_operation_mode, fz.battery,
|
|
1849
|
+
],
|
|
1850
|
+
toZigbee: [tz.tuya_operation_mode],
|
|
1851
|
+
exposes: [
|
|
1852
|
+
e.action([
|
|
1853
|
+
'toggle', 'brightness_step_up', 'brightness_step_down', 'color_temperature_step_up', 'color_temperature_step_down',
|
|
1854
|
+
'saturation_move', 'hue_move', 'hue_stop', 'single', 'double', 'hold', 'rotate_left', 'rotate_right',
|
|
1855
|
+
]),
|
|
1856
|
+
exposes.numeric('action_step_size', ea.STATE).withValueMin(0).withValueMax(255),
|
|
1857
|
+
exposes.numeric('action_transition_time', ea.STATE).withUnit('s'),
|
|
1858
|
+
exposes.numeric('action_rate', ea.STATE).withValueMin(0).withValueMax(255),
|
|
1859
|
+
e.battery(),
|
|
1860
|
+
exposes.enum('operation_mode', ea.ALL, ['command', 'event']).withDescription(
|
|
1861
|
+
'Operation mode: "command" - for group control, "event" - for clicks'),
|
|
1862
|
+
],
|
|
1863
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
1864
|
+
const endpoint = device.getEndpoint(1);
|
|
1865
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg']);
|
|
1866
|
+
await reporting.batteryPercentageRemaining(endpoint);
|
|
1867
|
+
await endpoint.read('genOnOff', ['tuyaOperationMode']);
|
|
1868
|
+
},
|
|
1840
1869
|
},
|
|
1841
1870
|
{
|
|
1842
1871
|
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_kzm5w4iz'}],
|
package/devices/xiaomi.js
CHANGED
|
@@ -1402,18 +1402,15 @@ 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,
|
|
1407
|
+
fz.xiaomi_power],
|
|
1406
1408
|
exposes: [e.switch(), e.energy(), e.power(), e.device_temperature(), e.power_outage_memory(), e.switch_type()],
|
|
1407
1409
|
toZigbee: [tz.xiaomi_switch_type, tz.on_off, tz.xiaomi_switch_power_outage_memory],
|
|
1408
1410
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
1409
1411
|
const endpoint = device.getEndpoint(1);
|
|
1410
|
-
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', '
|
|
1412
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'genDeviceTempCfg']);
|
|
1411
1413
|
await reporting.onOff(endpoint);
|
|
1412
|
-
// Gives UNSUPPORTED_ATTRIBUTE on reporting.readEletricalMeasurementMultiplierDivisors.
|
|
1413
|
-
await endpoint.read('haElectricalMeasurement', ['acPowerMultiplier', 'acPowerDivisor']);
|
|
1414
|
-
await reporting.readMeteringMultiplierDivisor(endpoint);
|
|
1415
|
-
await reporting.currentSummDelivered(endpoint);
|
|
1416
|
-
await reporting.activePower(endpoint, {min: 5, max: 600, change: 10});
|
|
1417
1414
|
await reporting.deviceTemperature(endpoint);
|
|
1418
1415
|
device.powerSource = 'Mains (single phase)';
|
|
1419
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,25 @@ 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
|
+
},
|
|
105
127
|
];
|
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
|
@@ -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;
|
|
@@ -79,7 +107,7 @@ async function getImageMeta(current, logger, device) {
|
|
|
79
107
|
// For this case additional identification through the modelId is done.
|
|
80
108
|
// In the case of Tuya and Moes, additional identification is carried out through the manufacturerName.
|
|
81
109
|
const image = images.find((i) => i.imageType === imageType && i.manufacturerCode === manufacturerCode &&
|
|
82
|
-
(!i.minFileVersion || current.fileVersion >= i.minFileVersion)
|
|
110
|
+
(!i.minFileVersion || current.fileVersion >= i.minFileVersion) && (!i.maxFileVersion || current.fileVersion <= i.maxFileVersion) &&
|
|
83
111
|
(!i.modelId || i.modelId === modelId) && (!i.manufacturerName || i.manufacturerName.includes(manufacturerName)));
|
|
84
112
|
|
|
85
113
|
assert(image !== undefined, `No image available for imageType '${imageType}'`);
|
|
@@ -88,6 +116,7 @@ async function getImageMeta(current, logger, device) {
|
|
|
88
116
|
fileSize: image.fileSize,
|
|
89
117
|
url: image.url,
|
|
90
118
|
sha512: image.sha512,
|
|
119
|
+
force: image.force,
|
|
91
120
|
};
|
|
92
121
|
}
|
|
93
122
|
|
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/npm-shrinkwrap.json
CHANGED