zigbee-herdsman-converters 14.0.689 → 14.0.690

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/ctm.js CHANGED
@@ -19,6 +19,19 @@ const dataType = {
19
19
  };
20
20
 
21
21
  const fzLocal = {
22
+ ctm_mbd_device_enabled: {
23
+ cluster: 'genOnOff',
24
+ type: ['attributeReport', 'readResponse'],
25
+ convert: (model, msg, publish, options, meta) => {
26
+ const result = {};
27
+ const data = msg.data;
28
+ if (data.hasOwnProperty('onOff')) {
29
+ result.device_enabled = data['onOff'] ? 'ON' : 'OFF';
30
+ }
31
+
32
+ return result;
33
+ },
34
+ },
22
35
  ctm_device_mode: {
23
36
  cluster: 'genOnOff',
24
37
  type: ['attributeReport', 'readResponse'],
@@ -72,6 +85,19 @@ const fzLocal = {
72
85
  return result;
73
86
  },
74
87
  },
88
+ ctm_relay_state: {
89
+ cluster: 'genOnOff',
90
+ type: ['attributeReport', 'readResponse'],
91
+ convert: (model, msg, publish, options, meta) => {
92
+ const result = {};
93
+ const data = msg.data;
94
+ if (data.hasOwnProperty(0x5001)) {
95
+ result.state = data[0x5001] ? 'ON' : 'OFF';
96
+ }
97
+
98
+ return result;
99
+ },
100
+ },
75
101
  ctm_temperature_offset: {
76
102
  cluster: 'msTemperatureMeasurement',
77
103
  type: ['attributeReport', 'readResponse'],
@@ -281,6 +307,15 @@ const fzLocal = {
281
307
 
282
308
 
283
309
  const tzLocal = {
310
+ ctm_mbd_device_enabled: {
311
+ key: ['device_enabled'],
312
+ convertSet: async (entity, key, value, meta) => {
313
+ await entity.command('genOnOff', value.toLowerCase(), {}, utils.getOptions(meta.mapped, entity));
314
+ },
315
+ convertGet: async (entity, key, meta) => {
316
+ await entity.read('genOnOff', ['onOff']);
317
+ },
318
+ },
284
319
  ctm_device_mode: {
285
320
  key: ['device_mode'],
286
321
  convertGet: async (entity, key, meta) => {
@@ -308,6 +343,16 @@ const tzLocal = {
308
343
  await entity.read('genOnOff', [0x5000], {manufacturerCode: 0x1337});
309
344
  },
310
345
  },
346
+ ctm_relay_state: {
347
+ key: ['state'],
348
+ convertSet: async (entity, key, value, meta) => {
349
+ await entity.write('genOnOff',
350
+ {0x5001: {value: {'OFF': 0, 'ON': 1}[value], type: dataType.boolean}}, {manufacturerCode: 0x1337});
351
+ },
352
+ convertGet: async (entity, key, meta) => {
353
+ await entity.read('genOnOff', [0x5001], {manufacturerCode: 0x1337});
354
+ },
355
+ },
311
356
  ctm_temperature_offset: {
312
357
  key: ['temperature_offset'],
313
358
  convertSet: async (entity, key, value, meta) => {
@@ -728,7 +773,7 @@ module.exports = [
728
773
  ],
729
774
  },
730
775
  {
731
- zigbeeModel: ['mStikk Outlet'],
776
+ zigbeeModel: ['mStikk Outlet', 'mStikk 16A', 'mStikk 25A', 'Tavlerele 25A'],
732
777
  model: 'mStikk_Outlet',
733
778
  vendor: 'CTM Lyng',
734
779
  description: 'mStikk OP, wall socket',
@@ -834,7 +879,7 @@ module.exports = [
834
879
  exposes.binary('child_lock', ea.STATE, 'locked', 'unlocked')
835
880
  .withDescription('Physical input on the device enabled/disabled'),
836
881
  exposes.numeric('group_id', ea.STATE)
837
- .withDescription('The device sends commands with this group ID. Put dvices in this group to control them.'),
882
+ .withDescription('The device sends commands with this group ID. Put devices in this group to control them.'),
838
883
  ],
839
884
  },
840
885
  {
@@ -866,10 +911,12 @@ module.exports = [
866
911
  meta: {disableDefaultResponse: true},
867
912
  configure: async (device, coordinatorEndpoint, logger) => {
868
913
  const endpoint = device.getEndpoint(1);
869
- await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'ssIasZone']);
914
+ await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff']);
870
915
  await endpoint.read('genOnOff', ['onOff']);
871
916
  await reporting.onOff(endpoint);
872
- await endpoint.read('ssIasZone', ['iasCieAddr', 'zoneState', 'zoneId']);
917
+ const endpoint2 = device.getEndpoint(2);
918
+ await reporting.bind(endpoint2, coordinatorEndpoint, ['ssIasZone']);
919
+ await endpoint2.read('ssIasZone', ['iasCieAddr', 'zoneState', 'zoneId']);
873
920
  },
874
921
  exposes: [e.switch(), e.water_leak(),
875
922
  exposes.binary('active_water_leak', ea.STATE, true, false)
@@ -897,7 +944,7 @@ module.exports = [
897
944
  exposes: [e.temperature(), e.battery(), e.battery_low(), e.smoke(),
898
945
  e.action(['on', 'off']),
899
946
  exposes.numeric('group_id', ea.STATE)
900
- .withDescription('The device sends commands with this group ID. Put dvices in this group to control them.'),
947
+ .withDescription('The device sends commands with this group ID. Put devices in this group to control them.'),
901
948
  ],
902
949
  },
903
950
  {
@@ -924,8 +971,8 @@ module.exports = [
924
971
  model: 'MBD-S',
925
972
  vendor: 'CTM Lyng',
926
973
  description: 'MBD-S, motion detector with 16A relay',
927
- fromZigbee: [fz.on_off, fz.illuminance, fz.occupancy, fzLocal.ctm_device_enabled],
928
- toZigbee: [tz.on_off, tzLocal.ctm_device_enabled],
974
+ fromZigbee: [fz.illuminance, fz.occupancy, fzLocal.ctm_mbd_device_enabled, fzLocal.ctm_relay_state],
975
+ toZigbee: [tzLocal.ctm_mbd_device_enabled, tzLocal.ctm_relay_state],
929
976
  meta: {disableDefaultResponse: true},
930
977
  configure: async (device, coordinatorEndpoint, logger) => {
931
978
  const endpoint = device.getEndpoint(1);
@@ -936,13 +983,13 @@ module.exports = [
936
983
  await reporting.illuminance(endpoint);
937
984
  await endpoint.read('msOccupancySensing', ['occupancy']);
938
985
  await reporting.occupancy(endpoint);
939
- // Device enabled
940
- await endpoint.read('genOnOff', [0x2201]);
986
+ // Relay State
987
+ await endpoint.read('genOnOff', [0x5001], {manufacturerCode: 0x1337});
941
988
  await endpoint.configureReporting('genOnOff', [{
942
- attribute: {ID: 0x2201, type: dataType.boolean},
943
- minimumReportInterval: 0,
989
+ attribute: {ID: 0x5001, type: dataType.boolean},
990
+ minimumReportInterval: 1,
944
991
  maximumReportInterval: constants.repInterval.HOUR,
945
- reportableChange: null}]);
992
+ reportableChange: 0}], {manufacturerCode: 0x1337});
946
993
  },
947
994
  exposes: [e.switch(), e.illuminance(), e.illuminance_lux(), e.occupancy(),
948
995
  exposes.binary('device_enabled', ea.ALL, 'ON', 'OFF')
package/devices/ikea.js CHANGED
@@ -375,7 +375,7 @@ module.exports = [
375
375
  extend: tradfriExtend.light_onoff_brightness_colortemp(),
376
376
  },
377
377
  {
378
- zigbeeModel: ['TRADFRIbulbE26WSglobeclear800lm', 'TRADFRIbulbE27WSglobeclear806lm'],
378
+ zigbeeModel: ['TRADFRIbulbE26WSglobeclear800lm', 'TRADFRIbulbE27WSglobeclear806lm', 'TRADFRIbulbE26WSglobeclear806lm'],
379
379
  model: 'LED2004G8',
380
380
  vendor: 'IKEA',
381
381
  description: 'TRADFRI LED bulb E26/E27 800/806 lumen, dimmable, white spectrum, clear',
package/devices/osram.js CHANGED
@@ -3,8 +3,24 @@ const fz = {...require('../converters/fromZigbee'), legacy: require('../lib/lega
3
3
  const ota = require('../lib/ota');
4
4
  const reporting = require('../lib/reporting');
5
5
  const extend = require('../lib/extend');
6
+ const utils = require('../lib/utils');
6
7
  const e = exposes.presets;
7
8
 
9
+ const fzLocal = {
10
+ pbc_level_to_action: {
11
+ cluster: 'genLevelCtrl',
12
+ type: ['commandMoveWithOnOff', 'commandStopWithOnOff', 'commandMove', 'commandStop', 'commandMoveToLevelWithOnOff'],
13
+ convert: (model, msg, publish, options, meta) => {
14
+ if (utils.hasAlreadyProcessedMessage(msg, model)) return;
15
+ const lookup = {
16
+ commandMoveWithOnOff: 'hold', commandMove: 'hold', commandStopWithOnOff: 'release',
17
+ commandStop: 'release', commandMoveToLevelWithOnOff: 'toggle',
18
+ };
19
+ return {[utils.postfixWithEndpointName('action', msg, model, meta)]: lookup[msg.type]};
20
+ },
21
+ },
22
+ };
23
+
8
24
  module.exports = [
9
25
  {
10
26
  zigbeeModel: ['Gardenspot RGB'],
@@ -476,4 +492,28 @@ module.exports = [
476
492
  extend: extend.ledvance.light_onoff_brightness_colortemp({colorTempRange: [153, 370]}),
477
493
  ota: ota.ledvance,
478
494
  },
495
+ {
496
+ zigbeeModel: ['PBC'],
497
+ model: '4052899930377',
498
+ vendor: 'OSRAM',
499
+ description: 'Lightify pro push button controller (PBC)',
500
+ meta: {multiEndpoint: true},
501
+ endpoint: (device) => {
502
+ return {'l1': 1, 'l2': 2, 'l3': 3, 'l4': 4};
503
+ },
504
+ fromZigbee: [fzLocal.pbc_level_to_action],
505
+ exposes: [
506
+ e.action(['hold', 'release', 'toggle']).withEndpoint('l1'),
507
+ e.action(['hold', 'release', 'toggle']).withEndpoint('l2'),
508
+ e.action(['hold', 'release', 'toggle']).withEndpoint('l3'),
509
+ e.action(['hold', 'release', 'toggle']).withEndpoint('l4'),
510
+ ],
511
+ toZigbee: [],
512
+ configure: async (device, coordinatorEndpoint, logger) => {
513
+ await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ['genLevelCtrl']);
514
+ await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ['genLevelCtrl']);
515
+ await reporting.bind(device.getEndpoint(3), coordinatorEndpoint, ['genLevelCtrl']);
516
+ await reporting.bind(device.getEndpoint(4), coordinatorEndpoint, ['genLevelCtrl']);
517
+ },
518
+ },
479
519
  ];
@@ -112,10 +112,12 @@ const fzLocal = {
112
112
  cluster: 'manuSpecificPhilips2',
113
113
  type: ['attributeReport', 'readResponse'],
114
114
  convert: (model, msg, publish, options, meta) => {
115
- if (msg.data.hasOwnProperty('state')) {
115
+ if (msg.data && msg.data.hasOwnProperty('state')) {
116
116
  const input = msg.data['state'].toString('hex');
117
- const gradient = philips.decodeGradientColors(input, opts);
118
- return {gradient: gradient.colors};
117
+ const decoded = philips.decodeGradientColors(input, opts);
118
+ if (decoded.color_mode === 'gradient') {
119
+ return {gradient: decoded.colors};
120
+ }
119
121
  }
120
122
  return {};
121
123
  },
package/devices/tuya.js CHANGED
@@ -1134,9 +1134,9 @@ module.exports = [
1134
1134
  model: 'IH012-RT01',
1135
1135
  vendor: 'TuYa',
1136
1136
  description: 'Motion sensor',
1137
- fromZigbee: [fz.ias_occupancy_alarm_1, fz.ignore_basic_report, fz.ZM35HQ_attr],
1137
+ fromZigbee: [fz.ias_occupancy_alarm_1, fz.ignore_basic_report, fz.ZM35HQ_attr, fz.battery],
1138
1138
  toZigbee: [tz.ZM35HQ_attr],
1139
- exposes: [e.occupancy(), e.battery_low(), e.tamper(),
1139
+ exposes: [e.occupancy(), e.battery_low(), e.tamper(), e.battery(), e.battery_voltage(),
1140
1140
  exposes.enum('sensitivity', ea.ALL, ['low', 'medium', 'high']).withDescription('PIR sensor sensitivity'),
1141
1141
  exposes.enum('keep_time', ea.ALL, [30, 60, 120]).withDescription('PIR keep time in seconds'),
1142
1142
  ],
@@ -1840,8 +1840,9 @@ module.exports = [
1840
1840
  endpoint.saveClusterAttributeKeyValue('seMetering', {divisor: 100, multiplier: 1});
1841
1841
  device.save();
1842
1842
  },
1843
- whiteLabel: [{vendor: 'Aubess', model: 'WDH02'}],
1844
- exposes: [e.switch(), e.power(), e.voltage().withAccess(ea.STATE), e.energy(), e.power_on_behavior(), tuya.exposes.switchType()],
1843
+ whiteLabel: [{vendor: 'Aubess', model: 'WHD02'}],
1844
+ exposes: [e.switch(), e.power(), e.current(), e.voltage().withAccess(ea.STATE), e.energy(), e.power_on_behavior(),
1845
+ tuya.exposes.switchType()],
1845
1846
  },
1846
1847
  {
1847
1848
  zigbeeModel: ['TS0001'],
@@ -2840,7 +2841,7 @@ module.exports = [
2840
2841
  model: 'TS0014',
2841
2842
  vendor: 'TuYa',
2842
2843
  description: 'Smart light switch - 4 gang without neutral wire',
2843
- extend: tuya.extend.switch({endpoints: ['l1', 'l2', 'l3', 'l4']}),
2844
+ extend: tuya.extend.switch({backlightMode: true, endpoints: ['l1', 'l2', 'l3', 'l4']}),
2844
2845
  endpoint: (device) => {
2845
2846
  return {'l1': 1, 'l2': 2, 'l3': 3, 'l4': 4};
2846
2847
  },
@@ -2884,6 +2885,15 @@ module.exports = [
2884
2885
  exposes: [e.action(['scene_1', 'scene_2', 'scene_3', 'scene_4', 'scene_5', 'scene_6'])],
2885
2886
  toZigbee: [],
2886
2887
  },
2888
+ {
2889
+ zigbeeModel: ['TS0026'],
2890
+ model: 'TS0026',
2891
+ vendor: 'TuYa',
2892
+ description: '6 button scene wall switch',
2893
+ fromZigbee: [fzLocal.scenes_recall_scene_65029],
2894
+ exposes: [e.action(['scene_1', 'scene_2', 'scene_3', 'scene_4', 'scene_5', 'scene_6'])],
2895
+ toZigbee: [],
2896
+ },
2887
2897
  {
2888
2898
  zigbeeModel: ['q9mpfhw'],
2889
2899
  model: 'SNTZ009',
package/lib/philips.js CHANGED
@@ -27,25 +27,45 @@ const decodeScaledGradientToRGB = (p) => {
27
27
  return new ColorXY(xx, yy).toRGB().toHEX();
28
28
  };
29
29
 
30
- function decodeGradientColors(input, opts) {
31
- // Example set: 500104001350000000f3297ff3bd52f3bd52f3297ff3bd522800
32
- // Example get 4b010164fb74346b1350000000f3297fda7d55da7d55f3297fda7d552800
30
+ const COLOR_MODE_GRADIENT = '4b01';
31
+ const COLOR_MODE_COLOR_XY = '0b00';
32
+ const COLOR_MODE_COLOR_TEMP = '0f00';
33
33
 
34
+ // decoder for manuSpecificPhilips2.state
35
+ function decodeGradientColors(input, opts) {
36
+ // Gradient mode (4b01)
37
+ // Example: 4b010164fb74346b1350000000f3297fda7d55da7d55f3297fda7d552800
34
38
  // 4b01 - mode? (4) (0b00 single color?, 4b01 gradient?)
35
- // 01 - on/off (2) or is it 1 full byte?
39
+ // 01 - on/off (2)
36
40
  // 64 - brightness (2)
37
- // fb74346b - unknown (8)
41
+ // fb74346b - unknown (8) - Might be XY Color?
38
42
  // 13 - length (2)
39
43
  // 50 - ncolors (2)
40
44
  // 000000 - unknown (6)
41
45
  // f3297fda7d55da7d55f3297fda7d55 - colors (6 * ncolors)
42
46
  // 28 - segments (2)
43
47
  // 00 - offset (2)
44
-
45
- // Skip the unknown prefix (4 bytes)
48
+ //
49
+ // Temperature mode (0f00)
50
+ // Example: 0f0000044d01ab6f7067
51
+ // 0f00 - mode (4)
52
+ // 01 - on/off (2)
53
+ // 1a - brightness (2)
54
+ // 4d01 - color temperature (4)
55
+ // ab6f7067 - unknown (8)
56
+ //
57
+ // XY Color mode (0b00)
58
+ // Example: 0b00010460b09c4e
59
+ // 0b00 - mode (4) == 0b00 single color mode
60
+ // 01 - on/off (2)
61
+ // 04 - brightness (2)
62
+ // 60b09c4e - color (8) (xLow, xHigh, yLow, yHigh)
63
+
64
+ // Device color mode
65
+ const mode = input.slice(0, 4);
46
66
  input = input.slice(4);
47
67
 
48
- // On/off (1 byte)
68
+ // On/off (2 bytes)
49
69
  const on = parseInt(input.slice(0, 2), 16) === 1;
50
70
  input = input.slice(2);
51
71
 
@@ -53,46 +73,85 @@ function decodeGradientColors(input, opts) {
53
73
  const brightness = parseInt(input.slice(0, 2), 16);
54
74
  input = input.slice(2);
55
75
 
56
- // Unknown (8 bytes)
57
- input = input.slice(8);
76
+ // Gradient mode
77
+ if (mode === COLOR_MODE_GRADIENT) {
78
+ // Unknown (8 bytes)
79
+ input = input.slice(8);
58
80
 
59
- // Length (2 bytes)
60
- input = input.slice(2);
81
+ // Length (2 bytes)
82
+ input = input.slice(2);
61
83
 
62
- // Number of colors (2 bytes)
63
- const nColors = parseInt(input.slice(0, 2), 16) >> 4;
64
- input = input.slice(2);
84
+ // Number of colors (2 bytes)
85
+ const nColors = parseInt(input.slice(0, 2), 16) >> 4;
86
+ input = input.slice(2);
65
87
 
66
- // Unknown (6 bytes)
67
- input = input.slice(6);
88
+ // Unknown (6 bytes)
89
+ input = input.slice(6);
68
90
 
69
- // Colors (6 * nColors bytes)
70
- const colorsPayload = input.slice(0, 6 * nColors);
71
- input = input.slice(6 * nColors);
72
- const colors = colorsPayload.match(/.{6}/g).map(decodeScaledGradientToRGB);
91
+ // Colors (6 * nColors bytes)
92
+ const colorsPayload = input.slice(0, 6 * nColors);
93
+ input = input.slice(6 * nColors);
94
+ const colors = colorsPayload.match(/.{6}/g).map(decodeScaledGradientToRGB);
73
95
 
74
- // Segments (2 bytes)
75
- const segments = parseInt(input.slice(0, 2), 16) >> 3;
76
- input = input.slice(2);
96
+ // Segments (2 bytes)
97
+ const segments = parseInt(input.slice(0, 2), 16) >> 3;
98
+ input = input.slice(2);
77
99
 
78
- // Offset (2 bytes)
79
- const offset = parseInt(input.slice(0, 2), 16) >> 3;
100
+ // Offset (2 bytes)
101
+ const offset = parseInt(input.slice(0, 2), 16) >> 3;
80
102
 
81
- if (opts.reverse) {
82
- colors.reverse();
83
- }
103
+ if (opts && opts.reverse) {
104
+ colors.reverse();
105
+ }
84
106
 
85
- return {
86
- colors,
87
-
88
- gradient_extras: {
89
- colors: nColors,
107
+ return {
108
+ color_mode: 'gradient',
109
+ colors,
90
110
  segments,
91
111
  offset,
92
112
  brightness,
93
113
  on,
94
- },
95
- };
114
+ };
115
+ } else if (mode === COLOR_MODE_COLOR_XY) {
116
+ // XY Color mode
117
+ const xLow = parseInt(input.slice(0, 2), 16);
118
+ input = input.slice(2);
119
+ const xHigh = parseInt(input.slice(0, 2), 16) << 8;
120
+ input = input.slice(2);
121
+ const yHigh = parseInt(input.slice(0, 2), 16);
122
+ input = input.slice(2);
123
+ const yLow = parseInt(input.slice(0, 2), 16) << 8;
124
+ input = input.slice(2);
125
+
126
+ const x = xHigh | xLow;
127
+ const y = yHigh | yLow;
128
+
129
+ return {
130
+ color_mode: 'color_xy',
131
+ x: Math.round(x / 65535 * 10000) / 10000,
132
+ y: Math.round(y / 65535 * 10000) / 10000,
133
+ brightness,
134
+ on,
135
+ };
136
+ } else if (mode === COLOR_MODE_COLOR_TEMP) {
137
+ // Color temperature mode
138
+ const low = parseInt(input.slice(0, 2), 16);
139
+ input = input.slice(2);
140
+ const high = parseInt(input.slice(0, 2), 16) << 8;
141
+ input = input.slice(2);
142
+
143
+ const temp = high | low;
144
+
145
+ return {
146
+ color_mode: 'color_temp',
147
+ color_temp: temp,
148
+ brightness,
149
+ on,
150
+ };
151
+ }
152
+
153
+ // Unknown mode
154
+ return {};
96
155
  }
97
156
 
98
157
  // Value is a list of RGB HEX colors
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zigbee-herdsman-converters",
3
- "version": "14.0.689",
3
+ "version": "14.0.690",
4
4
  "description": "Collection of device converters to be used with zigbee-herdsman",
5
5
  "main": "index.js",
6
6
  "files": [