zigbee-herdsman-converters 14.0.519 → 14.0.522

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.
@@ -7270,59 +7270,6 @@ const converters = {
7270
7270
  };
7271
7271
  },
7272
7272
  },
7273
- ubisys_dimmer_setup: {
7274
- cluster: 'manuSpecificUbisysDimmerSetup',
7275
- type: ['attributeReport', 'readResponse'],
7276
- convert: (model, msg, publish, options, meta) => {
7277
- if (msg.data.hasOwnProperty('capabilities')) {
7278
- const capabilities = msg.data.capabilities;
7279
- const forwardPhaseControl = capabilities & 1;
7280
- const reversePhaseControl = (capabilities & 2) >>> 1;
7281
- const reactanceDiscriminator = (capabilities & 0x20) >>> 5;
7282
- const configurableCurve = (capabilities & 0x40) >>> 6;
7283
- const overloadDetection = (capabilities & 0x80) >>> 7;
7284
- return {
7285
- capabilities_forward_phase_control: forwardPhaseControl ? true : false,
7286
- capabilities_reverse_phase_control: reversePhaseControl ? true : false,
7287
- capabilities_reactance_discriminator: reactanceDiscriminator ? true : false,
7288
- capabilities_configurable_curve: configurableCurve ? true : false,
7289
- capabilities_overload_detection: overloadDetection ? true : false,
7290
- };
7291
- }
7292
- if (msg.data.hasOwnProperty('status')) {
7293
- const status = msg.data.status;
7294
- const forwardPhaseControl = status & 1;
7295
- const reversePhaseControl = (status & 2) >>> 1;
7296
- const overload = (status & 8) >>> 3;
7297
- const capacitiveLoad = (status & 0x40) >>> 6;
7298
- const inductiveLoad = (status & 0x80) >>> 7;
7299
- return {
7300
- status_forward_phase_control: forwardPhaseControl ? true : false,
7301
- status_reverse_phase_control: reversePhaseControl ? true : false,
7302
- status_overload: overload ? true : false,
7303
- status_capacitive_load: capacitiveLoad ? true : false,
7304
- status_inductive_load: inductiveLoad ? true : false,
7305
- };
7306
- }
7307
- if (msg.data.hasOwnProperty('mode')) {
7308
- const mode = msg.data.mode;
7309
- const phaseControl = mode & 3;
7310
- const phaseControlValues = {0: 'automatic', 1: 'forward', 2: 'reverse'};
7311
- return {
7312
- mode_phase_control: phaseControlValues[phaseControl],
7313
- };
7314
- }
7315
- },
7316
- },
7317
- ubisys_dimmer_setup_genLevelCtrl: {
7318
- cluster: 'genLevelCtrl',
7319
- type: ['attributeReport', 'readResponse'],
7320
- convert: (model, msg, publish, options, meta) => {
7321
- if (msg.data.hasOwnProperty('ubisysMinimumOnLevel')) {
7322
- return {minimum_on_level: msg.data.ubisysMinimumOnLevel};
7323
- }
7324
- },
7325
- },
7326
7273
  itcmdr_clicks: {
7327
7274
  cluster: 'genMultistateInput',
7328
7275
  type: ['readResponse', 'attributeReport'],
@@ -20,13 +20,6 @@ const manufacturerOptions = {
20
20
  hue: {manufacturerCode: herdsman.Zcl.ManufacturerCode.PHILIPS},
21
21
  ikea: {manufacturerCode: herdsman.Zcl.ManufacturerCode.IKEA_OF_SWEDEN},
22
22
  sinope: {manufacturerCode: herdsman.Zcl.ManufacturerCode.SINOPE_TECH},
23
- /*
24
- * Ubisys doesn't accept a manufacturerCode on some commands
25
- * This bug has been reported, but it has not been fixed:
26
- * https://github.com/Koenkk/zigbee-herdsman/issues/52
27
- */
28
- ubisys: {manufacturerCode: herdsman.Zcl.ManufacturerCode.UBISYS},
29
- ubisysNull: {manufacturerCode: null},
30
23
  tint: {manufacturerCode: herdsman.Zcl.ManufacturerCode.MUELLER_LICHT_INT},
31
24
  legrand: {manufacturerCode: herdsman.Zcl.ManufacturerCode.VANTAGE, disableDefaultResponse: true},
32
25
  viessmann: {manufacturerCode: herdsman.Zcl.ManufacturerCode.VIESSMAN_ELEKTRO},
@@ -2734,6 +2727,17 @@ const converters = {
2734
2727
  await entity.read('aqaraOpple', [0x0002], manufacturerOptions.xiaomi);
2735
2728
  },
2736
2729
  },
2730
+ RTCGQ14LM_trigger_indicator: {
2731
+ key: ['trigger_indicator'],
2732
+ convertSet: async (entity, key, value, meta) => {
2733
+ const lookup = {true: 1, false: 0};
2734
+ await entity.write('aqaraOpple', {0x0152: {value: lookup[value], type: 0x20}}, manufacturerOptions.xiaomi);
2735
+ return {state: {trigger_indicator: value}};
2736
+ },
2737
+ convertGet: async (entity, key, meta) => {
2738
+ await entity.read('aqaraOpple', [0x0152], manufacturerOptions.xiaomi);
2739
+ },
2740
+ },
2737
2741
  LLKZMK11LM_interlock: {
2738
2742
  key: ['interlock'],
2739
2743
  convertSet: async (entity, key, value, meta) => {
@@ -4395,421 +4399,6 @@ const converters = {
4395
4399
  }
4396
4400
  },
4397
4401
  },
4398
- ubisys_configure_j1: {
4399
- key: ['configure_j1'],
4400
- convertSet: async (entity, key, value, meta) => {
4401
- const log = (message) => {
4402
- meta.logger.warn(`ubisys: ${message}`);
4403
- };
4404
- const sleepSeconds = async (s) => {
4405
- return new Promise((resolve) => setTimeout(resolve, s * 1000));
4406
- };
4407
- const waitUntilStopped = async () => {
4408
- let operationalStatus = 0;
4409
- do {
4410
- await sleepSeconds(2);
4411
- operationalStatus = (await entity.read('closuresWindowCovering',
4412
- ['operationalStatus'])).operationalStatus;
4413
- } while (operationalStatus != 0);
4414
- await sleepSeconds(2);
4415
- };
4416
- const writeAttrFromJson = async (attr, jsonAttr = attr, converterFunc, delaySecondsAfter) => {
4417
- if (jsonAttr.startsWith('ubisys')) {
4418
- jsonAttr = jsonAttr.substring(6, 1).toLowerCase + jsonAttr.substring(7);
4419
- }
4420
- if (value.hasOwnProperty(jsonAttr)) {
4421
- let attrValue = value[jsonAttr];
4422
- if (converterFunc) {
4423
- attrValue = converterFunc(attrValue);
4424
- }
4425
- const attributes = {};
4426
- attributes[attr] = attrValue;
4427
- await entity.write('closuresWindowCovering', attributes, manufacturerOptions.ubisys);
4428
- if (delaySecondsAfter) {
4429
- await sleepSeconds(delaySecondsAfter);
4430
- }
4431
- }
4432
- };
4433
- const stepsPerSecond = value.steps_per_second || 50;
4434
- const hasCalibrate = value.hasOwnProperty('calibrate');
4435
- // cancel any running calibration
4436
- let mode = (await entity.read('closuresWindowCovering', ['windowCoveringMode'])).windowCoveringMode;
4437
- const modeCalibrationBitMask = 0x02;
4438
- if (mode & modeCalibrationBitMask) {
4439
- await entity.write('closuresWindowCovering', {windowCoveringMode: mode & ~modeCalibrationBitMask});
4440
- await sleepSeconds(2);
4441
- }
4442
- // delay a bit if reconfiguring basic configuration attributes
4443
- await writeAttrFromJson('windowCoveringType', undefined, undefined, 2);
4444
- await writeAttrFromJson('configStatus', undefined, undefined, 2);
4445
- if (await writeAttrFromJson('windowCoveringMode', undefined, undefined, 2)) {
4446
- mode = value['windowCoveringMode'];
4447
- }
4448
- if (hasCalibrate) {
4449
- log('Cover calibration starting...');
4450
- // first of all, move to top position to not confuse calibration later
4451
- log(' Moving cover to top position to get a good starting point...');
4452
- await entity.command('closuresWindowCovering', 'upOpen');
4453
- await waitUntilStopped();
4454
- log(' Settings some attributes...');
4455
- // reset attributes
4456
- await entity.write('closuresWindowCovering', {
4457
- installedOpenLimitLiftCm: 0,
4458
- installedClosedLimitLiftCm: 240,
4459
- installedOpenLimitTiltDdegree: 0,
4460
- installedClosedLimitTiltDdegree: 900,
4461
- ubisysLiftToTiltTransitionSteps: 0xffff,
4462
- ubisysTotalSteps: 0xffff,
4463
- ubisysLiftToTiltTransitionSteps2: 0xffff,
4464
- ubisysTotalSteps2: 0xffff,
4465
- }, manufacturerOptions.ubisys);
4466
- // enable calibration mode
4467
- await sleepSeconds(2);
4468
- await entity.write('closuresWindowCovering', {windowCoveringMode: mode | modeCalibrationBitMask});
4469
- await sleepSeconds(2);
4470
- // move down a bit and back up to detect upper limit
4471
- log(' Moving cover down a bit...');
4472
- await entity.command('closuresWindowCovering', 'downClose');
4473
- await sleepSeconds(5);
4474
- await entity.command('closuresWindowCovering', 'stop');
4475
- await sleepSeconds(2);
4476
- log(' Moving up again to detect upper limit...');
4477
- await entity.command('closuresWindowCovering', 'upOpen');
4478
- await waitUntilStopped();
4479
- log(' Moving down to count steps from open to closed...');
4480
- await entity.command('closuresWindowCovering', 'downClose');
4481
- await waitUntilStopped();
4482
- log(' Moving up to count steps from closed to open...');
4483
- await entity.command('closuresWindowCovering', 'upOpen');
4484
- await waitUntilStopped();
4485
- }
4486
- // now write any attribute values present in JSON
4487
- await writeAttrFromJson('installedOpenLimitLiftCm');
4488
- await writeAttrFromJson('installedClosedLimitLiftCm');
4489
- await writeAttrFromJson('installedOpenLimitTiltDdegree');
4490
- await writeAttrFromJson('installedClosedLimitTiltDdegree');
4491
- await writeAttrFromJson('ubisysTurnaroundGuardTime');
4492
- await writeAttrFromJson('ubisysLiftToTiltTransitionSteps');
4493
- await writeAttrFromJson('ubisysTotalSteps');
4494
- await writeAttrFromJson('ubisysLiftToTiltTransitionSteps2');
4495
- await writeAttrFromJson('ubisysTotalSteps2');
4496
- await writeAttrFromJson('ubisysAdditionalSteps');
4497
- await writeAttrFromJson('ubisysInactivePowerThreshold');
4498
- await writeAttrFromJson('ubisysStartupSteps');
4499
- // some convenience functions to not have to calculate
4500
- await writeAttrFromJson('ubisysTotalSteps', 'open_to_closed_s', (s) => s * stepsPerSecond);
4501
- await writeAttrFromJson('ubisysTotalSteps2', 'closed_to_open_s', (s) => s * stepsPerSecond);
4502
- await writeAttrFromJson('ubisysLiftToTiltTransitionSteps', 'lift_to_tilt_transition_ms',
4503
- (s) => s * stepsPerSecond / 1000);
4504
- await writeAttrFromJson('ubisysLiftToTiltTransitionSteps2', 'lift_to_tilt_transition_ms',
4505
- (s) => s * stepsPerSecond / 1000);
4506
- if (hasCalibrate) {
4507
- log(' Finalizing calibration...');
4508
- // disable calibration mode again
4509
- await sleepSeconds(2);
4510
- await entity.write('closuresWindowCovering', {windowCoveringMode: mode & ~modeCalibrationBitMask});
4511
- await sleepSeconds(2);
4512
- // re-read and dump all relevant attributes
4513
- log(' Done - will now read back the results.');
4514
- converters.ubisys_configure_j1.convertGet(entity, key, meta);
4515
- }
4516
- },
4517
- convertGet: async (entity, key, meta) => {
4518
- const log = (json) => {
4519
- meta.logger.warn(`ubisys: Cover configuration read: ${JSON.stringify(json)}`);
4520
- };
4521
- log(await entity.read('closuresWindowCovering', [
4522
- 'windowCoveringType',
4523
- 'physicalClosedLimitLiftCm',
4524
- 'physicalClosedLimitTiltDdegree',
4525
- 'installedOpenLimitLiftCm',
4526
- 'installedClosedLimitLiftCm',
4527
- 'installedOpenLimitTiltDdegree',
4528
- 'installedClosedLimitTiltDdegree',
4529
- ]));
4530
- log(await entity.read('closuresWindowCovering', [
4531
- 'configStatus',
4532
- 'windowCoveringMode',
4533
- 'currentPositionLiftPercentage',
4534
- 'currentPositionLiftCm',
4535
- 'currentPositionTiltPercentage',
4536
- 'currentPositionTiltDdegree',
4537
- 'operationalStatus',
4538
- ]));
4539
- log(await entity.read('closuresWindowCovering', [
4540
- 'ubisysTurnaroundGuardTime',
4541
- 'ubisysLiftToTiltTransitionSteps',
4542
- 'ubisysTotalSteps',
4543
- 'ubisysLiftToTiltTransitionSteps2',
4544
- 'ubisysTotalSteps2',
4545
- 'ubisysAdditionalSteps',
4546
- 'ubisysInactivePowerThreshold',
4547
- 'ubisysStartupSteps',
4548
- ], manufacturerOptions.ubisys));
4549
- },
4550
- },
4551
- ubisys_dimmer_setup: {
4552
- key: ['capabilities_forward_phase_control',
4553
- 'capabilities_reverse_phase_control',
4554
- 'capabilities_reactance_discriminator',
4555
- 'capabilities_configurable_curve',
4556
- 'capabilities_overload_detection',
4557
- 'status_forward_phase_control',
4558
- 'status_reverse_phase_control',
4559
- 'status_overload',
4560
- 'status_capacitive_load',
4561
- 'status_inductive_load',
4562
- 'mode_phase_control'],
4563
- convertSet: async (entity, key, value, meta) => {
4564
- if (key === 'mode_phase_control') {
4565
- const phaseControl = value.toLowerCase();
4566
- const phaseControlValues = {'automatic': 0, 'forward': 1, 'reverse': 2};
4567
- utils.validateValue(phaseControl, Object.keys(phaseControlValues));
4568
- await entity.write('manuSpecificUbisysDimmerSetup',
4569
- {'mode': phaseControlValues[phaseControl]}, manufacturerOptions.ubisysNull);
4570
- }
4571
- converters.ubisys_dimmer_setup.convertGet(entity, key, meta);
4572
- },
4573
- convertGet: async (entity, key, meta) => {
4574
- await entity.read('manuSpecificUbisysDimmerSetup', ['capabilities'], manufacturerOptions.ubisysNull);
4575
- await entity.read('manuSpecificUbisysDimmerSetup', ['status'], manufacturerOptions.ubisysNull);
4576
- await entity.read('manuSpecificUbisysDimmerSetup', ['mode'], manufacturerOptions.ubisysNull);
4577
- },
4578
- },
4579
- ubisys_dimmer_setup_genLevelCtrl: {
4580
- key: ['minimum_on_level'],
4581
- convertSet: async (entity, key, value, meta) => {
4582
- if (key === 'minimum_on_level') {
4583
- await entity.write('genLevelCtrl', {'ubisysMinimumOnLevel': value}, manufacturerOptions.ubisys);
4584
- }
4585
- converters.ubisys_dimmer_setup_genLevelCtrl.convertGet(entity, key, meta);
4586
- },
4587
- convertGet: async (entity, key, meta) => {
4588
- await entity.read('genLevelCtrl', ['ubisysMinimumOnLevel'], manufacturerOptions.ubisys);
4589
- },
4590
- },
4591
- ubisys_device_setup: {
4592
- key: ['configure_device_setup'],
4593
- convertSet: async (entity, key, value, meta) => {
4594
- const devMgmtEp = meta.device.getEndpoint(232);
4595
-
4596
- if (value.hasOwnProperty('input_configurations')) {
4597
- // example: [0, 0, 0, 0]
4598
- await devMgmtEp.write(
4599
- 'manuSpecificUbisysDeviceSetup',
4600
- {'inputConfigurations': {elementType: 'data8', elements: value.input_configurations}},
4601
- manufacturerOptions.ubisysNull,
4602
- );
4603
- }
4604
-
4605
- if (value.hasOwnProperty('input_actions')) {
4606
- // example (default for C4): [[0,13,1,6,0,2], [1,13,2,6,0,2], [2,13,3,6,0,2], [3,13,4,6,0,2]]
4607
- await devMgmtEp.write(
4608
- 'manuSpecificUbisysDeviceSetup',
4609
- {'inputActions': {elementType: 'octetStr', elements: value.input_actions}},
4610
- manufacturerOptions.ubisysNull,
4611
- );
4612
- }
4613
-
4614
- if (value.hasOwnProperty('input_action_templates')) {
4615
- const templateTypes = {
4616
- // source: "ZigBee Device Physical Input Configurations Integrator’s Guide"
4617
- // (can be obtained directly from ubisys upon request)
4618
- 'toggle': {
4619
- getInputActions: (input, endpoint) => [
4620
- [input, 0x0D, endpoint, 0x06, 0x00, 0x02],
4621
- ],
4622
- },
4623
- 'toggle_switch': {
4624
- getInputActions: (input, endpoint) => [
4625
- [input, 0x0D, endpoint, 0x06, 0x00, 0x02],
4626
- [input, 0x03, endpoint, 0x06, 0x00, 0x02],
4627
- ],
4628
- },
4629
- 'on_off_switch': {
4630
- getInputActions: (input, endpoint) => [
4631
- [input, 0x0D, endpoint, 0x06, 0x00, 0x01],
4632
- [input, 0x03, endpoint, 0x06, 0x00, 0x00],
4633
- ],
4634
- },
4635
- 'on': {
4636
- getInputActions: (input, endpoint) => [
4637
- [input, 0x0D, endpoint, 0x06, 0x00, 0x01],
4638
- ],
4639
- },
4640
- 'off': {
4641
- getInputActions: (input, endpoint) => [
4642
- [input, 0x0D, endpoint, 0x06, 0x00, 0x00],
4643
- ],
4644
- },
4645
- 'dimmer_single': {
4646
- getInputActions: (input, endpoint, template) => {
4647
- const moveUpCmd = template.no_onoff || template.no_onoff_up ? 0x01 : 0x05;
4648
- const moveDownCmd = template.no_onoff || template.no_onoff_down ? 0x01 : 0x05;
4649
- const moveRate = template.rate || 50;
4650
- return [
4651
- [input, 0x07, endpoint, 0x06, 0x00, 0x02],
4652
- [input, 0x86, endpoint, 0x08, 0x00, moveUpCmd, 0x00, moveRate],
4653
- [input, 0xC6, endpoint, 0x08, 0x00, moveDownCmd, 0x01, moveRate],
4654
- [input, 0x0B, endpoint, 0x08, 0x00, 0x03],
4655
- ];
4656
- },
4657
- },
4658
- 'dimmer_double': {
4659
- doubleInputs: true,
4660
- getInputActions: (inputs, endpoint, template) => {
4661
- const moveUpCmd = template.no_onoff || template.no_onoff_up ? 0x01 : 0x05;
4662
- const moveDownCmd = template.no_onoff || template.no_onoff_down ? 0x01 : 0x05;
4663
- const moveRate = template.rate || 50;
4664
- return [
4665
- [inputs[0], 0x07, endpoint, 0x06, 0x00, 0x01],
4666
- [inputs[0], 0x06, endpoint, 0x08, 0x00, moveUpCmd, 0x00, moveRate],
4667
- [inputs[0], 0x0B, endpoint, 0x08, 0x00, 0x03],
4668
- [inputs[1], 0x07, endpoint, 0x06, 0x00, 0x00],
4669
- [inputs[1], 0x06, endpoint, 0x08, 0x00, moveDownCmd, 0x01, moveRate],
4670
- [inputs[1], 0x0B, endpoint, 0x08, 0x00, 0x03],
4671
- ];
4672
- },
4673
- },
4674
- 'cover': {
4675
- cover: true,
4676
- doubleInputs: true,
4677
- getInputActions: (inputs, endpoint) => [
4678
- [inputs[0], 0x0D, endpoint, 0x02, 0x01, 0x00],
4679
- [inputs[0], 0x07, endpoint, 0x02, 0x01, 0x02],
4680
- [inputs[1], 0x0D, endpoint, 0x02, 0x01, 0x01],
4681
- [inputs[1], 0x07, endpoint, 0x02, 0x01, 0x02],
4682
- ],
4683
- },
4684
- 'cover_switch': {
4685
- cover: true,
4686
- doubleInputs: true,
4687
- getInputActions: (inputs, endpoint) => [
4688
- [inputs[0], 0x0D, endpoint, 0x02, 0x01, 0x00],
4689
- [inputs[0], 0x03, endpoint, 0x02, 0x01, 0x02],
4690
- [inputs[1], 0x0D, endpoint, 0x02, 0x01, 0x01],
4691
- [inputs[1], 0x03, endpoint, 0x02, 0x01, 0x02],
4692
- ],
4693
- },
4694
- 'cover_up': {
4695
- cover: true,
4696
- getInputActions: (input, endpoint) => [
4697
- [input, 0x0D, endpoint, 0x02, 0x01, 0x00],
4698
- ],
4699
- },
4700
- 'cover_down': {
4701
- cover: true,
4702
- getInputActions: (input, endpoint) => [
4703
- [input, 0x0D, endpoint, 0x02, 0x01, 0x01],
4704
- ],
4705
- },
4706
- 'scene': {
4707
- scene: true,
4708
- getInputActions: (input, endpoint, groupId, sceneId) => [
4709
- [input, 0x07, endpoint, 0x05, 0x00, 0x05, groupId & 0xff, groupId >> 8, sceneId],
4710
- ],
4711
- getInputActions2: (input, endpoint, groupId, sceneId) => [
4712
- [input, 0x06, endpoint, 0x05, 0x00, 0x05, groupId & 0xff, groupId >> 8, sceneId],
4713
- ],
4714
- },
4715
- 'scene_switch': {
4716
- scene: true,
4717
- getInputActions: (input, endpoint, groupId, sceneId) => [
4718
- [input, 0x0D, endpoint, 0x05, 0x00, 0x05, groupId & 0xff, groupId >> 8, sceneId],
4719
- ],
4720
- getInputActions2: (input, endpoint, groupId, sceneId) => [
4721
- [input, 0x03, endpoint, 0x05, 0x00, 0x05, groupId & 0xff, groupId >> 8, sceneId],
4722
- ],
4723
- },
4724
- };
4725
-
4726
- // first input
4727
- let input = 0;
4728
- // first client endpoint - depends on actual device
4729
- let endpoint = {'S1': 2, 'S2': 3, 'D1': 2, 'J1': 2, 'C4': 1}[meta.mapped.model];
4730
- // default group id
4731
- let groupId = 0;
4732
-
4733
- const templates = Array.isArray(value.input_action_templates) ? value.input_action_templates :
4734
- [value.input_action_templates];
4735
- let resultingInputActions = [];
4736
- for (const template of templates) {
4737
- const templateType = templateTypes[template.type];
4738
- if (!templateType) {
4739
- throw new Error(`input_action_templates: Template type '${template.type}' is not valid ` +
4740
- `(valid types: ${Object.keys(templateTypes)})`);
4741
- }
4742
-
4743
- if (template.hasOwnProperty('input')) {
4744
- input = template.input;
4745
- }
4746
- if (template.hasOwnProperty('endpoint')) {
4747
- endpoint = template.endpoint;
4748
- }
4749
- // C4 cover endpoints only start at 5
4750
- if (templateType.cover && meta.mapped.model === 'C4' && endpoint < 5) {
4751
- endpoint += 4;
4752
- }
4753
-
4754
- let inputActions;
4755
- if (!templateType.doubleInputs) {
4756
- if (!templateType.scene) {
4757
- // single input, no scene(s)
4758
- inputActions = templateType.getInputActions(input, endpoint, template);
4759
- } else {
4760
- // scene(s) (always single input)
4761
- if (!template.hasOwnProperty('scene_id')) {
4762
- throw new Error(`input_action_templates: Need an attribute 'scene_id' for '${template.type}'`);
4763
- }
4764
- if (template.hasOwnProperty('group_id')) {
4765
- groupId = template.group_id;
4766
- }
4767
- inputActions = templateType.getInputActions(input, endpoint, groupId, template.scene_id);
4768
-
4769
- if (template.hasOwnProperty('scene_id_2')) {
4770
- if (template.hasOwnProperty('group_id_2')) {
4771
- groupId = template.group_id_2;
4772
- }
4773
- inputActions = inputActions.concat(templateType.getInputActions2(input, endpoint, groupId,
4774
- template.scene_id_2));
4775
- }
4776
- }
4777
- } else {
4778
- // double inputs
4779
- input = template.hasOwnProperty('inputs') ? template.inputs : [input, input + 1];
4780
- inputActions = templateType.getInputActions(input, endpoint, template);
4781
- }
4782
- resultingInputActions = resultingInputActions.concat(inputActions);
4783
-
4784
- meta.logger.warn(`ubisys: Using input(s) ${input} and endpoint ${endpoint} for '${template.type}'.`);
4785
- // input might by now be an array (in case of double inputs)
4786
- input = (Array.isArray(input) ? Math.max(...input) : input) + 1;
4787
- endpoint += 1;
4788
- }
4789
-
4790
- meta.logger.debug(`ubisys: input_actions to be sent to '${meta.options.friendlyName}': ` +
4791
- JSON.stringify(resultingInputActions));
4792
- await devMgmtEp.write(
4793
- 'manuSpecificUbisysDeviceSetup',
4794
- {'inputActions': {elementType: 'octetStr', elements: resultingInputActions}},
4795
- manufacturerOptions.ubisysNull,
4796
- );
4797
- }
4798
-
4799
- // re-read effective settings and dump them to the log
4800
- converters.ubisys_device_setup.convertGet(entity, key, meta);
4801
- },
4802
-
4803
- convertGet: async (entity, key, meta) => {
4804
- const log = (dataRead) => {
4805
- meta.logger.warn(
4806
- `ubisys: Device setup read for '${meta.options.friendly_name}': ${JSON.stringify(utils.toSnakeCase(dataRead))}`);
4807
- };
4808
- const devMgmtEp = meta.device.getEndpoint(232);
4809
- log(await devMgmtEp.read('manuSpecificUbisysDeviceSetup', ['inputConfigurations'], manufacturerOptions.ubisysNull));
4810
- log(await devMgmtEp.read('manuSpecificUbisysDeviceSetup', ['inputActions'], manufacturerOptions.ubisysNull));
4811
- },
4812
- },
4813
4402
  tint_scene: {
4814
4403
  key: ['tint_scene'],
4815
4404
  convertSet: async (entity, key, value, meta) => {
package/devices/kmpcil.js CHANGED
@@ -3,8 +3,71 @@ const fz = {...require('../converters/fromZigbee'), legacy: require('../lib/lega
3
3
  const tz = require('../converters/toZigbee');
4
4
  const constants = require('../lib/constants');
5
5
  const reporting = require('../lib/reporting');
6
+ const globalStore = require('../lib/store');
7
+ const utils = require('../lib/utils');
6
8
  const e = exposes.presets;
7
9
 
10
+ const kmpcilOptions={
11
+ presence_timeout_dc: () => {
12
+ return exposes.numeric('presence_timeout_dc').withValueMin(60).withDescription(
13
+ 'Time in seconds after which presence is cleared after detecting it (default 60 seconds) while in DC.');
14
+ },
15
+ presence_timeout_battery: () => {
16
+ return exposes.numeric('presence_timeout_battery').withValueMin(120).withDescription(
17
+ 'Time in seconds after which presence is cleared after detecting it (default 420 seconds) while in Battery.');
18
+ },
19
+ };
20
+
21
+ function handleKmpcilPresence(model, msg, publish, options, meta) {
22
+ const useOptionsTimeoutBattery = options && options.hasOwnProperty('presence_timeout_battery');
23
+ const timeoutBattery = useOptionsTimeoutBattery ? options.presence_timeout_battery : 420; // 100 seconds by default
24
+
25
+ const useOptionsTimeoutDc = options && options.hasOwnProperty('presence_timeout_dc');
26
+ const timeoutDc = useOptionsTimeoutDc ? options.presence_timeout_dc : 60;
27
+
28
+ const mode = meta.state? meta.state['power_state'] : false;
29
+
30
+ const timeout = mode ? timeoutDc : timeoutBattery;
31
+ // Stop existing timer because motion is detected and set a new one.
32
+ clearTimeout(globalStore.getValue(msg.endpoint, 'timer'));
33
+ const timer = setTimeout(() => publish({presence: false}), timeout * 1000);
34
+ globalStore.putValue(msg.endpoint, 'timer', timer);
35
+
36
+ return {presence: true};
37
+ }
38
+
39
+ const kmpcilConverters = {
40
+ presence_binary_input: {
41
+ cluster: 'genBinaryInput',
42
+ type: ['attributeReport', 'readResponse'],
43
+ convert: (model, msg, publish, options, meta) => {
44
+ const payload = handleKmpcilPresence(model, msg, publish, options, meta);
45
+ if (msg.data.hasOwnProperty('presentValue')) {
46
+ const presentValue = msg.data['presentValue'];
47
+ payload.power_state = (presentValue & 0x01)> 0;
48
+ payload.occupancy = (presentValue & 0x04) > 0;
49
+ payload.vibration = (presentValue & 0x02) > 0;
50
+ }
51
+ return payload;
52
+ },
53
+ },
54
+ presence_power: {
55
+ cluster: 'genPowerCfg',
56
+ type: ['attributeReport', 'readResponse'],
57
+ options: [kmpcilOptions.presence_timeout_dc(), kmpcilOptions.presence_timeout_battery()],
58
+ convert: (model, msg, publish, options, meta) => {
59
+ const payload = handleKmpcilPresence(model, msg, publish, options, meta);
60
+ if (msg.data.hasOwnProperty('batteryVoltage')) {
61
+ payload.voltage = msg.data['batteryVoltage'] * 100;
62
+ if (model.meta && model.meta.battery && model.meta.battery.voltageToPercentage) {
63
+ payload.battery = utils.batteryVoltageToPercentage(payload.voltage, model.meta.battery.voltageToPercentage);
64
+ }
65
+ }
66
+ return payload;
67
+ },
68
+ },
69
+ };
70
+
8
71
  module.exports = [
9
72
  {
10
73
  zigbeeModel: ['RES005'],
@@ -47,4 +110,38 @@ module.exports = [
47
110
  await endpoint.configureReporting('genBinaryOutput', payloadBinaryOutput);
48
111
  },
49
112
  },
113
+ {
114
+ zigbeeModel: ['tagv1'],
115
+ model: 'KMPCIL-tag-001',
116
+ vendor: 'KMPCIL',
117
+ description: 'Arrival sensor',
118
+ fromZigbee: [kmpcilConverters.presence_binary_input, kmpcilConverters.presence_power, fz.temperature],
119
+ exposes: [e.battery(), e.presence(), exposes.binary('power_state', exposes.access.STATE, true, false),
120
+ e.occupancy(), e.vibration(), e.temperature()],
121
+ toZigbee: [],
122
+ meta: {battery: {voltageToPercentage: '3V_1500_2800'}},
123
+ configure: async (device, coordinatorEndpoint, logger) => {
124
+ const endpoint = device.getEndpoint(1);
125
+ for (const cluster of ['msTemperatureMeasurement', 'genPowerCfg', 'genBinaryInput']) {
126
+ // This sleep here(and the sleep) after is to allow the command to be
127
+ // fully sent to coordinator. In case repeater involved and the repeater
128
+ // is litted in resources, we may want to give some time so that the sequence of
129
+ // commands does not overwhelm the repeater.
130
+ await utils.sleep(2000);
131
+ await endpoint.bind(cluster, coordinatorEndpoint);
132
+ }
133
+
134
+ await utils.sleep(1000);
135
+ const p = reporting.payload('batteryVoltage', 0, 10, 1);
136
+ await endpoint.configureReporting('genPowerCfg', p);
137
+
138
+ await utils.sleep(1000);
139
+ const p2 = reporting.payload('presentValue', 0, 300, 1);
140
+ await endpoint.configureReporting('genBinaryInput', p2);
141
+
142
+ await utils.sleep(1000);
143
+ await reporting.temperature(endpoint);
144
+ await endpoint.read('genBinaryInput', ['presentValue']);
145
+ },
146
+ },
50
147
  ];
@@ -32,8 +32,8 @@ module.exports = [
32
32
  {
33
33
  zigbeeModel: [' Contactor\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000'+
34
34
  '\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000'],
35
- model: 'FC80CC',
36
- description: 'Legrand (or Bticino) DIN contactor module',
35
+ model: '412171',
36
+ description: 'DIN contactor module ( Bticino FC80CC )',
37
37
  vendor: 'Legrand',
38
38
  extend: extend.switch(),
39
39
  fromZigbee: [fz.identify, fz.on_off, fz.electrical_measurement, fz.legrand_cluster_fc01, fz.ignore_basic_report, fz.ignore_genOta],
@@ -52,8 +52,8 @@ module.exports = [
52
52
  {
53
53
  zigbeeModel: [' Teleruptor\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000'+
54
54
  '\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000'],
55
- model: 'FC80RC',
56
- description: 'Legrand (or Bticino) DIN smart relay for light control (note: Legrand 412170 may be similar to Bticino FC80RC)',
55
+ model: '412170',
56
+ description: 'DIN smart relay for light control ( Bticino FC80RC ) ',
57
57
  vendor: 'Legrand',
58
58
  extend: extend.switch(),
59
59
  fromZigbee: [fz.identify, fz.on_off, fz.electrical_measurement, fz.legrand_cluster_fc01, fz.ignore_basic_report, fz.ignore_genOta],
package/devices/lidl.js CHANGED
@@ -528,6 +528,17 @@ module.exports = [
528
528
  device.getEndpoint(1).saveClusterAttributeKeyValue('lightingColorCtrl', {colorCapabilities: 29});
529
529
  },
530
530
  },
531
+ {
532
+ fingerprint: [{modelID: 'TS0502B', manufacturerName: '_TZ3210_c2iwpxf1'}],
533
+ model: '14156408L',
534
+ vendor: 'Lidl',
535
+ description: 'Livarno Lux smart LED ceiling light',
536
+ ...extend.light_onoff_brightness_colortemp_color({disableColorTempStartup: true, colorTempRange: [153, 500]}),
537
+ meta: {applyRedFix: true, enhancedHue: false},
538
+ configure: async (device, coordinatorEndpoint, logger) => {
539
+ device.getEndpoint(1).saveClusterAttributeKeyValue('lightingColorCtrl', {colorCapabilities: 16});
540
+ },
541
+ },
531
542
  {
532
543
  fingerprint: [{modelID: 'TS0505B', manufacturerName: '_TZ3210_p9ao60da'}],
533
544
  model: 'HG08008',