zigbee-herdsman-converters 15.0.20 → 15.0.22

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.
@@ -30,8 +30,10 @@ const converters = {
30
30
  cluster: 'hvacFanCtrl',
31
31
  type: ['attributeReport', 'readResponse'],
32
32
  convert: (model, msg, publish, options, meta) => {
33
- const key = getKey(constants.fanMode, msg.data.fanMode);
34
- return {fan_mode: key, fan_state: key === 'off' ? 'OFF' : 'ON'};
33
+ if (msg.data.hasOwnProperty('fanMode')) {
34
+ const key = getKey(constants.fanMode, msg.data.fanMode);
35
+ return {fan_mode: key, fan_state: key === 'off' ? 'OFF' : 'ON'};
36
+ }
35
37
  },
36
38
  },
37
39
  thermostat: {
@@ -978,9 +980,9 @@ const converters = {
978
980
  },
979
981
  ias_smoke_alarm_1: {
980
982
  cluster: 'ssIasZone',
981
- type: 'commandStatusChangeNotification',
983
+ type: ['commandStatusChangeNotification', 'attributeReport', 'readResponse'],
982
984
  convert: (model, msg, publish, options, meta) => {
983
- const zoneStatus = msg.data.zonestatus;
985
+ const zoneStatus = msg.type === 'commandStatusChangeNotification' ? msg.data.zonestatus : msg.data.zoneStatus;
984
986
  return {
985
987
  smoke: (zoneStatus & 1) > 0,
986
988
  tamper: (zoneStatus & 1<<2) > 0,
@@ -990,6 +992,7 @@ const converters = {
990
992
  trouble: (zoneStatus & 1<<6) > 0,
991
993
  ac_status: (zoneStatus & 1<<7) > 0,
992
994
  test: (zoneStatus & 1<<8) > 0,
995
+ battery_defect: (zoneStatus & 1<<9) > 0,
993
996
  };
994
997
  },
995
998
  },
@@ -4018,7 +4021,7 @@ const converters = {
4018
4021
  return {deadzone_temperature: value};
4019
4022
  case tuya.dataPoints.moesLocalTemp:
4020
4023
  temperature = value & 1<<15 ? value - (1<<16) + 1 : value;
4021
- if (!['_TZE200_ztvwu4nk', '_TZE200_ye5jkfsb'].includes(meta.device.manufacturerName)) {
4024
+ if (!['_TZE200_ztvwu4nk', '_TZE200_ye5jkfsb', '_TZE200_5toc8efa'].includes(meta.device.manufacturerName)) {
4022
4025
  // https://github.com/Koenkk/zigbee2mqtt/issues/11980
4023
4026
  temperature = temperature / 10;
4024
4027
  }
@@ -8312,6 +8315,15 @@ const converters = {
8312
8315
  return result;
8313
8316
  },
8314
8317
  },
8318
+ hw_version: {
8319
+ cluster: 'genBasic',
8320
+ type: ['attributeReport', 'readResponse'],
8321
+ convert: (model, msg, publish, options, meta) => {
8322
+ const result = {};
8323
+ if (msg.data.hasOwnProperty('hwVersion')) result['hw_version'] = msg.data.hwVersion;
8324
+ return result;
8325
+ },
8326
+ },
8315
8327
  // #endregion
8316
8328
 
8317
8329
  // #region Ignore converters (these message dont need parsing).
package/devices/awox.js CHANGED
@@ -151,6 +151,13 @@ module.exports = [
151
151
  {ID: 3, profileID: 4751, deviceID: 268, inputClusters: [65360, 65361], outputClusters: [65360, 65361]},
152
152
  ],
153
153
  },
154
+ {
155
+ type: 'Router', manufacturerName: 'AwoX', modelID: 'TLSR82xx', endpoints: [
156
+ {ID: 1, profileID: 260, deviceID: 268, inputClusters: [0, 3, 4, 5, 6, 8, 768, 4096, 64599, 10], outputClusters: [6]},
157
+ {ID: 242, profileID: 41440, deviceID: 97, inputClusters: [], outputClusters: [33]},
158
+ {ID: 3, profileID: 4751, deviceID: 268, inputClusters: [65360, 65361, 4], outputClusters: [65360, 65361]},
159
+ ],
160
+ },
154
161
  ],
155
162
  model: '33957',
156
163
  vendor: 'AwoX',
package/devices/bosch.js CHANGED
@@ -508,6 +508,26 @@ const definition = [
508
508
  exposes.enum('heartbeat', ea.ALL, Object.keys(stateOffOn)).withDescription('Enable/disable heartbeat'),
509
509
  ],
510
510
  },
511
+ {
512
+ zigbeeModel: ['RBSH-SP-ZB-EU'],
513
+ model: 'BSP-FZ2',
514
+ vendor: 'Bosch',
515
+ description: 'Plug compact EU',
516
+ fromZigbee: [fz.on_off, fz.power_on_behavior, fz.electrical_measurement, fz.metering],
517
+ toZigbee: [tz.on_off, tz.power_on_behavior],
518
+ configure: async (device, coordinatorEndpoint, logger) => {
519
+ const endpoint = device.getEndpoint(1);
520
+ await endpoint.read('genOnOff', ['onOff', 'startUpOnOff']);
521
+ await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff']);
522
+ await reporting.bind(endpoint, coordinatorEndpoint, ['seMetering']);
523
+ await reporting.readMeteringMultiplierDivisor(endpoint);
524
+ await reporting.currentSummDelivered(endpoint, {change: [0, 1]});
525
+ await reporting.bind(endpoint, coordinatorEndpoint, ['haElectricalMeasurement']);
526
+ await endpoint.read('haElectricalMeasurement', ['acPowerMultiplier', 'acPowerDivisor']);
527
+ await reporting.activePower(endpoint);
528
+ },
529
+ exposes: [e.switch(), e.power_on_behavior(), e.power(), e.energy()],
530
+ },
511
531
  ];
512
532
 
513
533
  module.exports = definition;
package/devices/datek.js CHANGED
@@ -10,12 +10,12 @@ const ea = exposes.access;
10
10
 
11
11
  module.exports = [
12
12
  {
13
- zigbeeModel: ['PoP'],
13
+ fingerprint: [{modelID: 'PoP', manufacturerName: 'Eva'}],
14
14
  model: 'HLU2909K',
15
15
  vendor: 'Datek',
16
16
  description: 'APEX smart plug 16A',
17
17
  fromZigbee: [fz.on_off, fz.electrical_measurement, fz.temperature],
18
- toZigbee: [tz.on_off],
18
+ toZigbee: [tz.on_off, tz.power_on_behavior],
19
19
  configure: async (device, coordinatorEndpoint, logger) => {
20
20
  const endpoint = device.getEndpoint(1);
21
21
  await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'msTemperatureMeasurement']);
@@ -28,24 +28,26 @@ module.exports = [
28
28
  await reporting.activePower(endpoint);
29
29
  await reporting.temperature(endpoint);
30
30
  },
31
- exposes: [e.power(), e.current(), e.voltage(), e.switch(), e.temperature()],
31
+ exposes: [e.power(), e.current(), e.voltage(), e.switch(), e.temperature(), e.power_on_behavior()],
32
32
  },
33
33
  {
34
- zigbeeModel: ['Meter Reader'],
34
+ fingerprint: [{modelID: 'Meter Reader', manufacturerName: 'Eva'}],
35
35
  model: 'HSE2905E',
36
36
  vendor: 'Datek',
37
37
  description: 'Datek Eva AMS HAN power-meter sensor',
38
- fromZigbee: [fz.metering_datek, fz.electrical_measurement, fz.temperature],
38
+ fromZigbee: [fz.metering_datek, fz.electrical_measurement, fz.temperature, fz.hw_version],
39
39
  toZigbee: [],
40
40
  ota: ota.zigbeeOTA,
41
41
  configure: async (device, coordinatorEndpoint, logger) => {
42
42
  const endpoint = device.getEndpoint(1);
43
43
  await reporting.bind(endpoint, coordinatorEndpoint, ['haElectricalMeasurement', 'seMetering', 'msTemperatureMeasurement']);
44
+ await reporting.readEletricalMeasurementMultiplierDivisors(endpoint);
44
45
  await reporting.readMeteringMultiplierDivisor(endpoint);
45
46
  try {
46
- await reporting.readEletricalMeasurementMultiplierDivisors(endpoint);
47
- } catch (error) {
48
- /* fails for some: https://github.com/Koenkk/zigbee2mqtt/issues/11867 */
47
+ // hwVersion < 2 do not support hwVersion attribute, so we are testing if this is hwVersion 1 or 2
48
+ await endpoint.read('genBasic', ['hwVersion']);
49
+ } catch (e) {
50
+ e;
49
51
  }
50
52
  const payload = [{
51
53
  attribute: 'rmsVoltagePhB',
@@ -78,8 +80,6 @@ module.exports = [
78
80
  await reporting.currentSummDelivered(endpoint, {min: 60, max: 3600, change: [1, 1]});
79
81
  await reporting.currentSummReceived(endpoint);
80
82
  await reporting.temperature(endpoint, {min: 60, max: 3600, change: 0});
81
- device.powerSource = 'DC source';
82
- device.save();
83
83
  },
84
84
  exposes: [e.power(), e.energy(), e.current(), e.voltage(), e.current_phase_b(), e.voltage_phase_b(), e.current_phase_c(),
85
85
  e.voltage_phase_c(), e.temperature()],
@@ -113,7 +113,7 @@ module.exports = [
113
113
  exposes.numeric('occupancy_timeout', ea.ALL).withUnit('seconds').withValueMin(0).withValueMax(65535)],
114
114
  },
115
115
  {
116
- zigbeeModel: ['ID Lock 150'],
116
+ fingerprint: [{modelID: 'ID Lock 150', manufacturerName: 'Eva'}],
117
117
  model: '0402946',
118
118
  vendor: 'Datek',
119
119
  description: 'Zigbee module for ID lock 150',
@@ -187,7 +187,7 @@ module.exports = [
187
187
  'random_pin_24_hours']).withDescription('Service Mode of the Lock')],
188
188
  },
189
189
  {
190
- zigbeeModel: ['Water Sensor'],
190
+ fingerprint: [{modelID: 'Water Sensor', manufacturerName: 'Eva'}],
191
191
  model: 'HSE2919E',
192
192
  vendor: 'Datek',
193
193
  description: 'Eva water leak sensor',
@@ -228,6 +228,7 @@ module.exports = [
228
228
  'brightness_move_down', 'brightness_move_up', 'brightness_stop'])],
229
229
  },
230
230
  {
231
+ fingerprint: [{modelID: 'Door/Window Sensor', manufacturerName: 'Eva'}],
231
232
  zigbeeModel: ['Door/Window Sensor'],
232
233
  model: 'HSE2920E',
233
234
  vendor: 'Datek',
@@ -0,0 +1,11 @@
1
+ const extend = require('../lib/extend');
2
+
3
+ module.exports = [
4
+ {
5
+ zigbeeModel: ['EB-E14-P45-RGBW'],
6
+ model: 'EB-E14-P45-RGBW',
7
+ vendor: 'EssentielB',
8
+ description: 'Smart LED bulb',
9
+ extend: extend.light_onoff_brightness_colortemp({colorTempRange: [153, 370]}),
10
+ },
11
+ ];
package/devices/hgkg.js CHANGED
@@ -42,7 +42,7 @@ module.exports = [
42
42
  .withPreset(['hold', 'program'])
43
43
  .withFanMode(['off', 'low', 'medium', 'high', 'auto'], ea.STATE_SET),
44
44
  e.temperature_sensor_select(['IN', 'AL', 'OU']),
45
- exposes.composite('programming_mode')
45
+ exposes.composite('programming_mode', 'programming_mode', ea.STATE)
46
46
  .withDescription(
47
47
  'Schedule MODE ⏱ - In this mode, the device executes a preset week programming temperature time and temperature.',
48
48
  )
@@ -162,7 +162,7 @@ module.exports = [
162
162
  exposes: [e.battery(), e.action([
163
163
  'color_move', 'color_temperature_move', 'hue_move', 'hue_stop', 'brightness_step_up', 'brightness_step_down',
164
164
  'recall_*', 'on', 'off']),
165
- exposes.composite('action_color', 'action_color')
165
+ exposes.composite('action_color', 'action_color', ea.STATE)
166
166
  .withFeature(exposes.numeric('x', ea.STATE))
167
167
  .withFeature(exposes.numeric('y', ea.STATE))
168
168
  .withDescription('Only shows the transmitted color in X7Y-Mode. Noch changes possible.'),
@@ -1077,10 +1077,10 @@ const exposesList = [
1077
1077
  e.power(),
1078
1078
  e.energy(),
1079
1079
  exposes
1080
- .composite('led_effect', 'led_effect')
1080
+ .composite('led_effect', 'led_effect', ea.STATE_SET)
1081
1081
  .withFeature(
1082
1082
  exposes
1083
- .enum('effect', ea.SET_STATE, [
1083
+ .enum('effect', ea.STATE_SET, [
1084
1084
  'off',
1085
1085
  'solid',
1086
1086
  'fast_blink',
@@ -1107,7 +1107,7 @@ const exposesList = [
1107
1107
  )
1108
1108
  .withFeature(
1109
1109
  exposes
1110
- .numeric('color', ea.SET_STATE)
1110
+ .numeric('color', ea.STATE_SET)
1111
1111
  .withValueMin(0)
1112
1112
  .withValueMax(255)
1113
1113
  .withDescription(
@@ -1116,14 +1116,14 @@ const exposesList = [
1116
1116
  )
1117
1117
  .withFeature(
1118
1118
  exposes
1119
- .numeric('level', ea.SET_STATE)
1119
+ .numeric('level', ea.STATE_SET)
1120
1120
  .withValueMin(0)
1121
1121
  .withValueMax(100)
1122
1122
  .withDescription('Brightness of the LEDs'),
1123
1123
  )
1124
1124
  .withFeature(
1125
1125
  exposes
1126
- .numeric('duration', ea.SET_STATE)
1126
+ .numeric('duration', ea.STATE_SET)
1127
1127
  .withValueMin(0)
1128
1128
  .withValueMax(255)
1129
1129
  .withDescription(
@@ -1133,15 +1133,15 @@ const exposesList = [
1133
1133
  ),
1134
1134
  ),
1135
1135
  exposes
1136
- .composite('individual_led_effect', 'individual_led_effect')
1136
+ .composite('individual_led_effect', 'individual_led_effect', ea.STATE_SET)
1137
1137
  .withFeature(
1138
1138
  exposes
1139
- .enum('led', ea.SET_STATE, ['1', '2', '3', '4', '5', '6', '7'])
1139
+ .enum('led', ea.STATE_SET, ['1', '2', '3', '4', '5', '6', '7'])
1140
1140
  .withDescription('Individual LED to target.'),
1141
1141
  )
1142
1142
  .withFeature(
1143
1143
  exposes
1144
- .enum('effect', ea.SET_STATE, [
1144
+ .enum('effect', ea.STATE_SET, [
1145
1145
  'off',
1146
1146
  'solid',
1147
1147
  'fast_blink',
@@ -1157,7 +1157,7 @@ const exposesList = [
1157
1157
  )
1158
1158
  .withFeature(
1159
1159
  exposes
1160
- .numeric('color', ea.SET_STATE)
1160
+ .numeric('color', ea.STATE_SET)
1161
1161
  .withValueMin(0)
1162
1162
  .withValueMax(255)
1163
1163
  .withDescription(
@@ -1166,14 +1166,14 @@ const exposesList = [
1166
1166
  )
1167
1167
  .withFeature(
1168
1168
  exposes
1169
- .numeric('level', ea.SET_STATE)
1169
+ .numeric('level', ea.STATE_SET)
1170
1170
  .withValueMin(0)
1171
1171
  .withValueMax(100)
1172
1172
  .withDescription('Brightness of the LED'),
1173
1173
  )
1174
1174
  .withFeature(
1175
1175
  exposes
1176
- .numeric('duration', ea.SET_STATE)
1176
+ .numeric('duration', ea.STATE_SET)
1177
1177
  .withValueMin(0)
1178
1178
  .withValueMax(255)
1179
1179
  .withDescription(
package/devices/lidl.js CHANGED
@@ -409,14 +409,15 @@ module.exports = [
409
409
  model: 'HG08164',
410
410
  vendor: 'Lidl',
411
411
  description: 'Silvercrest smart button',
412
- fromZigbee: [fz.command_on, fz.command_off, fz.command_step, fz.command_stop, fz.battery],
412
+ fromZigbee: [fz.command_on, fz.command_off, fz.command_step, fz.command_stop, fz.battery, fz.tuya_on_off_action],
413
413
  toZigbee: [],
414
414
  configure: async (device, coordinatorEndpoint, logger) => {
415
415
  const endpoint = device.getEndpoint(1);
416
416
  await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg']);
417
417
  await reporting.batteryPercentageRemaining(endpoint);
418
418
  },
419
- exposes: [e.action(['on', 'off', 'brightness_stop', 'brightness_step_up', 'brightness_step_down']), e.battery()],
419
+ exposes: [e.action(
420
+ ['on', 'off', 'brightness_stop', 'brightness_step_up', 'brightness_step_down', 'single', 'double']), e.battery()],
420
421
  },
421
422
  {
422
423
  fingerprint: [{modelID: 'TS0211', manufacturerName: '_TZ1800_ladpngdx'}],
@@ -523,7 +524,7 @@ module.exports = [
523
524
  description: 'Melinera smart LED string lights',
524
525
  toZigbee: [tz.on_off, tz.silvercrest_smart_led_string],
525
526
  fromZigbee: [fz.on_off, fz.silvercrest_smart_led_string],
526
- exposes: [e.light_brightness_colorhs().setAccess('brightness', ea.STATE_SET)],
527
+ exposes: [e.light_brightness_colorhs().setAccess('brightness', ea.STATE_SET).setAccess('color_hs', ea.STATE_SET)],
527
528
  },
528
529
  {
529
530
  fingerprint: [{modelID: 'TS0505A', manufacturerName: '_TZ3000_odygigth'}],
@@ -873,7 +874,8 @@ module.exports = [
873
874
  exposes.binary('binary_one', ea.STATE_SET, 'ON', 'OFF').withDescription('Unknown binary one'),
874
875
  exposes.binary('binary_two', ea.STATE_SET, 'ON', 'OFF').withDescription('Unknown binary two'),
875
876
  exposes.binary('away_mode', ea.STATE, 'ON', 'OFF').withDescription('Away mode'),
876
- exposes.composite('away_setting', 'away_setting').withFeature(e.away_preset_days()).setAccess('away_preset_days', ea.ALL)
877
+ exposes.composite('away_setting', 'away_setting', ea.STATE_SET)
878
+ .withFeature(e.away_preset_days()).setAccess('away_preset_days', ea.ALL)
877
879
  .withFeature(e.away_preset_temperature()).setAccess('away_preset_temperature', ea.ALL)
878
880
  .withFeature(exposes.numeric('away_preset_year', ea.ALL).withUnit('year').withDescription('Start away year 20xx'))
879
881
  .withFeature(exposes.numeric('away_preset_month', ea.ALL).withUnit('month').withDescription('Start away month'))
@@ -881,7 +883,7 @@ module.exports = [
881
883
  .withFeature(exposes.numeric('away_preset_hour', ea.ALL).withUnit('hour').withDescription('Start away hours'))
882
884
  .withFeature(exposes.numeric('away_preset_minute', ea.ALL).withUnit('min').withDescription('Start away minutes')),
883
885
  ...['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'].map((day) => {
884
- const expose = exposes.composite(day, day);
886
+ const expose = exposes.composite(day, day, ea.STATE_SET);
885
887
  [1, 2, 3, 4, 5, 6, 7, 8, 9].forEach((i) => {
886
888
  expose.withFeature(exposes.numeric(`${day}_temp_${i}`, ea.ALL).withValueMin(0.5)
887
889
  .withValueMax(29.5).withValueStep(0.5).withUnit('°C').withDescription(`Temperature ${i}`));
package/devices/livolo.js CHANGED
@@ -205,7 +205,7 @@ module.exports = [
205
205
  toZigbee: [tz.livolo_cover_state, tz.livolo_cover_position, tz.livolo_cover_options],
206
206
  exposes: [
207
207
  e.cover_position().setAccess('position', ea.STATE_SET),
208
- exposes.composite('options', 'options')
208
+ exposes.composite('options', 'options', ea.STATE_SET)
209
209
  .withDescription('Motor options')
210
210
  .withFeature(exposes.numeric('motor_speed', ea.STATE_SET)
211
211
  .withValueMin(20)
@@ -46,7 +46,7 @@ module.exports = [
46
46
  model: 'FUT036Z',
47
47
  description: 'Single color LED controller',
48
48
  vendor: 'Miboxer',
49
- extend: extend.light_onoff_brightness(),
49
+ extend: extend.light_onoff_brightness({disablePowerOnBehavior: true}),
50
50
  onEvent: tuya.onEventSetTime,
51
51
  },
52
52
  {
package/devices/moes.js CHANGED
@@ -114,7 +114,7 @@ module.exports = [
114
114
  .withSystemMode(['off', 'heat'], ea.STATE_SET).withRunningState(['idle', 'heat', 'cool'], ea.STATE)
115
115
  .withPreset(['hold', 'program']),
116
116
  e.temperature_sensor_select(['IN', 'AL', 'OU']),
117
- exposes.composite('program', 'program').withDescription('Time of day and setpoint to use when in program mode')
117
+ exposes.composite('program', 'program', ea.STATE_SET).withDescription('Time of day and setpoint to use when in program mode')
118
118
  .withFeature(exposesLocal.hour('weekdays_p1_hour'))
119
119
  .withFeature(exposesLocal.minute('weekdays_p1_minute'))
120
120
  .withFeature(exposesLocal.program_temperature('weekdays_p1_temperature'))
@@ -308,9 +308,9 @@ module.exports = [
308
308
  'You can set up to 4 stages of temperature every for WEEKDAY ➀➁➂➃➄, SATURDAY ➅ and SUNDAY ➆.'),
309
309
  exposes.binary('boost_heating', ea.STATE_SET, 'ON', 'OFF').withDescription('Boost Heating: press and hold "+" for 3 seconds, ' +
310
310
  'the device will enter the boost heating mode, and the ▷╵◁ will flash. The countdown will be displayed in the APP'),
311
- exposes.numeric('boost_heating_countdown', ea.STATE).withUnit('Min').withDescription('Countdown in minutes')
311
+ exposes.numeric('boost_heating_countdown', ea.STATE).withUnit('minutes').withDescription('Countdown in minutes')
312
312
  .withValueMin(0).withValueMax(15),
313
- exposes.numeric('boost_heating_countdown_time_set', ea.STATE_SET).withUnit('second')
313
+ exposes.numeric('boost_heating_countdown_time_set', ea.STATE_SET).withUnit('seconds')
314
314
  .withDescription('Boost Time Setting 100 sec - 900 sec, (default = 300 sec)').withValueMin(100)
315
315
  .withValueMax(900).withValueStep(100)],
316
316
  },
package/devices/namron.js CHANGED
@@ -734,4 +734,25 @@ module.exports = [
734
734
  extend: extend.light_onoff_brightness_colortemp({colorTempRange: [153, 555]}),
735
735
  meta: {turnsOffAtBrightness1: true},
736
736
  },
737
+ {
738
+ zigbeeModel: ['4512749'],
739
+ model: '4512749',
740
+ vendor: 'Namron',
741
+ description: 'Thermostat outlet socket',
742
+ fromZigbee: [fz.metering, fz.electrical_measurement, fz.on_off, fz.temperature],
743
+ toZigbee: [tz.on_off, tz.power_on_behavior],
744
+ exposes: [e.temperature(), e.power(), e.current(), e.voltage(), e.switch(), e.power_on_behavior()],
745
+ configure: async (device, coordinatorEndpoint, logger) => {
746
+ const endpoint = device.getEndpoint(1);
747
+ await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'msTemperatureMeasurement']);
748
+ await endpoint.read('haElectricalMeasurement', ['acVoltageMultiplier', 'acVoltageDivisor']);
749
+ await endpoint.read('haElectricalMeasurement', ['acPowerMultiplier', 'acPowerDivisor']);
750
+ await endpoint.read('haElectricalMeasurement', ['acCurrentMultiplier', 'acCurrentDivisor']);
751
+ await reporting.onOff(endpoint);
752
+ await reporting.temperature(endpoint);
753
+ await reporting.rmsVoltage(endpoint);
754
+ await reporting.rmsCurrent(endpoint);
755
+ await reporting.activePower(endpoint);
756
+ },
757
+ },
737
758
  ];
package/devices/nodon.js CHANGED
@@ -51,6 +51,21 @@ module.exports = [
51
51
  return {default: 1};
52
52
  },
53
53
  },
54
+ {
55
+ zigbeeModel: ['SIN-4-1-20_PRO'],
56
+ model: 'SIN-4-1-20_PRO',
57
+ vendor: 'NodOn',
58
+ description: 'Single LED relay',
59
+ extend: extend.switch(),
60
+ configure: async (device, coordinatorEndpoint, logger) => {
61
+ const ep = device.getEndpoint(1);
62
+ await reporting.bind(ep, coordinatorEndpoint, ['genOnOff']);
63
+ await reporting.onOff(ep);
64
+ },
65
+ endpoint: (device) => {
66
+ return {default: 1};
67
+ },
68
+ },
54
69
  {
55
70
  zigbeeModel: ['SIN-4-2-20'],
56
71
  model: 'SIN-4-2-20',
@@ -71,4 +86,24 @@ module.exports = [
71
86
  await reporting.onOff(ep2);
72
87
  },
73
88
  },
89
+ {
90
+ zigbeeModel: ['SIN-4-2-20_PRO'],
91
+ model: 'SIN-4-2-20_PRO',
92
+ vendor: 'NodOn',
93
+ description: 'Double LED relay',
94
+ exposes: [e.switch().withEndpoint('l1'), e.switch().withEndpoint('l2')],
95
+ extend: extend.switch(),
96
+ endpoint: (device) => {
97
+ return {'l1': 1, 'l2': 2};
98
+ },
99
+ meta: {multiEndpoint: true},
100
+ configure: async (device, coordinatorEndpoint, logger) => {
101
+ const ep1 = device.getEndpoint(1);
102
+ const ep2 = device.getEndpoint(2);
103
+ await reporting.bind(ep1, coordinatorEndpoint, ['genOnOff']);
104
+ await reporting.bind(ep2, coordinatorEndpoint, ['genOnOff']);
105
+ await reporting.onOff(ep1);
106
+ await reporting.onOff(ep2);
107
+ },
108
+ },
74
109
  ];
package/devices/nue_3a.js CHANGED
@@ -370,4 +370,27 @@ module.exports = [
370
370
  return {left: 1, right: 2};
371
371
  },
372
372
  },
373
+ {
374
+ zigbeeModel: ['LXN56-1S27LX1.2', 'LXX60-FN27LX1.0'],
375
+ model: 'NUE-ZBFLB',
376
+ vendor: 'Nue / 3A',
377
+ description: 'Smart fan light switch',
378
+ extend: extend.switch(),
379
+ exposes: [
380
+ e.switch().withEndpoint('button_light'),
381
+ e.switch().withEndpoint('button_fan_high'),
382
+ e.switch().withEndpoint('button_fan_med'),
383
+ e.switch().withEndpoint('button_fan_low'),
384
+ ],
385
+ endpoint: (device) => {
386
+ return {'button_light': 1, 'button_fan_high': 2, 'button_fan_med': 3, 'button_fan_low': 4};
387
+ },
388
+ meta: {multiEndpoint: true},
389
+ configure: async (device, coordinatorEndpoint, logger) => {
390
+ await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ['genOnOff']);
391
+ await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ['genOnOff']);
392
+ await reporting.bind(device.getEndpoint(3), coordinatorEndpoint, ['genOnOff']);
393
+ await reporting.bind(device.getEndpoint(4), coordinatorEndpoint, ['genOnOff']);
394
+ },
395
+ },
373
396
  ];
@@ -979,7 +979,7 @@ module.exports = [
979
979
  extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
980
980
  },
981
981
  {
982
- zigbeeModel: ['LCG002', '929003047701'],
982
+ zigbeeModel: ['LCG002', '929003047701', '929003047701'],
983
983
  model: '929001953101',
984
984
  vendor: 'Philips',
985
985
  description: 'Hue White and Color Ambiance GU10',
@@ -1288,7 +1288,7 @@ module.exports = [
1288
1288
  model: '1743930P7',
1289
1289
  vendor: 'Philips',
1290
1290
  description: 'Hue Outdoor Econic wall lantern',
1291
- extend: hueExtend.light_onoff_brightness_colortemp_color(),
1291
+ extend: hueExtend.light_onoff_brightness_colortemp_color({disableHueEffects: false, colorTempRange: [153, 500]}),
1292
1292
  },
1293
1293
  {
1294
1294
  zigbeeModel: ['929003053001'],
@@ -1963,7 +1963,7 @@ module.exports = [
1963
1963
  extend: hueExtend.light_onoff_brightness_colortemp_color_gradient({colorTempRange: [153, 500]}),
1964
1964
  },
1965
1965
  {
1966
- zigbeeModel: ['915005987701'],
1966
+ zigbeeModel: ['929003479701'],
1967
1967
  model: '915005987701',
1968
1968
  vendor: 'Philips',
1969
1969
  description: 'Hue Gradient Signe floor lamp (wood)',
@@ -3323,32 +3323,46 @@ module.exports = [
3323
3323
  description: 'Hue white ambiance extra bright high lumen dimmable LED smart retrofit recessed 6" downlight',
3324
3324
  extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 500]}),
3325
3325
  },
3326
+ {
3327
+ zigbeeModel: ['929003115801'],
3328
+ model: '929003115801',
3329
+ vendor: 'Philips',
3330
+ description: 'Hue Perifo ceiling light, 1 pendant (white)',
3331
+ extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
3332
+ },
3333
+ {
3334
+ zigbeeModel: ['929003116201'],
3335
+ model: '929003116201',
3336
+ vendor: 'Philips',
3337
+ description: 'Hue Perifo linear light bar',
3338
+ extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
3339
+ },
3326
3340
  {
3327
3341
  zigbeeModel: ['929003115901'],
3328
3342
  model: '929003117101',
3329
3343
  vendor: 'Philips',
3330
- description: 'Hue Perifo Ceiling Light, 3 pendant (black)',
3344
+ description: 'Hue Perifo ceiling light, 3 pendant (black)',
3331
3345
  extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
3332
3346
  },
3333
3347
  {
3334
3348
  zigbeeModel: ['929003117201'],
3335
3349
  model: '929003117201',
3336
3350
  vendor: 'Philips',
3337
- description: 'Hue Perifo Ceiling Light, 3 pendant (white)',
3351
+ description: 'Hue Perifo ceiling light, 3 pendant (white)',
3338
3352
  extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
3339
3353
  },
3340
3354
  {
3341
3355
  zigbeeModel: ['929003117301'],
3342
3356
  model: '929003117301',
3343
3357
  vendor: 'Philips',
3344
- description: 'Hue Perifo Ceiling Light, 4 spotlights (black)',
3358
+ description: 'Hue Perifo ceiling light, 4 spotlights (black)',
3345
3359
  extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
3346
3360
  },
3347
3361
  {
3348
3362
  zigbeeModel: ['929003117401'],
3349
3363
  model: '929003117401',
3350
3364
  vendor: 'Philips',
3351
- description: 'Hue Perifo Ceiling Light, 4 spotlights (white)',
3365
+ description: 'Hue Perifo ceiling light, 4 spotlights (white)',
3352
3366
  extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
3353
3367
  },
3354
3368
  {
@@ -5,6 +5,7 @@ const constants = require('../lib/constants');
5
5
  const reporting = require('../lib/reporting');
6
6
  const extend = require('../lib/extend');
7
7
  const utils = require('../lib/utils');
8
+ const ota = require('../lib/ota');
8
9
  const e = exposes.presets;
9
10
  const ea = exposes.access;
10
11
 
@@ -981,4 +982,28 @@ module.exports = [
981
982
  .withUnit('A').withDescription('Instantaneous measured electrical current on phase C'),
982
983
  ],
983
984
  },
985
+ {
986
+ zigbeeModel: ['W599001'],
987
+ model: 'W599001',
988
+ vendor: 'Schneider Electric',
989
+ description: 'Wiser smoke alarm',
990
+ fromZigbee: [fz.temperature, fz.battery, fz.ias_enroll, fz.ias_smoke_alarm_1],
991
+ toZigbee: [],
992
+ ota: ota.zigbeeOTA, // local OTA updates are untested
993
+ exposes: [e.smoke(), e.battery_low(), e.tamper(), e.battery(), e.battery_voltage(),
994
+ // the temperature readings are unreliable and may need more investigation.
995
+ e.temperature(),
996
+ ],
997
+ configure: async (device, coordinatorEndpoint, logger) => {
998
+ const endpoint = device.getEndpoint(20);
999
+ const binds = ['msTemperatureMeasurement', 'ssIasZone', 'genPowerCfg'];
1000
+ await reporting.bind(endpoint, coordinatorEndpoint, binds);
1001
+ await reporting.batteryPercentageRemaining(endpoint);
1002
+ await reporting.batteryVoltage(endpoint);
1003
+ await reporting.temperature(endpoint);
1004
+ await endpoint.read('msTemperatureMeasurement', ['measuredValue']);
1005
+ await endpoint.read('ssIasZone', ['iasCieAddr', 'zoneState', 'zoneStatus', 'zoneId']);
1006
+ await endpoint.read('genPowerCfg', ['batteryVoltage', 'batteryPercentageRemaining']);
1007
+ },
1008
+ },
984
1009
  ];
@@ -620,7 +620,7 @@ module.exports = [
620
620
  },
621
621
  exposes: [e.battery(), e.lock(), exposes.enum('door_state', ea.STATE, ['open', 'closed']).withDescription('Door status'),
622
622
  e.lock_action(), e.lock_action_source_name(), e.lock_action_user(),
623
- exposes.composite('pin_code', 'pin_code')
623
+ exposes.composite('pin_code', 'pin_code', ea.ALL)
624
624
  .withFeature(exposes.numeric('user', ea.SET).withDescription('User ID can only number 1'))
625
625
  .withFeature(exposes.numeric('pin_code', ea.SET).withDescription('Pincode to set, set pincode(4 digit) to null to clear')),
626
626
  ],
package/devices/sinope.js CHANGED
@@ -860,12 +860,12 @@ module.exports = [
860
860
  .withDescription('Control status LED intensity when load ON'),
861
861
  exposes.numeric('led_intensity_off', ea.ALL).withValueMin(0).withValueMax(100)
862
862
  .withDescription('Control status LED intensity when load OFF'),
863
- exposes.composite('led_color_on', 'led_color_on')
863
+ exposes.composite('led_color_on', 'led_color_on', ea.SET)
864
864
  .withFeature(exposes.numeric('r', ea.SET))
865
865
  .withFeature(exposes.numeric('g', ea.SET))
866
866
  .withFeature(exposes.numeric('b', ea.SET))
867
867
  .withDescription('Control status LED color when load ON'),
868
- exposes.composite('led_color_off', 'led_color_off')
868
+ exposes.composite('led_color_off', 'led_color_off', ea.SET)
869
869
  .withFeature(exposes.numeric('r', ea.SET))
870
870
  .withFeature(exposes.numeric('g', ea.SET))
871
871
  .withFeature(exposes.numeric('b', ea.SET))
@@ -894,12 +894,12 @@ module.exports = [
894
894
  .withDescription('Control status LED when load OFF'),
895
895
  exposes.numeric('minimum_brightness', ea.ALL).withValueMin(0).withValueMax(3000)
896
896
  .withDescription('Control minimum dimmer brightness'),
897
- exposes.composite('led_color_on', 'led_color_on')
897
+ exposes.composite('led_color_on', 'led_color_on', ea.SET)
898
898
  .withFeature(exposes.numeric('r', ea.SET))
899
899
  .withFeature(exposes.numeric('g', ea.SET))
900
900
  .withFeature(exposes.numeric('b', ea.SET))
901
901
  .withDescription('Control status LED color when load ON'),
902
- exposes.composite('led_color_off', 'led_color_off')
902
+ exposes.composite('led_color_off', 'led_color_off', ea.SET)
903
903
  .withFeature(exposes.numeric('r', ea.SET))
904
904
  .withFeature(exposes.numeric('g', ea.SET))
905
905
  .withFeature(exposes.numeric('b', ea.SET))
@@ -930,7 +930,7 @@ module.exports = [
930
930
  await reporting.activePower(endpoint, {min: 10, max: 305, change: 1}); // divider 10 : 0.1W
931
931
  await reporting.rmsCurrent(endpoint, {min: 10, max: 306, change: 10}); // divider 100: 0.1Arms
932
932
  await reporting.rmsVoltage(endpoint, {min: 10, max: 307, change: 10}); // divider 100: 0.1Vrms
933
- await reporting.currentSummDelivered(endpoint, {min: 10, max: 303, change: [1, 1]});
933
+ await reporting.currentSummDelivered(endpoint, {min: 10, max: 303, change: [0, 1]}); // divider 1
934
934
  },
935
935
  },
936
936
  {
@@ -950,7 +950,7 @@ module.exports = [
950
950
  await reporting.activePower(endpoint, {min: 10, max: 305, change: 1}); // divider 10 : 0.1W
951
951
  await reporting.rmsCurrent(endpoint, {min: 10, max: 306, change: 10}); // divider 100: 0.1Arms
952
952
  await reporting.rmsVoltage(endpoint, {min: 10, max: 307, change: 10}); // divider 100: 0.1Vrms
953
- await reporting.currentSummDelivered(endpoint, {min: 10, max: 303, change: [1, 1]});
953
+ await reporting.currentSummDelivered(endpoint, {min: 10, max: 303, change: [0, 1]}); // divider 1
954
954
  },
955
955
  },
956
956
  {
@@ -48,7 +48,7 @@ module.exports = [
48
48
  toZigbee: [tz.tuya_dimmer_state, tz.tuya_light_wz5],
49
49
  exposes: [
50
50
  exposes.light().withBrightness().setAccess('state', ea.STATE_SET).setAccess('brightness',
51
- ea.STATE_SET).withColor(['hs']),
51
+ ea.STATE_SET).withColor(['hs']).setAccess('color_hs', ea.STATE_SET),
52
52
  ],
53
53
  },
54
54
  {
@@ -71,7 +71,7 @@ module.exports = [
71
71
  toZigbee: [tz.tuya_dimmer_state, tz.tuya_light_wz5],
72
72
  exposes: [
73
73
  exposes.light().withBrightness().setAccess('state', ea.STATE_SET).setAccess('brightness',
74
- ea.STATE_SET).withColor(['hs']),
74
+ ea.STATE_SET).withColor(['hs']).setAccess('color_hs', ea.STATE_SET),
75
75
  exposes.numeric('white_brightness', ea.STATE_SET).withValueMin(0).withValueMax(254).withDescription(
76
76
  'White brightness of this light'),
77
77
  ],
@@ -90,7 +90,7 @@ module.exports = [
90
90
  exposes: [
91
91
  exposes.light().withBrightness().setAccess('state', ea.STATE_SET).setAccess('brightness',
92
92
  ea.STATE_SET).withColor(['hs']).withColorTemp([250, 454]).setAccess('color_temp',
93
- ea.STATE_SET),
93
+ ea.STATE_SET).setAccess('color_hs', ea.STATE_SET),
94
94
  exposes.numeric('white_brightness', ea.STATE_SET).withValueMin(0).withValueMax(254).withDescription(
95
95
  'White brightness of this light'),
96
96
  ],
@@ -1,7 +1,4 @@
1
- const exposes = require('../lib/exposes');
2
- const reporting = require('../lib/reporting');
3
1
  const extend = require('../lib/extend');
4
- const e = exposes.presets;
5
2
 
6
3
  module.exports = [
7
4
  {
@@ -18,23 +15,4 @@ module.exports = [
18
15
  description: 'Power plug',
19
16
  extend: extend.switch(),
20
17
  },
21
- {
22
- zigbeeModel: ['LXN56-1S27LX1.2'],
23
- model: 'NUE-ZBFLB',
24
- vendor: 'Nue / 3A',
25
- description: 'Smart fan light switch',
26
- extend: extend.switch(),
27
- exposes: [e.switch().withEndpoint('button_light'), e.switch().withEndpoint('button_fan_high'),
28
- e.switch().withEndpoint('button_fan_med'), e.switch().withEndpoint('button_fan_low')],
29
- endpoint: (device) => {
30
- return {'button_light': 1, 'button_fan_high': 2, 'button_fan_med': 3, 'button_fan_low': 4};
31
- },
32
- meta: {multiEndpoint: true},
33
- configure: async (device, coordinatorEndpoint, logger) => {
34
- await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ['genOnOff']);
35
- await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ['genOnOff']);
36
- await reporting.bind(device.getEndpoint(3), coordinatorEndpoint, ['genOnOff']);
37
- await reporting.bind(device.getEndpoint(4), coordinatorEndpoint, ['genOnOff']);
38
- },
39
- },
40
18
  ];
@@ -126,8 +126,7 @@ module.exports = [
126
126
  model: 'GP-WOU019BBDWG',
127
127
  vendor: 'SmartThings',
128
128
  description: 'Outlet with power meter',
129
- fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering],
130
- toZigbee: [tz.on_off],
129
+ extend: extend.switch({fromZigbee: [fz.electrical_measurement, fz.metering], exposes: [e.power(), e.energy()]}),
131
130
  configure: async (device, coordinatorEndpoint, logger) => {
132
131
  const endpoint = device.getEndpoint(1);
133
132
  await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering']);
@@ -139,7 +138,6 @@ module.exports = [
139
138
  await reporting.readMeteringMultiplierDivisor(endpoint);
140
139
  await reporting.currentSummDelivered(endpoint);
141
140
  },
142
- exposes: [e.switch(), e.power(), e.energy()],
143
141
  },
144
142
  {
145
143
  zigbeeModel: ['outlet'],
package/devices/sonoff.js CHANGED
@@ -90,7 +90,7 @@ module.exports = [
90
90
  model: 'S31ZB',
91
91
  vendor: 'SONOFF',
92
92
  description: 'Zigbee smart plug (US version)',
93
- extend: extend.switch(),
93
+ extend: extend.switch({disablePowerOnBehavior: true}),
94
94
  fromZigbee: [fz.on_off_skip_duplicate_transaction],
95
95
  configure: async (device, coordinatorEndpoint, logger) => {
96
96
  const endpoint = device.getEndpoint(1);
@@ -271,6 +271,14 @@ module.exports = [
271
271
  description: 'Constant Current Zigbee LED dimmable driver',
272
272
  extend: extend.light_onoff_brightness(),
273
273
  },
274
+ {
275
+ zigbeeModel: ['HK-DIM'],
276
+ model: '50208702',
277
+ vendor: 'Sunricher',
278
+ description: 'LED dimmable driver',
279
+ extend: extend.light_onoff_brightness(),
280
+ whiteLabel: [{vendor: 'Yphix', model: '50208702'}],
281
+ },
274
282
  {
275
283
  zigbeeModel: ['SR-ZG9040A-S'],
276
284
  model: 'SR-ZG9040A-S',
package/devices/tuya.js CHANGED
@@ -1009,6 +1009,8 @@ module.exports = [
1009
1009
  vendor: 'TuYa',
1010
1010
  description: 'Zigbee RGBW light',
1011
1011
  extend: extend.light_onoff_brightness_color({disablePowerOnBehavior: true}),
1012
+ exposes: [e.light_brightness_color({disablePowerOnBehavior: true})
1013
+ .setAccess('color_xy', ea.STATE_SET).setAccess('color_hs', ea.STATE_SET)],
1012
1014
  toZigbee: utils.replaceInArray(extend.light_onoff_brightness_color().toZigbee, [tz.light_color], [tzLocal.TS0504B_color]),
1013
1015
  meta: {applyRedFix: true},
1014
1016
  },
@@ -1153,11 +1155,18 @@ module.exports = [
1153
1155
  exposes.enum('sensitivity', ea.ALL, ['low', 'medium', 'high']).withDescription('PIR sensor sensitivity'),
1154
1156
  exposes.enum('keep_time', ea.ALL, [30, 60, 120]).withDescription('PIR keep time in seconds'),
1155
1157
  ],
1158
+ configure: async (device, coordinatorEndpoint, logger) => {
1159
+ const endpoint = device.getEndpoint(1);
1160
+ await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg']);
1161
+ await reporting.batteryPercentageRemaining(endpoint);
1162
+ await reporting.batteryVoltage(endpoint);
1163
+ },
1156
1164
  },
1157
1165
  {
1158
1166
  fingerprint: [{modelID: 'TS0207', manufacturerName: '_TZ3000_m0vaazab'},
1159
1167
  {modelID: 'TS0207', manufacturerName: '_TZ3000_ufttklsz'},
1160
1168
  {modelID: 'TS0207', manufacturerName: '_TZ3000_nkkl7uzv'},
1169
+ {modelID: 'TS0207', manufacturerName: '_TZ3000_misw04hq'},
1161
1170
  {modelID: 'TS0207', manufacturerName: '_TZ3000_gszjt2xx'},
1162
1171
  {modelID: 'TS0207', manufacturerName: '_TZ3000_5k5vh43t'}],
1163
1172
  model: 'TS0207_repeater',
@@ -2109,7 +2118,7 @@ module.exports = [
2109
2118
  toZigbee: [tz.tuya_cover_control, tz.tuya_cover_options],
2110
2119
  exposes: [
2111
2120
  e.cover_position().setAccess('position', ea.STATE_SET),
2112
- exposes.composite('options', 'options')
2121
+ exposes.composite('options', 'options', ea.STATE_SET)
2113
2122
  .withFeature(exposes.numeric('motor_speed', ea.STATE_SET)
2114
2123
  .withValueMin(0)
2115
2124
  .withValueMax(255)
@@ -2168,7 +2177,7 @@ module.exports = [
2168
2177
  .withRunningState(['idle', 'heat'], ea.STATE),
2169
2178
  e.auto_lock(), e.away_mode(), e.away_preset_days(), e.boost_time(), e.comfort_temperature(), e.eco_temperature(), e.force(),
2170
2179
  e.max_temperature(), e.min_temperature(), e.away_preset_temperature(),
2171
- exposes.composite('programming_mode').withDescription('Schedule MODE ⏱ - In this mode, ' +
2180
+ exposes.composite('programming_mode', 'programming_mode', ea.STATE).withDescription('Schedule MODE ⏱ - In this mode, ' +
2172
2181
  'the device executes a preset week programming temperature time and temperature.')
2173
2182
  .withFeature(e.week())
2174
2183
  .withFeature(exposes.text('workdays_schedule', ea.STATE_SET))
@@ -2224,7 +2233,7 @@ module.exports = [
2224
2233
  '- schedule for Monday used for each day (define it only for Monday). `mon_fri+sat+sun` - schedule for ' +
2225
2234
  'workdays used from Monday (define it only for Monday), Saturday and Sunday are defined separately. `separate` ' +
2226
2235
  '- schedule for each day is defined separately.'),
2227
- exposes.composite('schedule', 'schedule').withFeature(exposes.enum('week_day', ea.SET, ['monday', 'tuesday',
2236
+ exposes.composite('schedule', 'schedule', ea.SET).withFeature(exposes.enum('week_day', ea.SET, ['monday', 'tuesday',
2228
2237
  'wednesday', 'thursday', 'friday', 'saturday', 'sunday'])).withFeature(exposes.text('schedule', ea.SET))
2229
2238
  .withDescription('Schedule will work with "auto" preset. In this mode, the device executes ' +
2230
2239
  'a preset week programming temperature time and temperature. Before using these properties, check `working_day` ' +
@@ -2447,7 +2456,7 @@ module.exports = [
2447
2456
  'ON - In this mode, the thermostat stays open ' +
2448
2457
  'OFF - In this mode, the thermostat stays closed')
2449
2458
  .withSystemMode(['auto', 'heat', 'off'], ea.STATE_SET),
2450
- exposes.composite('programming_mode').withDescription('Auto MODE ⏱ - In this mode, ' +
2459
+ exposes.composite('programming_mode', 'programming_mode', ea.STATE).withDescription('Auto MODE ⏱ - In this mode, ' +
2451
2460
  'the device executes a preset week programming temperature time and temperature. ')
2452
2461
  .withFeature(exposes.text('monday_schedule', ea.STATE))
2453
2462
  .withFeature(exposes.text('tuesday_schedule', ea.STATE))
package/devices/ubisys.js CHANGED
@@ -704,7 +704,7 @@ module.exports = [
704
704
  'brightness_move_up_s2', 'brightness_move_down_s1', 'brightness_move_down_s2', 'brightness_stop_s1',
705
705
  'brightness_stop_s2']),
706
706
  e.light_brightness(),
707
- exposes.composite('level_config', 'level_config')
707
+ exposes.composite('level_config', 'level_config', ea.ALL)
708
708
  .withFeature(exposes.numeric('on_off_transition_time', ea.ALL)
709
709
  .withDescription('Specifies the amount of time, in units of 0.1 seconds, which will be used during a transition to ' +
710
710
  'either the on or off state, when an on/off/toggle command of the on/off cluster is used to turn the light on or off'))
package/devices/xiaomi.js CHANGED
@@ -2311,17 +2311,17 @@ module.exports = [
2311
2311
  .withDescription('Standby LCD brightness'),
2312
2312
  exposes.enum('available_switches', ea.STATE_SET, ['none', '1', '2', '3', '1 and 2', '1 and 3', '2 and 3', 'all'])
2313
2313
  .withDescription('Control which switches are available in the switches screen (none disables switches screen)'),
2314
- exposes.composite('switch_1_text_icon', 'switch_1_text_icon').withDescription('Switch 1 text and icon')
2314
+ exposes.composite('switch_1_text_icon', 'switch_1_text_icon', ea.STATE_SET).withDescription('Switch 1 text and icon')
2315
2315
  .withFeature(exposes.enum('switch_1_icon', ea.STATE_SET, ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11'])
2316
2316
  .withDescription('Icon'))
2317
2317
  .withFeature(exposes.text('switch_1_text', ea.STATE_SET)
2318
2318
  .withDescription('Text')),
2319
- exposes.composite('switch_2_text_icon', 'switch_2_text_icon').withDescription('Switch 2 text and icon')
2319
+ exposes.composite('switch_2_text_icon', 'switch_2_text_icon', ea.STATE_SET).withDescription('Switch 2 text and icon')
2320
2320
  .withFeature(exposes.enum('switch_2_icon', ea.STATE_SET, ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11'])
2321
2321
  .withDescription('Icon'))
2322
2322
  .withFeature(exposes.text('switch_2_text', ea.STATE_SET)
2323
2323
  .withDescription('Text')),
2324
- exposes.composite('switch_3_text_icon', 'switch_3_text_icon').withDescription('Switch 3 text and icon')
2324
+ exposes.composite('switch_3_text_icon', 'switch_3_text_icon', ea.STATE_SET).withDescription('Switch 3 text and icon')
2325
2325
  .withFeature(exposes.enum('switch_3_icon', ea.STATE_SET, ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11'])
2326
2326
  .withDescription('Icon'))
2327
2327
  .withFeature(exposes.text('switch_3_text', ea.STATE_SET)
@@ -2714,7 +2714,7 @@ module.exports = [
2714
2714
  exposes.numeric('weight_per_day', ea.STATE).withDescription('Weight per day').withUnit('g'),
2715
2715
  exposes.binary('error', ea.STATE, true, false)
2716
2716
  .withDescription('Indicates wether there is an error with the feeder'),
2717
- exposes.list('schedule', ea.STATE_SET, exposes.composite('dayTime', exposes.access.STATE_SET)
2717
+ exposes.list('schedule', ea.STATE_SET, exposes.composite('dayTime', 'dayTime', exposes.access.STATE_SET)
2718
2718
  .withFeature(exposes.enum('days', exposes.access.STATE_SET, [
2719
2719
  'everyday', 'workdays', 'weekend', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun',
2720
2720
  'mon-wed-fri-sun', 'tue-thu-sat']))
@@ -149,8 +149,8 @@ module.exports = [
149
149
  fromZigbee: [fz.ZMAM02_cover],
150
150
  toZigbee: [tz.ZMAM02_cover],
151
151
  exposes: [e.cover_position().setAccess('position', ea.STATE_SET),
152
- exposes.composite('options', 'options')
153
- .withFeature(exposes.numeric('motor_speed', ea.STATE_SET)
152
+ exposes.composite('options', 'options', ea.STATE)
153
+ .withFeature(exposes.numeric('motor_speed', ea.STATE)
154
154
  .withValueMin(0)
155
155
  .withValueMax(255)
156
156
  .withDescription('Motor speed')),
package/lib/exposes.js CHANGED
@@ -194,12 +194,13 @@ class Text extends Base {
194
194
  }
195
195
 
196
196
  class Composite extends Base {
197
- constructor(name, property) {
197
+ constructor(name, property, access) {
198
198
  super();
199
199
  this.type = 'composite';
200
200
  this.property = property;
201
201
  this.name = name;
202
202
  this.features = [];
203
+ this.access = access;
203
204
  }
204
205
 
205
206
  withFeature(feature) {
@@ -237,7 +238,7 @@ class Light extends Base {
237
238
 
238
239
  withLevelConfig() {
239
240
  assert(!this.endpoint, 'Cannot add feature after adding endpoint');
240
- const levelConfig = new Composite('level_config', 'level_config')
241
+ const levelConfig = new Composite('level_config', 'level_config', access.ALL)
241
242
  .withFeature(new Numeric('on_off_transition_time', access.ALL)
242
243
  .withDescription('Represents the time taken to move to or from the target level when On of Off commands are received by an On/Off cluster'),
243
244
  )
@@ -313,13 +314,13 @@ class Light extends Base {
313
314
  assert(!this.endpoint, 'Cannot add feature after adding endpoint');
314
315
  for (const type of types) {
315
316
  if (type === 'xy') {
316
- const colorXY = new Composite('color_xy', 'color')
317
+ const colorXY = new Composite('color_xy', 'color', access.ALL)
317
318
  .withFeature(new Numeric('x', access.ALL))
318
319
  .withFeature(new Numeric('y', access.ALL))
319
320
  .withDescription('Color of this light in the CIE 1931 color space (x/y)');
320
321
  this.features.push(colorXY);
321
322
  } else if (type === 'hs') {
322
- const colorHS = new Composite('color_hs', 'color')
323
+ const colorHS = new Composite('color_hs', 'color', access.ALL)
323
324
  .withFeature(new Numeric('hue', access.ALL))
324
325
  .withFeature(new Numeric('saturation', access.ALL))
325
326
  .withDescription('Color of this light expressed as hue/saturation');
@@ -491,7 +492,7 @@ module.exports = {
491
492
  access,
492
493
  binary: (name, access, valueOn, valueOff) => new Binary(name, access, valueOn, valueOff),
493
494
  climate: () => new Climate(),
494
- composite: (name, property) => new Composite(name, property),
495
+ composite: (name, property, access) => new Composite(name, property, access),
495
496
  cover: () => new Cover(),
496
497
  enum: (name, access, values) => new Enum(name, access, values),
497
498
  light: () => new Light(),
@@ -509,7 +510,7 @@ module.exports = {
509
510
  occupancy_timeout: () => new Numeric(`occupancy_timeout`, access.SET).withValueMin(0).withDescription('Time in seconds after which occupancy is cleared after detecting it (default 90 seconds).'),
510
511
  occupancy_timeout_2: () => new Numeric(`occupancy_timeout`, access.SET).withValueMin(0).withValueStep(0.1).withUnit('s').withDescription('Time in seconds after which occupancy is cleared after detecting it (default is "detection_interval" + 2 seconds). The value must be equal to or greater than "detection_interval", and it can also be a fraction.'),
511
512
  vibration_timeout: () => new Numeric(`vibration_timeout`, access.SET).withValueMin(0).withDescription('Time in seconds after which vibration is cleared after detecting it (default 90 seconds).'),
512
- simulated_brightness: (extraNote='') => new Composite('simulated_brightness', 'simulated_brightness')
513
+ simulated_brightness: (extraNote='') => new Composite('simulated_brightness', 'simulated_brightness', access.SET)
513
514
  .withDescription(`Simulate a brightness value. If this device provides a brightness_move_up or brightness_move_down action it is possible to specify the update interval and delta. The action_brightness_delta indicates the delta for each interval. ${extraNote}`)
514
515
  .withFeature(new Numeric('delta', access.SET).withValueMin(0).withDescription('Delta per interval, 20 by default'))
515
516
  .withFeature(new Numeric('interval', access.SET).withValueMin(0).withUnit('ms').withDescription('Interval duration')),
@@ -535,7 +536,7 @@ module.exports = {
535
536
  away_mode: () => new Switch().withState('away_mode', false, 'Enable/disable away mode', access.STATE_SET),
536
537
  away_preset_days: () => new Numeric('away_preset_days', access.STATE_SET).withDescription('Away preset days').withValueMin(0).withValueMax(100),
537
538
  away_preset_temperature: () => new Numeric('away_preset_temperature', access.STATE_SET).withUnit('°C').withDescription('Away preset temperature').withValueMin(-10).withValueMax(35),
538
- battery: () => new Numeric('battery', access.STATE).withUnit('%').withDescription('Remaining battery in %').withValueMin(0).withValueMax(100),
539
+ battery: () => new Numeric('battery', access.STATE).withUnit('%').withDescription('Remaining battery in %, can take up to 24 hours before reported.').withValueMin(0).withValueMax(100),
539
540
  battery_low: () => new Binary('battery_low', access.STATE, true, false).withDescription('Indicates if the battery of this device is almost empty'),
540
541
  battery_voltage: () => new Numeric('voltage', access.STATE).withUnit('mV').withDescription('Voltage of the battery in millivolts'),
541
542
  boost_time: () => new Numeric('boost_time', access.STATE_SET).withUnit('s').withDescription('Boost time').withValueMin(0).withValueMax(900),
@@ -637,7 +638,7 @@ module.exports = {
637
638
  voltage_phase_b: () => new Numeric('voltage_phase_b', access.STATE).withUnit('V').withDescription('Measured electrical potential value on phase B'),
638
639
  voltage_phase_c: () => new Numeric('voltage_phase_c', access.STATE).withUnit('V').withDescription('Measured electrical potential value on phase C'),
639
640
  water_leak: () => new Binary('water_leak', access.STATE, true, false).withDescription('Indicates whether the device detected a water leak'),
640
- warning: () => new Composite('warning', 'warning')
641
+ warning: () => new Composite('warning', 'warning', access.SET)
641
642
  .withFeature(new Enum('mode', access.SET, ['stop', 'burglar', 'fire', 'emergency', 'police_panic', 'fire_panic', 'emergency_panic']).withDescription('Mode of the warning (sound effect)'))
642
643
  .withFeature(new Enum('level', access.SET, ['low', 'medium', 'high', 'very_high']).withDescription('Sound level'))
643
644
  .withFeature(new Enum('strobe_level', access.SET, ['low', 'medium', 'high', 'very_high']).withDescription('Intensity of the strobe'))
@@ -650,12 +651,12 @@ module.exports = {
650
651
  x_axis: () => new Numeric('x_axis', access.STATE).withDescription('Accelerometer X value'),
651
652
  y_axis: () => new Numeric('y_axis', access.STATE).withDescription('Accelerometer Y value'),
652
653
  z_axis: () => new Numeric('z_axis', access.STATE).withDescription('Accelerometer Z value'),
653
- pincode: () => new Composite('pin_code', 'pin_code')
654
+ pincode: () => new Composite('pin_code', 'pin_code', access.ALL)
654
655
  .withFeature(new Numeric('user', access.SET).withDescription('User ID to set or clear the pincode for'))
655
656
  .withFeature(new Enum('user_type', access.SET, ['unrestricted', 'year_day_schedule', 'week_day_schedule', 'master', 'non_access']).withDescription('Type of user, unrestricted: owner (default), (year|week)_day_schedule: user has ability to open lock based on specific time period, master: user has ability to both program and operate the door lock, non_access: user is recognized by the lock but does not have the ability to open the lock'))
656
657
  .withFeature(new Binary('user_enabled', access.SET, true, false).withDescription('Whether the user is enabled/disabled'))
657
658
  .withFeature(new Numeric('pin_code', access.SET).withDescription('Pincode to set, set pincode to null to clear')),
658
- squawk: () => new Composite('squawk', 'squawk')
659
+ squawk: () => new Composite('squawk', 'squawk', access.SET)
659
660
  .withFeature(new Enum('state', access.SET, ['system_is_armed', 'system_is_disarmed']).withDescription('Set Squawk state'))
660
661
  .withFeature(new Enum('level', access.SET, ['low', 'medium', 'high', 'very_high']).withDescription('Sound level'))
661
662
  .withFeature(new Binary('strobe', access.SET, true, false).withDescription('Turn on/off the strobe (light) for Squawk')),
package/lib/extend.js CHANGED
@@ -6,10 +6,10 @@ const light = require('./light');
6
6
 
7
7
  const extend = {
8
8
  switch: (options={}) => {
9
- options = {disablePowerOnBehavior: false, ...options};
10
- const exposes = [e.switch()];
11
- const fromZigbee = [fz.on_off, fz.ignore_basic_report];
12
- const toZigbee = [tz.on_off];
9
+ options = {disablePowerOnBehavior: false, toZigbee: [], fromZigbee: [], exposes: [], ...options};
10
+ const exposes = [e.switch(), ...options.exposes];
11
+ const fromZigbee = [fz.on_off, fz.ignore_basic_report, ...options.fromZigbee];
12
+ const toZigbee = [tz.on_off, ...options.toZigbee];
13
13
  if (!options.disablePowerOnBehavior) {
14
14
  exposes.push(e.power_on_behavior(['off', 'on', 'toggle', 'previous']));
15
15
  fromZigbee.push(fz.power_on_behavior);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zigbee-herdsman-converters",
3
- "version": "15.0.20",
3
+ "version": "15.0.22",
4
4
  "description": "Collection of device converters to be used with zigbee-herdsman",
5
5
  "main": "index.js",
6
6
  "files": [