zigbee-herdsman-converters 14.0.410 → 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'],
@@ -5323,8 +5362,9 @@ const converters = {
5323
5362
  payload.presence_event = {0: 'enter', 1: 'leave', 2: 'left_enter', 3: 'right_leave', 4: 'right_enter',
5324
5363
  5: 'left_leave', 6: 'approach', 7: 'away', 255: null}[value];
5325
5364
  }
5326
- } else if (index ===103) payload.monitoring_mode = value === 1 ? 'left_right' : 'undirected'; // RTCZCGQ11LM
5327
- 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) {
5328
5368
  if (['RTCGQ13LM'].includes(model.model)) {
5329
5369
  payload.motion_sensitivity = {1: 'low', 2: 'medium', 3: 'high'}[value];
5330
5370
  } else if (['RTCZCGQ11LM'].includes(model.model)) {
@@ -3206,6 +3206,30 @@ const converters = {
3206
3206
  await entity.read('genOnOff', ['moesStartUpOnOff']);
3207
3207
  },
3208
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
+ },
3209
3233
  moes_thermostat_sensor: {
3210
3234
  key: ['sensor'],
3211
3235
  convertSet: async (entity, key, value, meta) => {
@@ -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) => {
@@ -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);
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',
package/devices/tuya.js CHANGED
@@ -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/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.410",
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.410",
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": [