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

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,15 @@ 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.2.3] - (15.10.2025)
13
+
14
+ ## Changes
15
+
16
+ - fix [#215](https://github.com/grzegorz914/homebridge-enphase-envoy/issues/215)
17
+ - epdate EVE Energy monitor
18
+ - other small fixes
19
+ - cleanup
20
+
12
21
  ## [10.2.2] - (12.10.2025)
13
22
 
14
23
  ## Changes
package/index.js CHANGED
@@ -98,7 +98,7 @@ class EnvoyPlatform {
98
98
  const impulseGenerator = new ImpulseGenerator()
99
99
  .on('start', async () => {
100
100
  try {
101
- const envoyDevice = new DeviceClass(api, accessoryName, host, displayType, envoyFirmware7xxTokenGenerationMode, envoyPasswd, envoyToken, envoyTokenInstaller, enlightenUser, enlightenPasswd, envoyIdFile, envoyTokenFile, device, prefDir, energyMeterHistoryFileName)
101
+ const envoyDevice = new DeviceClass(api, accessoryName, host, displayType, envoyFirmware7xxTokenGenerationMode, envoyPasswd, envoyToken, envoyTokenInstaller, enlightenUser, enlightenPasswd, envoyIdFile, envoyTokenFile, device, prefDir, energyMeterHistoryFileName, log)
102
102
  .on('devInfo', (info) => logLevel.devInfo && log.info(info))
103
103
  .on('success', (msg) => logLevel.success && log.success(`Device: ${host} ${accessoryName}, ${msg}`))
104
104
  .on('info', (msg) => logLevel.info && log.info(`Device: ${host} ${accessoryName}, ${msg}`))
@@ -133,7 +133,6 @@ class EnvoyPlatform {
133
133
  }
134
134
 
135
135
  configureAccessory(accessory) {
136
- accessory.log = this.log;
137
136
  this.accessories.push(accessory);
138
137
  }
139
138
  }
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.3-beta.8",
5
+ "version": "10.2.3",
6
6
  "description": "Homebridge p7ugin for Photovoltaic Energy System manufactured by Enphase.",
7
7
  "license": "MIT",
8
8
  "author": "grzegorz914",
@@ -2256,7 +2256,7 @@ export default (api) => {
2256
2256
  Service.LiveDataService = LiveDataService;
2257
2257
 
2258
2258
  // EVE electric meter
2259
- class EveCurrentConsumption extends Characteristic {
2259
+ class EvePower extends Characteristic {
2260
2260
  constructor() {
2261
2261
  super('Power', 'E863F10D-079E-48FF-8F27-9C2605A29F52');
2262
2262
  this.setProps({
@@ -2270,9 +2270,9 @@ export default (api) => {
2270
2270
  this.value = this.getDefaultValue();
2271
2271
  }
2272
2272
  }
2273
- Characteristic.EveCurrentConsumption = EveCurrentConsumption;
2273
+ Characteristic.EvePower = EvePower;
2274
2274
 
2275
- class EveTotalConsumption extends Characteristic {
2275
+ class EveEnergyLifetime extends Characteristic {
2276
2276
  constructor() {
2277
2277
  super('Energy', 'E863F10C-079E-48FF-8F27-9C2605A29F52');
2278
2278
  this.setProps({
@@ -2286,7 +2286,7 @@ export default (api) => {
2286
2286
  this.value = this.getDefaultValue();
2287
2287
  }
2288
2288
  }
2289
- Characteristic.EveTotalConsumption = EveTotalConsumption;
2289
+ Characteristic.EveEnergyLifetime = EveEnergyLifetime;
2290
2290
 
2291
2291
  class EveVoltage extends Characteristic {
2292
2292
  constructor() {
@@ -2324,7 +2324,7 @@ export default (api) => {
2324
2324
  constructor() {
2325
2325
  super('Reset time', 'E863F112-079E-48FF-8F27-9C2605A29F52');
2326
2326
  this.setProps({
2327
- format: Formats.UInt32,
2327
+ format: Formats.UINT32,
2328
2328
  perms: [Perms.PAIRED_READ, Perms.PAIRED_WRITE, Perms.NOTIFY]
2329
2329
  });
2330
2330
  this.value = this.getDefaultValue();
@@ -2338,8 +2338,8 @@ export default (api) => {
2338
2338
  constructor(displayName, subtype) {
2339
2339
  super(displayName, 'E863F130-079E-48FF-8F27-9C2605A29F52', subtype);
2340
2340
  // Mandatory Characteristics
2341
- this.addCharacteristic(Characteristic.EveCurrentConsumption);
2342
- this.addCharacteristic(Characteristic.EveTotalConsumption);
2341
+ this.addCharacteristic(Characteristic.EvePower);
2342
+ this.addCharacteristic(Characteristic.EveEnergyLifetime);
2343
2343
  // Optional Characteristics
2344
2344
  this.addOptionalCharacteristic(Characteristic.EveVoltage);
2345
2345
  this.addOptionalCharacteristic(Characteristic.EveCurrent);
@@ -10,7 +10,7 @@ import fakegato from 'fakegato-history';
10
10
  let Accessory, Characteristic, Service, Categories, AccessoryUUID;
11
11
 
12
12
  class EnergyMeter extends EventEmitter {
13
- constructor(api, deviceName, host, displayType, envoyFirmware7xxTokenGenerationMode, envoyPasswd, envoyToken, envoyTokenInstaller, enlightenUser, enlightenPasswd, envoyIdFile, envoyTokenFile, device, prefDir, energyMeterHistoryFileName) {
13
+ constructor(api, deviceName, host, displayType, envoyFirmware7xxTokenGenerationMode, envoyPasswd, envoyToken, envoyTokenInstaller, enlightenUser, enlightenPasswd, envoyIdFile, envoyTokenFile, device, prefDir, energyMeterHistoryFileName, log) {
14
14
  super();
15
15
 
16
16
  Accessory = api.platformAccessory;
@@ -20,6 +20,7 @@ class EnergyMeter extends EventEmitter {
20
20
  AccessoryUUID = api.hap.uuid;
21
21
 
22
22
  //device configuration
23
+ this.log = log;
23
24
  this.name = deviceName;
24
25
  this.host = host;
25
26
 
@@ -50,6 +51,7 @@ class EnergyMeter extends EventEmitter {
50
51
  this.fakegatoHistory = fakegato(api);
51
52
  this.prefDir = prefDir;
52
53
  this.energyMeterHistoryFileName = energyMeterHistoryFileName;
54
+ this.lastReset = 0;
53
55
 
54
56
  //url
55
57
  this.url = envoyFirmware7xxTokenGenerationMode > 0 ? `https://${this.host}` : `http://${this.host}`;
@@ -974,42 +976,43 @@ class EnergyMeter extends EventEmitter {
974
976
 
975
977
  try {
976
978
  const powerAndEnergy = [];
977
- const dataArr = [
979
+ const powerAndEnergyTypeArr = [
978
980
  { type: 'production', state: this.feature.meters.production.enabled },
979
- { type: 'consumptionNet', state: this.feature.meters.consumptionNet.enabled },
980
- { type: 'consumptionTotal', state: this.feature.meters.consumptionTotal.enabled }
981
+ { type: 'net-consumption', state: this.feature.meters.consumptionNet.enabled },
982
+ { type: 'total-consumption', state: this.feature.meters.consumptionTotal.enabled }
981
983
  ];
982
984
 
983
- for (const [index, data] of dataArr.entries()) {
984
- const { type: key, state: meterEnabled } = data;
985
+ for (const [index, data] of powerAndEnergyTypeArr.entries()) {
986
+ const { type: meterType, state: meterEnabled } = data;
987
+ if (meterType !== 'production' && !meterEnabled) continue;
985
988
 
986
- if (key !== 'production' && !meterEnabled) continue;
987
-
988
- let sourceMeter, sourceEnergy, measurementType;
989
- let power;
989
+ const key = MetersKeyMap[meterType];
990
+ const measurementType = ApiCodes[meterType];
990
991
 
992
+ let sourceMeter, sourceEnergy;
993
+ let power, energyLifetime;
991
994
  switch (key) {
992
995
  case 'production': {
993
- measurementType = 'Production';
994
996
  const sourcePcu = this.pv.powerAndEnergy[key].pcu;
995
997
  const sourceEim = this.pv.powerAndEnergy[key].eim;
996
998
  sourceMeter = meterEnabled ? this.pv.meters.find(m => m.measurementType === 'production') : sourcePcu;
997
999
  sourceEnergy = meterEnabled ? sourceEim : sourcePcu;
998
1000
  power = this.functions.isValidValue(sourceMeter.power) ? sourceMeter.power : null;
1001
+ energyLifetime = this.functions.isValidValue(sourceMeter.energyLifetime) ? sourceMeter.energyLifetime / 1000 : null;
999
1002
  break;
1000
1003
  }
1001
1004
  case 'consumptionNet': {
1002
- measurementType = 'Consumption Net';
1003
1005
  sourceMeter = this.pv.meters.find(m => m.measurementType === 'net-consumption');
1004
1006
  sourceEnergy = this.pv.powerAndEnergy.consumptionNet;
1005
1007
  power = this.functions.isValidValue(sourceMeter.power) ? sourceMeter.power : null;
1008
+ energyLifetime = this.functions.isValidValue(sourceMeter.energyLifetime) ? sourceMeter.energyLifetime / 1000 : null;
1006
1009
  break;
1007
1010
  }
1008
1011
  case 'consumptionTotal': {
1009
- measurementType = 'Consumption Total';
1010
1012
  sourceMeter = this.pv.meters.find(m => m.measurementType === 'total-consumption');
1011
1013
  sourceEnergy = this.pv.powerAndEnergy.consumptionTotal;
1012
1014
  power = this.functions.isValidValue(sourceMeter.power) ? sourceMeter.power : null;
1015
+ energyLifetime = this.functions.isValidValue(sourceMeter.energyLifetime) ? sourceMeter.energyLifetime / 1000 : null;
1013
1016
  break;
1014
1017
  }
1015
1018
  }
@@ -1026,12 +1029,20 @@ class EnergyMeter extends EventEmitter {
1026
1029
  type,
1027
1030
  measurementType,
1028
1031
  power,
1032
+ energyLifetime,
1029
1033
  gridQualityState: meterEnabled,
1030
1034
  };
1031
1035
 
1036
+ // Add to fakegato history
1037
+ this.fakegatoHistoryService?.addEntry({
1038
+ time: Math.floor(Date.now() / 1000),
1039
+ power: power
1040
+ });
1041
+
1032
1042
  // Create characteristics energy meter
1033
1043
  const characteristics = [
1034
- { type: Characteristic.EveCurrentConsumption, value: obj.power },
1044
+ { type: Characteristic.EvePower, value: obj.power },
1045
+ { type: Characteristic.EveEnergyLifetime, value: obj.energyLifetime },
1035
1046
  ];
1036
1047
 
1037
1048
  // Create characteristics energy meter
@@ -1053,12 +1064,6 @@ class EnergyMeter extends EventEmitter {
1053
1064
  this.energyMeterServices?.[index]?.updateCharacteristic(type, value);
1054
1065
  };
1055
1066
 
1056
- // FakeGato history per energy meter service
1057
- this.fakegatoHistoryService?.addEntry({
1058
- time: Math.floor(Date.now() / 1000),
1059
- power: obj.power
1060
- });
1061
-
1062
1067
  powerAndEnergy.push(obj);
1063
1068
  }
1064
1069
  }
@@ -1096,6 +1101,7 @@ class EnergyMeter extends EventEmitter {
1096
1101
  const accessoryUUID = AccessoryUUID.generate(envoySerialNumber + 'Energy Meter');
1097
1102
  const accessoryCategory = Categories.SENSOR;
1098
1103
  const accessory = new Accessory(accessoryName, accessoryUUID, accessoryCategory);
1104
+ accessory.log = this.log;
1099
1105
 
1100
1106
  // Accessory Info Service
1101
1107
  if (this.logDebug) this.emit('debug', `Prepare Information Service`);
@@ -1105,30 +1111,33 @@ class EnergyMeter extends EventEmitter {
1105
1111
  .setCharacteristic(Characteristic.SerialNumber, envoySerialNumber ?? 'Serial Number')
1106
1112
  .setCharacteristic(Characteristic.FirmwareRevision, this.pv.info.software?.replace(/[a-zA-Z]/g, '') ?? '0');
1107
1113
 
1114
+ // Create FakeGatoHistory
1115
+ if (this.logDebug) this.emit('debug', `Prepare Fakegato Service`);
1116
+ this.fakegatoHistoryService = new this.fakegatoHistory(`energy`, accessory, {
1117
+ storage: 'fs',
1118
+ disableRepeatLastData: true,
1119
+ disableTimer: false,
1120
+ path: this.prefDir,
1121
+ filename: this.energyMeterHistoryFileName
1122
+ })
1123
+ this.fakegatoHistoryService.addEntry({
1124
+ time: Math.floor(Date.now() / 1000),
1125
+ power: this.pv.powerAndEnergy.data[0].power
1126
+ });
1127
+
1108
1128
  // Energy Meter Service
1109
1129
  this.energyMeterServices = [];
1110
1130
  for (const source of this.pv.powerAndEnergy.data) {
1111
1131
  const measurementType = source.measurementType;
1112
1132
 
1113
- // Create FakeGatoHistory
1114
- if (this.logDebug) this.emit('debug', `Prepare Fakegato ${measurementType} Service`);
1115
- this.fakegatoHistoryService = new this.fakegatoHistory(`energy`, accessory, {
1116
- storage: 'fs',
1117
- disableRepeatLastData: true,
1118
- disableTimer: false
1119
- })
1120
- this.fakegatoHistoryService.addEntry({
1121
- time: Math.floor(Date.now() / 1000),
1122
- power: source.power
1123
- });
1124
-
1125
1133
  if (this.logDebug) this.emit('debug', `Prepare Meter ${measurementType} Service`);
1126
1134
  const energyMeterService = accessory.addService(Service.EvePowerMeter, `Energy Meter ${measurementType}`, `energyMeterService${measurementType}`);
1127
1135
  energyMeterService.setCharacteristic(Characteristic.ConfiguredName, `Energy Meter ${measurementType}`);
1128
1136
 
1129
1137
  // Create characteristics
1130
1138
  const characteristics = [
1131
- { type: Characteristic.EveCurrentConsumption, label: 'power', value: source.power, unit: 'W' },
1139
+ { type: Characteristic.EvePower, label: 'power', value: source.power, unit: 'W' },
1140
+ { type: Characteristic.EveEnergyLifetime, label: 'energy lifetime', value: source.energyLifetime, unit: 'kWh' },
1132
1141
  ];
1133
1142
 
1134
1143
  if (source.gridQualityState) {
@@ -1149,6 +1158,20 @@ class EnergyMeter extends EventEmitter {
1149
1158
  });
1150
1159
  }
1151
1160
 
1161
+ energyMeterService.getCharacteristic(Characteristic.EveResetTime)
1162
+ .onGet(async () => {
1163
+ const resetTime = this.lastReset;
1164
+ if (this.logInfo) this.emit('info', `${measurementType}, reset time: ${resetTime}`);
1165
+ return resetTime;
1166
+ })
1167
+ .onSet(async (value) => {
1168
+ try {
1169
+ this.lastReset = value;
1170
+ } catch (error) {
1171
+ if (this.logWarn) this.emit('warn', `${measurementType}, Reset time error: ${error}`);
1172
+ }
1173
+ });
1174
+
1152
1175
  this.energyMeterServices.push(energyMeterService);
1153
1176
  }
1154
1177