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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"updatePolicy.d.ts","sourceRoot":"","sources":["../src/updatePolicy.ts"],"names":[],"mappings":"AAiBA,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG,UAAU,GAAG,MAAM,CAAC;AAChE,eAAO,MAAM,sBAAsB,EAAE,SAAS,eAAe,EAAsC,CAAC;AAEpG,MAAM,MAAM,OAAO,GAAG,GAAG,GAAG,KAAK,CAAC;AAElC,MAAM,WAAW,mBAAmB;IAClC,eAAe,EAAE,eAAe,CAAC;IACjC,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,eAAO,MAAM,qBAAqB,EAAE,mBAOnC,CAAC;AAEF,mGAAmG;AACnG,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,mBAAmB,CAexF;AAED,2DAA2D;AAC3D,qBAAa,WAAW;IACtB,IAAI,SAAK;IACT,UAAU,SAAK;IAEf,kEAAkE;IAClE,IAAI,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE;CAM7C;AAOD,iFAAiF;AACjF,qBAAa,iBAAiB;IAI1B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,QAAQ,CAAC,KAAK,EAAE,WAAW;IAC3B,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,GAAG;IANtB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA+B;gBAGrC,OAAO,EAAE,mBAAmB,EACpC,KAAK,GAAE,WAA+B,EAC9B,KAAK,GAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAe,EAC3C,GAAG,GAAE,MAAM,MAAiB;IAG/C,oFAAoF;IACpF,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED;;;;OAIG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO;IAuB9D,OAAO,CAAC,aAAa;CAkBtB"}
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ // Controls how much HomeKit event traffic the plugin generates.
3
+ //
4
+ // The EAGLE is polled every ~15 s and its readings differ slightly on nearly
5
+ // every poll. Pushing every value produces a steady stream of HomeKit events,
6
+ // so the Eve custom power/energy characteristics are pushed according to the
7
+ // `evePowerUpdates` mode:
8
+ //
9
+ // throttled (default) — push when the value changes by at least the
10
+ // configured threshold, or maxIntervalSeconds after
11
+ // the last push
12
+ // pollOnly — never push; NOTIFY is removed, values are served
13
+ // from onGet only
14
+ // live — push every poll (behavior before 1.2.0)
15
+ //
16
+ // Standard HomeKit characteristics are always evented; the power-derived On
17
+ // switches are handled separately by PowerSwitch (see powerSwitch.ts).
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.EveUpdateThrottle = exports.UpdateStats = exports.DEFAULT_UPDATE_POLICY = exports.EVE_POWER_UPDATE_MODES = void 0;
20
+ exports.resolveUpdatePolicy = resolveUpdatePolicy;
21
+ exports.EVE_POWER_UPDATE_MODES = ['throttled', 'pollOnly', 'live'];
22
+ exports.DEFAULT_UPDATE_POLICY = {
23
+ evePowerUpdates: 'throttled',
24
+ minChangeWatts: 25,
25
+ minChangePercent: 2,
26
+ minChangeKwh: 0.1,
27
+ maxIntervalSeconds: 300,
28
+ switchHoldSeconds: 60,
29
+ };
30
+ /** Builds options from raw config values, falling back to defaults for missing/invalid entries. */
31
+ function resolveUpdatePolicy(config) {
32
+ const d = exports.DEFAULT_UPDATE_POLICY;
33
+ const num = (v, fallback) => typeof v === 'number' && Number.isFinite(v) && v >= 0 ? v : fallback;
34
+ const mode = config.evePowerUpdates;
35
+ return {
36
+ evePowerUpdates: exports.EVE_POWER_UPDATE_MODES.includes(mode)
37
+ ? mode
38
+ : d.evePowerUpdates,
39
+ minChangeWatts: num(config.minChangeWatts, d.minChangeWatts),
40
+ minChangePercent: num(config.minChangePercent, d.minChangePercent),
41
+ minChangeKwh: num(config.minChangeKwh, d.minChangeKwh),
42
+ maxIntervalSeconds: num(config.maxIntervalSeconds, d.maxIntervalSeconds),
43
+ switchHoldSeconds: num(config.switchHoldSeconds, d.switchHoldSeconds),
44
+ };
45
+ }
46
+ /** Sent/suppressed counters for the hourly summary log. */
47
+ class UpdateStats {
48
+ constructor() {
49
+ this.sent = 0;
50
+ this.suppressed = 0;
51
+ }
52
+ /** Returns the counts since the previous call and resets them. */
53
+ take() {
54
+ const stats = { sent: this.sent, suppressed: this.suppressed };
55
+ this.sent = 0;
56
+ this.suppressed = 0;
57
+ return stats;
58
+ }
59
+ }
60
+ exports.UpdateStats = UpdateStats;
61
+ /** Decides, per accessory+characteristic key, whether an Eve value is pushed. */
62
+ class EveUpdateThrottle {
63
+ constructor(options, stats = new UpdateStats(), debug = () => { }, now = Date.now) {
64
+ this.options = options;
65
+ this.stats = stats;
66
+ this.debug = debug;
67
+ this.now = now;
68
+ this.lastSent = new Map();
69
+ }
70
+ /** Whether Eve characteristics should advertise NOTIFY (false in pollOnly mode). */
71
+ get notify() {
72
+ return this.options.evePowerUpdates !== 'pollOnly';
73
+ }
74
+ /**
75
+ * Returns true if `value` should be pushed for `key`. The first value for a
76
+ * key is always pushed in throttled mode, so HomeKit gets the correct value
77
+ * immediately on startup.
78
+ */
79
+ shouldSend(key, value, unit) {
80
+ switch (this.options.evePowerUpdates) {
81
+ case 'live':
82
+ this.stats.sent++;
83
+ return true;
84
+ case 'pollOnly':
85
+ this.stats.suppressed++;
86
+ return false;
87
+ }
88
+ const now = this.now();
89
+ const last = this.lastSent.get(key);
90
+ if (last === undefined || this.isSignificant(last, value, unit, now)) {
91
+ this.lastSent.set(key, { value, time: now });
92
+ this.stats.sent++;
93
+ return true;
94
+ }
95
+ this.stats.suppressed++;
96
+ this.debug(`Suppressed ${key} update ${value} ${unit} (last sent ${last.value} ${unit})`);
97
+ return false;
98
+ }
99
+ isSignificant(last, value, unit, now) {
100
+ const { minChangeWatts, minChangePercent, minChangeKwh, maxIntervalSeconds } = this.options;
101
+ // Sign change, including crossing to/from 0 (import vs export).
102
+ if (Math.sign(value) !== Math.sign(last.value)) {
103
+ return true;
104
+ }
105
+ const threshold = unit === 'W'
106
+ ? Math.max(minChangeWatts, (minChangePercent / 100) * Math.abs(last.value))
107
+ : minChangeKwh;
108
+ if (Math.abs(value - last.value) >= threshold) {
109
+ return true;
110
+ }
111
+ return now - last.time >= maxIntervalSeconds * 1000;
112
+ }
113
+ }
114
+ exports.EveUpdateThrottle = EveUpdateThrottle;
115
+ //# sourceMappingURL=updatePolicy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"updatePolicy.js","sourceRoot":"","sources":["../src/updatePolicy.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "homebridge-rainforest-eagle3",
3
3
  "displayName": "Eagle 3",
4
- "version": "1.1.0",
4
+ "version": "1.2.0",
5
5
  "description": "Homebridge plugin for Rainforest EAGLE-3 smart meter — Eve Energy accessory with fakegato history.",
6
6
  "author": {
7
7
  "name": "David Carson",
@@ -29,7 +29,8 @@
29
29
  "build": "rimraf ./dist && tsc",
30
30
  "watch": "npm run build && nodemon",
31
31
  "lint": "eslint src/**.ts",
32
- "prepublishOnly": "npm run build"
32
+ "prepublishOnly": "npm run build",
33
+ "test": "rimraf ./build-test && tsc -p tsconfig.test.json && node --test build-test/*.spec.js"
33
34
  },
34
35
  "keywords": [
35
36
  "homebridge-plugin",