zigbee-herdsman-converters 14.0.264 → 14.0.268
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 +42 -1
- package/converters/toZigbee.js +34 -33
- package/devices/climax.js +10 -0
- package/devices/develco.js +4 -2
- package/devices/neo.js +1 -1
- package/devices/onesti.js +8 -4
- package/devices/philips.js +18 -0
- package/devices/saswell.js +1 -0
- package/devices/the_light_group.js +24 -0
- package/devices/tuya.js +35 -0
- package/lib/constants.js +38 -0
- package/lib/exposes.js +1 -1
- package/lib/utils.js +27 -2
- package/npm-shrinkwrap.json +1 -1
- package/package.json +1 -1
package/converters/fromZigbee.js
CHANGED
|
@@ -2517,6 +2517,18 @@ const converters = {
|
|
|
2517
2517
|
}
|
|
2518
2518
|
},
|
|
2519
2519
|
},
|
|
2520
|
+
easycodetouch_action: {
|
|
2521
|
+
cluster: 'closuresDoorLock',
|
|
2522
|
+
type: 'raw',
|
|
2523
|
+
convert: (model, msg, publish, options, meta) => {
|
|
2524
|
+
const value = constants.easyCodeTouchActions[(msg.data[3] << 8) | msg.data[4]];
|
|
2525
|
+
if (value) {
|
|
2526
|
+
return {action: value};
|
|
2527
|
+
} else {
|
|
2528
|
+
meta.logger.log('Unknown lock status with source ' + msg.data[3] + ' and event code ' + msg.data[4]);
|
|
2529
|
+
}
|
|
2530
|
+
},
|
|
2531
|
+
},
|
|
2520
2532
|
livolo_switch_state_raw: {
|
|
2521
2533
|
cluster: 'genPowerCfg',
|
|
2522
2534
|
type: ['raw'],
|
|
@@ -3757,6 +3769,16 @@ const converters = {
|
|
|
3757
3769
|
});
|
|
3758
3770
|
},
|
|
3759
3771
|
},
|
|
3772
|
+
tuya_switch_type: {
|
|
3773
|
+
cluster: 'manuSpecificTuya_3',
|
|
3774
|
+
type: ['attributeReport', 'readResponse'],
|
|
3775
|
+
convert: (model, msg, publish, options, meta) => {
|
|
3776
|
+
const lookup = {0: 'toggle', 1: 'state', 2: 'momentary'};
|
|
3777
|
+
if (msg.data.hasOwnProperty('switchType')) {
|
|
3778
|
+
return {switch_type: lookup[msg.data['switchType']]};
|
|
3779
|
+
}
|
|
3780
|
+
},
|
|
3781
|
+
},
|
|
3760
3782
|
restorable_brightness: {
|
|
3761
3783
|
cluster: 'genLevelCtrl',
|
|
3762
3784
|
type: ['attributeReport', 'readResponse'],
|
|
@@ -6059,6 +6081,18 @@ const converters = {
|
|
|
6059
6081
|
}
|
|
6060
6082
|
},
|
|
6061
6083
|
},
|
|
6084
|
+
ias_keypad: {
|
|
6085
|
+
cluster: 'ssIasZone',
|
|
6086
|
+
type: 'commandStatusChangeNotification',
|
|
6087
|
+
convert: (model, msg, publish, options, meta) => {
|
|
6088
|
+
const zoneStatus = msg.data.zonestatus;
|
|
6089
|
+
return {
|
|
6090
|
+
tamper: (zoneStatus & 1<<2) > 0,
|
|
6091
|
+
battery_low: (zoneStatus & 1<<3) > 0,
|
|
6092
|
+
restore_reports: (zoneStatus & 1<<5) > 0,
|
|
6093
|
+
};
|
|
6094
|
+
},
|
|
6095
|
+
},
|
|
6062
6096
|
ubisys_dimmer_setup: {
|
|
6063
6097
|
cluster: 'manuSpecificUbisysDimmerSetup',
|
|
6064
6098
|
type: ['attributeReport', 'readResponse'],
|
|
@@ -6509,8 +6543,15 @@ const converters = {
|
|
|
6509
6543
|
convert: (model, msg, publish, options, meta) => {
|
|
6510
6544
|
const result = {};
|
|
6511
6545
|
if (0x8000 in msg.data) {
|
|
6512
|
-
|
|
6546
|
+
const firmware = msg.data[0x8000].join('.');
|
|
6547
|
+
result.current_firmware = firmware;
|
|
6548
|
+
msg.device.zhDevice.softwareBuildID = firmware;
|
|
6513
6549
|
}
|
|
6550
|
+
|
|
6551
|
+
if (0x8020 in msg.data) {
|
|
6552
|
+
msg.device.zhDevice.hardwareVersion = msg.data[0x8020].join('.');
|
|
6553
|
+
}
|
|
6554
|
+
|
|
6514
6555
|
return result;
|
|
6515
6556
|
},
|
|
6516
6557
|
},
|
package/converters/toZigbee.js
CHANGED
|
@@ -2869,6 +2869,19 @@ const converters = {
|
|
|
2869
2869
|
return {state: {state: value.toUpperCase()}};
|
|
2870
2870
|
},
|
|
2871
2871
|
},
|
|
2872
|
+
tuya_switch_type: {
|
|
2873
|
+
key: ['switch_type'],
|
|
2874
|
+
convertSet: async (entity, key, value, meta) => {
|
|
2875
|
+
value = value.toLowerCase();
|
|
2876
|
+
const lookup = {'toggle': 0, 'state': 1, 'momentary': 2};
|
|
2877
|
+
utils.validateValue(value, Object.keys(lookup));
|
|
2878
|
+
await entity.write('manuSpecificTuya_3', {'switchType': lookup[value]}, {disableDefaultResponse: true});
|
|
2879
|
+
return {state: {switch_type: value}};
|
|
2880
|
+
},
|
|
2881
|
+
convertGet: async (entity, key, meta) => {
|
|
2882
|
+
await entity.read('manuSpecificTuya_3', ['switchType']);
|
|
2883
|
+
},
|
|
2884
|
+
},
|
|
2872
2885
|
frankever_threshold: {
|
|
2873
2886
|
key: ['threshold'],
|
|
2874
2887
|
convertSet: async (entity, key, value, meta) => {
|
|
@@ -4612,17 +4625,23 @@ const converters = {
|
|
|
4612
4625
|
convertSet: async (entity, key, value, meta) => {
|
|
4613
4626
|
const isGroup = entity.constructor.name === 'Group';
|
|
4614
4627
|
const groupid = isGroup ? entity.groupID : 0;
|
|
4615
|
-
|
|
4628
|
+
let sceneid = value;
|
|
4629
|
+
let scenename = null;
|
|
4630
|
+
if (typeof value === 'object') {
|
|
4631
|
+
sceneid = value.ID;
|
|
4632
|
+
scenename = value.name;
|
|
4633
|
+
}
|
|
4634
|
+
|
|
4616
4635
|
const response = await entity.command('genScenes', 'store', {groupid, sceneid}, utils.getOptions(meta.mapped));
|
|
4617
4636
|
|
|
4618
4637
|
if (isGroup) {
|
|
4619
4638
|
if (meta.membersState) {
|
|
4620
4639
|
for (const member of entity.members) {
|
|
4621
|
-
utils.saveSceneState(member, sceneid, groupid, meta.membersState[member.getDevice().ieeeAddr]);
|
|
4640
|
+
utils.saveSceneState(member, sceneid, groupid, meta.membersState[member.getDevice().ieeeAddr], scenename);
|
|
4622
4641
|
}
|
|
4623
4642
|
}
|
|
4624
4643
|
} else if (response.status === 0) {
|
|
4625
|
-
utils.saveSceneState(entity, sceneid, groupid, meta.state);
|
|
4644
|
+
utils.saveSceneState(entity, sceneid, groupid, meta.state, scenename);
|
|
4626
4645
|
} else {
|
|
4627
4646
|
throw new Error(`Scene add not succesfull ('${herdsman.Zcl.Status[response.status]}')`);
|
|
4628
4647
|
}
|
|
@@ -4652,15 +4671,11 @@ const converters = {
|
|
|
4652
4671
|
};
|
|
4653
4672
|
|
|
4654
4673
|
const isGroup = entity.constructor.name === 'Group';
|
|
4655
|
-
const metaKey = `${sceneid}_${groupid}`;
|
|
4656
4674
|
if (isGroup) {
|
|
4657
4675
|
const membersState = {};
|
|
4658
4676
|
for (const member of entity.members) {
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
let recalledState = member.meta.scenes[metaKey].state;
|
|
4663
|
-
|
|
4677
|
+
let recalledState = utils.getSceneState(member, sceneid, groupid);
|
|
4678
|
+
if (recalledState) {
|
|
4664
4679
|
// add color_mode if saved state does not contain it
|
|
4665
4680
|
if (!recalledState.hasOwnProperty('color_mode')) {
|
|
4666
4681
|
recalledState = addColorMode(recalledState);
|
|
@@ -4675,9 +4690,8 @@ const converters = {
|
|
|
4675
4690
|
}
|
|
4676
4691
|
return {membersState};
|
|
4677
4692
|
} else {
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4693
|
+
let recalledState = utils.getSceneState(entity, sceneid, groupid);
|
|
4694
|
+
if (recalledState) {
|
|
4681
4695
|
// add color_mode if saved state does not contain it
|
|
4682
4696
|
if (!recalledState.hasOwnProperty('color_mode')) {
|
|
4683
4697
|
recalledState = addColorMode(recalledState);
|
|
@@ -4711,7 +4725,7 @@ const converters = {
|
|
|
4711
4725
|
const isGroup = entity.constructor.name === 'Group';
|
|
4712
4726
|
const groupid = isGroup ? entity.groupID : 0;
|
|
4713
4727
|
const sceneid = value.ID;
|
|
4714
|
-
const scenename =
|
|
4728
|
+
const scenename = value.name;
|
|
4715
4729
|
const transtime = value.hasOwnProperty('transition') ? value.transition : 0;
|
|
4716
4730
|
|
|
4717
4731
|
const state = {};
|
|
@@ -4813,17 +4827,17 @@ const converters = {
|
|
|
4813
4827
|
|
|
4814
4828
|
if (isGroup || (removeresp.status === 0 || removeresp.status == 133 || removeresp.status == 139)) {
|
|
4815
4829
|
const response = await entity.command(
|
|
4816
|
-
'genScenes', 'add', {groupid, sceneid, scenename, transtime, extensionfieldsets}, utils.getOptions(meta.mapped),
|
|
4830
|
+
'genScenes', 'add', {groupid, sceneid, scenename: '', transtime, extensionfieldsets}, utils.getOptions(meta.mapped),
|
|
4817
4831
|
);
|
|
4818
4832
|
|
|
4819
4833
|
if (isGroup) {
|
|
4820
4834
|
if (meta.membersState) {
|
|
4821
4835
|
for (const member of entity.members) {
|
|
4822
|
-
utils.saveSceneState(member, sceneid, groupid, state);
|
|
4836
|
+
utils.saveSceneState(member, sceneid, groupid, state, scenename);
|
|
4823
4837
|
}
|
|
4824
4838
|
}
|
|
4825
4839
|
} else if (response.status === 0) {
|
|
4826
|
-
utils.saveSceneState(entity, sceneid, groupid, state);
|
|
4840
|
+
utils.saveSceneState(entity, sceneid, groupid, state, scenename);
|
|
4827
4841
|
} else {
|
|
4828
4842
|
throw new Error(`Scene add not succesfull ('${herdsman.Zcl.Status[response.status]}')`);
|
|
4829
4843
|
}
|
|
@@ -4844,21 +4858,14 @@ const converters = {
|
|
|
4844
4858
|
);
|
|
4845
4859
|
|
|
4846
4860
|
const isGroup = entity.constructor.name === 'Group';
|
|
4847
|
-
const metaKey = `${sceneid}_${groupid}`;
|
|
4848
4861
|
if (isGroup) {
|
|
4849
4862
|
if (meta.membersState) {
|
|
4850
4863
|
for (const member of entity.members) {
|
|
4851
|
-
|
|
4852
|
-
delete member.meta.scenes[metaKey];
|
|
4853
|
-
member.save();
|
|
4854
|
-
}
|
|
4864
|
+
utils.deleteSceneState(member, sceneid, groupid);
|
|
4855
4865
|
}
|
|
4856
4866
|
}
|
|
4857
4867
|
} else if (response.status === 0) {
|
|
4858
|
-
|
|
4859
|
-
delete entity.meta.scenes[metaKey];
|
|
4860
|
-
entity.save();
|
|
4861
|
-
}
|
|
4868
|
+
utils.deleteSceneState(entity, sceneid, groupid);
|
|
4862
4869
|
} else {
|
|
4863
4870
|
throw new Error(`Scene remove not succesfull ('${herdsman.Zcl.Status[response.status]}')`);
|
|
4864
4871
|
}
|
|
@@ -4876,17 +4883,11 @@ const converters = {
|
|
|
4876
4883
|
if (isGroup) {
|
|
4877
4884
|
if (meta.membersState) {
|
|
4878
4885
|
for (const member of entity.members) {
|
|
4879
|
-
|
|
4880
|
-
member.meta.scenes = {};
|
|
4881
|
-
member.save();
|
|
4882
|
-
}
|
|
4886
|
+
utils.deleteSceneState(member);
|
|
4883
4887
|
}
|
|
4884
4888
|
}
|
|
4885
4889
|
} else if (response.status === 0) {
|
|
4886
|
-
|
|
4887
|
-
entity.meta.scenes = {};
|
|
4888
|
-
entity.save();
|
|
4889
|
-
}
|
|
4890
|
+
utils.deleteSceneState(entity);
|
|
4890
4891
|
} else {
|
|
4891
4892
|
throw new Error(`Scene remove all not succesfull ('${herdsman.Zcl.Status[response.status]}')`);
|
|
4892
4893
|
}
|
package/devices/climax.js
CHANGED
|
@@ -111,4 +111,14 @@ module.exports = [
|
|
|
111
111
|
toZigbee: [],
|
|
112
112
|
exposes: [e.carbon_monoxide(), e.battery_low(), e.tamper(), e.battery()],
|
|
113
113
|
},
|
|
114
|
+
{
|
|
115
|
+
zigbeeModel: ['KP-ACE_00.00.03.12TC'],
|
|
116
|
+
model: 'KP-23EL-ZBS-ACE',
|
|
117
|
+
vendor: 'Climax',
|
|
118
|
+
description: 'Remote Keypad',
|
|
119
|
+
fromZigbee: [fz.ias_keypad, fz.battery, fz.command_arm, fz.command_panic, fz.command_emergency],
|
|
120
|
+
toZigbee: [],
|
|
121
|
+
exposes: [e.battery_low(), e.tamper(), e.action(['emergency', 'panic', 'disarm', 'arm_all_zones', 'arm_day_zones']),
|
|
122
|
+
],
|
|
123
|
+
},
|
|
114
124
|
];
|
package/devices/develco.js
CHANGED
|
@@ -112,11 +112,13 @@ module.exports = [
|
|
|
112
112
|
model: 'EMIZB-132',
|
|
113
113
|
vendor: 'Develco',
|
|
114
114
|
description: 'Wattle AMS HAN power-meter sensor',
|
|
115
|
-
fromZigbee: [fz.metering, fz.electrical_measurement],
|
|
115
|
+
fromZigbee: [fz.metering, fz.electrical_measurement, fz.develco_fw],
|
|
116
116
|
toZigbee: [tz.EMIZB_132_mode],
|
|
117
117
|
ota: ota.zigbeeOTA,
|
|
118
118
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
119
119
|
const endpoint = device.getEndpoint(2);
|
|
120
|
+
const options = {manufacturerCode: 4117};
|
|
121
|
+
await endpoint.read('genBasic', [0x8000, 0x8010, 0x8020], options);
|
|
120
122
|
await reporting.bind(endpoint, coordinatorEndpoint, ['haElectricalMeasurement', 'seMetering']);
|
|
121
123
|
|
|
122
124
|
try {
|
|
@@ -162,7 +164,7 @@ module.exports = [
|
|
|
162
164
|
|
|
163
165
|
await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg', 'ssIasZone', 'ssIasWd', 'genBasic', 'genBinaryInput']);
|
|
164
166
|
await reporting.batteryVoltage(endpoint);
|
|
165
|
-
await endpoint.read('genBasic', [0x8000], options);
|
|
167
|
+
await endpoint.read('genBasic', [0x8000, 0x8010, 0x8020], options);
|
|
166
168
|
await endpoint.read('ssIasZone', ['iasCieAddr', 'zoneState', 'zoneId']);
|
|
167
169
|
await endpoint.read('genBinaryInput', ['reliability', 'statusFlags']);
|
|
168
170
|
await endpoint.read('ssIasWd', ['maxDuration']);
|
package/devices/neo.js
CHANGED
|
@@ -36,7 +36,7 @@ module.exports = [
|
|
|
36
36
|
fromZigbee: [fz.neo_nas_pd07],
|
|
37
37
|
toZigbee: [],
|
|
38
38
|
onEvent: tuya.setTime,
|
|
39
|
-
exposes: [e.occupancy(), e.humidity(), e.temperature(), e.tamper(),
|
|
39
|
+
exposes: [e.occupancy(), e.humidity(), e.temperature(), e.tamper(), e.battery_low(),
|
|
40
40
|
exposes.enum('power_type', ea.STATE, ['battery_full', 'battery_high', 'battery_medium', 'battery_low', 'usb'])],
|
|
41
41
|
},
|
|
42
42
|
];
|
package/devices/onesti.js
CHANGED
|
@@ -12,8 +12,9 @@ module.exports = [
|
|
|
12
12
|
model: 'easyCodeTouch_v1',
|
|
13
13
|
vendor: 'Onesti Products AS',
|
|
14
14
|
description: 'Zigbee module for EasyAccess code touch series',
|
|
15
|
-
fromZigbee: [fz.lock, fz.lock_operation_event, fz.battery, fz.lock_programming_event],
|
|
16
|
-
toZigbee: [tz.lock, tz.lock_sound_volume],
|
|
15
|
+
fromZigbee: [fz.lock, fz.lock_operation_event, fz.battery, fz.lock_programming_event, fz.easycodetouch_action],
|
|
16
|
+
toZigbee: [tz.lock, tz.easycode_auto_relock, tz.lock_sound_volume, tz.pincode_lock],
|
|
17
|
+
meta: {pinCodeCount: 50},
|
|
17
18
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
18
19
|
const endpoint = device.getEndpoint(11);
|
|
19
20
|
await reporting.bind(endpoint, coordinatorEndpoint, ['closuresDoorLock', 'genPowerCfg']);
|
|
@@ -21,8 +22,11 @@ module.exports = [
|
|
|
21
22
|
await reporting.batteryPercentageRemaining(endpoint);
|
|
22
23
|
await endpoint.read('closuresDoorLock', ['lockState', 'soundVolume']);
|
|
23
24
|
},
|
|
24
|
-
exposes: [e.lock(), e.battery(),
|
|
25
|
-
|
|
25
|
+
exposes: [e.lock(), e.battery(), e.sound_volume(),
|
|
26
|
+
e.action(Array.from(Object.values(constants.easyCodeTouchActions))),
|
|
27
|
+
exposes.binary('auto_relock', ea.STATE_SET, true, false).withDescription('Auto relock after 7 seconds.'),
|
|
28
|
+
e.pincode(),
|
|
29
|
+
],
|
|
26
30
|
},
|
|
27
31
|
{
|
|
28
32
|
zigbeeModel: ['S4RX-110'],
|
package/devices/philips.js
CHANGED
|
@@ -1813,6 +1813,15 @@ module.exports = [
|
|
|
1813
1813
|
meta: {turnsOffAtBrightness1: true},
|
|
1814
1814
|
extend: hueExtend.light_onoff_brightness(),
|
|
1815
1815
|
},
|
|
1816
|
+
{
|
|
1817
|
+
zigbeeModel: ['LTV002'],
|
|
1818
|
+
model: '929002477901',
|
|
1819
|
+
vendor: 'Philips',
|
|
1820
|
+
description: 'Hue white filament Edison ST72 E27 LED warm-to-cool',
|
|
1821
|
+
ota: ota.zigbeeOTA,
|
|
1822
|
+
meta: {turnsOffAtBrightness1: true},
|
|
1823
|
+
extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [222, 454]}),
|
|
1824
|
+
},
|
|
1816
1825
|
{
|
|
1817
1826
|
zigbeeModel: ['LWV002'],
|
|
1818
1827
|
model: '046677551780',
|
|
@@ -2038,4 +2047,13 @@ module.exports = [
|
|
|
2038
2047
|
extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 500]}),
|
|
2039
2048
|
ota: ota.zigbeeOTA,
|
|
2040
2049
|
},
|
|
2050
|
+
{
|
|
2051
|
+
zigbeeModel: ['LTV001'],
|
|
2052
|
+
model: '92900244777',
|
|
2053
|
+
vendor: 'Philips',
|
|
2054
|
+
description: 'Hue White Ambiance E27 ST64 filament bulb',
|
|
2055
|
+
extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [222, 454]}),
|
|
2056
|
+
meta: {turnsOffAtBrightness1: true},
|
|
2057
|
+
ota: ota.zigbeeOTA,
|
|
2058
|
+
},
|
|
2041
2059
|
];
|
package/devices/saswell.js
CHANGED
|
@@ -17,6 +17,7 @@ module.exports = [
|
|
|
17
17
|
{modelID: 'TS0601', manufacturerName: '_TZE200_yw7cahqs'},
|
|
18
18
|
{modelID: 'TS0601', manufacturerName: '_TZE200_azqp6ssj'},
|
|
19
19
|
{modelID: 'TS0601', manufacturerName: '_TZE200_zuhszj9s'},
|
|
20
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_9gvruqf5'},
|
|
20
21
|
],
|
|
21
22
|
model: 'SEA801-Zigbee/SEA802-Zigbee',
|
|
22
23
|
vendor: 'Saswell',
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const exposes = require('../lib/exposes');
|
|
2
|
+
const fz = {...require('../converters/fromZigbee'), legacy: require('../lib/legacy').fromZigbee};
|
|
3
|
+
const e = exposes.presets;
|
|
4
|
+
|
|
5
|
+
module.exports = [
|
|
6
|
+
{
|
|
7
|
+
zigbeeModel: ['S57003'],
|
|
8
|
+
model: 'S57003',
|
|
9
|
+
vendor: 'The Light Group',
|
|
10
|
+
description: 'SLC SmartOne Zigbee wall remote 4-channels',
|
|
11
|
+
fromZigbee: [fz.command_on, fz.command_off, fz.battery, fz.command_move, fz.command_stop],
|
|
12
|
+
exposes: [e.battery(), e.action([
|
|
13
|
+
'on_l1', 'off_l1', 'brightness_move_up_l1', 'brightness_move_down_l1', 'brightness_stop_l1',
|
|
14
|
+
'on_l2', 'off_l2', 'brightness_move_up_l2', 'brightness_move_down_l2', 'brightness_stop_l2',
|
|
15
|
+
'on_l3', 'off_l3', 'brightness_move_up_l3', 'brightness_move_down_l3', 'brightness_stop_l3',
|
|
16
|
+
'on_l4', 'off_l4', 'brightness_move_up_l4', 'brightness_move_down_l4', 'brightness_stop_l4',
|
|
17
|
+
])],
|
|
18
|
+
toZigbee: [],
|
|
19
|
+
meta: {multiEndpoint: true},
|
|
20
|
+
endpoint: (device) => {
|
|
21
|
+
return {l1: 1, l2: 2, l3: 3, l4: 4};
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
];
|
package/devices/tuya.js
CHANGED
|
@@ -585,6 +585,40 @@ module.exports = [
|
|
|
585
585
|
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ['genOnOff']);
|
|
586
586
|
},
|
|
587
587
|
},
|
|
588
|
+
{
|
|
589
|
+
fingerprint: [{modelID: 'TS0001', manufacturerName: '_TZ3000_tqlv4ug4'}],
|
|
590
|
+
model: 'TS0001_switch_module',
|
|
591
|
+
vendor: 'TuYa',
|
|
592
|
+
description: '1 gang switch module',
|
|
593
|
+
whiteLabel: [{vendor: 'OXT', model: 'SWTZ21'}],
|
|
594
|
+
toZigbee: extend.switch().toZigbee.concat([tz.moes_power_on_behavior, tz.tuya_switch_type]),
|
|
595
|
+
fromZigbee: extend.switch().fromZigbee.concat([fz.moes_power_on_behavior, fz.tuya_switch_type]),
|
|
596
|
+
exposes: extend.switch().exposes.concat([exposes.presets.power_on_behavior(),
|
|
597
|
+
exposes.enum('switch_type', ea.ALL, ['toggle', 'state', 'momentary'])
|
|
598
|
+
.withDescription('Switch type settings')]),
|
|
599
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
600
|
+
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ['genOnOff']);
|
|
601
|
+
},
|
|
602
|
+
},
|
|
603
|
+
{
|
|
604
|
+
fingerprint: [{modelID: 'TS0002', manufacturerName: '_TZ3000_01gpyda5'}],
|
|
605
|
+
model: 'TS0002_switch_module',
|
|
606
|
+
vendor: 'TuYa',
|
|
607
|
+
description: '2 gang switch module',
|
|
608
|
+
whiteLabel: [{vendor: 'OXT', model: 'SWTZ22'}],
|
|
609
|
+
toZigbee: extend.switch().toZigbee.concat([tz.moes_power_on_behavior, tz.tuya_switch_type]),
|
|
610
|
+
fromZigbee: extend.switch().fromZigbee.concat([fz.moes_power_on_behavior, fz.tuya_switch_type]),
|
|
611
|
+
exposes: [e.switch().withEndpoint('l1'), e.switch().withEndpoint('l2'), exposes.presets.power_on_behavior(),
|
|
612
|
+
exposes.enum('switch_type', ea.ALL, ['toggle', 'state', 'momentary']).withDescription('Switch type settings')],
|
|
613
|
+
endpoint: (device) => {
|
|
614
|
+
return {'l1': 1, 'l2': 2};
|
|
615
|
+
},
|
|
616
|
+
meta: {multiEndpoint: true},
|
|
617
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
618
|
+
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ['genOnOff']);
|
|
619
|
+
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ['genOnOff']);
|
|
620
|
+
},
|
|
621
|
+
},
|
|
588
622
|
{
|
|
589
623
|
zigbeeModel: [
|
|
590
624
|
'owvfni3\u0000', 'owvfni3', 'u1rkty3', 'aabybja', // Curtain motors
|
|
@@ -827,6 +861,7 @@ module.exports = [
|
|
|
827
861
|
const interval = setInterval(async () => {
|
|
828
862
|
try {
|
|
829
863
|
await endpoint.read('haElectricalMeasurement', ['rmsVoltage', 'rmsCurrent', 'activePower']);
|
|
864
|
+
await endpoint.read('seMetering', ['currentSummDelivered']);
|
|
830
865
|
} catch (error) {/* Do nothing*/}
|
|
831
866
|
}, seconds*1000);
|
|
832
867
|
globalStore.putValue(device, 'interval', interval);
|
package/lib/constants.js
CHANGED
|
@@ -147,6 +147,43 @@ const lockUserStatus = {
|
|
|
147
147
|
3: 'disabled',
|
|
148
148
|
};
|
|
149
149
|
|
|
150
|
+
const easyCodeTouchActions = {
|
|
151
|
+
// First byte are source / msg.data[3]
|
|
152
|
+
// 0x00 KeyPad: If the user uses the code panel.
|
|
153
|
+
// 0x02 Manual: If the user used a key, button or fingerprint.
|
|
154
|
+
// 0x03 RFID: If the user used an RFID tag.
|
|
155
|
+
// 0xFF Other: If the user used an unknown method
|
|
156
|
+
|
|
157
|
+
// Last byte are eventCode / msg.data[4]
|
|
158
|
+
// 0x00 Lock: The device was locked using either button, code panel or RFID.
|
|
159
|
+
// 0x01 Unlock: The device was unlocked using either button, code panel or RFID.
|
|
160
|
+
// 0x08 Key Lock: If the user locked with a key.
|
|
161
|
+
// 0x09 Key Unlock: If the user unlocked with a key.
|
|
162
|
+
// 0x10 Fingerprint Lock: The device was locked using fingerprint.
|
|
163
|
+
// 0x11 Fingerprint Unlock: The device was unlocked using fingerprint.
|
|
164
|
+
|
|
165
|
+
0x0000: 'keypad_lock',
|
|
166
|
+
0x0001: 'keypad_unlock',
|
|
167
|
+
|
|
168
|
+
// Manual says 0x0001 but the lock sends 0x0002 when you unlock it using the keypad
|
|
169
|
+
0x0002: 'keypad_unlock',
|
|
170
|
+
|
|
171
|
+
0x0200: 'manual_lock',
|
|
172
|
+
0x0201: 'manual_unlock',
|
|
173
|
+
|
|
174
|
+
0x0208: 'key_lock',
|
|
175
|
+
0x0209: 'key_unlock',
|
|
176
|
+
|
|
177
|
+
0x0210: 'fingerprint_lock',
|
|
178
|
+
0x0211: 'fingerprint_unlock',
|
|
179
|
+
|
|
180
|
+
0x0300: 'rfid_lock',
|
|
181
|
+
0x0301: 'rfid_unlock',
|
|
182
|
+
|
|
183
|
+
0xFF0D: 'lock',
|
|
184
|
+
0xFF0E: 'zigbee_unlock',
|
|
185
|
+
};
|
|
186
|
+
|
|
150
187
|
module.exports = {
|
|
151
188
|
OneJanuary2000,
|
|
152
189
|
repInterval,
|
|
@@ -166,4 +203,5 @@ module.exports = {
|
|
|
166
203
|
colorMode,
|
|
167
204
|
lockSoundVolume,
|
|
168
205
|
lockUserStatus,
|
|
206
|
+
easyCodeTouchActions,
|
|
169
207
|
};
|
package/lib/exposes.js
CHANGED
|
@@ -469,7 +469,7 @@ module.exports = {
|
|
|
469
469
|
child_lock: () => new Lock().withState('child_lock', 'LOCK', 'UNLOCK', 'Enables/disables physical input on the device', access.STATE_SET),
|
|
470
470
|
co2: () => new Numeric('co2', access.STATE).withUnit('ppm').withDescription('The measured CO2 (carbon dioxide) value'),
|
|
471
471
|
comfort_temperature: () => new Numeric('comfort_temperature', access.STATE_SET).withUnit('°C').withDescription('Comfort temperature'),
|
|
472
|
-
consumer_connected: () => new Binary('consumer_connected', access.STATE, true, false).withDescription('Indicates whether
|
|
472
|
+
consumer_connected: () => new Binary('consumer_connected', access.STATE, true, false).withDescription('Indicates whether a plug is physically attached. Device does not have to pull power or even be connected electrically (state of this binary switch can be ON even if main power switch is OFF)'),
|
|
473
473
|
contact: () => new Binary('contact', access.STATE, false, true).withDescription('Indicates if the contact is closed (= true) or open (= false)'),
|
|
474
474
|
cover_position: () => new Cover().withPosition(),
|
|
475
475
|
cover_position_tilt: () => new Cover().withPosition().withTilt(),
|
package/lib/utils.js
CHANGED
|
@@ -271,14 +271,37 @@ function toCamelCase(value) {
|
|
|
271
271
|
}
|
|
272
272
|
}
|
|
273
273
|
|
|
274
|
-
function saveSceneState(entity, sceneID, groupID, state) {
|
|
274
|
+
function saveSceneState(entity, sceneID, groupID, state, name) {
|
|
275
275
|
const attributes = ['state', 'brightness', 'color', 'color_temp', 'color_mode'];
|
|
276
276
|
if (!entity.meta.hasOwnProperty('scenes')) entity.meta.scenes = {};
|
|
277
277
|
const metaKey = `${sceneID}_${groupID}`;
|
|
278
|
-
entity.meta.scenes[metaKey] = {state: filterObject(state, attributes)};
|
|
278
|
+
entity.meta.scenes[metaKey] = {name, state: filterObject(state, attributes)};
|
|
279
279
|
entity.save();
|
|
280
280
|
}
|
|
281
281
|
|
|
282
|
+
function deleteSceneState(entity, sceneID=null, groupID=null) {
|
|
283
|
+
if (entity.meta.scenes) {
|
|
284
|
+
if (sceneID == null && groupID == null) {
|
|
285
|
+
entity.meta.scenes = {};
|
|
286
|
+
} else {
|
|
287
|
+
const metaKey = `${sceneID}_${groupID}`;
|
|
288
|
+
if (entity.meta.scenes.hasOwnProperty(metaKey)) {
|
|
289
|
+
delete entity.meta.scenes[metaKey];
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
entity.save();
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function getSceneState(entity, sceneID, groupID) {
|
|
297
|
+
const metaKey = `${sceneID}_${groupID}`;
|
|
298
|
+
if (entity.meta.hasOwnProperty('scenes') && entity.meta.scenes.hasOwnProperty(metaKey)) {
|
|
299
|
+
return entity.meta.scenes[metaKey].state;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
|
|
282
305
|
function getEntityOrFirstGroupMember(entity) {
|
|
283
306
|
if (entity.constructor.name === 'Group') {
|
|
284
307
|
return entity.members.length > 0 ? entity.members[0] : null;
|
|
@@ -381,4 +404,6 @@ module.exports = {
|
|
|
381
404
|
toSnakeCase,
|
|
382
405
|
toCamelCase,
|
|
383
406
|
normalizeCelsiusVersionOfFahrenheit,
|
|
407
|
+
deleteSceneState,
|
|
408
|
+
getSceneState,
|
|
384
409
|
};
|
package/npm-shrinkwrap.json
CHANGED