zigbee-herdsman-converters 15.0.91 → 15.0.93

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/devices/bosch.js CHANGED
@@ -4,7 +4,6 @@ const fz = require('../converters/fromZigbee');
4
4
  const tz = require('../converters/toZigbee');
5
5
  const reporting = require('../lib/reporting');
6
6
  const utils = require('../lib/utils');
7
- const extend = require('../lib/extend');
8
7
  const constants = require('../lib/constants');
9
8
  const ota = require('../lib/ota');
10
9
  const e = exposes.presets;
@@ -13,6 +12,26 @@ const ea = exposes.access;
13
12
  // Radiator Thermostat II
14
13
  const boschManufacturer = {manufacturerCode: 0x1209};
15
14
 
15
+ // BMCT
16
+ const stateDeviceType = {
17
+ 'light': 0x04,
18
+ 'shutter': 0x01,
19
+ };
20
+ // BMCT
21
+ const stateMotor = {
22
+ 'idle': 0x00,
23
+ 'opening': 0x02,
24
+ 'closing': 0x01,
25
+ };
26
+ // BMCT
27
+ const stateSwitchType = {
28
+ 'button': 0x01,
29
+ 'button_key_change': 0x02,
30
+ 'rocker_switch': 0x03,
31
+ 'rocker_rwitch_key_change': 0x04,
32
+ };
33
+
34
+
16
35
  // Twinguard
17
36
  const smokeSensitivity = {
18
37
  'low': 3,
@@ -55,6 +74,84 @@ const displayedTemperature = {
55
74
 
56
75
  // Radiator Thermostat II
57
76
  const tzLocal = {
77
+ bmct: {
78
+ key: [
79
+ 'device_type',
80
+ 'switch_type',
81
+ 'child_lock', 'child_lock_left', 'child_lock_right',
82
+ 'calibration_closing_time', 'calibration_opening_time',
83
+ 'state',
84
+ ],
85
+ convertSet: async (entity, key, value, meta) => {
86
+ if (key === 'state') {
87
+ const state = value.toLowerCase();
88
+ utils.validateValue(state, ['toggle', 'off', 'on', 'open', 'close', 'stop']);
89
+ if ( state === 'on' || state === 'off' || state === 'toggle') {
90
+ await entity.command('genOnOff', state, {}, utils.getOptions(meta.mapped, entity));
91
+ if (state === 'toggle') {
92
+ const currentState = meta.state[`state${meta.endpoint_name ? `_${meta.endpoint_name}` : ''}`];
93
+ return currentState ? {state: {state: currentState === 'OFF' ? 'ON' : 'OFF'}} : {};
94
+ } else {
95
+ return {state: {state: state.toUpperCase()}};
96
+ }
97
+ } else if ( state === 'open' || state === 'close' || state === 'stop') {
98
+ const lookup = {'open': 'upOpen', 'close': 'downClose', 'stop': 'stop', 'on': 'upOpen', 'off': 'downClose'};
99
+ value = value.toLowerCase();
100
+ utils.validateValue(value, Object.keys(lookup));
101
+ await entity.command('closuresWindowCovering', lookup[value], {}, utils.getOptions(meta.mapped, entity));
102
+ }
103
+ }
104
+ if (key === 'device_type') {
105
+ const index = stateDeviceType[value];
106
+ await entity.write(0xFCA0, {0x0000: {value: index, type: 0x30}}, boschManufacturer);
107
+ return {state: {device_type: value}};
108
+ }
109
+ if (key === 'switch_type') {
110
+ const index = stateSwitchType[value];
111
+ await entity.write(0xFCA0, {0x0001: {value: index, type: 0x30}}, boschManufacturer);
112
+ return {state: {switch_type: value}};
113
+ }
114
+ if (key === 'child_lock') {
115
+ const index = stateOffOn[value];
116
+ await entity.write(0xFCA0, {0x0008: {value: index, type: 0x10}}, boschManufacturer);
117
+ return {state: {child_lock: value}};
118
+ }
119
+ if (key === 'calibration_closing_time') {
120
+ const index = value *10;
121
+ await entity.write(0xFCA0, {0x0002: {value: index, type: 0x23}}, boschManufacturer);
122
+ return {state: {calibration_closing_time: value}};
123
+ }
124
+ if (key === 'calibration_opening_time') {
125
+ const index = value *10;
126
+ await entity.write(0xFCA0, {0x0003: {value: index, type: 0x23}}, boschManufacturer);
127
+ return {state: {calibration_opening_time: value}};
128
+ }
129
+ },
130
+ convertGet: async (entity, key, meta) => {
131
+ switch (key) {
132
+ case 'state':
133
+ await entity.read('genOnOff', ['onOff']);
134
+ break;
135
+ case 'device_type':
136
+ await entity.read(0xFCA0, [0x0000], boschManufacturer);
137
+ break;
138
+ case 'switch_type':
139
+ await entity.read(0xFCA0, [0x0001], boschManufacturer);
140
+ break;
141
+ case 'child_lock':
142
+ await entity.read(0xFCA0, [0x0008], boschManufacturer);
143
+ break;
144
+ case 'calibration_closing_time':
145
+ await entity.read(0xFCA0, [0x0002], boschManufacturer);
146
+ break;
147
+ case 'calibration_opening_time':
148
+ await entity.read(0xFCA0, [0x0003], boschManufacturer);
149
+ break;
150
+ default: // Unknown key
151
+ throw new Error(`Unhandled key toZigbee.bcmt.convertGet ${key}`);
152
+ }
153
+ },
154
+ },
58
155
  bwa1: {
59
156
  key: ['alarm_on_motion', 'test'],
60
157
  convertSet: async (entity, key, value, meta) => {
@@ -256,6 +353,27 @@ const tzLocal = {
256
353
 
257
354
 
258
355
  const fzLocal = {
356
+ bmct: {
357
+ cluster: '64672',
358
+ type: ['attributeReport', 'readResponse'],
359
+ options: [],
360
+ convert: (model, msg, publish, options, meta) => {
361
+ const result = {};
362
+ const data = msg.data;
363
+ if (data.hasOwnProperty(0x0000)) {
364
+ result.device_type = (Object.keys(stateDeviceType)[msg.data[0x0000]]);
365
+ } else if (data.hasOwnProperty(0x0001)) {
366
+ result.switch_type = (Object.keys(stateSwitchType)[msg.data[0x0001]]);
367
+ } else if (data.hasOwnProperty(0x0002)) {
368
+ result.calibration_closing_time = msg.data[0x0002];
369
+ } else if (data.hasOwnProperty(0x0003)) {
370
+ result.calibration_opening_time = msg.data[0x0003];
371
+ } else if (data.hasOwnProperty(0x0013)) {
372
+ result.motor_state = (Object.keys(stateMotor)[msg.data[0x0013]]);
373
+ }
374
+ return result;
375
+ },
376
+ },
259
377
  bwa1_alarm_on_motion: {
260
378
  cluster: '64684',
261
379
  type: ['attributeReport', 'readResponse'],
@@ -742,27 +860,51 @@ const definition = [
742
860
  zigbeeModel: ['RBSH-MMS-ZB-EU'],
743
861
  model: 'BMCT-SLZ',
744
862
  vendor: 'Bosch',
745
- description: 'Light/shutter control II',
746
- extend: extend.switch(),
747
- exposes: [e.switch().withEndpoint('l1'), e.switch().withEndpoint('l2')],
863
+ description: 'Bosch Light/shutter control unit II',
864
+ fromZigbee: [fzLocal.bmct, fz.cover_position_tilt, fz.on_off, fz.power_on_behavior],
865
+ toZigbee: [tzLocal.bmct, tz.cover_position_tilt, tz.on_off, tz.power_on_behavior],
866
+ meta: {multiEndpoint: true},
748
867
  endpoint: (device) => {
749
- return {'l1': 2, 'l2': 3};
868
+ return {'left': 2, 'right': 3};
750
869
  },
751
- meta: {multiEndpoint: true},
752
870
  configure: async (device, coordinatorEndpoint, logger) => {
753
- // Configuration values:
754
- // 0x0000 0x0001
755
- // Roller Shutter 1 3
756
- // Window Blind 2 3
757
- // Light Switch 4 3
758
-
759
- // Configure device as dual switch.
760
- // Device will perform a rejoin after this write
761
- await device.getEndpoint(1).write(0xfca0, {0x0000: {value: 0x04, type: 0x30}, 0x0001: {value: 0x03, type: 0x30}});
762
-
763
- await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ['genOnOff']);
764
- await reporting.bind(device.getEndpoint(3), coordinatorEndpoint, ['genOnOff']);
871
+ const endpoint1 = device.getEndpoint(1);
872
+ await reporting.bind(endpoint1, coordinatorEndpoint, ['genIdentify', 'closuresWindowCovering', 64672]);
873
+ await endpoint1.unbind('genOnOff', coordinatorEndpoint);
874
+ await endpoint1.read(64672, [0x0000, 0x0001, 0x0002, 0x0003, 0x0008, 0x0013], boschManufacturer);
875
+ const endpoint2 = device.getEndpoint(2);
876
+ await endpoint2.read(64672, [0x0008], boschManufacturer);
877
+ await reporting.bind(endpoint2, coordinatorEndpoint, ['genIdentify', 'genOnOff']);
878
+ await reporting.onOff(endpoint2);
879
+ const endpoint3 = device.getEndpoint(3);
880
+ await endpoint3.read(64672, [0x0008], boschManufacturer);
881
+ await reporting.bind(endpoint3, coordinatorEndpoint, ['genIdentify', 'genOnOff']);
882
+ await reporting.onOff(endpoint3);
765
883
  },
884
+ exposes: [
885
+ // light
886
+ exposes.enum('device_type', ea.ALL, Object.keys(stateDeviceType))
887
+ .withDescription('Device type: '),
888
+ exposes.enum('switch_type', ea.ALL, Object.keys(stateSwitchType))
889
+ .withDescription('Module controlled by a rocker switch or a button'),
890
+ e.switch().withEndpoint('left'),
891
+ e.switch().withEndpoint('right'),
892
+ e.power_on_behavior().withEndpoint('right'),
893
+ e.power_on_behavior().withEndpoint('left'),
894
+ exposes.binary('child_lock', ea.ALL, 'ON', 'OFF').withEndpoint('left')
895
+ .withDescription('Enable/Disable child lock'),
896
+ exposes.binary('child_lock', ea.ALL, 'ON', 'OFF').withEndpoint('right')
897
+ .withDescription('Enable/Disable child lock'),
898
+ // cover
899
+ e.cover_position().setAccess('state', ea.ALL),
900
+ exposes.enum('motor_state', ea.STATE, Object.keys(stateMotor))
901
+ .withDescription('Shutter motor actual state '),
902
+ exposes.binary('child_lock', ea.ALL, 'ON', 'OFF').withDescription('Enable/Disable child lock'),
903
+ exposes.numeric('calibration_closing_time', ea.ALL).withUnit('S')
904
+ .withDescription('Calibration opening time').withValueMin(1).withValueMax(90),
905
+ exposes.numeric('calibration_opening_time', ea.ALL).withUnit('S')
906
+ .withDescription('Calibration closing time').withValueMin(1).withValueMax(90),
907
+ ],
766
908
  },
767
909
  ];
768
910
 
package/devices/climax.js CHANGED
@@ -82,14 +82,14 @@ module.exports = [
82
82
  vendor: 'Climax',
83
83
  description: 'Smart siren',
84
84
  fromZigbee: [fz.battery, fz.ias_wd, fz.ias_enroll, fz.ias_siren],
85
- toZigbee: [tz.warning_simple, tz.ias_max_duration, tz.warning],
85
+ toZigbee: [tz.warning_simple, tz.ias_max_duration, tz.warning, tz.squawk],
86
86
  configure: async (device, coordinatorEndpoint, logger) => {
87
87
  const endpoint = device.getEndpoint(1);
88
88
  await reporting.bind(endpoint, coordinatorEndpoint, ['genBasic', 'ssIasZone', 'ssIasWd']);
89
89
  await endpoint.read('ssIasZone', ['zoneState', 'iasCieAddr', 'zoneId']);
90
90
  await endpoint.read('ssIasWd', ['maxDuration']);
91
91
  },
92
- exposes: [e.battery_low(), e.tamper(), e.warning(),
92
+ exposes: [e.battery_low(), e.tamper(), e.warning(), e.squawk(),
93
93
  exposes.numeric('max_duration', ea.ALL).withUnit('s').withValueMin(0).withValueMax(600).withDescription('Duration of Siren'),
94
94
  exposes.binary('alarm', ea.SET, 'START', 'OFF').withDescription('Manual start of siren')],
95
95
  },
@@ -24,6 +24,24 @@ module.exports = [
24
24
  exposes: [
25
25
  e.lock(), e.battery(), e.auto_relock_time().withValueMin(0).withValueMax(3600), e.sound_volume()],
26
26
  },
27
+ {
28
+ zigbeeModel: ['HT-SLM-2'],
29
+ model: 'HT-SLM-2',
30
+ vendor: 'Heimgard Technologies',
31
+ description: 'Doorlock with fingerprint',
32
+ fromZigbee: [fz.lock, fz.battery, fz.lock_pin_code_response, fz.lock_user_status_response],
33
+ toZigbee: [tz.lock, tz.lock_sound_volume, tz.identify, tz.pincode_lock, tz.lock_userstatus],
34
+ meta: {pinCodeCount: 39},
35
+ ota: ota.zigbeeOTA,
36
+ configure: async (device, coordinatorEndpoint, logger) => {
37
+ const endpoint = device.getEndpoint(1);
38
+ await reporting.bind(endpoint, coordinatorEndpoint, ['closuresDoorLock', 'genPowerCfg']);
39
+ await reporting.lockState(endpoint);
40
+ await reporting.batteryPercentageRemaining(endpoint);
41
+ await endpoint.read('closuresDoorLock', ['lockState', 'soundVolume']);
42
+ },
43
+ exposes: [e.lock(), e.pincode(), e.battery(), e.sound_volume()],
44
+ },
27
45
  {
28
46
  zigbeeModel: ['HC-IWDIM-1'],
29
47
  model: 'HC-IWDIM-1',
package/devices/namron.js CHANGED
@@ -481,13 +481,6 @@ module.exports = [
481
481
  await reporting.thermostatUnoccupiedHeatingSetpoint(endpoint);
482
482
  await reporting.thermostatKeypadLockMode(endpoint);
483
483
 
484
- await endpoint.configureReporting('hvacThermostat', [{
485
- attribute: 'occupancy',
486
- minimumReportInterval: 0,
487
- maximumReportInterval: constants.repInterval.HOUR,
488
- reportableChange: null,
489
- }]);
490
-
491
484
  // Metering
492
485
  await endpoint.read('haElectricalMeasurement', ['acVoltageMultiplier', 'acVoltageDivisor', 'acCurrentMultiplier']);
493
486
  await endpoint.read('haElectricalMeasurement', ['acCurrentDivisor']);
package/devices/niko.js CHANGED
@@ -1,6 +1,7 @@
1
1
  const exposes = require('../lib/exposes');
2
2
  const fz = {...require('../converters/fromZigbee'), legacy: require('../lib/legacy').fromZigbee};
3
3
  const tz = require('../converters/toZigbee');
4
+ const utils = require('../lib/utils');
4
5
  const reporting = require('../lib/reporting');
5
6
  const e = exposes.presets;
6
7
  const ea = exposes.access;
@@ -13,9 +14,8 @@ const local = {
13
14
  convert: (model, msg, publish, options, meta) => {
14
15
  const state = {};
15
16
  if (msg.data.hasOwnProperty('switchOperationMode')) {
16
- const operationModeProperty = `operation_mode${meta.endpoint_name ? `_${meta.endpoint_name}` : ''}`;
17
17
  const operationModeMap = {0x02: 'control_relay', 0x01: 'decoupled', 0x00: 'unknown'};
18
- state[operationModeProperty] = operationModeMap[msg.data.switchOperationMode];
18
+ state['operation_mode'] = operationModeMap[msg.data.switchOperationMode];
19
19
  }
20
20
  return state;
21
21
  },
@@ -29,9 +29,22 @@ const local = {
29
29
  if (msg.data.hasOwnProperty('switchAction')) {
30
30
  // NOTE: a single press = two seperate values reported, 16 followed by 64
31
31
  // a hold/release cyle = three seperate values, 16, 32, and 48
32
- const actionProperty = `action${meta.endpoint_name ? `_${meta.endpoint_name}` : ''}`;
33
- const actionMap = {16: null, 64: 'single', 32: 'hold', 48: 'release'};
34
- state[actionProperty] = actionMap[msg.data.switchAction];
32
+ const actionMap = (model.model == '552-721X1') ? {
33
+ 16: null,
34
+ 64: 'single',
35
+ 32: 'hold',
36
+ 48: 'release',
37
+ } : {
38
+ 16: null,
39
+ 64: 'single_left',
40
+ 32: 'hold_left',
41
+ 48: 'release_left',
42
+ 4096: 'single_right',
43
+ 8192: 'hold_right',
44
+ 12288: 'release_right',
45
+ };
46
+
47
+ state['action'] = actionMap[msg.data.switchAction];
35
48
  }
36
49
  return state;
37
50
  },
@@ -75,12 +88,18 @@ const local = {
75
88
  if (!operationModeLookup.hasOwnProperty(value)) {
76
89
  throw new Error(`operation_mode was called with an invalid value (${value})`);
77
90
  } else {
78
- await entity.write('manuSpecificNiko1', {'switchOperationMode': operationModeLookup[value]});
91
+ await utils.enforceEndpoint(entity, key, meta).write(
92
+ 'manuSpecificNiko1',
93
+ {'switchOperationMode': operationModeLookup[value]},
94
+ );
79
95
  return {state: {operation_mode: value.toLowerCase()}};
80
96
  }
81
97
  },
82
98
  convertGet: async (entity, key, meta) => {
83
- await entity.read('manuSpecificNiko1', ['switchOperationMode']);
99
+ await utils.enforceEndpoint(entity, key, meta).read(
100
+ 'manuSpecificNiko1',
101
+ ['switchOperationMode'],
102
+ );
84
103
  },
85
104
  },
86
105
  switch_led_enable: {
@@ -259,7 +278,7 @@ module.exports = [
259
278
  endpoint: (device) => {
260
279
  return {'l1': 1, 'l2': 2};
261
280
  },
262
- meta: {multiEndpoint: true},
281
+ meta: {multiEndpointEnforce: {'operation_mode': 1}},
263
282
  configure: async (device, coordinatorEndpoint, logger) => {
264
283
  const ep1 = device.getEndpoint(1);
265
284
  const ep2 = device.getEndpoint(2);
@@ -272,10 +291,11 @@ module.exports = [
272
291
  },
273
292
  exposes: [
274
293
  e.switch().withEndpoint('l1'), e.switch().withEndpoint('l2'),
275
- e.action(['single', 'hold', 'release']).withEndpoint('l1'),
276
- e.action(['single', 'hold', 'release']).withEndpoint('l2'),
277
- exposes.enum('operation_mode', ea.ALL, ['control_relay', 'decoupled']).withEndpoint('l1'),
278
- exposes.enum('operation_mode', ea.ALL, ['control_relay', 'decoupled']).withEndpoint('l2'),
294
+ e.action([
295
+ 'single_left', 'hold_left', 'release_left',
296
+ 'single_right', 'hold_right', 'release_right',
297
+ ]),
298
+ exposes.enum('operation_mode', ea.ALL, ['control_relay', 'decoupled']),
279
299
  exposes.binary('led_enable', ea.ALL, true, false).withEndpoint('l1').withDescription('Enable LED'),
280
300
  exposes.binary('led_enable', ea.ALL, true, false).withEndpoint('l2').withDescription('Enable LED'),
281
301
  exposes.binary('led_state', ea.ALL, 'ON', 'OFF').withEndpoint('l1').withDescription('LED State'),
package/devices/tuya.js CHANGED
@@ -805,6 +805,7 @@ module.exports = [
805
805
  fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_bq5c8xfe'},
806
806
  {modelID: 'TS0601', manufacturerName: '_TZE200_bjawzodf'},
807
807
  {modelID: 'TS0601', manufacturerName: '_TZE200_qyflbnbj'},
808
+ {modelID: 'TS0601', manufacturerName: '_TZE200_vs0skpuc'},
808
809
  {modelID: 'TS0601', manufacturerName: '_TZE200_9yapgbuv'},
809
810
  {modelID: 'TS0601', manufacturerName: '_TZE200_zl1kmjqx'}],
810
811
  model: 'TS0601_temperature_humidity_sensor',
@@ -199,7 +199,7 @@ module.exports = [
199
199
  exposes: [e.cover_position().setAccess('position', ea.STATE_SET)],
200
200
  },
201
201
  {
202
- fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_1n2kyphz'}],
202
+ fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_1n2kyphz'}, {modelID: 'TS0601', manufacturerName: '_TZE200_shkxsgis'}],
203
203
  model: 'TB26-4',
204
204
  vendor: 'Zemismart',
205
205
  description: '4-gang smart wall switch',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zigbee-herdsman-converters",
3
- "version": "15.0.91",
3
+ "version": "15.0.93",
4
4
  "description": "Collection of device converters to be used with zigbee-herdsman",
5
5
  "main": "index.js",
6
6
  "files": [