zigbee-herdsman-converters 14.0.465 → 14.0.466

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.
@@ -4580,10 +4580,33 @@ const converters = {
4580
4580
  } else if (meta.device.manufacturerName === '_TZE200_swaamsoy') {
4581
4581
  // https://github.com/Koenkk/zigbee-herdsman-converters/pull/3004
4582
4582
  if (dpValue.dp === 2) {
4583
+ if (value < 10) {
4584
+ tuya.logUnexpectedDataValue('tuya_dimmer', msg, dpValue, meta, 'brightness', 10, 1000);
4585
+ }
4583
4586
  return {brightness: mapNumberRange(value, 10, 1000, 0, 254)};
4584
4587
  }
4585
- } else { // TODO: Unknown dp, assumed value type
4586
- return {brightness: mapNumberRange(value, 10, 1000, 0, 254), level: value};
4588
+ } else if (meta.device.manufacturerName === '_TZE200_3p5ydos3') {
4589
+ if (dpValue.dp === tuya.dataPoints.eardaDimmerLevel) {
4590
+ return {brightness: mapNumberRange(value, 0, 1000, 0, 254)};
4591
+ } else if (dpValue.dp === tuya.dataPoints.dimmerMinLevel) {
4592
+ return {min_brightness: mapNumberRange(value, 0, 1000, 1, 255)};
4593
+ } else if (dpValue.dp === tuya.dataPoints.dimmerMaxLevel) {
4594
+ return {max_brightness: mapNumberRange(value, 0, 1000, 1, 255)};
4595
+ } else {
4596
+ tuya.logUnexpectedDataPoint('tuya_dimmer', msg, dpValue, meta);
4597
+ }
4598
+ } else {
4599
+ if (dpValue.dp !== tuya.dataPoints.dimmerLevel) {
4600
+ tuya.logUnexpectedDataPoint('tuya_dimmer', msg, dpValue, meta);
4601
+ }
4602
+ if (dpValue.datatype !== tuya.dataTypes.value) {
4603
+ tuya.logUnexpectedDataType('tuya_dimmer', msg, dpValue, meta);
4604
+ } else {
4605
+ if (value < 10) {
4606
+ tuya.logUnexpectedDataValue('tuya_dimmer', msg, dpValue, meta, 'brightness', 10, 1000);
4607
+ }
4608
+ return {brightness: mapNumberRange(value, 10, 1000, 0, 254), level: value};
4609
+ }
4587
4610
  }
4588
4611
  },
4589
4612
  },
@@ -4593,14 +4616,6 @@ const converters = {
4593
4616
  convert: (model, msg, publis, options, meta) => {
4594
4617
  // Don't use in production!
4595
4618
  // Used in: https://www.zigbee2mqtt.io/how_tos/how_to_support_new_tuya_devices.html
4596
- const getType = (datatype) => {
4597
- const entry = Object.entries(tuya.dataTypes).find(([typeName, typeId]) => typeId === datatype);
4598
- return (entry ? entry[0] : 'unknown');
4599
- };
4600
- const getAllDpIds = (dp) => {
4601
- const entries = Object.entries(tuya.dataPoints).filter(([dpName, dpId]) => dpId === dp);
4602
- return entries.map(([dpName, dpId]) => dpName);
4603
- };
4604
4619
  const getHex = (value) => {
4605
4620
  let hex = value.toString(16);
4606
4621
  if (hex.length < 2) {
@@ -4611,11 +4626,7 @@ const converters = {
4611
4626
  const now = Date.now().toString();
4612
4627
  let dataStr = '';
4613
4628
  for (const [i, dpValue] of msg.data.dpValues.entries()) {
4614
- const value = tuya.getDataValue(dpValue);
4615
- meta.logger.info(`zigbee-herdsman-converters:tuya_data_point_dump: Received DP #${
4616
- dpValue.dp} from ${meta.device.ieeeAddr} with raw data '${JSON.stringify(dpValue)}': type='${msg.type}', datatype='${
4617
- getType(dpValue.datatype)}', value='${value}', known DP# usage: ${JSON.stringify(getAllDpIds(dpValue.dp))}`);
4618
-
4629
+ tuya.logDataPoint('tuya_data_point_dump', msg, dpValue, meta);
4619
4630
  dataStr +=
4620
4631
  now + ' ' +
4621
4632
  meta.device.ieeeAddr + ' ' +
@@ -3516,7 +3516,7 @@ const converters = {
3516
3516
  },
3517
3517
  },
3518
3518
  tuya_dimmer_level: {
3519
- key: ['brightness_min', 'brightness', 'brightness_percent', 'level'],
3519
+ key: ['brightness_min', 'min_brightness', 'max_brightness', 'brightness', 'brightness_percent', 'level'],
3520
3520
  convertSet: async (entity, key, value, meta) => {
3521
3521
  // upscale to 1000
3522
3522
  let newValue;
@@ -3531,6 +3531,20 @@ const converters = {
3531
3531
  } else {
3532
3532
  throw new Error('Dimmer brightness_min is out of range 0..100');
3533
3533
  }
3534
+ } else if (key === 'min_brightness') {
3535
+ if (value >= 1 && value <= 255) {
3536
+ newValue = utils.mapNumberRange(value, 1, 255, 0, 1000);
3537
+ dp = tuya.dataPoints.dimmerMinLevel;
3538
+ } else {
3539
+ throw new Error('Dimmer min_brightness is out of range 1..255');
3540
+ }
3541
+ } else if (key === 'max_brightness') {
3542
+ if (value >= 1 && value <= 255) {
3543
+ newValue = utils.mapNumberRange(value, 1, 255, 0, 1000);
3544
+ dp = tuya.dataPoints.dimmerMaxLevel;
3545
+ } else {
3546
+ throw new Error('Dimmer min_brightness is out of range 1..255');
3547
+ }
3534
3548
  } else if (key === 'level') {
3535
3549
  if (value >= 0 && value <= 1000) {
3536
3550
  newValue = Math.round(Number(value));
@@ -3543,11 +3557,11 @@ const converters = {
3543
3557
  } else {
3544
3558
  throw new Error('Dimmer brightness_percent is out of range 0..100');
3545
3559
  }
3546
- } else {
3547
- if (value >= 0 && value <= 255) {
3548
- newValue = utils.mapNumberRange(value, 0, 255, 0, 1000);
3560
+ } else { // brightness
3561
+ if (value >= 0 && value <= 254) {
3562
+ newValue = utils.mapNumberRange(value, 0, 254, 0, 1000);
3549
3563
  } else {
3550
- throw new Error('Dimmer brightness is out of range 0..255');
3564
+ throw new Error('Dimmer brightness is out of range 0..254');
3551
3565
  }
3552
3566
  }
3553
3567
  // Always use same transid as tuya_dimmer_state (https://github.com/Koenkk/zigbee2mqtt/issues/6366)
package/devices/lidl.js CHANGED
@@ -507,6 +507,17 @@ module.exports = [
507
507
  device.getEndpoint(1).saveClusterAttributeKeyValue('lightingColorCtrl', {colorCapabilities: 29});
508
508
  },
509
509
  },
510
+ {
511
+ fingerprint: [{modelID: 'TS0505B', manufacturerName: '_TZ3210_z1vlyufu'}],
512
+ model: '14158704L',
513
+ vendor: 'Lidl',
514
+ description: 'Livarno Home LED floor lamp, RGBW',
515
+ ...extend.light_onoff_brightness_colortemp_color({disableColorTempStartup: true, colorTempRange: [153, 500]}),
516
+ meta: {applyRedFix: true, enhancedHue: false},
517
+ configure: async (device, coordinatorEndpoint, logger) => {
518
+ device.getEndpoint(1).saveClusterAttributeKeyValue('lightingColorCtrl', {colorCapabilities: 29});
519
+ },
520
+ },
510
521
  {
511
522
  fingerprint: [{modelID: 'TS0505B', manufacturerName: '_TZ3000_quqaeew6'}],
512
523
  model: 'HG07834A',
package/devices/tuya.js CHANGED
@@ -450,7 +450,9 @@ module.exports = [
450
450
  const endpoint = device.getEndpoint(1);
451
451
  await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'genLevelCtrl']);
452
452
  },
453
- exposes: [e.light_brightness().setAccess('state', ea.STATE_SET).setAccess('brightness', ea.STATE_SET)],
453
+ exposes: [e.light_brightness().withMinBrightness().withMaxBrightness().setAccess(
454
+ 'state', ea.STATE_SET).setAccess('brightness', ea.STATE_SET).setAccess(
455
+ 'min_brightness', ea.STATE_SET).setAccess('max_brightness', ea.STATE_SET)],
454
456
  whiteLabel: [
455
457
  {vendor: 'Larkkey', model: 'ZSTY-SM-1DMZG-EU'},
456
458
  {vendor: 'Earda', model: 'EDM-1ZAA-EU'},
@@ -703,10 +705,7 @@ module.exports = [
703
705
  extend: extend.light_onoff_brightness_colortemp_color(),
704
706
  },
705
707
  {
706
- fingerprint: [
707
- {type: 'EndDevice', manufacturerID: 4098, endpoints: [{ID: 1, inputClusters: [], outputClusters: []}]},
708
- {manufacturerName: '_TZ2000_a476raq2'},
709
- ],
708
+ fingerprint: [{manufacturerName: '_TZ2000_a476raq2'}],
710
709
  zigbeeModel: ['TS0201', 'SNTZ003'],
711
710
  model: 'TS0201',
712
711
  vendor: 'TuYa',
@@ -715,6 +714,10 @@ module.exports = [
715
714
  fromZigbee: [fzLocal.TS0201_battery, fz.temperature, fz.humidity],
716
715
  toZigbee: [],
717
716
  exposes: [e.battery(), e.temperature(), e.humidity(), e.battery_voltage()],
717
+ configure: async (device, coordinatorEndpoint, logger) => {
718
+ const endpoint = device.getEndpoint(1);
719
+ await endpoint.read('genBasic', ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
720
+ },
718
721
  },
719
722
  {
720
723
  fingerprint: [{modelID: 'TS0201', manufacturerName: '_TZ3000_bguser20'}],
@@ -2176,7 +2179,8 @@ module.exports = [
2176
2179
  exposes: [e.illuminance_lux(), e.brightness_state()],
2177
2180
  },
2178
2181
  {
2179
- fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_kltffuzl'}, {modelID: 'TS0601', manufacturerName: '_TZE200_fwoorn8y'}],
2182
+ fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_kltffuzl'}, {modelID: 'TS0601', manufacturerName: '_TZE200_fwoorn8y'},
2183
+ {modelID: 'TS0601', manufacturerName: '_TZE200_pay2byax'}],
2180
2184
  model: 'TM001-ZA/TM081',
2181
2185
  vendor: 'TuYa',
2182
2186
  description: 'Door and window sensor',
package/lib/exposes.js CHANGED
@@ -218,6 +218,12 @@ class Light extends Base {
218
218
  return this;
219
219
  }
220
220
 
221
+ withMaxBrightness() {
222
+ assert(!this.endpoint, 'Cannot add feature after adding endpoint');
223
+ this.features.push(new Numeric('max_brightness', access.ALL).withValueMin(1).withValueMax(255).withDescription('Maximum light brightness'));
224
+ return this;
225
+ }
226
+
221
227
  withLevelConfig() {
222
228
  assert(!this.endpoint, 'Cannot add feature after adding endpoint');
223
229
  const levelConfig = new Composite('level_config', 'level_config')
package/lib/tuya.js CHANGED
@@ -58,6 +58,61 @@ function getDataValue(dpValue) {
58
58
  }
59
59
  }
60
60
 
61
+ function getTypeName(dpValue) {
62
+ const entry = Object.entries(dataTypes).find(([typeName, typeId]) => typeId === dpValue.datatype);
63
+ return (entry ? entry[0] : 'unknown');
64
+ }
65
+
66
+ function getDataPointNames(dpValue) {
67
+ const entries = Object.entries(dataPoints).filter(([dpName, dpId]) => dpId === dpValue.dp);
68
+ return entries.map(([dpName, dpId]) => dpName);
69
+ }
70
+
71
+ function logDataPoint(where, msg, dpValue, meta) {
72
+ meta.logger.info(`zigbee-herdsman-converters:${where}: Received Tuya DataPoint #${
73
+ dpValue.dp} from ${meta.device.ieeeAddr} with raw data '${JSON.stringify(dpValue)}': type='${
74
+ msg.type}', datatype='${getTypeName(dpValue)}', value='${
75
+ getDataValue(dpValue)}', known DP# usage: ${JSON.stringify(getDataPointNames(dpValue))}`);
76
+ }
77
+
78
+ function logUnexpectedDataPoint(where, msg, dpValue, meta) {
79
+ meta.logger.warn(`zigbee-herdsman-converters:${where}: Received unexpected Tuya DataPoint #${
80
+ dpValue.dp} from ${meta.device.ieeeAddr} with raw data '${JSON.stringify(dpValue)}': type='${
81
+ msg.type}', datatype='${getTypeName(dpValue)}', value='${
82
+ getDataValue(dpValue)}', known DP# usage: ${JSON.stringify(getDataPointNames(dpValue))}`);
83
+ }
84
+
85
+ function logUnexpectedDataType(where, msg, dpValue, meta, expectedDataType) {
86
+ meta.logger.warn(`zigbee-herdsman-converters:${where}: Received Tuya DataPoint #${
87
+ dpValue.dp} with unexpected datatype from ${meta.device.ieeeAddr} with raw data '${
88
+ JSON.stringify(dpValue)}': type='${msg.type}', datatype='${
89
+ getTypeName(dpValue)}' (instead of '${expectedDataType}'), value='${
90
+ getDataValue(dpValue)}', known DP# usage: ${JSON.stringify(getDataPointNames(dpValue))}`);
91
+ }
92
+
93
+ function logUnexpectedDataValue(where, msg, dpValue, meta, valueKind, expectedMinValue=null, expectedMaxValue=null) {
94
+ if (expectedMinValue === null) {
95
+ if (expectedMaxValue === null) {
96
+ meta.logger.warn(`zigbee-herdsman-converters:${where}: Received Tuya DataPoint #${dpValue.dp
97
+ } with invalid value ${getDataValue(dpValue)} for ${valueKind} from ${meta.device.ieeeAddr}`);
98
+ } else {
99
+ meta.logger.warn(`zigbee-herdsman-converters:${where}: Received Tuya DataPoint #${dpValue.dp
100
+ } with invalid value ${getDataValue(dpValue)} for ${valueKind} from ${meta.device.ieeeAddr
101
+ } which is higher than the expected maximum of ${expectedMaxValue}`);
102
+ }
103
+ } else {
104
+ if (expectedMaxValue === null) {
105
+ meta.logger.warn(`zigbee-herdsman-converters:${where}: Received Tuya DataPoint #${dpValue.dp
106
+ } with invalid value ${getDataValue(dpValue)} for ${valueKind} from ${meta.device.ieeeAddr
107
+ } which is lower than the expected minimum of ${expectedMinValue}`);
108
+ } else {
109
+ meta.logger.warn(`zigbee-herdsman-converters:${where}: Received Tuya DataPoint #${dpValue.dp
110
+ } with invalid value ${getDataValue(dpValue)} for ${valueKind} from ${meta.device.ieeeAddr
111
+ } which is outside the expected range from ${expectedMinValue} to ${expectedMaxValue}`);
112
+ }
113
+ }
114
+ }
115
+
61
116
  function convertDecimalValueTo4ByteHexArray(value) {
62
117
  const hexValue = Number(value).toString(16).padStart(8, '0');
63
118
  const chunk1 = hexValue.substr(0, 2);
@@ -229,11 +284,13 @@ const dataPoints = {
229
284
  heatingSetpoint: 2,
230
285
  coverPosition: 2,
231
286
  dimmerLevel: 3,
287
+ dimmerMinLevel: 3,
232
288
  localTemp: 3,
233
289
  coverArrived: 3,
234
290
  occupancy: 3,
235
291
  mode: 4,
236
292
  fanMode: 5,
293
+ dimmerMaxLevel: 5,
237
294
  motorDirection: 5,
238
295
  config: 5,
239
296
  childLock: 7,
@@ -873,6 +930,12 @@ module.exports = {
873
930
  sendDataPointStringBuffer,
874
931
  firstDpValue,
875
932
  getDataValue,
933
+ getTypeName,
934
+ getDataPointNames,
935
+ logDataPoint,
936
+ logUnexpectedDataPoint,
937
+ logUnexpectedDataType,
938
+ logUnexpectedDataValue,
876
939
  dataTypes,
877
940
  dataPoints,
878
941
  dpValueFromIntValue,
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "zigbee-herdsman-converters",
3
- "version": "14.0.465",
3
+ "version": "14.0.466",
4
4
  "lockfileVersion": 2,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "zigbee-herdsman-converters",
9
- "version": "14.0.465",
9
+ "version": "14.0.466",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "axios": "^0.26.1",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zigbee-herdsman-converters",
3
- "version": "14.0.465",
3
+ "version": "14.0.466",
4
4
  "description": "Collection of device converters to be used with zigbee-herdsman",
5
5
  "main": "index.js",
6
6
  "files": [