zigbee-herdsman-converters 14.0.407 → 14.0.411

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.
@@ -616,6 +616,25 @@ const converters = {
616
616
  return result;
617
617
  },
618
618
  },
619
+ meter_identification: {
620
+ cluster: 'haMeterIdentification',
621
+ type: ['readResponse'],
622
+ convert: (model, msg, publish, options, meta) => {
623
+ const result = {};
624
+ const elements = [
625
+ /* 0x000A*/ 'softwareRevision',
626
+ /* 0x000D*/ 'availablePower',
627
+ /* 0x000E*/ 'powerThreshold',
628
+ ];
629
+ for (const at of elements) {
630
+ const atSnake = at.split(/(?=[A-Z])/).join('_').toLowerCase();
631
+ if (msg.data[at]) {
632
+ result[atSnake] = msg.data[at];
633
+ }
634
+ }
635
+ return result;
636
+ },
637
+ },
619
638
  metering: {
620
639
  /**
621
640
  * When using this converter also add the following to the configure method of the device:
@@ -2395,6 +2414,26 @@ const converters = {
2395
2414
  }
2396
2415
  },
2397
2416
  },
2417
+ moes_switch: {
2418
+ cluster: 'manuSpecificTuya',
2419
+ type: ['commandDataResponse', 'commandDataReport'],
2420
+ convert: (model, msg, publish, options, meta) => {
2421
+ const dpValue = tuya.firstDpValue(msg, meta, 'moes_switch');
2422
+ const dp = dpValue.dp;
2423
+ const value = tuya.getDataValue(dpValue);
2424
+
2425
+ switch (dp) {
2426
+ case tuya.dataPoints.moesSwitchPowerOnBehavior:
2427
+ return {power_on_behavior: tuya.moesSwitch.powerOnBehavior[value]};
2428
+ case tuya.dataPoints.moesSwitchIndicateLight:
2429
+ return {indicate_light: tuya.moesSwitch.indicateLight[value]};
2430
+ default:
2431
+ meta.logger.warn(`fromZigbee:moes_switch: NOT RECOGNIZED DP #${
2432
+ dp} with data ${JSON.stringify(dpValue)}`);
2433
+ break;
2434
+ }
2435
+ },
2436
+ },
2398
2437
  eurotronic_thermostat: {
2399
2438
  cluster: 'hvacThermostat',
2400
2439
  type: ['attributeReport', 'readResponse'],
@@ -5168,8 +5207,16 @@ const converters = {
5168
5207
  aqara_opple: {
5169
5208
  cluster: 'aqaraOpple',
5170
5209
  type: ['attributeReport', 'readResponse'],
5171
- options: [exposes.options.precision('temperature'), exposes.options.calibration('temperature'),
5172
- exposes.options.precision('illuminance'), exposes.options.calibration('illuminance', 'percentual')],
5210
+ options: (definition) => {
5211
+ const result = [];
5212
+ if (definition.exposes.find((e) => e.name === 'temperature')) {
5213
+ result.push(exposes.options.precision('temperature'), exposes.options.calibration('temperature'));
5214
+ }
5215
+ if (definition.exposes.find((e) => e.name === 'illuminance')) {
5216
+ result.push(exposes.options.precision('illuminance'), exposes.options.calibration('illuminance', 'percentual'));
5217
+ }
5218
+ return result;
5219
+ },
5173
5220
  convert: (model, msg, publish, options, meta) => {
5174
5221
  const payload = {};
5175
5222
  if (msg.data.hasOwnProperty('247')) {
@@ -5315,8 +5362,9 @@ const converters = {
5315
5362
  payload.presence_event = {0: 'enter', 1: 'leave', 2: 'left_enter', 3: 'right_leave', 4: 'right_enter',
5316
5363
  5: 'left_leave', 6: 'approach', 7: 'away', 255: null}[value];
5317
5364
  }
5318
- } else if (index ===103) payload.monitoring_mode = value === 1 ? 'left_right' : 'undirected'; // RTCZCGQ11LM
5319
- else if (index === 105) {
5365
+ } else if (index === 103) {
5366
+ if (['RTCZCGQ11LM'].includes(model.model)) payload.monitoring_mode = value === 1 ? 'left_right' : 'undirected';
5367
+ } else if (index === 105) {
5320
5368
  if (['RTCGQ13LM'].includes(model.model)) {
5321
5369
  payload.motion_sensitivity = {1: 'low', 2: 'medium', 3: 'high'}[value];
5322
5370
  } else if (['RTCZCGQ11LM'].includes(model.model)) {
@@ -2417,12 +2417,6 @@ const converters = {
2417
2417
  await entity.read('genAnalogOutput', [0x0055]);
2418
2418
  },
2419
2419
  },
2420
- xiaomi_curtain_acn002_status: {
2421
- key: ['motor_state'],
2422
- convertGet: async (entity, key, meta) => {
2423
- await entity.read('genMultistateOutput', [0x0055]);
2424
- },
2425
- },
2426
2420
  ledvance_commands: {
2427
2421
  /* deprectated osram_*/
2428
2422
  key: ['set_transition', 'remember_state', 'osram_set_transition', 'osram_remember_state'],
@@ -3212,6 +3206,30 @@ const converters = {
3212
3206
  await entity.read('genOnOff', ['moesStartUpOnOff']);
3213
3207
  },
3214
3208
  },
3209
+ moes_switch: {
3210
+ key: ['power_on_behavior', 'indicate_light'],
3211
+ convertSet: async (entity, key, value, meta) => {
3212
+ switch (key) {
3213
+ case 'power_on_behavior':
3214
+ await tuya.sendDataPointEnum(
3215
+ entity,
3216
+ tuya.dataPoints.moesSwitchPowerOnBehavior,
3217
+ utils.getKey(tuya.moesSwitch.powerOnBehavior, value),
3218
+ );
3219
+ break;
3220
+ case 'indicate_light':
3221
+ await tuya.sendDataPointValue(
3222
+ entity,
3223
+ tuya.dataPoints.moesSwitchIndicateLight,
3224
+ utils.getKey(tuya.moesSwitch.indicateLight, value),
3225
+ );
3226
+ break;
3227
+ default:
3228
+ meta.logger.warn(`toZigbee.moes_switch: Unhandled Key ${key}`);
3229
+ break;
3230
+ }
3231
+ },
3232
+ },
3215
3233
  moes_thermostat_sensor: {
3216
3234
  key: ['sensor'],
3217
3235
  convertSet: async (entity, key, value, meta) => {
@@ -62,6 +62,12 @@ const gledoptoExtend = {
62
62
  }),
63
63
  };
64
64
 
65
+ const configureReadModelID = async (device) => {
66
+ // https://github.com/Koenkk/zigbee-herdsman-converters/issues/3016#issuecomment-1027726604
67
+ const endpoint = device.endpoints[0];
68
+ await endpoint.read('genBasic', ['modelId']);
69
+ };
70
+
65
71
  module.exports = [
66
72
  {
67
73
  fingerprint: [
@@ -116,7 +122,11 @@ module.exports = [
116
122
  vendor: 'Gledopto',
117
123
  ota: ota.zigbeeOTA,
118
124
  description: 'Zigbee LED Controller WW/CW (pro)',
119
- extend: gledoptoExtend.light_onoff_brightness_colortemp(),
125
+ extend: gledoptoExtend.light_onoff_brightness_colortemp({noConfigure: true}),
126
+ configure: async (device, coordinatorEndpoint, logger) => {
127
+ await extend.light_onoff_brightness_colortemp().configure(device, coordinatorEndpoint, logger);
128
+ await configureReadModelID(device);
129
+ },
120
130
  },
121
131
  {
122
132
  fingerprint: [
@@ -179,7 +189,11 @@ module.exports = [
179
189
  vendor: 'Gledopto',
180
190
  ota: ota.zigbeeOTA,
181
191
  description: 'Zigbee LED Controller RGBW (pro)',
182
- extend: gledoptoExtend.light_onoff_brightness_colortemp_color(),
192
+ extend: gledoptoExtend.light_onoff_brightness_colortemp_color({noConfigure: true}),
193
+ configure: async (device, coordinatorEndpoint, logger) => {
194
+ await extend.light_onoff_brightness_colortemp_color().configure(device, coordinatorEndpoint, logger);
195
+ await configureReadModelID(device);
196
+ },
183
197
  },
184
198
  {
185
199
  fingerprint: [
@@ -237,7 +251,11 @@ module.exports = [
237
251
  vendor: 'Gledopto',
238
252
  ota: ota.zigbeeOTA,
239
253
  description: 'Zigbee LED Controller RGB (pro)',
240
- extend: gledoptoExtend.light_onoff_brightness_color(),
254
+ extend: gledoptoExtend.light_onoff_brightness_color({noConfigure: true}),
255
+ configure: async (device, coordinatorEndpoint, logger) => {
256
+ await extend.light_onoff_brightness_color().configure(device, coordinatorEndpoint, logger);
257
+ await configureReadModelID(device);
258
+ },
241
259
  },
242
260
  {
243
261
  zigbeeModel: ['GL-C-008P'],
@@ -245,8 +263,12 @@ module.exports = [
245
263
  vendor: 'Gledopto',
246
264
  ota: ota.zigbeeOTA,
247
265
  description: 'Zigbee LED Controller RGB+CCT (pro)',
248
- extend: gledoptoExtend.light_onoff_brightness_colortemp_color({colorTempRange: [158, 495]}),
266
+ extend: gledoptoExtend.light_onoff_brightness_colortemp_color({colorTempRange: [158, 495], noConfigure: true}),
249
267
  meta: {disableDefaultResponse: true},
268
+ configure: async (device, coordinatorEndpoint, logger) => {
269
+ await extend.light_onoff_brightness_colortemp_color().configure(device, coordinatorEndpoint, logger);
270
+ await configureReadModelID(device);
271
+ },
250
272
  },
251
273
  {
252
274
  zigbeeModel: ['GL-C-009'],
@@ -267,7 +289,11 @@ module.exports = [
267
289
  vendor: 'Gledopto',
268
290
  ota: ota.zigbeeOTA,
269
291
  description: 'Zigbee LED Controller W (pro)',
270
- extend: gledoptoExtend.light_onoff_brightness(),
292
+ extend: gledoptoExtend.light_onoff_brightness({noConfigure: true}),
293
+ configure: async (device, coordinatorEndpoint, logger) => {
294
+ await extend.light_onoff_brightness().configure(device, coordinatorEndpoint, logger);
295
+ await configureReadModelID(device);
296
+ },
271
297
  },
272
298
  {
273
299
  zigbeeModel: ['GL-C-009S'],
@@ -0,0 +1,574 @@
1
+ /* eslint-disable camelcase */
2
+ /* eslint-disable max-len */
3
+ 'use strict';
4
+ const exposes = require('../lib/exposes');
5
+ const globalStore = require('../lib/store');
6
+ const {repInterval} = require('../lib/constants');
7
+ const reporting = require('../lib/reporting');
8
+ const fz = require('../converters/fromZigbee');
9
+ const ea = exposes.access;
10
+ const e = exposes.presets;
11
+ const utils = require('../lib/utils');
12
+ const ota = require('../lib/ota');
13
+ const {Buffer} = require('buffer');
14
+
15
+ const fzLocal = {
16
+ lixee_ha_electrical_measurement: {
17
+ cluster: 'haElectricalMeasurement',
18
+ type: ['attributeReport', 'readResponse'],
19
+ convert: (model, msg, publish, options, meta) => {
20
+ const result = {};
21
+
22
+ const elements = [
23
+ /* 0x0305 */ 'totalReactivePower',
24
+ /* 0x0505 */ 'rmsVoltage',
25
+ /* 0x0508 */ 'rmsCurrent',
26
+ /* 0x050A */ 'rmsCurrentMax',
27
+ /* 0x050B */ 'activePower',
28
+ /* 0x050D */ 'activePowerMax',
29
+ /* 0x050E */ 'reactivePower',
30
+ /* 0x050F */ 'apparentPower',
31
+ /* 0x0511 */ 'averageRmsVoltageMeasPeriod',
32
+ /* 0x0905 */ 'rmsVoltagePhB',
33
+ /* 0x0908 */ 'rmsCurrentPhB',
34
+ /* 0x090A */ 'rmsCurrentMaxPhB',
35
+ /* 0x090B */ 'activePowerPhB',
36
+ /* 0x090E */ 'reactivePowerPhB',
37
+ /* 0x090D */ 'activePowerMaxPhB',
38
+ /* 0x090F */ 'apparentPowerPhB',
39
+ /* 0x0911 */ 'averageRmsVoltageMeasurePeriodPhB',
40
+ /* 0x0A05 */ 'rmsVoltagePhC',
41
+ /* 0x0A08 */ 'rmsCurrentPhC',
42
+ /* 0x0A0A */ 'rmsCurrentMaxPhC',
43
+ /* 0x0A0D */ 'activePowerMaxPhC',
44
+ /* 0x0A0E */ 'reactivePowerPhC',
45
+ /* 0x0A0F */ 'apparentPowerPhC',
46
+ /* 0x0A11 */ 'averageRmsVoltageMeasPeriodPhC',
47
+ ];
48
+
49
+ for (const at of elements) {
50
+ const at_snake = at.split(/(?=[A-Z])/).join('_').toLowerCase();
51
+ if (msg.data[at]) {
52
+ result[at_snake] = msg.data[at];
53
+ }
54
+ }
55
+ return result;
56
+ },
57
+ },
58
+ lixee_private_fz: {
59
+ cluster: 'liXeePrivate', // 0xFF66
60
+ type: ['attributeReport', 'readResponse'],
61
+ convert: (model, msg, publish, options, meta) => {
62
+ const result = {};
63
+ const elements = [
64
+ /* 0x0000 */ 'currentTarif',
65
+ /* 0x0001 */ 'tomorrowColor',
66
+ /* 0x0002 */ 'scheduleHPHC',
67
+ /* 0x0003 */ 'presencePotential',
68
+ /* 0x0004 */ 'startNoticeEJP',
69
+ /* 0x0005 */ 'warnDPS',
70
+ /* 0x0006 */ 'warnDIR1',
71
+ /* 0x0007 */ 'warnDIR2',
72
+ /* 0x0008 */ 'warnDIR3',
73
+ /* 0x0200 */ 'currentPrice',
74
+ /* 0x0201 */ 'currentIndexTarif',
75
+ /* 0x0202 */ 'currentDate',
76
+ /* 0x0203 */ 'activeEnerfyOutD01',
77
+ /* 0x0204 */ 'activeEnerfyOutD02',
78
+ /* 0x0205 */ 'activeEnerfyOutD03',
79
+ /* 0x0206 */ 'activeEnerfyOutD04',
80
+ /* 0x0207 */ 'injectedVA',
81
+ /* 0x0208 */ 'injectedVAMaxN',
82
+ /* 0x0209 */ 'injectedVAMaxN1',
83
+ /* 0x0210 */ 'injectedActiveLoadN',
84
+ /* 0x0211 */ 'injectedActiveLoadN1',
85
+ /* 0x0212 */ 'drawnVAMaxN1',
86
+ /* 0x0213 */ 'drawnVAMaxN1P2',
87
+ /* 0x0214 */ 'drawnVAMaxN1P3',
88
+ /* 0x0215 */ 'message1',
89
+ /* 0x0216 */ 'message2',
90
+ /* 0x0217 */ 'statusRegister',
91
+ /* 0x0218 */ 'startMobilePoint1',
92
+ /* 0x0219 */ 'stopMobilePoint1',
93
+ /* 0x0220 */ 'startMobilePoint2',
94
+ /* 0x0221 */ 'stopMobilePoint2',
95
+ /* 0x0222 */ 'startMobilePoint3',
96
+ /* 0x0223 */ 'stopMobilePoint3',
97
+ /* 0x0224 */ 'relais',
98
+ /* 0x0225 */ 'daysNumberCurrentCalendar',
99
+ /* 0x0226 */ 'daysNumberNextCalendar',
100
+ /* 0x0227 */ 'daysProfileCurrentCalendar',
101
+ /* 0x0228 */ 'daysProfileNextCalendar',
102
+ ];
103
+ const kWh_p = options && options.kWh_precision ? options.kWh_precision : 0;
104
+ for (const at of elements) {
105
+ const at_snake = at.split(/(?=[A-Z])/).join('_').toLowerCase();
106
+ let val = msg.data[at];
107
+ if (val) {
108
+ if (val.hasOwnProperty('type') && val.type === 'Buffer') {
109
+ val = Buffer.from(val.data);
110
+ }
111
+ if (Buffer.isBuffer(val)) {
112
+ val = val.toString(); // Convert buffer to string
113
+ }
114
+ if (typeof val === 'string' || val instanceof String) {
115
+ val = val.replace(/\0/g, ''); // Remove all null chars when str
116
+ val = val.replace(/\s+/g, ' ').trim(); // Remove extra and leading spaces
117
+ }
118
+ switch (at) {
119
+ case 'activeEnerfyOutD01':
120
+ case 'activeEnerfyOutD02':
121
+ case 'activeEnerfyOutD03':
122
+ case 'activeEnerfyOutD04':
123
+ val = utils.precisionRound(val / 1000, kWh_p); // from Wh to kWh
124
+ break;
125
+ }
126
+ result[at_snake] = val;
127
+ }
128
+ }
129
+ return result;
130
+ },
131
+ },
132
+ lixee_metering: {
133
+ cluster: 'seMetering', // 0x0702
134
+ type: ['attributeReport', 'readResponse'],
135
+ convert: (model, msg, publish, options, meta) => {
136
+ const result = {};
137
+ const elements = [
138
+ /* 0x0000 */ 'currentSummDelivered',
139
+ /* 0x0001 */ 'currentSummReceived',
140
+ /* 0x0020 */ 'activeRegisterTierDelivered',
141
+ /* 0x0100 */ 'currentTier1SummDelivered',
142
+ /* 0x0102 */ 'currentTier2SummDelivered',
143
+ /* 0x0104 */ 'currentTier3SummDelivered',
144
+ /* 0x0106 */ 'currentTier4SummDelivered',
145
+ /* 0x0108 */ 'currentTier5SummDelivered',
146
+ /* 0x010A */ 'currentTier6SummDelivered',
147
+ /* 0x010C */ 'currentTier7SummDelivered',
148
+ /* 0x010E */ 'currentTier8SummDelivered',
149
+ /* 0x0110 */ 'currentTier9SummDelivered',
150
+ /* 0x0112 */ 'currentTier10SummDelivered',
151
+ /* 0x0307 */ 'siteId',
152
+ /* 0x0308 */ 'meterSerialNumber',
153
+ ];
154
+ const kWh_p = options && options.kWh_precision ? options.kWh_precision : 0;
155
+ for (const at of elements) {
156
+ const at_snake = at.split(/(?=[A-Z])/).join('_').toLowerCase();
157
+ const val = msg.data[at];
158
+ if (val) {
159
+ result[at_snake] = val; // By default we assign raw value
160
+ switch (at) {
161
+ // If we receive a Buffer, transform to human readable text
162
+ case 'meterSerialNumber':
163
+ case 'siteId':
164
+ if (Buffer.isBuffer(val)) {
165
+ result[at_snake] = val.toString();
166
+ }
167
+ break;
168
+ case 'currentSummDelivered':
169
+ case 'currentSummReceived':
170
+ case 'currentTier1SummDelivered':
171
+ case 'currentTier2SummDelivered':
172
+ case 'currentTier3SummDelivered':
173
+ case 'currentTier4SummDelivered':
174
+ case 'currentTier5SummDelivered':
175
+ case 'currentTier6SummDelivered':
176
+ case 'currentTier7SummDelivered':
177
+ case 'currentTier8SummDelivered':
178
+ case 'currentTier9SummDelivered':
179
+ case 'currentTier10SummDelivered':
180
+ result[at_snake] = utils.precisionRound(((val[0] << 32) + val[1]) / 1000, kWh_p); // Wh to kWh
181
+ break;
182
+ }
183
+ }
184
+ }
185
+ // TODO: Check if all tarifs which doesn't publish "currentSummDelivered" use just Tier1 & Tier2
186
+ if (result['current_summ_delivered'] == 0 &&
187
+ (result['current_tier1_summ_delivered'] > 0 || result['current_tier2_summ_delivered'] > 0)) {
188
+ result['current_summ_delivered'] = result['current_tier1_summ_delivered'] + result['current_tier2_summ_delivered'];
189
+ }
190
+ return result;
191
+ },
192
+ },
193
+ };
194
+
195
+ const tarifsDef = {
196
+ histo_BASE: {fname: 'Historique - BASE',
197
+ currentTarf: 'BASE', excluded: [
198
+ 'HCHC',
199
+ 'HCHP',
200
+ 'HHPHC',
201
+ 'EJPHN',
202
+ 'EJPHPM',
203
+ 'BBRHCJB',
204
+ 'BBRHPJB',
205
+ 'BBRHCJW',
206
+ 'BBRHPJW',
207
+ 'BBRHCJR',
208
+ 'BBRHPJR',
209
+ 'DEMAIN',
210
+ 'PEJP',
211
+ ]},
212
+ histo_HCHP: {fname: 'Historique - HCHP',
213
+ currentTarf: 'HC..', excluded: [
214
+ 'BASE',
215
+ 'EJPHN',
216
+ 'EJPHPM',
217
+ 'BBRHCJB',
218
+ 'BBRHPJB',
219
+ 'BBRHCJW',
220
+ 'BBRHPJW',
221
+ 'BBRHCJR',
222
+ 'BBRHPJR',
223
+ 'DEMAIN',
224
+ 'PEJP',
225
+ ]},
226
+ histo_EJP: {fname: 'Historique - EJP',
227
+ currentTarf: 'EJP.', excluded: [
228
+ 'BASE',
229
+ 'HCHC',
230
+ 'HCHP',
231
+ 'BBRHCJB',
232
+ 'BBRHPJB',
233
+ 'BBRHCJW',
234
+ 'BBRHPJW',
235
+ 'BBRHCJR',
236
+ 'BBRHPJR',
237
+ 'DEMAIN',
238
+ ]},
239
+ histo_BBR: {fname: 'Historique - BBR',
240
+ currentTarf: 'BBR', excluded: [
241
+ 'BASE',
242
+ 'HCHC',
243
+ 'HCHP',
244
+ 'EJPHN',
245
+ 'EJPHPM',
246
+ 'PEJP',
247
+ ]},
248
+ stand_SEM_WE_MERCR: {fname: 'Standard - Sem WE Mercredi',
249
+ currentTarf: 'SEM WE MERCREDI', excluded: [
250
+ 'EASF04',
251
+ 'EASF05',
252
+ 'EASF06',
253
+ 'EASF07',
254
+ 'EASF08',
255
+ 'EASF09',
256
+ 'EASF10',
257
+ 'EASD02',
258
+ 'EASD03',
259
+ 'EASD04',
260
+ 'DPM1',
261
+ 'DPM2',
262
+ 'DPM3',
263
+ 'FPM1',
264
+ 'FPM2',
265
+ 'FPM3',
266
+ 'NJOURF',
267
+ 'NJOURF+1',
268
+ 'PJOURF+1',
269
+ 'PPOINTE1',
270
+ ]},
271
+ };
272
+
273
+ const linkyModeDef = {
274
+ standard: 'standard',
275
+ legacy: 'historique',
276
+ };
277
+
278
+ const linkyPhaseDef = {
279
+ single: 'single_phase',
280
+ three: 'three_phase',
281
+ all: 'both',
282
+ };
283
+
284
+ const clustersDef = {
285
+ _0xFF66: 'liXeePrivate', // 0xFF66
286
+ _0x0B04: 'haElectricalMeasurement', // 0x0B04
287
+ _0x0702: 'seMetering', // 0x0702
288
+ _0x0B01: 'haMeterIdentification', // 0x0B01
289
+ };
290
+
291
+
292
+ // full list available on https://github.com/fairecasoimeme/Zlinky_TIC/blob/master/README.md
293
+
294
+ // Properties must be EAXCTLY ".split(/(?=[A-Z])/).join('_').toLowerCase()" of att
295
+ const exposedData = [
296
+ // Historique
297
+ {cluster: clustersDef._0x0702, att: 'meterSerialNumber', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.legacy, exposes: exposes.text('ADCO', ea.STATE).withProperty('meter_serial_number').withDescription('Serial Number')},
298
+ {cluster: clustersDef._0x0702, att: 'currentSummDelivered', reportable: true, reportChange: 100, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('BASE', ea.STATE).withUnit('kWh').withProperty('current_summ_delivered').withDescription('Base index')},
299
+ {cluster: clustersDef._0xFF66, att: 'currentTarif', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.legacy, exposes: exposes.text('OPTARIF', ea.STATE).withProperty('current_tarif').withDescription('Tarif option')},
300
+ {cluster: clustersDef._0x0B01, att: 'availablePower', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('ISOUSC', ea.STATE).withUnit('A').withProperty('available_power').withDescription('Subscribed intensity level')},
301
+ {cluster: clustersDef._0x0702, att: 'currentTier1SummDelivered', reportable: false, reportChange: 100, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('HCHC', ea.STATE).withUnit('kWh').withProperty('current_tier1_summ_delivered').withDescription('HCHC index')},
302
+ {cluster: clustersDef._0x0702, att: 'currentTier2SummDelivered', reportable: false, reportChange: 100, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('HCHP', ea.STATE).withUnit('kWh').withProperty('current_tier2_summ_delivered').withDescription('HCHP index')},
303
+ {cluster: clustersDef._0x0702, att: 'currentTier1SummDelivered', reportable: false, reportChange: 100, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('EJPHN', ea.STATE).withUnit('kWh').withProperty('current_tier1_summ_delivered').withDescription('EJPHN index')},
304
+ {cluster: clustersDef._0x0702, att: 'currentTier2SummDelivered', reportable: false, reportChange: 100, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('EJPHPM', ea.STATE).withUnit('kWh').withProperty('current_tier2_summ_delivered').withDescription('EJPHPM index')},
305
+ {cluster: clustersDef._0x0702, att: 'currentTier1SummDelivered', reportable: false, reportChange: 100, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('BBRHCJB', ea.STATE).withUnit('kWh').withProperty('current_tier1_summ_delivered').withDescription('BBRHCJB index')},
306
+ {cluster: clustersDef._0x0702, att: 'currentTier2SummDelivered', reportable: false, reportChange: 100, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('BBRHPJB', ea.STATE).withUnit('kWh').withProperty('current_tier2_summ_delivered').withDescription('BBRHPJB index')},
307
+ {cluster: clustersDef._0x0702, att: 'currentTier3SummDelivered', reportable: false, reportChange: 100, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('BBRHCJW', ea.STATE).withUnit('kWh').withProperty('current_tier3_summ_delivered').withDescription('BBRHCJW index')},
308
+ {cluster: clustersDef._0x0702, att: 'currentTier4SummDelivered', reportable: false, reportChange: 100, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('BBRHPJW', ea.STATE).withUnit('kWh').withProperty('current_tier4_summ_delivered').withDescription('BBRHPJW index')},
309
+ {cluster: clustersDef._0x0702, att: 'currentTier5SummDelivered', reportable: false, reportChange: 100, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('BBRHCJR', ea.STATE).withUnit('kWh').withProperty('current_tier5_summ_delivered').withDescription('BBRHCJR index')},
310
+ {cluster: clustersDef._0x0702, att: 'currentTier6SummDelivered', reportable: false, reportChange: 100, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('BBRHPJR', ea.STATE).withUnit('kWh').withProperty('current_tier6_summ_delivered').withDescription('BBRHPJR index')},
311
+ {cluster: clustersDef._0x0B04, att: 'rmsCurrent', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('IINST', ea.STATE).withUnit('A').withProperty('rms_current').withDescription('RMS current')},
312
+ {cluster: clustersDef._0x0B04, att: 'rmsCurrent', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('IINST1', ea.STATE).withUnit('A').withProperty('rms_current').withDescription('RMS current (phase 1)')},
313
+ {cluster: clustersDef._0x0B04, att: 'rmsCurrentPhB', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('IINST2', ea.STATE).withUnit('A').withProperty('rms_current_ph_b').withDescription('RMS current (phase 2)')},
314
+ {cluster: clustersDef._0x0B04, att: 'rmsCurrentPhC', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('IINST3', ea.STATE).withUnit('A').withProperty('rms_current_ph_c').withDescription('RMS current (phase 3)')},
315
+ {cluster: clustersDef._0x0B04, att: 'rmsCurrentMax', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('IMAX', ea.STATE).withUnit('A').withProperty('rms_current_max').withDescription('RMS current peak')},
316
+ {cluster: clustersDef._0x0B04, att: 'rmsCurrentMax', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('IMAX1', ea.STATE).withUnit('A').withProperty('rms_current_max').withDescription('RMS current peak (phase 1)')},
317
+ {cluster: clustersDef._0x0B04, att: 'rmsCurrentMaxPhB', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('IMAX2', ea.STATE).withUnit('A').withProperty('rms_current_max_ph_b').withDescription('RMS current peak (phase 2)')},
318
+ {cluster: clustersDef._0x0B04, att: 'rmsCurrentMaxPhC', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('IMAX3', ea.STATE).withUnit('A').withProperty('rms_current_max_ph_c').withDescription('RMS current peak (phase 3)')},
319
+ {cluster: clustersDef._0x0B04, att: 'activePowerMax', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('PMAX', ea.STATE).withUnit('W').withProperty('active_power_max').withDescription('Three-phase power peak')},
320
+ {cluster: clustersDef._0x0B04, att: 'apparentPower', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('PAPP', ea.STATE).withUnit('VA').withProperty('apparent_power').withDescription('Apparent power')},
321
+ {cluster: clustersDef._0x0702, att: 'activeRegisterTierDelivered', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.legacy, exposes: exposes.text('PTEC', ea.STATE).withProperty('active_register_tier_delivered').withDescription('Current pricing period')},
322
+ {cluster: clustersDef._0xFF66, att: 'tomorrowColor', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.legacy, exposes: exposes.text('DEMAIN', ea.STATE).withProperty('tomorrow_color').withDescription('Tomorrow color')},
323
+ {cluster: clustersDef._0xFF66, att: 'scheduleHPHC', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('HHPHC', ea.STATE).withProperty('schedule_h_p_h_c').withDescription('Schedule HPHC')},
324
+ {cluster: clustersDef._0xFF66, att: 'presencePotential', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('PPOT', ea.STATE).withProperty('presence_potential').withDescription('Presence of potentials')},
325
+ {cluster: clustersDef._0xFF66, att: 'startNoticeEJP', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('PEJP', ea.STATE).withUnit('min').withProperty('start_notice_e_j_p').withDescription('EJP start notice (30min)')},
326
+ {cluster: clustersDef._0xFF66, att: 'warnDPS', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('ADPS', ea.STATE).withUnit('A').withProperty('warn_d_p_s').withDescription('Subscribed Power Exceeded Warning')},
327
+ {cluster: clustersDef._0xFF66, att: 'warnDIR1', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('ADIR1', ea.STATE).withUnit('A').withProperty('warn_d_i_r1').withDescription('Over Current Warning (phase 1)')},
328
+ {cluster: clustersDef._0xFF66, att: 'warnDIR2', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('ADIR2', ea.STATE).withUnit('A').withProperty('warn_d_i_r2').withDescription('Over Current Warning (phase 2)')},
329
+ {cluster: clustersDef._0xFF66, att: 'warnDIR3', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('ADIR3', ea.STATE).withUnit('A').withProperty('warn_d_i_r3').withDescription('Over Current Warning (phase 3)')},
330
+ {cluster: clustersDef._0x0702, att: 'meterSerialNumber', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.text('ADSC', ea.STATE).withProperty('meter_serial_number').withDescription('Serial Number')},
331
+ {cluster: clustersDef._0xFF66, att: 'currentTarif', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.text('NGTF', ea.STATE).withProperty('current_tarif').withDescription('Supplier pricing schedule name')},
332
+ {cluster: clustersDef._0xFF66, att: 'currentPrice', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.text('LTARF', ea.STATE).withProperty('current_price').withDescription('Current supplier price label')},
333
+ {cluster: clustersDef._0xFF66, att: 'currentIndexTarif', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('NTARF', ea.STATE).withProperty('current_index_tarif').withDescription('Current tariff index number')},
334
+ {cluster: clustersDef._0x0B01, att: 'softwareRevision', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('VTIC', ea.STATE).withProperty('software_revision').withDescription('Customer tele-information protocol version')},
335
+ {cluster: clustersDef._0xFF66, att: 'currentDate', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.text('DATE', ea.STATE).withProperty('current_date').withDescription('Current date and time')},
336
+ {cluster: clustersDef._0x0702, att: 'currentSummDelivered', reportable: true, reportChange: 100, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('EAST', ea.STATE).withUnit('kWh').withProperty('current_summ_delivered').withDescription('Total active power delivered')},
337
+ {cluster: clustersDef._0x0702, att: 'currentTier1SummDelivered', reportable: true, reportChange: 100, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('EASF01', ea.STATE).withUnit('kWh').withProperty('current_tier1_summ_delivered').withDescription('Total provider active power delivered (index 01)')},
338
+ {cluster: clustersDef._0x0702, att: 'currentTier2SummDelivered', reportable: true, reportChange: 100, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('EASF02', ea.STATE).withUnit('kWh').withProperty('current_tier2_summ_delivered').withDescription('Total provider active power delivered (index 02)')},
339
+ {cluster: clustersDef._0x0702, att: 'currentTier3SummDelivered', reportable: true, reportChange: 100, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('EASF03', ea.STATE).withUnit('kWh').withProperty('current_tier3_summ_delivered').withDescription('Total provider active power delivered (index 03)')},
340
+ {cluster: clustersDef._0x0702, att: 'currentTier4SummDelivered', reportable: false, reportChange: 100, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('EASF04', ea.STATE).withUnit('kWh').withProperty('current_tier4_summ_delivered').withDescription('Total provider active power delivered (index 04)')},
341
+ {cluster: clustersDef._0x0702, att: 'currentTier5SummDelivered', reportable: false, reportChange: 100, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('EASF05', ea.STATE).withUnit('kWh').withProperty('current_tier5_summ_delivered').withDescription('Total provider active power delivered (index 05)')},
342
+ {cluster: clustersDef._0x0702, att: 'currentTier6SummDelivered', reportable: false, reportChange: 100, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('EASF06', ea.STATE).withUnit('kWh').withProperty('current_tier6_summ_delivered').withDescription('Total provider active power delivered (index 06)')},
343
+ {cluster: clustersDef._0x0702, att: 'currentTier7SummDelivered', reportable: false, reportChange: 100, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('EASF07', ea.STATE).withUnit('kWh').withProperty('current_tier7_summ_delivered').withDescription('Total provider active power delivered (index 07)')},
344
+ {cluster: clustersDef._0x0702, att: 'currentTier8SummDelivered', reportable: false, reportChange: 100, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('EASF08', ea.STATE).withUnit('kWh').withProperty('current_tier8_summ_delivered').withDescription('Total provider active power delivered (index 08)')},
345
+ {cluster: clustersDef._0x0702, att: 'currentTier9SummDelivered', reportable: false, reportChange: 100, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('EASF09', ea.STATE).withUnit('kWh').withProperty('current_tier9_summ_delivered').withDescription('Total provider active power delivered (index 09)')},
346
+ {cluster: clustersDef._0x0702, att: 'currentTier10SummDelivered', reportable: false, reportChange: 100, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('EASF10', ea.STATE).withUnit('kWh').withProperty('current_tier10_summ_delivered').withDescription('Total provider active power delivered (index 10)')},
347
+ {cluster: clustersDef._0xFF66, att: 'activeEnerfyOutD01', reportable: true, reportChange: 100, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('EASD01', ea.STATE).withUnit('kWh').withProperty('active_enerfy_out_d01').withDescription('Active energy withdrawn Distributor (index 01)')},
348
+ {cluster: clustersDef._0xFF66, att: 'activeEnerfyOutD02', reportable: false, reportChange: 100, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('EASD02', ea.STATE).withUnit('kWh').withProperty('active_enerfy_out_d02').withDescription('Active energy withdrawn Distributor (index 02)')},
349
+ {cluster: clustersDef._0xFF66, att: 'activeEnerfyOutD03', reportable: false, reportChange: 100, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('EASD03', ea.STATE).withUnit('kWh').withProperty('active_enerfy_out_d03').withDescription('Active energy withdrawn Distributor (index 03)')},
350
+ {cluster: clustersDef._0xFF66, att: 'activeEnerfyOutD04', reportable: false, reportChange: 100, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('EASD04', ea.STATE).withUnit('kWh').withProperty('active_enerfy_out_d04').withDescription('Active energy withdrawn Distributor (index 04)')},
351
+ {cluster: clustersDef._0x0702, att: 'currentSummReceived', reportable: true, reportChange: 100, onlyProducer: true, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('EAIT', ea.STATE).withUnit('kWh').withProperty('current_summ_received').withDescription('Total active power injected')},
352
+ {cluster: clustersDef._0x0B04, att: 'totalReactivePower', reportable: true, onlyProducer: true, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('ERQ1', ea.STATE).withUnit('VArh').withProperty('total_reactive_power').withDescription('Total reactive power (Q1)')},
353
+ {cluster: clustersDef._0x0B04, att: 'reactivePower', reportable: true, onlyProducer: true, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('ERQ2', ea.STATE).withUnit('VArh').withProperty('reactive_power').withDescription('Total reactive power (Q2)')},
354
+ {cluster: clustersDef._0x0B04, att: 'reactivePowerPhB', reportable: true, onlyProducer: true, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('ERQ3', ea.STATE).withUnit('VArh').withProperty('reactive_power_ph_b').withDescription('Total reactive power (Q3)')},
355
+ {cluster: clustersDef._0x0B04, att: 'reactivePowerPhC', reportable: true, onlyProducer: true, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('ERQ4', ea.STATE).withUnit('VArh').withProperty('reactive_power_ph_c').withDescription('Total reactive power (Q4)')},
356
+ {cluster: clustersDef._0x0B04, att: 'rmsCurrent', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('IRMS1', ea.STATE).withUnit('A').withProperty('rms_current').withDescription('RMS current')},
357
+ {cluster: clustersDef._0x0B04, att: 'rmsCurrentPhB', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('IRMS2', ea.STATE).withUnit('A').withProperty('rms_current_ph_b').withDescription('RMS current (phase 2)')},
358
+ {cluster: clustersDef._0x0B04, att: 'rmsCurrentPhC', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('IRMS3', ea.STATE).withUnit('A').withProperty('rms_current_ph_c').withDescription('RMS current (phase 3)')},
359
+ {cluster: clustersDef._0x0B04, att: 'rmsVoltage', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('URMS1', ea.STATE).withUnit('V').withProperty('rms_voltage').withDescription('RMS voltage')},
360
+ {cluster: clustersDef._0x0B04, att: 'rmsVoltagePhB', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('URMS2', ea.STATE).withUnit('V').withProperty('rms_voltage_ph_b').withDescription('RMS voltage (phase 2)')},
361
+ {cluster: clustersDef._0x0B04, att: 'rmsVoltagePhC', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('URMS3', ea.STATE).withUnit('V').withProperty('rms_voltage_ph_c').withDescription('RMS voltage (phase 3)')},
362
+ {cluster: clustersDef._0x0B01, att: 'availablePower', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('PREF', ea.STATE).withUnit('kVA').withProperty('available_power').withDescription('Apparent power of reference')},
363
+ {cluster: clustersDef._0xFF66, att: 'statusRegister', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.text('STGE', ea.STATE).withProperty('status_register').withDescription('Register of Statutes')},
364
+ {cluster: clustersDef._0x0B01, att: 'powerThreshold', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('PCOUP', ea.STATE).withUnit('kVA').withProperty('power_threshold').withDescription('Apparent power threshold')},
365
+ {cluster: clustersDef._0xFF66, att: 'injectedVA', reportable: true, onlyProducer: true, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('SINSTI', ea.STATE).withUnit('VA').withProperty('injected_v_a').withDescription('Instantaneous apparent power injected')},
366
+ {cluster: clustersDef._0xFF66, att: 'injectedVAMaxN', reportable: true, onlyProducer: true, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('SMAXIN', ea.STATE).withUnit('VA').withProperty('injected_v_a_max_n').withDescription('Apparent power max. injected n')},
367
+ {cluster: clustersDef._0xFF66, att: 'injectedVAMaxN1', reportable: false, onlyProducer: true, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('SMAXIN-1', ea.STATE).withUnit('VA').withProperty('injected_v_a_max_n1').withDescription('Apparent power max. injected n-1')},
368
+ {cluster: clustersDef._0x0B04, att: 'activePower', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('CCASN', ea.STATE).withUnit('W').withProperty('active_power').withDescription('Current point of the active load curve drawn')},
369
+ {cluster: clustersDef._0x0B04, att: 'activePowerPhB', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('CCASN-1', ea.STATE).withUnit('W').withProperty('active_power_ph_b').withDescription('Previous point of the active load curve drawn')},
370
+ {cluster: clustersDef._0xFF66, att: 'injectedActiveLoadN', reportable: true, onlyProducer: true, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('CCAIN', ea.STATE).withUnit('W').withProperty('injected_active_load_n').withDescription('Point n of the withdrawn active load curve')},
371
+ {cluster: clustersDef._0xFF66, att: 'injectedActiveLoadN1', reportable: false, onlyProducer: true, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('CCAIN-1', ea.STATE).withUnit('W').withProperty('injected_active_load_n1').withDescription('Point n-1 of the withdrawn active load curve')},
372
+ {cluster: clustersDef._0x0B04, att: 'averageRmsVoltageMeasPeriod', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('UMOY1', ea.STATE).withUnit('V').withProperty('average_rms_voltage_meas_period').withDescription('Average RMS voltage (phase 1)')},
373
+ {cluster: clustersDef._0x0B04, att: 'averageRmsVoltageMeasurePeriodPhB', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('UMOY2', ea.STATE).withUnit('V').withProperty('average_rms_voltage_measure_period_ph_b').withDescription('Average RMS voltage (phase 2)')},
374
+ {cluster: clustersDef._0x0B04, att: 'averageRmsVoltageMeasPeriodPhC', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('UMOY3', ea.STATE).withUnit('V').withProperty('average_rms_voltage_meas_period_ph_c').withDescription('Average RMS voltage (phase 3)')},
375
+ {cluster: clustersDef._0x0B04, att: 'apparentPower', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('SINSTS', ea.STATE).withUnit('VA').withProperty('apparent_power').withDescription('Immediate apparent power delivered')},
376
+ {cluster: clustersDef._0x0B04, att: 'apparentPower', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('SINSTS1', ea.STATE).withUnit('VA').withProperty('apparent_power').withDescription('Immediate apparent power delivered (phase 1)')},
377
+ {cluster: clustersDef._0x0B04, att: 'apparentPowerPhB', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('SINSTS2', ea.STATE).withUnit('VA').withProperty('apparent_power_ph_b').withDescription('Immediate apparent power delivered (phase 2)')},
378
+ {cluster: clustersDef._0x0B04, att: 'apparentPowerPhC', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('SINSTS3', ea.STATE).withUnit('VA').withProperty('apparent_power_ph_c').withDescription('Immediate apparent power delivered (phase 3)')},
379
+ {cluster: clustersDef._0x0B04, att: 'activePowerMax', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('SMAXN', ea.STATE).withUnit('VA').withProperty('active_power_max').withDescription('Apparent power delivered peak')},
380
+ {cluster: clustersDef._0x0B04, att: 'activePowerMax', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('SMAXN1', ea.STATE).withUnit('VA').withProperty('active_power_max').withDescription('Apparent power delivered peak (phase 1)')},
381
+ {cluster: clustersDef._0x0B04, att: 'activePowerMaxPhB', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('SMAXN2', ea.STATE).withUnit('VA').withProperty('active_power_max_ph_b').withDescription('Apparent power delivered peak (phase 2)')},
382
+ {cluster: clustersDef._0x0B04, att: 'activePowerMaxPhC', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('SMAXN3', ea.STATE).withUnit('VA').withProperty('active_power_max_ph_c').withDescription('Apparent power delivered peak (phase 3)')},
383
+ {cluster: clustersDef._0xFF66, att: 'drawnVAMaxN1', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('SMAXN-1', ea.STATE).withUnit('VA').withProperty('drawn_v_a_max_n1').withDescription('Apparent power max. draw-off n-1')},
384
+ {cluster: clustersDef._0xFF66, att: 'drawnVAMaxN1', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('SMAXN1-1', ea.STATE).withUnit('VA').withProperty('drawn_v_a_max_n1').withDescription('Apparent power max. draw-off n-1 (phase 1)')},
385
+ {cluster: clustersDef._0xFF66, att: 'drawnVAMaxN1P2', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('SMAXN2-1', ea.STATE).withUnit('VA').withProperty('drawn_v_a_max_n1_p2').withDescription('Apparent power max. draw-off n-1 (phase 2)')},
386
+ {cluster: clustersDef._0xFF66, att: 'drawnVAMaxN1P3', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('SMAXN3-1', ea.STATE).withUnit('VA').withProperty('drawn_v_a_max_n1_p3').withDescription('Apparent power max. draw-off n-1 (phase 3)')},
387
+ {cluster: clustersDef._0xFF66, att: 'message1', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.text('MSG1', ea.STATE).withProperty('message1').withDescription('Message short')},
388
+ {cluster: clustersDef._0xFF66, att: 'message2', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.text('MSG2', ea.STATE).withProperty('message2').withDescription('Message ultra-short')},
389
+ {cluster: clustersDef._0x0702, att: 'siteId', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.text('PRM', ea.STATE).withProperty('site_id').withDescription('PRM number')},
390
+ {cluster: clustersDef._0xFF66, att: 'startMobilePoint1', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('DPM1', ea.STATE).withProperty('start_mobile_point1').withDescription('Start mobile point 1')},
391
+ {cluster: clustersDef._0xFF66, att: 'stopMobilePoint1', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('FPM1', ea.STATE).withProperty('stop_mobile_point1').withDescription('Stop mobile point 1')},
392
+ {cluster: clustersDef._0xFF66, att: 'startMobilePoint2', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('DPM2', ea.STATE).withProperty('start_mobile_point2').withDescription('Start mobile point 2')},
393
+ {cluster: clustersDef._0xFF66, att: 'stopMobilePoint2', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('FPM2', ea.STATE).withProperty('stop_mobile_point2').withDescription('Stop mobile point 2')},
394
+ {cluster: clustersDef._0xFF66, att: 'startMobilePoint3', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('DPM3', ea.STATE).withProperty('start_mobile_point3').withDescription('Start mobile point 3')},
395
+ {cluster: clustersDef._0xFF66, att: 'stopMobilePoint3', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('FPM3', ea.STATE).withProperty('stop_mobile_point3').withDescription('Stop mobile point 3')},
396
+ {cluster: clustersDef._0xFF66, att: 'relais', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('RELAIS', ea.STATE).withProperty('relais')},
397
+ {cluster: clustersDef._0xFF66, att: 'daysNumberCurrentCalendar', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('NJOURF', ea.STATE).withProperty('days_number_current_calendar').withDescription('Current day number supplier calendar')},
398
+ {cluster: clustersDef._0xFF66, att: 'daysNumberNextCalendar', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('NJOURF+1', ea.STATE).withProperty('days_number_next_calendar').withDescription('Next day number supplier calendar')},
399
+ {cluster: clustersDef._0xFF66, att: 'daysProfileCurrentCalendar', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.text('PJOURF+1', ea.STATE).withProperty('days_profile_current_calendar').withDescription('Profile of the next supplier calendar day')},
400
+ {cluster: clustersDef._0xFF66, att: 'daysProfileNextCalendar', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.text('PPOINTE1', ea.STATE).withProperty('days_profile_next_calendar').withDescription('Profile of the next check-in day')},
401
+ ];
402
+
403
+ function getCurrentConfig(device, options, logger=console) {
404
+ let endpoint;
405
+ try {
406
+ endpoint = device.getEndpoint(1);
407
+ } catch (error) {
408
+ logger.debug(error);
409
+ }
410
+
411
+ function getConfig(targetOption, bitLinkyMode, valueTrue, valueFalse) {
412
+ const valueDefault = valueFalse;
413
+ if (options && options.hasOwnProperty(targetOption) && options[targetOption] != 'auto') {
414
+ if (options[targetOption] === 'true' || options[targetOption] === 'false') {
415
+ return options[targetOption] === 'true'; // special case for production
416
+ }
417
+ return options[targetOption];
418
+ }
419
+
420
+ let lMode;
421
+ try {
422
+ lMode = endpoint.clusters[clustersDef._0xFF66].attributes['linkyMode'];
423
+ lMode.raiseError; // raise if undefined
424
+ return (lMode >> bitLinkyMode & 1) == 1 ? valueTrue : valueFalse;
425
+ } catch (err) {
426
+ logger.warn(`Was not able to detect the Linky `+ targetOption +`. Default to ` + valueDefault);
427
+ return valueDefault; // default value in the worst case
428
+ }
429
+ }
430
+
431
+ const linkyMode = getConfig('linky_mode', 0, linkyModeDef.standard, linkyModeDef.legacy);
432
+
433
+ const linkyPhase = getConfig('energy_phase', 1, linkyPhaseDef.three, linkyPhaseDef.single);
434
+
435
+ let linkyProduction = false; // In historique we can't be producer
436
+
437
+ if (linkyMode == linkyModeDef.standard) {
438
+ linkyProduction = getConfig('production', 2, true, false);
439
+ }
440
+
441
+ // Main filter
442
+ let myExpose = exposedData
443
+ .filter((e) => e.linkyMode == linkyMode && (e.linkyPhase == linkyPhase || e.linkyPhase == linkyPhaseDef.all) && (linkyProduction || !e.onlyProducer));
444
+
445
+ // Filter even more, based on our current tarif
446
+ let currentTarf;
447
+
448
+ try {
449
+ // Try to remove atributes which doesn't match current tarif
450
+ currentTarf = endpoint.clusters.liXeePrivate.attributes.currentTarif.replace(/\0/g, '');
451
+ } catch (error) {
452
+ currentTarf = '';
453
+ if (options && options.hasOwnProperty('tarif') && options['tarif'] != 'auto') {
454
+ currentTarf = Object.entries(tarifsDef).find(( [k, v] ) => (v.fname == options['tarif']))[1].currentTarf;
455
+ }
456
+ }
457
+
458
+ // logger.debug(`zlinky config: ` + linkyMode + `, `+ linkyPhase + `, `+ linkyProduction.toString() +`, `+ currentTarf);
459
+
460
+ switch (currentTarf) {
461
+ case linkyMode == linkyModeDef.legacy && tarifsDef.histo_BASE.currentTarf:
462
+ myExpose = myExpose.filter((a) => !tarifsDef.histo_BASE.excluded.includes(a.exposes.name));
463
+ break;
464
+ case linkyMode == linkyModeDef.legacy && tarifsDef.histo_HCHP.currentTarf:
465
+ myExpose = myExpose.filter((a) => !tarifsDef.histo_HCHP.excluded.includes(a.exposes.name));
466
+ break;
467
+ case linkyMode == linkyModeDef.legacy && tarifsDef.histo_EJP.currentTarf:
468
+ myExpose = myExpose.filter((a) => !tarifsDef.histo_EJP.excluded.includes(a.exposes.name));
469
+ break;
470
+ case linkyMode == linkyModeDef.legacy && currentTarf.startsWith(tarifsDef.histo_BBR.currentTarf):
471
+ myExpose = myExpose.filter((a) => !tarifsDef.histo_BBR.excluded.includes(a.exposes.name));
472
+ break;
473
+ case linkyMode == linkyModeDef.standard && tarifsDef.stand_SEM_WE_MERCR.currentTarf:
474
+ myExpose = myExpose.filter((a) => !tarifsDef.stand_SEM_WE_MERCR.excluded.includes(a.exposes.name));
475
+ break;
476
+ default:
477
+ break;
478
+ }
479
+
480
+
481
+ return myExpose;
482
+ }
483
+ const definition = {
484
+ zigbeeModel: ['ZLinky_TIC'],
485
+ model: 'ZLinky_TIC',
486
+ vendor: 'LiXee',
487
+ description: 'Lixee ZLinky',
488
+ fromZigbee: [fzLocal.lixee_metering, fz.meter_identification, fzLocal.lixee_ha_electrical_measurement, fzLocal.lixee_private_fz],
489
+ toZigbee: [],
490
+ exposes: (device, options) => {
491
+ // docs generation
492
+ let exposes;
493
+ if (device == null && options == null) {
494
+ exposes = exposedData.map((e) => e.exposes);
495
+ } else {
496
+ exposes = getCurrentConfig(device, options).map((e) => e.exposes);
497
+ }
498
+
499
+ exposes.push(e.linkquality());
500
+ return exposes;
501
+ },
502
+ options: [
503
+ exposes.options.measurement_poll_interval(),
504
+ exposes.enum(`linky_mode`, ea.SET, ['auto', linkyModeDef.legacy, linkyModeDef.standard])
505
+ .withDescription(`Counter with TIC in mode standard or historique. May require restart (default: auto)`),
506
+ exposes.enum(`energy_phase`, ea.SET, ['auto', linkyPhaseDef.single, linkyPhaseDef.three])
507
+ .withDescription(`Power with single or three phase. May require restart (default: auto)`),
508
+ exposes.enum(`production`, ea.SET, ['auto', 'true', 'false']).withDescription(`If you produce energy back to the grid (works ONLY when linky_mode: ${linkyModeDef.standard}, default: auto)`),
509
+ exposes.enum(`tarif`, ea.SET, [...Object.entries(tarifsDef).map(( [k, v] ) => (v.fname)), 'auto'])
510
+ .withDescription(`The current tarif. This option will exclude unnecesary attributes. Default: auto`),
511
+ exposes.options.precision(`kWh`),
512
+ ],
513
+ configure: async (device, coordinatorEndpoint, logger, options) => {
514
+ const endpoint = device.getEndpoint(1);
515
+
516
+ await reporting.bind(endpoint, coordinatorEndpoint, [
517
+ clustersDef._0x0702, /* seMetering */
518
+ clustersDef._0x0B01, /* haMeterIdentification */
519
+ clustersDef._0x0B04, /* haElectricalMeasurement */
520
+ clustersDef._0xFF66, /* liXeePrivate */
521
+ ]);
522
+
523
+ const configReportings = [];
524
+ const suscribeNew = getCurrentConfig(device, options, logger).filter((e) => e.reportable);
525
+
526
+ const unsuscribe = endpoint.configuredReportings
527
+ .filter((e) => !suscribeNew.some((r) => e.cluster.name == r.cluster && e.attribute.name == r.att));
528
+ // Unsuscribe reports that doesn't correspond with the current config
529
+ (await Promise.allSettled(unsuscribe.map((e) => endpoint.configureReporting(e.cluster.name, reporting.payload(e.attribute.name, e.minimumReportInterval, 65535, e.reportableChange)))))
530
+ .filter((e) => e.status == 'rejected')
531
+ .forEach((e) => {
532
+ throw e.reason;
533
+ });
534
+
535
+ for (const e of suscribeNew) {
536
+ let change = 1;
537
+ if (e.hasOwnProperty('reportChange')) {
538
+ change = e['reportChange'];
539
+ }
540
+ configReportings.push(endpoint
541
+ .configureReporting(
542
+ e.cluster, reporting.payload(e.att, 0, repInterval.MINUTES_15, change)),
543
+ );
544
+ }
545
+ (await Promise.allSettled(configReportings))
546
+ .filter((e) => e.status == 'rejected')
547
+ .forEach((e) => {
548
+ throw e.reason;
549
+ });
550
+ },
551
+ ota: ota.lixee,
552
+ onEvent: async (type, data, device, options) => {
553
+ const endpoint = device.getEndpoint(1);
554
+ if (type === 'stop') {
555
+ clearInterval(globalStore.getValue(device, 'interval'));
556
+ globalStore.clearValue(device, 'interval');
557
+ } else if (!globalStore.hasValue(device, 'interval')) {
558
+ const seconds = options && options.measurement_poll_interval ? options.measurement_poll_interval : 60;
559
+
560
+ const interval = setInterval(async () => {
561
+ const currentExposes = getCurrentConfig(device, options)
562
+ .filter((e) => !endpoint.configuredReportings.some((r) => r.cluster.name == e.cluster && r.attribute.name == e.att));
563
+ for (const e of currentExposes) {
564
+ await endpoint
565
+ .read(e.cluster, [e.att])
566
+ .catch((err) => { }); // TODO: Ignore reads error?
567
+ }
568
+ }, seconds * 1000);
569
+ globalStore.putValue(device, 'interval', interval);
570
+ }
571
+ },
572
+ };
573
+
574
+ module.exports = [definition];
package/devices/moes.js CHANGED
@@ -118,9 +118,13 @@ module.exports = [
118
118
  model: 'ZTS-EU_1gang',
119
119
  vendor: 'Moes',
120
120
  description: 'Wall touch light switch (1 gang)',
121
- exposes: [e.switch().setAccess('state', ea.STATE_SET)],
122
- fromZigbee: [fz.tuya_switch],
123
- toZigbee: [tz.tuya_switch_state],
121
+ exposes: [e.switch().setAccess('state', ea.STATE_SET),
122
+ exposes.enum('indicate_light', ea.STATE_SET, ['off', 'switch', 'position'])
123
+ .withDescription('Indicator light status'),
124
+ exposes.enum('power_on_behavior', ea.STATE_SET, ['off', 'on', 'previous'])
125
+ .withDescription('Controls the behavior when the device is powered on')],
126
+ fromZigbee: [fz.tuya_switch, fz.moes_switch],
127
+ toZigbee: [tz.tuya_switch_state, tz.moes_switch],
124
128
  onEvent: tuya.onEventSetLocalTime,
125
129
  configure: async (device, coordinatorEndpoint, logger) => {
126
130
  await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ['genOnOff']);
@@ -135,9 +139,13 @@ module.exports = [
135
139
  vendor: 'Moes',
136
140
  description: 'Wall touch light switch (2 gang)',
137
141
  exposes: [e.switch().withEndpoint('l1').setAccess('state', ea.STATE_SET),
138
- e.switch().withEndpoint('l2').setAccess('state', ea.STATE_SET)],
139
- fromZigbee: [fz.ignore_basic_report, fz.tuya_switch],
140
- toZigbee: [tz.tuya_switch_state],
142
+ e.switch().withEndpoint('l2').setAccess('state', ea.STATE_SET),
143
+ exposes.enum('indicate_light', ea.STATE_SET, ['off', 'switch', 'position'])
144
+ .withDescription('Indicator light status'),
145
+ exposes.enum('power_on_behavior', ea.STATE_SET, ['off', 'on', 'previous'])
146
+ .withDescription('Controls the behavior when the device is powered on')],
147
+ fromZigbee: [fz.ignore_basic_report, fz.tuya_switch, fz.moes_switch],
148
+ toZigbee: [tz.tuya_switch_state, tz.moes_switch],
141
149
  onEvent: tuya.onEventSetLocalTime,
142
150
  meta: {multiEndpoint: true},
143
151
  endpoint: (device) => {
@@ -158,9 +166,14 @@ module.exports = [
158
166
  vendor: 'Moes',
159
167
  description: 'Wall touch light switch (3 gang)',
160
168
  exposes: [e.switch().withEndpoint('l1').setAccess('state', ea.STATE_SET),
161
- e.switch().withEndpoint('l2').setAccess('state', ea.STATE_SET), e.switch().withEndpoint('l3').setAccess('state', ea.STATE_SET)],
162
- fromZigbee: [fz.ignore_basic_report, fz.tuya_switch],
163
- toZigbee: [tz.tuya_switch_state],
169
+ e.switch().withEndpoint('l2').setAccess('state', ea.STATE_SET),
170
+ e.switch().withEndpoint('l3').setAccess('state', ea.STATE_SET),
171
+ exposes.enum('indicate_light', ea.STATE_SET, ['off', 'switch', 'position'])
172
+ .withDescription('Indicator light status'),
173
+ exposes.enum('power_on_behavior', ea.STATE_SET, ['off', 'on', 'previous'])
174
+ .withDescription('Controls the behavior when the device is powered on')],
175
+ fromZigbee: [fz.ignore_basic_report, fz.tuya_switch, fz.moes_switch],
176
+ toZigbee: [tz.tuya_switch_state, tz.moes_switch],
164
177
  onEvent: tuya.onEventSetLocalTime,
165
178
  meta: {multiEndpoint: true},
166
179
  endpoint: (device) => {
@@ -29,7 +29,7 @@ module.exports = [
29
29
  description: 'Smart power strip',
30
30
  extend: extend.switch(),
31
31
  configure: async (device, coordinatorEndpoint, logger) => {
32
- const endpoint = device.getEndpoint(11);
32
+ const endpoint = device.getEndpoint(11) || device.getEndpoint(1);
33
33
  await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff']);
34
34
  await reporting.onOff(endpoint);
35
35
  },
@@ -96,7 +96,8 @@ module.exports = [
96
96
  toZigbee: extend.light_onoff_brightness_colortemp_color().toZigbee.concat([tz.tint_scene]),
97
97
  },
98
98
  {
99
- zigbeeModel: ['ZBT-Remote-ALL-RGBW'],
99
+ fingerprint: [{manufacturerName: '_TZ3000_bdbb0fon'}],
100
+ zigbeeModel: ['ZBT-Remote-ALL-RGBW', 'TS1001'],
100
101
  model: 'MLI-404011',
101
102
  description: 'Tint remote control',
102
103
  vendor: 'Müller Licht',
@@ -1904,10 +1904,10 @@ module.exports = [
1904
1904
  vendor: 'Philips',
1905
1905
  description: 'Hue dimmer switch',
1906
1906
  fromZigbee: [fz.ignore_command_on, fz.ignore_command_off, fz.ignore_command_step, fz.ignore_command_stop,
1907
- fz.hue_dimmer_switch, fz.battery],
1907
+ fz.hue_dimmer_switch, fz.battery, fz.command_recall],
1908
1908
  exposes: [e.battery(), e.action(['on_press', 'on_hold', 'on_press_release', 'on_hold_release',
1909
1909
  'off_press', 'off_hold', 'off_press_release', 'off_hold_release', 'up_press', 'up_hold', 'up_press_release', 'up_hold_release',
1910
- 'down_press', 'down_hold', 'down_press_release', 'down_hold_release'])],
1910
+ 'down_press', 'down_hold', 'down_press_release', 'down_hold_release', 'recall_0', 'recall_1'])],
1911
1911
  toZigbee: [],
1912
1912
  configure: async (device, coordinatorEndpoint, logger) => {
1913
1913
  const endpoint = device.getEndpoint(1);
@@ -45,4 +45,11 @@ module.exports = [
45
45
  description: 'LED bulb GU10 350 lumen, dimmable, color, white 2700-6500K',
46
46
  extend: extend.light_onoff_brightness_colortemp({colorTempRange: [153, 370]}),
47
47
  },
48
+ {
49
+ zigbeeModel: ['ZBT-DIMLight-GU100800'],
50
+ model: 'HAL400',
51
+ vendor: 'Schwaiger',
52
+ description: 'LED Schwaiger HAL400 GU10 dimmable, warm white',
53
+ extend: extend.light_onoff_brightness(),
54
+ },
48
55
  ];
@@ -60,13 +60,20 @@ module.exports = [
60
60
  model: 'E11-G13',
61
61
  vendor: 'Sengled',
62
62
  description: 'Element classic (A19)',
63
- extend: extend.light_onoff_brightness({noConfigure: true}),
64
- ota: ota.zigbeeOTA,
63
+ fromZigbee: extend.light_onoff_brightness().fromZigbee.concat([fz.metering]),
64
+ toZigbee: extend.light_onoff_brightness().toZigbee,
65
65
  configure: async (device, coordinatorEndpoint, logger) => {
66
66
  await extend.light_onoff_brightness().configure(device, coordinatorEndpoint, logger);
67
67
  device.powerSource = 'Mains (single phase)';
68
68
  device.save();
69
+
70
+ const endpoint = device.getEndpoint(1);
71
+ await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'seMetering']);
72
+ await reporting.readMeteringMultiplierDivisor(endpoint);
73
+ await reporting.currentSummDelivered(endpoint);
74
+ await reporting.instantaneousDemand(endpoint);
69
75
  },
76
+ exposes: [e.power(), e.energy(), e.light_brightness()],
70
77
  },
71
78
  {
72
79
  zigbeeModel: ['E11-G23', 'E11-G33'],
package/devices/sonoff.js CHANGED
@@ -14,6 +14,17 @@ module.exports = [
14
14
  extend: extend.switch(),
15
15
  fromZigbee: [fz.on_off_skip_duplicate_transaction],
16
16
  },
17
+ {
18
+ zigbeeModel: ['ZBMINI-L'],
19
+ model: 'ZBMINI-L',
20
+ vendor: 'SONOFF',
21
+ description: 'Zigbee smart switch (no neutral)',
22
+ extend: extend.switch(),
23
+ configure: async (device, coordinatorEndpoint, logger) => {
24
+ device.powerSource = 'Mains (single phase)';
25
+ device.save();
26
+ },
27
+ },
17
28
  {
18
29
  zigbeeModel: ['01MINIZB'],
19
30
  model: 'ZBMINI',
@@ -103,7 +103,7 @@ module.exports = [
103
103
  },
104
104
  },
105
105
  {
106
- zigbeeModel: ['ON/OFF', 'ZIGBEE-SWITCH'],
106
+ zigbeeModel: ['ON/OFF -M', 'ON/OFF', 'ZIGBEE-SWITCH'],
107
107
  model: 'ZG9101SAC-HP-Switch',
108
108
  vendor: 'Sunricher',
109
109
  description: 'Zigbee AC in wall switch',
package/devices/tuya.js CHANGED
@@ -12,7 +12,7 @@ const utils = require('../lib/utils');
12
12
 
13
13
  const TS011Fplugs = ['_TZ3000_5f43h46b', '_TZ3000_cphmq0q7', '_TZ3000_dpo1ysak', '_TZ3000_ew3ldmgx', '_TZ3000_gjnozsaz',
14
14
  '_TZ3000_jvzvulen', '_TZ3000_mraovvmm', '_TZ3000_nfnmi125', '_TZ3000_ps3dmato', '_TZ3000_w0qqde0g', '_TZ3000_u5u4cakc',
15
- '_TZ3000_rdtixbnu', '_TZ3000_typdpbpg'];
15
+ '_TZ3000_rdtixbnu', '_TZ3000_typdpbpg', '_TZ3000_2xlvlnez'];
16
16
 
17
17
  const tzLocal = {
18
18
  TS0504B_color: {
@@ -250,7 +250,7 @@ module.exports = [
250
250
  model: 'TS0202',
251
251
  vendor: 'TuYa',
252
252
  description: 'Motion sensor',
253
- whiteLabel: [{vendor: 'Mercator Ikuü', model: 'SMA02P'}, {vendor: 'TuYa ', model: 'TY-ZPR06'}],
253
+ whiteLabel: [{vendor: 'Mercator Ikuü', model: 'SMA02P'}, {vendor: 'TuYa', model: 'TY-ZPR06'}],
254
254
  fromZigbee: [fz.ias_occupancy_alarm_1, fz.battery, fz.ignore_basic_report, fz.ias_occupancy_alarm_1_report],
255
255
  toZigbee: [],
256
256
  exposes: [e.occupancy(), e.battery_low(), e.tamper(), e.battery()],
@@ -882,6 +882,7 @@ module.exports = [
882
882
  {modelID: 'TS0601', manufacturerName: '_TZE200_5sbebbzs'},
883
883
  {modelID: 'TS0601', manufacturerName: '_TZE200_zuz7f94z'},
884
884
  {modelID: 'TS0601', manufacturerName: '_TZE200_zyrdrmno'},
885
+ {modelID: 'TS0601', manufacturerName: '_TZE200_68nvbio9'},
885
886
  ],
886
887
  model: 'TS0601_cover',
887
888
  vendor: 'TuYa',
package/devices/xiaomi.js CHANGED
@@ -1174,8 +1174,8 @@ module.exports = [
1174
1174
  exposes.enum('mute_buzzer', ea.SET, ['Mute']).withDescription('Mute the buzzer for 10 minutes (buzzer cannot be ' +
1175
1175
  'pre-muted, because this function only works when the alarm is triggered)'),
1176
1176
  exposes.binary('mute', ea.STATE_GET, true, false).withDescription('Buzzer muted'),
1177
- exposes.switch().withState('linkage_alarm', true, 'After being turned on, one of the devices triggers the ' +
1178
- 'natural gas leakage alarm, and other devices with linkage turned on', ea.ALL, true, false),
1177
+ exposes.binary('linkage_alarm', ea.ALL, true, false).withDescription('When this option is enabled and a gas leak ' +
1178
+ 'is detected, other detectors with this option enabled will also sound the alarm buzzer'),
1179
1179
  exposes.binary('state', ea.STATE_GET, 'preparation', 'work').withDescription('"Preparation" or "work" ' +
1180
1180
  '(measurement of the gas concentration value and triggering of an alarm are only performed in the "work" state)'),
1181
1181
  exposes.numeric('power_outage_count', ea.STATE_GET).withDescription('Number of power outages (since last pairing)')],
@@ -1272,9 +1272,9 @@ module.exports = [
1272
1272
  vendor: 'Xiaomi',
1273
1273
  fromZigbee: [fz.xiaomi_curtain_acn002_position, fz.xiaomi_curtain_acn002_status, fz.cover_position_tilt, fz.ignore_basic_report,
1274
1274
  fz.aqara_opple],
1275
- toZigbee: [tz.xiaomi_curtain_position_state, tz.xiaomi_curtain_acn002_status],
1275
+ toZigbee: [tz.xiaomi_curtain_position_state],
1276
1276
  exposes: [e.cover_position().setAccess('state', ea.ALL), e.battery(),
1277
- exposes.enum('motor_state', ea.STATE_GET, ['declining', 'rising', 'pause', 'blocked'])
1277
+ exposes.enum('motor_state', ea.STATE, ['declining', 'rising', 'pause', 'blocked'])
1278
1278
  .withDescription('The current state of the motor.'),
1279
1279
  exposes.binary('running', ea.STATE, true, false)
1280
1280
  .withDescription('Whether the motor is moving or not.')],
@@ -1289,7 +1289,7 @@ module.exports = [
1289
1289
  model: 'LLKZMK11LM',
1290
1290
  vendor: 'Xiaomi',
1291
1291
  description: 'Aqara wireless relay controller',
1292
- fromZigbee: [fz.xiaomi_switch_basic, fz.xiaomi_power, fz.ignore_multistate_report, fz.on_off],
1292
+ fromZigbee: [fz.xiaomi_switch_basic, fz.xiaomi_power, fz.ignore_multistate_report, fz.on_off, fz.aqara_opple],
1293
1293
  meta: {multiEndpoint: true},
1294
1294
  toZigbee: [tz.on_off, tz.LLKZMK11LM_interlock, tz.xiaomi_power],
1295
1295
  endpoint: (device) => {
@@ -1299,7 +1299,7 @@ module.exports = [
1299
1299
  e.switch().withEndpoint('l1'), e.switch().withEndpoint('l2'),
1300
1300
  exposes.binary('interlock', ea.STATE_SET, true, false)
1301
1301
  .withDescription('Enabling prevents both relais being on at the same time')],
1302
- // TEMP DISABLED: https://github.com/Koenkk/zigbee2mqtt/issues/7112 ota: ota.zigbeeOTA,
1302
+ ota: ota.zigbeeOTA,
1303
1303
  },
1304
1304
  {
1305
1305
  zigbeeModel: ['lumi.lock.acn02'],
@@ -1597,7 +1597,8 @@ module.exports = [
1597
1597
  e.battery(), e.battery_voltage(), e.action([
1598
1598
  'single_left', 'single_right', 'single_both',
1599
1599
  'double_left', 'double_right', 'double_both',
1600
- 'triple_left', 'triple_right', 'triple_both']),
1600
+ 'triple_left', 'triple_right', 'triple_both',
1601
+ 'hold_left', 'hold_right', 'hold_both']),
1601
1602
  exposes.enum('click_mode', ea.ALL, ['fast', 'multi'])
1602
1603
  .withDescription('Click mode, fast: only supports single click which will be send immediately after clicking.' +
1603
1604
  'multi: supports more events like double and hold'),
package/devices/yale.js CHANGED
@@ -124,4 +124,11 @@ module.exports = [
124
124
  description: 'Real living lock / Intelligent biometric digital lock',
125
125
  extend: lockExtend(),
126
126
  },
127
+ {
128
+ zigbeeModel: ['06ffff2027'],
129
+ model: 'YMF40A RL',
130
+ vendor: 'Yale',
131
+ description: 'Real living lock / Intelligent biometric digital lock',
132
+ extend: lockExtend({battery: {dontDividePercentage: true}}),
133
+ },
127
134
  ];
package/index.js CHANGED
@@ -62,7 +62,7 @@ function addDefinition(definition) {
62
62
  const {extend, ...definitionWithoutExtend} = definition;
63
63
  if (extend) {
64
64
  if (extend.hasOwnProperty('configure') && definition.hasOwnProperty('configure')) {
65
- console.log(`'${definition.model}' has configure in extend and device, this is not allowed`);
65
+ assert.fail(`'${definition.model}' has configure in extend and device, this is not allowed`);
66
66
  }
67
67
 
68
68
  definition = {
@@ -89,7 +89,8 @@ function addDefinition(definition) {
89
89
  const optionKeys = definition.options.map((o) => o.name);
90
90
  for (const converter of [...definition.toZigbee, ...definition.fromZigbee]) {
91
91
  if (converter.options) {
92
- for (const option of converter.options) {
92
+ const options = typeof converter.options === 'function' ? converter.options(definition) : converter.options;
93
+ for (const option of options) {
93
94
  if (!optionKeys.includes(option.name)) {
94
95
  definition.options.push(option);
95
96
  optionKeys.push(option.name);
package/lib/extend.js CHANGED
@@ -58,12 +58,14 @@ const extend = {
58
58
  tz.light_brightness_step, tz.level_config, tz.power_on_behavior, tz.light_hue_saturation_move,
59
59
  tz.light_hue_saturation_step, tz.light_color_options, tz.light_color_mode, ...(!options.disableEffect ? [tz.effect] : [])];
60
60
 
61
- return {
62
- exposes, fromZigbee, toZigbee,
63
- configure: async (device, coordinatorEndpoint, logger) => {
61
+ const result = {exposes, fromZigbee, toZigbee};
62
+ if (!options.noConfigure) {
63
+ result.configure = async (device, coordinatorEndpoint, logger) => {
64
64
  await light.configure(device, coordinatorEndpoint, logger, false);
65
- },
66
- };
65
+ };
66
+ }
67
+
68
+ return result;
67
69
  },
68
70
  light_onoff_brightness_colortemp_color: (options={}) => {
69
71
  options = {disableEffect: false, supportsHS: false, disableColorTempStartup: false, preferHS: false, ...options};
package/lib/ota/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  module.exports = {
2
2
  ledvance: require('./ledvance'),
3
3
  salus: require('./salus'),
4
+ lixee: require('./lixee'),
4
5
  securifi: require('./securifi'),
5
6
  tradfri: require('./tradfri'),
6
7
  ubisys: require('./ubisys'),
@@ -0,0 +1,57 @@
1
+ const firmwareOrigin = 'https://api.github.com/repos/fairecasoimeme/Zlinky_TIC/releases';
2
+ const assert = require('assert');
3
+ const common = require('./common');
4
+ const axios = common.getAxios();
5
+
6
+ /**
7
+ * Helper functions
8
+ */
9
+
10
+ async function getImageMeta(current, logger, device) {
11
+ const manufacturerCode = current.manufacturerCode;
12
+ const imageType = current.imageType;
13
+ const releasesLIST = (await axios.get(firmwareOrigin)).data;
14
+
15
+ let firmURL;
16
+
17
+ // Find the most recent OTA file available
18
+ for (const e of releasesLIST.sort((a, b) => a.published_at - a.published_at)) {
19
+ if (e.assets) {
20
+ const targetObj = e.assets
21
+ .find((a) => a.name.endsWith('.ota'));
22
+ if (targetObj && targetObj.browser_download_url) {
23
+ firmURL = targetObj;
24
+ break;
25
+ }
26
+ }
27
+ }
28
+
29
+ assert(firmURL,
30
+ `No image available for manufacturerCode '${manufacturerCode}' imageType '${imageType} on Github repo'`);
31
+
32
+ logger.info(`Using firmware file ` + firmURL.name);
33
+ const image = common.parseImage((await common.getAxios().get(firmURL.browser_download_url, {responseType: 'arraybuffer'})).data);
34
+
35
+ return {
36
+ fileVersion: image.header.fileVersion,
37
+ fileSize: firmURL.size,
38
+ url: firmURL.browser_download_url,
39
+ };
40
+ }
41
+
42
+ /**
43
+ * Interface implementation
44
+ */
45
+
46
+ async function isUpdateAvailable(device, logger, requestPayload=null) {
47
+ return common.isUpdateAvailable(device, logger, common.isNewImageAvailable, requestPayload, getImageMeta);
48
+ }
49
+
50
+ async function updateToLatest(device, logger, onProgress) {
51
+ return common.updateToLatest(device, logger, onProgress, common.getNewImage, getImageMeta);
52
+ }
53
+
54
+ module.exports = {
55
+ isUpdateAvailable,
56
+ updateToLatest,
57
+ };
package/lib/tuya.js CHANGED
@@ -578,6 +578,9 @@ const dataPoints = {
578
578
  garageDoorTrigger: 1,
579
579
  garageDoorContact: 3,
580
580
  garageDoorStatus: 12,
581
+ // Moes switch with optional neutral
582
+ moesSwitchPowerOnBehavior: 14,
583
+ moesSwitchIndicateLight: 15,
581
584
  };
582
585
 
583
586
  const thermostatWeekFormat = {
@@ -731,6 +734,19 @@ const ZMAM02 = {
731
734
  },
732
735
  };
733
736
 
737
+ const moesSwitch = {
738
+ powerOnBehavior: {
739
+ 0: 'off',
740
+ 1: 'on',
741
+ 2: 'previous',
742
+ },
743
+ indicateLight: {
744
+ 0: 'off',
745
+ 1: 'switch',
746
+ 2: 'position',
747
+ },
748
+ };
749
+
734
750
  // Return `seq` - transaction ID for handling concrete response
735
751
  async function sendDataPoints(entity, dpValues, cmd, seq=undefined) {
736
752
  if (seq === undefined) {
@@ -881,4 +897,5 @@ module.exports = {
881
897
  tvThermostatPreset,
882
898
  tuyaRadar,
883
899
  ZMAM02,
900
+ moesSwitch,
884
901
  };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zigbee-herdsman-converters",
3
- "version": "14.0.407",
3
+ "version": "14.0.411",
4
4
  "lockfileVersion": 1,
5
5
  "requires": true,
6
6
  "dependencies": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zigbee-herdsman-converters",
3
- "version": "14.0.407",
3
+ "version": "14.0.411",
4
4
  "description": "Collection of device converters to be used with zigbee-herdsman",
5
5
  "main": "index.js",
6
6
  "files": [