zigbee-herdsman-converters 14.0.385 → 14.0.389

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.
@@ -4362,6 +4362,14 @@ const converters = {
4362
4362
  convert: (model, msg, publis, options, meta) => {
4363
4363
  // Don't use in production!
4364
4364
  // Used in: https://www.zigbee2mqtt.io/how_tos/how_to_support_new_tuya_devices.html
4365
+ const getType = (datatype) => {
4366
+ const entry = Object.entries(tuya.dataTypes).find(([typeName, typeId]) => typeId === datatype);
4367
+ return (entry ? entry[0] : 'unknown');
4368
+ };
4369
+ const getAllDpIds = (dp) => {
4370
+ const entries = Object.entries(tuya.dataPoints).filter(([dpName, dpId]) => dpId === dp);
4371
+ return entries.map(([dpName, dpId]) => dpName);
4372
+ };
4365
4373
  const getHex = (value) => {
4366
4374
  let hex = value.toString(16);
4367
4375
  if (hex.length < 2) {
@@ -4372,6 +4380,11 @@ const converters = {
4372
4380
  const now = Date.now().toString();
4373
4381
  let dataStr = '';
4374
4382
  for (const [i, dpValue] of msg.data.dpValues.entries()) {
4383
+ const value = tuya.getDataValue(dpValue);
4384
+ meta.logger.info(`zigbee-herdsman-converters:tuya_data_point_dump: Received DP #${
4385
+ dpValue.dp} from ${meta.device.ieeeAddr} with raw data '${JSON.stringify(dpValue)}': type='${msg.type}', datatype='${
4386
+ getType(dpValue.datatype)}', value='${value}', known DP# usage: ${JSON.stringify(getAllDpIds(dpValue.dp))}`);
4387
+
4375
4388
  dataStr +=
4376
4389
  now + ' ' +
4377
4390
  meta.device.ieeeAddr + ' ' +
@@ -5177,7 +5190,9 @@ const converters = {
5177
5190
  payload.voltage = value;
5178
5191
  payload.battery = batteryVoltageToPercentage(value, '3V_2100');
5179
5192
  } else if (index === 3) payload.temperature = calibrateAndPrecisionRoundOptions(value, options, 'temperature'); // 0x03
5180
- else if (index === 100) {
5193
+ else if (index === 5) {
5194
+ if (['JT-BZ-01AQ/A'].includes(model.model)) payload.power_outage_count = value;
5195
+ } else if (index === 100) {
5181
5196
  if (['QBKG19LM', 'QBKG20LM', 'QBKG39LM', 'QBKG41LM', 'QBCZ15LM'].includes(model.model)) {
5182
5197
  const mapping = model.model === 'QBCZ15LM' ? 'relay' : 'left';
5183
5198
  payload[`state_${mapping}`] = value === 1 ? 'ON' : 'OFF';
@@ -5198,15 +5213,37 @@ const converters = {
5198
5213
  } else if (index === 150) payload.voltage = precisionRound(value * 0.1, 1); // 0x96
5199
5214
  else if (index === 151) payload.current = precisionRound(value * 0.001, 4); // 0x97
5200
5215
  else if (index === 152) payload.power = precisionRound(value, 2); // 0x98
5216
+ else if (index === 159) payload.gas_sensitivity = {1: '15%LEL', 2: '10%LEL'}[value]; // JT-BZ-01AQ/A
5217
+ else if (index === 160) payload.gas = value === 1; // JT-BZ-01AQ/A
5218
+ else if (index === 161) payload.gas_density = value; // JT-BZ-01AQ/A
5219
+ else if (index === 162) payload.test = value === 1; // JT-BZ-01AQ/A
5220
+ else if (index === 163) payload.mute = value === 1; // JT-BZ-01AQ/A
5221
+ else if (index === 164) payload.state = value === 1 ? 'preparation' : 'work'; // JT-BZ-01AQ/A
5222
+ else if (index === 166) payload.linkage_alarm = value === 1; // JT-BZ-01AQ/A
5201
5223
  else if (meta.logger) meta.logger.debug(`${model.zigbeeModel}: unknown index ${index} with value ${value}`);
5202
5224
  }
5203
5225
  }
5204
5226
 
5205
5227
  if (msg.data.hasOwnProperty('0')) payload.detection_period = msg.data['0'];
5228
+ if (msg.data.hasOwnProperty('2')) {
5229
+ if (['JT-BZ-01AQ/A'].includes(model.model)) payload.power_outage_count = msg.data['2'];
5230
+ }
5206
5231
  if (msg.data.hasOwnProperty('4')) payload.mode_switch = {4: 'anti_flicker_mode', 1: 'quick_mode'}[msg.data['4']];
5207
5232
  if (msg.data.hasOwnProperty('10')) payload.switch_type = {1: 'toggle', 2: 'momentary'}[msg.data['10']];
5208
5233
  if (msg.data.hasOwnProperty('258')) payload.detection_interval = msg.data['258'];
5209
- if (msg.data.hasOwnProperty('268')) payload.motion_sensitivity = {1: 'low', 2: 'medium', 3: 'high'}[msg.data['268']];
5234
+ if (msg.data.hasOwnProperty('268')) {
5235
+ if (['RTCGQ13LM'].includes(model.model)) {
5236
+ payload.motion_sensitivity = {1: 'low', 2: 'medium', 3: 'high'}[msg.data['268']];
5237
+ } else if (['JT-BZ-01AQ/A'].includes(model.model)) {
5238
+ payload.gas_sensitivity = {1: '15%LEL', 2: '10%LEL'}[msg.data['268']];
5239
+ }
5240
+ }
5241
+ if (msg.data.hasOwnProperty('294')) payload.mute = msg.data['294'] === 1; // JT-BZ-01AQ/A
5242
+ if (msg.data.hasOwnProperty('295')) payload.test = msg.data['295'] === 1; // JT-BZ-01AQ/A
5243
+ if (msg.data.hasOwnProperty('313')) payload.state = msg.data['313'] === 1 ? 'preparation' : 'work'; // JT-BZ-01AQ/A
5244
+ if (msg.data.hasOwnProperty('314')) payload.gas = msg.data['314'] === 1; // JT-BZ-01AQ/A
5245
+ if (msg.data.hasOwnProperty('315')) payload.gas_density = msg.data['315']; // JT-BZ-01AQ/A
5246
+ if (msg.data.hasOwnProperty('331')) payload.linkage_alarm = msg.data['331'] === 1; // JT-BZ-01AQ/A
5210
5247
  if (msg.data.hasOwnProperty('512')) {
5211
5248
  if (['ZNCZ15LM', 'QBCZ14LM', 'QBCZ15LM'].includes(model.model)) {
5212
5249
  payload.button_lock = msg.data['512'] === 1 ? 'OFF' : 'ON';
@@ -7590,6 +7627,57 @@ const converters = {
7590
7627
  return result;
7591
7628
  },
7592
7629
  },
7630
+ tuya_radar_sensor_fall: {
7631
+ cluster: 'manuSpecificTuya',
7632
+ type: ['commandDataResponse', 'commandDataReport'],
7633
+ convert: (model, msg, publish, options, meta) => {
7634
+ const dpValue = tuya.firstDpValue(msg, meta, 'tuya_radar_sensor_fall');
7635
+ const dp = dpValue.dp;
7636
+ const value = tuya.getDataValue(dpValue);
7637
+ let result = null;
7638
+ switch (dp) {
7639
+ case tuya.dataPoints.trsfPresenceState:
7640
+ result = {presence: {0: false, 1: true}[value]};
7641
+ break;
7642
+ case tuya.dataPoints.trsfMotionState:
7643
+ result = {occupancy: {1: false, 2: true}[value]};
7644
+ break;
7645
+ case tuya.dataPoints.trsfMotionSpeed:
7646
+ result = {motion_speed: value};
7647
+ break;
7648
+ case tuya.dataPoints.trsfMotionDirection:
7649
+ result = {motion_direction: tuya.tuyaRadar.motionDirection[value]};
7650
+ break;
7651
+ case tuya.dataPoints.trsfScene:
7652
+ result = {radar_scene: tuya.tuyaRadar.radarScene[value]};
7653
+ break;
7654
+ case tuya.dataPoints.trsfSensitivity:
7655
+ result = {radar_sensitivity: value};
7656
+ break;
7657
+ case tuya.dataPoints.trsfIlluminanceLux:
7658
+ result = {illuminance_lux: value};
7659
+ break;
7660
+ case tuya.dataPoints.trsfTumbleAlarmTime:
7661
+ result = {tumble_alarm_time: value+1};
7662
+ break;
7663
+ case tuya.dataPoints.trsfTumbleSwitch:
7664
+ result = {tumble_switch: {false: 'OFF', true: 'ON'}[value]};
7665
+ break;
7666
+ case tuya.dataPoints.trsfFallDownStatus:
7667
+ result = {fall_down_status: {0: false, 1: true}[value]};
7668
+ break;
7669
+ case tuya.dataPoints.trsfStaticDwellAlarm:
7670
+ result = {static_dwell_alarm: value};
7671
+ break;
7672
+ case tuya.dataPoints.trsfFallSensitivity:
7673
+ result = {fall_sensitivity: value};
7674
+ break;
7675
+ default:
7676
+ meta.logger.warn(`fromZigbee.tuya_radar_sensor_fall: NOT RECOGNIZED DP ${dp} with data ${JSON.stringify(dpValue)}`);
7677
+ }
7678
+ return result;
7679
+ },
7680
+ },
7593
7681
  tuya_smart_vibration_sensor: {
7594
7682
  cluster: 'manuSpecificTuya',
7595
7683
  type: ['commandGetData', 'commandDataResponse', 'raw'],
@@ -7956,6 +8044,81 @@ const converters = {
7956
8044
  return {action};
7957
8045
  },
7958
8046
  },
8047
+ ZMAM02: {
8048
+ cluster: 'manuSpecificTuya',
8049
+ type: ['commandDataResponse', 'commandDataReport', 'commandSetDataresponse'],
8050
+ convert: (model, msg, publish, options, meta) => {
8051
+ const result = {};
8052
+ // let value = tuya.getDataValue(dpValue);
8053
+ // let result = null;
8054
+ for (const dpValue of msg.data.dpValues) {
8055
+ const value = tuya.getDataValue(dpValue);
8056
+ switch (dpValue.dp) {
8057
+ case tuya.dataPoints.AM02Control:
8058
+ result.control = tuya.ZMAM02.AM02Control[value];
8059
+ break;
8060
+ case tuya.dataPoints.AM02PercentControl:
8061
+ result.percent_control = value;
8062
+ break;
8063
+ case tuya.dataPoints.AM02ControlBackMode:
8064
+ result.control_back_mode = tuya.ZMAM02.AM02Direction[value];
8065
+ break;
8066
+ case tuya.dataPoints.AM02MotorWorkingMode:
8067
+ switch (value) {
8068
+ case 0: // continuous 1
8069
+ result.motor_working_mode = 'continuous';
8070
+ break;
8071
+ case 1: // intermittently
8072
+ result.motor_working_mode = 'intermittently';
8073
+ break;
8074
+ default:
8075
+ meta.logger.warn('zigbee-herdsman-converters:ZM_AM_02: ' +
8076
+ `Mode ${value} is not recognized.`);
8077
+ break;
8078
+ }
8079
+ break;
8080
+ case tuya.dataPoints.AM02Border:
8081
+ switch (value) {
8082
+ case 0: // up
8083
+ result.border = 'up';
8084
+ break;
8085
+ case 1: // down
8086
+ result.border = 'down';
8087
+ break;
8088
+ case 2: // down_delete
8089
+ result.border = 'down_delete';
8090
+ break;
8091
+ default:
8092
+ meta.logger.warn('zigbee-herdsman-converters:ZM_AM_02: ' +
8093
+ `Mode ${value} is not recognized.`);
8094
+ break;
8095
+ }
8096
+ break;
8097
+ case tuya.dataPoints.AM02PercentState:
8098
+ result.percent_state = value;
8099
+ break;
8100
+ case tuya.dataPoints.AM02Mode:
8101
+ switch (value) {
8102
+ case 0: // morning
8103
+ result.mode = 'morning';
8104
+ break;
8105
+ case 1: // night
8106
+ result.mode = 'night';
8107
+ break;
8108
+ default:
8109
+ meta.logger.warn('zigbee-herdsman-converters:ZM_AM_02: ' +
8110
+ `Mode ${value} is not recognized.`);
8111
+ break;
8112
+ }
8113
+ break;
8114
+ default:
8115
+ meta.logger.warn(`fromZigbee.Zemismart Shader Konverter (Zm_AM02): NOT RECOGNIZED ` +
8116
+ `DP #${dpValue.dp} with data ${JSON.stringify(dpValue)}`);
8117
+ }
8118
+ }
8119
+ return result;
8120
+ },
8121
+ },
7959
8122
  // #endregion
7960
8123
 
7961
8124
  // #region Ignore converters (these message dont need parsing).
@@ -1982,7 +1982,7 @@ const converters = {
1982
1982
  convertSet: async (entity, key, value, meta) => {
1983
1983
  const lookup = {'siren_led': 3, 'siren': 2, 'led': 1, 'nothing': 0};
1984
1984
  await entity.write('genBasic', {0x400a: {value: lookup[value], type: 32}},
1985
- {manufacturerCode: 0x1168, disableDefaultResponse: true, sendWhenActive: true});
1985
+ {manufacturerCode: 0x1168, disableDefaultResponse: true, sendWhen: 'active'});
1986
1986
  return {state: {alert_behaviour: value}};
1987
1987
  },
1988
1988
  },
@@ -2419,6 +2419,72 @@ const converters = {
2419
2419
  await entity.write('ssIasZone', {0xFFF1: {value: 0x03010000, type: 0x23}}, options);
2420
2420
  },
2421
2421
  },
2422
+ JTBZ01AQA_gas: {
2423
+ key: ['gas'],
2424
+ convertGet: async (entity, key, meta) => {
2425
+ await entity.read('aqaraOpple', [0x013a], manufacturerOptions.xiaomi);
2426
+ },
2427
+ },
2428
+ JTBZ01AQA_gas_density: {
2429
+ key: ['gas_density'],
2430
+ convertGet: async (entity, key, meta) => {
2431
+ await entity.read('aqaraOpple', [0x013b], manufacturerOptions.xiaomi);
2432
+ },
2433
+ },
2434
+ JTBZ01AQA_gas_sensitivity: {
2435
+ key: ['gas_sensitivity'],
2436
+ convertSet: async (entity, key, value, meta) => {
2437
+ value = value.toLowerCase();
2438
+ const lookup = {'15%lel': 1, '10%lel': 2};
2439
+ await entity.write('aqaraOpple', {0x010c: {value: lookup[value], type: 0x20}}, manufacturerOptions.xiaomi);
2440
+ return {state: {gas_sensitivity: value}};
2441
+ },
2442
+ convertGet: async (entity, key, meta) => {
2443
+ await entity.read('aqaraOpple', [0x010c], manufacturerOptions.xiaomi);
2444
+ },
2445
+ },
2446
+ JTBZ01AQA_selftest: {
2447
+ key: ['selftest'],
2448
+ convertSet: async (entity, key, value, meta) => {
2449
+ await entity.write('aqaraOpple', {0x0127: {value: true, type: 0x10}}, manufacturerOptions.xiaomi);
2450
+ },
2451
+ },
2452
+ JTBZ01AQA_mute_buzzer: {
2453
+ key: ['mute_buzzer'],
2454
+ convertSet: async (entity, key, value, meta) => {
2455
+ await entity.write('aqaraOpple', {0x013f: {value: 15360, type: 0x23}}, manufacturerOptions.xiaomi);
2456
+ await entity.write('aqaraOpple', {0x0126: {value: 1, type: 0x20}}, manufacturerOptions.xiaomi);
2457
+ },
2458
+ },
2459
+ JTBZ01AQA_mute: {
2460
+ key: ['mute'],
2461
+ convertGet: async (entity, key, meta) => {
2462
+ await entity.read('aqaraOpple', [0x0126], manufacturerOptions.xiaomi);
2463
+ },
2464
+ },
2465
+ JTBZ01AQA_linkage_alarm: {
2466
+ key: ['linkage_alarm'],
2467
+ convertSet: async (entity, key, value, meta) => {
2468
+ const lookup = {true: 1, false: 0};
2469
+ await entity.write('aqaraOpple', {0x014b: {value: lookup[value], type: 0x20}}, manufacturerOptions.xiaomi);
2470
+ return {state: {linkage_alarm: value}};
2471
+ },
2472
+ convertGet: async (entity, key, meta) => {
2473
+ await entity.read('aqaraOpple', [0x014b], manufacturerOptions.xiaomi);
2474
+ },
2475
+ },
2476
+ JTBZ01AQA_state: {
2477
+ key: ['state'],
2478
+ convertGet: async (entity, key, meta) => {
2479
+ await entity.read('aqaraOpple', [0x0139], manufacturerOptions.xiaomi);
2480
+ },
2481
+ },
2482
+ aqara_power_outage_count: {
2483
+ key: ['power_outage_count'],
2484
+ convertGet: async (entity, key, meta) => {
2485
+ await entity.read('aqaraOpple', [0x0002], manufacturerOptions.xiaomi);
2486
+ },
2487
+ },
2422
2488
  LLKZMK11LM_interlock: {
2423
2489
  key: ['interlock'],
2424
2490
  convertSet: async (entity, key, value, meta) => {
@@ -6033,7 +6099,7 @@ const converters = {
6033
6099
  key: ['keypad_lockout'],
6034
6100
  convertSet: async (entity, key, value, meta) => {
6035
6101
  const keypadLockout = utils.getKey(constants.keypadLockoutMode, value, value, Number);
6036
- entity.write('hvacUserInterfaceCfg', {keypadLockout}, {sendWhenActive: true});
6102
+ entity.write('hvacUserInterfaceCfg', {keypadLockout}, {sendWhen: 'active'});
6037
6103
  entity.saveClusterAttributeKeyValue('hvacUserInterfaceCfg', {keypadLockout});
6038
6104
  return {state: {keypad_lockout: value}};
6039
6105
  },
@@ -6172,7 +6238,7 @@ const converters = {
6172
6238
  key: ['calibrate_valve'],
6173
6239
  convertSet: async (entity, key, value, meta) => {
6174
6240
  await entity.command('hvacThermostat', 'wiserSmartCalibrateValve', {},
6175
- {srcEndpoint: 11, disableDefaultResponse: true, sendWhenActive: true});
6241
+ {srcEndpoint: 11, disableDefaultResponse: true, sendWhen: 'active'});
6176
6242
  return {state: {'calibrate_valve': value}};
6177
6243
  },
6178
6244
  },
@@ -6194,7 +6260,7 @@ const converters = {
6194
6260
  key: ['local_temperature_calibration'],
6195
6261
  convertSet: (entity, key, value, meta) => {
6196
6262
  entity.write('hvacThermostat', {localTemperatureCalibration: Math.round(value * 10)},
6197
- {srcEndpoint: 11, disableDefaultResponse: true, sendWhenActive: true});
6263
+ {srcEndpoint: 11, disableDefaultResponse: true, sendWhen: 'active'});
6198
6264
  return {state: {local_temperature_calibration: value}};
6199
6265
  },
6200
6266
  },
@@ -6203,7 +6269,7 @@ const converters = {
6203
6269
  convertSet: async (entity, key, value, meta) => {
6204
6270
  const keypadLockout = utils.getKey(constants.keypadLockoutMode, value, value, Number);
6205
6271
  await entity.write('hvacUserInterfaceCfg', {keypadLockout},
6206
- {srcEndpoint: 11, disableDefaultResponse: true, sendWhenActive: true});
6272
+ {srcEndpoint: 11, disableDefaultResponse: true, sendWhen: 'active'});
6207
6273
  return {state: {keypad_lockout: value}};
6208
6274
  },
6209
6275
  },
@@ -6305,6 +6371,30 @@ const converters = {
6305
6371
  }
6306
6372
  },
6307
6373
  },
6374
+ tuya_radar_sensor_fall: {
6375
+ key: ['radar_scene', 'radar_sensitivity', 'tumble_alarm_time', 'tumble_switch', 'fall_sensitivity'],
6376
+ convertSet: async (entity, key, value, meta) => {
6377
+ switch (key) {
6378
+ case 'radar_scene':
6379
+ await tuya.sendDataPointEnum(entity, tuya.dataPoints.trsfScene, utils.getKey(tuya.tuyaRadar.radarScene, value));
6380
+ break;
6381
+ case 'radar_sensitivity':
6382
+ await tuya.sendDataPointValue(entity, tuya.dataPoints.trsfSensitivity, value);
6383
+ break;
6384
+ case 'tumble_switch':
6385
+ await tuya.sendDataPointEnum(entity, tuya.dataPoints.trsfTumbleSwitch, {'on': true, 'off': false}[value.toLowerCase()]);
6386
+ break;
6387
+ case 'tumble_alarm_time':
6388
+ await tuya.sendDataPointEnum(entity, tuya.dataPoints.trsfTumbleAlarmTime, value-1);
6389
+ break;
6390
+ case 'fall_sensitivity':
6391
+ await tuya.sendDataPointValue(entity, tuya.dataPoints.trsfFallSensitivity, value);
6392
+ break;
6393
+ default: // Unknown Key
6394
+ meta.logger.warn(`toZigbee.tuya_radar_sensor_fall: Unhandled Key ${key}`);
6395
+ }
6396
+ },
6397
+ },
6308
6398
  javis_microwave_sensor: {
6309
6399
  key: [
6310
6400
  'illuminance_calibration', 'led_enable',
@@ -6592,6 +6682,33 @@ const converters = {
6592
6682
  }
6593
6683
  },
6594
6684
  },
6685
+ ZMAM02: {
6686
+ key: ['control', 'percent_control', 'mode', 'control_back_mode', 'border', 'motor_working_mode'],
6687
+ convertSet: async (entity, key, value, meta) => {
6688
+ switch (key) {
6689
+ case 'control':
6690
+ await tuya.sendDataPointEnum(entity, tuya.dataPoints.AM02Control, utils.getKey(tuya.ZMAM02.AM02Control, value));
6691
+ break;
6692
+ case 'percent_control':
6693
+ await tuya.sendDataPointValue(entity, tuya.dataPoints.AM02PercentState, value);
6694
+ break;
6695
+ case 'mode':
6696
+ await tuya.sendDataPointEnum(entity, tuya.dataPoints.AM02Mode, utils.getKey(tuya.ZMAM02.AM02Mode, value));
6697
+ break;
6698
+ case 'control_back_mode':
6699
+ await tuya.sendDataPointEnum(entity, tuya.dataPoints.AM02ControlBackMode, utils.getKey(tuya.ZMAM02.AM02Direction, value));
6700
+ break;
6701
+ case 'border':
6702
+ await tuya.sendDataPointEnum(entity, tuya.dataPoints.AM02Border, utils.getKey(tuya.ZMAM02.AM02Border, value));
6703
+ break;
6704
+ case 'motor_working_mode':
6705
+ await tuya.sendDataPointEnum(entity, tuya.dataPoints.AM02MotorWorkingMode, utils.getKey(tuya.ZMAM02.AM02MotorMode, value));
6706
+ break;
6707
+ default: // Unknown Key
6708
+ meta.logger.warn(`toZigbee.ZMAM02: Unhandled Key ${key}`);
6709
+ }
6710
+ },
6711
+ },
6595
6712
  // #endregion
6596
6713
 
6597
6714
  // #region Ignore converters
package/devices/ikea.js CHANGED
@@ -252,7 +252,7 @@ module.exports = [
252
252
  extend: tradfriExtend.light_onoff_brightness_colortemp(),
253
253
  },
254
254
  {
255
- zigbeeModel: ['TRADFRI bulb E27 WS clear 950lm', 'TRADFRI bulb E26 WS clear 950lm'],
255
+ zigbeeModel: ['TRADFRI bulb E27 WS clear 950lm', 'TRADFRI bulb E26 WS clear 950lm', 'TRADFRI bulb E27 WS\uFFFDclear 950lm'],
256
256
  model: 'LED1546G12',
257
257
  vendor: 'IKEA',
258
258
  description: 'TRADFRI LED bulb E26/E27 950 lumen, dimmable, white spectrum, clear',
@@ -91,7 +91,7 @@ module.exports = [
91
91
  zigbeeModel: ['LEDVANCE DIM'],
92
92
  model: '4058075208421',
93
93
  vendor: 'LEDVANCE',
94
- description: 'SMART+ candle E14 tunable white',
94
+ description: 'SMART+ candle E14 dimmable white',
95
95
  extend: extend.ledvance.light_onoff_brightness(),
96
96
  ota: ota.ledvance,
97
97
  },
@@ -4,6 +4,7 @@ const tz = require('../converters/toZigbee');
4
4
  const e = exposes.presets;
5
5
  const ea = exposes.access;
6
6
  const extend = require('../lib/extend');
7
+ const tuya = require('../lib/tuya');
7
8
 
8
9
  module.exports = [
9
10
  {
@@ -21,11 +22,13 @@ module.exports = [
21
22
  ],
22
23
  },
23
24
  {
24
- fingerprint: [{modelID: 'TS0501B', manufacturerName: '_TZ3210_dxroobu3'}],
25
+ fingerprint: [{modelID: 'TS0501B', manufacturerName: '_TZ3210_dxroobu3'},
26
+ {modelID: 'TS0501B', manufacturerName: '_TZ3210_dbilpfqk'}],
25
27
  model: 'FUT036Z',
26
28
  description: 'Single color LED controller',
27
29
  vendor: 'Miboxer',
28
30
  extend: extend.light_onoff_brightness(),
31
+ onEvent: tuya.onEventSetTime,
29
32
  },
30
33
  {
31
34
  fingerprint: [{modelID: 'TS0502B', manufacturerName: '_TZ3210_frm6149r'}],
package/devices/moes.js CHANGED
@@ -9,6 +9,27 @@ const e = exposes.presets;
9
9
  const ea = exposes.access;
10
10
 
11
11
  module.exports = [
12
+ {
13
+ fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_cymsnfvf'}],
14
+ model: 'ZP-LZ-FR2U',
15
+ vendor: 'Moes',
16
+ description: 'Zigbee 3.0 dual USB wireless socket plug',
17
+ fromZigbee: [fz.on_off, fz.tuya_switch_power_outage_memory],
18
+ toZigbee: [tz.on_off, tz.tuya_switch_power_outage_memory],
19
+ exposes: [e.switch().withEndpoint('l1'), e.switch().withEndpoint('l2'),
20
+ exposes.enum('power_outage_memory', ea.STATE_SET, ['on', 'off', 'restore'])
21
+ .withDescription('Recover state after power outage')],
22
+ endpoint: (device) => {
23
+ return {'l1': 1, 'l2': 2};
24
+ },
25
+ meta: {multiEndpoint: true},
26
+ configure: async (device, coordinatorEndpoint, logger) => {
27
+ await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ['genOnOff']);
28
+ await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ['genOnOff']);
29
+ await reporting.onOff(device.getEndpoint(1));
30
+ await reporting.onOff(device.getEndpoint(2));
31
+ },
32
+ },
12
33
  {
13
34
  fingerprint: [{modelID: 'TS0121', manufacturerName: '_TYZB01_iuepbmpv'}, {modelID: 'TS011F', manufacturerName: '_TZ3000_zmy1waw6'},
14
35
  {modelID: 'TS011F', manufacturerName: '_TZ3000_bkfe0bab'}],
@@ -1543,6 +1543,15 @@ module.exports = [
1543
1543
  extend: hueExtend.light_onoff_brightness_colortemp_color(),
1544
1544
  ota: ota.zigbeeOTA,
1545
1545
  },
1546
+ {
1547
+ zigbeeModel: ['LCF003', '4080248P7'],
1548
+ model: '4080248P7',
1549
+ vendor: 'Philips',
1550
+ description: 'Hue Signe floor light',
1551
+ meta: {turnsOffAtBrightness1: true},
1552
+ extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
1553
+ ota: ota.zigbeeOTA,
1554
+ },
1546
1555
  {
1547
1556
  zigbeeModel: ['4080248U9'],
1548
1557
  model: '4080248U9',
package/devices/tuya.js CHANGED
@@ -845,7 +845,6 @@ module.exports = [
845
845
  {modelID: 'TS0601', manufacturerName: '_TZE200_fzo2pocs'},
846
846
  {modelID: 'TS0601', manufacturerName: '_TZE200_5sbebbzs'},
847
847
  {modelID: 'TS0601', manufacturerName: '_TZE200_zuz7f94z'},
848
- {modelID: 'TS0601', manufacturerName: '_TZE200_iossyxra'},
849
848
  ],
850
849
  model: 'TS0601_cover',
851
850
  vendor: 'TuYa',
@@ -1127,7 +1126,6 @@ module.exports = [
1127
1126
  {
1128
1127
  fingerprint: [
1129
1128
  {modelID: 'TS011F', manufacturerName: '_TZ3000_hyfvrar3'},
1130
- {modelID: 'TS011F', manufacturerName: '_TZ3000_cymsnfvf'},
1131
1129
  {modelID: 'TS011F', manufacturerName: '_TZ3000_bfn1w0mm'}],
1132
1130
  model: 'TS011F_plug_2',
1133
1131
  description: 'Smart plug (without power monitoring)',
@@ -1718,9 +1716,7 @@ module.exports = [
1718
1716
  ],
1719
1717
  },
1720
1718
  {
1721
- fingerprint: [
1722
- {modelID: 'TS0601', manufacturerName: '_TZE200_vrfecyku'},
1723
- {modelID: 'TS0601', manufacturerName: '_TZE200_lu01t0zl'}],
1719
+ fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_vrfecyku'}],
1724
1720
  model: 'MIR-HE200-TY',
1725
1721
  vendor: 'TuYa',
1726
1722
  description: 'Human presence sensor',
@@ -1737,6 +1733,35 @@ module.exports = [
1737
1733
  .withDescription('presets for sensitivity for presence and movement'),
1738
1734
  ],
1739
1735
  },
1736
+ {
1737
+ fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_lu01t0zl'}],
1738
+ model: 'MIR-HE200-TY_fall',
1739
+ vendor: 'TuYa',
1740
+ description: 'Human presence sensor with fall function',
1741
+ fromZigbee: [fz.tuya_radar_sensor_fall],
1742
+ toZigbee: [tz.tuya_radar_sensor_fall],
1743
+ exposes: [
1744
+ e.illuminance_lux(), e.presence(), e.occupancy(),
1745
+ exposes.numeric('motion_speed', ea.STATE).withDescription('Speed of movement'),
1746
+ exposes.enum('motion_direction', ea.STATE, Object.values(tuya.tuyaRadar.motionDirection))
1747
+ .withDescription('direction of movement from the point of view of the radar'),
1748
+ exposes.numeric('radar_sensitivity', ea.STATE_SET).withValueMin(0).withValueMax(10).withValueStep(1)
1749
+ .withDescription('sensitivity of the radar'),
1750
+ exposes.enum('radar_scene', ea.STATE_SET, Object.values(tuya.tuyaRadar.radarScene))
1751
+ .withDescription('presets for sensitivity for presence and movement'),
1752
+ exposes.enum('tumble_switch', ea.STATE_SET, ['ON', 'OFF']).withDescription('Tumble status switch'),
1753
+ exposes.numeric('fall_sensitivity', ea.STATE_SET).withValueMin(1).withValueMax(10).withValueStep(1)
1754
+ .withDescription('fall sensitivity of the radar'),
1755
+ exposes.numeric('tumble_alarm_time', ea.STATE_SET).withValueMin(1).withValueMax(5).withValueStep(1)
1756
+ .withUnit('min').withDescription('tumble alarm time'),
1757
+ exposes.binary('fall_down_status', ea.STATE).withDescription('fall down status'),
1758
+ exposes.text('static_dwell_alarm', ea.STATE).withDescription('static dwell alarm'),
1759
+ ],
1760
+ configure: async (device, coordinatorEndpoint, logger) => {
1761
+ const endpoint = device.getEndpoint(1);
1762
+ await tuya.sendDataPointEnum(endpoint, tuya.dataPoints.trsfTumbleSwitch, false);
1763
+ },
1764
+ },
1740
1765
  {
1741
1766
  fingerprint: [{modelID: 'TS004F', manufacturerName: '_TZ3000_pcqjmcud'}],
1742
1767
  model: 'YSR-MINI-Z',
package/devices/xiaomi.js CHANGED
@@ -1133,6 +1133,41 @@ module.exports = [
1133
1133
  exposes.numeric('gas_density', ea.STATE), exposes.enum('selftest', ea.SET, ['']),
1134
1134
  ],
1135
1135
  },
1136
+ {
1137
+ zigbeeModel: ['lumi.sensor_gas.acn02'],
1138
+ model: 'JT-BZ-01AQ/A',
1139
+ vendor: 'Xiaomi',
1140
+ description: 'Aqara smart natural gas detector',
1141
+ fromZigbee: [fz.aqara_opple],
1142
+ toZigbee: [tz.JTBZ01AQA_gas, tz.JTBZ01AQA_gas_density, tz.JTBZ01AQA_gas_sensitivity, tz.JTBZ01AQA_selftest,
1143
+ tz.JTBZ01AQA_mute_buzzer, tz.JTBZ01AQA_mute, tz.JTBZ01AQA_linkage_alarm, tz.JTBZ01AQA_state, tz.aqara_power_outage_count],
1144
+ exposes: [e.gas().withAccess(ea.STATE_GET),
1145
+ exposes.numeric('gas_density', ea.STATE_GET).withUnit('%LEL').withDescription('Value of gas concentration'),
1146
+ exposes.enum('gas_sensitivity', ea.ALL, ['10%LEL', '15%LEL']).withDescription('Gas concentration value at which ' +
1147
+ 'an alarm is triggered ("10%LEL" is more sensitive than "15%LEL")'),
1148
+ exposes.enum('selftest', ea.SET, ['Test']).withDescription('Starts the self-test process (checking the indicator ' +
1149
+ 'light and buzzer work properly)'),
1150
+ exposes.binary('test', ea.STATE, true, false).withDescription('Self-test in progress'),
1151
+ exposes.enum('mute_buzzer', ea.SET, ['Mute']).withDescription('Mute the buzzer for 10 minutes (buzzer cannot be ' +
1152
+ 'pre-muted, because this function only works when the alarm is triggered)'),
1153
+ exposes.binary('mute', ea.STATE_GET, true, false).withDescription('Buzzer muted'),
1154
+ exposes.switch().withState('linkage_alarm', true, 'After being turned on, one of the devices triggers the ' +
1155
+ 'natural gas leakage alarm, and other devices with linkage turned on', ea.ALL, true, false),
1156
+ exposes.binary('state', ea.STATE_GET, 'preparation', 'work').withDescription('"Preparation" or "work" ' +
1157
+ '(measurement of the gas concentration value and triggering of an alarm are only performed in the "work" state)'),
1158
+ exposes.numeric('power_outage_count', ea.STATE_GET).withDescription('Number of power outages (since last pairing)')],
1159
+ configure: async (device, coordinatorEndpoint, logger) => {
1160
+ const endpoint = device.getEndpoint(1);
1161
+ await endpoint.read('aqaraOpple', [0x013a], {manufacturerCode: 0x115f});
1162
+ await endpoint.read('aqaraOpple', [0x013b], {manufacturerCode: 0x115f});
1163
+ await endpoint.read('aqaraOpple', [0x0126], {manufacturerCode: 0x115f});
1164
+ await endpoint.read('aqaraOpple', [0x0139], {manufacturerCode: 0x115f});
1165
+ await endpoint.read('aqaraOpple', [0x010c], {manufacturerCode: 0x115f});
1166
+ await endpoint.read('aqaraOpple', [0x014b], {manufacturerCode: 0x115f});
1167
+ await endpoint.read('aqaraOpple', [0x0002], {manufacturerCode: 0x115f});
1168
+ },
1169
+ ota: ota.zigbeeOTA,
1170
+ },
1136
1171
  {
1137
1172
  zigbeeModel: ['lumi.lock.v1'],
1138
1173
  model: 'A6121',
@@ -124,4 +124,26 @@ module.exports = [
124
124
  await reporting.onOff(device.getEndpoint(2));
125
125
  },
126
126
  },
127
+ {
128
+ fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_iossyxra'}],
129
+ model: 'ZM-AM02',
130
+ vendor: 'Zemismart',
131
+ description: 'Zigbee/RF curtain converter',
132
+ fromZigbee: [fz.ZMAM02],
133
+ toZigbee: [tz.ZMAM02],
134
+ exposes: [exposes.enum('motor_working_mode', ea.STATE_SET, Object.values(tuya.ZMAM02.AM02MotorMode)),
135
+ exposes.enum('control', ea.STATE_SET, Object.values(tuya.ZMAM02.AM02Control)),
136
+ exposes.numeric('percent_state', ea.STATE).withValueMin(0).withValueMax(100).withValueStep(1).withUnit('%'),
137
+ exposes.enum('mode', ea.STATE_SET, Object.values(tuya.ZMAM02.AM02Mode)),
138
+ exposes.enum('control_back_mode', ea.STATE_SET, Object.values(tuya.ZMAM02.AM02Direction)),
139
+ exposes.enum('border', ea.STATE_SET, Object.values(tuya.ZMAM02.AM02Border)),
140
+ // ---------------------------------------------------------------------------------
141
+ // DP exists, but not used at the moment
142
+ // exposes.numeric('percent_control', ea.STATE_SET).withValueMin(0).withValueMax(100).withValueStep(1).withUnit('%'),
143
+ // exposes.enum('work_state', ea.STATE, Object.values(tuya.ZMAM02.AM02WorkState)),
144
+ // exposes.numeric('countdown_left', ea.STATE).withUnit('s'),
145
+ // exposes.numeric('time_total', ea.STATE).withUnit('ms'),
146
+ // exposes.enum('situation_set', ea.STATE, Object.values(tuya.ZMAM02.AM02Situation)),
147
+ ],
148
+ },
127
149
  ];
package/lib/ota/common.js CHANGED
@@ -385,11 +385,18 @@ async function updateToLatest(device, logger, onProgress, getNewImage, getImageM
385
385
 
386
386
  endpoint.commandResponse('genOta', 'upgradeEndResponse', payload).then(
387
387
  () => {
388
- logger.debug(`Update succeeded, waiting for device to restart`);
389
- setTimeout(() => {
390
- onProgress(100, null);
388
+ logger.debug(`Update succeeded, waiting for device announce`);
389
+ onProgress(100, null);
390
+
391
+ let timer = null;
392
+ const cb = () => {
393
+ logger.debug('Got device announce or timed out, call resolve');
394
+ clearInterval(timer);
395
+ device.removeListener('deviceAnnounce', cb);
391
396
  resolve();
392
- }, 90 * 1000);
397
+ };
398
+ timer = setTimeout(cb, 120 * 1000); // timeout after 2 minutes
399
+ device.once('deviceAnnounce', cb);
393
400
  },
394
401
  (e) => {
395
402
  const message = `Upgrade end reponse failed (${e.message})`;