homebridge-enphase-envoy 10.3.1-beta.8 → 10.3.1

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/README.md CHANGED
@@ -23,8 +23,8 @@ The `homebridge-enphase-envoy` plugin integrates Enphase Envoy solar energy moni
23
23
 
24
24
  | Package | Installation | Role | Required |
25
25
  | --- | --- | --- | --- |
26
- | [Homebridge](https://github.com/homebridge/homebridge) | [Homebridge Wiki](https://github.com/homebridge/homebridge/wiki) | HomeKit Bridge | Required |
27
- | [Homebridge UI](https://github.com/homebridge/homebridge-config-ui-x) | [Homebridge UI Wiki](https://github.com/homebridge/homebridge-config-ui-x/wiki) | Homebridge Web User Interface | Recommended |
26
+ | [Homebridge v2.0.0](https://github.com/homebridge/homebridge) | [Homebridge Wiki](https://github.com/homebridge/homebridge/wiki) | HomeKit Bridge | Required |
27
+ | [Homebridge UI <= v5.5.0](https://github.com/homebridge/homebridge-config-ui-x) | [Homebridge UI Wiki](https://github.com/homebridge/homebridge-config-ui-x/wiki) | Homebridge Web User Interface | Required |
28
28
  | [Enphase Envoy](https://www.npmjs.com/package/homebridge-enphase-envoy) | [Plug-In Wiki](https://github.com/grzegorz914/homebridge-enphase-envoy/wiki) | Homebridge Plug-In | Required |
29
29
 
30
30
  ## Supported hardware
@@ -90,7 +90,7 @@ The `homebridge-enphase-envoy` plugin integrates Enphase Envoy solar energy moni
90
90
  ### Configuration
91
91
 
92
92
  * Running this plugin as a [Child Bridge](https://github.com/homebridge/homebridge/wiki/Child-Bridges) is **highly recommended**. This prevents Homebridge from crashing if the plugin crashes.
93
- * Installation and use of [Homebridge UI](https://github.com/homebridge/homebridge-config-ui-x) to configure this plugin is **highly recommended**.
93
+ * Installation and use of [Homebridge UI <= v5.5.0](https://github.com/homebridge/homebridge-config-ui-x) to configure this plugin.
94
94
  * The `sample-config.json` can be edited and used as an alternative for advanced users.
95
95
 
96
96
  <p align="center">
@@ -1432,8 +1432,7 @@
1432
1432
  ]
1433
1433
  }
1434
1434
  ],
1435
- "description": "Accessory type for Home app",
1436
- "required": true
1435
+ "description": "Accessory type for Home app"
1437
1436
  },
1438
1437
  "name": {
1439
1438
  "title": "Accessory name",
@@ -3066,7 +3065,6 @@
3066
3065
  ]
3067
3066
  }
3068
3067
  ],
3069
- "required": true,
3070
3068
  "condition": {
3071
3069
  "functionBody": "return model.devices[arrayIndices[0]].generatorModeControls[arrayIndices[1]].displayType > 0;"
3072
3070
  }
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.3.1-beta.8",
5
+ "version": "10.3.1",
6
6
  "description": "Homebridge p7ugin for Photovoltaic Energy System manufactured by Enphase.",
7
7
  "license": "MIT",
8
8
  "author": "grzegorz914",
@@ -36,7 +36,7 @@
36
36
  },
37
37
  "dependencies": {
38
38
  "async-mqtt": "^2.6.3",
39
- "axios": "^1.12.2",
39
+ "axios": "^1.13.1",
40
40
  "express": "^5.1.0",
41
41
  "fast-xml-parser": "^5.3.0",
42
42
  "fakegato-history": "^0.6.7"
package/src/constants.js CHANGED
@@ -174,13 +174,10 @@ export const ApiCodes = {
174
174
  "ENCHG_STATE_DISCHARGING": "Encharge state discharging",
175
175
  "ENCHG_STATE_IDLE": "Encharge state idle",
176
176
  "ENCHG_STATE_READY": "Encharge state ready",
177
- "ENCMN_MDE_BMU_READY": "Encharge BMU ready",
178
177
  "ENCMN_MDE_ENCHARGE_READY": "Encharge mode ready",
179
178
  "ENCMN_MDE_ON_GRID": "Encharge mode on grid",
180
179
  "ENCMN_MDE_OFF_GRID": "Encharge mode off grid",
181
- "ENCMN_MDE_PCU_READY": "Encharge Microinverter ready",
182
180
  "ENCMN_C6_CC_READY": "C6 Combiner Controller ready",
183
- "ENCMN_C6_RGM_DEV_CONNECTED": "C6 Revenue Grade Meter connected",
184
181
  "ENPOWER": "Enpower",
185
182
  "ENS_DEVICE_STATE_READY": "Ensemble state ready",
186
183
  "ENPWR_STATE_GRIDMODE_CONFIRM": "Enpower state grid mode confirm",
@@ -205,7 +202,6 @@ export const ApiCodes = {
205
202
  "check-wiring": "Check Wiring",
206
203
  "close": "Close",
207
204
  "closed": "Closed",
208
- "configured": "Configured",
209
205
  "connected": "Connected",
210
206
  "consumption": "Consumption Net",
211
207
  "discharging": "Discharging",
@@ -1554,6 +1554,22 @@ export default (api) => {
1554
1554
  }
1555
1555
  Characteristic.EncAggSoc = EncAggSoc;
1556
1556
 
1557
+ class EncAggRatedPower extends Characteristic {
1558
+ constructor() {
1559
+ super('ENC rated power', '00000208-000B-1000-8000-0026BB765291');
1560
+ this.setProps({
1561
+ format: Formats.FLOAT,
1562
+ unit: 'kW',
1563
+ maxValue: 1000,
1564
+ minValue: -1000,
1565
+ minStep: 0.001,
1566
+ perms: [Perms.PAIRED_READ, Perms.NOTIFY]
1567
+ });
1568
+ this.value = this.getDefaultValue();
1569
+ }
1570
+ }
1571
+ Characteristic.EncAggRatedPower = EncAggRatedPower;
1572
+
1557
1573
  class EncAggBackupEnergy extends Characteristic {
1558
1574
  constructor() {
1559
1575
  super('ENC backup energy', '00000209-000B-1000-8000-0026BB765291');
package/src/envoydata.js CHANGED
@@ -338,6 +338,7 @@ class EnvoyData extends EventEmitter {
338
338
  devices: [],
339
339
  settings: {},
340
340
  tariff: {},
341
+ tariffRaw: {},
341
342
  ratedPowerSumKw: null,
342
343
  realPowerSumKw: null,
343
344
  phaseA: false,
@@ -412,7 +413,7 @@ class EnvoyData extends EventEmitter {
412
413
  .on('updateEnsemble', () => this.handleWithLock('updateEnsemble', async () => {
413
414
  const updateEnsemble = this.feature.ensemble.inventory.supported ? await this.updateEnsembleInventory() : false;
414
415
  if (updateEnsemble && this.feature.ensemble.status.supported) await this.updateEnsembleStatus();
415
- if (updateEnsemble && this.feature.ensemble.power.supported) await this.updateEnsemblePower();
416
+ if (updateEnsemble && this.feature.inventory.esubs.encharges.power.supported) await this.updateEnsemblePower();
416
417
 
417
418
  const updateEnchargeSettings = updateEnsemble && this.feature.inventory.esubs.encharges.settings.supported ? await this.updateEnchargesSettings() : false;
418
419
  if (updateEnchargeSettings && this.feature.inventory.esubs.encharges.tariff.supported) await this.updateTariff();
@@ -587,13 +588,12 @@ class EnvoyData extends EventEmitter {
587
588
  // Load token from file on startup, only if mode is 1
588
589
  if (this.envoyFirmware7xxTokenGenerationMode === 1 && start) {
589
590
  try {
590
- const data = await this.functions.readData(this.envoyTokenFile);
591
+ const data = await this.functions.readData(this.envoyTokenFile, true);
591
592
  try {
592
- const parsedData = JSON.parse(data);
593
- const fileTokenExist = parsedData.token ? 'Exist' : 'Missing';
593
+ const fileTokenExist = data.token ? 'Exist' : 'Missing';
594
594
  if (this.logDebug) this.emit('debug', `Token from file: ${fileTokenExist}`);
595
- if (parsedData.token) {
596
- this.feature.info.jwtToken = parsedData;
595
+ if (data.token) {
596
+ this.feature.info.jwtToken = data;
597
597
  }
598
598
  } catch (error) {
599
599
  if (this.logWarn) this.emit('warn', `Token parse error: ${error}`);
@@ -906,18 +906,17 @@ class EnvoyData extends EventEmitter {
906
906
  const home = response.data;
907
907
  if (this.logDebug) this.emit('debug', 'Home:', home);
908
908
 
909
+ const comm = home.comm ?? {};
909
910
  const network = home.network ?? {};
910
- network.interfaces = (network.interfaces ?? []).filter(iface => iface.carrier === true || iface.ip !== '169.254.120.1');
911
- home.wireless_connection = (home.wireless_connection ?? []).filter(kit => kit.signal_strength_max > 0);
911
+ const wirelessConnections = home.wireless_connection ?? [];
912
+ const networkInterfaces = network.interfaces ?? [];
912
913
 
913
914
  // Communication device support flags
914
- const microinvertersSupported = 'pcu' in home.comm;
915
- const acBatteriesSupported = 'acb' in home.comm;
916
- const qRelaysSupported = 'nsrb' in home.comm;
917
- const ensemblesSupported = 'esub' in home.comm;
918
- const enchargesSupported = 'encharge' in home.comm;
919
- const networkInterfacesSupported = 'interfaces' in network;
920
- const wirelessConnectionsSupported = 'wireless_connection' in home;
915
+ const microinvertersSupported = 'pcu' in comm;
916
+ const acBatteriesSupported = 'acb' in comm;
917
+ const qRelaysSupported = 'nsrb' in comm;
918
+ const ensemblesSupported = 'esub' in comm;
919
+ const enchargesSupported = 'encharge' in comm;
921
920
  this.pv.home = home;
922
921
 
923
922
  // Update feature flags
@@ -927,13 +926,13 @@ class EnvoyData extends EventEmitter {
927
926
  this.feature.inventory.esubs.supported = ensemblesSupported;
928
927
  this.feature.inventory.esubs.encharges.supported = enchargesSupported;
929
928
 
930
- this.feature.home.networkInterfaces.supported = networkInterfacesSupported;
931
- this.feature.home.networkInterfaces.installed = network.interfaces.length > 0;
932
- this.feature.home.networkInterfaces.count = network.interfaces.length;
929
+ this.feature.home.networkInterfaces.supported = networkInterfaces.length > 0;
930
+ this.feature.home.networkInterfaces.installed = networkInterfaces.some(i => i.carrier);
931
+ this.feature.home.networkInterfaces.count = networkInterfaces.length;
933
932
 
934
- this.feature.home.wirelessConnections.supported = wirelessConnectionsSupported;
935
- this.feature.home.wirelessConnections.installed = home.wireless_connection.length > 0;
936
- this.feature.home.wirelessConnections.count = home.wireless_connection.length;
933
+ this.feature.home.wirelessConnections.supported = wirelessConnections.length > 0;
934
+ this.feature.home.wirelessConnections.installed = wirelessConnections.some(w => w.connected);
935
+ this.feature.home.wirelessConnections.count = wirelessConnections.length;
937
936
  this.feature.home.supported = true;
938
937
 
939
938
  // RESTful + MQTT
@@ -1963,7 +1962,7 @@ class EnvoyData extends EventEmitter {
1963
1962
  };
1964
1963
 
1965
1964
  // Calculate encharges rated power summary in kW
1966
- this.pv.inventory.esubs.encharges.ratedPowerSumKw = enchargesRatedPowerSummary.length > 0 ? enchargesRatedPowerSummary.reduce((total, num) => total + num, 0) / 1000 : null;
1965
+ this.pv.inventory.esubs.encharges.ratedPowerSumKw = enchargesRatedPowerSummary.length > 0 ? (enchargesRatedPowerSummary.reduce((total, num) => total + num, 0) / enchargesRatedPowerSummary.length) / 1000 : null;
1967
1966
  }
1968
1967
 
1969
1968
  // Update enpowers statuses if installed
@@ -2039,17 +2038,18 @@ class EnvoyData extends EventEmitter {
2039
2038
 
2040
2039
  try {
2041
2040
  const response = await this.axiosInstance.get(ApiUrls.EnsemblePower);
2042
- const responseData = response.data ?? {};
2041
+ const responseData = response.data;
2043
2042
  if (this.logDebug) this.emit('debug', `Ensemble power response:`, responseData);
2044
2043
 
2045
- const devices = responseData.devices || [];
2046
- if (devices.length === 0) return false;
2044
+ const devices = responseData.devices ?? [];
2045
+ if (!devices.length === 0) return false;
2047
2046
 
2048
2047
  // update encharges
2049
2048
  const enchargesRealPowerSummary = [];
2050
2049
  const encharges = this.pv.inventory.esubs.encharges.devices || [];
2051
- for (const encharge of encharges) {
2052
- const device = devices.find(device => device.serial_num === encharge.serialNumber);
2050
+ for (const device of devices) {
2051
+ const serialNumber = device.serial_num;
2052
+ const encharge = encharges.find(device => device.serialNumber === serialNumber);
2053
2053
  if (this.logDebug) this.emit('debug', `Ensemble device power:`, device);
2054
2054
  if (!device) continue;
2055
2055
 
@@ -2060,12 +2060,12 @@ class EnvoyData extends EventEmitter {
2060
2060
  soc: device.soc,
2061
2061
  };
2062
2062
 
2063
- this.feature.inventory.esubs.encharges.power.supported = true;
2064
2063
  if (this.functions.isValidValue(encharge.power.realPower)) enchargesRealPowerSummary.push(encharge.power.realPower);
2064
+ this.feature.inventory.esubs.encharges.power.supported = true;
2065
2065
  }
2066
2066
 
2067
2067
  // Calculate encharges real power summary in kW
2068
- this.pv.inventory.esubs.encharges.realPowerSumKw = enchargesRealPowerSummary.length > 0 ? enchargesRealPowerSummary.reduce((total, num) => total + num, 0) / 1000000 : null;
2068
+ this.pv.inventory.esubs.encharges.realPowerSumKw = enchargesRealPowerSummary.length > 0 ? (enchargesRealPowerSummary.reduce((total, num) => total + num, 0) / enchargesRealPowerSummary.length) / 1000 : null;
2069
2069
 
2070
2070
  // ensemble power supported
2071
2071
  this.feature.ensemble.power.supported = true;
@@ -2091,14 +2091,15 @@ class EnvoyData extends EventEmitter {
2091
2091
  const enchargesSettingsSupported = 'enc_settings' in enchargesSettings;
2092
2092
  if (!enchargesSettingsSupported) return false;
2093
2093
 
2094
- const settings = {
2095
- enable: enchargesSettings.enc_settings.enable, // boolean
2096
- country: enchargesSettings.enc_settings.country, // string
2097
- currentLimit: enchargesSettings.enc_settings.current_limit, // float
2098
- perPhase: enchargesSettings.enc_settings.per_phase // boolean
2094
+ const settings = enchargesSettings.enc_settings;
2095
+ const encharges = this.pv.inventory.esubs.encharges;
2096
+ encharges.settings = {
2097
+ enable: settings.enable, // boolean
2098
+ country: settings.country, // string
2099
+ currentLimit: settings.current_limit, // float
2100
+ perPhase: settings.per_phase // boolean
2099
2101
  };
2100
2102
 
2101
- this.pv.inventory.esubs.encharges.settings = settings;
2102
2103
  this.feature.inventory.esubs.encharges.settings.supported = true;
2103
2104
 
2104
2105
  // RESTFul and MQTT update
@@ -2117,11 +2118,12 @@ class EnvoyData extends EventEmitter {
2117
2118
  try {
2118
2119
  const response = await this.axiosInstance.get(ApiUrls.TariffSettingsGetPut);
2119
2120
  const tariffSettings = response.data;
2121
+
2120
2122
  if (this.logDebug) this.emit('debug', 'Tariff:', tariffSettings);
2121
2123
 
2122
2124
  const enchargesTariffSupported = 'tariff' in tariffSettings;
2123
2125
  if (!enchargesTariffSupported) return false;
2124
-
2126
+ this.pv.inventory.esubs.encharges.tariffRaw = tariffSettings;
2125
2127
  this.pv.inventory.esubs.encharges.tariff = tariffSettings;
2126
2128
  this.feature.inventory.esubs.encharges.tariff.supported = true;
2127
2129
 
@@ -2546,7 +2548,7 @@ class EnvoyData extends EventEmitter {
2546
2548
  if (this.logDebug) this.emit('debug', `Requesting set encharge settings`);
2547
2549
 
2548
2550
  try {
2549
- const tariff = this.pv.inventory.esubs.encharges.tariff.tariff;
2551
+ const tariff = this.pv.inventory.esubs.encharges.tariffRaw.tariff;
2550
2552
  tariff.storage_settings.mode = profile;
2551
2553
  tariff.storage_settings.reserved_soc = reservedSoc;
2552
2554
  tariff.storage_settings.charge_from_grid = chargeFromGrid;
@@ -2772,16 +2774,12 @@ class EnvoyData extends EventEmitter {
2772
2774
  const getEnsemble = tokenRequired && this.feature.inventory.esubs.supported ? await this.updateEnsembleInventory() : false;
2773
2775
  if (getEnsemble) {
2774
2776
  await this.updateEnsembleStatus();
2775
- if (this.feature.inventory.esubs.encharges.installed) {
2776
- await this.updateEnsemblePower();
2777
- await this.updateEnchargesSettings();
2778
- await this.updateTariff();
2779
- }
2777
+ if (this.feature.inventory.esubs.encharges.installed) await this.updateEnsemblePower();
2778
+ const getEnchargeSettings = this.feature.inventory.esubs.encharges.installed ? await this.updateEnchargesSettings() : false;
2779
+ if (getEnchargeSettings) await this.updateTariff();
2780
2780
 
2781
- if (this.feature.inventory.esubs.enpowers.installed) {
2782
- await this.updateDryContacts();
2783
- await this.updateDryContactsSettings();
2784
- }
2781
+ const getDryContacts = this.feature.inventory.esubs.enpowers.installed ? await this.updateDryContacts() : false;
2782
+ if (getDryContacts) await this.updateDryContactsSettings();
2785
2783
 
2786
2784
  const getGenerator = await this.updateGenerator();
2787
2785
  if (getGenerator && this.feature.inventory.esubs.generator.installed) await this.updateGeneratorSettings();
@@ -1988,8 +1988,8 @@ class EnvoyDevice extends EventEmitter {
1988
1988
  }
1989
1989
 
1990
1990
  if (ensemblesCountersSupported) characteristics.push({ type: Characteristic.RestPower, label: 'rest power', value: counters.restPowerKw, unit: 'kW' });
1991
- if (enchargesStatusSupported) characteristics.push({ type: Characteristic.RatedPower, label: 'rated power', value: this.pv.inventoryData.esubs.encharges.ratedPowerSumKw, unit: 'kW' });
1992
- if (enchargesPowerSupported) characteristics.push({ type: Characteristic.RealPower, label: 'real power', value: this.pv.inventoryData.esubs.encharges.realPowerSumKw, unit: 'kW' });
1991
+ if (enchargesStatusSupported) characteristics.push({ type: Characteristic.RatedPower, label: 'rated power', value: this.pv.inventoryData.esubs.ratedPowerSumKw, unit: 'kW' });
1992
+ if (enchargesPowerSupported) characteristics.push({ type: Characteristic.RealPower, label: 'real power', value: this.pv.inventoryData.esubs.realPowerSumKw, unit: 'kW' });
1993
1993
 
1994
1994
  for (const { type, label, value, unit = '', postfix = '' } of characteristics) {
1995
1995
  if (!this.functions.isValidValue(value)) continue;
@@ -2257,14 +2257,22 @@ class EnvoyDevice extends EventEmitter {
2257
2257
  { type: Characteristic.ReadingTime, label: 'reading time', value: encharge.readingTime },
2258
2258
  ];
2259
2259
 
2260
- if (gridProfileSupported) characteristics.push({ type: Characteristic.GridProfile, label: 'grid profile', value: encharge.gridProfile });
2260
+ if (gridProfileSupported) {
2261
+ characteristics.push(
2262
+ { type: Characteristic.GridProfile, label: 'grid profile', value: encharge.gridProfile }
2263
+ );
2264
+ }
2265
+
2261
2266
  if (enchargesStatusSupported && encharge.status) {
2262
2267
  characteristics.push(
2263
2268
  { type: Characteristic.CommInterface, label: 'comm interface', value: encharge.status.commInterfaceStr },
2264
2269
  { type: Characteristic.RatedPower, label: 'rated power', value: encharge.status.ratedPowerKw, unit: 'kW' }
2265
2270
  );
2266
2271
  }
2267
- if (enchargesPowerSupported && encharge.power) characteristics.push({ type: Characteristic.RealPower, label: 'real power', value: encharge.power.realPowerKw, unit: 'kW' });
2272
+
2273
+ if (enchargesPowerSupported && encharge.power) {
2274
+ characteristics.push({ type: Characteristic.RealPower, label: 'real power', value: encharge.power.realPowerKw, unit: 'kW' });
2275
+ }
2268
2276
 
2269
2277
  for (const { type, label, value, unit = '', postfix = '' } of characteristics) {
2270
2278
  if (!this.functions.isValidValue(value)) continue;
@@ -2391,23 +2399,24 @@ class EnvoyDevice extends EventEmitter {
2391
2399
  if (this.logDebug) this.emit('debug', `Prepare ${enchargeName} Profile Sensor Services`);
2392
2400
 
2393
2401
  this.enchargeProfileSensorsServices = [];
2402
+
2394
2403
  for (let i = 0; i < this.enchargeProfileSensors.length; i++) {
2395
2404
  const sensor = this.enchargeProfileSensors[i];
2396
2405
  const { namePrefix, name, serviceType, characteristicType } = sensor;
2397
2406
  const serviceName = namePrefix ? `${accessoryName} ${name}` : name;
2398
2407
 
2399
- const sensorService = accessory.addService(serviceType, serviceName, `enchargeProfileSensorService${i}`);
2400
- sensorService.addOptionalCharacteristic(Characteristic.ConfiguredName);
2401
- sensorService.setCharacteristic(Characteristic.ConfiguredName, serviceName);
2408
+ const service = accessory.addService(serviceType, serviceName, `enchargeProfileSensorService${i}`);
2409
+ service.addOptionalCharacteristic(Characteristic.ConfiguredName);
2410
+ service.setCharacteristic(Characteristic.ConfiguredName, serviceName);
2402
2411
 
2403
- sensorService.getCharacteristic(characteristicType)
2412
+ service.getCharacteristic(characteristicType)
2404
2413
  .onGet(async () => {
2405
2414
  const currentState = sensor.state;
2406
2415
  if (this.logInfo) this.emit('info', `${enchargeName} profile: ${name}, state: ${currentState ? 'Active' : 'Not Active'}`);
2407
2416
  return currentState;
2408
2417
  });
2409
2418
 
2410
- this.enchargeProfileSensorsServices.push(sensorService);
2419
+ this.enchargeProfileSensorsServices.push(service);
2411
2420
  }
2412
2421
  }
2413
2422
  }
@@ -2686,7 +2695,7 @@ class EnvoyDevice extends EventEmitter {
2686
2695
  { type: Characteristic.AdminState, label: 'admin state', value: collar.adminStateStr },
2687
2696
  { type: Characteristic.Status, label: 'status', value: collar.deviceStatus },
2688
2697
  { type: Characteristic.MidState, label: 'mid state', value: collar.midState },
2689
- { type: Characteristic.GridState, label: 'grid state', value: collar.gridState },
2698
+ { type: Characteristic.GridState, label: 'mid state', value: collar.gridState },
2690
2699
  { type: Characteristic.Communicating, label: 'communicating', value: collar.communicating, postfix: collar.communicating ? 'Yes' : 'No' },
2691
2700
  { type: Characteristic.Temperature, label: 'temperature', value: collar.temperature, unit: '°C' },
2692
2701
  { type: Characteristic.ReadingTime, label: 'reading time', value: collar.readingTime }
@@ -3108,6 +3117,7 @@ class EnvoyDevice extends EventEmitter {
3108
3117
  this.emit('devInfo', `Firmware: ${info.software}`);
3109
3118
  this.emit('devInfo', `SerialNr: ${info.serialNumber}`);
3110
3119
  this.emit('devInfo', `Time: ${this.functions.formatTimestamp(info.time, timeZone)}`);
3120
+ this.emit('devInfo', `Energy Meter: ${this.energyMeter ? 'Enabled' : 'Disabled'}`);
3111
3121
  this.emit('devInfo', `------------------------------`);
3112
3122
 
3113
3123
  // Inventory
@@ -3165,15 +3175,6 @@ class EnvoyDevice extends EventEmitter {
3165
3175
 
3166
3176
  this.emit('devInfo', `--------------------------------`);
3167
3177
  }
3168
-
3169
- // Eve Energy Meter
3170
- if (this.energyMeter) {
3171
- this.emit('devInfo', `EVE Meter: Yes`);
3172
- this.emit('devInfo', `Production: Enabled`);
3173
- if (feature.meters.consumptionNet.supported) this.emit('devInfo', `Consumption Net: ${feature.meters.consumptionNet.enabled ? 'Enabled' : 'Disabled'}`);
3174
- if (feature.meters.consumptionTotal.supported) this.emit('devInfo', `Consumption Total: ${feature.meters.consumptionTotal.enabled ? 'Enabled' : 'Disabled'}`);
3175
- this.emit('devInfo', `------------------------------`);
3176
- }
3177
3178
  })
3178
3179
  .on('updateDataSampling', (state) => {
3179
3180
  if (this.logDebug) this.emit('debug', `Update data sampling`);
@@ -3204,9 +3205,8 @@ class EnvoyDevice extends EventEmitter {
3204
3205
  try {
3205
3206
  const comm = home.comm ?? {};
3206
3207
  const network = home.network ?? {};
3207
- const wirelessConnections = home.wireless_connection ?? [];
3208
- const networkInterfaces = network.interfaces ?? []
3209
-
3208
+ const wirelessConnections = (home.wireless_connection ?? []).filter(kit => kit.signal_strength_max > 0);
3209
+ const networkInterfaces = (network.interfaces ?? []).filter(iface => iface.carrier === true || iface.ip !== '169.254.120.1');
3210
3210
  // Communication device support flags
3211
3211
  const commEnsemble = comm.esub ?? {};
3212
3212
  const commEncharges = Array.isArray(comm.encharge) ? comm.encharge : [];
@@ -3527,16 +3527,10 @@ class EnvoyDevice extends EventEmitter {
3527
3527
  powerPeak: pcu.powerPeak,
3528
3528
  });
3529
3529
 
3530
- if (this.logInfo) {
3531
- this.emit('info', `Microinverter, ${pcuData.serialNumber}, power: ${pcuData.power} W`);
3532
- this.emit('info', `Microinverter, ${pcuData.serialNumber}, phase: ${pcuData.phase}`);
3533
- }
3534
-
3535
3530
  // Add characteristics
3536
3531
  characteristics.push(
3537
3532
  { type: Characteristic.PowerW, value: pcuData.power },
3538
- { type: Characteristic.PowerPeakW, value: pcuData.powerPeak }
3539
- );
3533
+ { type: Characteristic.PowerPeakW, value: pcuData.powerPeak });
3540
3534
  }
3541
3535
 
3542
3536
  // Add detailed info if supported
@@ -3636,9 +3630,9 @@ class EnvoyDevice extends EventEmitter {
3636
3630
  plcLevel: nsrb.plcLevel,
3637
3631
  };
3638
3632
 
3639
- if (this.logInfo) {
3640
- this.emit('info', `Q-Relay, ${nsrbData.serialNumber}, state: ${nsrbData.relay}`);
3641
- this.emit('info', `Q-Relay, ${nsrbData.serialNumber}, lines: ${nsrbData.linesCount}`);
3633
+ if (this.logDebug) {
3634
+ this.emit('debug', `Q-Rela state:`, nsrbData.relay);
3635
+ this.emit('debug', `Q-Relay lines:`, nsrbData.linesCount);
3642
3636
  }
3643
3637
 
3644
3638
  // Create characteristics
@@ -4341,10 +4335,10 @@ class EnvoyDevice extends EventEmitter {
4341
4335
  // Add to ensemble summary characteristics if live data not supported
4342
4336
  if (!this.feature.liveData.supported || !this.feature.meters.storage.enabled) {
4343
4337
  ensembleSummaryCharacteristics.push(
4344
- { type: Characteristic.AggSoc, value: secctrl.aggSoc },
4345
4338
  { type: Characteristic.AggMaxEnergy, value: secctrl.aggMaxEnergyKw },
4346
- { type: Characteristic.EncAggSoc, value: secctrl.encAggSoc },
4347
- { type: Characteristic.EncAggBackupEnergy, value: secctrl.encAggBackupEnergy });
4339
+ { type: Characteristic.EncAggBackupEnergy, value: secctrl.encAggBackupEnergy },
4340
+ { type: Characteristic.AggSoc, value: secctrl.aggSoc },
4341
+ { type: Characteristic.encAggSoc, value: secctrl.encAggSoc });
4348
4342
  }
4349
4343
 
4350
4344
  if (phaseA) {
@@ -4842,8 +4836,8 @@ class EnvoyDevice extends EventEmitter {
4842
4836
  const info = tariffData.tariff ?? {};
4843
4837
  const tariff = {};
4844
4838
  tariff.info = {
4845
- currencyCode: info.currency.code,
4846
- logger: info.logger,
4839
+ currencyCode: info.currency.code ?? '',
4840
+ logger: info.logger ?? '',
4847
4841
  date: this.functions.formatTimestamp(info.date, this.pv.homeData.timeZone),
4848
4842
  };
4849
4843
 
@@ -4851,7 +4845,7 @@ class EnvoyDevice extends EventEmitter {
4851
4845
  const s = info.storage_settings ?? {};
4852
4846
  tariff.storageSettings = {
4853
4847
  mode: s.mode,
4854
- operationModeSubType: s.operation_mode_sub_type,
4848
+ operationModeSubType: s.operation_mode_sub_type ?? '',
4855
4849
  reservedSoc: s.reserved_soc,
4856
4850
  veryLowSoc: s.very_low_soc,
4857
4851
  chargeFromGrid: !!s.charge_from_grid,
@@ -4898,16 +4892,16 @@ class EnvoyDevice extends EventEmitter {
4898
4892
  // Schedule
4899
4893
  const sched = tariffData.schedule ?? {};
4900
4894
  tariff.schedule = {
4901
- fileName: sched.filename,
4902
- source: sched.source,
4895
+ fileName: sched.filename ?? '',
4896
+ source: sched.source ?? '',
4903
4897
  date: this.functions.formatTimestamp(sched.date, this.pv.homeData.timeZone),
4904
- version: sched.version,
4898
+ version: sched.version ?? '',
4905
4899
  reservedSoc: sched.reserved_soc,
4906
4900
  veryLowSoc: sched.very_low_soc,
4907
4901
  chargeFromGrid: !!sched.charge_from_grid,
4908
- battMode: sched.batt_mode,
4909
- batteryMode: sched.battery_mode,
4910
- operationModeSubType: sched.operation_mode_sub_type,
4902
+ battMode: sched.batt_mode ?? '',
4903
+ batteryMode: sched.battery_mode ?? '',
4904
+ operationModeSubType: sched.operation_mode_sub_type ?? '',
4911
4905
  override: !!sched.override,
4912
4906
  overrideBackupSoc: sched.override_backup_soc,
4913
4907
  overrideChgDischargeRate: sched.override_chg_discharge_rate,
@@ -5080,8 +5074,8 @@ class EnvoyDevice extends EventEmitter {
5080
5074
  gridActionBool: settings.gridAction !== 'none',
5081
5075
  microGridAction: settings.microGridAction,
5082
5076
  genAction: settings.genAction,
5083
- essentialStartTime: settings.essentialStartTime,
5084
- essentialEndTime: settings.essentialEndTime,
5077
+ essentialStartTime: settings.essentialStartTime ?? '',
5078
+ essentialEndTime: settings.essentialEndTime ?? '',
5085
5079
  priority: settings.priority,
5086
5080
  blackSStart: settings.blackSStart,
5087
5081
  override: settings.override ?? 'false',
@@ -5599,8 +5593,8 @@ class EnvoyDevice extends EventEmitter {
5599
5593
 
5600
5594
  // Agg Energy and Soc
5601
5595
  const characteristics = [
5602
- { type: Characteristic.AggSoc, value: percentFullSum, valueKey: 'aggSoc' },
5603
5596
  { type: Characteristic.AggMaxEnergy, value: energySumKw, valueKey: 'aggMaxEnergyKw' },
5597
+ { type: Characteristic.AggSoc, value: percentFullSum, valueKey: 'aggSoc' },
5604
5598
  ];
5605
5599
 
5606
5600
  // Update storage summary services
@@ -5669,8 +5663,8 @@ class EnvoyDevice extends EventEmitter {
5669
5663
  // Update ensemble summary service
5670
5664
  if (this.feature.inventory.esubs.secctrl.supported) {
5671
5665
  const characteristics = [
5672
- { type: Characteristic.EncAggSoc, value: percentFullSumEnc, valueKey: 'encAggSoc' },
5673
5666
  { type: Characteristic.EncAggBackupEnergy, value: energySumEncKw, valueKey: 'encAggBackupEnergy' },
5667
+ { type: Characteristic.EncAggSoc, value: percentFullSumEnc, valueKey: 'encAggSoc' },
5674
5668
  ];
5675
5669
 
5676
5670
  // Update storage summary services
package/src/functions.js CHANGED
@@ -17,12 +17,33 @@ class Functions {
17
17
  }
18
18
  }
19
19
 
20
- async readData(path) {
20
+ async readData(path, parseJson = false) {
21
21
  try {
22
- const data = await fsPromises.readFile(path);
22
+ const data = await fsPromises.readFile(path, 'utf8');
23
+
24
+ if (parseJson) {
25
+ if (!data.trim()) {
26
+ // Empty file when expecting JSON
27
+ return null;
28
+ }
29
+ try {
30
+ return JSON.parse(data);
31
+ } catch (jsonError) {
32
+ throw new Error(`JSON parse error in file "${path}": ${jsonError.message}`);
33
+ }
34
+ }
35
+
36
+ // For non-JSON, just return file content (can be empty string)
23
37
  return data;
24
38
  } catch (error) {
25
- throw new Error(`Read data error: ${error}`);
39
+ if (error.code === 'ENOENT') {
40
+ // File does not exist
41
+ return null;
42
+ }
43
+ // Preserve original error details
44
+ const wrappedError = new Error(`Read data error for "${path}": ${error.message}`);
45
+ wrappedError.original = error;
46
+ throw wrappedError;
26
47
  }
27
48
  }
28
49