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 +9 -0
- package/index.js +1 -2
- package/package.json +1 -1
- package/src/customcharacteristics.js +7 -7
- package/src/energymeter.js +56 -33
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
|
|
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
|
|
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
|
@@ -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
|
|
979
|
+
const powerAndEnergyTypeArr = [
|
|
978
980
|
{ type: 'production', state: this.feature.meters.production.enabled },
|
|
979
|
-
{ type: '
|
|
980
|
-
{ type: '
|
|
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
|
|
984
|
-
const { type:
|
|
985
|
+
for (const [index, data] of powerAndEnergyTypeArr.entries()) {
|
|
986
|
+
const { type: meterType, state: meterEnabled } = data;
|
|
987
|
+
if (meterType !== 'production' && !meterEnabled) continue;
|
|
985
988
|
|
|
986
|
-
|
|
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.
|
|
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.
|
|
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
|
|