homebridge-enphase-envoy 10.2.3-beta.9 → 10.2.4
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 +9 -0
- package/index.js +0 -1
- package/package.json +1 -1
- package/src/customcharacteristics.js +7 -7
- package/src/energymeter.js +55 -34
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
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.
|
|
5
|
+
"version": "10.2.4",
|
|
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
|
|
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.
|
|
2273
|
+
Characteristic.EvePower = EvePower;
|
|
2274
2274
|
|
|
2275
|
-
class
|
|
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.
|
|
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.
|
|
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.
|
|
2342
|
-
this.addCharacteristic(Characteristic.
|
|
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);
|
package/src/energymeter.js
CHANGED
|
@@ -27,7 +27,7 @@ class EnergyMeter extends EventEmitter {
|
|
|
27
27
|
this.envoyFirmware7xxTokenGenerationMode = envoyFirmware7xxTokenGenerationMode;
|
|
28
28
|
this.envoyPasswd = envoyPasswd;
|
|
29
29
|
this.enlightenUser = enlightenUser;
|
|
30
|
-
this.
|
|
30
|
+
this.enlightenPasswd = enlightenPasswd;
|
|
31
31
|
this.envoyToken = envoyToken;
|
|
32
32
|
this.envoyTokenInstaller = envoyTokenInstaller;
|
|
33
33
|
this.powerProductionSummary = device.powerProductionSummary || 1;
|
|
@@ -51,6 +51,7 @@ class EnergyMeter extends EventEmitter {
|
|
|
51
51
|
this.fakegatoHistory = fakegato(api);
|
|
52
52
|
this.prefDir = prefDir;
|
|
53
53
|
this.energyMeterHistoryFileName = energyMeterHistoryFileName;
|
|
54
|
+
this.lastReset = 0;
|
|
54
55
|
|
|
55
56
|
//url
|
|
56
57
|
this.url = envoyFirmware7xxTokenGenerationMode > 0 ? `https://${this.host}` : `http://${this.host}`;
|
|
@@ -975,42 +976,43 @@ class EnergyMeter extends EventEmitter {
|
|
|
975
976
|
|
|
976
977
|
try {
|
|
977
978
|
const powerAndEnergy = [];
|
|
978
|
-
const
|
|
979
|
+
const powerAndEnergyTypeArr = [
|
|
979
980
|
{ type: 'production', state: this.feature.meters.production.enabled },
|
|
980
|
-
{ type: '
|
|
981
|
-
{ type: '
|
|
981
|
+
{ type: 'net-consumption', state: this.feature.meters.consumptionNet.enabled },
|
|
982
|
+
{ type: 'total-consumption', state: this.feature.meters.consumptionTotal.enabled }
|
|
982
983
|
];
|
|
983
984
|
|
|
984
|
-
for (const [index, data] of
|
|
985
|
-
const { type:
|
|
985
|
+
for (const [index, data] of powerAndEnergyTypeArr.entries()) {
|
|
986
|
+
const { type: meterType, state: meterEnabled } = data;
|
|
987
|
+
if (meterType !== 'production' && !meterEnabled) continue;
|
|
986
988
|
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
let sourceMeter, sourceEnergy, measurementType;
|
|
990
|
-
let power;
|
|
989
|
+
const key = MetersKeyMap[meterType];
|
|
990
|
+
const measurementType = ApiCodes[meterType];
|
|
991
991
|
|
|
992
|
+
let sourceMeter, sourceEnergy;
|
|
993
|
+
let power, energyLifetime;
|
|
992
994
|
switch (key) {
|
|
993
995
|
case 'production': {
|
|
994
|
-
measurementType = 'Production';
|
|
995
996
|
const sourcePcu = this.pv.powerAndEnergy[key].pcu;
|
|
996
997
|
const sourceEim = this.pv.powerAndEnergy[key].eim;
|
|
997
998
|
sourceMeter = meterEnabled ? this.pv.meters.find(m => m.measurementType === 'production') : sourcePcu;
|
|
998
999
|
sourceEnergy = meterEnabled ? sourceEim : sourcePcu;
|
|
999
1000
|
power = this.functions.isValidValue(sourceMeter.power) ? sourceMeter.power : null;
|
|
1001
|
+
energyLifetime = this.functions.isValidValue(sourceMeter.energyLifetime) ? sourceMeter.energyLifetime / 1000 : null;
|
|
1000
1002
|
break;
|
|
1001
1003
|
}
|
|
1002
1004
|
case 'consumptionNet': {
|
|
1003
|
-
measurementType = 'Consumption Net';
|
|
1004
1005
|
sourceMeter = this.pv.meters.find(m => m.measurementType === 'net-consumption');
|
|
1005
1006
|
sourceEnergy = this.pv.powerAndEnergy.consumptionNet;
|
|
1006
1007
|
power = this.functions.isValidValue(sourceMeter.power) ? sourceMeter.power : null;
|
|
1008
|
+
energyLifetime = this.functions.isValidValue(sourceMeter.energyLifetime) ? sourceMeter.energyLifetime / 1000 : null;
|
|
1007
1009
|
break;
|
|
1008
1010
|
}
|
|
1009
1011
|
case 'consumptionTotal': {
|
|
1010
|
-
measurementType = 'Consumption Total';
|
|
1011
1012
|
sourceMeter = this.pv.meters.find(m => m.measurementType === 'total-consumption');
|
|
1012
1013
|
sourceEnergy = this.pv.powerAndEnergy.consumptionTotal;
|
|
1013
1014
|
power = this.functions.isValidValue(sourceMeter.power) ? sourceMeter.power : null;
|
|
1015
|
+
energyLifetime = this.functions.isValidValue(sourceMeter.energyLifetime) ? sourceMeter.energyLifetime / 1000 : null;
|
|
1014
1016
|
break;
|
|
1015
1017
|
}
|
|
1016
1018
|
}
|
|
@@ -1027,12 +1029,20 @@ class EnergyMeter extends EventEmitter {
|
|
|
1027
1029
|
type,
|
|
1028
1030
|
measurementType,
|
|
1029
1031
|
power,
|
|
1032
|
+
energyLifetime,
|
|
1030
1033
|
gridQualityState: meterEnabled,
|
|
1031
1034
|
};
|
|
1032
1035
|
|
|
1036
|
+
// Add to fakegato history
|
|
1037
|
+
this.fakegatoHistoryService?.addEntry({
|
|
1038
|
+
time: Math.floor(Date.now() / 1000),
|
|
1039
|
+
power: power
|
|
1040
|
+
});
|
|
1041
|
+
|
|
1033
1042
|
// Create characteristics energy meter
|
|
1034
1043
|
const characteristics = [
|
|
1035
|
-
{ type: Characteristic.
|
|
1044
|
+
{ type: Characteristic.EvePower, value: obj.power },
|
|
1045
|
+
{ type: Characteristic.EveEnergyLifetime, value: obj.energyLifetime },
|
|
1036
1046
|
];
|
|
1037
1047
|
|
|
1038
1048
|
// Create characteristics energy meter
|
|
@@ -1054,12 +1064,6 @@ class EnergyMeter extends EventEmitter {
|
|
|
1054
1064
|
this.energyMeterServices?.[index]?.updateCharacteristic(type, value);
|
|
1055
1065
|
};
|
|
1056
1066
|
|
|
1057
|
-
// FakeGato history per energy meter service
|
|
1058
|
-
this.fakegatoHistoryService?.addEntry({
|
|
1059
|
-
time: Math.floor(Date.now() / 1000),
|
|
1060
|
-
power: obj.power
|
|
1061
|
-
});
|
|
1062
|
-
|
|
1063
1067
|
powerAndEnergy.push(obj);
|
|
1064
1068
|
}
|
|
1065
1069
|
}
|
|
@@ -1097,6 +1101,7 @@ class EnergyMeter extends EventEmitter {
|
|
|
1097
1101
|
const accessoryUUID = AccessoryUUID.generate(envoySerialNumber + 'Energy Meter');
|
|
1098
1102
|
const accessoryCategory = Categories.SENSOR;
|
|
1099
1103
|
const accessory = new Accessory(accessoryName, accessoryUUID, accessoryCategory);
|
|
1104
|
+
accessory.log = this.log;
|
|
1100
1105
|
|
|
1101
1106
|
// Accessory Info Service
|
|
1102
1107
|
if (this.logDebug) this.emit('debug', `Prepare Information Service`);
|
|
@@ -1106,31 +1111,33 @@ class EnergyMeter extends EventEmitter {
|
|
|
1106
1111
|
.setCharacteristic(Characteristic.SerialNumber, envoySerialNumber ?? 'Serial Number')
|
|
1107
1112
|
.setCharacteristic(Characteristic.FirmwareRevision, this.pv.info.software?.replace(/[a-zA-Z]/g, '') ?? '0');
|
|
1108
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
|
+
|
|
1109
1128
|
// Energy Meter Service
|
|
1110
1129
|
this.energyMeterServices = [];
|
|
1111
1130
|
for (const source of this.pv.powerAndEnergy.data) {
|
|
1112
1131
|
const measurementType = source.measurementType;
|
|
1113
1132
|
|
|
1114
|
-
// Create FakeGatoHistory
|
|
1115
|
-
if (this.logDebug) this.emit('debug', `Prepare Fakegato ${measurementType} Service`);
|
|
1116
|
-
this.fakegatoHistoryService = new this.fakegatoHistory(`energy`, accessory, {
|
|
1117
|
-
log: this.log,
|
|
1118
|
-
storage: 'fs',
|
|
1119
|
-
disableRepeatLastData: true,
|
|
1120
|
-
disableTimer: false
|
|
1121
|
-
})
|
|
1122
|
-
this.fakegatoHistoryService.addEntry({
|
|
1123
|
-
time: Math.floor(Date.now() / 1000),
|
|
1124
|
-
power: source.power
|
|
1125
|
-
});
|
|
1126
|
-
|
|
1127
1133
|
if (this.logDebug) this.emit('debug', `Prepare Meter ${measurementType} Service`);
|
|
1128
1134
|
const energyMeterService = accessory.addService(Service.EvePowerMeter, `Energy Meter ${measurementType}`, `energyMeterService${measurementType}`);
|
|
1129
1135
|
energyMeterService.setCharacteristic(Characteristic.ConfiguredName, `Energy Meter ${measurementType}`);
|
|
1130
1136
|
|
|
1131
1137
|
// Create characteristics
|
|
1132
1138
|
const characteristics = [
|
|
1133
|
-
{ type: Characteristic.
|
|
1139
|
+
{ type: Characteristic.EvePower, label: 'power', value: source.power, unit: 'W' },
|
|
1140
|
+
{ type: Characteristic.EveEnergyLifetime, label: 'energy lifetime', value: source.energyLifetime, unit: 'kWh' },
|
|
1134
1141
|
];
|
|
1135
1142
|
|
|
1136
1143
|
if (source.gridQualityState) {
|
|
@@ -1151,6 +1158,20 @@ class EnergyMeter extends EventEmitter {
|
|
|
1151
1158
|
});
|
|
1152
1159
|
}
|
|
1153
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
|
+
|
|
1154
1175
|
this.energyMeterServices.push(energyMeterService);
|
|
1155
1176
|
}
|
|
1156
1177
|
|