homebridge-enphase-envoy 10.2.7-beta.3 → 10.2.7-beta.5

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.
package/index.js CHANGED
@@ -1,7 +1,6 @@
1
1
  import { join } from 'path';
2
2
  import { mkdirSync, existsSync, writeFileSync } from 'fs';
3
3
  import EnvoyDevice from './src/envoydevice.js';
4
- import EnergyMeter from './src/energymeter.js';
5
4
  import ImpulseGenerator from './src/impulsegenerator.js';
6
5
  import { PluginName, PlatformName } from './src/constants.js';
7
6
  import CustomCharacteristics from './src/customcharacteristics.js';
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "private": false,
3
3
  "displayName": "Enphase Envoy",
4
4
  "name": "homebridge-enphase-envoy",
5
- "version": "10.2.7-beta.3",
5
+ "version": "10.2.7-beta.5",
6
6
  "description": "Homebridge p7ugin for Photovoltaic Energy System manufactured by Enphase.",
7
7
  "license": "MIT",
8
8
  "author": "grzegorz914",
@@ -3007,15 +3007,12 @@ class EnvoyDevice extends EventEmitter {
3007
3007
  path: this.prefDir,
3008
3008
  filename: this.energyMeterHistoryFileName
3009
3009
  })
3010
- this.fakegatoHistoryService.addEntry({
3011
- time: Math.floor(Date.now() / 1000),
3012
- power: this.pv.powerAndEnergyData.data[0].power ?? 0
3013
- });
3014
3010
 
3015
3011
  // Energy Meter Service
3016
3012
  this.energyMeterServices = [];
3017
3013
  for (const source of this.pv.powerAndEnergyData.data) {
3018
3014
  const measurementType = source.measurementType;
3015
+ const power = source.power > 0 ? source.power : 0;
3019
3016
 
3020
3017
  if (this.logDebug) this.emit('debug', `Prepare Energy Meter ${measurementType} Service`);
3021
3018
  const energyMeterService = accessory.addService(Service.EvePowerMeter, `Energy Meter ${measurementType}`, `energyMeterService${measurementType}`);
@@ -3023,7 +3020,7 @@ class EnvoyDevice extends EventEmitter {
3023
3020
 
3024
3021
  // Create characteristics
3025
3022
  const characteristics = [
3026
- { type: Characteristic.EvePower, label: 'power', value: source.power, unit: 'W' },
3023
+ { type: Characteristic.EvePower, label: 'power', value: power, unit: 'W' },
3027
3024
  { type: Characteristic.EveEnergyLifetime, label: 'energy lifetime', value: source.energyLifetimeWithOffset, unit: 'kWh' },
3028
3025
  ];
3029
3026
 
@@ -3094,6 +3091,7 @@ class EnvoyDevice extends EventEmitter {
3094
3091
  this.emit('devInfo', `Firmware: ${info.software}`);
3095
3092
  this.emit('devInfo', `SerialNr: ${info.serialNumber}`);
3096
3093
  this.emit('devInfo', `Time: ${this.functions.formatTimestamp(info.time, timeZone)}`);
3094
+ this.emit('devInfo', `Energy Meter: ${this.energyMeter ? 'Enabled' : 'Disabled'}`);
3097
3095
  this.emit('devInfo', `------------------------------`);
3098
3096
 
3099
3097
  // Inventory
@@ -4106,6 +4104,7 @@ class EnvoyDevice extends EventEmitter {
4106
4104
 
4107
4105
  // Energy meter
4108
4106
  if (key === 'production' && this.energyMeter) {
4107
+ const power = obj.power > 0 ? obj.power : 0;
4109
4108
  // Add to fakegato history
4110
4109
  this.fakegatoHistoryService?.addEntry({
4111
4110
  time: Math.floor(Date.now() / 1000),
@@ -4114,7 +4113,7 @@ class EnvoyDevice extends EventEmitter {
4114
4113
 
4115
4114
  // Create characteristics energy meter
4116
4115
  const characteristics2 = [
4117
- { type: Characteristic.EvePower, value: obj.power },
4116
+ { type: Characteristic.EvePower, value: power },
4118
4117
  { type: Characteristic.EveEnergyLifetime, value: obj.energyLifetimeKw },
4119
4118
  ];
4120
4119
 
@@ -1,1208 +0,0 @@
1
- import { XMLParser, XMLBuilder, XMLValidator } from 'fast-xml-parser';
2
- import EventEmitter from 'events';
3
- import EnvoyToken from './envoytoken.js';
4
- import ImpulseGenerator from './impulsegenerator.js';
5
- import Functions from './functions.js';
6
- import { ApiUrls, PartNumbers, ApiCodes, MetersKeyMap } from './constants.js';
7
- import fakegato from 'fakegato-history';
8
- let Accessory, Characteristic, Service, Categories, AccessoryUUID;
9
-
10
- class EnergyMeter extends EventEmitter {
11
- constructor(api, log, url, deviceName, device, envoyIdFile, envoyTokenFile, prefDir, energyMeterHistoryFileName) {
12
- super();
13
-
14
- Accessory = api.platformAccessory;
15
- Characteristic = api.hap.Characteristic;
16
- Service = api.hap.Service;
17
- Categories = api.hap.Categories;
18
- AccessoryUUID = api.hap.uuid;
19
-
20
- //device configuration
21
- this.log = log;
22
- this.url = url;
23
- this.name = deviceName;
24
- this.envoyFirmware7xxTokenGenerationMode = device.envoyFirmware7xxTokenGenerationMode;
25
- this.enlightenUser = device.enlightenUser;
26
- this.enlightenPasswd = device.enlightenPasswd;
27
- this.energyProductionLifetimeOffset = device.energyProductionLifetimeOffset || 0;
28
- this.energyConsumptionTotalLifetimeOffset = device.energyConsumptionTotalLifetimeOffset || 0;
29
- this.energyConsumptionNetLifetimeOffset = device.energyConsumptionNetLifetimeOffset || 0;
30
-
31
- //log
32
- this.logDeviceInfo = device.log?.deviceInfo || true;
33
- this.logInfo = device.log?.info || false;
34
- this.logWarn = device.log?.warn || true;
35
- this.logError = device.log?.error || true;
36
- this.logDebug = device.log?.debug || false;
37
-
38
- //setup variables
39
- this.functions = new Functions();
40
- this.envoyTokenFile = envoyTokenFile;
41
- this.checkTokenRunning = false;
42
-
43
- //fakegato
44
- this.fakegatoHistory = fakegato(api);
45
- this.prefDir = prefDir;
46
- this.energyMeterHistoryFileName = energyMeterHistoryFileName;
47
- this.lastReset = 0;
48
-
49
- //supported functions
50
- this.feature = {
51
- info: {
52
- devId: '',
53
- envoyPasswd: '',
54
- installerPasswd: '',
55
- firmware: 500,
56
- tokenRequired: false,
57
- tokenValid: false,
58
- cookie: '',
59
- jwtToken: {
60
- generation_time: 0,
61
- token: device.envoyToken,
62
- expires_at: 0,
63
- installer: this.envoyFirmware7xxTokenGenerationMode === 2 ? device.envoyTokenInstaller : false
64
- }
65
- },
66
- meters: {
67
- supported: false,
68
- installed: false,
69
- count: 0,
70
- production: {
71
- supported: false,
72
- enabled: false
73
- },
74
- consumptionNet: {
75
- supported: false,
76
- enabled: false
77
- },
78
- consumptionTotal: {
79
- supported: false,
80
- enabled: false
81
- },
82
- storage: {
83
- supported: false,
84
- enabled: false
85
- },
86
- backfeed: {
87
- supported: false,
88
- enabled: false
89
- },
90
- load: {
91
- supported: false,
92
- enabled: false
93
- },
94
- evse: {
95
- supported: false,
96
- enabled: false
97
- },
98
- pv3p: {
99
- supported: false,
100
- enabled: false
101
- },
102
- generator: {
103
- supported: false,
104
- enabled: false
105
- },
106
- detailedData: {
107
- supported: false
108
- },
109
- },
110
- metersReading: {
111
- supported: false,
112
- installed: false
113
- },
114
- metersReports: {
115
- supported: false,
116
- installed: false
117
- },
118
- production: {
119
- supported: false
120
- },
121
- productionPdm: {
122
- supported: false,
123
- pcu: {
124
- supported: false
125
- },
126
- eim: {
127
- supported: false
128
- },
129
- rgm: {
130
- supported: false
131
- },
132
- pmu: {
133
- supported: false
134
- }
135
- },
136
- energyPdm: {
137
- supported: false,
138
- production: {
139
- supported: false,
140
- pcu: {
141
- supported: false
142
- },
143
- eim: {
144
- supported: false
145
- },
146
- rgm: {
147
- supported: false
148
- },
149
- pmu: {
150
- supported: false
151
- }
152
- },
153
- comsumptionNet: {
154
- supported: false
155
- },
156
- consumptionTotal: {
157
- supported: false
158
- }
159
- },
160
- productionCt: {
161
- supported: false,
162
- production: {
163
- supported: false,
164
- pcu: {
165
- supported: false
166
- },
167
- eim: {
168
- supported: false
169
- }
170
- },
171
- consumptionNet: {
172
- supported: false
173
- },
174
- consumptionTotal: {
175
- supported: false
176
- },
177
- storage: {
178
- supported: false
179
- }
180
- },
181
- powerAndEnergyData: {
182
- supported: false
183
- }
184
- };
185
-
186
- //pv object
187
- this.pv = {
188
- info: {},
189
- meters: [],
190
- powerAndEnergy: {
191
- data: [],
192
- production: {
193
- pcu: {},
194
- eim: {},
195
- rgm: {},
196
- pmu: {},
197
- },
198
- consumptionNet: {},
199
- consumptionTotal: {},
200
- },
201
- };
202
-
203
- //lock flags
204
- this.locks = {
205
- updatePowerAndEnergy: false
206
- };
207
-
208
- //impulse generator
209
- this.impulseGenerator = new ImpulseGenerator()
210
- .on('updatePowerAndEnergy', () => this.handleWithLock('updatePowerAndEnergy', async () => {
211
- if (this.feature.meters.supported) {
212
- await this.updateMeters();
213
- if (this.feature.metersReading.installed && !this.feature.metersReports.installed) await this.updateMetersReading(false);
214
- if (this.feature.metersReports.installed) await this.updateMetersReports(false);
215
- }
216
-
217
- if (this.feature.production.supported) await this.updateProduction();
218
- if (this.feature.productionPdm.supported && !this.feature.energyPdm.supported) await this.updateProductionPdm();
219
- if (this.feature.energyPdm.supported) await this.updateEnergyPdm();
220
- if (this.feature.productionCt.supported) await this.updateProductionCt();
221
- await this.updatePowerAndEnergyData();
222
- }))
223
- .on('state', (state) => {
224
- this.emit(state ? 'success' : 'warn', `Impulse generator ${state ? 'started' : 'stopped'}`);
225
- });
226
- }
227
-
228
- handleError(error) {
229
- const errorString = error.toString();
230
- const tokenNotValid = errorString.includes('status code 401');
231
- if (tokenNotValid) {
232
- if (this.checkTokenRunning) return;
233
-
234
- this.feature.info.jwtToken.token = '';
235
- this.feature.tokenValid = false;
236
- return;
237
- }
238
- if (this.logError) this.emit('error', `Impulse generator: ${error}`);
239
- }
240
-
241
- async startStopImpulseGenerator(state) {
242
- try {
243
- //start impulse generator
244
- const timers = state ? this.timers : [];
245
- await this.impulseGenerator.state(state, timers)
246
- return true;
247
- } catch (error) {
248
- throw new Error(`Impulse generator start error: ${error}`);
249
- }
250
- }
251
-
252
- async handleWithLock(lockKey, fn) {
253
- if (this.locks[lockKey]) return;
254
-
255
- const tokenValid = await this.checkToken();
256
- if (!tokenValid) return;
257
-
258
- this.locks[lockKey] = true;
259
- try {
260
- await fn();
261
- } catch (error) {
262
- this.handleError(error);
263
- } finally {
264
- this.locks[lockKey] = false;
265
- }
266
- }
267
-
268
- async getInfo() {
269
- if (this.logDebug) this.emit('debug', 'Requesting info');
270
-
271
- try {
272
- const response = await this.axiosInstance.get(ApiUrls.GetInfo);
273
- const xmlString = response.data;
274
-
275
- // XML Parsing options
276
- const options = {
277
- ignoreAttributes: false,
278
- ignorePiTags: true,
279
- allowBooleanAttributes: true
280
- };
281
- const parser = new XMLParser(options);
282
- const parsed = parser.parse(xmlString);
283
-
284
- // Defensive structure checks
285
- const envoyInfo = parsed.envoy_info ?? {};
286
- const device = envoyInfo.device ?? {};
287
- const buildInfo = envoyInfo.build_info ?? {};
288
-
289
- // Masked debug version
290
- const debugParsed = {
291
- ...parsed,
292
- envoy_info: {
293
- ...envoyInfo,
294
- device: {
295
- ...device,
296
- sn: 'removed'
297
- }
298
- }
299
- };
300
-
301
- if (this.logDebug) this.emit('debug', 'Parsed info:', debugParsed);
302
-
303
- const serialNumber = device.sn?.toString() ?? null;
304
- if (!serialNumber) {
305
- if (this.logWarn) this.emit('warn', 'Envoy serial number missing!');
306
- return null;
307
- }
308
-
309
- // Construct info object
310
- const obj = {
311
- time: envoyInfo.time,
312
- serialNumber,
313
- partNumber: device.pn,
314
- modelName: PartNumbers[device.pn] ?? device.pn,
315
- software: device.software,
316
- euaid: device.euaid,
317
- seqNum: device.seqnum,
318
- apiVer: device.apiver,
319
- imeter: !!device.imeter,
320
- webTokens: !!envoyInfo['web-tokens'],
321
- packages: envoyInfo.package ?? [],
322
- buildInfo: {
323
- buildId: buildInfo.build_id,
324
- buildTimeQmt: buildInfo.build_time_gmt,
325
- releaseVer: buildInfo.release_ver,
326
- releaseStage: buildInfo.release_stage
327
- }
328
- };
329
-
330
- this.pv.info = obj;
331
-
332
- // Feature: meters
333
- this.feature.meters.supported = obj.imeter;
334
-
335
- // Feature: firmware version
336
- const cleanedVersion = obj.software?.replace(/\D/g, '') ?? '';
337
- const parsedFirmware = cleanedVersion ? parseInt(cleanedVersion.slice(0, 3)) : 500;
338
- this.feature.info.firmware = parsedFirmware;
339
- this.feature.info.tokenRequired = obj.webTokens;
340
-
341
- return true;
342
- } catch (error) {
343
- throw new Error(`Update info error: ${error}`);
344
- }
345
- }
346
-
347
- async checkToken(start) {
348
- if (this.logDebug) this.emit('debug', 'Requesting check token');
349
-
350
- if (this.checkTokenRunning) {
351
- if (this.logDebug) this.emit('debug', 'Token check already running');
352
- return null;
353
- }
354
-
355
- if (!this.feature.info.tokenRequired) {
356
- if (this.logDebug) this.emit('debug', 'Token not required, skipping token check');
357
- return true;
358
- }
359
-
360
- this.checkTokenRunning = true;
361
- try {
362
- const now = Math.floor(Date.now() / 1000);
363
-
364
- // Load token from file on startup, only if mode is 1
365
- if (this.envoyFirmware7xxTokenGenerationMode === 1 && start) {
366
- try {
367
- const data = await this.functions.readData(this.envoyTokenFile);
368
- try {
369
- const parsedData = JSON.parse(data);
370
- const fileTokenExist = parsedData.token ? 'Exist' : 'Missing';
371
- if (this.logDebug) this.emit('debug', `Token from file: ${fileTokenExist}`);
372
- if (parsedData.token) {
373
- this.feature.info.jwtToken = parsedData;
374
- }
375
- } catch (error) {
376
- if (this.logWarn) this.emit('warn', `Token parse error: ${error}`);
377
- }
378
- } catch (error) {
379
- if (this.logWarn) this.emit('warn', `Read Token from file error: ${error}`);
380
- }
381
- }
382
-
383
- const jwt = this.feature.info.jwtToken || {};
384
- const tokenExist = jwt.token && (this.envoyFirmware7xxTokenGenerationMode === 2 || jwt.expires_at >= now + 60);
385
-
386
- if (this.logDebug) {
387
- const remaining = jwt.expires_at ? jwt.expires_at - now : 'N/A';
388
- this.emit('debug', `Token: ${tokenExist ? 'Exist' : 'Missing'}, expires in ${remaining} seconds`);
389
- }
390
-
391
- const tokenValid = this.feature.info.tokenValid;
392
- if (this.logDebug) this.emit('debug', `Token: ${tokenValid ? 'Valid' : 'Not valid'}`);
393
-
394
- if (tokenExist && tokenValid) {
395
- if (this.logDebug) this.emit('debug', 'Token check complete, state: Valid');
396
- return true;
397
- }
398
-
399
- if (!tokenExist) {
400
- if (this.logWarn) this.emit('warn', 'Token not exist, requesting new');
401
- await this.delayBeforeRetry?.() ?? new Promise(resolve => setTimeout(resolve, 30000));
402
- const gotToken = await this.getToken();
403
- if (!gotToken) return null;
404
- }
405
-
406
- if (!this.feature.info.jwtToken.token) {
407
- if (this.logWarn) this.emit('warn', 'Token became invalid before validation');
408
- return null;
409
- }
410
-
411
- if (this.logWarn) this.emit('warn', 'Token exist but not valid, validating');
412
- const validated = await this.validateToken();
413
- if (!validated) return null;
414
-
415
- if (this.logDebug) this.emit('debug', 'Token check complete: Valid=true');
416
- return true;
417
- } catch (error) {
418
- throw new Error(`Check token error: ${error}`);
419
- } finally {
420
- this.checkTokenRunning = false;
421
- }
422
- }
423
-
424
- async getToken() {
425
- if (this.logDebug) this.emit('debug', 'Requesting token');
426
-
427
- try {
428
- // Create EnvoyToken instance and attach log event handlers
429
- const envoyToken = new EnvoyToken({
430
- user: this.enlightenUser,
431
- passwd: this.enlightenPasswd,
432
- serialNumber: this.pv.info.serialNumber,
433
- logWarn: this.logWarn,
434
- logError: this.logError,
435
- })
436
- .on('success', message => this.emit('success', message))
437
- .on('warn', warn => this.emit('warn', warn))
438
- .on('error', error => this.emit('error', error));
439
-
440
- // Attempt to refresh token
441
- const tokenData = await envoyToken.refreshToken();
442
-
443
- if (!tokenData || !tokenData.token) {
444
- if (this.logWarn) this.emit('warn', 'Token request returned empty or invalid');
445
- return null;
446
- }
447
-
448
- // Mask token in debug output
449
- const maskedTokenData = {
450
- ...tokenData,
451
- token: `${tokenData.token.slice(0, 5)}...<redacted>`
452
- };
453
- if (this.logDebug) this.emit('debug', 'Token:', maskedTokenData);
454
-
455
- // Save token in memory
456
- this.feature.info.jwtToken = tokenData;
457
-
458
- // Persist token to disk
459
- try {
460
- await this.functions.saveData(this.envoyTokenFile, tokenData);
461
- } catch (error) {
462
- if (this.logError) this.emit('error', `Save token error: ${error}`);
463
- }
464
-
465
- return true;
466
- } catch (error) {
467
- throw new Error(`Get token error: ${error}`);
468
- }
469
- }
470
-
471
- async validateToken() {
472
- if (this.logDebug) this.emit('debug', 'Requesting validate token');
473
-
474
- this.feature.info.tokenValid = false;
475
-
476
- try {
477
- const jwt = this.feature.info.jwtToken;
478
-
479
- // Create a token-authenticated Axios instance
480
- const axiosInstance = this.functions.createAxiosInstance(this.url, `Bearer ${jwt.token}`, null);
481
-
482
- // Send validation request
483
- const response = await axiosInstance.get(ApiUrls.CheckJwt);
484
- const responseBody = response.data;
485
-
486
- // Check for expected response string
487
- const tokenValid = typeof responseBody === 'string' && responseBody.includes('Valid token');
488
- if (!tokenValid) {
489
- if (this.logWarn) this.emit('warn', `Token not valid. Response: ${responseBody}`);
490
- return null;
491
- }
492
-
493
- // Extract and validate cookie
494
- const cookie = response.headers['set-cookie'];
495
- if (!cookie) {
496
- if (this.logWarn) this.emit('warn', 'No cookie received during token validation');
497
- return null;
498
- }
499
-
500
- // Replace axios instance with cookie-authenticated one
501
- this.axiosInstance = this.functions.createAxiosInstance(this.url, null, cookie);
502
-
503
- // Update internal state
504
- this.feature.info.tokenValid = true;
505
- this.feature.info.cookie = cookie;
506
-
507
- this.emit('success', 'Token validate success');
508
- return true;
509
- } catch (error) {
510
- this.feature.info.tokenValid = false;
511
- throw new Error(`Validate token error: ${error}`);
512
- }
513
- }
514
-
515
- async updateMeters() {
516
- if (this.logDebug) this.emit('debug', `Requesting meters info`);
517
-
518
- try {
519
- const response = await this.axiosInstance.get(ApiUrls.InternalMeterInfo);
520
- const responseData = response.data;
521
- if (this.logDebug) this.emit('debug', `Meters:`, responseData);
522
-
523
- // Check if any meters are installed
524
- const metersInstalled = responseData.length > 0;
525
- if (metersInstalled) {
526
- const arr = [];
527
- for (const meter of responseData) {
528
- const key = MetersKeyMap[meter.measurementType];
529
- if (!key) {
530
- if (this.logDebug) this.emit('debug', `Unknown meter measurement type: ${meter.measurementType}`);
531
- continue;
532
- }
533
-
534
- const phaseModeCode = ApiCodes[meter.phaseMode];
535
- const meteringStatusCode = ApiCodes[meter.meteringStatus];
536
- const voltageDivide = meter.phaseMode === 'split' ? 2 : meter.phaseMode === 'three' ? 3 : 1;
537
- const powerFactorDivide = meter.phaseMode === 'split' ? 2 : 1;
538
-
539
- const obj = {
540
- eid: meter.eid,
541
- type: 'eim',
542
- activeCount: 1,
543
- measurementType: meter.measurementType,
544
- state: meter.state === 'enabled',
545
- phaseMode: phaseModeCode,
546
- phaseCount: meter.phaseCount ?? 1,
547
- meteringStatus: meteringStatusCode,
548
- statusFlags: meter.statusFlags,
549
- voltageDivide: voltageDivide,
550
- powerFactorDivide: powerFactorDivide,
551
- };
552
- arr.push(obj);
553
-
554
- this.feature.meters[key].supported = true;
555
- this.feature.meters[key].enabled = obj.state;
556
- }
557
- this.pv.meters = arr;
558
- this.feature.meters.installed = arr.some(m => m.state);
559
- this.feature.meters.count = arr.length;
560
- }
561
-
562
- //meters supported
563
- this.feature.meters.supported = true;
564
-
565
- return true;
566
- } catch (error) {
567
- throw new Error(`Update meters error: ${error}`);
568
- }
569
- }
570
-
571
- async updateMetersReading(start) {
572
- if (this.logDebug) this.emit('debug', `Requesting meters reading`);
573
-
574
- try {
575
- const response = await this.axiosInstance.get(ApiUrls.InternalMeterReadings);
576
- const responseData = response.data;
577
- if (this.logDebug) this.emit('debug', `Meters reading:`, responseData);
578
-
579
- // Check if readings exist and are valid
580
- const metersReadingInstalled = Array.isArray(responseData) && responseData.length > 0;
581
- if (metersReadingInstalled) {
582
- for (const meter of responseData) {
583
- const meterConfig = this.pv.meters.find(m => m.eid === meter.eid && m.state === true);
584
- if (!meterConfig) continue;
585
-
586
- const obj = {
587
- readingTime: meter.timestamp,
588
- power: meter.activePower,
589
- apparentPower: meter.apparentPower,
590
- reactivePower: meter.reactivePower,
591
- energyLifetime: meter.actEnergyDlvd,
592
- energyLifetimeUpload: meter.actEnergyRcvd,
593
- apparentEnergy: meter.apparentEnergy,
594
- current: meter.current,
595
- voltage: meter.voltage / meterConfig.voltageDivide,
596
- pwrFactor: meter.pwrFactor / meterConfig.powerFactorDivide,
597
- frequency: meter.freq,
598
- channels: meter.channels ?? [],
599
- };
600
- Object.assign(meterConfig, obj);
601
- }
602
- this.feature.metersReading.installed = true;
603
- }
604
-
605
- //meters readings supported
606
- this.feature.metersReading.supported = true;
607
-
608
- return true;
609
- } catch (error) {
610
- if (start) {
611
- if (this.logWarn) this.emit('warn', `Meters readings not supported, dont worry all working correct, only some additional data will not be present, error: ${error}`);
612
- return null;
613
- }
614
- throw new Error(`Update meters reading error: ${error}`);
615
- }
616
- }
617
-
618
- async updateMetersReports(start) {
619
- if (this.logDebug) this.emit('debug', `Requesting meters reports`);
620
-
621
- try {
622
- const response = await this.axiosInstance.get(ApiUrls.InternalMetersReports);
623
- const responseData = response.data;
624
- if (this.logDebug) this.emit('debug', `Meters reports:`, responseData);
625
-
626
- // Check if reports exist
627
- const metersReportsInstalled = Array.isArray(responseData) && responseData.length > 0;
628
- if (metersReportsInstalled) {
629
- for (const meter of responseData) {
630
- const key = MetersKeyMap[meter.reportType];
631
- if (!key) {
632
- if (!this.logDebug) this.emit('debug', `Unknown meters reports type: ${meter.reportType}`);
633
- continue;
634
- }
635
-
636
- const meterConfig = key === 'consumptionTotal' ? this.pv.meters.find(m => m.measurementType === 'net-consumption' && m.state === true) : this.pv.meters.find(m => m.measurementType === meter.reportType && m.state === true);
637
- if (!meterConfig) continue;
638
-
639
- const cumulative = meter.cumulative;
640
- const obj = {
641
- readingTime: meter.createdAt,
642
- power: cumulative.actPower,
643
- apparentPower: cumulative.apprntPwr,
644
- reactivePower: cumulative.reactPwr,
645
- energyLifetime: cumulative.whDlvdCum,
646
- energyLifetimeUpload: cumulative.whRcvdCum,
647
- apparentEnergy: cumulative.vahCum,
648
- current: cumulative.rmsCurrent,
649
- voltage: cumulative.rmsVoltage / meterConfig.voltageDivide,
650
- pwrFactor: cumulative.pwrFactor / meterConfig.powerFactorDivide,
651
- frequency: cumulative.freqHz,
652
- channels: meter.lines ?? [],
653
- };
654
-
655
- // Handle each meter type
656
- switch (key) {
657
- case 'consumptionTotal':
658
- const obj1 = {
659
- eid: meterConfig.eid,
660
- type: meterConfig.type,
661
- activeCount: meterConfig.activeCount,
662
- measurementType: 'total-consumption',
663
- readingTime: meterConfig.readingTime,
664
- state: meterConfig.state,
665
- phaseMode: meterConfig.phaseMode,
666
- phaseCount: meterConfig.phaseCount,
667
- meteringStatus: meterConfig.meteringStatus,
668
- statusFlags: meterConfig.statusFlags,
669
- voltageDivide: meterConfig.voltageDivide,
670
- powerFactorDivide: meterConfig.powerFactorDivide,
671
- };
672
- this.pv.meters = [...this.pv.meters, { ...obj1, ...obj }];
673
- this.feature.meters[key].supported = true;
674
- this.feature.meters[key].enabled = true;
675
- break;
676
- default:
677
- Object.assign(meterConfig, obj);
678
- break;
679
- }
680
- }
681
- this.feature.metersReports.installed = true;
682
- }
683
-
684
- //meters reports supported
685
- this.feature.metersReports.supported = true;
686
-
687
- return true;
688
- } catch (error) {
689
- if (start) {
690
- if (this.logWarn) this.emit('warn', `Meters reports not supported, dont worry all working correct, only some additional data will not be present, error: ${error}`);
691
- return null;
692
- }
693
- throw new Error(`Update meters reports error: ${error}`);
694
- }
695
- }
696
-
697
- async updateProduction() {
698
- if (this.logDebug) this.emit('debug', `Requesting production`);
699
-
700
- try {
701
- const response = await this.axiosInstance.get(ApiUrls.Production);
702
- const production = response.data;
703
- if (this.logDebug) this.emit('debug', `Production:`, production);
704
-
705
- const productionSupported = Object.keys(production).length > 0;
706
- if (productionSupported) {
707
- const readingTime = this.functions.formatTimestamp();
708
- const obj = {
709
- type: 'pcu',
710
- activeCount: this.feature.inventory.pcus.count,
711
- measurementType: 'production',
712
- readingTime,
713
- power: production.wattsNow,
714
- energyToday: production.wattHoursToday,
715
- energyLastSevenDays: production.wattHoursSevenDays,
716
- energyLifetime: production.wattHoursLifetime
717
- };
718
-
719
- this.pv.powerAndEnergy.production.pcu = obj;
720
- this.feature.production.supported = true;
721
- }
722
-
723
- return true;
724
- } catch (error) {
725
- throw new Error(`Update production error: ${error}`);
726
- }
727
- }
728
-
729
- async updateProductionPdm() {
730
- if (this.logDebug) this.emit('debug', `Requesting production pdm`);
731
-
732
- try {
733
- const response = await this.axiosInstance.get(ApiUrls.ProductionPdm);
734
- const data = response.data;
735
- if (this.logDebug) this.emit('debug', `Production pdm:`, data);
736
-
737
- const readingTime = this.functions.formatTimestamp();
738
-
739
- // PCU
740
- const pcu = {
741
- type: 'pcu',
742
- measurementType: 'production',
743
- activeCount: this.feature.inventory?.pcus?.count,
744
- readingTime,
745
- power: data.watts_now_pcu,
746
- energyToday: data.joules_today_pcu / 3600,
747
- energyLastSevenDays: data.pcu_joules_seven_days / 3600,
748
- energyLifetime: data.joules_lifetime_pcu / 3600
749
- };
750
- this.pv.powerAndEnergy.production.pcu = pcu;
751
- this.feature.productionPdm.pcu.supported = pcu.power > 0;
752
-
753
- // EIM
754
- const eimActive = !!data.there_is_an_active_eim;
755
- const eim = {
756
- type: 'eim',
757
- measurementType: 'production',
758
- activeCount: 1,
759
- readingTime,
760
- active: eimActive,
761
- power: data.watts_now_eim,
762
- energyToday: data.watt_hours_today_eim?.aggregate,
763
- energyLastSevenDays: data.eim_watt_hours_seven_days?.aggregate,
764
- energyLifetime: data.watt_hours_lifetime_eim?.aggregate
765
- };
766
- this.pv.powerAndEnergy.production.eim = eim;
767
- this.feature.productionPdm.eim.supported = eimActive;
768
-
769
- // RGM
770
- const rgmActive = !!data.there_is_an_active_rgm;
771
- const rgm = {
772
- type: 'rgm',
773
- measurementType: 'production',
774
- activeCount: 1,
775
- readingTime,
776
- active: rgmActive,
777
- power: data.watts_now_rgm,
778
- energyToday: data.watt_hours_today_rgm,
779
- energyLastSevenDays: data.rgm_watt_hours_seven_days,
780
- energyLifetime: data.watt_hours_lifetime_rgm
781
- };
782
- this.pv.powerAndEnergy.production.rgm = rgm;
783
- this.feature.productionPdm.rgm.supported = rgmActive;
784
-
785
- // PMU
786
- const pmuActive = !!data.there_is_an_active_pmu;
787
- const pmu = {
788
- type: 'pmu',
789
- measurementType: 'production',
790
- activeCount: 1,
791
- readingTime,
792
- active: pmuActive,
793
- power: data.watts_now_pmu,
794
- energyToday: data.watt_hours_today_pmu,
795
- energyLastSevenDays: data.pmu_watt_hours_seven_days,
796
- energyLifetime: data.watt_hours_lifetime_pmu
797
- };
798
- this.pv.powerAndEnergy.production.pmu = pmu;
799
- this.feature.productionPdm.pmu.supported = pmuActive;
800
-
801
- // Mark as supported
802
- this.feature.productionPdm.supported = true;
803
-
804
- return true;
805
- } catch (error) {
806
- throw new Error(`Update production pdm error: ${error}`);
807
- }
808
- }
809
-
810
- async updateEnergyPdm() {
811
- if (this.logDebug) this.emit('debug', `Requesting energy pdm`);
812
-
813
- try {
814
- const response = await this.axiosInstance.get(ApiUrls.EnergyPdm);
815
- const energyPdm = response.data;
816
- if (this.logDebug) this.emit('debug', `Energy pdm: `, energyPdm);
817
-
818
- const readingTime = this.functions.formatTimestamp();
819
-
820
- // Process production data
821
- if ('production' in energyPdm && energyPdm.production) {
822
- for (const [type, data] of Object.entries(energyPdm.production)) {
823
- if (data) {
824
- const obj = {
825
- type,
826
- activeCount: 1,
827
- measurementType: 'production',
828
- readingTime,
829
- power: data.wattsNow,
830
- energyToday: data.wattHoursToday,
831
- energyLastSevenDays: data.wattHoursSevenDays,
832
- energyLifetime: data.wattHoursLifetime
833
- };
834
- this.pv.powerAndEnergy.production[type] = obj;
835
- this.feature.energyPdm.production[type].supported = true;
836
- }
837
- }
838
- this.feature.energyPdm.production.supported = true;
839
- }
840
-
841
- // Process consumption data
842
- if ('consumption' in energyPdm && energyPdm.consumption?.eim) {
843
- const data = energyPdm.consumption.eim;
844
- const obj = {
845
- type: 'eim',
846
- activeCount: 1,
847
- measurementType: 'net-consumption',
848
- readingTime,
849
- power: data.wattsNow,
850
- energyToday: data.wattHoursToday,
851
- energyLastSevenDays: data.wattHoursSevenDays,
852
- energyLifetime: data.wattHoursLifetime
853
- };
854
- Object.assign(this.pv.powerAndEnergy.consumptionNet, obj);
855
- this.feature.energyPdm.comsumptionNet.supported = true;
856
- }
857
-
858
- this.feature.energyPdm.supported = true;
859
-
860
- return true;
861
- } catch (error) {
862
- throw new Error(`Update energy pdm error: ${error}`);
863
- }
864
- }
865
-
866
- async updateProductionCt() {
867
- if (this.logDebug) this.emit('debug', `Requesting production ct`);
868
-
869
- try {
870
- const response = await this.axiosInstance.get(ApiUrls.SystemReadingStats);
871
- const data = response.data;
872
- if (this.logDebug) this.emit('debug', `Production ct:`, data);
873
-
874
- const keys = Object.keys(data);
875
-
876
- // --- Production: PCU ---
877
- if (keys.includes('production') && Array.isArray(data.production)) {
878
- const productionPcu = data.production[0];
879
- if (productionPcu) {
880
- this.feature.productionCt.production.pcu.supported = true;
881
- }
882
-
883
- const productionEim = data.production[1];
884
- if (productionEim) {
885
- const energyToday = (productionEim.lines[0]?.whToday || 0) + (productionEim.lines[1]?.whToday || 0) + (productionEim.lines[2]?.whToday || 0);
886
- const energyLastSevenDays = (productionEim.lines[0]?.whLastSevenDays || 0) + (productionEim.lines[1]?.whLastSevenDays || 0) + (productionEim.lines[2]?.whLastSevenDays || 0);
887
- const energyLifetime = (productionEim.lines[0]?.whLifetime || 0) + (productionEim.lines[1]?.whLifetime || 0) + (productionEim.lines[2]?.whLifetime || 0);
888
- const obj = {
889
- type: 'eim',
890
- activeCount: 1,
891
- measurementType: productionEim.measurementType,
892
- readingTime: productionEim.readingTime,
893
- power: productionEim.wNow,
894
- energyToday,
895
- energyLastSevenDays,
896
- energyLifetime,
897
- reactivePower: productionEim.reactPwr,
898
- apparentPower: productionEim.apprntPwr,
899
- current: productionEim.rmsCurrent,
900
- voltage: productionEim.rmsVoltage,
901
- pwrFactor: productionEim.pwrFactor
902
- };
903
- this.pv.powerAndEnergy.production.eim = obj;
904
- this.feature.productionCt.production.eim.supported = true;
905
- }
906
- }
907
-
908
- // --- Consumption: EIM ---
909
- if (keys.includes('consumption') && Array.isArray(data.consumption) && this.feature.meters.consumptionNet.enabled) {
910
- for (const item of data.consumption) {
911
- const key = MetersKeyMap[item.measurementType];
912
- const energyToday = (item.lines[0]?.whToday || 0) + (item.lines[1]?.whToday || 0) + (item.lines[2]?.whToday || 0);
913
- const energyLastSevenDays = (item.lines[0]?.whLastSevenDays || 0) + (item.lines[1]?.whLastSevenDays || 0) + (item.lines[2]?.whLastSevenDays || 0);
914
- const energyLifetime = (item.lines[0]?.whLifetime || 0) + (item.lines[1]?.whLifetime || 0) + (item.lines[2]?.whLifetime || 0);
915
- const obj = {
916
- type: 'eim',
917
- measurementType: item.measurementType,
918
- activeCount: 1,
919
- readingTime: item.readingTime,
920
- power: item.wNow,
921
- energyToday,
922
- energyLastSevenDays,
923
- energyLifetime,
924
- reactivePower: item.reactPwr,
925
- apparentPower: item.apprntPwr,
926
- current: item.rmsCurrent,
927
- voltage: item.rmsVoltage,
928
- pwrFactor: item.pwrFactor
929
- };
930
- Object.assign(this.pv.powerAndEnergy[key], obj);
931
- this.feature.productionCt[key].supported = true;
932
- }
933
- }
934
-
935
- // --- Finalize ---
936
- this.feature.productionCt.supported = true;
937
-
938
- return true;
939
- } catch (error) {
940
- throw new Error(`Update production ct error: ${error}`);
941
- }
942
- }
943
-
944
- async updatePowerAndEnergyData() {
945
- if (this.logDebug) this.emit('debug', `Requesting power and energy data`);
946
-
947
- try {
948
- const powerAndEnergy = [];
949
- const powerAndEnergyTypeArr = [
950
- { type: 'production', state: this.feature.meters.production.enabled },
951
- { type: 'net-consumption', state: this.feature.meters.consumptionNet.enabled },
952
- { type: 'total-consumption', state: this.feature.meters.consumptionTotal.enabled }
953
- ];
954
-
955
- for (const [index, data] of powerAndEnergyTypeArr.entries()) {
956
- const { type: meterType, state: meterEnabled } = data;
957
- if (meterType !== 'production' && !meterEnabled) continue;
958
-
959
- const key = MetersKeyMap[meterType];
960
- const measurementType = ApiCodes[meterType];
961
-
962
- let sourceMeter, sourceEnergy;
963
- let power, energyLifetime, energyLifetimeWithOffset;
964
- switch (key) {
965
- case 'production': {
966
- const sourcePcu = this.pv.powerAndEnergy[key].pcu;
967
- const sourceEim = this.pv.powerAndEnergy[key].eim;
968
- sourceMeter = meterEnabled ? this.pv.meters.find(m => m.measurementType === 'production') : sourcePcu;
969
- sourceEnergy = meterEnabled ? sourceEim : sourcePcu;
970
- power = this.functions.isValidValue(sourceMeter.power) && sourceMeter.power >= 0 ? sourceMeter.power : 0;
971
- energyLifetime = this.functions.isValidValue(sourceMeter.energyLifetime) ? sourceMeter.energyLifetime / 1000 : null;
972
- energyLifetimeWithOffset = this.functions.isValidValue(energyLifetime) ? energyLifetime + this.energyProductionLifetimeOffset : null;
973
- break;
974
- }
975
- case 'consumptionNet': {
976
- sourceMeter = this.pv.meters.find(m => m.measurementType === 'net-consumption');
977
- sourceEnergy = this.pv.powerAndEnergy.consumptionNet;
978
- power = this.functions.isValidValue(sourceMeter.power) && sourceMeter.power >= 0 ? sourceMeter.power : 0;
979
- energyLifetime = this.functions.isValidValue(sourceMeter.energyLifetime) ? sourceMeter.energyLifetime / 1000 : null;
980
- energyLifetimeWithOffset = this.functions.isValidValue(energyLifetime) ? energyLifetime + this.energyConsumptionNetLifetimeOffset : null;
981
- break;
982
- }
983
- case 'consumptionTotal': {
984
- sourceMeter = this.pv.meters.find(m => m.measurementType === 'total-consumption');
985
- sourceEnergy = this.pv.powerAndEnergy.consumptionTotal;
986
- power = this.functions.isValidValue(sourceMeter.power) && sourceMeter.power >= 0 ? sourceMeter.power : 0;
987
- energyLifetime = this.functions.isValidValue(sourceMeter.energyLifetime) ? sourceMeter.energyLifetime / 1000 : null;
988
- energyLifetimeWithOffset = this.functions.isValidValue(energyLifetime) ? energyLifetime + this.energyConsumptionTotalLifetimeOffset : null;
989
- break;
990
- }
991
- }
992
-
993
- if (!sourceMeter) continue;
994
- if (this.logDebug) {
995
- this.emit('debug', `${measurementType} data source meter:`, sourceMeter);
996
- this.emit('debug', `${measurementType} data source energy:`, sourceEnergy);
997
- }
998
-
999
- if (key === 'production') {
1000
- const type = ApiCodes[sourceMeter.type] ?? sourceMeter.type;
1001
- const obj = {
1002
- type,
1003
- measurementType,
1004
- power,
1005
- energyLifetimeWithOffset,
1006
- gridQualityState: meterEnabled,
1007
- };
1008
-
1009
- // Add to fakegato history
1010
- this.fakegatoHistoryService?.addEntry({
1011
- time: Math.floor(Date.now() / 1000),
1012
- power: power ?? 0
1013
- });
1014
-
1015
- // Create characteristics energy meter
1016
- const characteristics = [
1017
- { type: Characteristic.EvePower, value: power },
1018
- { type: Characteristic.EveEnergyLifetime, value: energyLifetimeWithOffset },
1019
- ];
1020
-
1021
- // Create characteristics energy meter
1022
- if (meterEnabled) {
1023
- Object.assign(obj, {
1024
- current: sourceMeter.current,
1025
- voltage: sourceMeter.voltage
1026
- });
1027
-
1028
- characteristics.push([
1029
- { type: Characteristic.EveCurrent, value: sourceMeter.current },
1030
- { type: Characteristic.EveVoltage, value: sourceMeter.voltage },
1031
- ]);
1032
- }
1033
-
1034
- // Update characteristics
1035
- for (const { type, value } of characteristics) {
1036
- if (!this.functions.isValidValue(value)) continue;
1037
- this.energyMeterServices?.[index]?.updateCharacteristic(type, value);
1038
- };
1039
-
1040
- powerAndEnergy.push(obj);
1041
- }
1042
- }
1043
-
1044
- this.pv.powerAndEnergy.data = powerAndEnergy.filter(Boolean);
1045
- this.feature.powerAndEnergyData.supported = true;
1046
-
1047
- return true;
1048
- } catch (error) {
1049
- throw new Error(`Update power and energy data error: ${error.message || error}`);
1050
- }
1051
- }
1052
-
1053
- async getDeviceInfo() {
1054
- if (this.logDebug) {
1055
- this.emit('debug', `Requesting device info`);
1056
- this.emit('debug', `Pv object:`, this.pv);
1057
- }
1058
-
1059
- // Device basic info
1060
- this.emit('devInfo', `-------- ${this.name} --------`);
1061
- this.emit('devInfo', `Manufacturer: Enphase`);
1062
- this.emit('devInfo', `Model: ${this.pv.info.modelName}`);
1063
- this.emit('devInfo', `------------------------------`);
1064
- return true;
1065
- }
1066
-
1067
- //prepare accessory
1068
- async prepareAccessory() {
1069
- try {
1070
- if (this.logDebug) this.emit('debug', `Prepare accessory`);
1071
-
1072
- const envoySerialNumber = this.pv.info.serialNumber;
1073
- const accessoryName = `${this.name} ${this.pv.powerAndEnergy.data[0].measurementType}`;
1074
- const accessoryUUID = AccessoryUUID.generate(envoySerialNumber + 'Energy Meter');
1075
- const accessoryCategory = Categories.SENSOR;
1076
- const accessory = new Accessory(accessoryName, accessoryUUID, accessoryCategory);
1077
- accessory.log = this.log;
1078
-
1079
- // Accessory Info Service
1080
- if (this.logDebug) this.emit('debug', `Prepare Information Service`);
1081
- accessory.getService(Service.AccessoryInformation)
1082
- .setCharacteristic(Characteristic.Manufacturer, 'Enphase')
1083
- .setCharacteristic(Characteristic.Model, this.pv.info.modelName ?? 'Model Name')
1084
- .setCharacteristic(Characteristic.SerialNumber, envoySerialNumber ?? 'Serial Number')
1085
- .setCharacteristic(Characteristic.FirmwareRevision, this.pv.info.software?.replace(/[a-zA-Z]/g, '') ?? '0');
1086
-
1087
- // Create FakeGatoHistory
1088
- if (this.logDebug) this.emit('debug', `Prepare Fakegato ${this.pv.powerAndEnergy.data[0].measurementType} Service`);
1089
- this.fakegatoHistoryService = new this.fakegatoHistory(`energy`, accessory, {
1090
- storage: 'fs',
1091
- disableRepeatLastData: true,
1092
- disableTimer: false,
1093
- path: this.prefDir,
1094
- filename: this.energyMeterHistoryFileName
1095
- })
1096
- this.fakegatoHistoryService.addEntry({
1097
- time: Math.floor(Date.now() / 1000),
1098
- power: this.pv.powerAndEnergy.data[0].power ?? 0
1099
- });
1100
-
1101
- // Energy Meter Service
1102
- this.energyMeterServices = [];
1103
- for (const source of this.pv.powerAndEnergy.data) {
1104
- const measurementType = source.measurementType;
1105
-
1106
- if (this.logDebug) this.emit('debug', `Prepare Energy Meter ${measurementType} Service`);
1107
- const energyMeterService = accessory.addService(Service.EvePowerMeter, `Energy Meter ${measurementType}`, `energyMeterService${measurementType}`);
1108
- energyMeterService.setCharacteristic(Characteristic.ConfiguredName, `Energy Meter ${measurementType}`);
1109
-
1110
- // Create characteristics
1111
- const characteristics = [
1112
- { type: Characteristic.EvePower, label: 'power', value: source.power, unit: 'W' },
1113
- { type: Characteristic.EveEnergyLifetime, label: 'energy lifetime', value: source.energyLifetimeWithOffset, unit: 'kWh' },
1114
- ];
1115
-
1116
- if (source.gridQualityState) {
1117
- characteristics.push(
1118
- { type: Characteristic.EveCurrent, label: 'current', value: source.current, unit: 'A' },
1119
- { type: Characteristic.EveVoltage, label: 'voltage', value: source.voltage, unit: 'V' }
1120
- );
1121
- }
1122
-
1123
- for (const { type, label, value, unit = '' } of characteristics) {
1124
- if (!this.functions.isValidValue(value)) continue;
1125
-
1126
- energyMeterService.getCharacteristic(type)
1127
- .onGet(async () => {
1128
- const currentValue = value;
1129
- if (this.logInfo) this.emit('info', `Energy Meter: ${measurementType}, ${label}: ${currentValue} ${unit}`);
1130
- return currentValue;
1131
- });
1132
- }
1133
-
1134
- energyMeterService.getCharacteristic(Characteristic.EveResetTime)
1135
- .onGet(async () => {
1136
- const resetTime = this.lastReset;
1137
- if (this.logInfo) this.emit('info', `${measurementType}, reset time: ${resetTime}`);
1138
- return resetTime;
1139
- })
1140
- .onSet(async (value) => {
1141
- try {
1142
- this.lastReset = value;
1143
- } catch (error) {
1144
- if (this.logWarn) this.emit('warn', `${measurementType}, Reset time error: ${error}`);
1145
- }
1146
- });
1147
-
1148
- this.energyMeterServices.push(energyMeterService);
1149
- }
1150
-
1151
- return accessory;
1152
- } catch (error) {
1153
- throw new Error(`Prepare accessory error: ${error}`);
1154
- }
1155
- }
1156
-
1157
- //start
1158
- async start() {
1159
- if (this.logDebug) this.emit('debug', `Start`);
1160
-
1161
- try {
1162
- // Create axios instance
1163
- this.axiosInstance = this.functions.createAxiosInstance(this.url);
1164
-
1165
- // Get basic PV info
1166
- const getInfo = await this.getInfo();
1167
- if (!getInfo) return null;
1168
-
1169
- const tokenRequired = this.feature.info.tokenRequired;
1170
-
1171
- // Authenticate
1172
- const tokenValid = tokenRequired ? await this.checkToken(true) : true;
1173
- if (tokenRequired && !tokenValid) return null;
1174
-
1175
- // Meters
1176
- const getMeters = this.feature.meters.supported ? await this.updateMeters() : false;
1177
- if (getMeters && this.feature.meters.installed) await this.updateMetersReading(true);
1178
- if (getMeters && this.feature.meters.installed) await this.updateMetersReports(true);
1179
-
1180
- // Production
1181
- if (this.feature.info.firmware < 824) await this.updateProduction();
1182
- if (this.feature.info.firmware >= 824) await this.updateProductionPdm();
1183
- if (this.feature.info.firmware >= 824) await this.updateEnergyPdm();
1184
- if (this.feature.meters.installed) await this.updateProductionCt();
1185
-
1186
- // Data
1187
- const getPowerAndEnergyData = await this.updatePowerAndEnergyData();
1188
-
1189
- // Success message
1190
- this.emit('success', `Connect Success`);
1191
-
1192
- // Optional logging
1193
- if (this.logDeviceInfo) await this.getDeviceInfo();
1194
-
1195
- // Setup timers
1196
- this.timers = [];
1197
- if (getPowerAndEnergyData) this.timers.push({ name: 'updatePowerAndEnergy', sampling: 10000 });
1198
-
1199
- // Prepare HomeKit accessory
1200
- const accessory = await this.prepareAccessory();
1201
- return accessory;
1202
- } catch (error) {
1203
- throw new Error(`Start error: ${error}`);
1204
- }
1205
- }
1206
-
1207
- }
1208
- export default EnergyMeter;