homebridge-rainforest-eagle3 1.0.0 → 1.2.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/README.md CHANGED
@@ -1,6 +1,12 @@
1
1
  # homebridge-rainforest-eagle3
2
+ [![License: MIT](https://img.shields.io/github/license/dacarson/homebridge-rainforest-eagle3)](LICENSE)
3
+ [![Version](https://img.shields.io/github/v/release/dacarson/homebridge-rainforest-eagle3)](https://github.com/dacarson/homebridge-rainforest-eagle3/releases)
4
+ [![npm downloads](https://img.shields.io/npm/dt/homebridge-rainforest-eagle3)](https://www.npmjs.com/package/homebridge-rainforest-eagle3)
2
5
 
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.
6
+ A [Homebridge](https://homebridge.io) plugin for the [Rainforest Automation EAGLE-3](https://www.rainforestautomation.com) 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.
7
+
8
+ <img width="300" alt="Grid Meter - Export" src="https://github.com/user-attachments/assets/9f2bfed2-6ab8-45e0-ab5b-d5ac91f5a38a" />
9
+ <img width="300" alt="Grid Meter - Import" src="https://github.com/user-attachments/assets/3c0cba11-386a-4185-bd54-f1c0861454dc" />
4
10
 
5
11
  ---
6
12
 
@@ -9,10 +15,10 @@ A [Homebridge](https://homebridge.io) plugin for the [Rainforest Automation EAGL
9
15
  - Real-time grid demand in Watts (visible in the Eve app and HomeKit detail view)
10
16
  - Cumulative energy imported (kWh) as a lifetime total
11
17
  - Optional **export meter** accessory for homes with solar net metering — shows real-time export watts and lifetime energy exported to the grid
18
+ - Optional: live watts and energy in the Apple Home **Energy** view via Matter (see [Apple Home Energy & Matter](#apple-home-energy--matter))
12
19
  - 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
20
+ - Polls the EAGLE-3 **local** HTTP API — no cloud account or internet required at runtime
14
21
  - 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
22
 
17
23
  ---
18
24
 
@@ -20,15 +26,17 @@ A [Homebridge](https://homebridge.io) plugin for the [Rainforest Automation EAGL
20
26
 
21
27
  | Device | Status |
22
28
  |---|---|
23
- | Rainforest EAGLE-200 (RFA-Z114) | Supported |
24
- | Rainforest EAGLE-3 | Expected compatible (uses same local API; unverified) |
29
+ | Rainforest EAGLE-3 | Tested |
30
+ | Rainforest EAGLE-200 (RFA-Z114) | Expected compatible — uses the same local API; unverified |
25
31
  | Original EAGLE (Z109) | Not supported — uses a different relay-server API |
26
32
 
27
33
  ---
28
34
 
29
35
  ## How It Works
30
36
 
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.
37
+ The EAGLE-3 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.
38
+
39
+ The EAGLE-3's embedded HTTP server requires HTTP/1.0. Standard HTTP libraries (axios, fetch) negotiate HTTP/1.1 and are incompatible, so the plugin uses raw TCP sockets to communicate with the device.
32
40
 
33
41
  The accessory renders as a **smart plug** in Apple Home:
34
42
 
@@ -40,10 +48,10 @@ The accessory renders as a **smart plug** in Apple Home:
40
48
 
41
49
  ## Requirements
42
50
 
43
- - [Homebridge](https://homebridge.io) v1.6 or later
51
+ - [Homebridge](https://homebridge.io) v2.0 or later (v2.4.0+ and iOS 27+ if you want the optional Apple Home Energy view via Matter)
44
52
  - 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)
53
+ - Rainforest EAGLE-3 on the same local network as your Homebridge host
54
+ - The EAGLE-3's **Cloud ID** and **Install Code** (printed on the label on the underside of the device)
47
55
 
48
56
  ---
49
57
 
@@ -100,17 +108,62 @@ With export meter enabled (for solar / net metering):
100
108
  | Field | Type | Required | Default | Description |
101
109
  |---|---|---|---|---|
102
110
  | `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. |
111
+ | `host` | string | no | `eagle-<cloudId>.local` | IP address or mDNS hostname of the EAGLE-3. Omit to use mDNS auto-discovery. |
104
112
  | `cloudId` | string | yes | — | Cloud ID from the device label (6 hex characters, upper-left of label) |
105
113
  | `installCode` | string | yes | — | Install Code from the device label (16 hex characters) |
106
114
  | `pollInterval` | integer | no | `15` | Seconds between polls. Minimum enforced: `5` |
107
115
  | `meterName` | string | no | `"Grid Meter"` | Display name for the import meter accessory. Defaults to `"Grid Meter - Import"` when `showExportMeter` is `true`. |
108
116
  | `showExportMeter` | boolean | no | `false` | Register a second accessory showing power exported to the grid. |
109
117
  | `exportMeterName` | string | no | `"Grid Meter - Export"` | Display name for the export meter accessory. |
118
+ | `matter` | boolean | no | `false` | Also publish the grid meter over Matter with live electrical measurements, so it shows watts on its tile in the Apple Home Energy view (see [Apple Home Energy & Matter](#apple-home-energy--matter)) |
119
+ | `evePowerUpdates` | string | no | `"throttled"` | How Eve Watts / Eve kWh are sent to HomeKit: `"throttled"`, `"pollOnly"` or `"live"` (see [HomeKit Updates](#homekit-updates)). |
120
+ | `minChangeWatts` | number | no | `25` | Throttled mode: minimum change in watts, since the last push, that pushes Eve Watts. |
121
+ | `minChangePercent` | number | no | `2` | Throttled mode: minimum change as a percentage of the last push. The larger of this and `minChangeWatts` applies. |
122
+ | `minChangeKwh` | number | no | `0.1` | Throttled mode: minimum change in kWh, since the last push, that pushes Eve kWh. |
123
+ | `maxIntervalSeconds` | number | no | `300` | Throttled mode: push anyway once this many seconds have passed since the last push. |
124
+ | `switchHoldSeconds` | number | no | `60` | How long a new On state must hold before it is reported. `0` disables the hold. |
125
+
126
+ ### HomeKit Updates
127
+
128
+ The EAGLE is polled every `pollInterval` seconds and the readings differ slightly on nearly every poll. Pushing every value sends a HomeKit event per characteristic per poll, hundreds of events an hour, that every connected Home hub and device has to process. These settings reduce that traffic without breaking automations. They appear in the Homebridge UI under **HomeKit Updates**.
129
+
130
+ On startup the plugin polls right away and reports the current values immediately, in every mode.
131
+
132
+ #### Eve power and energy (`evePowerUpdates`)
133
+
134
+ Eve Watts and Eve kWh are Eve custom characteristics. Besides the Eve app showing them, **Eve and Home+ automations can trigger on or check these values** (for example "when power rises above 3 kW"). Choose a mode with that in mind:
135
+
136
+ | Mode | Traffic | Automations on these values |
137
+ |---|---|---|
138
+ | `throttled` (default) | Low | Keep working. Values are accurate to within the configured thresholds. |
139
+ | `pollOnly` | Lowest | **Triggers on these values stop working.** Use it only if no automation uses them. |
140
+ | `live` | High | Work, with every reading (the behavior before 1.2.0). |
141
+
142
+ - **throttled** pushes a value only when one of these is true:
143
+ - Eve Watts has changed by at least `max(minChangeWatts, minChangePercent% of the last value pushed)`, or has crossed to or from 0
144
+ - Eve kWh has changed by at least `minChangeKwh`
145
+ - `maxIntervalSeconds` (default 5 minutes) have passed since the last push for that value
146
+ - **pollOnly** removes notify support from these characteristics and never pushes them. The newest reading is still returned whenever an app reads the value, so the Eve app shows current figures when opened.
147
+ - **live** pushes every reading.
148
+
149
+ In every mode, reads return the newest reading, and Eve history (fakegato) still logs every poll.
150
+
151
+ #### On switches
152
+
153
+ The On characteristic of each meter is a standard HomeKit characteristic and is always pushed, so Home app automations keep working. To keep it from flapping on small or brief changes:
154
+
155
+ - **Deadband:** it turns on when power rises above **50 W** and off when it falls below **20 W**. Readings in between keep the current state.
156
+ - **Hold:** a new state must hold for `switchHoldSeconds` (default 60) before it is reported. A spike shorter than that never flips the switch. Set it to `0` to report changes on the next poll.
157
+
158
+ **Automations triggered by these switches can fire up to `switchHoldSeconds` (plus one poll interval) later than the underlying change.**
159
+
160
+ #### Logging
161
+
162
+ Suppressed Eve updates and held switch changes are logged at debug level. Unless `evePowerUpdates` is `live` and `switchHoldSeconds` is `0`, a one-line summary of sent vs. suppressed updates is logged every hour.
110
163
 
111
164
  ### Finding Your Credentials
112
165
 
113
- Flip the EAGLE-200 over and look at the label. You need:
166
+ Flip the EAGLE-3 over and look at the label. You need:
114
167
 
115
168
  - **Cloud ID** — 6-character hex string in the upper-left (e.g. `004792`)
116
169
  - **Install Code** — 16-character hex string below the Cloud ID (e.g. `bfb0fc05f51a3932`)
@@ -125,7 +178,7 @@ The device is also reachable at `eagle-<cloudId>.local` via mDNS if you prefer n
125
178
 
126
179
  | Characteristic | Source | Notes |
127
180
  |---|---|---|
128
- | On | `demand > 0` | True when consuming grid power |
181
+ | On | `demand` above 50 W / below 20 W | True when importing from the grid. Changes are held for `switchHoldSeconds`; see [On switches](#on-switches). |
129
182
  | OutletInUse | Always `true` | Required by Eve Energy |
130
183
  | Eve Watts | `max(0, demand) × 1000` | Import watts. Zero when net-exporting. |
131
184
  | Eve kWh | `CurrentSummationDelivered` | Lifetime energy imported from grid |
@@ -134,7 +187,7 @@ The device is also reachable at `eagle-<cloudId>.local` via mDNS if you prefer n
134
187
 
135
188
  | Characteristic | Source | Notes |
136
189
  |---|---|---|
137
- | On | `demand < 0` | True when exporting to the grid |
190
+ | On | export above 50 W / below 20 W | True when exporting to the grid. Changes are held for `switchHoldSeconds`; see [On switches](#on-switches). |
138
191
  | OutletInUse | Always `true` | Required by Eve Energy |
139
192
  | Eve Watts | `max(0, −demand) × 1000` | Export watts. Zero when not exporting. |
140
193
  | Eve kWh | `CurrentSummationReceived` | Lifetime energy exported to grid. Shows `0` if the meter does not report this variable. |
@@ -145,12 +198,57 @@ The two accessories are mutually exclusive — at any given moment only one show
145
198
 
146
199
  ---
147
200
 
201
+ ## Apple Home Energy & Matter
202
+ <table>
203
+ <td>
204
+ <img width="600" alt="MatterEnergy" src="https://github.com/user-attachments/assets/fcff5f12-54cb-4431-a944-8ac04c6e044f" />
205
+ <br><sub>Apple Energy view with other Energy accessories</sub>
206
+ </td>
207
+ </table>
208
+
209
+ Apple Home's native **Energy** view is driven by **Matter** electrical-measurement clusters, **not** by classic HomeKit/HAP characteristics. HAP has no power or energy characteristic at all, so the Eve characteristics above (which only Eve-class apps read) can never populate it — no matter how the HomeKit accessory is shaped.
210
+
211
+ With `"matter": true`, this plugin publishes a single **`ElectricalSensor`** Matter accessory named **"Grid"**, carrying live power and cumulative/periodic energy — no on/off, no controllable state, purely metering.
212
+
213
+ Power is sent in milliwatts, energy in milliwatt-hours, per the Matter spec. Matter's `activePower` sign convention is positive = the accessory is *drawing* power, negative = it's *supplying* power, which lines up directly with `InstantaneousDemand` — no sign flip needed.
214
+
215
+ **The grid meter is a single, bidirectional accessory on the Matter side**, even when `showExportMeter` splits Import and Export into two separate accessories in Eve/HomeKit — that split exists only because Eve's custom Energy characteristic can't represent a negative wattage. Matter's `activePower` attribute *is* signed, so power flips sign as the meter crosses between importing and exporting. Matter's cumulative/periodic *energy* attributes have no equivalent signed "net" value — Imported and Exported are always separate running totals per the Matter spec — so the Grid accessory reports both simultaneously.
216
+
217
+ Live power is updated on every poll. Energy is reported only when there is something new: the cumulative totals when they change (or every 15 minutes as a heartbeat), and periodic energy once per 15-minute period. When energy starts flowing again after an idle period, the periodic total is reported right away.
218
+
219
+ **Why a pure sensor and not an outlet:** this device type has no on/off cluster, so its tile in the Home app shows "Not Supported" as its headline status — Home's tile face wants a primary characteristic (on/off, a reading, etc.) to display, and a pure measurement cluster doesn't provide one. That tradeoff is accepted here: a fake on/off state isn't worth carrying for a tile headline, as long as the wattage still rolls into the Home aggregate and — via periodic energy — into the accessory's own Energy-view attribution, which it does either way.
220
+
221
+ ### Enabling Matter
222
+
223
+ - **Homebridge 2.4.0+**
224
+ - **Matter enabled on this plugin's child bridge** — in the Homebridge UI: plugin settings → **Bridge Settings** → enable Matter, then pair the Matter bridge in the Home app
225
+ - **iOS/iPadOS 27+** on the device you use to view the Apple Home **Energy** view — earlier versions don't show it
226
+
227
+ ```json
228
+ {
229
+ "platforms": [
230
+ {
231
+ "platform": "EAGLE",
232
+ "name": "EAGLE",
233
+ "cloudId": "004792",
234
+ "installCode": "bfb0fc05f51a3932",
235
+ "matter": true
236
+ }
237
+ ]
238
+ }
239
+ ```
240
+
241
+ If the Matter API isn't available (older Homebridge, or Matter not enabled), the plugin detects that, logs a single informational line, and continues to work exactly as before over HomeKit/Eve.
242
+
243
+ ---
244
+
148
245
  ## Error Handling
149
246
 
150
- The plugin is designed to be resilient to transient EAGLE-200 failures:
247
+ The plugin is designed to be resilient to transient EAGLE-3 failures:
151
248
 
152
249
  - 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
250
+ - If the EAGLE responds but reports no electric meter device, discovery retries every 60 seconds
251
+ - Poll cycles are skipped (not fatal) on timeout, XML parse errors, HTTP 5xx responses, or when the meter's ZigBee connection status is not "connected"
154
252
  - HTTP 401 triggers a 60-second backoff and an error log (check your credentials)
155
253
  - The EAGLE's embedded HTTP server can be overwhelmed by frequent polling; the default 15-second interval is conservative by design
156
254
  - HomeKit characteristics retain their last known-good values during outages
@@ -166,6 +264,12 @@ npm install
166
264
  npm run build
167
265
  ```
168
266
 
267
+ To run the unit tests:
268
+
269
+ ```bash
270
+ npm test
271
+ ```
272
+
169
273
  To develop with live rebuilds:
170
274
 
171
275
  ```bash
@@ -52,6 +52,58 @@
52
52
  "type": "string",
53
53
  "default": "Grid Meter - Export",
54
54
  "description": "HomeKit display name for the export meter accessory. Only used when showExportMeter is true."
55
+ },
56
+ "matter": {
57
+ "title": "Show in the Apple Home Energy view (via Matter)",
58
+ "type": "boolean",
59
+ "default": false,
60
+ "description": "Also publish the grid meter over Matter as a single bidirectional electrical sensor with live power and cumulative/periodic energy, feeding your Apple Home Energy view (requires iOS/iPadOS 27+ to view). Requires Homebridge 2.4.0+ with Matter enabled on this plugin's child bridge; skipped safely otherwise."
61
+ },
62
+ "evePowerUpdates": {
63
+ "title": "Eve Power Updates",
64
+ "type": "string",
65
+ "default": "throttled",
66
+ "oneOf": [
67
+ { "title": "Throttled — push meaningful changes (recommended)", "enum": ["throttled"] },
68
+ { "title": "Poll only — never push (breaks Eve/Home+ triggers on these values)", "enum": ["pollOnly"] },
69
+ { "title": "Live — push every poll (pre-1.2.0 behavior)", "enum": ["live"] }
70
+ ],
71
+ "description": "How the Eve Watts and Eve kWh values are sent to HomeKit. Eve and Home+ automations can trigger on or check these values: Throttled keeps them working, accurate to within the thresholds below. Poll only gives the lowest traffic but automations triggered by these values will not fire, so use it only if no automation uses them."
72
+ },
73
+ "minChangeWatts": {
74
+ "title": "Minimum Change (W)",
75
+ "type": "number",
76
+ "default": 25,
77
+ "minimum": 0,
78
+ "description": "Throttled mode: push Eve Watts when power has changed by at least this many watts since the last push (or Minimum Change %, whichever is larger)."
79
+ },
80
+ "minChangePercent": {
81
+ "title": "Minimum Change (%)",
82
+ "type": "number",
83
+ "default": 2,
84
+ "minimum": 0,
85
+ "description": "Throttled mode: push Eve Watts when power has changed by at least this percentage of the last value pushed (or Minimum Change W, whichever is larger)."
86
+ },
87
+ "minChangeKwh": {
88
+ "title": "Minimum Change (kWh)",
89
+ "type": "number",
90
+ "default": 0.1,
91
+ "minimum": 0,
92
+ "description": "Throttled mode: push Eve kWh when the total has changed by at least this much since the last push."
93
+ },
94
+ "maxIntervalSeconds": {
95
+ "title": "Maximum Interval (seconds)",
96
+ "type": "number",
97
+ "default": 300,
98
+ "minimum": 0,
99
+ "description": "Throttled mode: push anyway once this long has passed since the last push, even if the change is small."
100
+ },
101
+ "switchHoldSeconds": {
102
+ "title": "On Switch Hold (seconds)",
103
+ "type": "number",
104
+ "default": 60,
105
+ "minimum": 0,
106
+ "description": "The meter's On switch (importing / exporting) changes only after the new state has held this long, so brief spikes don't flip it. Automations triggered by the switch can fire up to this long after the underlying change. 0 disables the hold."
55
107
  }
56
108
  },
57
109
  "required": ["cloudId", "installCode"]
@@ -69,6 +121,32 @@
69
121
  "condition": {
70
122
  "functionBody": "return model.showExportMeter === true;"
71
123
  }
124
+ },
125
+ { "key": "matter" },
126
+ {
127
+ "type": "fieldset",
128
+ "title": "HomeKit Updates",
129
+ "expandable": true,
130
+ "items": [
131
+ { "key": "evePowerUpdates" },
132
+ {
133
+ "key": "minChangeWatts",
134
+ "condition": { "functionBody": "return !model.evePowerUpdates || model.evePowerUpdates === 'throttled';" }
135
+ },
136
+ {
137
+ "key": "minChangePercent",
138
+ "condition": { "functionBody": "return !model.evePowerUpdates || model.evePowerUpdates === 'throttled';" }
139
+ },
140
+ {
141
+ "key": "minChangeKwh",
142
+ "condition": { "functionBody": "return !model.evePowerUpdates || model.evePowerUpdates === 'throttled';" }
143
+ },
144
+ {
145
+ "key": "maxIntervalSeconds",
146
+ "condition": { "functionBody": "return !model.evePowerUpdates || model.evePowerUpdates === 'throttled';" }
147
+ },
148
+ { "key": "switchHoldSeconds" }
149
+ ]
72
150
  }
73
151
  ]
74
152
  }
@@ -11,4 +11,11 @@ export interface EveChars {
11
11
  EveKWh: EveCharClass;
12
12
  }
13
13
  export declare function createEveCharacteristics(api: API): EveChars;
14
+ /**
15
+ * Adds or removes NOTIFY on an Eve characteristic. Applied to every instance,
16
+ * including ones restored from the accessory cache (which keep their cached
17
+ * props rather than the class defaults), so switching evePowerUpdates to or
18
+ * from pollOnly takes effect on restart.
19
+ */
20
+ export declare function setEveNotify(characteristic: Characteristic, notify: boolean): void;
14
21
  //# sourceMappingURL=eveCharacteristics.d.ts.map
@@ -1 +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"}
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;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,cAAc,EAAE,cAAc,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAIlF"}
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.EVE_KWH_UUID = exports.EVE_WATT_UUID = exports.EVE_ENERGY_SERVICE_UUID = void 0;
4
4
  exports.createEveCharacteristics = createEveCharacteristics;
5
+ exports.setEveNotify = setEveNotify;
5
6
  exports.EVE_ENERGY_SERVICE_UUID = 'E863F10A-079E-48FF-8F27-9C2605A29F52';
6
7
  exports.EVE_WATT_UUID = 'E863F10D-079E-48FF-8F27-9C2605A29F52';
7
8
  exports.EVE_KWH_UUID = 'E863F10C-079E-48FF-8F27-9C2605A29F52';
@@ -40,4 +41,15 @@ function createEveCharacteristics(api) {
40
41
  EveKWh: EveKWh,
41
42
  };
42
43
  }
44
+ /**
45
+ * Adds or removes NOTIFY on an Eve characteristic. Applied to every instance,
46
+ * including ones restored from the accessory cache (which keep their cached
47
+ * props rather than the class defaults), so switching evePowerUpdates to or
48
+ * from pollOnly takes effect on restart.
49
+ */
50
+ function setEveNotify(characteristic, notify) {
51
+ characteristic.setProps({
52
+ perms: notify ? ["pr" /* Perms.PAIRED_READ */, "ev" /* Perms.NOTIFY */] : ["pr" /* Perms.PAIRED_READ */],
53
+ });
54
+ }
43
55
  //# sourceMappingURL=eveCharacteristics.js.map
@@ -1 +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"}
1
+ {"version":3,"file":"eveCharacteristics.js","sourceRoot":"","sources":["../src/eveCharacteristics.ts"],"names":[],"mappings":";;;AAcA,4DAuCC;AAQD,oCAIC;AA/DY,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;AAED;;;;;GAKG;AACH,SAAgB,YAAY,CAAC,cAA8B,EAAE,MAAe;IAC1E,cAAc,CAAC,QAAQ,CAAC;QACtB,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,uDAAiC,CAAC,CAAC,CAAC,8BAAmB;KACxE,CAAC,CAAC;AACL,CAAC"}
@@ -7,6 +7,8 @@ export declare class ExportMeterAccessory {
7
7
  private readonly historyService;
8
8
  private lastExportW;
9
9
  private lastReceivedKwh;
10
+ private readonly key;
11
+ private readonly powerSwitch;
10
12
  constructor(platform: EAGLEPlatform, accessory: PlatformAccessory, FakeGatoHistoryService: any, meterAddress: string);
11
13
  updateValues(reading: MeterReading): void;
12
14
  }
@@ -1 +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"}
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;AAI7C,qBAAa,oBAAoB;IAW7B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAV3B,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAU;IAE3C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAM;IAErC,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;gBAGvB,QAAQ,EAAE,aAAa,EACxC,SAAS,EAAE,iBAAiB,EAE5B,sBAAsB,EAAE,GAAG,EAC3B,YAAY,EAAE,MAAM;IAsDtB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;CAoB1C"}
@@ -11,6 +11,8 @@ class ExportMeterAccessory {
11
11
  this.lastReceivedKwh = 0;
12
12
  const { Characteristic, api } = platform;
13
13
  const { EveWatts, EveKWh } = platform.eveChars;
14
+ this.key = `export:${accessory.displayName}`;
15
+ this.powerSwitch = platform.createPowerSwitch(this.key);
14
16
  const infoService = accessory.getService(platform.Service.AccessoryInformation) ??
15
17
  accessory.addService(platform.Service.AccessoryInformation);
16
18
  infoService
@@ -25,12 +27,12 @@ class ExportMeterAccessory {
25
27
  this.eveEnergyService = accessory.addService(new api.hap.Service(platform.exportMeterName, eveCharacteristics_1.EVE_ENERGY_SERVICE_UUID));
26
28
  }
27
29
  this.eveEnergyService.setCharacteristic(Characteristic.Name, platform.exportMeterName);
28
- // On — true when the home is actively exporting to the grid
30
+ // On — true when exporting to the grid (deadband + hold, see powerSwitch.ts)
29
31
  this.eveEnergyService
30
32
  .getCharacteristic(Characteristic.On)
31
- .onGet(() => this.lastExportW > 0)
33
+ .onGet(() => this.powerSwitch.state)
32
34
  .onSet(async () => {
33
- this.eveEnergyService.updateCharacteristic(Characteristic.On, this.lastExportW > 0);
35
+ this.eveEnergyService.updateCharacteristic(Characteristic.On, this.powerSwitch.state);
34
36
  });
35
37
  this.eveEnergyService
36
38
  .getCharacteristic(Characteristic.OutletInUse)
@@ -38,9 +40,11 @@ class ExportMeterAccessory {
38
40
  this.eveEnergyService
39
41
  .getCharacteristic(EveWatts)
40
42
  .onGet(() => this.lastExportW);
43
+ (0, eveCharacteristics_1.setEveNotify)(this.eveEnergyService.getCharacteristic(EveWatts), platform.eveThrottle.notify);
41
44
  this.eveEnergyService
42
45
  .getCharacteristic(EveKWh)
43
46
  .onGet(() => this.lastReceivedKwh);
47
+ (0, eveCharacteristics_1.setEveNotify)(this.eveEnergyService.getCharacteristic(EveKWh), platform.eveThrottle.notify);
44
48
  this.historyService = new FakeGatoHistoryService('energy', accessory, {
45
49
  storage: 'fs',
46
50
  });
@@ -50,10 +54,13 @@ class ExportMeterAccessory {
50
54
  const { EveWatts, EveKWh } = this.platform.eveChars;
51
55
  this.lastExportW = Math.round(Math.max(0, -reading.demand_kw) * 1000 * 10) / 10;
52
56
  this.lastReceivedKwh = reading.summation_received_kwh ?? 0;
53
- this.eveEnergyService.updateCharacteristic(Characteristic.On, this.lastExportW > 0);
57
+ const on = this.powerSwitch.update(this.lastExportW);
58
+ if (on !== null) {
59
+ this.eveEnergyService.updateCharacteristic(Characteristic.On, on);
60
+ }
54
61
  this.eveEnergyService.updateCharacteristic(Characteristic.OutletInUse, true);
55
- this.eveEnergyService.updateCharacteristic(EveWatts, this.lastExportW);
56
- this.eveEnergyService.updateCharacteristic(EveKWh, this.lastReceivedKwh);
62
+ this.platform.updateEve(this.eveEnergyService, EveWatts, `${this.key}:EveWatts`, this.lastExportW, 'W');
63
+ this.platform.updateEve(this.eveEnergyService, EveKWh, `${this.key}:EveKWh`, this.lastReceivedKwh, 'kWh');
57
64
  this.historyService.addEntry({
58
65
  time: Math.round(Date.now() / 1000),
59
66
  power: this.lastExportW,
@@ -1 +1 @@
1
- {"version":3,"file":"exportMeterAccessory.js","sourceRoot":"","sources":["../src/exportMeterAccessory.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"exportMeterAccessory.js","sourceRoot":"","sources":["../src/exportMeterAccessory.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,8 @@ export declare class GridMeterAccessory {
7
7
  private readonly historyService;
8
8
  private lastDemandW;
9
9
  private lastDeliveredKwh;
10
+ private readonly key;
11
+ private readonly powerSwitch;
10
12
  constructor(platform: EAGLEPlatform, accessory: PlatformAccessory, FakeGatoHistoryService: any, meterAddress: string);
11
13
  updateValues(reading: MeterReading): void;
12
14
  }
@@ -1 +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"}
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;AAI7C,qBAAa,kBAAkB;IAW3B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAV3B,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAU;IAE3C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAM;IAErC,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;gBAGvB,QAAQ,EAAE,aAAa,EACxC,SAAS,EAAE,iBAAiB,EAE5B,sBAAsB,EAAE,GAAG,EAC3B,YAAY,EAAE,MAAM;IA8DtB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;CA2B1C"}
@@ -11,6 +11,8 @@ class GridMeterAccessory {
11
11
  this.lastDeliveredKwh = 0;
12
12
  const { Characteristic, api } = platform;
13
13
  const { EveWatts, EveKWh } = platform.eveChars;
14
+ this.key = `import:${accessory.displayName}`;
15
+ this.powerSwitch = platform.createPowerSwitch(this.key);
14
16
  // Accessory information service
15
17
  const infoService = accessory.getService(platform.Service.AccessoryInformation) ??
16
18
  accessory.addService(platform.Service.AccessoryInformation);
@@ -28,13 +30,13 @@ class GridMeterAccessory {
28
30
  this.eveEnergyService = accessory.addService(new api.hap.Service(platform.meterName, eveCharacteristics_1.EVE_ENERGY_SERVICE_UUID));
29
31
  }
30
32
  this.eveEnergyService.setCharacteristic(Characteristic.Name, platform.meterName);
31
- // On — true when grid is actively being consumed
33
+ // On — true when importing from the grid (deadband + hold, see powerSwitch.ts)
32
34
  this.eveEnergyService
33
35
  .getCharacteristic(Characteristic.On)
34
- .onGet(() => this.lastDemandW > 0)
36
+ .onGet(() => this.powerSwitch.state)
35
37
  .onSet(async () => {
36
38
  // Read-only: revert to polled state immediately
37
- this.eveEnergyService.updateCharacteristic(Characteristic.On, this.lastDemandW > 0);
39
+ this.eveEnergyService.updateCharacteristic(Characteristic.On, this.powerSwitch.state);
38
40
  });
39
41
  // OutletInUse — always true (required by Eve Energy)
40
42
  this.eveEnergyService
@@ -45,9 +47,11 @@ class GridMeterAccessory {
45
47
  this.eveEnergyService
46
48
  .getCharacteristic(EveWatts)
47
49
  .onGet(() => this.lastDemandW);
50
+ (0, eveCharacteristics_1.setEveNotify)(this.eveEnergyService.getCharacteristic(EveWatts), platform.eveThrottle.notify);
48
51
  this.eveEnergyService
49
52
  .getCharacteristic(EveKWh)
50
53
  .onGet(() => this.lastDeliveredKwh);
54
+ (0, eveCharacteristics_1.setEveNotify)(this.eveEnergyService.getCharacteristic(EveKWh), platform.eveThrottle.notify);
51
55
  // fakegato-history: 'energy' type logs { time, power } in Watts
52
56
  this.historyService = new FakeGatoHistoryService('energy', accessory, {
53
57
  storage: 'fs',
@@ -58,10 +62,13 @@ class GridMeterAccessory {
58
62
  const { EveWatts, EveKWh } = this.platform.eveChars;
59
63
  this.lastDemandW = Math.round(Math.max(0, reading.demand_kw) * 1000 * 10) / 10;
60
64
  this.lastDeliveredKwh = reading.summation_delivered_kwh;
61
- this.eveEnergyService.updateCharacteristic(Characteristic.On, this.lastDemandW > 0);
65
+ const on = this.powerSwitch.update(this.lastDemandW);
66
+ if (on !== null) {
67
+ this.eveEnergyService.updateCharacteristic(Characteristic.On, on);
68
+ }
62
69
  this.eveEnergyService.updateCharacteristic(Characteristic.OutletInUse, true);
63
- this.eveEnergyService.updateCharacteristic(EveWatts, this.lastDemandW);
64
- this.eveEnergyService.updateCharacteristic(EveKWh, this.lastDeliveredKwh);
70
+ this.platform.updateEve(this.eveEnergyService, EveWatts, `${this.key}:EveWatts`, this.lastDemandW, 'W');
71
+ this.platform.updateEve(this.eveEnergyService, EveKWh, `${this.key}:EveKWh`, this.lastDeliveredKwh, 'kWh');
65
72
  this.historyService.addEntry({
66
73
  time: Math.round(Date.now() / 1000),
67
74
  power: this.lastDemandW,
@@ -1 +1 @@
1
- {"version":3,"file":"gridMeterAccessory.js","sourceRoot":"","sources":["../src/gridMeterAccessory.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gridMeterAccessory.js","sourceRoot":"","sources":["../src/gridMeterAccessory.ts"],"names":[],"mappings":";;;AAGA,6DAA6E;AAG7E,MAAa,kBAAkB;IAU7B,YACmB,QAAuB,EACxC,SAA4B;IAC5B,8DAA8D;IAC9D,sBAA2B,EAC3B,YAAoB;QAJH,aAAQ,GAAR,QAAQ,CAAe;QANlC,gBAAW,GAAG,CAAC,CAAC;QAChB,qBAAgB,GAAG,CAAC,CAAC;QAW3B,MAAM,EAAE,cAAc,EAAE,GAAG,EAAE,GAAG,QAAQ,CAAC;QACzC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAC,QAAQ,CAAC;QAC/C,IAAI,CAAC,GAAG,GAAG,UAAU,SAAS,CAAC,WAAW,EAAE,CAAC;QAC7C,IAAI,CAAC,WAAW,GAAG,QAAQ,CAAC,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAExD,gCAAgC;QAChC,MAAM,WAAW,GACf,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,oBAAoB,CAAC;YAC3D,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;QAE9D,WAAW;aACR,iBAAiB,CAAC,cAAc,CAAC,YAAY,EAAE,uBAAuB,CAAC;aACvE,iBAAiB,CAAC,cAAc,CAAC,KAAK,EAAE,WAAW,CAAC;aACpD,iBAAiB,CAAC,cAAc,CAAC,YAAY,EAAE,YAAY,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;QAEpF,qFAAqF;QACrF,8DAA8D;QAC9D,MAAM,eAAe,GAAG,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,4CAAuB,CAAC,CAAC;QACzF,IAAI,eAAe,EAAE,CAAC;YACpB,IAAI,CAAC,gBAAgB,GAAG,eAAe,CAAC;QAC1C,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,gBAAgB,GAAG,SAAS,CAAC,UAAU,CAC1C,IAAI,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,EAAE,4CAAuB,CAAC,CACjE,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,cAAc,CAAC,IAAI,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;QAEjF,+EAA+E;QAC/E,IAAI,CAAC,gBAAgB;aAClB,iBAAiB,CAAC,cAAc,CAAC,EAAE,CAAC;aACpC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;aACnC,KAAK,CAAC,KAAK,IAAI,EAAE;YAChB,gDAAgD;YAChD,IAAI,CAAC,gBAAgB,CAAC,oBAAoB,CAAC,cAAc,CAAC,EAAE,EAAE,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QACxF,CAAC,CAAC,CAAC;QAEL,qDAAqD;QACrD,IAAI,CAAC,gBAAgB;aAClB,iBAAiB,CAAC,cAAc,CAAC,WAAW,CAAC;aAC7C,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAErB,+FAA+F;QAC/F,sEAAsE;QACtE,IAAI,CAAC,gBAAgB;aAClB,iBAAiB,CAAC,QAAQ,CAAC;aAC3B,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACjC,IAAA,iCAAY,EAAC,IAAI,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAE7F,IAAI,CAAC,gBAAgB;aAClB,iBAAiB,CAAC,MAAM,CAAC;aACzB,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QACtC,IAAA,iCAAY,EAAC,IAAI,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAE3F,gEAAgE;QAChE,IAAI,CAAC,cAAc,GAAG,IAAI,sBAAsB,CAAC,QAAQ,EAAE,SAAS,EAAE;YACpE,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;IACL,CAAC;IAED,YAAY,CAAC,OAAqB;QAChC,MAAM,EAAE,cAAc,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC;QACzC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAEpD,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,IAAI,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC;QAC/E,IAAI,CAAC,gBAAgB,GAAG,OAAO,CAAC,uBAAuB,CAAC;QAExD,MAAM,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACrD,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;YAChB,IAAI,CAAC,gBAAgB,CAAC,oBAAoB,CAAC,cAAc,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACpE,CAAC;QACD,IAAI,CAAC,gBAAgB,CAAC,oBAAoB,CAAC,cAAc,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;QAC7E,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,gBAAgB,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,GAAG,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;QACxG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,gBAAgB,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,SAAS,EAAE,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;QAE3G,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC;YAC3B,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;YACnC,KAAK,EAAE,IAAI,CAAC,WAAW;SACxB,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CACrB,mBAAmB,IAAI,CAAC,WAAW,gBAAgB,IAAI,CAAC,gBAAgB,KAAK;YAC3E,CAAC,OAAO,CAAC,sBAAsB,KAAK,SAAS;gBAC3C,CAAC,CAAC,cAAc,OAAO,CAAC,sBAAsB,KAAK;gBACnD,CAAC,CAAC,EAAE,CAAC,CACV,CAAC;IACJ,CAAC;CACF;AAxGD,gDAwGC"}