homebridge-rainforest-eagle3 1.1.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
@@ -116,6 +116,50 @@ With export meter enabled (for solar / net metering):
116
116
  | `showExportMeter` | boolean | no | `false` | Register a second accessory showing power exported to the grid. |
117
117
  | `exportMeterName` | string | no | `"Grid Meter - Export"` | Display name for the export meter accessory. |
118
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.
119
163
 
120
164
  ### Finding Your Credentials
121
165
 
@@ -134,7 +178,7 @@ The device is also reachable at `eagle-<cloudId>.local` via mDNS if you prefer n
134
178
 
135
179
  | Characteristic | Source | Notes |
136
180
  |---|---|---|
137
- | 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). |
138
182
  | OutletInUse | Always `true` | Required by Eve Energy |
139
183
  | Eve Watts | `max(0, demand) × 1000` | Import watts. Zero when net-exporting. |
140
184
  | Eve kWh | `CurrentSummationDelivered` | Lifetime energy imported from grid |
@@ -143,7 +187,7 @@ The device is also reachable at `eagle-<cloudId>.local` via mDNS if you prefer n
143
187
 
144
188
  | Characteristic | Source | Notes |
145
189
  |---|---|---|
146
- | 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). |
147
191
  | OutletInUse | Always `true` | Required by Eve Energy |
148
192
  | Eve Watts | `max(0, −demand) × 1000` | Export watts. Zero when not exporting. |
149
193
  | Eve kWh | `CurrentSummationReceived` | Lifetime energy exported to grid. Shows `0` if the meter does not report this variable. |
@@ -155,6 +199,12 @@ The two accessories are mutually exclusive — at any given moment only one show
155
199
  ---
156
200
 
157
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>
158
208
 
159
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.
160
210
 
@@ -164,6 +214,8 @@ Power is sent in milliwatts, energy in milliwatt-hours, per the Matter spec. Mat
164
214
 
165
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.
166
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
+
167
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.
168
220
 
169
221
  ### Enabling Matter
@@ -212,6 +264,12 @@ npm install
212
264
  npm run build
213
265
  ```
214
266
 
267
+ To run the unit tests:
268
+
269
+ ```bash
270
+ npm test
271
+ ```
272
+
215
273
  To develop with live rebuilds:
216
274
 
217
275
  ```bash
@@ -58,6 +58,52 @@
58
58
  "type": "boolean",
59
59
  "default": false,
60
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."
61
107
  }
62
108
  },
63
109
  "required": ["cloudId", "installCode"]
@@ -76,6 +122,31 @@
76
122
  "functionBody": "return model.showExportMeter === true;"
77
123
  }
78
124
  },
79
- { "key": "matter" }
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
+ ]
150
+ }
80
151
  ]
81
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":"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"}
@@ -74,16 +74,31 @@
74
74
  * features compose once at registration, so PeriodicEnergy must already be
75
75
  * present in the *initial* cluster state passed to registerPlatformAccessories()
76
76
  * — declaring it for the first time in a later updateAccessoryState() call
77
- * would not retroactively add the feature. buildClusters() therefore seeds a
78
- * zero-energy periodic fragment (no timestamps yet) on its very first call,
79
- * which is always the one register() makes, before any real reading exists
80
- * to diff against; every call after that computes a real delta against the
81
- * last *periodic* baseline (not the last poll), throttled to at most once
82
- * per MIN_PERIODIC_INTERVAL_S so a short poll interval (default 15s, minimum
83
- * 5s) doesn't turn into excessive Matter event/state churn compared to a
84
- * device that naturally reports once a minute. Imported and exported
85
- * baselines are tracked independently, since either can advance while the
86
- * other sits idle.
77
+ * would not retroactively add the feature. register() therefore seeds a
78
+ * zero-energy periodic fragment (no timestamps yet).
79
+ *
80
+ * Event rate
81
+ * ----------
82
+ * Homebridge routes every energy field passed to updateAccessoryState() through
83
+ * matter.js setMeasurement(), which records a CumulativeEnergyMeasured or
84
+ * PeriodicEnergyMeasured event for each one. Sending both on every poll
85
+ * (default 15s) produced events that almost always repeated the previous
86
+ * total or reported 0 energy, so update() includes each field only when it
87
+ * carries news:
88
+ *
89
+ * - Cumulative: when the total (in mWh) has changed since the last one sent,
90
+ * or CUMULATIVE_HEARTBEAT_S has passed, so controllers still get a periodic
91
+ * heartbeat while the meter is idle.
92
+ * - Periodic: energy is accumulated across polls (per-poll deltas, so a meter
93
+ * counter that steps backwards doesn't produce a negative period) and
94
+ * emitted once per PERIODIC_INTERVAL_S, with start/end timestamps covering
95
+ * the whole period. If the previous period was idle (zero energy) and energy
96
+ * starts flowing, the period is emitted immediately and a new one starts, so
97
+ * a new session starts reporting promptly instead of up to 15 minutes later.
98
+ *
99
+ * The periodic baseline is taken from the first real poll, not from the
100
+ * placeholder readings register() is called with. The first update() after
101
+ * registration always sends both fields, as before.
87
102
  *
88
103
  * Requirements
89
104
  * ------------
@@ -109,29 +124,39 @@ export interface EnergyReadings {
109
124
  export declare class MatterEnergyBridge {
110
125
  private readonly log;
111
126
  private readonly direction;
112
- private static readonly MIN_PERIODIC_INTERVAL_S;
127
+ private readonly nowMs;
128
+ /** Re-send an unchanged cumulative total at least this often. */
129
+ static readonly CUMULATIVE_HEARTBEAT_S: number;
130
+ /** Length of one PeriodicEnergyMeasured period. */
131
+ static readonly PERIODIC_INTERVAL_S: number;
113
132
  private readonly api;
133
+ private readonly kinds;
114
134
  private uuid;
115
135
  private registered;
116
136
  private warnedUpdate;
117
- private periodicState;
118
- constructor(api: API, log: Logger, direction: EnergyDirection);
137
+ private sentFirstUpdate;
138
+ private lastCumulative;
139
+ private lastReadingKWh;
140
+ private periodStartS;
141
+ private periodKWh;
142
+ private lastPeriodic;
143
+ private idle;
144
+ constructor(api: API, log: Logger, direction: EnergyDirection, nowMs?: () => number);
119
145
  /**
120
146
  * Whether this Homebridge build exposes everything needed to publish this
121
147
  * meter. Logs at debug level so unsupported builds stay quiet.
122
148
  */
123
149
  isSupported(): boolean;
124
- private buildClusters;
150
+ private nowS;
151
+ private static readingsByKind;
152
+ /** Initial cluster state for register(): every energy field, periodic seeded at zero. */
153
+ private buildInitialClusters;
154
+ private energyFields;
125
155
  /**
126
- * Compute (or, between periodic reports, just return the last computed)
127
- * periodic-energy fragment for one energy kind. The very first call —
128
- * always from register(), before any real reading exists — seeds a
129
- * zero-energy fragment with no timestamps, purely so the PeriodicEnergy
130
- * feature composes at registration. Every call after that reports a real
131
- * delta against the last periodic baseline once MIN_PERIODIC_INTERVAL_S
132
- * has elapsed.
156
+ * Decide which energy fields this poll should send, updating the cumulative
157
+ * and periodic bookkeeping. Returns an empty object when nothing is due.
133
158
  */
134
- private computePeriodic;
159
+ private buildEnergyUpdate;
135
160
  /**
136
161
  * Register this meter as a Matter electrical sensor.
137
162
  *
@@ -1 +1 @@
1
- {"version":3,"file":"matterEnergy.d.ts","sourceRoot":"","sources":["../src/matterEnergy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiGG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAkB9C,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,UAAU,GAAG,eAAe,CAAC;AAExE,MAAM,WAAW,cAAc;IAC7B,uFAAuF;IACvF,MAAM,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,gEAAgE;IAChE,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAmDD,qBAAa,kBAAkB;IAmB3B,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAnB5B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,uBAAuB,CAAM;IAErD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAgB;IACpC,OAAO,CAAC,IAAI,CAAuB;IACnC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,YAAY,CAAS;IAM7B,OAAO,CAAC,aAAa,CAGnB;gBAGA,GAAG,EAAE,GAAG,EACS,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,eAAe;IAK7C;;;OAGG;IACH,WAAW,IAAI,OAAO;IAiBtB,OAAO,CAAC,aAAa;IAkBrB;;;;;;;;OAQG;IACH,OAAO,CAAC,eAAe;IAwBvB;;;;;;;;OAQG;IACG,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC;IA2BtH;;;OAGG;IACG,MAAM,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;CAwBtD"}
1
+ {"version":3,"file":"matterEnergy.d.ts","sourceRoot":"","sources":["../src/matterEnergy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgHG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAkB9C,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,UAAU,GAAG,eAAe,CAAC;AAExE,MAAM,WAAW,cAAc;IAC7B,uFAAuF;IACvF,MAAM,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,gEAAgE;IAChE,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAyDD,qBAAa,kBAAkB;IA6B3B,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,KAAK;IA9BxB,iEAAiE;IACjE,MAAM,CAAC,QAAQ,CAAC,sBAAsB,SAAW;IACjD,mDAAmD;IACnD,MAAM,CAAC,QAAQ,CAAC,mBAAmB,SAAW;IAE9C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAgB;IACpC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;IACrC,OAAO,CAAC,IAAI,CAAuB;IACnC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,eAAe,CAAS;IAGhC,OAAO,CAAC,cAAc,CAAmE;IAGzF,OAAO,CAAC,cAAc,CAA2C;IACjE,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,SAAS,CAA4D;IAC7E,OAAO,CAAC,YAAY,CAGlB;IAEF,OAAO,CAAC,IAAI,CAAQ;gBAGlB,GAAG,EAAE,GAAG,EACS,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,eAAe,EAC1B,KAAK,GAAE,MAAM,MAAiB;IAMjD;;;OAGG;IACH,WAAW,IAAI,OAAO;IAiBtB,OAAO,CAAC,IAAI;IAIZ,OAAO,CAAC,MAAM,CAAC,cAAc;IAI7B,yFAAyF;IACzF,OAAO,CAAC,oBAAoB;IAU5B,OAAO,CAAC,YAAY;IAiBpB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAgDzB;;;;;;;;OAQG;IACG,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC;IA2BtH;;;OAGG;IACG,MAAM,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;CA+BtD"}