zigbee-herdsman-converters 14.0.510 → 14.0.513

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.
@@ -1699,7 +1699,7 @@ const converters = {
1699
1699
  result.hysterersis = precisionRound(data[0x100A], 2) / 10;
1700
1700
  }
1701
1701
  if (data.hasOwnProperty(0x100B)) { // DisplayAutoOffEnable
1702
- const lookup = {0: 'enable', 1: 'disable'};
1702
+ const lookup = {0: 'enabled', 1: 'disabled'};
1703
1703
  result.display_auto_off_enabled = lookup[data[0x100B]];
1704
1704
  }
1705
1705
  if (data.hasOwnProperty(0x2001)) { // AlarmAirTempOverValue
@@ -8496,6 +8496,38 @@ const converters = {
8496
8496
  return result;
8497
8497
  },
8498
8498
  },
8499
+ ZG204ZL_lms: {
8500
+ cluster: 'manuSpecificTuya',
8501
+ type: ['commandDataResponse', 'commandDataReport'],
8502
+ convert: (model, msg, publish, options, meta) => {
8503
+ const result = {};
8504
+ for (const dpValue of msg.data.dpValues) {
8505
+ const dp = dpValue.dp;
8506
+ const value = tuya.getDataValue(dpValue);
8507
+ switch (dp) {
8508
+ case tuya.dataPoints.lmsState:
8509
+ result.occupancy = (value === 0);
8510
+ break;
8511
+ case tuya.dataPoints.lmsBattery:
8512
+ result.battery = value;
8513
+ break;
8514
+ case tuya.dataPoints.lmsSensitivity:
8515
+ result.sensitivity = {'0': 'low', '1': 'medium', '2': 'high'}[value];
8516
+ break;
8517
+ case tuya.dataPoints.lmsKeepTime:
8518
+ result.keep_time = {'0': '10', '1': '30', '2': '60', '3': '120'}[value];
8519
+ break;
8520
+ case tuya.dataPoints.lmsIlluminance:
8521
+ result.illuminance = value;
8522
+ break;
8523
+ default:
8524
+ meta.logger.warn(`zigbee-herdsman-converters:ZG204ZL_lms: NOT RECOGNIZED DP #${
8525
+ dp} with data ${JSON.stringify(dpValue)}`);
8526
+ }
8527
+ }
8528
+ return result;
8529
+ },
8530
+ },
8499
8531
  // #endregion
8500
8532
 
8501
8533
  // #region Ignore converters (these message dont need parsing).
@@ -798,7 +798,7 @@ const converters = {
798
798
  const {message} = meta;
799
799
  const transition = utils.getTransition(entity, 'brightness', meta);
800
800
  const turnsOffAtBrightness1 = utils.getMetaValue(entity, meta.mapped, 'turnsOffAtBrightness1', 'allEqual', false);
801
- let state = message.hasOwnProperty('state') ? message.state.toLowerCase() : undefined;
801
+ let state = message.hasOwnProperty('state') ? (message.state === null ? null : message.state.toLowerCase()) : undefined;
802
802
  let brightness = undefined;
803
803
  if (message.hasOwnProperty('brightness')) {
804
804
  brightness = Number(message.brightness);
@@ -806,91 +806,106 @@ const converters = {
806
806
  brightness = utils.mapNumberRange(Number(message.brightness_percent), 0, 100, 0, 255);
807
807
  }
808
808
 
809
- if (brightness !== undefined && (isNaN(brightness) || brightness < 0 || brightness > 255)) {
810
- // Allow 255 value, changing this to 254 would be a breaking change.
809
+ if (brightness === 255) {
810
+ // Allow 255 for backwards compatibility.
811
+ brightness = 254;
812
+ }
813
+
814
+ if (brightness !== undefined && (isNaN(brightness) || brightness < 0 || brightness > 254)) {
811
815
  throw new Error(`Brightness value of message: '${JSON.stringify(message)}' invalid, must be a number >= 0 and =< 254`);
812
816
  }
813
817
 
814
- if (state !== undefined && ['on', 'off', 'toggle'].includes(state) === false) {
818
+ if (state !== undefined && state !== null && ['on', 'off', 'toggle'].includes(state) === false) {
815
819
  throw new Error(`State value of message: '${JSON.stringify(message)}' invalid, must be 'ON', 'OFF' or 'TOGGLE'`);
816
820
  }
817
821
 
818
- if (state === 'toggle' || state === 'off' || (brightness === undefined && state === 'on')) {
819
- if (transition.specified) {
820
- if (state === 'toggle') {
821
- state = meta.state.state === 'ON' ? 'off' : 'on';
822
- }
823
-
824
- if (state === 'off' && meta.state.brightness && meta.state.state === 'ON') {
825
- // https://github.com/Koenkk/zigbee2mqtt/issues/2850#issuecomment-580365633
826
- // We need to remember the state before turning the device off as we need to restore
827
- // it once we turn it on again.
828
- // We cannot rely on the meta.state as when reporting is enabled the bulb will reports
829
- // it brightness while decreasing the brightness.
830
- globalStore.putValue(entity, 'brightness', meta.state.brightness);
831
- globalStore.putValue(entity, 'turnedOffWithTransition', true);
832
- }
833
-
834
- const fallbackLevel = utils.getObjectProperty(meta.state, 'brightness', 254);
835
- let level = state === 'off' ? 0 : globalStore.getValue(entity, 'brightness', fallbackLevel);
836
- if (state === 'on' && level === 0) level = turnsOffAtBrightness1 ? 2 : 1;
837
-
838
- const payload = {level, transtime: transition.time};
839
- await entity.command('genLevelCtrl', 'moveToLevelWithOnOff', payload, utils.getOptions(meta.mapped, entity));
840
- const result = {state: {state: state.toUpperCase()}};
841
- if (state === 'on') result.state.brightness = level;
842
- return result;
843
- } else {
844
- if (state === 'on' && globalStore.getValue(entity, 'turnedOffWithTransition') === true) {
845
- /**
846
- * In case the bulb it turned OFF with a transition and turned ON WITHOUT
847
- * a transition, the brightness is not recovered as it turns on with brightness 1.
848
- * https://github.com/Koenkk/zigbee-herdsman-converters/issues/1073
849
- */
850
- globalStore.putValue(entity, 'turnedOffWithTransition', false);
851
- await entity.command(
852
- 'genLevelCtrl',
853
- 'moveToLevelWithOnOff',
854
- {level: globalStore.getValue(entity, 'brightness'), transtime: 0},
855
- utils.getOptions(meta.mapped, entity),
856
- );
857
- return {state: {state: 'ON'}, readAfterWriteTime: transition * 100};
858
- } else {
859
- // Store brightness where the bulb was turned off with as we need it when the bulb is turned on
860
- // with transition.
861
- if (meta.state.hasOwnProperty('brightness') && state === 'off') {
862
- globalStore.putValue(entity, 'brightness', meta.state.brightness);
863
- globalStore.putValue(entity, 'turnedOffWithTransition', false);
864
- }
865
-
866
- const result = await converters.on_off.convertSet(entity, 'state', state, meta);
867
- result.readAfterWriteTime = 0;
868
- if (result.state && result.state.state === 'ON' && meta.state.brightness === 0) {
869
- result.state.brightness = 1;
822
+ if ((state === undefined || state === null) && brightness === undefined) {
823
+ throw new Error(`At least one of "brightness" or "state" must have a value: '${JSON.stringify(message)}'`);
824
+ }
825
+
826
+ // Infer state from desired brightness if unset. Ideally we'd want to keep it as it is, but this code has always
827
+ // used 'MoveToLevelWithOnOff' so that'd break backwards compatibility. To keep the state, the user
828
+ // has to explicitly set it to null.
829
+ if (state === undefined) {
830
+ // Also write to `meta.message.state` in case we delegate to the `on_off` converter.
831
+ state = meta.message.state = brightness === 0 ? 'off' : 'on';
832
+ }
833
+
834
+ const targetState = state === 'toggle' ? (meta.state.state === 'ON' ? 'off' : 'on') : state;
835
+ if (targetState === 'off') {
836
+ // Simulate 'Off' with transition via 'MoveToLevelWithOnOff', otherwise just use 'Off'.
837
+ // TODO: if this is a group where some members don't support Level Control, turning them off
838
+ // with transition may have no effect. (Some devices, such as Envilar ZG302-BOX-RELAY, handle
839
+ // 'MoveToLevelWithOnOff' despite not supporting the cluster; others, like the LEDVANCE SMART+
840
+ // plug, do not.)
841
+ brightness = transition.specified || brightness === 0 ? 0 : undefined;
842
+ if (meta.state.hasOwnProperty('brightness') && meta.state.state === 'ON') {
843
+ // The light's current level gets clobbered in two cases:
844
+ // 1. when 'Off' has a transition, in which case it is really 'MoveToLevelWithOnOff'
845
+ // https://github.com/Koenkk/zigbee-herdsman-converters/issues/1073
846
+ // 2. when 'OnLevel' is set: "If OnLevel is not defined, set the CurrentLevel to the stored level."
847
+ // https://github.com/Koenkk/zigbee2mqtt/issues/2850#issuecomment-580365633
848
+ // We need to remember current brightness in case the next 'On' does not provide it. `meta` is not reliable
849
+ // here, as it will get clobbered too if reporting is configured.
850
+ globalStore.putValue(entity, 'brightness', meta.state.brightness);
851
+ globalStore.putValue(entity, 'turnedOffWithTransition', brightness !== undefined);
852
+ }
853
+ } else if (targetState === 'on' && brightness === undefined) {
854
+ // Simulate 'On' with transition via 'MoveToLevelWithOnOff', or restore the level from before
855
+ // it was clobbered by a previous transition to off; otherwise just use 'On'.
856
+ // TODO: same problem as above.
857
+ // TODO: if transition is not specified, should use device default (OnTransitionTime), not 0.
858
+ if (transition.specified || globalStore.getValue(entity, 'turnedOffWithTransition') === true) {
859
+ const current = utils.getObjectProperty(meta.state, 'brightness', 254);
860
+ brightness = globalStore.getValue(entity, 'brightness', current);
861
+ try {
862
+ const attributeRead = await entity.read('genLevelCtrl', ['onLevel']);
863
+ // TODO: for groups, `read` does not wait for responses. If it did, we could still issue a single
864
+ // command if all values of `OnLevel` are equal, or split into one command per device if not.
865
+ if (attributeRead !== undefined && attributeRead['onLevel'] != 255) {
866
+ brightness = attributeRead['onLevel'];
870
867
  }
871
-
872
- return result;
868
+ } catch (e) {
869
+ // OnLevel not supported
873
870
  }
874
871
  }
875
- } else {
876
- brightness = Math.min(254, brightness);
877
- if (brightness === 1 && turnsOffAtBrightness1) {
878
- brightness = 2;
872
+ }
873
+
874
+ if (brightness === undefined) {
875
+ const result = await converters.on_off.convertSet(entity, 'state', state, meta);
876
+ result.readAfterWriteTime = 0;
877
+ if (result.state && result.state.state === 'ON' && meta.state.brightness === 0) {
878
+ result.state.brightness = 1;
879
879
  }
880
+ return result;
881
+ }
880
882
 
883
+ if (brightness === 0 && (targetState === 'on' || state === null)) {
884
+ brightness = 1;
885
+ }
886
+ if (brightness === 1 && turnsOffAtBrightness1) {
887
+ brightness = 2;
888
+ }
889
+
890
+ if (targetState !== 'off') {
881
891
  globalStore.putValue(entity, 'brightness', brightness);
882
- await entity.command(
883
- 'genLevelCtrl',
884
- 'moveToLevelWithOnOff',
885
- {level: Number(brightness), transtime: transition.time},
886
- utils.getOptions(meta.mapped, entity),
887
- );
892
+ globalStore.clearValue(entity, 'turnedOffWithTransition');
893
+ }
894
+ await entity.command(
895
+ 'genLevelCtrl',
896
+ state === null ? 'moveToLevel' : 'moveToLevelWithOnOff',
897
+ {level: Number(brightness), transtime: transition.time},
898
+ utils.getOptions(meta.mapped, entity),
899
+ );
888
900
 
889
- return {
890
- state: {state: brightness === 0 ? 'OFF' : 'ON', brightness: Number(brightness)},
891
- readAfterWriteTime: transition.time * 100,
892
- };
901
+ const result = {state: {}, readAfterWriteTime: transition.time * 100};
902
+ if (brightness !== 0) {
903
+ result.state.brightness = Number(brightness);
904
+ }
905
+ if (state !== null) {
906
+ result.state.state = brightness === 0 ? 'OFF' : 'ON';
893
907
  }
908
+ return result;
894
909
  },
895
910
  convertGet: async (entity, key, meta) => {
896
911
  if (key === 'brightness') {
@@ -2546,8 +2561,9 @@ const converters = {
2546
2561
  key: ['state'],
2547
2562
  convertSet: async (entity, key, value, meta) => {
2548
2563
  const options = {disableDefaultResponse: true};
2564
+ value = value.toLowerCase();
2549
2565
  utils.validateValue(value, ['toggle', 'off', 'on']);
2550
- if (value.toLowerCase() === 'toggle') {
2566
+ if (value === 'toggle') {
2551
2567
  if (!meta.state.hasOwnProperty('state')) {
2552
2568
  throw new Error('Cannot toggle, state not known yet');
2553
2569
  } else {
@@ -3076,10 +3092,10 @@ const converters = {
3076
3092
  const payload = {0x1009: {value: value * 2, type: 0x20}};
3077
3093
  await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
3078
3094
  } else if (key==='hysterersis') {
3079
- const payload = {0x100A: {value: value* 10, type: 0x20}};
3095
+ const payload = {0x100A: {value: value * 10, type: 0x20}};
3080
3096
  await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
3081
3097
  } else if (key==='display_auto_off_enabled') {
3082
- const lookup = {'enable': 0, 'disabled': 1};
3098
+ const lookup = {'enabled': 0, 'disabled': 1};
3083
3099
  const payload = {0x100B: {value: lookup[value], type: herdsman.Zcl.DataType.enum8}};
3084
3100
  await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
3085
3101
  } else if (key==='alarm_airtemp_overvalue') {
@@ -7420,6 +7436,33 @@ const converters = {
7420
7436
  }
7421
7437
  },
7422
7438
  },
7439
+ ZG204ZL_lms: {
7440
+ key: ['sensitivity', 'keep_time'],
7441
+ convertSet: async (entity, key, value, meta) => {
7442
+ switch (key) {
7443
+ case 'sensitivity':
7444
+ await tuya.sendDataPointEnum(entity, tuya.dataPoints.lmsSensitivity, {'low': 0, 'medium': 1, 'high': 2}[value]);
7445
+ break;
7446
+ case 'keep_time':
7447
+ await tuya.sendDataPointEnum(entity, tuya.dataPoints.lmsKeepTime, {'10': 0, '30': 1, '60': 2, '120': 3}[value]);
7448
+ break;
7449
+ default: // Unknown key
7450
+ meta.logger.warn(`tz.ZG204ZL_lms: Unhandled key ${key}`);
7451
+ }
7452
+ },
7453
+ convertGet: async (entity, key, meta) => {
7454
+ switch (key) {
7455
+ case 'sensitivity':
7456
+ await tuya.sendDataPointEnum(entity, tuya.dataPoints.lmsSensitivity, 0, 'dataQuery' );
7457
+ break;
7458
+ case 'keep_time':
7459
+ await tuya.sendDataPointEnum(entity, tuya.dataPoints.lmsKeepTime, 0, 'dataQuery' );
7460
+ break;
7461
+ default: // Unknown key
7462
+ meta.logger.warn(`Unhandled key toZigbee.ZG204ZL_lms.convertGet ${key}`);
7463
+ }
7464
+ },
7465
+ },
7423
7466
  // #endregion
7424
7467
 
7425
7468
  // #region Ignore converters
package/devices/awox.js CHANGED
@@ -67,6 +67,7 @@ module.exports = [
67
67
  vendor: 'AwoX',
68
68
  description: 'LED white',
69
69
  extend: extend.light_onoff_brightness(),
70
+ whiteLabel: [{vendor: 'EGLO', model: '12229'}],
70
71
  },
71
72
  {
72
73
  fingerprint: [
@@ -248,6 +249,7 @@ module.exports = [
248
249
  vendor: 'AwoX',
249
250
  description: 'LED light with color temperature',
250
251
  extend: extend.light_onoff_brightness_colortemp({colorTempRange: [153, 370]}),
252
+ whiteLabel: [{vendor: 'EGLO', model: '12239'}],
251
253
  },
252
254
  {
253
255
  fingerprint: [
package/devices/ikea.js CHANGED
@@ -13,11 +13,15 @@ const {
13
13
  calibrateAndPrecisionRoundOptions, postfixWithEndpointName, getMetaValue,
14
14
  } = require('../lib/utils');
15
15
 
16
- const bulbOnEvent = async (type, data, device) => {
16
+ const bulbOnEvent = async (type, data, device, options, state) => {
17
17
  /**
18
18
  * IKEA bulbs lose their configured reportings when losing power.
19
19
  * A deviceAnnounce indicates they are powered on again.
20
20
  * Reconfigure the configured reoprting here.
21
+ *
22
+ * Additionally some other information is lost like
23
+ * color_options.execute_if_off. We also restore these.
24
+ *
21
25
  * NOTE: binds are not lost so rebinding is not needed!
22
26
  */
23
27
  if (type === 'deviceAnnounce') {
@@ -29,6 +33,12 @@ const bulbOnEvent = async (type, data, device) => {
29
33
  }]);
30
34
  }
31
35
  }
36
+
37
+ // NOTE: execute_if_off default is false
38
+ // we only restore if true, to save unneeded network writes
39
+ if (state.color_options.execute_if_off === true) {
40
+ device.endpoints[0].write('lightingColorCtrl', {'options': 1});
41
+ }
32
42
  }
33
43
  };
34
44
 
package/devices/immax.js CHANGED
@@ -66,16 +66,18 @@ module.exports = [
66
66
  model: '07048L',
67
67
  vendor: 'Immax',
68
68
  description: 'NEO SMART plug',
69
- fromZigbee: [fz.on_off, fz.electrical_measurement],
69
+ fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering],
70
70
  toZigbee: [tz.on_off],
71
71
  configure: async (device, coordinatorEndpoint, logger) => {
72
72
  const endpoint = device.getEndpoint(1);
73
- await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement']);
73
+ await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering']);
74
74
  await reporting.onOff(endpoint);
75
75
  await reporting.readEletricalMeasurementMultiplierDivisors(endpoint);
76
+ await reporting.readMeteringMultiplierDivisor(endpoint);
77
+ await reporting.currentSummDelivered(endpoint);
76
78
  await reporting.activePower(endpoint);
77
79
  },
78
- exposes: [e.switch(), e.power()],
80
+ exposes: [e.switch(), e.power(), e.energy()],
79
81
  },
80
82
  {
81
83
  zigbeeModel: ['losfena'],
package/devices/lellki.js CHANGED
@@ -9,9 +9,10 @@ const tuya = require('../lib/tuya');
9
9
 
10
10
  module.exports = [
11
11
  {
12
- fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_air9m6af'}, {modelID: 'TS011F', manufacturerName: '_TZ3000_9djocypn'}],
12
+ fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_air9m6af'}, {modelID: 'TS011F', manufacturerName: '_TZ3000_9djocypn'},
13
+ {modelID: 'TS011F', manufacturerName: '_TZ3000_bppxj3sf'}],
13
14
  zigbeeModel: ['JZ-ZB-005'],
14
- model: 'WP33-EU',
15
+ model: 'WP33-EU/WP34-EU',
15
16
  vendor: 'LELLKI',
16
17
  description: 'Multiprise with 4 AC outlets and 2 USB super charging ports (16A)',
17
18
  extend: extend.switch(),
@@ -22,11 +23,9 @@ module.exports = [
22
23
  return {l1: 1, l2: 2, l3: 3, l4: 4, l5: 5};
23
24
  },
24
25
  configure: async (device, coordinatorEndpoint, logger) => {
25
- await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ['genOnOff']);
26
- await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ['genOnOff']);
27
- await reporting.bind(device.getEndpoint(3), coordinatorEndpoint, ['genOnOff']);
28
- await reporting.bind(device.getEndpoint(4), coordinatorEndpoint, ['genOnOff']);
29
- await reporting.bind(device.getEndpoint(5), coordinatorEndpoint, ['genOnOff']);
26
+ for (const ID of [1, 2, 3, 4, 5]) {
27
+ await reporting.bind(device.getEndpoint(ID), coordinatorEndpoint, ['genOnOff']);
28
+ }
30
29
  },
31
30
  },
32
31
  {
@@ -104,24 +103,6 @@ module.exports = [
104
103
  .withDescription('Recover state after power outage')],
105
104
  onEvent: tuya.onEventMeasurementPoll,
106
105
  },
107
- {
108
- fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_bppxj3sf'}],
109
- model: 'WP34-EU',
110
- vendor: 'LELLKI',
111
- description: 'Outlet power cord with 4 sockets and 2 USB',
112
- exposes: [e.switch().withEndpoint('l1'), e.switch().withEndpoint('l2'), e.switch().withEndpoint('l3'),
113
- e.switch().withEndpoint('l4'), e.switch().withEndpoint('l5')],
114
- extend: extend.switch(),
115
- meta: {multiEndpoint: true},
116
- configure: async (device, coordinatorEndpoint, logger) => {
117
- for (const ID of [1, 2, 3, 4, 5]) {
118
- await reporting.bind(device.getEndpoint(ID), coordinatorEndpoint, ['genOnOff']);
119
- }
120
- },
121
- endpoint: (device) => {
122
- return {'l1': 1, 'l2': 2, 'l3': 3, 'l4': 4, 'l5': 5};
123
- },
124
- },
125
106
  {
126
107
  fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_0yxeawjt'}],
127
108
  model: 'WK34-EU',
@@ -0,0 +1,41 @@
1
+ const exposes = require('../lib/exposes');
2
+ const fz = require('../converters/fromZigbee');
3
+ const tz = require('../converters/toZigbee');
4
+ const reporting = require('../lib/reporting');
5
+ const e = exposes.presets;
6
+ const ea = exposes.access;
7
+
8
+ module.exports = [
9
+ {
10
+ fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3210_7jnk7l3k'}],
11
+ model: 'SPP02GIP',
12
+ vendor: 'Mercator',
13
+ description: 'Ikuü double outdoors power point',
14
+ fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering, fz.ignore_basic_report, fz.tuya_switch_power_outage_memory],
15
+ toZigbee: [tz.on_off],
16
+ exposes: [e.switch().withEndpoint('left'), e.switch().withEndpoint('right'),
17
+ e.power().withEndpoint('left'), e.current().withEndpoint('left'),
18
+ e.voltage().withEndpoint('left').withAccess(ea.STATE), e.energy()],
19
+ endpoint: (device) => {
20
+ return {left: 1, right: 2};
21
+ },
22
+ meta: {multiEndpoint: true},
23
+ configure: async (device, coordinatorEndpoint, logger) => {
24
+ const endpoint1 = device.getEndpoint(1);
25
+ const endpoint2 = device.getEndpoint(2);
26
+ await reporting.bind(endpoint1, coordinatorEndpoint, ['genBasic', 'genOnOff', 'haElectricalMeasurement', 'seMetering']);
27
+ await reporting.bind(endpoint2, coordinatorEndpoint, ['genOnOff']);
28
+ await reporting.onOff(endpoint1);
29
+ await reporting.onOff(endpoint1);
30
+ await reporting.onOff(endpoint1);
31
+ await reporting.rmsVoltage(endpoint1, {change: 5});
32
+ await reporting.rmsCurrent(endpoint1, {change: 50});
33
+ await reporting.activePower(endpoint1, {change: 1});
34
+ await reporting.onOff(endpoint1);
35
+ await reporting.onOff(endpoint2);
36
+ endpoint1.saveClusterAttributeKeyValue('haElectricalMeasurement', {acCurrentDivisor: 1000, acCurrentMultiplier: 1});
37
+ endpoint1.saveClusterAttributeKeyValue('seMetering', {divisor: 100, multiplier: 1});
38
+ device.save();
39
+ },
40
+ },
41
+ ];
package/devices/moes.js CHANGED
@@ -165,7 +165,7 @@ module.exports = [
165
165
  },
166
166
  },
167
167
  {
168
- fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_tz32mtza'}, {modelID: 'TS0601', manufacturerName: '_TZE200_vm1gyrso'}],
168
+ fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_tz32mtza'}],
169
169
  model: 'ZTS-EU_3gang',
170
170
  vendor: 'Moes',
171
171
  description: 'Wall touch light switch (3 gang)',
package/devices/namron.js CHANGED
@@ -314,7 +314,7 @@ module.exports = [
314
314
  .withUnit('°C')
315
315
  .withValueMin(0.5).withValueMax(2).withValueStep(0.1)
316
316
  .withDescription('Hysteresis setting, between 0.5 and 2 in 0.1 °C. Default: 0.5.'),
317
- exposes.enum('display_auto_off_enabled', ea.ALL, ['enable', 'disabled']),
317
+ exposes.enum('display_auto_off_enabled', ea.ALL, ['enabled', 'disabled']),
318
318
  exposes.numeric('alarm_airtemp_overvalue', ea.ALL)
319
319
  .withUnit('°C')
320
320
  .withValueMin(20).withValueMax(60)
@@ -81,6 +81,15 @@ module.exports = [
81
81
  extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
82
82
  ota: ota.zigbeeOTA,
83
83
  },
84
+ {
85
+ zigbeeModel: ['929003045501_01', '929003045501_02', '929003045501_03'],
86
+ model: '929003045501',
87
+ vendor: 'Philips',
88
+ description: 'Hue Centura recessed spotlight white and color ambiance GU10 (black)',
89
+ meta: {turnsOffAtBrightness1: true},
90
+ extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
91
+ ota: ota.zigbeeOTA,
92
+ },
84
93
  {
85
94
  zigbeeModel: ['929003047501'],
86
95
  model: '929003047501',
@@ -2636,6 +2645,15 @@ module.exports = [
2636
2645
  extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
2637
2646
  ota: ota.zigbeeOTA,
2638
2647
  },
2648
+ {
2649
+ zigbeeModel: ['929003045601_01', '929003045601_02'],
2650
+ model: '8719514338142',
2651
+ vendor: 'Philips',
2652
+ description: 'Hue White ambiance Runner double spotlight',
2653
+ meta: {turnsOffAtBrightness1: true},
2654
+ extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
2655
+ ota: ota.zigbeeOTA,
2656
+ },
2639
2657
  {
2640
2658
  zigbeeModel: ['5047230P6', '5047230P6'],
2641
2659
  model: '5047230P6',
package/devices/tuya.js CHANGED
@@ -592,7 +592,7 @@ module.exports = [
592
592
  },
593
593
  },
594
594
  {
595
- fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_aqnazj70'}],
595
+ fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_aqnazj70'}, {modelID: 'TS0601', manufacturerName: 'TZE200_k6jhsr0q'}],
596
596
  model: 'TS0601_switch_4_gang',
597
597
  vendor: 'TuYa',
598
598
  description: '4 gang switch',
@@ -712,6 +712,7 @@ module.exports = [
712
712
  {modelID: 'TS0502B', manufacturerName: '_TZ3210_ijsj2evj'},
713
713
  {modelID: 'TS0502B', manufacturerName: '_TZ3210_pgq2qvyv'},
714
714
  {modelID: 'TS0502B', manufacturerName: '_TZ3210_nvaik6gk'},
715
+ {modelID: 'TS0502B', manufacturerName: '_TZ3000_armwcncd'},
715
716
  ],
716
717
  model: 'TS0502B',
717
718
  vendor: 'TuYa',
@@ -1417,7 +1418,10 @@ module.exports = [
1417
1418
  .withDescription('Plug LED indicator mode'), e.child_lock()],
1418
1419
  },
1419
1420
  {
1420
- fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_gjnozsaz', applicationVersion: 74}]
1421
+ fingerprint: [
1422
+ {modelID: 'TS011F', manufacturerName: '_TZ3000_gjnozsaz', applicationVersion: 74},
1423
+ {modelID: 'TS011F', manufacturerName: '_TZ3000_cehuw1lw', applicationVersion: 74},
1424
+ ]
1421
1425
  .concat(...TS011Fplugs.map((manufacturerName) => {
1422
1426
  return [69, 68, 65, 64].map((applicationVersion) => {
1423
1427
  return {modelID: 'TS011F', manufacturerName, applicationVersion};
@@ -2350,4 +2354,20 @@ module.exports = [
2350
2354
  onEvent: tuya.onEventSetLocalTime,
2351
2355
  exposes: [e.temperature(), e.humidity(), e.battery()],
2352
2356
  },
2357
+ {
2358
+ fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_3towulqd'}],
2359
+ model: 'ZG-204ZL',
2360
+ vendor: 'TuYa',
2361
+ description: 'Luminance motion sensor',
2362
+ fromZigbee: [fz.ZG204ZL_lms],
2363
+ toZigbee: [tz.ZG204ZL_lms],
2364
+ exposes: [
2365
+ e.occupancy(), e.illuminance(), e.battery(),
2366
+ exposes.enum('sensitivity', ea.ALL, ['low', 'medium', 'high'])
2367
+ .withDescription('PIR sensor sensitivity (refresh and update only while active)'),
2368
+ exposes.enum('keep_time', ea.ALL, ['10', '30', '60', '120'])
2369
+ .withDescription('PIR keep time in seconds (refresh and update only while active)'),
2370
+ ],
2371
+ },
2372
+
2353
2373
  ];
package/devices/xiaomi.js CHANGED
@@ -884,7 +884,8 @@ module.exports = [
884
884
  description: 'Aqara T1 human body movement and illuminance sensor',
885
885
  fromZigbee: [fz.aqara_occupancy_illuminance, fz.aqara_opple, fz.battery],
886
886
  toZigbee: [tz.aqara_detection_interval],
887
- exposes: [e.occupancy(), e.illuminance().withUnit('lx').withDescription('Measured illuminance in lux'),
887
+ exposes: [e.occupancy(), e.illuminance_lux().withProperty('illuminance'),
888
+ e.illuminance().withUnit('lx').withDescription('Measured illuminance in lux'),
888
889
  exposes.numeric('detection_interval', ea.ALL).withValueMin(2).withValueMax(65535).withUnit('s')
889
890
  .withDescription('Time interval for detecting actions'), e.temperature(), e.battery()],
890
891
  meta: {battery: {voltageToPercentage: '3V_2850_3000_log'}},
package/lib/tuya.js CHANGED
@@ -686,6 +686,12 @@ const dataPoints = {
686
686
  tshpsIlluminanceLux: 104,
687
687
  tshpsCLI: 103, // not recognize
688
688
  tshpsSelfTest: 6, // not recognize
689
+ // TuYa Luminance Motion sensor
690
+ lmsState: 1,
691
+ lmsBattery: 4,
692
+ lmsSensitivity: 9,
693
+ lmsKeepTime: 10,
694
+ lmsIlluminance: 12,
689
695
  };
690
696
 
691
697
  const thermostatWeekFormat = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zigbee-herdsman-converters",
3
- "version": "14.0.510",
3
+ "version": "14.0.513",
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": "^2.2.0",
41
- "zigbee-herdsman": "^0.14.27"
41
+ "zigbee-herdsman": "^0.14.28"
42
42
  },
43
43
  "devDependencies": {
44
44
  "eslint": "*",