homebridge-enphase-envoy 10.2.0-beta.21 → 10.2.0-beta.211

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
@@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
13
13
 
14
14
  ## Changes
15
15
 
16
+ - fix encharge profile control UI interface
17
+ - added to encharge profile controls option to allow charge from grid
16
18
  - fix [#206](https://github.com/grzegorz914/homebridge-enphase-envoy/issues/206)
17
19
  - fix [#205](https://github.com/grzegorz914/homebridge-enphase-envoy/issues/205)
18
20
  - refactor code of ensemble section
package/README.md CHANGED
@@ -111,6 +111,7 @@ The `homebridge-enphase-envoy` plugin integrates Enphase Envoy solar energy moni
111
111
  | `envoyTokenInstaller` | | boolean | Enable if you are using the installer token |
112
112
  | `lockControl` | | boolean | Enables auto lock control accessory |
113
113
  | `lockControlPrefix` | | boolean | Use accessory name for prefix |
114
+ | `energyMeter` | | boolean | Enables energy meter as a axtra accessory to display charts in EVE app |
114
115
  | `productionStateSensor` | | key | `Production State Sensor` for production state monitoring |
115
116
  | | `name` | string | Accessory name for Home app |
116
117
  | | `displayType` | number | Accessory type to be displayed in Home app: `0` - None/Disabled, `1` - Motion Sensor, `2` - Occupancy Sensor, `3` - Contact Sensor |
@@ -220,6 +221,8 @@ The `homebridge-enphase-envoy` plugin integrates Enphase Envoy solar energy moni
220
221
  | | `name` | string | Accessory name for Home app |
221
222
  | | `profile` | string | Profile: `Savings`, `Economy`, `Full Backup`, `Self Consumption` |
222
223
  | | `displayType` | number | Accessory type to be displayed in Home app: `0` - None/Disabled, `1` - Lightbulb |
224
+ | | `chargeFromGrid` | boolean | Allow charge from grid |
225
+ | | `namePrefix` | boolean | Use accessory name for prefix |
223
226
  | `enchargeProfileSensors` | | key | `Encharge Profile Sensors` for monitoring. If the `Profile` matches, the contact was opened. |
224
227
  | | `name` | string | Accessory name for Home app |
225
228
  | | `profile` | string | Profile: `Savings`, `Economy`, `Full Backup`, `Self Consumption` |
@@ -317,7 +320,7 @@ Path `status` response all available paths.
317
320
  | POST | `http//ip:port` | `DataSampling` | `true`, `false` | boolean | Data sampling Start/Stop |
318
321
  | | `http//ip:port` | `PowerProductionState` | `true`, `false` | boolean | Production state On/Off |
319
322
  | | `http//ip:port` | `PlcLevel` | `true` | boolean | Check Plc Level On |
320
- | | `http//ip:port` | `EnchargeProfile` | `self-consumption`, `savings`, `economy`, `fullbackup` | string | Set encharge profile |
323
+ | | `http//ip:port` | `EnchargeProfile` | `self-consumption`, `savings-mode`, `economy`, `backup` | string | Set encharge profile |
321
324
  | | `http//ip:port` | `EnpowerGridState` | `true`, `false` | boolean | Grid state On/Off |
322
325
  | | `http//ip:port` | `GeneratorMode` | `off`, `on`, `auto` | string | Generator mode Off/On/Auto |
323
326
 
@@ -334,6 +337,6 @@ Subscribe using JSON `{ "EnchargeProfile": "savings" }`
334
337
  | Subscribe | `Set` | `DataSampling` | `true`, `false` | boolean | Data sampling Start/Stop |
335
338
  | | `Set` | `ProductionState` | `true`, `false` | boolean | Production state On/Off |
336
339
  | | `Set` | `PlcLevel` | `true` | boolean | Check Plc Level On |
337
- | | `Set` | `EnchargeProfile` | `self-consumption`, `savings`, `economy`, `fullbackup` | string | Set encharge profile |
340
+ | | `Set` | `EnchargeProfile` | `self-consumption`, `savings-mode`, `economy`, `backup` | string | Set encharge profile |
338
341
  | | `Set` | `EnpowerGridState` | `true`, `false` | boolean | Grid state On/Off |
339
342
  | | `Set` | `GeneratorMode` | `off`, `on`, `auto` | string | Generator mode Off/On/Auto |
@@ -170,6 +170,13 @@
170
170
  "functionBody": "return model.devices[arrayIndices].lockControl === true"
171
171
  }
172
172
  },
173
+ "energyMeter": {
174
+ "title": "Energy Meter",
175
+ "type": "boolean",
176
+ "default": false,
177
+ "description": "Enables energy meter as a axtra accessory to display charts in EVE app",
178
+ "required": false
179
+ },
173
180
  "productionStateSensor": {
174
181
  "title": "Production State Sensor",
175
182
  "type": "object",
@@ -2057,7 +2064,7 @@
2057
2064
  "default": "backup",
2058
2065
  "oneOf": [
2059
2066
  {
2060
- "title": "Savings",
2067
+ "title": "Savings Mode",
2061
2068
  "enum": [
2062
2069
  "savings-mode"
2063
2070
  ]
@@ -2079,23 +2086,18 @@
2079
2086
  "enum": [
2080
2087
  "self-consumption"
2081
2088
  ]
2082
- },
2083
- {
2084
- "title": "Grid Tied",
2085
- "enum": [
2086
- "grid-tied"
2087
- ]
2088
- },
2089
- {
2090
- "title": "Grid Forming",
2091
- "enum": [
2092
- "grid-forming"
2093
- ]
2094
2089
  }
2095
2090
  ],
2096
2091
  "description": "Here select the profile.",
2097
2092
  "required": true
2098
2093
  },
2094
+ "chargeFromGrid": {
2095
+ "title": "Charge From Grid",
2096
+ "type": "boolean",
2097
+ "default": false,
2098
+ "description": "Here allow charge from grid",
2099
+ "required": false
2100
+ },
2099
2101
  "namePrefix": {
2100
2102
  "title": "Prefix",
2101
2103
  "type": "boolean",
@@ -2160,7 +2162,7 @@
2160
2162
  "default": "backup",
2161
2163
  "oneOf": [
2162
2164
  {
2163
- "title": "Savings",
2165
+ "title": "Savings Mode",
2164
2166
  "enum": [
2165
2167
  "savings-mode"
2166
2168
  ]
@@ -2182,18 +2184,6 @@
2182
2184
  "enum": [
2183
2185
  "self-consumption"
2184
2186
  ]
2185
- },
2186
- {
2187
- "title": "Grid Tied",
2188
- "enum": [
2189
- "grid-tied"
2190
- ]
2191
- },
2192
- {
2193
- "title": "Grid Forming",
2194
- "enum": [
2195
- "grid-forming"
2196
- ]
2197
2187
  }
2198
2188
  ],
2199
2189
  "description": "Here select the profile.",
@@ -3383,8 +3373,7 @@
3383
3373
  "key": "devices[]",
3384
3374
  "title": "Envoy",
3385
3375
  "items": [
3386
- "devices[].lockControl",
3387
- "devices[].lockControlPrefix",
3376
+ "devices[].energyMeter",
3388
3377
  {
3389
3378
  "key": "devices[]",
3390
3379
  "type": "tabarray",
@@ -3465,6 +3454,15 @@
3465
3454
  ]
3466
3455
  }
3467
3456
  ]
3457
+ },
3458
+ {
3459
+ "key": "devices[]",
3460
+ "type": "section",
3461
+ "title": "System Control",
3462
+ "items": [
3463
+ "devices[].lockControl",
3464
+ "devices[].lockControlPrefix"
3465
+ ]
3468
3466
  }
3469
3467
  ]
3470
3468
  }
@@ -4025,14 +4023,15 @@
4025
4023
  "expanded": false,
4026
4024
  "items": [
4027
4025
  {
4028
- "key": "devices[].enchargeProfileControl",
4026
+ "key": "devices[].enchargeProfileControls",
4029
4027
  "type": "tabarray",
4030
4028
  "title": "{{ value.name || 'control' }}",
4031
4029
  "items": [
4032
- "devices[].enchargeProfileControl[].displayType",
4033
- "devices[].enchargeProfileControl[].name",
4034
- "devices[].enchargeProfileControl[].profile",
4035
- "devices[].enchargeProfileControl[].namePrefix"
4030
+ "devices[].enchargeProfileControls[].displayType",
4031
+ "devices[].enchargeProfileControls[].name",
4032
+ "devices[].enchargeProfileControls[].profile",
4033
+ "devices[].enchargeProfileControls[].chargeFromGrid",
4034
+ "devices[].enchargeProfileControls[].namePrefix"
4036
4035
  ]
4037
4036
  }
4038
4037
  ]
package/index.js CHANGED
@@ -1,21 +1,23 @@
1
1
  import { join } from 'path';
2
2
  import { mkdirSync, existsSync, writeFileSync } from 'fs';
3
3
  import EnvoyDevice from './src/envoydevice.js';
4
+ import EnergyMeter from './src/energymeter.js';
4
5
  import ImpulseGenerator from './src/impulsegenerator.js';
5
6
  import { PluginName, PlatformName } from './src/constants.js';
6
7
  import CustomCharacteristics from './src/customcharacteristics.js';
8
+ import fakegato from 'fakegato-history';
7
9
 
8
10
  class EnvoyPlatform {
9
11
  constructor(log, config, api) {
10
- // only load if configured
11
12
  if (!config || !Array.isArray(config.devices)) {
12
13
  log.warn(`No configuration found for ${PluginName}.`);
13
14
  return;
14
15
  }
15
- this.accessories = [];
16
16
 
17
+ this.log = log;
18
+ this.accessories = [];
19
+ this.FakeGatoHistoryService = fakegato(api);
17
20
 
18
- //check if prefs directory exist
19
21
  const prefDir = join(api.user.storagePath(), 'enphaseEnvoy');
20
22
  try {
21
23
  mkdirSync(prefDir, { recursive: true });
@@ -25,146 +27,170 @@ class EnvoyPlatform {
25
27
  }
26
28
 
27
29
  api.on('didFinishLaunching', async () => {
28
- let i = 1;
29
- for (const device of config.devices) {
30
-
31
- //check accessory is enabled
30
+ for (let i = 0; i < config.devices.length; i++) {
31
+ const device = config.devices[i];
32
32
  const displayType = device.displayType || 0;
33
- if (displayType === 0) {
34
- continue;
35
- }
33
+ if (displayType === 0) continue;
36
34
 
37
35
  const deviceName = device.name;
38
- const host = device.host || (i === 1 ? 'envoy.local' : `envoy-${i}.local`);
39
- const envoyFirmware7xxTokenGenerationMode = device.envoyFirmware7xxTokenGenerationMode || 0; //0 - envoy password, 1 - enlighten credentials, 2 - own token
40
- const envoyPasswd = device.envoyPasswd;
41
- const envoyToken = device.envoyToken;
42
- const envoyTokenInstaller = device.envoyTokenInstaller || false;
43
- const enlightenUser = device.enlightenUser;
44
- const enlightenPasswd = device.enlightenPasswd;
45
-
46
- //check mandatory properties
36
+ const host = device.host || (i === 0 ? 'envoy.local' : `envoy-${i + 1}.local`);
37
+ const {
38
+ envoyFirmware7xxTokenGenerationMode = 0,
39
+ envoyPasswd,
40
+ envoyToken,
41
+ envoyTokenInstaller = false,
42
+ enlightenUser,
43
+ enlightenPasswd,
44
+ enableDebugMode = false,
45
+ disableLogDeviceInfo = false,
46
+ disableLogInfo = false,
47
+ disableLogSuccess = false,
48
+ disableLogWarn = false,
49
+ disableLogError = false
50
+ } = device;
51
+
47
52
  if (!deviceName) {
48
- log.warn(`Device: ${host} ${deviceName}, Name missing: ${deviceName}.`);
49
- return;
53
+ log.warn(`Device: ${host}, Name missing.`);
54
+ continue;
50
55
  }
51
56
 
52
57
  if (envoyFirmware7xxTokenGenerationMode === 1 && (!enlightenUser || !enlightenPasswd)) {
53
- log.warn(`Device: ${host} ${deviceName}, Envoy firmware v7.x.x enabled, enlighten user: ${enlightenUser ? 'OK' : enlightenUser}, password: ${enlightenPasswd ? 'OK' : enlightenPasswd}.`);
54
- return;
58
+ log.warn(`Device: ${host} ${deviceName}, missing Enlighten credentials.`);
59
+ continue;
55
60
  }
56
61
 
57
62
  if (envoyFirmware7xxTokenGenerationMode === 2 && !envoyToken) {
58
- log.warn(`Device: ${host} ${deviceName}, Envoy firmware v7.x.x enabled but envoy token: ${envoyToken ? 'OK' : envoyToken}.`);
59
- return;
63
+ log.warn(`Device: ${host} ${deviceName}, missing Envoy token.`);
64
+ continue;
60
65
  }
61
66
 
62
- //log config
63
- const enableDebugMode = device.enableDebugMode || false;
64
- const disableLogDeviceInfo = device.disableLogDeviceInfo || false;
65
- const disableLogInfo = device.disableLogInfo || false;
66
- const disableLogSuccess = device.disableLogSuccess || false;
67
- const disableLogWarn = device.disableLogWarn || false;
68
- const disableLogError = device.disableLogError || false;
69
- const debug = !enableDebugMode ? false : log.info(`Device: ${host} ${deviceName}, did finish launching.`);
70
- const config = {
71
- ...device,
72
- envoyPasswd: 'removed',
73
- envoyToken: 'removed',
74
- enlightenPasswd: 'removed',
75
- mqtt: {
76
- ...device.mqtt,
77
- passwd: 'removed'
78
- }
79
- };
80
- const debug1 = !enableDebugMode ? false : log.info(`Device: ${host} ${deviceName}, Config: ${JSON.stringify(config, null, 2)}.`);
67
+ if (enableDebugMode) {
68
+ log.info(`Device: ${host} ${deviceName}, did finish launching.`);
69
+ const redactedConfig = JSON.stringify({
70
+ ...device,
71
+ envoyPasswd: 'removed',
72
+ envoyToken: 'removed',
73
+ enlightenPasswd: 'removed',
74
+ mqtt: { ...device.mqtt, passwd: 'removed' }
75
+ }, null, 2);
76
+ log.info(`Device: ${host} ${deviceName}, Config: ${redactedConfig}`);
77
+ }
81
78
 
82
- //check files exists, if not then create it
83
79
  const postFix = host.split('.').join('');
84
80
  const envoyIdFile = join(prefDir, `envoyId_${postFix}`);
85
81
  const envoyTokenFile = join(prefDir, `envoyToken_${postFix}`);
82
+ const energyMeterHistory = join(prefDir, `energyMeterHistory_${postFix}`);
86
83
 
87
84
  try {
88
- const files = [
89
- envoyIdFile,
90
- envoyTokenFile,
91
- ];
92
-
93
- files.forEach((file) => {
94
- if (!existsSync(file)) {
95
- writeFileSync(file, '0');
96
- }
85
+ [envoyIdFile, envoyTokenFile].forEach(file => {
86
+ if (!existsSync(file)) writeFileSync(file, '0');
97
87
  });
98
88
  } catch (error) {
99
- const emitLog = disableLogError ? false : log.error(`Device: ${host} ${deviceName}, Prepare files error: ${error}.`);
100
- return;
89
+ if (!disableLogError) log.error(`Device: ${host} ${deviceName}, File init error: ${error}`);
90
+ continue;
101
91
  }
102
92
 
103
- //envoy device
104
- try {
105
- const envoyDevice = new EnvoyDevice(api, deviceName, host, displayType, envoyFirmware7xxTokenGenerationMode, envoyPasswd, envoyToken, envoyTokenInstaller, enlightenUser, enlightenPasswd, envoyIdFile, envoyTokenFile, device);
106
- envoyDevice.on('publishAccessory', (accessory) => {
107
- api.publishExternalAccessories(PluginName, [accessory]);
108
- const emitLog = disableLogSuccess ? false : log.success(`Device: ${host} ${deviceName}, Published as external accessory.`);
109
- })
110
- .on('devInfo', (devInfo) => {
111
- const emitLog = disableLogDeviceInfo ? false : log.info(devInfo);
112
- })
113
- .on('success', (success) => {
114
- const emitLog = disableLogSuccess ? false : log.success(`Device: ${host} ${deviceName}, ${success}.`);
115
- })
116
- .on('info', (info) => {
117
- const emitLog = disableLogInfo ? false : log.info(`Device: ${host} ${deviceName}, ${info}.`);
118
- })
119
- .on('debug', (debug, data) => {
120
- const emitLog = !enableDebugMode ? false : log.info(`Device: ${host} ${deviceName}, debug: ${data ? `${debug} ${JSON.stringify(data, null, 2)}` : `${debug}.`}`);
121
- })
122
- .on('warn', (warn) => {
123
- const emitLog = disableLogWarn ? false : log.warn(`Device: ${host} ${deviceName}, ${warn}.`);
124
- })
125
- .on('error', (error) => {
126
- const emitLog = disableLogError ? false : log.error(`Device: ${host} ${deviceName}, ${error}.`);
127
- })
128
-
129
- //create impulse generator
130
- let lock = false;
131
- const impulseGenerator = new ImpulseGenerator();
132
- impulseGenerator.on('start', async () => {
133
- if (lock) return;
134
-
135
- try {
136
- lock = true;
137
- const startDone = await envoyDevice.start();
138
- const stopImpulseGenerator = startDone ? await impulseGenerator.stop() : false;
139
-
140
- //start impulse generator
141
- const startImpulseGenerator = startDone ? await envoyDevice.startImpulseGenerator() : false
142
- lock = false;
143
- } catch (error) {
144
- lock = false;
145
- const emitLog = disableLogError ? false : log.error(`Device: ${host} ${deviceName}, ${error}, trying again.`);
146
- }
147
- }).on('state', (state) => {
148
- const emitLog = !enableDebugMode ? false : state ? log.info(`Device: ${host} ${deviceName}, Start impulse generator started.`) : log.info(`Device: ${host} ${deviceName}, Start impulse generator stopped.`);
149
- })
150
-
151
- //start impulse generator
152
- await impulseGenerator.start([{ name: 'start', sampling: 60000 }]);
153
- } catch (error) {
154
- throw new Error(`Device: ${host} ${deviceName}, Did finish launching error: ${error}.`);
93
+ const devicesClass = device.energyMeter ? [EnvoyDevice, EnergyMeter] : [EnvoyDevice];
94
+ for (const [index, DeviceClass] of devicesClass.entries()) {
95
+ try {
96
+ const accessoryName = index === 0 ? deviceName : 'Energy Meter';
97
+ const envoyDevice = new DeviceClass(
98
+ api,
99
+ log,
100
+ accessoryName,
101
+ host,
102
+ displayType,
103
+ envoyFirmware7xxTokenGenerationMode,
104
+ envoyPasswd,
105
+ envoyToken,
106
+ envoyTokenInstaller,
107
+ enlightenUser,
108
+ enlightenPasswd,
109
+ envoyIdFile,
110
+ envoyTokenFile,
111
+ device,
112
+ energyMeterHistory,
113
+ index === 1 ? this.FakeGatoHistoryService : undefined
114
+ );
115
+
116
+ this.attachEventHandlers(api, envoyDevice, log, {
117
+ host,
118
+ deviceName: accessoryName,
119
+ enableDebugMode,
120
+ disableLogDeviceInfo,
121
+ disableLogInfo,
122
+ disableLogSuccess,
123
+ disableLogWarn,
124
+ disableLogError
125
+ });
126
+
127
+ const impulseGenerator = new ImpulseGenerator();
128
+ let lock = false;
129
+
130
+ impulseGenerator
131
+ .on('start', async () => {
132
+ if (lock) return;
133
+ lock = true;
134
+ try {
135
+ const started = await envoyDevice.start();
136
+ if (started) {
137
+ await impulseGenerator.stop();
138
+ await envoyDevice.startImpulseGenerator();
139
+ }
140
+ } catch (error) {
141
+ if (!disableLogError) log.error(`Device: ${host} ${accessoryName}, ${error}, retrying.`);
142
+ } finally {
143
+ lock = false;
144
+ }
145
+ })
146
+ .on('state', state => {
147
+ if (enableDebugMode) log.info(`Device: ${host} ${accessoryName}, Impulse generator ${state ? 'started' : 'stopped'}.`);
148
+ });
149
+
150
+ await impulseGenerator.start([{ name: 'start', sampling: 60000 }]);
151
+ } catch (error) {
152
+ log.error(`Device: ${host} ${deviceName}, Initialization error: ${error}`);
153
+ }
155
154
  }
156
- i++;
157
155
  }
158
- })
156
+ });
157
+ }
158
+
159
+ attachEventHandlers(api, envoyDevice, log, { host, deviceName, enableDebugMode, disableLogDeviceInfo, disableLogInfo, disableLogSuccess, disableLogWarn, disableLogError }) {
160
+ envoyDevice
161
+ .on('publishAccessory', accessory => {
162
+ api.publishExternalAccessories(PluginName, [accessory]);
163
+ if (!disableLogSuccess) log.success(`Device: ${host} ${deviceName}, Published as external accessory.`);
164
+ })
165
+ .on('devInfo', devInfo => {
166
+ if (!disableLogDeviceInfo) log.info(devInfo);
167
+ })
168
+ .on('success', msg => {
169
+ if (!disableLogSuccess) log.success(`Device: ${host} ${deviceName}, ${msg}`);
170
+ })
171
+ .on('info', msg => {
172
+ if (!disableLogInfo) log.info(`Device: ${host} ${deviceName}, ${msg}`);
173
+ })
174
+ .on('debug', (msg, data) => {
175
+ if (enableDebugMode) log.info(`Device: ${host} ${deviceName}, debug: ${data ? `${msg} ${JSON.stringify(data, null, 2)}` : msg}`);
176
+ })
177
+ .on('warn', msg => {
178
+ if (!disableLogWarn) log.warn(`Device: ${host} ${deviceName}, ${msg}`);
179
+ })
180
+ .on('error', error => {
181
+ if (!disableLogError) log.error(`Device: ${host} ${deviceName}, ${error}`);
182
+ });
159
183
  }
160
184
 
161
185
  configureAccessory(accessory) {
186
+ accessory.log = this.log;
187
+ this.loggingService = new fakegato('energy', accessory, 4032);
162
188
  this.accessories.push(accessory);
163
189
  }
164
190
  }
165
191
 
166
192
  export default (api) => {
167
- //import and register custom characteristics
168
193
  CustomCharacteristics(api);
169
194
  api.registerPlatform(PluginName, PlatformName, EnvoyPlatform);
170
- }
195
+ };
196
+
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.0-beta.21",
5
+ "version": "10.2.0-beta.211",
6
6
  "description": "Homebridge plugin for Photovoltaic Energy System manufactured by Enphase.",
7
7
  "license": "MIT",
8
8
  "author": "grzegorz914",
@@ -38,7 +38,8 @@
38
38
  "async-mqtt": "^2.6.3",
39
39
  "axios": "^1.10.0",
40
40
  "express": "^5.1.0",
41
- "fast-xml-parser": "^5.2.5"
41
+ "fast-xml-parser": "^5.2.5",
42
+ "fakegato-history": "^0.6.7"
42
43
  },
43
44
  "keywords": [
44
45
  "homebridge",
package/src/constants.js CHANGED
@@ -160,6 +160,10 @@ export const PartNumbers = {
160
160
 
161
161
  export const ApiCodes = {
162
162
  "unknown": "Unknown",
163
+ "backup": "Full backup",
164
+ "economy": "Economy",
165
+ "savings-mode": "Savings",
166
+ "self-consumption": "Self consumption",
163
167
  "on": "On",
164
168
  "off": "Off",
165
169
  "auto": "Auto",
@@ -211,6 +215,7 @@ export const ApiCodes = {
211
215
  "ENCHG_STATE_IDLE": "Encharge state idle",
212
216
  "ENCHG_STATE_CHARGING": "Encharge state charging",
213
217
  "ENCHG_STATE_DISCHARGING": "Encharge state discharging",
218
+ "StorageTouMode_DEFAULT_TOU_MODE": "Default tou mode",
214
219
  "ready": "Ready",
215
220
  "idle": "Idle",
216
221
  "full": "Full",
@@ -2126,7 +2126,7 @@ export default (api) => {
2126
2126
  Service.LiveDataService = LiveDataService;
2127
2127
 
2128
2128
  // EVE electric meter
2129
- class EvePower extends Characteristic {
2129
+ class EveCurrentConsumption extends Characteristic {
2130
2130
  constructor() {
2131
2131
  super('Power', 'E863F10D-079E-48FF-8F27-9C2605A29F52');
2132
2132
  this.setProps({
@@ -2140,23 +2140,23 @@ export default (api) => {
2140
2140
  this.value = this.getDefaultValue();
2141
2141
  }
2142
2142
  }
2143
- Characteristic.EvePower = EvePower;
2143
+ Characteristic.EveCurrentConsumption = EveCurrentConsumption;
2144
2144
 
2145
- class EveEnergy extends Characteristic {
2145
+ class EveTotalConsumption extends Characteristic {
2146
2146
  constructor() {
2147
2147
  super('Energy', 'E863F10C-079E-48FF-8F27-9C2605A29F52');
2148
2148
  this.setProps({
2149
2149
  format: Formats.FLOAT,
2150
2150
  unit: 'kWh',
2151
- maxValue: 100000000,
2152
- minValue: -100000000,
2151
+ maxValue: 4294967295,
2152
+ minValue: 0,
2153
2153
  minStep: 0.001,
2154
2154
  perms: [Perms.PAIRED_READ, Perms.NOTIFY]
2155
2155
  });
2156
2156
  this.value = this.getDefaultValue();
2157
2157
  }
2158
2158
  }
2159
- Characteristic.EveEnergy = EveEnergy;
2159
+ Characteristic.EveTotalConsumption = EveTotalConsumption;
2160
2160
 
2161
2161
  class EveVoltage extends Characteristic {
2162
2162
  constructor() {
@@ -2174,7 +2174,7 @@ export default (api) => {
2174
2174
  }
2175
2175
  Characteristic.EveVoltage = EveVoltage;
2176
2176
 
2177
- class EveCurrent extends Characteristic {
2177
+ class EveElectricCurrent extends Characteristic {
2178
2178
  constructor() {
2179
2179
  super('Current', 'E863F126-079E-48FF-8F27-9C2605A29F52');
2180
2180
  this.setProps({
@@ -2188,20 +2188,34 @@ export default (api) => {
2188
2188
  this.value = this.getDefaultValue();
2189
2189
  }
2190
2190
  }
2191
- Characteristic.EveCurrent = EveCurrent;
2191
+ Characteristic.EveElectricCurrent = EveElectricCurrent;
2192
+
2193
+ class EveResetTime extends Characteristic {
2194
+ constructor() {
2195
+ super('Reset time', 'E863F112-079E-48FF-8F27-9C2605A29F52');
2196
+ this.setProps({
2197
+ format: Formats.UInt32,
2198
+ perms: [Perms.PAIRED_READ, Perms.PAIRED_WRITE, Perms.NOTIFY]
2199
+ });
2200
+ this.value = this.getDefaultValue();
2201
+ }
2202
+ }
2203
+ Characteristic.EveResetTime = EveResetTime;
2204
+
2192
2205
 
2193
2206
  // Eve Power‑Meter service
2194
- class EveMeter extends Service {
2207
+ class EvePowerMeter extends Service {
2195
2208
  constructor(displayName, subtype) {
2196
2209
  super(displayName, 'E863F130-079E-48FF-8F27-9C2605A29F52', subtype);
2197
2210
  // Mandatory Characteristics
2198
- this.addCharacteristic(Characteristic.EvePower);
2199
- this.addCharacteristic(Characteristic.EveEnergy);
2211
+ this.addCharacteristic(Characteristic.EveCurrentConsumption);
2212
+ this.addCharacteristic(Characteristic.EveTotalConsumption);
2200
2213
  // Optional Characteristics
2201
2214
  this.addOptionalCharacteristic(Characteristic.EveVoltage);
2202
- this.addOptionalCharacteristic(Characteristic.EveCurrent);
2215
+ this.addOptionalCharacteristic(Characteristic.EveElectricCurrent);
2216
+ this.addOptionalCharacteristic(Characteristic.EveResetTime);
2203
2217
  this.addOptionalCharacteristic(Characteristic.ConfiguredName);
2204
2218
  }
2205
2219
  }
2206
- Service.EveMeter = EveMeter;
2220
+ Service.EvePowerMeter = EvePowerMeter;
2207
2221
  };