homebridge-enphase-envoy 10.3.1-beta.9 → 10.3.2

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/CHANGELOG.md CHANGED
@@ -9,6 +9,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  - after update to v10.0.0 and above the accessory and bridge need to be removed from the homebridge / Home.app and added again
11
11
 
12
+ ## [10.3.2] - (30.10.2025)
13
+
14
+ ## Changes
15
+
16
+ - fix [#220](https://github.com/grzegorz914/homebridge-enphase-envoy/issues/220)
17
+
18
+ ## [10.3.1] - (29.10.2025)
19
+
20
+ ## Changes
21
+
22
+ - bump dependencies
23
+ - redme updated
24
+ - cleanup
25
+
12
26
  ## [10.3.0] - (20.10.2025)
13
27
 
14
28
  ## Changes
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.9",
5
+ "version": "10.3.2",
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",
@@ -1085,8 +1085,8 @@ export default (api) => {
1085
1085
  this.setProps({
1086
1086
  format: Formats.FLOAT,
1087
1087
  unit: 'A',
1088
- maxValue: 1000000,
1089
- minValue: -1000000,
1088
+ maxValue: 10000000,
1089
+ minValue: -10000000,
1090
1090
  minStep: 0.1,
1091
1091
  perms: [Perms.PAIRED_READ, Perms.NOTIFY]
1092
1092
  });
@@ -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,36 +906,33 @@ 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 ?? {};
910
+ const network = home.network ?? {};
911
+ const wirelessConnections = home.wireless_connection ?? [];
912
+ const networkInterfaces = network.interfaces ?? [];
913
+
909
914
  // Communication device support flags
910
- const microinvertersSupported = 'pcu' in home.comm;
911
- const acBatteriesSupported = 'acb' in home.comm;
912
- const qRelaysSupported = 'nsrb' in home.comm;
913
- const ensemblesSupported = 'esub' in home.comm;
914
- const enchargesSupported = 'encharge' in home.comm;
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;
920
+ this.pv.home = home;
915
921
 
922
+ // Update feature flags
916
923
  this.feature.inventory.pcus.supported = microinvertersSupported;
917
924
  this.feature.inventory.acbs.supported = acBatteriesSupported;
918
925
  this.feature.inventory.nsrbs.supported = qRelaysSupported;
919
926
  this.feature.inventory.esubs.supported = ensemblesSupported;
920
927
  this.feature.inventory.esubs.encharges.supported = enchargesSupported;
921
928
 
922
- const networkInterfacesSupported = 'interfaces' in home.network;
923
- if (networkInterfacesSupported) {
924
- home.network.interfaces = (home.network.interfaces ?? []).filter(iface => iface.carrier === true || iface.ip !== '169.254.120.1');
925
- this.feature.home.networkInterfaces.supported = networkInterfacesSupported;
926
- this.feature.home.networkInterfaces.installed = home.network.interfaces.length > 0;
927
- this.feature.home.networkInterfaces.count = home.network.interfaces.length;
928
- }
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;
929
932
 
930
- const wirelessConnectionsSupported = 'wireless_connection' in home;
931
- if (wirelessConnectionsSupported) {
932
- home.wireless_connection = (home.wireless_connection ?? []).filter(kit => kit.signal_strength_max > 0);
933
- this.feature.home.wirelessConnections.supported = wirelessConnectionsSupported;
934
- this.feature.home.wirelessConnections.installed = home.wireless_connection.length > 0;
935
- this.feature.home.wirelessConnections.count = home.wireless_connection.length;
936
- }
937
-
938
- this.pv.home = home;
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;
939
936
  this.feature.home.supported = true;
940
937
 
941
938
  // RESTful + MQTT
@@ -1965,7 +1962,7 @@ class EnvoyData extends EventEmitter {
1965
1962
  };
1966
1963
 
1967
1964
  // Calculate encharges rated power summary in kW
1968
- 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;
1969
1966
  }
1970
1967
 
1971
1968
  // Update enpowers statuses if installed
@@ -2041,17 +2038,18 @@ class EnvoyData extends EventEmitter {
2041
2038
 
2042
2039
  try {
2043
2040
  const response = await this.axiosInstance.get(ApiUrls.EnsemblePower);
2044
- const responseData = response.data ?? {};
2041
+ const responseData = response.data;
2045
2042
  if (this.logDebug) this.emit('debug', `Ensemble power response:`, responseData);
2046
2043
 
2047
- const devices = responseData.devices || [];
2048
- if (devices.length === 0) return false;
2044
+ const devices = responseData.devices ?? [];
2045
+ if (!devices.length === 0) return false;
2049
2046
 
2050
2047
  // update encharges
2051
2048
  const enchargesRealPowerSummary = [];
2052
2049
  const encharges = this.pv.inventory.esubs.encharges.devices || [];
2053
- for (const encharge of encharges) {
2054
- 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);
2055
2053
  if (this.logDebug) this.emit('debug', `Ensemble device power:`, device);
2056
2054
  if (!device) continue;
2057
2055
 
@@ -2062,12 +2060,12 @@ class EnvoyData extends EventEmitter {
2062
2060
  soc: device.soc,
2063
2061
  };
2064
2062
 
2065
- this.feature.inventory.esubs.encharges.power.supported = true;
2066
2063
  if (this.functions.isValidValue(encharge.power.realPower)) enchargesRealPowerSummary.push(encharge.power.realPower);
2064
+ this.feature.inventory.esubs.encharges.power.supported = true;
2067
2065
  }
2068
2066
 
2069
2067
  // Calculate encharges real power summary in kW
2070
- 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;
2071
2069
 
2072
2070
  // ensemble power supported
2073
2071
  this.feature.ensemble.power.supported = true;
@@ -2093,14 +2091,15 @@ class EnvoyData extends EventEmitter {
2093
2091
  const enchargesSettingsSupported = 'enc_settings' in enchargesSettings;
2094
2092
  if (!enchargesSettingsSupported) return false;
2095
2093
 
2096
- const settings = {
2097
- enable: enchargesSettings.enc_settings.enable, // boolean
2098
- country: enchargesSettings.enc_settings.country, // string
2099
- currentLimit: enchargesSettings.enc_settings.current_limit, // float
2100
- 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
2101
2101
  };
2102
2102
 
2103
- this.pv.inventory.esubs.encharges.settings = settings;
2104
2103
  this.feature.inventory.esubs.encharges.settings.supported = true;
2105
2104
 
2106
2105
  // RESTFul and MQTT update
@@ -2119,11 +2118,12 @@ class EnvoyData extends EventEmitter {
2119
2118
  try {
2120
2119
  const response = await this.axiosInstance.get(ApiUrls.TariffSettingsGetPut);
2121
2120
  const tariffSettings = response.data;
2121
+
2122
2122
  if (this.logDebug) this.emit('debug', 'Tariff:', tariffSettings);
2123
2123
 
2124
2124
  const enchargesTariffSupported = 'tariff' in tariffSettings;
2125
2125
  if (!enchargesTariffSupported) return false;
2126
-
2126
+ this.pv.inventory.esubs.encharges.tariffRaw = tariffSettings;
2127
2127
  this.pv.inventory.esubs.encharges.tariff = tariffSettings;
2128
2128
  this.feature.inventory.esubs.encharges.tariff.supported = true;
2129
2129
 
@@ -2548,7 +2548,7 @@ class EnvoyData extends EventEmitter {
2548
2548
  if (this.logDebug) this.emit('debug', `Requesting set encharge settings`);
2549
2549
 
2550
2550
  try {
2551
- const tariff = this.pv.inventory.esubs.encharges.tariff.tariff;
2551
+ const tariff = this.pv.inventory.esubs.encharges.tariffRaw.tariff;
2552
2552
  tariff.storage_settings.mode = profile;
2553
2553
  tariff.storage_settings.reserved_soc = reservedSoc;
2554
2554
  tariff.storage_settings.charge_from_grid = chargeFromGrid;
@@ -2774,16 +2774,12 @@ class EnvoyData extends EventEmitter {
2774
2774
  const getEnsemble = tokenRequired && this.feature.inventory.esubs.supported ? await this.updateEnsembleInventory() : false;
2775
2775
  if (getEnsemble) {
2776
2776
  await this.updateEnsembleStatus();
2777
- if (this.feature.inventory.esubs.encharges.installed) {
2778
- await this.updateEnsemblePower();
2779
- await this.updateEnchargesSettings();
2780
- await this.updateTariff();
2781
- }
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();
2782
2780
 
2783
- if (this.feature.inventory.esubs.enpowers.installed) {
2784
- await this.updateDryContacts();
2785
- await this.updateDryContactsSettings();
2786
- }
2781
+ const getDryContacts = this.feature.inventory.esubs.enpowers.installed ? await this.updateDryContacts() : false;
2782
+ if (getDryContacts) await this.updateDryContactsSettings();
2787
2783
 
2788
2784
  const getGenerator = await this.updateGenerator();
2789
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