homebridge-rainforest-eagle3 1.0.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 dacarson
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,185 @@
1
+ # homebridge-rainforest-eagle3
2
+
3
+ A [Homebridge](https://homebridge.io) plugin for the [Rainforest Automation EAGLE-200](https://www.rainforestautomation.com/rfa-z114-eagle-200/) smart meter gateway. Exposes your utility grid meter as an **Eve Energy** accessory in Apple HomeKit, with real-time power demand, cumulative import energy, and native Eve app consumption history.
4
+
5
+ ---
6
+
7
+ ## Features
8
+
9
+ - Real-time grid demand in Watts (visible in the Eve app and HomeKit detail view)
10
+ - Cumulative energy imported (kWh) as a lifetime total
11
+ - Optional **export meter** accessory for homes with solar net metering — shows real-time export watts and lifetime energy exported to the grid
12
+ - Up to 7 days of native consumption/export history in the Eve app via [fakegato-history](https://github.com/simont77/fakegato-history)
13
+ - Polls the EAGLE-200 **local** HTTP API — no cloud account or internet required at runtime
14
+ - Stateless Basic Auth — no session management, no re-login lifecycle
15
+ - Designed to complement [homebridge-pvs6](https://github.com/dacarson/homebridge-pvs6) for a complete solar + grid picture in Apple Home
16
+
17
+ ---
18
+
19
+ ## Supported Hardware
20
+
21
+ | Device | Status |
22
+ |---|---|
23
+ | Rainforest EAGLE-200 (RFA-Z114) | Supported |
24
+ | Rainforest EAGLE-3 | Expected compatible (uses same local API; unverified) |
25
+ | Original EAGLE (Z109) | Not supported — uses a different relay-server API |
26
+
27
+ ---
28
+
29
+ ## How It Works
30
+
31
+ The EAGLE-200 connects to your utility smart meter over ZigBee (HAN) and exposes live meter data over a local HTTP API. This plugin polls that API every `pollInterval` seconds and publishes the data as a HomeKit accessory. All communication is on your local network — no external services involved.
32
+
33
+ The accessory renders as a **smart plug** in Apple Home:
34
+
35
+ - **On** — the outlet is "in use" when the grid is actively delivering power (demand > 0 W)
36
+ - **Wattage** — visible in the detail view and in the Eve app
37
+ - **Energy history** — the Eve app shows up to 7 days of consumption history
38
+
39
+ ---
40
+
41
+ ## Requirements
42
+
43
+ - [Homebridge](https://homebridge.io) v1.6 or later
44
+ - Node.js 18 or later
45
+ - Rainforest EAGLE-200 on the same local network as your Homebridge host
46
+ - The EAGLE-200's **Cloud ID** and **Install Code** (printed on the label on the underside of the device)
47
+
48
+ ---
49
+
50
+ ## Installation
51
+
52
+ Install via the Homebridge UI plugin search, or from the command line:
53
+
54
+ ```bash
55
+ npm install -g homebridge-rainforest-eagle3
56
+ ```
57
+
58
+ ---
59
+
60
+ ## Configuration
61
+
62
+ Add a platform entry to your Homebridge `config.json`.
63
+
64
+ Minimal setup (import meter only):
65
+
66
+ ```json
67
+ {
68
+ "platforms": [
69
+ {
70
+ "platform": "EAGLE",
71
+ "name": "EAGLE",
72
+ "cloudId": "004792",
73
+ "installCode": "bfb0fc05f51a3932"
74
+ }
75
+ ]
76
+ }
77
+ ```
78
+
79
+ With export meter enabled (for solar / net metering):
80
+
81
+ ```json
82
+ {
83
+ "platforms": [
84
+ {
85
+ "platform": "EAGLE",
86
+ "name": "EAGLE",
87
+ "cloudId": "004792",
88
+ "installCode": "bfb0fc05f51a3932",
89
+ "pollInterval": 15,
90
+ "meterName": "Grid Meter - Import",
91
+ "showExportMeter": true,
92
+ "exportMeterName": "Grid Meter - Export"
93
+ }
94
+ ]
95
+ }
96
+ ```
97
+
98
+ ### Configuration Options
99
+
100
+ | Field | Type | Required | Default | Description |
101
+ |---|---|---|---|---|
102
+ | `platform` | string | yes | — | Must be `EAGLE` |
103
+ | `host` | string | no | `eagle-<cloudId>.local` | IP address or mDNS hostname of the EAGLE-200. Omit to use mDNS auto-discovery. |
104
+ | `cloudId` | string | yes | — | Cloud ID from the device label (6 hex characters, upper-left of label) |
105
+ | `installCode` | string | yes | — | Install Code from the device label (16 hex characters) |
106
+ | `pollInterval` | integer | no | `15` | Seconds between polls. Minimum enforced: `5` |
107
+ | `meterName` | string | no | `"Grid Meter"` | Display name for the import meter accessory. Defaults to `"Grid Meter - Import"` when `showExportMeter` is `true`. |
108
+ | `showExportMeter` | boolean | no | `false` | Register a second accessory showing power exported to the grid. |
109
+ | `exportMeterName` | string | no | `"Grid Meter - Export"` | Display name for the export meter accessory. |
110
+
111
+ ### Finding Your Credentials
112
+
113
+ Flip the EAGLE-200 over and look at the label. You need:
114
+
115
+ - **Cloud ID** — 6-character hex string in the upper-left (e.g. `004792`)
116
+ - **Install Code** — 16-character hex string below the Cloud ID (e.g. `bfb0fc05f51a3932`)
117
+
118
+ The device is also reachable at `eagle-<cloudId>.local` via mDNS if you prefer not to use a static IP.
119
+
120
+ ---
121
+
122
+ ## HomeKit Accessories
123
+
124
+ ### Import Meter (always registered)
125
+
126
+ | Characteristic | Source | Notes |
127
+ |---|---|---|
128
+ | On | `demand > 0` | True when consuming grid power |
129
+ | OutletInUse | Always `true` | Required by Eve Energy |
130
+ | Eve Watts | `max(0, demand) × 1000` | Import watts. Zero when net-exporting. |
131
+ | Eve kWh | `CurrentSummationDelivered` | Lifetime energy imported from grid |
132
+
133
+ ### Export Meter (optional — `showExportMeter: true`)
134
+
135
+ | Characteristic | Source | Notes |
136
+ |---|---|---|
137
+ | On | `demand < 0` | True when exporting to the grid |
138
+ | OutletInUse | Always `true` | Required by Eve Energy |
139
+ | Eve Watts | `max(0, −demand) × 1000` | Export watts. Zero when not exporting. |
140
+ | Eve kWh | `CurrentSummationReceived` | Lifetime energy exported to grid. Shows `0` if the meter does not report this variable. |
141
+
142
+ The two accessories are mutually exclusive — at any given moment only one shows a non-zero wattage. Both render as smart plugs in Apple Home; the Eve app shows up to 7 days of history for each.
143
+
144
+ **Note on `CurrentSummationReceived`:** Many meters and firmware versions do not report this variable. When it is absent, the export kWh characteristic stays at `0`, but the real-time export watts (derived from a negative `InstantaneousDemand`) still work correctly.
145
+
146
+ ---
147
+
148
+ ## Error Handling
149
+
150
+ The plugin is designed to be resilient to transient EAGLE-200 failures:
151
+
152
+ - If the EAGLE is unreachable at startup, discovery retries every 30 seconds
153
+ - Poll cycles are skipped (not fatal) on timeout, XML parse errors, or HTTP 5xx responses
154
+ - HTTP 401 triggers a 60-second backoff and an error log (check your credentials)
155
+ - The EAGLE's embedded HTTP server can be overwhelmed by frequent polling; the default 15-second interval is conservative by design
156
+ - HomeKit characteristics retain their last known-good values during outages
157
+
158
+ ---
159
+
160
+ ## Building from Source
161
+
162
+ ```bash
163
+ git clone https://github.com/dacarson/homebridge-rainforest-eagle3.git
164
+ cd homebridge-rainforest-eagle3
165
+ npm install
166
+ npm run build
167
+ ```
168
+
169
+ To develop with live rebuilds:
170
+
171
+ ```bash
172
+ npm run watch
173
+ ```
174
+
175
+ ---
176
+
177
+ ## Related Plugins
178
+
179
+ - [homebridge-pvs6](https://github.com/dacarson/homebridge-pvs6) — SunPower PVS6 solar production, designed to sit alongside this plugin in Apple Home
180
+
181
+ ---
182
+
183
+ ## License
184
+
185
+ Apache-2.0
@@ -0,0 +1,74 @@
1
+ {
2
+ "pluginAlias": "EAGLE",
3
+ "pluginType": "platform",
4
+ "singular": true,
5
+ "schema": {
6
+ "type": "object",
7
+ "properties": {
8
+ "name": {
9
+ "title": "Name",
10
+ "type": "string",
11
+ "default": "EAGLE"
12
+ },
13
+ "cloudId": {
14
+ "title": "Cloud ID",
15
+ "type": "string",
16
+ "placeholder": "004792",
17
+ "description": "6-character Cloud ID from the label on the underside of the device."
18
+ },
19
+ "installCode": {
20
+ "title": "Install Code",
21
+ "type": "string",
22
+ "placeholder": "bfb0fc05f51a3932",
23
+ "description": "16-character Install Code from the label on the underside of the device."
24
+ },
25
+ "host": {
26
+ "title": "Host",
27
+ "type": "string",
28
+ "placeholder": "192.168.1.x or eagle-XXXXXX.local",
29
+ "description": "IP address or mDNS hostname of the EAGLE-200. If omitted, defaults to eagle-<cloudId>.local (mDNS)."
30
+ },
31
+ "pollInterval": {
32
+ "title": "Poll Interval (seconds)",
33
+ "type": "integer",
34
+ "default": 15,
35
+ "minimum": 5,
36
+ "description": "How often to poll the EAGLE-200 for new meter data. Minimum 5 seconds."
37
+ },
38
+ "meterName": {
39
+ "title": "Import Meter Display Name",
40
+ "type": "string",
41
+ "default": "Grid Meter",
42
+ "description": "HomeKit display name for the import meter accessory. Defaults to 'Grid Meter - Import' when showExportMeter is true."
43
+ },
44
+ "showExportMeter": {
45
+ "title": "Show Export Meter",
46
+ "type": "boolean",
47
+ "default": false,
48
+ "description": "Register a second Eve Energy accessory showing power exported to the grid (net metering / solar)."
49
+ },
50
+ "exportMeterName": {
51
+ "title": "Export Meter Display Name",
52
+ "type": "string",
53
+ "default": "Grid Meter - Export",
54
+ "description": "HomeKit display name for the export meter accessory. Only used when showExportMeter is true."
55
+ }
56
+ },
57
+ "required": ["cloudId", "installCode"]
58
+ },
59
+ "layout": [
60
+ { "key": "name" },
61
+ { "key": "cloudId" },
62
+ { "key": "installCode" },
63
+ { "key": "host" },
64
+ { "key": "pollInterval" },
65
+ { "key": "meterName" },
66
+ { "key": "showExportMeter" },
67
+ {
68
+ "key": "exportMeterName",
69
+ "condition": {
70
+ "functionBody": "return model.showExportMeter === true;"
71
+ }
72
+ }
73
+ ]
74
+ }
@@ -0,0 +1,22 @@
1
+ import { Logger } from 'homebridge';
2
+ export interface MeterReading {
3
+ demand_kw: number;
4
+ summation_delivered_kwh: number;
5
+ summation_received_kwh?: number;
6
+ }
7
+ export declare class HttpError extends Error {
8
+ readonly statusCode: number;
9
+ constructor(statusCode: number, message: string);
10
+ }
11
+ export declare class EagleClient {
12
+ private readonly host;
13
+ private readonly log;
14
+ private readonly auth;
15
+ private readonly parser;
16
+ constructor(host: string, cloudId: string, installCode: string, log: Logger);
17
+ discoverMeter(): Promise<string>;
18
+ queryMeter(meterAddress: string): Promise<MeterReading>;
19
+ private sendCommand;
20
+ private parseValue;
21
+ }
22
+ //# sourceMappingURL=eagleClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eagleClient.d.ts","sourceRoot":"","sources":["../src/eagleClient.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAGpC,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,uBAAuB,EAAE,MAAM,CAAC;IAChC,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAGD,qBAAa,SAAU,SAAQ,KAAK;aACN,UAAU,EAAE,MAAM;gBAAlB,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAIhE;AAED,qBAAa,WAAW;IAKpB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAGrB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAPtB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;gBAGhB,IAAI,EAAE,MAAM,EAC7B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACF,GAAG,EAAE,MAAM;IAcxB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC;IAiChC,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAwE7D,OAAO,CAAC,WAAW;IAgFnB,OAAO,CAAC,UAAU;CAwBnB"}
@@ -0,0 +1,228 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.EagleClient = exports.HttpError = void 0;
37
+ const net = __importStar(require("net"));
38
+ const fast_xml_parser_1 = require("fast-xml-parser");
39
+ // Thrown for HTTP-level errors so the caller can distinguish 401 vs 503 vs other.
40
+ class HttpError extends Error {
41
+ constructor(statusCode, message) {
42
+ super(message);
43
+ this.statusCode = statusCode;
44
+ this.name = 'HttpError';
45
+ }
46
+ }
47
+ exports.HttpError = HttpError;
48
+ class EagleClient {
49
+ constructor(host, cloudId, installCode, log) {
50
+ this.host = host;
51
+ this.log = log;
52
+ this.auth = Buffer.from(`${cloudId}:${installCode}`).toString('base64');
53
+ this.parser = new fast_xml_parser_1.XMLParser({
54
+ ignoreAttributes: false,
55
+ parseTagValue: false,
56
+ // Force Device to array only inside DeviceList (device_list response).
57
+ // The device_query response has a single <Device> at root — must NOT be an array.
58
+ isArray: (name, jpath) => (name === 'Device' && jpath === 'DeviceList.Device') || name === 'Variable',
59
+ });
60
+ }
61
+ // Returns the HardwareAddress of the electric_meter device.
62
+ async discoverMeter() {
63
+ const body = '<Command>\r\n <Name>device_list</Name>\r\n</Command>';
64
+ const responseXml = await this.sendCommand(body);
65
+ const parsed = this.parser.parse(responseXml);
66
+ const deviceList = parsed['DeviceList'];
67
+ if (!deviceList) {
68
+ throw new Error('device_list response missing <DeviceList> element');
69
+ }
70
+ const devices = deviceList['Device'];
71
+ if (!Array.isArray(devices) || devices.length === 0) {
72
+ throw new Error('No devices in device_list response');
73
+ }
74
+ const meter = devices.find((d) => String(d['ModelId'] ?? '').toLowerCase() === 'electric_meter');
75
+ if (!meter) {
76
+ throw new Error('No electric_meter device found in device_list response');
77
+ }
78
+ const address = meter['HardwareAddress'];
79
+ if (!address) {
80
+ throw new Error('electric_meter device has no HardwareAddress');
81
+ }
82
+ // The EAGLE returns the address with the 0x prefix already — use verbatim.
83
+ return String(address);
84
+ }
85
+ // Returns current meter readings. summation_received_kwh is optional — not all
86
+ // meters/firmwares return CurrentSummationReceived.
87
+ async queryMeter(meterAddress) {
88
+ const body = [
89
+ '<Command>',
90
+ ' <Name>device_query</Name>',
91
+ ' <DeviceDetails>',
92
+ ` <HardwareAddress>${meterAddress}</HardwareAddress>`,
93
+ ' </DeviceDetails>',
94
+ ' <Components>',
95
+ ' <Component>',
96
+ ' <Name>Main</Name>',
97
+ ' <Variables>',
98
+ ' <Variable><Name>zigbee:InstantaneousDemand</Name></Variable>',
99
+ ' <Variable><Name>zigbee:CurrentSummationDelivered</Name></Variable>',
100
+ ' <Variable><Name>zigbee:CurrentSummationReceived</Name></Variable>',
101
+ ' </Variables>',
102
+ ' </Component>',
103
+ ' </Components>',
104
+ '</Command>',
105
+ ].join('\r\n');
106
+ const responseXml = await this.sendCommand(body);
107
+ const parsed = this.parser.parse(responseXml);
108
+ const device = parsed['Device'];
109
+ if (!device) {
110
+ throw new Error('device_query response missing <Device> element');
111
+ }
112
+ const deviceDetails = device['DeviceDetails'];
113
+ const connectionStatus = deviceDetails?.['ConnectionStatus'] ?? '';
114
+ if (connectionStatus.toLowerCase() !== 'connected') {
115
+ throw new Error(`Meter ConnectionStatus is '${connectionStatus}', not Connected`);
116
+ }
117
+ // Navigate Device > Components > Component > Variables > Variable[]
118
+ const components = device['Components'];
119
+ const component = components?.['Component'];
120
+ const variables = component?.['Variables'];
121
+ const varList = variables?.['Variable'];
122
+ if (!Array.isArray(varList)) {
123
+ throw new Error('device_query response has no <Variable> elements');
124
+ }
125
+ const varMap = new Map();
126
+ for (const v of varList) {
127
+ const name = v['Name'];
128
+ const value = v['Value'];
129
+ if (name && value) {
130
+ varMap.set(String(name), String(value));
131
+ }
132
+ }
133
+ const demand_kw = this.parseValue(varMap.get('zigbee:InstantaneousDemand'), 'zigbee:InstantaneousDemand');
134
+ const summation_delivered_kwh = this.parseValue(varMap.get('zigbee:CurrentSummationDelivered'), 'zigbee:CurrentSummationDelivered');
135
+ const receivedRaw = varMap.get('zigbee:CurrentSummationReceived');
136
+ const summation_received_kwh = receivedRaw !== undefined
137
+ ? this.parseValue(receivedRaw, 'zigbee:CurrentSummationReceived')
138
+ : undefined;
139
+ return { demand_kw, summation_delivered_kwh, summation_received_kwh };
140
+ }
141
+ // Raw HTTP/1.0 over net.Socket — axios/fetch cannot downgrade from HTTP/1.1.
142
+ sendCommand(xmlBody) {
143
+ return new Promise((resolve, reject) => {
144
+ const bodyBytes = Buffer.from(xmlBody, 'utf8');
145
+ const request = `POST /cgi-bin/post_manager HTTP/1.0\r\n` +
146
+ `Host: ${this.host}\r\n` +
147
+ `Content-type: text/xml\r\n` +
148
+ `Content-Length: ${bodyBytes.length}\r\n` +
149
+ `Authorization: Basic ${this.auth}\r\n` +
150
+ `\r\n`;
151
+ const socket = new net.Socket();
152
+ const chunks = [];
153
+ let settled = false;
154
+ const done = (err) => {
155
+ if (settled) {
156
+ return;
157
+ }
158
+ settled = true;
159
+ socket.destroy();
160
+ if (err) {
161
+ reject(err);
162
+ }
163
+ };
164
+ socket.setTimeout(10000);
165
+ socket.on('timeout', () => done(new Error('Socket timeout after 10s')));
166
+ socket.on('error', (err) => done(err));
167
+ socket.on('data', (chunk) => chunks.push(chunk));
168
+ socket.on('close', () => {
169
+ if (settled) {
170
+ return;
171
+ }
172
+ settled = true;
173
+ socket.destroy();
174
+ const raw = Buffer.concat(chunks).toString('utf8');
175
+ const headerBodySplit = raw.indexOf('\r\n\r\n');
176
+ if (headerBodySplit === -1) {
177
+ reject(new Error('Malformed HTTP response: no header/body separator'));
178
+ return;
179
+ }
180
+ const headerSection = raw.slice(0, headerBodySplit);
181
+ const body = raw.slice(headerBodySplit + 4);
182
+ this.log.debug(`EAGLE response: ${body.trim()}`);
183
+ const statusLine = headerSection.split('\r\n')[0] ?? '';
184
+ const statusMatch = statusLine.match(/^HTTP\/\S+\s+(\d{3})/);
185
+ if (!statusMatch) {
186
+ reject(new Error(`Could not parse HTTP status line: ${statusLine}`));
187
+ return;
188
+ }
189
+ const statusCode = parseInt(statusMatch[1], 10);
190
+ if (statusCode !== 200) {
191
+ reject(new HttpError(statusCode, `HTTP ${statusCode}: ${statusLine}`));
192
+ return;
193
+ }
194
+ if (!body.trim()) {
195
+ reject(new Error('Empty response body'));
196
+ return;
197
+ }
198
+ resolve(body);
199
+ });
200
+ socket.connect(80, this.host, () => {
201
+ socket.write(request);
202
+ socket.write(bodyBytes);
203
+ });
204
+ });
205
+ }
206
+ parseValue(raw, varName) {
207
+ if (raw === undefined) {
208
+ throw new Error(`Required variable ${varName} missing from response`);
209
+ }
210
+ const trimmed = raw.trim();
211
+ // Expected format: "1.234 kW" or "12345.678 kWh"
212
+ const match = trimmed.match(/^(-?[\d.]+)\s*(\S+)?$/);
213
+ if (!match) {
214
+ throw new Error(`Cannot parse value '${trimmed}' for ${varName}`);
215
+ }
216
+ const unit = match[2] ?? '';
217
+ if (unit && unit !== 'kW' && unit !== 'kWh') {
218
+ this.log.warn(`Unexpected unit '${unit}' for ${varName} — value: ${trimmed}`);
219
+ }
220
+ const parsed = parseFloat(match[1]);
221
+ if (isNaN(parsed)) {
222
+ throw new Error(`NaN after parsing '${trimmed}' for ${varName}`);
223
+ }
224
+ return parsed;
225
+ }
226
+ }
227
+ exports.EagleClient = EagleClient;
228
+ //# sourceMappingURL=eagleClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eagleClient.js","sourceRoot":"","sources":["../src/eagleClient.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { API, Characteristic } from 'homebridge';
2
+ export declare const EVE_ENERGY_SERVICE_UUID = "E863F10A-079E-48FF-8F27-9C2605A29F52";
3
+ export declare const EVE_WATT_UUID = "E863F10D-079E-48FF-8F27-9C2605A29F52";
4
+ export declare const EVE_KWH_UUID = "E863F10C-079E-48FF-8F27-9C2605A29F52";
5
+ export type EveCharClass = {
6
+ new (): Characteristic;
7
+ UUID: string;
8
+ };
9
+ export interface EveChars {
10
+ EveWatts: EveCharClass;
11
+ EveKWh: EveCharClass;
12
+ }
13
+ export declare function createEveCharacteristics(api: API): EveChars;
14
+ //# sourceMappingURL=eveCharacteristics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eveCharacteristics.d.ts","sourceRoot":"","sources":["../src/eveCharacteristics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,cAAc,EAAkB,MAAM,YAAY,CAAC;AAEjE,eAAO,MAAM,uBAAuB,yCAAyC,CAAC;AAC9E,eAAO,MAAM,aAAa,yCAAyC,CAAC;AACpE,eAAO,MAAM,YAAY,yCAAyC,CAAC;AAGnE,MAAM,MAAM,YAAY,GAAG;IAAE,QAAO,cAAc,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnE,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,YAAY,CAAC;IACvB,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,GAAG,GAAG,QAAQ,CAuC3D"}
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EVE_KWH_UUID = exports.EVE_WATT_UUID = exports.EVE_ENERGY_SERVICE_UUID = void 0;
4
+ exports.createEveCharacteristics = createEveCharacteristics;
5
+ exports.EVE_ENERGY_SERVICE_UUID = 'E863F10A-079E-48FF-8F27-9C2605A29F52';
6
+ exports.EVE_WATT_UUID = 'E863F10D-079E-48FF-8F27-9C2605A29F52';
7
+ exports.EVE_KWH_UUID = 'E863F10C-079E-48FF-8F27-9C2605A29F52';
8
+ function createEveCharacteristics(api) {
9
+ const hap = api.hap;
10
+ class EveWatts extends hap.Characteristic {
11
+ constructor() {
12
+ super('Eve Watts', EveWatts.UUID, {
13
+ format: "float" /* Formats.FLOAT */,
14
+ unit: 'W',
15
+ minValue: 0,
16
+ maxValue: 100000,
17
+ minStep: 0.1,
18
+ perms: ["pr" /* Perms.PAIRED_READ */, "ev" /* Perms.NOTIFY */],
19
+ });
20
+ this.value = this.getDefaultValue();
21
+ }
22
+ }
23
+ EveWatts.UUID = exports.EVE_WATT_UUID;
24
+ class EveKWh extends hap.Characteristic {
25
+ constructor() {
26
+ super('Eve kWh', EveKWh.UUID, {
27
+ format: "float" /* Formats.FLOAT */,
28
+ unit: 'kWh',
29
+ minValue: 0,
30
+ maxValue: 1000000,
31
+ minStep: 0.001,
32
+ perms: ["pr" /* Perms.PAIRED_READ */, "ev" /* Perms.NOTIFY */],
33
+ });
34
+ this.value = this.getDefaultValue();
35
+ }
36
+ }
37
+ EveKWh.UUID = exports.EVE_KWH_UUID;
38
+ return {
39
+ EveWatts: EveWatts,
40
+ EveKWh: EveKWh,
41
+ };
42
+ }
43
+ //# sourceMappingURL=eveCharacteristics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eveCharacteristics.js","sourceRoot":"","sources":["../src/eveCharacteristics.ts"],"names":[],"mappings":";;;AAcA,4DAuCC;AAnDY,QAAA,uBAAuB,GAAG,sCAAsC,CAAC;AACjE,QAAA,aAAa,GAAG,sCAAsC,CAAC;AACvD,QAAA,YAAY,GAAG,sCAAsC,CAAC;AAUnE,SAAgB,wBAAwB,CAAC,GAAQ;IAC/C,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IAEpB,MAAM,QAAS,SAAQ,GAAG,CAAC,cAAc;QAGvC;YACE,KAAK,CAAC,WAAW,EAAE,QAAQ,CAAC,IAAI,EAAE;gBAChC,MAAM,6BAAe;gBACrB,IAAI,EAAE,GAAa;gBACnB,QAAQ,EAAE,CAAC;gBACX,QAAQ,EAAE,MAAM;gBAChB,OAAO,EAAE,GAAG;gBACZ,KAAK,EAAE,uDAAiC;aACzC,CAAC,CAAC;YACH,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QACtC,CAAC;;IAZe,aAAI,GAAG,qBAAa,CAAC;IAevC,MAAM,MAAO,SAAQ,GAAG,CAAC,cAAc;QAGrC;YACE,KAAK,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,EAAE;gBAC5B,MAAM,6BAAe;gBACrB,IAAI,EAAE,KAAe;gBACrB,QAAQ,EAAE,CAAC;gBACX,QAAQ,EAAE,OAAO;gBACjB,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,uDAAiC;aACzC,CAAC,CAAC;YACH,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QACtC,CAAC;;IAZe,WAAI,GAAG,oBAAY,CAAC;IAetC,OAAO;QACL,QAAQ,EAAE,QAAmC;QAC7C,MAAM,EAAE,MAAiC;KAC1C,CAAC;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { PlatformAccessory } from 'homebridge';
2
+ import { EAGLEPlatform } from './platform';
3
+ import { MeterReading } from './eagleClient';
4
+ export declare class ExportMeterAccessory {
5
+ private readonly platform;
6
+ private readonly eveEnergyService;
7
+ private readonly historyService;
8
+ private lastExportW;
9
+ private lastReceivedKwh;
10
+ constructor(platform: EAGLEPlatform, accessory: PlatformAccessory, FakeGatoHistoryService: any, meterAddress: string);
11
+ updateValues(reading: MeterReading): void;
12
+ }
13
+ //# sourceMappingURL=exportMeterAccessory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exportMeterAccessory.d.ts","sourceRoot":"","sources":["../src/exportMeterAccessory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAW,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAG7C,qBAAa,oBAAoB;IAS7B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAR3B,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAU;IAE3C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAM;IAErC,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,eAAe,CAAK;gBAGT,QAAQ,EAAE,aAAa,EACxC,SAAS,EAAE,iBAAiB,EAE5B,sBAAsB,EAAE,GAAG,EAC3B,YAAY,EAAE,MAAM;IAqDtB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;CAiB1C"}
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ExportMeterAccessory = void 0;
4
+ const eveCharacteristics_1 = require("./eveCharacteristics");
5
+ class ExportMeterAccessory {
6
+ constructor(platform, accessory,
7
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
+ FakeGatoHistoryService, meterAddress) {
9
+ this.platform = platform;
10
+ this.lastExportW = 0;
11
+ this.lastReceivedKwh = 0;
12
+ const { Characteristic, api } = platform;
13
+ const { EveWatts, EveKWh } = platform.eveChars;
14
+ const infoService = accessory.getService(platform.Service.AccessoryInformation) ??
15
+ accessory.addService(platform.Service.AccessoryInformation);
16
+ infoService
17
+ .setCharacteristic(Characteristic.Manufacturer, 'Rainforest Automation')
18
+ .setCharacteristic(Characteristic.Model, 'EAGLE-200')
19
+ .setCharacteristic(Characteristic.SerialNumber, meterAddress.replace(/^0x/i, ''));
20
+ const existingService = accessory.services.find(s => s.UUID === eveCharacteristics_1.EVE_ENERGY_SERVICE_UUID);
21
+ if (existingService) {
22
+ this.eveEnergyService = existingService;
23
+ }
24
+ else {
25
+ this.eveEnergyService = accessory.addService(new api.hap.Service(platform.exportMeterName, eveCharacteristics_1.EVE_ENERGY_SERVICE_UUID));
26
+ }
27
+ this.eveEnergyService.setCharacteristic(Characteristic.Name, platform.exportMeterName);
28
+ // On — true when the home is actively exporting to the grid
29
+ this.eveEnergyService
30
+ .getCharacteristic(Characteristic.On)
31
+ .onGet(() => this.lastExportW > 0)
32
+ .onSet(async () => {
33
+ this.eveEnergyService.updateCharacteristic(Characteristic.On, this.lastExportW > 0);
34
+ });
35
+ this.eveEnergyService
36
+ .getCharacteristic(Characteristic.OutletInUse)
37
+ .onGet(() => true);
38
+ this.eveEnergyService
39
+ .getCharacteristic(EveWatts)
40
+ .onGet(() => this.lastExportW);
41
+ this.eveEnergyService
42
+ .getCharacteristic(EveKWh)
43
+ .onGet(() => this.lastReceivedKwh);
44
+ this.historyService = new FakeGatoHistoryService('energy', accessory, {
45
+ storage: 'fs',
46
+ });
47
+ }
48
+ updateValues(reading) {
49
+ const { Characteristic } = this.platform;
50
+ const { EveWatts, EveKWh } = this.platform.eveChars;
51
+ this.lastExportW = Math.round(Math.max(0, -reading.demand_kw) * 1000 * 10) / 10;
52
+ this.lastReceivedKwh = reading.summation_received_kwh ?? 0;
53
+ this.eveEnergyService.updateCharacteristic(Characteristic.On, this.lastExportW > 0);
54
+ this.eveEnergyService.updateCharacteristic(Characteristic.OutletInUse, true);
55
+ this.eveEnergyService.updateCharacteristic(EveWatts, this.lastExportW);
56
+ this.eveEnergyService.updateCharacteristic(EveKWh, this.lastReceivedKwh);
57
+ this.historyService.addEntry({
58
+ time: Math.round(Date.now() / 1000),
59
+ power: this.lastExportW,
60
+ });
61
+ }
62
+ }
63
+ exports.ExportMeterAccessory = ExportMeterAccessory;
64
+ //# sourceMappingURL=exportMeterAccessory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exportMeterAccessory.js","sourceRoot":"","sources":["../src/exportMeterAccessory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { PlatformAccessory } from 'homebridge';
2
+ import { EAGLEPlatform } from './platform';
3
+ import { MeterReading } from './eagleClient';
4
+ export declare class GridMeterAccessory {
5
+ private readonly platform;
6
+ private readonly eveEnergyService;
7
+ private readonly historyService;
8
+ private lastDemandW;
9
+ private lastDeliveredKwh;
10
+ constructor(platform: EAGLEPlatform, accessory: PlatformAccessory, FakeGatoHistoryService: any, meterAddress: string);
11
+ updateValues(reading: MeterReading): void;
12
+ }
13
+ //# sourceMappingURL=gridMeterAccessory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gridMeterAccessory.d.ts","sourceRoot":"","sources":["../src/gridMeterAccessory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAW,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAG7C,qBAAa,kBAAkB;IAS3B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAR3B,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAU;IAE3C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAM;IAErC,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,gBAAgB,CAAK;gBAGV,QAAQ,EAAE,aAAa,EACxC,SAAS,EAAE,iBAAiB,EAE5B,sBAAsB,EAAE,GAAG,EAC3B,YAAY,EAAE,MAAM;IA6DtB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;CAwB1C"}
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GridMeterAccessory = void 0;
4
+ const eveCharacteristics_1 = require("./eveCharacteristics");
5
+ class GridMeterAccessory {
6
+ constructor(platform, accessory,
7
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
+ FakeGatoHistoryService, meterAddress) {
9
+ this.platform = platform;
10
+ this.lastDemandW = 0;
11
+ this.lastDeliveredKwh = 0;
12
+ const { Characteristic, api } = platform;
13
+ const { EveWatts, EveKWh } = platform.eveChars;
14
+ // Accessory information service
15
+ const infoService = accessory.getService(platform.Service.AccessoryInformation) ??
16
+ accessory.addService(platform.Service.AccessoryInformation);
17
+ infoService
18
+ .setCharacteristic(Characteristic.Manufacturer, 'Rainforest Automation')
19
+ .setCharacteristic(Characteristic.Model, 'EAGLE-200')
20
+ .setCharacteristic(Characteristic.SerialNumber, meterAddress.replace(/^0x/i, ''));
21
+ // getService(string) in hap-nodejs matches by displayName/name/subtype, NOT by UUID.
22
+ // Use services.find() to reliably look up by UUID from cache.
23
+ const existingService = accessory.services.find(s => s.UUID === eveCharacteristics_1.EVE_ENERGY_SERVICE_UUID);
24
+ if (existingService) {
25
+ this.eveEnergyService = existingService;
26
+ }
27
+ else {
28
+ this.eveEnergyService = accessory.addService(new api.hap.Service(platform.meterName, eveCharacteristics_1.EVE_ENERGY_SERVICE_UUID));
29
+ }
30
+ this.eveEnergyService.setCharacteristic(Characteristic.Name, platform.meterName);
31
+ // On — true when grid is actively being consumed
32
+ this.eveEnergyService
33
+ .getCharacteristic(Characteristic.On)
34
+ .onGet(() => this.lastDemandW > 0)
35
+ .onSet(async () => {
36
+ // Read-only: revert to polled state immediately
37
+ this.eveEnergyService.updateCharacteristic(Characteristic.On, this.lastDemandW > 0);
38
+ });
39
+ // OutletInUse — always true (required by Eve Energy)
40
+ this.eveEnergyService
41
+ .getCharacteristic(Characteristic.OutletInUse)
42
+ .onGet(() => true);
43
+ // getCharacteristic(class) finds the existing characteristic from cache or adds it if absent —
44
+ // unlike addCharacteristic which always adds and throws on duplicate.
45
+ this.eveEnergyService
46
+ .getCharacteristic(EveWatts)
47
+ .onGet(() => this.lastDemandW);
48
+ this.eveEnergyService
49
+ .getCharacteristic(EveKWh)
50
+ .onGet(() => this.lastDeliveredKwh);
51
+ // fakegato-history: 'energy' type logs { time, power } in Watts
52
+ this.historyService = new FakeGatoHistoryService('energy', accessory, {
53
+ storage: 'fs',
54
+ });
55
+ }
56
+ updateValues(reading) {
57
+ const { Characteristic } = this.platform;
58
+ const { EveWatts, EveKWh } = this.platform.eveChars;
59
+ this.lastDemandW = Math.round(Math.max(0, reading.demand_kw) * 1000 * 10) / 10;
60
+ this.lastDeliveredKwh = reading.summation_delivered_kwh;
61
+ this.eveEnergyService.updateCharacteristic(Characteristic.On, this.lastDemandW > 0);
62
+ this.eveEnergyService.updateCharacteristic(Characteristic.OutletInUse, true);
63
+ this.eveEnergyService.updateCharacteristic(EveWatts, this.lastDemandW);
64
+ this.eveEnergyService.updateCharacteristic(EveKWh, this.lastDeliveredKwh);
65
+ this.historyService.addEntry({
66
+ time: Math.round(Date.now() / 1000),
67
+ power: this.lastDemandW,
68
+ });
69
+ this.platform.log.debug(`Updated: demand=${this.lastDemandW}W, delivered=${this.lastDeliveredKwh}kWh` +
70
+ (reading.summation_received_kwh !== undefined
71
+ ? `, received=${reading.summation_received_kwh}kWh`
72
+ : ''));
73
+ }
74
+ }
75
+ exports.GridMeterAccessory = GridMeterAccessory;
76
+ //# sourceMappingURL=gridMeterAccessory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gridMeterAccessory.js","sourceRoot":"","sources":["../src/gridMeterAccessory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { API } from 'homebridge';
2
+ declare const _default: (api: API) => void;
3
+ export = _default;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;yBAIvB,KAAK,GAAG,KAAG,IAAI;AAAzB,kBAEE"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ const settings_1 = require("./settings");
3
+ const platform_1 = require("./platform");
4
+ module.exports = (api) => {
5
+ api.registerPlatform(settings_1.PLATFORM_NAME, platform_1.EAGLEPlatform);
6
+ };
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,yCAA2C;AAC3C,yCAA2C;AAE3C,iBAAS,CAAC,GAAQ,EAAQ,EAAE;IAC1B,GAAG,CAAC,gBAAgB,CAAC,wBAAa,EAAE,wBAAa,CAAC,CAAC;AACrD,CAAC,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { API, Characteristic, DynamicPlatformPlugin, Logger, PlatformAccessory, PlatformConfig, Service } from 'homebridge';
2
+ import { EveChars } from './eveCharacteristics';
3
+ export declare class EAGLEPlatform implements DynamicPlatformPlugin {
4
+ readonly log: Logger;
5
+ readonly api: API;
6
+ readonly Service: typeof Service;
7
+ readonly Characteristic: typeof Characteristic;
8
+ readonly accessories: PlatformAccessory[];
9
+ readonly eveChars: EveChars;
10
+ readonly meterName: string;
11
+ readonly showExportMeter: boolean;
12
+ readonly exportMeterName: string;
13
+ private readonly client;
14
+ private readonly pollIntervalMs;
15
+ private gridMeterAccessory?;
16
+ private exportMeterAccessory?;
17
+ private pollTimer?;
18
+ private pollInFlight;
19
+ private backedOff;
20
+ constructor(log: Logger, config: PlatformConfig, api: API);
21
+ configureAccessory(accessory: PlatformAccessory): void;
22
+ private discoverDevices;
23
+ private registerOrRestoreAccessory;
24
+ private startPolling;
25
+ private enterBackoff;
26
+ }
27
+ //# sourceMappingURL=platform.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,GAAG,EACH,cAAc,EACd,qBAAqB,EACrB,MAAM,EACN,iBAAiB,EACjB,cAAc,EACd,OAAO,EACR,MAAM,YAAY,CAAC;AAMpB,OAAO,EAA4B,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAO1E,qBAAa,aAAc,YAAW,qBAAqB;aAoBvC,GAAG,EAAE,MAAM;aAEX,GAAG,EAAE,GAAG;IArB1B,SAAgB,OAAO,EAAE,OAAO,OAAO,CAAC;IACxC,SAAgB,cAAc,EAAE,OAAO,cAAc,CAAC;IAEtD,SAAgB,WAAW,EAAE,iBAAiB,EAAE,CAAM;IACtD,SAAgB,QAAQ,EAAE,QAAQ,CAAC;IACnC,SAAgB,SAAS,EAAE,MAAM,CAAC;IAClC,SAAgB,eAAe,EAAE,OAAO,CAAC;IACzC,SAAgB,eAAe,EAAE,MAAM,CAAC;IAExC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IAExC,OAAO,CAAC,kBAAkB,CAAC,CAAqB;IAChD,OAAO,CAAC,oBAAoB,CAAC,CAAuB;IACpD,OAAO,CAAC,SAAS,CAAC,CAAiC;IACnD,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,SAAS,CAAS;gBAGR,GAAG,EAAE,MAAM,EAC3B,MAAM,EAAE,cAAc,EACN,GAAG,EAAE,GAAG;IAyD1B,kBAAkB,CAAC,SAAS,EAAE,iBAAiB,GAAG,IAAI;IAKtD,OAAO,CAAC,eAAe;IAgBvB,OAAO,CAAC,0BAA0B;IAqDlC,OAAO,CAAC,YAAY;IA6CpB,OAAO,CAAC,YAAY;CAOrB"}
@@ -0,0 +1,176 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EAGLEPlatform = void 0;
4
+ const settings_1 = require("./settings");
5
+ const eagleClient_1 = require("./eagleClient");
6
+ const gridMeterAccessory_1 = require("./gridMeterAccessory");
7
+ const exportMeterAccessory_1 = require("./exportMeterAccessory");
8
+ const eveCharacteristics_1 = require("./eveCharacteristics");
9
+ const MIN_POLL_INTERVAL = 5;
10
+ const DISCOVER_RETRY_MS = 30000;
11
+ const NO_METER_RETRY_MS = 60000;
12
+ const AUTH_BACKOFF_MS = 60000;
13
+ class EAGLEPlatform {
14
+ constructor(log, config, api) {
15
+ this.log = log;
16
+ this.api = api;
17
+ this.accessories = [];
18
+ this.pollInFlight = false;
19
+ this.backedOff = false;
20
+ this.Service = api.hap.Service;
21
+ this.Characteristic = api.hap.Characteristic;
22
+ this.eveChars = (0, eveCharacteristics_1.createEveCharacteristics)(api);
23
+ const eagleConfig = config;
24
+ if (!eagleConfig.cloudId || !eagleConfig.installCode) {
25
+ this.log.error('Missing required config: cloudId and installCode are required.');
26
+ // Platform will do nothing; Homebridge still loads cleanly.
27
+ this.client = new eagleClient_1.EagleClient('', '', '', log);
28
+ this.pollIntervalMs = MIN_POLL_INTERVAL * 1000;
29
+ this.showExportMeter = false;
30
+ this.meterName = 'Grid Meter';
31
+ this.exportMeterName = 'Grid Meter - Export';
32
+ return;
33
+ }
34
+ const host = eagleConfig.host || `eagle-${eagleConfig.cloudId}.local`;
35
+ if (!eagleConfig.host) {
36
+ this.log.info(`No host configured — using mDNS default: ${host}`);
37
+ }
38
+ let pollInterval = eagleConfig.pollInterval ?? 15;
39
+ if (pollInterval < MIN_POLL_INTERVAL) {
40
+ this.log.warn(`pollInterval ${pollInterval}s is below minimum; clamping to ${MIN_POLL_INTERVAL}s`);
41
+ pollInterval = MIN_POLL_INTERVAL;
42
+ }
43
+ this.pollIntervalMs = pollInterval * 1000;
44
+ this.showExportMeter = eagleConfig.showExportMeter ?? false;
45
+ this.exportMeterName = eagleConfig.exportMeterName ?? 'Grid Meter - Export';
46
+ this.meterName = eagleConfig.meterName ?? (this.showExportMeter ? 'Grid Meter - Import' : 'Grid Meter');
47
+ this.client = new eagleClient_1.EagleClient(host, eagleConfig.cloudId, eagleConfig.installCode, log);
48
+ this.log.info('Finished initializing platform:', config.name ?? settings_1.PLATFORM_NAME);
49
+ this.api.on('didFinishLaunching', () => {
50
+ this.log.debug('didFinishLaunching — starting device discovery');
51
+ this.discoverDevices();
52
+ });
53
+ this.api.on('shutdown', () => {
54
+ if (this.pollTimer) {
55
+ clearInterval(this.pollTimer);
56
+ }
57
+ });
58
+ }
59
+ configureAccessory(accessory) {
60
+ this.log.info('Loading accessory from cache:', accessory.displayName);
61
+ this.accessories.push(accessory);
62
+ }
63
+ discoverDevices() {
64
+ this.client
65
+ .discoverMeter()
66
+ .then((address) => {
67
+ this.log.info(`Meter discovered at hardware address: ${address}`);
68
+ this.registerOrRestoreAccessory(address);
69
+ this.startPolling(address);
70
+ })
71
+ .catch((err) => {
72
+ const isNoMeter = err.message.includes('No electric_meter');
73
+ const retryMs = isNoMeter ? NO_METER_RETRY_MS : DISCOVER_RETRY_MS;
74
+ this.log.warn(`Device discovery failed: ${err.message}. Retrying in ${retryMs / 1000}s`);
75
+ setTimeout(() => this.discoverDevices(), retryMs);
76
+ });
77
+ }
78
+ registerOrRestoreAccessory(meterAddress) {
79
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
80
+ const FakeGatoHistoryService = require('fakegato-history')(this.api);
81
+ // --- Import meter ---
82
+ const importUuid = this.api.hap.uuid.generate(meterAddress);
83
+ const existingImport = this.accessories.find((a) => a.UUID === importUuid);
84
+ if (existingImport) {
85
+ this.log.info('Restoring import meter accessory from cache:', existingImport.displayName);
86
+ existingImport.displayName = this.meterName;
87
+ this.api.updatePlatformAccessories([existingImport]);
88
+ this.gridMeterAccessory = new gridMeterAccessory_1.GridMeterAccessory(this, existingImport, FakeGatoHistoryService, meterAddress);
89
+ }
90
+ else {
91
+ this.log.info('Registering new import meter accessory:', this.meterName);
92
+ const accessory = new this.api.platformAccessory(this.meterName, importUuid);
93
+ this.gridMeterAccessory = new gridMeterAccessory_1.GridMeterAccessory(this, accessory, FakeGatoHistoryService, meterAddress);
94
+ this.api.registerPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [accessory]);
95
+ this.accessories.push(accessory);
96
+ }
97
+ // --- Export meter ---
98
+ const exportUuid = this.api.hap.uuid.generate(meterAddress + '-export');
99
+ const existingExport = this.accessories.find((a) => a.UUID === exportUuid);
100
+ if (this.showExportMeter) {
101
+ if (existingExport) {
102
+ this.log.info('Restoring export meter accessory from cache:', existingExport.displayName);
103
+ existingExport.displayName = this.exportMeterName;
104
+ this.api.updatePlatformAccessories([existingExport]);
105
+ this.exportMeterAccessory = new exportMeterAccessory_1.ExportMeterAccessory(this, existingExport, FakeGatoHistoryService, meterAddress);
106
+ }
107
+ else {
108
+ this.log.info('Registering new export meter accessory:', this.exportMeterName);
109
+ const accessory = new this.api.platformAccessory(this.exportMeterName, exportUuid);
110
+ this.exportMeterAccessory = new exportMeterAccessory_1.ExportMeterAccessory(this, accessory, FakeGatoHistoryService, meterAddress);
111
+ this.api.registerPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [accessory]);
112
+ this.accessories.push(accessory);
113
+ }
114
+ }
115
+ else if (existingExport) {
116
+ // showExportMeter was disabled — remove the stale cached accessory
117
+ this.log.info('Removing stale export meter accessory');
118
+ this.api.unregisterPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [existingExport]);
119
+ }
120
+ }
121
+ startPolling(meterAddress) {
122
+ this.pollTimer = setInterval(async () => {
123
+ if (this.pollInFlight) {
124
+ this.log.debug('Poll skipped — previous request still in flight');
125
+ return;
126
+ }
127
+ if (this.backedOff) {
128
+ this.log.debug('Poll skipped — in backoff period');
129
+ return;
130
+ }
131
+ this.pollInFlight = true;
132
+ try {
133
+ const reading = await this.client.queryMeter(meterAddress);
134
+ this.gridMeterAccessory?.updateValues(reading);
135
+ this.exportMeterAccessory?.updateValues(reading);
136
+ }
137
+ catch (err) {
138
+ if (err instanceof eagleClient_1.HttpError) {
139
+ if (err.statusCode === 401) {
140
+ this.log.error('HTTP 401 Unauthorized — check cloudId and installCode. Backing off 60s.');
141
+ this.enterBackoff(AUTH_BACKOFF_MS);
142
+ }
143
+ else if (err.statusCode >= 500) {
144
+ this.log.warn(`HTTP ${err.statusCode} from EAGLE — device overloaded. Skipping cycle.`);
145
+ }
146
+ else {
147
+ this.log.warn(`Poll HTTP error: ${err.message}`);
148
+ }
149
+ }
150
+ else if (err instanceof Error) {
151
+ if (err.message.includes("not Connected")) {
152
+ this.log.warn(`Meter not connected to ZigBee network — skipping cycle (${err.message})`);
153
+ }
154
+ else if (err.message.includes('timeout')) {
155
+ this.log.warn('Poll timed out after 10s — skipping cycle');
156
+ }
157
+ else {
158
+ this.log.warn(`Poll error: ${err.message}`);
159
+ }
160
+ }
161
+ }
162
+ finally {
163
+ this.pollInFlight = false;
164
+ }
165
+ }, this.pollIntervalMs);
166
+ }
167
+ enterBackoff(durationMs) {
168
+ this.backedOff = true;
169
+ setTimeout(() => {
170
+ this.backedOff = false;
171
+ this.log.info('Backoff period ended — resuming polls');
172
+ }, durationMs);
173
+ }
174
+ }
175
+ exports.EAGLEPlatform = EAGLEPlatform;
176
+ //# sourceMappingURL=platform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { PlatformConfig } from 'homebridge';
2
+ export declare const PLATFORM_NAME = "EAGLE";
3
+ export declare const PLUGIN_NAME = "homebridge-rainforest-eagle3";
4
+ export interface EAGLEConfig extends PlatformConfig {
5
+ host?: string;
6
+ cloudId: string;
7
+ installCode: string;
8
+ pollInterval?: number;
9
+ meterName?: string;
10
+ showExportMeter?: boolean;
11
+ exportMeterName?: string;
12
+ }
13
+ //# sourceMappingURL=settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,eAAO,MAAM,aAAa,UAAU,CAAC;AACrC,eAAO,MAAM,WAAW,iCAAiC,CAAC;AAE1D,MAAM,WAAW,WAAY,SAAQ,cAAc;IACjD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B"}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PLUGIN_NAME = exports.PLATFORM_NAME = void 0;
4
+ exports.PLATFORM_NAME = 'EAGLE';
5
+ exports.PLUGIN_NAME = 'homebridge-rainforest-eagle3';
6
+ //# sourceMappingURL=settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":";;;AAEa,QAAA,aAAa,GAAG,OAAO,CAAC;AACxB,QAAA,WAAW,GAAG,8BAA8B,CAAC"}
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "homebridge-rainforest-eagle3",
3
+ "displayName": "Eagle 3",
4
+ "version": "1.0.0",
5
+ "description": "Homebridge plugin for Rainforest EAGLE-200 smart meter — Eve Energy accessory with fakegato history.",
6
+ "author": {
7
+ "name": "David Carson",
8
+ "email": "dacarson@gmail.com",
9
+ "url": "https://github.com/dacarson"
10
+ },
11
+ "license": "Apache-2.0",
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git://github.com/dacarson/homebridge-rainforest-eagle3.git"
15
+ },
16
+ "bugs": {
17
+ "url": "https://github.com/dacarson/homebridge-rainforest-eagle3/issues"
18
+ },
19
+ "engines": {
20
+ "node": ">=18.0.0",
21
+ "homebridge": ">=1.6.0"
22
+ },
23
+ "main": "dist/index.js",
24
+ "files": [
25
+ "dist",
26
+ "config.schema.json"
27
+ ],
28
+ "scripts": {
29
+ "build": "rimraf ./dist && tsc",
30
+ "watch": "npm run build && nodemon",
31
+ "lint": "eslint src/**.ts",
32
+ "prepublishOnly": "npm run build"
33
+ },
34
+ "keywords": [
35
+ "homebridge-plugin",
36
+ "rainforest",
37
+ "eagle",
38
+ "eagle-200",
39
+ "smart-meter",
40
+ "energy"
41
+ ],
42
+ "peerDependencies": {
43
+ "homebridge": ">=1.6.0"
44
+ },
45
+ "dependencies": {
46
+ "fakegato-history": "^0.6.7",
47
+ "fast-xml-parser": "^4.4.1",
48
+ "strnum": "^1.0.5"
49
+ },
50
+ "devDependencies": {
51
+ "@types/node": "^20.0.0",
52
+ "@typescript-eslint/eslint-plugin": "^7.0.0",
53
+ "@typescript-eslint/parser": "^7.0.0",
54
+ "eslint": "^8.57.0",
55
+ "homebridge": "^1.8.0",
56
+ "nodemon": "^3.0.0",
57
+ "rimraf": "^5.0.0",
58
+ "typescript": "^5.4.0"
59
+ }
60
+ }