zigbee-herdsman-converters 14.0.606 → 14.0.609
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 +4 -3
- package/converters/toZigbee.js +16 -15
- package/devices/garza.js +11 -0
- package/devices/moes.js +86 -0
- package/devices/niko.js +1 -2
- package/devices/onesti.js +3 -1
- package/devices/perenio.js +90 -5
- package/devices/qoto.js +113 -0
- package/devices/rtx.js +9 -0
- package/devices/saswell.js +0 -1
- package/devices/tuya.js +9 -12
- package/devices/yale.js +1 -1
- package/package.json +1 -1
package/converters/fromZigbee.js
CHANGED
|
@@ -1540,14 +1540,15 @@ const converters = {
|
|
|
1540
1540
|
// HomeAssistant etc. work the other way round.
|
|
1541
1541
|
// For zigbee-herdsman-converters: open = 100, close = 0
|
|
1542
1542
|
// ubisys J1 will report 255 if lift or tilt positions are not known, so skip that.
|
|
1543
|
-
const
|
|
1543
|
+
const metaInvert = model.meta && model.meta.coverInverted;
|
|
1544
|
+
const invert = metaInvert ? !options.invert_cover : options.invert_cover;
|
|
1544
1545
|
const coverStateFromTilt = model.meta && model.meta.coverStateFromTilt;
|
|
1545
1546
|
if (msg.data.hasOwnProperty('currentPositionLiftPercentage') && msg.data['currentPositionLiftPercentage'] <= 100) {
|
|
1546
1547
|
const value = msg.data['currentPositionLiftPercentage'];
|
|
1547
1548
|
result[postfixWithEndpointName('position', msg, model, meta)] = invert ? value : 100 - value;
|
|
1548
1549
|
if (!coverStateFromTilt) {
|
|
1549
1550
|
result[postfixWithEndpointName('state', msg, model, meta)] =
|
|
1550
|
-
|
|
1551
|
+
metaInvert ? (value === 0 ? 'CLOSE' : 'OPEN') : (value === 100 ? 'CLOSE' : 'OPEN');
|
|
1551
1552
|
}
|
|
1552
1553
|
}
|
|
1553
1554
|
if (msg.data.hasOwnProperty('currentPositionTiltPercentage') && msg.data['currentPositionTiltPercentage'] <= 100) {
|
|
@@ -1555,7 +1556,7 @@ const converters = {
|
|
|
1555
1556
|
result[postfixWithEndpointName('tilt', msg, model, meta)] = invert ? value : 100 - value;
|
|
1556
1557
|
if (coverStateFromTilt) {
|
|
1557
1558
|
result[postfixWithEndpointName('state', msg, model, meta)] =
|
|
1558
|
-
|
|
1559
|
+
metaInvert ? (value === 100 ? 'OPEN' : 'CLOSE') : (value === 0 ? 'OPEN' : 'CLOSE');
|
|
1559
1560
|
}
|
|
1560
1561
|
}
|
|
1561
1562
|
return result;
|
package/converters/toZigbee.js
CHANGED
|
@@ -176,7 +176,7 @@ const converters = {
|
|
|
176
176
|
if (!utils.isInRange(0, meta.mapped.meta.pinCodeCount - 1, user)) throw new Error('user must be in range for device');
|
|
177
177
|
|
|
178
178
|
if (pinCode == null) {
|
|
179
|
-
await entity.command('closuresDoorLock', 'clearPinCode', {'userid': user}, utils.getOptions(meta.mapped));
|
|
179
|
+
await entity.command('closuresDoorLock', 'clearPinCode', {'userid': user}, utils.getOptions(meta.mapped, entity));
|
|
180
180
|
} else {
|
|
181
181
|
if (isNaN(pinCode)) throw new Error('pinCode must be a number');
|
|
182
182
|
const typeLookup = {'unrestricted': 0, 'year_day_schedule': 1, 'week_day_schedule': 2, 'master': 3, 'non_access': 4};
|
|
@@ -187,7 +187,7 @@ const converters = {
|
|
|
187
187
|
'usertype': typeLookup[userType],
|
|
188
188
|
'pincodevalue': pinCode.toString(),
|
|
189
189
|
};
|
|
190
|
-
await entity.command('closuresDoorLock', 'setPinCode', payload, utils.getOptions(meta.mapped));
|
|
190
|
+
await entity.command('closuresDoorLock', 'setPinCode', payload, utils.getOptions(meta.mapped, entity));
|
|
191
191
|
}
|
|
192
192
|
},
|
|
193
193
|
convertGet: async (entity, key, meta) => {
|
|
@@ -235,7 +235,7 @@ const converters = {
|
|
|
235
235
|
'userid': user,
|
|
236
236
|
'userstatus': status,
|
|
237
237
|
},
|
|
238
|
-
utils.getOptions(meta.mapped),
|
|
238
|
+
utils.getOptions(meta.mapped, entity),
|
|
239
239
|
);
|
|
240
240
|
},
|
|
241
241
|
convertGet: async (entity, key, meta) => {
|
|
@@ -3070,24 +3070,24 @@ const converters = {
|
|
|
3070
3070
|
|
|
3071
3071
|
const oldPosition = meta.state.position;
|
|
3072
3072
|
if (value == 100) {
|
|
3073
|
-
await entity.command('closuresWindowCovering', 'upOpen', {}, utils.getOptions(meta.mapped));
|
|
3073
|
+
await entity.command('closuresWindowCovering', 'upOpen', {}, utils.getOptions(meta.mapped, entity));
|
|
3074
3074
|
} else if (value == 0) {
|
|
3075
|
-
await entity.command('closuresWindowCovering', 'downClose', {}, utils.getOptions(meta.mapped));
|
|
3075
|
+
await entity.command('closuresWindowCovering', 'downClose', {}, utils.getOptions(meta.mapped, entity));
|
|
3076
3076
|
} else {
|
|
3077
3077
|
if (oldPosition > value) {
|
|
3078
3078
|
const delta = oldPosition - value;
|
|
3079
3079
|
const mutiplicateur = meta.options.time_open / 100;
|
|
3080
3080
|
const timeBeforeStop = delta * mutiplicateur;
|
|
3081
|
-
await entity.command('closuresWindowCovering', 'downClose', {}, utils.getOptions(meta.mapped));
|
|
3081
|
+
await entity.command('closuresWindowCovering', 'downClose', {}, utils.getOptions(meta.mapped, entity));
|
|
3082
3082
|
await sleepSeconds(timeBeforeStop);
|
|
3083
|
-
await entity.command('closuresWindowCovering', 'stop', {}, utils.getOptions(meta.mapped));
|
|
3083
|
+
await entity.command('closuresWindowCovering', 'stop', {}, utils.getOptions(meta.mapped, entity));
|
|
3084
3084
|
} else if (oldPosition < value) {
|
|
3085
3085
|
const delta = value - oldPosition;
|
|
3086
3086
|
const mutiplicateur = meta.options.time_close / 100;
|
|
3087
3087
|
const timeBeforeStop = delta * mutiplicateur;
|
|
3088
|
-
await entity.command('closuresWindowCovering', 'upOpen', {}, utils.getOptions(meta.mapped));
|
|
3088
|
+
await entity.command('closuresWindowCovering', 'upOpen', {}, utils.getOptions(meta.mapped, entity));
|
|
3089
3089
|
await sleepSeconds(timeBeforeStop);
|
|
3090
|
-
await entity.command('closuresWindowCovering', 'stop', {}, utils.getOptions(meta.mapped));
|
|
3090
|
+
await entity.command('closuresWindowCovering', 'stop', {}, utils.getOptions(meta.mapped, entity));
|
|
3091
3091
|
}
|
|
3092
3092
|
}
|
|
3093
3093
|
|
|
@@ -5545,7 +5545,7 @@ const converters = {
|
|
|
5545
5545
|
scenename = value.name;
|
|
5546
5546
|
}
|
|
5547
5547
|
|
|
5548
|
-
const response = await entity.command('genScenes', 'store', {groupid, sceneid}, utils.getOptions(meta.mapped));
|
|
5548
|
+
const response = await entity.command('genScenes', 'store', {groupid, sceneid}, utils.getOptions(meta.mapped, entity));
|
|
5549
5549
|
|
|
5550
5550
|
if (isGroup) {
|
|
5551
5551
|
if (meta.membersState) {
|
|
@@ -5567,7 +5567,7 @@ const converters = {
|
|
|
5567
5567
|
convertSet: async (entity, key, value, meta) => {
|
|
5568
5568
|
const groupid = entity.constructor.name === 'Group' ? entity.groupID : 0;
|
|
5569
5569
|
const sceneid = value;
|
|
5570
|
-
await entity.command('genScenes', 'recall', {groupid, sceneid}, utils.getOptions(meta.mapped));
|
|
5570
|
+
await entity.command('genScenes', 'recall', {groupid, sceneid}, utils.getOptions(meta.mapped, entity));
|
|
5571
5571
|
|
|
5572
5572
|
const addColorMode = (newState) => {
|
|
5573
5573
|
if (newState.hasOwnProperty('color_temp')) {
|
|
@@ -5736,12 +5736,13 @@ const converters = {
|
|
|
5736
5736
|
* We accept a SUCESS or NOT_FOUND as a result of the remove call.
|
|
5737
5737
|
*/
|
|
5738
5738
|
const removeresp = await entity.command(
|
|
5739
|
-
'genScenes', 'remove', {groupid, sceneid}, utils.getOptions(meta.mapped),
|
|
5739
|
+
'genScenes', 'remove', {groupid, sceneid}, utils.getOptions(meta.mapped, entity),
|
|
5740
5740
|
);
|
|
5741
5741
|
|
|
5742
5742
|
if (isGroup || (removeresp.status === 0 || removeresp.status == 133 || removeresp.status == 139)) {
|
|
5743
5743
|
const response = await entity.command(
|
|
5744
|
-
'genScenes', 'add', {groupid, sceneid, scenename: '', transtime, extensionfieldsets},
|
|
5744
|
+
'genScenes', 'add', {groupid, sceneid, scenename: '', transtime, extensionfieldsets},
|
|
5745
|
+
utils.getOptions(meta.mapped, entity),
|
|
5745
5746
|
);
|
|
5746
5747
|
|
|
5747
5748
|
if (isGroup) {
|
|
@@ -5768,7 +5769,7 @@ const converters = {
|
|
|
5768
5769
|
const groupid = entity.constructor.name === 'Group' ? entity.groupID : 0;
|
|
5769
5770
|
const sceneid = value;
|
|
5770
5771
|
const response = await entity.command(
|
|
5771
|
-
'genScenes', 'remove', {groupid, sceneid}, utils.getOptions(meta.mapped),
|
|
5772
|
+
'genScenes', 'remove', {groupid, sceneid}, utils.getOptions(meta.mapped, entity),
|
|
5772
5773
|
);
|
|
5773
5774
|
const isGroup = entity.constructor.name === 'Group';
|
|
5774
5775
|
if (isGroup) {
|
|
@@ -5790,7 +5791,7 @@ const converters = {
|
|
|
5790
5791
|
convertSet: async (entity, key, value, meta) => {
|
|
5791
5792
|
const groupid = entity.constructor.name === 'Group' ? entity.groupID : 0;
|
|
5792
5793
|
const response = await entity.command(
|
|
5793
|
-
'genScenes', 'removeAll', {groupid}, utils.getOptions(meta.mapped),
|
|
5794
|
+
'genScenes', 'removeAll', {groupid}, utils.getOptions(meta.mapped, entity),
|
|
5794
5795
|
);
|
|
5795
5796
|
const isGroup = entity.constructor.name === 'Group';
|
|
5796
5797
|
if (isGroup) {
|
package/devices/garza.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const extend = require('../lib/extend');
|
|
2
|
+
|
|
3
|
+
module.exports = [
|
|
4
|
+
{
|
|
5
|
+
fingerprint: [{modelID: 'TS0505B', manufacturerName: '_TZ3210_sln7ah6r'}],
|
|
6
|
+
model: 'Garza-Standard-A60',
|
|
7
|
+
vendor: 'Garza Smart',
|
|
8
|
+
description: 'Standard A60 bulb',
|
|
9
|
+
extend: extend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
|
|
10
|
+
},
|
|
11
|
+
];
|
package/devices/moes.js
CHANGED
|
@@ -8,10 +8,78 @@ const extend = require('../lib/extend');
|
|
|
8
8
|
const e = exposes.presets;
|
|
9
9
|
const ea = exposes.access;
|
|
10
10
|
const zosung = require('../lib/zosung');
|
|
11
|
+
const utils = require('../lib/utils');
|
|
11
12
|
const fzZosung = zosung.fzZosung;
|
|
12
13
|
const tzZosung = zosung.tzZosung;
|
|
13
14
|
const ez = zosung.presetsZosung;
|
|
14
15
|
|
|
16
|
+
const fzLocal = {
|
|
17
|
+
ZSEUD: {
|
|
18
|
+
cluster: 'manuSpecificTuya',
|
|
19
|
+
type: ['commandDataResponse', 'commandDataReport'],
|
|
20
|
+
convert: async (model, msg, publish, options, meta) => {
|
|
21
|
+
const result = {};
|
|
22
|
+
for (const dpValue of msg.data.dpValues) {
|
|
23
|
+
const dp = dpValue.dp;
|
|
24
|
+
const value = tuya.getDataValue(dpValue);
|
|
25
|
+
switch (dp) {
|
|
26
|
+
case 1:
|
|
27
|
+
result.state_l1 = value ? 'ON' : 'OFF';
|
|
28
|
+
break;
|
|
29
|
+
case 2:
|
|
30
|
+
result.brightness_l1 = utils.mapNumberRange(value, 0, 1000, 0, 254);
|
|
31
|
+
break;
|
|
32
|
+
case 7:
|
|
33
|
+
result.state_l2 = value ? 'ON' : 'OFF';
|
|
34
|
+
break;
|
|
35
|
+
case 8:
|
|
36
|
+
result.brightness_l2 = utils.mapNumberRange(value, 0, 1000, 0, 254);
|
|
37
|
+
break;
|
|
38
|
+
default:
|
|
39
|
+
meta.logger.warn(`zigbee-herdsman-converters:ZSEUD: NOT RECOGNIZED DP #${dp} with data ${JSON.stringify(dpValue)}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const tzLocal = {
|
|
48
|
+
ZSEUD_state: {
|
|
49
|
+
key: ['state'],
|
|
50
|
+
convertSet: async (entity, key, value, meta) => {
|
|
51
|
+
const lookup = {l1: 1, l2: 7};
|
|
52
|
+
const dp = lookup[meta.endpoint_name];
|
|
53
|
+
await tuya.sendDataPointBool(entity, dp, value === 'ON');
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
ZSEUD_brightness: {
|
|
57
|
+
key: ['brightness'],
|
|
58
|
+
convertSet: async (entity, key, value, meta) => {
|
|
59
|
+
const lookup = {l1: 2, l2: 8};
|
|
60
|
+
const dp = lookup[meta.endpoint_name];
|
|
61
|
+
|
|
62
|
+
if (key == 'brightness') {
|
|
63
|
+
// upscale to 1000
|
|
64
|
+
if (value >= 0 && value <= 254) {
|
|
65
|
+
const newValue = utils.mapNumberRange(value, 0, 254, 0, 1000);
|
|
66
|
+
// Always use same transid as tuya_dimmer_state (https://github.com/Koenkk/zigbee2mqtt/issues/6366)
|
|
67
|
+
if (meta.state[`state_${meta.endpoint_name}`] === 'ON') {
|
|
68
|
+
await tuya.sendDataPointValue(entity, dp, newValue, 'dataRequest', 1);
|
|
69
|
+
} else {
|
|
70
|
+
await tuya.sendDataPoints(entity, [tuya.dpValueFromBool(dp-1, true), tuya.dpValueFromIntValue(dp, newValue)],
|
|
71
|
+
'dataRequest', 1);
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
throw new Error('Dimmer brightness is out of range 0..254');
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
meta.logger.warn(`ZSEUD TZ unsupported key=${key} value=${value}`);
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
|
|
15
83
|
module.exports = [
|
|
16
84
|
{
|
|
17
85
|
fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_cymsnfvf'},
|
|
@@ -284,6 +352,24 @@ module.exports = [
|
|
|
284
352
|
},
|
|
285
353
|
exposes: [e.light_brightness().setAccess('state', ea.STATE_SET).setAccess('brightness', ea.STATE_SET)],
|
|
286
354
|
},
|
|
355
|
+
{
|
|
356
|
+
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_fjjbhx9d'}],
|
|
357
|
+
model: 'ZS-EUD',
|
|
358
|
+
vendor: 'Moes',
|
|
359
|
+
description: '2 gang light dimmer switch',
|
|
360
|
+
fromZigbee: [fzLocal.ZSEUD, fz.ignore_basic_report],
|
|
361
|
+
toZigbee: [tzLocal.ZSEUD_brightness, tzLocal.ZSEUD_state],
|
|
362
|
+
meta: {turnsOffAtBrightness1: true, multiEndpoint: true},
|
|
363
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
364
|
+
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ['genOnOff', 'genLevelCtrl']);
|
|
365
|
+
if (device.getEndpoint(2)) await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ['genOnOff']);
|
|
366
|
+
},
|
|
367
|
+
exposes: [e.light_brightness().withEndpoint('l1').setAccess('state', ea.STATE_SET).setAccess('brightness', ea.STATE_SET),
|
|
368
|
+
e.light_brightness().withEndpoint('l2').setAccess('state', ea.STATE_SET).setAccess('brightness', ea.STATE_SET)],
|
|
369
|
+
endpoint: (device) => {
|
|
370
|
+
return {'l1': 1, 'l2': 1};
|
|
371
|
+
},
|
|
372
|
+
},
|
|
287
373
|
{
|
|
288
374
|
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_e3oitdyu'}],
|
|
289
375
|
model: 'MS-105B',
|
package/devices/niko.js
CHANGED
|
@@ -61,9 +61,8 @@ const local = {
|
|
|
61
61
|
if (!operationModeLookup.hasOwnProperty(value)) {
|
|
62
62
|
throw new Error(`operation_mode was called with an invalid value (${value})`);
|
|
63
63
|
} else {
|
|
64
|
-
const operationModeProperty = `operation_mode${meta.endpoint_name ? `_${meta.endpoint_name}` : ''}`;
|
|
65
64
|
await entity.write('manuSpecificNiko1', {'switchOperationMode': operationModeLookup[value]});
|
|
66
|
-
return {state: {
|
|
65
|
+
return {state: {operation_mode: value.toLowerCase()}};
|
|
67
66
|
}
|
|
68
67
|
},
|
|
69
68
|
convertGet: async (entity, key, meta) => {
|
package/devices/onesti.js
CHANGED
|
@@ -8,7 +8,7 @@ const constants = require('../lib/constants');
|
|
|
8
8
|
|
|
9
9
|
module.exports = [
|
|
10
10
|
{
|
|
11
|
-
zigbeeModel: ['easyCodeTouch_v1', 'EasyCodeTouch'],
|
|
11
|
+
zigbeeModel: ['easyCodeTouch_v1', 'EasyCodeTouch', 'EasyFingerTouch'],
|
|
12
12
|
model: 'easyCodeTouch_v1',
|
|
13
13
|
vendor: 'Onesti Products AS',
|
|
14
14
|
description: 'Zigbee module for EasyAccess code touch series',
|
|
@@ -21,6 +21,8 @@ module.exports = [
|
|
|
21
21
|
await reporting.lockState(endpoint);
|
|
22
22
|
await reporting.batteryPercentageRemaining(endpoint);
|
|
23
23
|
await endpoint.read('closuresDoorLock', ['lockState', 'soundVolume']);
|
|
24
|
+
device.powerSource = 'Battery';
|
|
25
|
+
device.save();
|
|
24
26
|
},
|
|
25
27
|
exposes: [e.lock(), e.battery(), e.sound_volume(),
|
|
26
28
|
e.lock_action_source_name(), e.lock_action_user(),
|
package/devices/perenio.js
CHANGED
|
@@ -59,15 +59,30 @@ const fzPerenio = {
|
|
|
59
59
|
type: ['attributeReport', 'readResponse'],
|
|
60
60
|
convert: (model, msg, publish, options, meta) => {
|
|
61
61
|
const result = {};
|
|
62
|
+
if (msg.data.hasOwnProperty(2)) {
|
|
63
|
+
result['rms_current'] = msg.data[2];
|
|
64
|
+
}
|
|
62
65
|
if (msg.data.hasOwnProperty(3)) {
|
|
63
66
|
result['rms_voltage'] = msg.data[3];
|
|
64
67
|
}
|
|
68
|
+
if (msg.data.hasOwnProperty(4)) {
|
|
69
|
+
result['voltage_min'] = msg.data[4];
|
|
70
|
+
}
|
|
71
|
+
if (msg.data.hasOwnProperty(5)) {
|
|
72
|
+
result['voltage_max'] = msg.data[5];
|
|
73
|
+
}
|
|
65
74
|
if (msg.data.hasOwnProperty(10)) {
|
|
66
75
|
result['active_power'] = msg.data[10];
|
|
67
76
|
}
|
|
77
|
+
if (msg.data.hasOwnProperty(11)) {
|
|
78
|
+
result['power_max'] = msg.data[11];
|
|
79
|
+
}
|
|
68
80
|
if (msg.data.hasOwnProperty(14)) {
|
|
69
81
|
result['consumed_energy'] = msg.data[14];
|
|
70
82
|
}
|
|
83
|
+
if (msg.data.hasOwnProperty(15)) {
|
|
84
|
+
result['consumed_energy_limit'] = msg.data[15];
|
|
85
|
+
}
|
|
71
86
|
if (msg.data.hasOwnProperty(24)) {
|
|
72
87
|
result['rssi'] = msg.data[24];
|
|
73
88
|
}
|
|
@@ -84,6 +99,7 @@ const fzPerenio = {
|
|
|
84
99
|
result['alarm_voltage_min'] = false;
|
|
85
100
|
result['alarm_voltage_max'] = false;
|
|
86
101
|
result['alarm_power_max'] = false;
|
|
102
|
+
result['alarm_consumed_energy'] = false;
|
|
87
103
|
} else {
|
|
88
104
|
if (msg.data[1] & 1) {
|
|
89
105
|
result['alarm_voltage_min'] = true;
|
|
@@ -94,6 +110,9 @@ const fzPerenio = {
|
|
|
94
110
|
if (msg.data[1] & 4) {
|
|
95
111
|
result['alarm_power_max'] = true;
|
|
96
112
|
}
|
|
113
|
+
if (msg.data[1] & 8) {
|
|
114
|
+
result['alarm_consumed_energy'] = true;
|
|
115
|
+
}
|
|
97
116
|
}
|
|
98
117
|
}
|
|
99
118
|
return result;
|
|
@@ -135,15 +154,51 @@ const tzPerenio = {
|
|
|
135
154
|
},
|
|
136
155
|
},
|
|
137
156
|
alarms_reset: {
|
|
138
|
-
key: ['alarm_voltage_min', 'alarm_voltage_max', 'alarm_power_max'],
|
|
157
|
+
key: ['alarm_voltage_min', 'alarm_voltage_max', 'alarm_power_max', 'alarm_consumed_energy'],
|
|
139
158
|
convertSet: async (entity, key, val, meta) => {
|
|
140
159
|
await entity.write(64635, {1: {value: 0, type: 0x20}}, {manufacturerCode: 0x007B});
|
|
141
|
-
return {state: {alarm_voltage_min: false, alarm_voltage_max: false, alarm_power_max: false}};
|
|
160
|
+
return {state: {alarm_voltage_min: false, alarm_voltage_max: false, alarm_power_max: false, alarm_consumed_energy: false}};
|
|
142
161
|
},
|
|
143
162
|
convertGet: async (entity, key, meta) => {
|
|
144
163
|
await entity.read(64635, [1]);
|
|
145
164
|
},
|
|
146
165
|
},
|
|
166
|
+
alarms_limits: {
|
|
167
|
+
key: ['voltage_min', 'voltage_max', 'power_max', 'consumed_energy_limit'],
|
|
168
|
+
convertSet: async (entity, key, val, meta) => {
|
|
169
|
+
switch (key) {
|
|
170
|
+
case 'voltage_min':
|
|
171
|
+
await entity.write(64635, {4: {value: val, type: 0x21}}, {manufacturerCode: 0x007B});
|
|
172
|
+
break;
|
|
173
|
+
case 'voltage_max':
|
|
174
|
+
await entity.write(64635, {5: {value: val, type: 0x21}}, {manufacturerCode: 0x007B});
|
|
175
|
+
break;
|
|
176
|
+
case 'power_max':
|
|
177
|
+
await entity.write(64635, {11: {value: val, type: 0x21}}, {manufacturerCode: 0x007B});
|
|
178
|
+
break;
|
|
179
|
+
case 'consumed_energy_limit':
|
|
180
|
+
await entity.write(64635, {15: {value: val, type: 0x21}}, {manufacturerCode: 0x007B});
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
return {state: {[key]: val}};
|
|
184
|
+
},
|
|
185
|
+
convertGet: async (entity, key, meta) => {
|
|
186
|
+
switch (key) {
|
|
187
|
+
case 'voltage_min':
|
|
188
|
+
await entity.read(64635, [4]);
|
|
189
|
+
break;
|
|
190
|
+
case 'voltage_max':
|
|
191
|
+
await entity.read(64635, [5]);
|
|
192
|
+
break;
|
|
193
|
+
case 'power_max':
|
|
194
|
+
await entity.read(64635, [11]);
|
|
195
|
+
break;
|
|
196
|
+
case 'consumed_energy_limit':
|
|
197
|
+
await entity.read(64635, [15]);
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
},
|
|
147
202
|
on_off_mod: {
|
|
148
203
|
key: ['state', 'on_time', 'off_wait_time'],
|
|
149
204
|
convertSet: async (entity, key, value, meta) => {
|
|
@@ -291,8 +346,8 @@ module.exports = [
|
|
|
291
346
|
model: 'PEHPL0X',
|
|
292
347
|
vendor: 'Perenio',
|
|
293
348
|
description: 'Power link',
|
|
294
|
-
fromZigbee: [fz.on_off, fzPerenio.smart_plug],
|
|
295
|
-
toZigbee: [tzPerenio.on_off_mod, tzPerenio.default_state, tzPerenio.alarms_reset],
|
|
349
|
+
fromZigbee: [fz.on_off, fzPerenio.smart_plug, fz.metering],
|
|
350
|
+
toZigbee: [tzPerenio.on_off_mod, tzPerenio.default_state, tzPerenio.alarms_reset, tzPerenio.alarms_limits],
|
|
296
351
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
297
352
|
const endpoint = device.getEndpoint(1);
|
|
298
353
|
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 64635]);
|
|
@@ -303,7 +358,26 @@ module.exports = [
|
|
|
303
358
|
reportableChange: 0,
|
|
304
359
|
}];
|
|
305
360
|
await endpoint.configureReporting('genOnOff', payload);
|
|
306
|
-
await endpoint.
|
|
361
|
+
await endpoint.configureReporting(64635, [{
|
|
362
|
+
attribute: {ID: 0x000a, type: 0x21},
|
|
363
|
+
minimumReportInterval: 5,
|
|
364
|
+
maximumReportInterval: 60,
|
|
365
|
+
reportableChange: 0,
|
|
366
|
+
}]);
|
|
367
|
+
await endpoint.configureReporting(64635, [{
|
|
368
|
+
attribute: {ID: 0x000e, type: 0x23},
|
|
369
|
+
minimumReportInterval: 5,
|
|
370
|
+
maximumReportInterval: 60,
|
|
371
|
+
reportableChange: 0,
|
|
372
|
+
}]);
|
|
373
|
+
await endpoint.configureReporting(64635, [{
|
|
374
|
+
attribute: {ID: 0x0003, type: 0x21},
|
|
375
|
+
minimumReportInterval: 5,
|
|
376
|
+
maximumReportInterval: 5,
|
|
377
|
+
reportableChange: 0,
|
|
378
|
+
}]);
|
|
379
|
+
await endpoint.read(64635, [0, 1, 2, 3]);
|
|
380
|
+
await endpoint.read(64635, [4, 5, 11, 15]);
|
|
307
381
|
},
|
|
308
382
|
exposes: [
|
|
309
383
|
e.switch(),
|
|
@@ -317,6 +391,17 @@ module.exports = [
|
|
|
317
391
|
.withDescription('Indicates if the alarm is triggered on the voltage rise above the limit, allows to reset alarms'),
|
|
318
392
|
exposes.binary('alarm_power_max', ea.ALL, true, false)
|
|
319
393
|
.withDescription('Indicates if the alarm is triggered on the active power rise above the limit, allows to reset alarms'),
|
|
394
|
+
exposes.binary('alarm_consumed_energy', ea.ALL, true, false)
|
|
395
|
+
.withDescription(
|
|
396
|
+
'Indicates if the alarm is triggered when the consumption energy limit is reached, allows to reset alarms'),
|
|
397
|
+
exposes.numeric('voltage_min', ea.ALL).withValueMin(0).withValueMax(253)
|
|
398
|
+
.withDescription('Minimum allowable voltage limit for alarms.'),
|
|
399
|
+
exposes.numeric('voltage_max', ea.ALL).withValueMin(0).withValueMax(253)
|
|
400
|
+
.withDescription('Maximum allowable voltage limit for alarms.'),
|
|
401
|
+
exposes.numeric('power_max', ea.ALL).withValueMin(0).withValueMax(65534)
|
|
402
|
+
.withDescription('Maximum allowable power limit for alarms.'),
|
|
403
|
+
exposes.numeric('consumed_energy_limit', ea.ALL).withValueMin(0).withValueMax(65534)
|
|
404
|
+
.withDescription('Limit of electric energy consumption in kW*h. 0 value represents no limit'),
|
|
320
405
|
exposes.numeric('rssi', ea.STATE).withUnit('dB')
|
|
321
406
|
.withDescription('RSSI seen by the device').withValueMin(-128).withValueMax(127),
|
|
322
407
|
],
|
package/devices/qoto.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
const fz = require('../converters/fromZigbee');
|
|
2
|
+
const exposes = require('../lib/exposes');
|
|
3
|
+
const tuya = require('../lib/tuya');
|
|
4
|
+
const e = exposes.presets;
|
|
5
|
+
const ea = exposes.access;
|
|
6
|
+
|
|
7
|
+
const dataPoints = {
|
|
8
|
+
valve_state_auto_shutdown: 2,
|
|
9
|
+
water_flow: 3,
|
|
10
|
+
shutdown_timer: 11,
|
|
11
|
+
remaining_watering_time: 101,
|
|
12
|
+
valve_state: 102,
|
|
13
|
+
last_watering_duration: 107,
|
|
14
|
+
battery: 110,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const fzLocal = {
|
|
18
|
+
watering_timer: {
|
|
19
|
+
cluster: 'manuSpecificTuya',
|
|
20
|
+
type: ['commandDataReport'],
|
|
21
|
+
convert: (model, msg, publish, options, meta) => {
|
|
22
|
+
const result = {};
|
|
23
|
+
for (const dpValue of msg.data.dpValues) {
|
|
24
|
+
const dp = dpValue.dp; // First we get the data point ID
|
|
25
|
+
const value = tuya.getDataValue(dpValue); // This function will take care of converting the data to proper JS type
|
|
26
|
+
switch (dp) {
|
|
27
|
+
case dataPoints.water_flow: {
|
|
28
|
+
result.water_flow = value;
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
case dataPoints.remaining_watering_time: {
|
|
32
|
+
result.remaining_watering_time = value;
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
case dataPoints.last_watering_duration: {
|
|
36
|
+
result.last_watering_duration = value;
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
case dataPoints.valve_state: {
|
|
41
|
+
result.valve_state = value;
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
case dataPoints.shutdown_timer: {
|
|
46
|
+
result.shutdown_timer = value;
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
case dataPoints.valve_state_auto_shutdown: {
|
|
50
|
+
result.valve_state_auto_shutdown = value;
|
|
51
|
+
result.valve_state = value;
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
case dataPoints.battery: {
|
|
56
|
+
result.battery = value;
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
default: {
|
|
60
|
+
meta.logger.debug(`>>> UNKNOWN DP #${dp} with data "${JSON.stringify(dpValue)}"`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return result;
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const tzLocal = {
|
|
70
|
+
valve_state: {
|
|
71
|
+
key: ['valve_state'],
|
|
72
|
+
convertSet: async (entity, key, value, meta) => {
|
|
73
|
+
await tuya.sendDataPointValue(entity, dataPoints.valve_state, value);
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
shutdown_timer: {
|
|
77
|
+
key: ['shutdown_timer'],
|
|
78
|
+
convertSet: async (entity, key, value, meta) => {
|
|
79
|
+
await tuya.sendDataPointValue(entity, dataPoints.shutdown_timer, value);
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
valve_state_auto_shutdown: {
|
|
83
|
+
key: ['valve_state_auto_shutdown'],
|
|
84
|
+
convertSet: async (entity, key, value, meta) => {
|
|
85
|
+
await tuya.sendDataPointValue(entity, dataPoints.valve_state_auto_shutdown, value);
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
module.exports = [
|
|
91
|
+
{
|
|
92
|
+
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_arge1ptm'}],
|
|
93
|
+
model: 'QT-05M',
|
|
94
|
+
vendor: 'QOTO',
|
|
95
|
+
description: 'Solar powered garden watering timer',
|
|
96
|
+
fromZigbee: [fz.ignore_basic_report, fz.ignore_tuya_set_time, fz.ignore_onoff_report, fzLocal.watering_timer],
|
|
97
|
+
toZigbee: [tzLocal.valve_state, tzLocal.shutdown_timer, tzLocal.valve_state_auto_shutdown],
|
|
98
|
+
exposes: [
|
|
99
|
+
exposes.numeric('water_flow', ea.STATE).withUnit('%').withValueMin(0).withDescription('Current water flow in %.'),
|
|
100
|
+
exposes.numeric('last_watering_duration', ea.STATE).withUnit('sec').withValueMin(0)
|
|
101
|
+
.withDescription('Last watering duration in seconds.'),
|
|
102
|
+
exposes.numeric('remaining_watering_time', ea.STATE).withUnit('sec').withValueMin(0)
|
|
103
|
+
.withDescription('Remaning watering time (for auto shutdown). Updates every minute, and every 10s in the last minute.'),
|
|
104
|
+
exposes.numeric('valve_state', ea.STATE_SET).withValueMin(0).withValueMax(100).withValueStep(5).withUnit('%')
|
|
105
|
+
.withDescription('Set valve to %.'),
|
|
106
|
+
exposes.numeric('shutdown_timer', ea.STATE_SET).withValueMin(0).withValueMax(14400).withUnit('sec')
|
|
107
|
+
.withDescription('Auto shutdown in seconds.'),
|
|
108
|
+
exposes.numeric('valve_state_auto_shutdown', ea.STATE_SET).withValueMin(0).withValueMax(100).withValueStep(5).withUnit('%')
|
|
109
|
+
.withDescription('Set valve to % with auto shutdown.'),
|
|
110
|
+
e.battery(),
|
|
111
|
+
],
|
|
112
|
+
},
|
|
113
|
+
];
|
package/devices/rtx.js
CHANGED
|
@@ -76,4 +76,13 @@ module.exports = [
|
|
|
76
76
|
'MoTu..= active weekdays ' +
|
|
77
77
|
'1 = deactivate timer with 0)')],
|
|
78
78
|
},
|
|
79
|
+
{
|
|
80
|
+
fingerprint: [{modelID: 'TS0202', manufacturerName: '_TZ3000_mwd3c2at'}],
|
|
81
|
+
model: 'ZMS4',
|
|
82
|
+
vendor: 'RTX',
|
|
83
|
+
description: 'Zigbee PIR sensor',
|
|
84
|
+
fromZigbee: [fz.ias_occupancy_alarm_1],
|
|
85
|
+
toZigbee: [],
|
|
86
|
+
exposes: [e.battery_low(), e.occupancy()],
|
|
87
|
+
},
|
|
79
88
|
];
|
package/devices/saswell.js
CHANGED
|
@@ -16,7 +16,6 @@ module.exports = [
|
|
|
16
16
|
{modelID: 'TS0601', manufacturerName: '_TZE200_c88teujp'},
|
|
17
17
|
{modelID: 'TS0601', manufacturerName: '_TZE200_yw7cahqs'},
|
|
18
18
|
{modelID: 'TS0601', manufacturerName: '_TZE200_azqp6ssj'},
|
|
19
|
-
{modelID: 'TS0601', manufacturerName: '_TZE200_bvu2wnxz'},
|
|
20
19
|
{modelID: 'TS0601', manufacturerName: '_TZE200_zuhszj9s'},
|
|
21
20
|
{modelID: 'TS0601', manufacturerName: '_TZE200_9gvruqf5'},
|
|
22
21
|
{modelID: 'TS0601', manufacturerName: '_TZE200_zr9c0day'},
|
package/devices/tuya.js
CHANGED
|
@@ -20,19 +20,13 @@ const TS011Fplugs = ['_TZ3000_5f43h46b', '_TZ3000_cphmq0q7', '_TZ3000_dpo1ysak',
|
|
|
20
20
|
'_TZ3000_rdtixbnu', '_TZ3000_typdpbpg', '_TZ3000_kx0pris5', '_TZ3000_amdymr7l', '_TZ3000_z1pnpsdo', '_TZ3000_ksw8qtmt',
|
|
21
21
|
'_TZ3000_1h2x4akh', '_TZ3000_9vo5icau', '_TZ3000_cehuw1lw', '_TZ3000_ko6v90pg', '_TZ3000_f1bapcit', '_TZ3000_cjrngdr3',
|
|
22
22
|
'_TZ3000_zloso4jk', '_TZ3000_r6buo8ba', '_TZ3000_iksasdbv', '_TZ3000_idrffznf', '_TZ3000_okaz9tjs', '_TZ3210_q7oryllx',
|
|
23
|
-
'_TZ3000_ss98ec5d', '_TZ3000_gznh2xla'];
|
|
23
|
+
'_TZ3000_ss98ec5d', '_TZ3000_gznh2xla', '_TZ3000_hdopuwv6'];
|
|
24
24
|
|
|
25
25
|
const tzLocal = {
|
|
26
26
|
hpsz: {
|
|
27
27
|
key: ['led_state'],
|
|
28
28
|
convertSet: async (entity, key, value, meta) => {
|
|
29
|
-
|
|
30
|
-
case 'led_state': {
|
|
31
|
-
const ledState = value.toUpperCase() === 'ON' ? true : false;
|
|
32
|
-
await tuya.sendDataPointBool(entity, tuya.dataPoints.HPSZLEDState, ledState);
|
|
33
|
-
return {led_state: value};
|
|
34
|
-
}
|
|
35
|
-
}
|
|
29
|
+
await tuya.sendDataPointBool(entity, tuya.dataPoints.HPSZLEDState, value);
|
|
36
30
|
},
|
|
37
31
|
},
|
|
38
32
|
TS0504B_color: {
|
|
@@ -302,7 +296,7 @@ const fzLocal = {
|
|
|
302
296
|
result = {duration_of_absence: value};
|
|
303
297
|
break;
|
|
304
298
|
case tuya.dataPoints.HPSZLEDState:
|
|
305
|
-
result = {
|
|
299
|
+
result = {led_state: value};
|
|
306
300
|
break;
|
|
307
301
|
default:
|
|
308
302
|
meta.logger.warn(`zigbee-herdsman-converters:hpsz: NOT RECOGNIZED DP #${
|
|
@@ -631,7 +625,7 @@ module.exports = [
|
|
|
631
625
|
fromZigbee: [fz.ias_contact_alarm_1, fz.battery, fz.ignore_basic_report, fz.ias_contact_alarm_1_report],
|
|
632
626
|
toZigbee: [],
|
|
633
627
|
exposes: [e.contact(), e.battery_low(), e.tamper(), e.battery(), e.battery_voltage()],
|
|
634
|
-
whiteLabel: [{vendor: 'CR Smart Home', model: 'TS0203'}],
|
|
628
|
+
whiteLabel: [{vendor: 'CR Smart Home', model: 'TS0203'}, {vendor: 'TuYa', model: 'iH-F001'}],
|
|
635
629
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
636
630
|
try {
|
|
637
631
|
const endpoint = device.getEndpoint(1);
|
|
@@ -892,7 +886,8 @@ module.exports = [
|
|
|
892
886
|
{modelID: 'TS0501B', manufacturerName: '_TZ3210_nehayyhx'},
|
|
893
887
|
{modelID: 'TS0501B', manufacturerName: '_TZ3210_wuheofsg'},
|
|
894
888
|
{modelID: 'TS0501B', manufacturerName: '_TZ3210_e5t9bfdv'},
|
|
895
|
-
{modelID: 'TS0501B', manufacturerName: '_TZ3210_19qb27da'}
|
|
889
|
+
{modelID: 'TS0501B', manufacturerName: '_TZ3210_19qb27da'},
|
|
890
|
+
{modelID: 'TS0501B', manufacturerName: '_TZ3210_4zinq6io'}],
|
|
896
891
|
model: 'TS0501B',
|
|
897
892
|
description: 'Zigbee light',
|
|
898
893
|
vendor: 'TuYa',
|
|
@@ -914,6 +909,7 @@ module.exports = [
|
|
|
914
909
|
{modelID: 'TS0202', manufacturerName: '_TYZB01_ef5xlc9q'},
|
|
915
910
|
{modelID: 'TS0202', manufacturerName: '_TYZB01_vwqnz1sn'},
|
|
916
911
|
{modelID: 'TS0202', manufacturerName: '_TYZB01_2b8f6cio'},
|
|
912
|
+
{modelID: 'TS0202', manufacturerName: '_TYZB01_71kfvvma'},
|
|
917
913
|
{modelID: 'TS0202', manufacturerName: '_TZE200_bq5c8xfe'},
|
|
918
914
|
{modelID: 'TS0202', manufacturerName: '_TYZB01_dl7cejts'},
|
|
919
915
|
{modelID: 'TS0202', manufacturerName: '_TYZB01_qjqgmqxr'},
|
|
@@ -1691,6 +1687,7 @@ module.exports = [
|
|
|
1691
1687
|
{modelID: 'TS0601', manufacturerName: '_TZE200_tvrvdj6o'},
|
|
1692
1688
|
{modelID: 'zo2pocs\u0000', manufacturerName: '_TYST11_fzo2pocs'},
|
|
1693
1689
|
{modelID: 'TS0601', manufacturerName: '_TZE200_cf1sl3tj'},
|
|
1690
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_b2u1drdv'},
|
|
1694
1691
|
// Roller blinds:
|
|
1695
1692
|
{modelID: 'TS0601', manufacturerName: '_TZE200_fctwhugx'},
|
|
1696
1693
|
{modelID: 'TS0601', manufacturerName: '_TZE200_zah67ekd'},
|
|
@@ -3135,7 +3132,7 @@ module.exports = [
|
|
|
3135
3132
|
.withDescription('Shows the presence duration in minutes'),
|
|
3136
3133
|
exposes.numeric('duration_of_absence', ea.STATE).withUnit('minutes')
|
|
3137
3134
|
.withDescription('Shows the duration of the absence in minutes'),
|
|
3138
|
-
exposes.
|
|
3135
|
+
exposes.binary('led_state', ea.STATE_SET, true, false)
|
|
3139
3136
|
.withDescription('Turns the onboard LED on or off'),
|
|
3140
3137
|
],
|
|
3141
3138
|
},
|
package/devices/yale.js
CHANGED
|
@@ -55,7 +55,7 @@ module.exports = [
|
|
|
55
55
|
vendor: 'Yale',
|
|
56
56
|
description: 'Real living lock / Intelligent biometric digital lock',
|
|
57
57
|
// Increased timeout needed: https://github.com/Koenkk/zigbee2mqtt/issues/3290 for YDM4109+
|
|
58
|
-
extend: lockExtend({timeout: 20000}),
|
|
58
|
+
extend: lockExtend({battery: {dontDividePercentage: true}}, {timeout: 20000}),
|
|
59
59
|
},
|
|
60
60
|
{
|
|
61
61
|
zigbeeModel: ['YRD210 PB DB'],
|