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 +60 -2
- package/config.schema.json +72 -1
- package/dist/eveCharacteristics.d.ts +7 -0
- package/dist/eveCharacteristics.d.ts.map +1 -1
- package/dist/eveCharacteristics.js +12 -0
- package/dist/eveCharacteristics.js.map +1 -1
- package/dist/exportMeterAccessory.d.ts +2 -0
- package/dist/exportMeterAccessory.d.ts.map +1 -1
- package/dist/exportMeterAccessory.js +13 -6
- package/dist/exportMeterAccessory.js.map +1 -1
- package/dist/gridMeterAccessory.d.ts +2 -0
- package/dist/gridMeterAccessory.d.ts.map +1 -1
- package/dist/gridMeterAccessory.js +13 -6
- package/dist/gridMeterAccessory.js.map +1 -1
- package/dist/matterEnergy.d.ts +47 -22
- package/dist/matterEnergy.d.ts.map +1 -1
- package/dist/matterEnergy.js +130 -60
- package/dist/matterEnergy.js.map +1 -1
- package/dist/platform.d.ts +11 -0
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +38 -2
- package/dist/platform.js.map +1 -1
- package/dist/powerSwitch.d.ts +24 -0
- package/dist/powerSwitch.d.ts.map +1 -0
- package/dist/powerSwitch.js +70 -0
- package/dist/powerSwitch.js.map +1 -0
- package/dist/settings.d.ts +6 -0
- package/dist/settings.d.ts.map +1 -1
- package/dist/updatePolicy.d.ts +43 -0
- package/dist/updatePolicy.d.ts.map +1 -0
- package/dist/updatePolicy.js +115 -0
- package/dist/updatePolicy.js.map +1 -0
- package/package.json +3 -2
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
|
|
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 |
|
|
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
|
package/config.schema.json
CHANGED
|
@@ -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;
|
|
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;
|
|
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
|
|
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.
|
|
33
|
+
.onGet(() => this.powerSwitch.state)
|
|
32
34
|
.onSet(async () => {
|
|
33
|
-
this.eveEnergyService.updateCharacteristic(Characteristic.On, this.
|
|
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.
|
|
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.
|
|
56
|
-
this.
|
|
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":";;;AAGA,
|
|
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;
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
64
|
-
this.
|
|
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":";;;AAGA,
|
|
1
|
+
{"version":3,"file":"gridMeterAccessory.js","sourceRoot":"","sources":["../src/gridMeterAccessory.ts"],"names":[],"mappings":"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"}
|
package/dist/matterEnergy.d.ts
CHANGED
|
@@ -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.
|
|
78
|
-
* zero-energy periodic fragment (no timestamps yet)
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
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
|
|
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
|
|
118
|
-
|
|
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
|
|
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
|
-
*
|
|
127
|
-
* periodic
|
|
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
|
|
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
|
|
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"}
|