zigbee-herdsman-converters 15.0.61 → 15.0.63

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.
@@ -1514,8 +1514,8 @@ const converters = {
1514
1514
  const payload = {
1515
1515
  action: postfixWithEndpointName(`color_move`, msg, model, meta),
1516
1516
  action_color: {
1517
- x: precisionRound(msg.data.colorx / 65536, 3),
1518
- y: precisionRound(msg.data.colory / 65536, 3),
1517
+ x: precisionRound(msg.data.colorx / 65535, 3),
1518
+ y: precisionRound(msg.data.colory / 65535, 3),
1519
1519
  },
1520
1520
  action_transition_time: msg.data.transtime,
1521
1521
  };
@@ -2886,6 +2886,18 @@ const converters = {
2886
2886
  return {action: `${button}${clickMapping[msg.data[3]]}`};
2887
2887
  },
2888
2888
  },
2889
+ tuya_switch_scene: {
2890
+ cluster: 'genOnOff',
2891
+ type: 'raw',
2892
+ convert: (model, msg, publish, options, meta) => {
2893
+ if (hasAlreadyProcessedMessage(msg, model, msg.data[1])) return;
2894
+ // Since it is a non standard ZCL command, no default response is send from zigbee-herdsman
2895
+ // Send the defaultResponse here, otherwise the second button click delays.
2896
+ // https://github.com/Koenkk/zigbee2mqtt/issues/8149
2897
+ msg.endpoint.defaultResponse(0xfd, 0, 6, msg.data[1]).catch((error) => {});
2898
+ return {action: 'switch_scene', action_scene: msg.data[3]};
2899
+ },
2900
+ },
2889
2901
  tuya_water_leak: {
2890
2902
  cluster: 'manuSpecificTuya',
2891
2903
  type: 'commandDataReport',
@@ -1222,24 +1222,69 @@ const converters = {
1222
1222
  key: ['weekly_schedule'],
1223
1223
  convertSet: async (entity, key, value, meta) => {
1224
1224
  const payload = {
1225
- numoftrans: value.numoftrans,
1226
1225
  dayofweek: value.dayofweek,
1227
- mode: value.mode,
1228
1226
  transitions: value.transitions,
1229
1227
  };
1230
1228
 
1229
+ if (Array.isArray(payload.transitions)) {
1230
+ // calculate numoftrans
1231
+ if (typeof value.numoftrans !== 'undefined') {
1232
+ meta.logger.warn(`weekly_schedule: igonoring provided numoftrans value (${JSON.stringify(value.numoftrans)}),\
1233
+ this is now calculated automatically`);
1234
+ }
1235
+ payload.numoftrans = payload.transitions.length;
1231
1236
 
1232
- // map array of desired modes to bitmask
1233
- if (typeof payload.dayofweek === 'string') payload.dayofweek = [payload.dayofweek];
1234
- if (Array.isArray(payload.dayofweek)) {
1235
- let mode = 0;
1236
- for (let m of payload.mode) {
1237
- // lookup mode bit
1238
- m = utils.getKey(constants.thermostatScheduleMode, m.toLowerCase(), m, Number);
1239
- mode |= (1 << m);
1237
+ // mode is calculated below
1238
+ if (typeof value.mode !== 'undefined') {
1239
+ meta.logger.warn(
1240
+ `weekly_schedule: igonoring provided mode value (${JSON.stringify(value.mode)}),\
1241
+ this is now calculated automatically`);
1242
+ }
1243
+ payload.mode = [];
1244
+
1245
+ // transform transition payload values if needed
1246
+ for (const elem of payload.transitions) {
1247
+ // update payload.mode if needed
1248
+ if (elem.hasOwnProperty('heatSetpoint') && !payload.mode.includes('heat')) {
1249
+ payload.mode.push('heat');
1250
+ }
1251
+ if (elem.hasOwnProperty('coolSetpoint') && !payload.mode.includes('cool')) {
1252
+ payload.mode.push('cool');
1253
+ }
1254
+
1255
+ // transform setpoint values if numeric
1256
+ if (typeof elem['heatSetpoint'] === 'number') {
1257
+ elem['heatSetpoint'] = Math.round(elem['heatSetpoint'] * 100);
1258
+ }
1259
+ if (typeof elem['coolSetpoint'] === 'number') {
1260
+ elem['coolSetpoint'] = Math.round(elem['coolSetpoint'] * 100);
1261
+ }
1262
+
1263
+ // accept 24h time notation (e.g. 19:30)
1264
+ if (typeof elem['transitionTime'] === 'string') {
1265
+ const time = elem['transitionTime'].split(':');
1266
+ if ((time.length != 2) || isNaN(time[0]) || isNaN(time[1])) {
1267
+ meta.logger.warn(
1268
+ `weekly_schedule: expected 24h time notation (e.g. 19:30) but got '${elem['transitionTime']}'!`,
1269
+ );
1270
+ } else {
1271
+ elem['transitionTime'] = ((parseInt(time[0]) * 60) + parseInt(time[1]));
1272
+ }
1273
+ }
1240
1274
  }
1241
- payload.mode = mode;
1275
+ } else {
1276
+ meta.logger.error('weekly_schedule: transitions is not an array!');
1277
+ return;
1278
+ }
1279
+
1280
+ // map array of desired modes to bitmask
1281
+ let mode = 0;
1282
+ for (let m of payload.mode) {
1283
+ // lookup mode bit
1284
+ m = utils.getKey(constants.thermostatScheduleMode, m.toLowerCase(), m, Number);
1285
+ mode |= (1 << m);
1242
1286
  }
1287
+ payload.mode = mode;
1243
1288
 
1244
1289
  // map array of days to desired dayofweek bitmask
1245
1290
  if (typeof payload.dayofweek === 'string') payload.dayofweek = [payload.dayofweek];
@@ -1253,24 +1298,6 @@ const converters = {
1253
1298
  payload.dayofweek = dayofweek;
1254
1299
  }
1255
1300
 
1256
- for (const elem of payload['transitions']) {
1257
- if (typeof elem['heatSetpoint'] === 'number') {
1258
- elem['heatSetpoint'] = Math.round(elem['heatSetpoint'] * 100);
1259
- }
1260
- if (typeof elem['coolSetpoint'] === 'number') {
1261
- elem['coolSetpoint'] = Math.round(elem['coolSetpoint'] * 100);
1262
- }
1263
-
1264
- // accept 24h time notation (e.g. 19:30)
1265
- if (typeof elem['transitionTime'] === 'string') {
1266
- const time = elem['transitionTime'].split(':');
1267
- if ((time.length != 2) || isNaN(time[0]) || isNaN(time[1])) {
1268
- meta.logger.warn(`weekly_schedule: expected 24h time notation (e.g. 19:30) but got '${elem['transitionTime']}'!`);
1269
- } else {
1270
- elem['transitionTime'] = ((parseInt(time[0]) * 60) + parseInt(time[1]));
1271
- }
1272
- }
1273
- }
1274
1301
  await entity.command('hvacThermostat', 'setWeeklySchedule', payload, utils.getOptions(meta.mapped, entity));
1275
1302
  },
1276
1303
  convertGet: async (entity, key, meta) => {
@@ -115,6 +115,13 @@ module.exports = [
115
115
  meta: {turnsOffAtBrightness1: true},
116
116
  extend: extend.light_onoff_brightness(),
117
117
  },
118
+ {
119
+ zigbeeModel: ['FWBulb51AU'],
120
+ model: 'AU-A1GSZ9B/27',
121
+ vendor: 'Aurora Lighting',
122
+ description: 'AOne 9W smart GLS B22',
123
+ extend: extend.light_onoff_brightness(),
124
+ },
118
125
  {
119
126
  zigbeeModel: ['FWGU10Bulb50AU', 'FWGU10Bulb01UK'],
120
127
  model: 'AU-A1GUZB5/30',
package/devices/lidl.js CHANGED
@@ -575,8 +575,8 @@ module.exports = [
575
575
  vendor: 'Lidl',
576
576
  description: 'Livarno Lux switch and dimming light remote control',
577
577
  exposes: [e.action(['on', 'off', 'brightness_stop', 'brightness_step_up', 'brightness_step_down', 'brightness_move_up',
578
- 'brightness_move_down'])],
579
- fromZigbee: [fz.command_on, fz.command_off, fz.command_step, fz.command_move, fz.command_stop],
578
+ 'brightness_move_down', 'switch_scene'])],
579
+ fromZigbee: [fz.command_on, fz.command_off, fz.command_step, fz.command_move, fz.command_stop, fz.tuya_switch_scene],
580
580
  toZigbee: [],
581
581
  },
582
582
  {
package/devices/namron.js CHANGED
@@ -452,7 +452,7 @@ module.exports = [
452
452
  const time = Math.round(((new Date()).getTime() - constants.OneJanuary2000) / 1000 + ((new Date())
453
453
  .getTimezoneOffset() * -1) * 60);
454
454
  const values = {time: time};
455
- endpoint.write('genTime', values);
455
+ await endpoint.write('genTime', values);
456
456
  } catch (error) {/* Do nothing*/}
457
457
  }, hours24);
458
458
  globalStore.putValue(device, 'time', interval);
@@ -962,6 +962,13 @@ module.exports = [
962
962
  description: 'Hue White and color ambiance Play Lightbar',
963
963
  extend: philips.extend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
964
964
  },
965
+ {
966
+ zigbeeModel: ['915005988501'],
967
+ model: '915005988501',
968
+ vendor: 'Philips',
969
+ description: 'Play gradient light tube large',
970
+ extend: philips.extend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
971
+ },
965
972
  {
966
973
  zigbeeModel: ['LTW011', 'LTB002'],
967
974
  model: '464800',
@@ -1781,6 +1788,13 @@ module.exports = [
1781
1788
  description: 'Hue Centura',
1782
1789
  extend: philips.extend.light_onoff_brightness_colortemp_color(),
1783
1790
  },
1791
+ {
1792
+ zigbeeModel: ['LWV007'],
1793
+ model: '9290030523',
1794
+ vendor: 'Philips',
1795
+ description: 'Hue white filament Edison ST72 LED',
1796
+ extend: philips.extend.light_onoff_brightness(),
1797
+ },
1784
1798
  {
1785
1799
  zigbeeModel: ['5055148P7'],
1786
1800
  model: '5055148P7',
@@ -7,5 +7,10 @@ module.exports = [
7
7
  vendor: 'Fischer & Honsel',
8
8
  description: 'LED Tischleuchte Beta Zig',
9
9
  extend: extend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 370]}),
10
+ endpoint: (device) => {
11
+ // https://github.com/Koenkk/zigbee-herdsman-converters/issues/5463
12
+ const endpoint = device.endpoints.find((e) => e.inputClusters.includes(6)).ID;
13
+ return {'default': endpoint};
14
+ },
10
15
  },
11
16
  ];
package/devices/sonoff.js CHANGED
@@ -216,7 +216,7 @@ module.exports = [
216
216
  model: 'S40ZBTPB',
217
217
  vendor: 'SONOFF',
218
218
  description: '15A Zigbee smart plug',
219
- extend: extend.switch(),
219
+ extend: extend.switch({disablePowerOnBehavior: true}),
220
220
  fromZigbee: [fz.on_off_skip_duplicate_transaction],
221
221
  ota: ota.zigbeeOTA,
222
222
  configure: async (device, coordinatorEndpoint, logger) => {
package/devices/tuya.js CHANGED
@@ -1740,7 +1740,7 @@ module.exports = [
1740
1740
  configure: tuya.configureMagicPacket,
1741
1741
  },
1742
1742
  {
1743
- fingerprint: [{modelID: 'SM0201', manufacturerName: '_TYZB01_cbiezpds'}],
1743
+ fingerprint: tuya.fingerprint('SM0201', ['_TYZB01_cbiezpds', '_TYZB01_zqvwka4k']),
1744
1744
  model: 'SM0201',
1745
1745
  vendor: 'TuYa',
1746
1746
  description: 'Temperature & humidity sensor with LED screen',
@@ -3415,7 +3415,7 @@ module.exports = [
3415
3415
  fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering, fz.ignore_basic_report, tuya.fz.power_outage_memory,
3416
3416
  fz.tuya_relay_din_led_indicator],
3417
3417
  toZigbee: [tz.on_off, tuya.tz.power_on_behavior, tz.tuya_relay_din_led_indicator],
3418
- whiteLabel: [{vendor: 'MatSee Plus', model: 'ATMS1602Z'}],
3418
+ whiteLabel: [{vendor: 'MatSee Plus', model: 'ATMS1602Z'}, {vendor: 'Tongou', model: 'TO-Q-SY1-JZT'}],
3419
3419
  ota: ota.zigbeeOTA,
3420
3420
  configure: async (device, coordinatorEndpoint, logger) => {
3421
3421
  const endpoint = device.getEndpoint(1);
package/devices/xiaomi.js CHANGED
@@ -142,6 +142,11 @@ const fzLocal = {
142
142
  result['schedule_settings'] = trv.stringifySchedule(schedule);
143
143
  break;
144
144
  }
145
+ case 0x00EE: {
146
+ meta.device.meta.aqaraFileVersion = value;
147
+ meta.device.save();
148
+ break;
149
+ }
145
150
  case 0xfff2:
146
151
  case 0x00ff: // 4e:27:49:bb:24:b6:30:dd:74:de:53:76:89:44:c4:81
147
152
  case 0x027c: // 0x00
package/lib/constants.js CHANGED
@@ -24,6 +24,7 @@ const thermostatControlSequenceOfOperations = {
24
24
  const thermostatProgrammingOperationModes = {
25
25
  0: 'setpoint',
26
26
  1: 'schedule',
27
+ 3: 'schedule_with_preheat',
27
28
  4: 'eco',
28
29
  };
29
30
 
package/lib/exposes.js CHANGED
@@ -626,7 +626,7 @@ module.exports = {
626
626
  power_outage_memory: () => new Binary('power_outage_memory', access.ALL, true, false).withDescription('Enable/disable the power outage memory, this recovers the on/off mode after power failure'),
627
627
  presence: () => new Binary('presence', access.STATE, true, false).withDescription('Indicates whether the device detected presence'),
628
628
  pressure: () => new Numeric('pressure', access.STATE).withUnit('hPa').withDescription('The measured atmospheric pressure'),
629
- programming_operation_mode: () => new Enum('programming_operation_mode', access.ALL, ['setpoint', 'schedule', 'eco']).withDescription('Controls how programming affects the thermostat. Possible values: setpoint (only use specified setpoint), schedule (follow programmed setpoint schedule). Changing this value does not clear programmed schedules.'),
629
+ programming_operation_mode: () => new Enum('programming_operation_mode', access.ALL, ['setpoint', 'schedule', 'schedule_with_preheat', 'eco']).withDescription('Controls how programming affects the thermostat. Possible values: setpoint (only use specified setpoint), schedule (follow programmed setpoint schedule), schedule_with_preheat (follow programmed setpoint schedule with pre-heating). Changing this value does not clear programmed schedules.'),
630
630
  smoke: () => new Binary('smoke', access.STATE, true, false).withDescription('Indicates whether the device detected smoke'),
631
631
  soil_moisture: () => new Numeric('soil_moisture', access.STATE).withUnit('%').withDescription('Measured soil moisture value'),
632
632
  sos: () => new Binary('sos', access.STATE, true, false).withDescription('SOS alarm'),
@@ -122,12 +122,26 @@ async function getImageMeta(current, logger, device) {
122
122
  };
123
123
  }
124
124
 
125
+ async function isNewImageAvailable(current, logger, device, getImageMeta) {
126
+ if (device.modelID === 'lumi.airrtc.agl001') {
127
+ // The current.fileVersion which comes from the device is wrong.
128
+ // Use the `aqaraFileVersion` which comes from the aqaraOpple.attributeReport instead.
129
+ // https://github.com/Koenkk/zigbee2mqtt/issues/16345#issuecomment-1454835056
130
+ if (!device.meta.aqaraFileVersion) {
131
+ throw new Error(`Did not receive a current fileVersion from 'lumi.airrtc.agl001' yet, please wait some hours and try again`);
132
+ }
133
+ current = {...current, fileVersion: device.meta.aqaraFileVersion};
134
+ }
135
+
136
+ return common.isNewImageAvailable(current, logger, device, getImageMeta);
137
+ }
138
+
125
139
  /**
126
140
  * Interface implementation
127
141
  */
128
142
 
129
143
  async function isUpdateAvailable(device, logger, requestPayload=null) {
130
- return common.isUpdateAvailable(device, logger, common.isNewImageAvailable, requestPayload, getImageMeta);
144
+ return common.isUpdateAvailable(device, logger, isNewImageAvailable, requestPayload, getImageMeta);
131
145
  }
132
146
 
133
147
  async function updateToLatest(device, logger, onProgress) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zigbee-herdsman-converters",
3
- "version": "15.0.61",
3
+ "version": "15.0.63",
4
4
  "description": "Collection of device converters to be used with zigbee-herdsman",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -38,7 +38,7 @@
38
38
  "buffer-crc32": "^0.2.13",
39
39
  "https-proxy-agent": "^5.0.1",
40
40
  "tar-stream": "^3.0.0",
41
- "zigbee-herdsman": "^0.14.96"
41
+ "zigbee-herdsman": "^0.14.97"
42
42
  },
43
43
  "devDependencies": {
44
44
  "eslint": "*",