homebridge-viessmann-vicare 2.0.7 → 2.0.8
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 +24 -3
- package/dist/accessories/boiler-accessory.d.ts.map +1 -1
- package/dist/accessories/boiler-accessory.js +14 -3
- package/dist/accessories/dhw-accessory.d.ts.map +1 -1
- package/dist/accessories/dhw-accessory.js +42 -6
- package/dist/accessories/heating-circuit-accessory.d.ts.map +1 -1
- package/dist/accessories/heating-circuit-accessory.js +21 -3
- package/dist/auth-manager.d.ts +2 -1
- package/dist/auth-manager.d.ts.map +1 -1
- package/dist/auth-manager.js +31 -13
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +109 -98
- package/dist/settings.d.ts +1 -1
- package/dist/settings.js +1 -1
- package/dist/viessmann-api.d.ts +2 -1
- package/dist/viessmann-api.d.ts.map +1 -1
- package/dist/viessmann-api.js +5 -3
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -142,7 +142,7 @@ src/
|
|
|
142
142
|
**API Errors** → Debug `viessmann-api-endpoints.ts` parsing
|
|
143
143
|
**Network Issues** → Examine `network-utils.ts` detection
|
|
144
144
|
|
|
145
|
-
For detailed architecture documentation, see [
|
|
145
|
+
For detailed architecture documentation, see the [Plugin Architecture](#%EF%B8%8F-plugin-architecture-v20) section above.
|
|
146
146
|
|
|
147
147
|
## 🆕 What's New in v2.0
|
|
148
148
|
|
|
@@ -263,7 +263,7 @@ npm install -g homebridge-viessmann-vicare
|
|
|
263
263
|
"maxDelay": 300000,
|
|
264
264
|
"maxConsecutiveErrors": 5,
|
|
265
265
|
"deviceUpdateDelay": 1000,
|
|
266
|
-
"userAgent": "homebridge-viessmann-vicare/2.0.
|
|
266
|
+
"userAgent": "homebridge-viessmann-vicare/2.0.8"
|
|
267
267
|
},
|
|
268
268
|
"debug": false
|
|
269
269
|
}
|
|
@@ -810,7 +810,7 @@ Contributions are welcome! Please:
|
|
|
810
810
|
## 📋 Compatibility
|
|
811
811
|
|
|
812
812
|
- **Homebridge**: >= 1.8.0 or >= 2.0.0-beta.0
|
|
813
|
-
- **Node.js**: >=
|
|
813
|
+
- **Node.js**: >= 20.0.0
|
|
814
814
|
- **Viessmann API**: v1 and v2
|
|
815
815
|
- **iOS**: All HomeKit-supported devices
|
|
816
816
|
- **Languages**: All languages supported via custom names
|
|
@@ -841,6 +841,27 @@ For issues and questions:
|
|
|
841
841
|
|
|
842
842
|
## 📈 Changelog
|
|
843
843
|
|
|
844
|
+
### [2.0.8] - 2026-02-26
|
|
845
|
+
**Fixed**
|
|
846
|
+
- 🐛 Token storage now uses `api.user.storagePath()` (Homebridge storage directory) instead of `process.cwd()`, as required by Homebridge plugin verification guidelines.
|
|
847
|
+
- 🐛 Early config validation in `ViessmannPlatform` constructor: plugin exits cleanly if `clientId` or `username` are missing, instead of crashing on first API call.
|
|
848
|
+
**Changed**
|
|
849
|
+
- 🔧 `PLUGIN_VERSION` updated to `2.0.8` in `settings.ts` (User-Agent and logs now reflect the correct version).
|
|
850
|
+
- 🔧 `ViessmannAPI` constructor now accepts optional `storagePath` parameter passed from Homebridge.
|
|
851
|
+
- 🔧 `AuthManager` constructor accepts optional `storagePath` parameter (fallback to `.homebridge` in cwd for backward compatibility).
|
|
852
|
+
|
|
853
|
+
### [2.0.7] - 2025-10-07
|
|
854
|
+
**Fixed**
|
|
855
|
+
- 🐛 Minor stability improvements and internal code cleanup.
|
|
856
|
+
|
|
857
|
+
### [2.0.6] - 2025-10-07
|
|
858
|
+
**Fixed**
|
|
859
|
+
- 🐛 Improved error handling for edge cases in token refresh flow.
|
|
860
|
+
|
|
861
|
+
### [2.0.5] - 2025-10-07
|
|
862
|
+
**Fixed**
|
|
863
|
+
- 🐛 Additional resilience improvements for authentication on headless systems.
|
|
864
|
+
|
|
844
865
|
### [2.0.4] - 2025-10-06
|
|
845
866
|
**Added**
|
|
846
867
|
- ✨ `logEnvDiagnostics()` for better detection of graphical environment (X11, Wayland, systemd, headless).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"boiler-accessory.d.ts","sourceRoot":"","sources":["../../src/accessories/boiler-accessory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,eAAe,EAA2B,MAAM,aAAa,CAAC;AAEnI,qBAAa,wBAAwB;IA2CjC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IA9CzB,OAAO,CAAC,mBAAmB,CAAU;IACrC,OAAO,CAAC,kBAAkB,CAAU;IACpC,OAAO,CAAC,iBAAiB,CAAC,CAAU;IACpC,OAAO,CAAC,aAAa,CAAC,CAAU;IAGhC,OAAO,CAAC,yBAAyB,CAAC,CAAU;IAC5C,OAAO,CAAC,qBAAqB,CAAC,CAAU;IACxC,OAAO,CAAC,uBAAuB,CAAC,CAAU;IAC1C,OAAO,CAAC,uBAAuB,CAAC,CAAU;IAC1C,OAAO,CAAC,qBAAqB,CAAC,CAAU;IACxC,OAAO,CAAC,uBAAuB,CAAC,CAAU;IAC1C,OAAO,CAAC,oBAAoB,CAAC,CAAU;IAEvC,OAAO,CAAC,0BAA0B,CAAS;IAC3C,OAAO,CAAC,sBAAsB,CAAwB;IACtD,OAAO,CAAC,kBAAkB,CAAS;IACnC,OAAO,CAAC,iBAAiB,CAAK;IAE9B,OAAO,CAAC,MAAM,CAoBZ;gBAGiB,QAAQ,EAAE,iBAAiB,EAC3B,SAAS,EAAE,iBAAiB,EAC5B,YAAY,EAAE,qBAAqB,EACnC,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,eAAe;YAuB5B,sBAAsB;IAmBpC,OAAO,CAAC,mBAAmB;IA2E3B,OAAO,CAAC,oBAAoB;IAiB5B,OAAO,CAAC,yBAAyB;IAoBjC,OAAO,CAAC,wBAAwB;IAoEhC,OAAO,CAAC,kBAAkB;IAwD1B,OAAO,CAAC,sBAAsB;IAyE9B,OAAO,CAAC,uBAAuB;IAmO/B,OAAO,CAAC,gCAAgC;IAqCxC,OAAO,CAAC,2BAA2B;IAInC,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,mBAAmB;IAI3B,OAAO,CAAC,gBAAgB;IAIlB,qBAAqB,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAIrD,8BAA8B,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAI9D,8BAA8B,CAAC,KAAK,EAAE,mBAAmB;YAoCjD,YAAY;
|
|
1
|
+
{"version":3,"file":"boiler-accessory.d.ts","sourceRoot":"","sources":["../../src/accessories/boiler-accessory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,eAAe,EAA2B,MAAM,aAAa,CAAC;AAEnI,qBAAa,wBAAwB;IA2CjC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IA9CzB,OAAO,CAAC,mBAAmB,CAAU;IACrC,OAAO,CAAC,kBAAkB,CAAU;IACpC,OAAO,CAAC,iBAAiB,CAAC,CAAU;IACpC,OAAO,CAAC,aAAa,CAAC,CAAU;IAGhC,OAAO,CAAC,yBAAyB,CAAC,CAAU;IAC5C,OAAO,CAAC,qBAAqB,CAAC,CAAU;IACxC,OAAO,CAAC,uBAAuB,CAAC,CAAU;IAC1C,OAAO,CAAC,uBAAuB,CAAC,CAAU;IAC1C,OAAO,CAAC,qBAAqB,CAAC,CAAU;IACxC,OAAO,CAAC,uBAAuB,CAAC,CAAU;IAC1C,OAAO,CAAC,oBAAoB,CAAC,CAAU;IAEvC,OAAO,CAAC,0BAA0B,CAAS;IAC3C,OAAO,CAAC,sBAAsB,CAAwB;IACtD,OAAO,CAAC,kBAAkB,CAAS;IACnC,OAAO,CAAC,iBAAiB,CAAK;IAE9B,OAAO,CAAC,MAAM,CAoBZ;gBAGiB,QAAQ,EAAE,iBAAiB,EAC3B,SAAS,EAAE,iBAAiB,EAC5B,YAAY,EAAE,qBAAqB,EACnC,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,eAAe;YAuB5B,sBAAsB;IAmBpC,OAAO,CAAC,mBAAmB;IA2E3B,OAAO,CAAC,oBAAoB;IAiB5B,OAAO,CAAC,yBAAyB;IAoBjC,OAAO,CAAC,wBAAwB;IAoEhC,OAAO,CAAC,kBAAkB;IAwD1B,OAAO,CAAC,sBAAsB;IAyE9B,OAAO,CAAC,uBAAuB;IAmO/B,OAAO,CAAC,gCAAgC;IAqCxC,OAAO,CAAC,2BAA2B;IAInC,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,mBAAmB;IAI3B,OAAO,CAAC,gBAAgB;IAIlB,qBAAqB,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAIrD,8BAA8B,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAI9D,8BAA8B,CAAC,KAAK,EAAE,mBAAmB;YAoCjD,YAAY;YAYZ,kBAAkB;IAoTzB,oBAAoB,IAAI;QAC7B,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,EAAE,MAAM,CAAC;QACtB,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;QACxC,mBAAmB,EAAE,MAAM,CAAC;QAC5B,sBAAsB,EAAE,MAAM,CAAC;QAC/B,qBAAqB,EAAE,MAAM,CAAC;QAC9B,wBAAwB,EAAE,MAAM,CAAC;QACjC,kBAAkB,EAAE,MAAM,CAAC;QAC3B,aAAa,EAAE,MAAM,CAAC;QACtB,YAAY,EAAE,MAAM,CAAC;KACtB;CAsBF"}
|
|
@@ -562,11 +562,15 @@ class ViessmannBoilerAccessory {
|
|
|
562
562
|
}
|
|
563
563
|
}
|
|
564
564
|
async handleUpdate(features) {
|
|
565
|
+
const t0 = Date.now();
|
|
565
566
|
try {
|
|
566
567
|
await this.updateFromFeatures(features);
|
|
568
|
+
this.platform.log.debug(`🔥 Caldaia handleUpdate OK in ${Date.now() - t0}ms`);
|
|
567
569
|
}
|
|
568
570
|
catch (error) {
|
|
569
|
-
|
|
571
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
572
|
+
this.platform.log.error(`❌ Caldaia handleUpdate failed after ${Date.now() - t0}ms: ${msg}`);
|
|
573
|
+
this.platform.log.error(` State at failure: burner=${this.states.BurnerActive}, temp=${this.states.CurrentTemperature}°C, mod=${this.states.Modulation}%`);
|
|
570
574
|
}
|
|
571
575
|
}
|
|
572
576
|
async updateFromFeatures(features) {
|
|
@@ -798,8 +802,15 @@ class ViessmannBoilerAccessory {
|
|
|
798
802
|
const efficiency = parseFloat(startsPerHour) < 2 ? 'Good' : 'Poor';
|
|
799
803
|
diagnosticInfo.push(`Efficiency: ${startsPerHour}starts/h(${efficiency})`);
|
|
800
804
|
}
|
|
801
|
-
const diagnosticStr = diagnosticInfo.length > 0 ?
|
|
802
|
-
|
|
805
|
+
const diagnosticStr = diagnosticInfo.length > 0 ? ` | ${diagnosticInfo.join(' | ')}` : '';
|
|
806
|
+
// Log sempre a debug; se il bruciatore è attivo logga anche a info per visibilità
|
|
807
|
+
const statusLine = `🔥 Caldaia — burner=${this.states.BurnerActive ? 'ON 🔥' : 'OFF'} | mod=${this.states.Modulation}% | temp=${this.states.CurrentTemperature}°C→${this.states.HeatingThresholdTemperature}°C${diagnosticStr}`;
|
|
808
|
+
if (this.states.BurnerActive) {
|
|
809
|
+
this.platform.log.info(statusLine);
|
|
810
|
+
}
|
|
811
|
+
else {
|
|
812
|
+
this.platform.log.debug(statusLine);
|
|
813
|
+
}
|
|
803
814
|
}
|
|
804
815
|
// 🆕 NEW: Public method to get diagnostic summary for platform health reports
|
|
805
816
|
getDiagnosticSummary() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dhw-accessory.d.ts","sourceRoot":"","sources":["../../src/accessories/dhw-accessory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,eAAe,EAA2B,MAAM,aAAa,CAAC;AAGnI,qBAAa,qBAAqB;IAsB9B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAzBzB,OAAO,CAAC,mBAAmB,CAAU;IACrC,OAAO,CAAC,kBAAkB,CAAU;IACpC,OAAO,CAAC,cAAc,CAAC,CAAU;IACjC,OAAO,CAAC,UAAU,CAAC,CAAU;IAC7B,OAAO,CAAC,UAAU,CAAC,CAAU;IAE7B,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,0BAA0B,CAAS;IAC3C,OAAO,CAAC,sBAAsB,CAAwB;IACtD,OAAO,CAAC,WAAW,CAAS;IAE5B,OAAO,CAAC,MAAM,CAOZ;gBAGiB,QAAQ,EAAE,iBAAiB,EAC3B,SAAS,EAAE,iBAAiB,EAC5B,YAAY,EAAE,qBAAqB,EACnC,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,eAAe;YAuB5B,sBAAsB;IAmBpC,OAAO,CAAC,mBAAmB;IAmE7B,OAAO,CAAC,oBAAoB;IAW1B,OAAO,CAAC,yBAAyB;IAqBjC,OAAO,CAAC,wBAAwB;IAsFhC,OAAO,CAAC,iBAAiB;IAgGzB,OAAO,CAAC,qBAAqB;IAqBzB,SAAS,CAAC,KAAK,EAAE,mBAAmB;IAoBlC,cAAc,CAAC,KAAK,EAAE,mBAAmB;IAsBzC,UAAU,CAAC,KAAK,EAAE,mBAAmB;IAsBrC,UAAU,CAAC,KAAK,EAAE,mBAAmB;YAsB7B,OAAO;IA0CrB,OAAO,CAAC,wBAAwB;YA8BlB,iBAAiB;IAqBzB,qBAAqB,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAIrD,8BAA8B,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAK9D,8BAA8B,CAAC,KAAK,EAAE,mBAAmB;YA8CjD,YAAY;
|
|
1
|
+
{"version":3,"file":"dhw-accessory.d.ts","sourceRoot":"","sources":["../../src/accessories/dhw-accessory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,eAAe,EAA2B,MAAM,aAAa,CAAC;AAGnI,qBAAa,qBAAqB;IAsB9B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAzBzB,OAAO,CAAC,mBAAmB,CAAU;IACrC,OAAO,CAAC,kBAAkB,CAAU;IACpC,OAAO,CAAC,cAAc,CAAC,CAAU;IACjC,OAAO,CAAC,UAAU,CAAC,CAAU;IAC7B,OAAO,CAAC,UAAU,CAAC,CAAU;IAE7B,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,0BAA0B,CAAS;IAC3C,OAAO,CAAC,sBAAsB,CAAwB;IACtD,OAAO,CAAC,WAAW,CAAS;IAE5B,OAAO,CAAC,MAAM,CAOZ;gBAGiB,QAAQ,EAAE,iBAAiB,EAC3B,SAAS,EAAE,iBAAiB,EAC5B,YAAY,EAAE,qBAAqB,EACnC,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,eAAe;YAuB5B,sBAAsB;IAmBpC,OAAO,CAAC,mBAAmB;IAmE7B,OAAO,CAAC,oBAAoB;IAW1B,OAAO,CAAC,yBAAyB;IAqBjC,OAAO,CAAC,wBAAwB;IAsFhC,OAAO,CAAC,iBAAiB;IAgGzB,OAAO,CAAC,qBAAqB;IAqBzB,SAAS,CAAC,KAAK,EAAE,mBAAmB;IAoBlC,cAAc,CAAC,KAAK,EAAE,mBAAmB;IAsBzC,UAAU,CAAC,KAAK,EAAE,mBAAmB;IAsBrC,UAAU,CAAC,KAAK,EAAE,mBAAmB;YAsB7B,OAAO;IA0CrB,OAAO,CAAC,wBAAwB;YA8BlB,iBAAiB;IAqBzB,qBAAqB,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAIrD,8BAA8B,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAK9D,8BAA8B,CAAC,KAAK,EAAE,mBAAmB;YA8CjD,YAAY;YAcZ,kBAAkB;IA+DzB,2BAA2B,CAAC,YAAY,EAAE,GAAG,GAAG,IAAI;IA2DpD,kBAAkB,IAAI;QAC3B,cAAc,EAAE,MAAM,EAAE,CAAC;QACzB,0BAA0B,EAAE,OAAO,CAAC;QACpC,gBAAgB,EAAE;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,GAAG,EAAE,MAAM,CAAA;SAAE,CAAC;QAC/C,WAAW,EAAE,MAAM,CAAC;QACpB,cAAc,EAAE,OAAO,CAAC;QACxB,UAAU,EAAE,OAAO,CAAC;QACpB,UAAU,EAAE,OAAO,CAAC;KACrB;IAaM,YAAY,IAAI;QACrB,QAAQ,EAAE,OAAO,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;QACpB,kBAAkB,EAAE,MAAM,CAAC;QAC3B,iBAAiB,EAAE,MAAM,CAAC;QAC1B,kBAAkB,EAAE,OAAO,CAAC;QAC5B,cAAc,EAAE,MAAM,CAAC;QACvB,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB;IAgBY,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC;IA+B9C,OAAO,CAAC,8BAA8B;IAwBzB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;IA4BxC,OAAO,IAAI,IAAI;CASvB"}
|
|
@@ -495,42 +495,78 @@ class ViessmannDHWAccessory {
|
|
|
495
495
|
}
|
|
496
496
|
}
|
|
497
497
|
async handleUpdate(features) {
|
|
498
|
+
// FIX#6: log entry/exit with timing so stale states are immediately visible in logs
|
|
499
|
+
const t0 = Date.now();
|
|
498
500
|
try {
|
|
499
501
|
await this.updateFromFeatures(features);
|
|
502
|
+
this.platform.log.debug(`🚿 ACS handleUpdate OK in ${Date.now() - t0}ms`);
|
|
500
503
|
}
|
|
501
504
|
catch (error) {
|
|
502
|
-
|
|
505
|
+
// FIX#6: was silently swallowing errors — now logs full context so stale state is diagnosable
|
|
506
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
507
|
+
this.platform.log.error(`❌ ACS handleUpdate failed after ${Date.now() - t0}ms: ${msg}`);
|
|
508
|
+
this.platform.log.error(` State at failure: mode=${this.currentMode}, temp=${this.states.CurrentTemperature}°C, target=${this.states.HeatingThresholdTemperature}°C`);
|
|
503
509
|
}
|
|
504
510
|
}
|
|
505
511
|
async updateFromFeatures(features) {
|
|
512
|
+
let changed = false;
|
|
506
513
|
// Update DHW current temperature
|
|
507
514
|
const dhwTempFeature = features.find(f => f.feature === 'heating.dhw.sensors.temperature.dhwCylinder' ||
|
|
508
515
|
f.feature === 'heating.dhw.sensors.temperature.hotWaterStorage' ||
|
|
509
516
|
f.feature === 'heating.dhw.sensors.temperature.outlet');
|
|
510
517
|
if (dhwTempFeature?.properties?.value?.value !== undefined) {
|
|
511
|
-
|
|
518
|
+
const newTemp = dhwTempFeature.properties.value.value;
|
|
519
|
+
if (newTemp !== this.states.CurrentTemperature) {
|
|
520
|
+
this.platform.log.debug(`🌡️ ACS current temp: ${this.states.CurrentTemperature}°C → ${newTemp}°C`);
|
|
521
|
+
this.states.CurrentTemperature = newTemp;
|
|
522
|
+
changed = true;
|
|
523
|
+
}
|
|
512
524
|
this.heaterCoolerService.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, this.states.CurrentTemperature);
|
|
513
525
|
}
|
|
526
|
+
else {
|
|
527
|
+
this.platform.log.debug(`🌡️ ACS current temp: no sensor feature found (checked dhwCylinder/hotWaterStorage/outlet)`);
|
|
528
|
+
}
|
|
514
529
|
// Update DHW target temperature
|
|
515
530
|
const dhwTargetTempFeature = features.find(f => f.feature === 'heating.dhw.temperature.main');
|
|
516
531
|
if (dhwTargetTempFeature?.properties?.value?.value !== undefined && this.supportsTemperatureControl) {
|
|
517
532
|
const targetTemp = dhwTargetTempFeature.properties.value.value;
|
|
518
533
|
if (targetTemp >= this.temperatureConstraints.min && targetTemp <= this.temperatureConstraints.max) {
|
|
519
|
-
this.states.HeatingThresholdTemperature
|
|
534
|
+
if (targetTemp !== this.states.HeatingThresholdTemperature) {
|
|
535
|
+
this.platform.log.debug(`🎯 ACS target temp: ${this.states.HeatingThresholdTemperature}°C → ${targetTemp}°C`);
|
|
536
|
+
this.states.HeatingThresholdTemperature = targetTemp;
|
|
537
|
+
changed = true;
|
|
538
|
+
}
|
|
520
539
|
this.heaterCoolerService.updateCharacteristic(this.platform.Characteristic.HeatingThresholdTemperature, targetTemp);
|
|
521
540
|
}
|
|
541
|
+
else {
|
|
542
|
+
this.platform.log.warn(`🎯 ACS target temp ${targetTemp}°C out of range ${this.temperatureConstraints.min}-${this.temperatureConstraints.max}°C — ignored`);
|
|
543
|
+
}
|
|
522
544
|
}
|
|
523
|
-
// Update DHW operating mode
|
|
545
|
+
// Update DHW operating mode — THE MOST CRITICAL UPDATE
|
|
524
546
|
const dhwOperatingModeFeature = features.find(f => f.feature === 'heating.dhw.operating.modes.active');
|
|
525
547
|
if (dhwOperatingModeFeature?.properties?.value?.value !== undefined) {
|
|
526
548
|
const newMode = dhwOperatingModeFeature.properties.value.value;
|
|
527
549
|
if (newMode !== this.currentMode) {
|
|
528
|
-
this.platform.log.
|
|
550
|
+
this.platform.log.info(`🚿 ACS mode changed: ${this.currentMode.toUpperCase()} → ${newMode.toUpperCase()}`);
|
|
529
551
|
this.currentMode = newMode;
|
|
530
552
|
this.updateAllCharacteristics();
|
|
553
|
+
changed = true;
|
|
531
554
|
}
|
|
555
|
+
else {
|
|
556
|
+
this.platform.log.debug(`🚿 ACS mode unchanged: ${this.currentMode.toUpperCase()}`);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
else {
|
|
560
|
+
this.platform.log.warn(`🚿 ACS mode: feature 'heating.dhw.operating.modes.active' not found in ${features.length} features — state NOT updated`);
|
|
561
|
+
}
|
|
562
|
+
// Summary log — always visible at debug, visible at info only when something changed
|
|
563
|
+
const summary = `mode=${this.currentMode.toUpperCase()} | temp=${this.states.CurrentTemperature}°C | target=${this.states.HeatingThresholdTemperature}°C`;
|
|
564
|
+
if (changed) {
|
|
565
|
+
this.platform.log.info(`🚿 ACS state updated: ${summary}`);
|
|
566
|
+
}
|
|
567
|
+
else {
|
|
568
|
+
this.platform.log.debug(`🚿 ACS state unchanged: ${summary}`);
|
|
532
569
|
}
|
|
533
|
-
this.platform.log.debug(`DHW Status - Mode: ${this.currentMode.toUpperCase()}, Temp: ${this.states.CurrentTemperature}°C → ${this.states.HeatingThresholdTemperature}°C`);
|
|
534
570
|
}
|
|
535
571
|
// 🆕 NEW: Handle immediate burner status updates from platform
|
|
536
572
|
handleImmediateBurnerUpdate(burnerStatus) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"heating-circuit-accessory.d.ts","sourceRoot":"","sources":["../../src/accessories/heating-circuit-accessory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,eAAe,EAA2B,MAAM,aAAa,CAAC;AAInI,qBAAa,gCAAgC;IA8CzC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,aAAa;IAlDhC,OAAO,CAAC,mBAAmB,CAAU;IACrC,OAAO,CAAC,kBAAkB,CAAU;IAGpC,OAAO,CAAC,cAAc,CAAC,CAAU;IACjC,OAAO,CAAC,oBAAoB,CAAC,CAAU;IACvC,OAAO,CAAC,sBAAsB,CAAC,CAAU;IAGzC,OAAO,CAAC,cAAc,CAAC,CAAU;IACjC,OAAO,CAAC,cAAc,CAAC,CAAU;IACjC,OAAO,CAAC,cAAc,CAAC,CAAU;IAEjC,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,iBAAiB,CAAgB;IACzC,OAAO,CAAC,wBAAwB,CAAgB;IAChD,OAAO,CAAC,0BAA0B,CAAS;IAC3C,OAAO,CAAC,sBAAsB,CAAuB;IACrD,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,cAAc,CAAY;IAElC,OAAO,CAAC,MAAM,CAaZ;IAGF,OAAO,CAAC,mBAAmB,CAIzB;gBAGiB,QAAQ,EAAE,iBAAiB,EAC3B,SAAS,EAAE,iBAAiB,EAC5B,YAAY,EAAE,qBAAqB,EACnC,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,eAAe,EACvB,aAAa,EAAE,MAAM;YAuB1B,sBAAsB;IAyBpC,OAAO,CAAC,mBAAmB;IAuJ3B,OAAO,CAAC,oBAAoB;IAoB5B,OAAO,CAAC,yBAAyB;IAqBjC,OAAO,CAAC,wBAAwB;IA4DlC,OAAO,CAAC,+BAA+B;IA8FrC,OAAO,CAAC,2BAA2B;IAqFnC,OAAO,CAAC,mCAAmC;IA0B3C,OAAO,CAAC,+BAA+B;YA2BzB,iBAAiB;YAejB,gBAAgB;YAehB,iBAAiB;YAejB,wBAAwB;IA2CtC,OAAO,CAAC,gCAAgC;IAqBlC,SAAS,CAAC,KAAK,EAAE,mBAAmB;IAgBpC,0BAA0B,CAAC,KAAK,EAAE,mBAAmB;YAa7C,cAAc;YA+Dd,oBAAoB;YA4DpB,sBAAsB;YAqGtB,6BAA6B;YAsH7B,qBAAqB;IAsBnC,OAAO,CAAC,4BAA4B;IAyCpC,OAAO,CAAC,2BAA2B;IAMnC;;OAEG;YACW,oCAAoC;IAiDlD;;OAEG;YACW,6BAA6B;IAyB3C;;OAEG;YACW,+BAA+B;IAsB7C;;OAEG;IACH,OAAO,CAAC,+BAA+B;YAyBzB,OAAO;IAqCrB,OAAO,CAAC,wBAAwB;IAa1B,qBAAqB,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAIrD,8BAA8B,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAI9D,8BAA8B,CAAC,KAAK,EAAE,mBAAmB;IAgD/D,OAAO,CAAC,kBAAkB;IA4BpB,0BAA0B,IAAI,OAAO,CAAC,mBAAmB,CAAC;YAIlD,YAAY;
|
|
1
|
+
{"version":3,"file":"heating-circuit-accessory.d.ts","sourceRoot":"","sources":["../../src/accessories/heating-circuit-accessory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,eAAe,EAA2B,MAAM,aAAa,CAAC;AAInI,qBAAa,gCAAgC;IA8CzC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,aAAa;IAlDhC,OAAO,CAAC,mBAAmB,CAAU;IACrC,OAAO,CAAC,kBAAkB,CAAU;IAGpC,OAAO,CAAC,cAAc,CAAC,CAAU;IACjC,OAAO,CAAC,oBAAoB,CAAC,CAAU;IACvC,OAAO,CAAC,sBAAsB,CAAC,CAAU;IAGzC,OAAO,CAAC,cAAc,CAAC,CAAU;IACjC,OAAO,CAAC,cAAc,CAAC,CAAU;IACjC,OAAO,CAAC,cAAc,CAAC,CAAU;IAEjC,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,iBAAiB,CAAgB;IACzC,OAAO,CAAC,wBAAwB,CAAgB;IAChD,OAAO,CAAC,0BAA0B,CAAS;IAC3C,OAAO,CAAC,sBAAsB,CAAuB;IACrD,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,cAAc,CAAY;IAElC,OAAO,CAAC,MAAM,CAaZ;IAGF,OAAO,CAAC,mBAAmB,CAIzB;gBAGiB,QAAQ,EAAE,iBAAiB,EAC3B,SAAS,EAAE,iBAAiB,EAC5B,YAAY,EAAE,qBAAqB,EACnC,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,eAAe,EACvB,aAAa,EAAE,MAAM;YAuB1B,sBAAsB;IAyBpC,OAAO,CAAC,mBAAmB;IAuJ3B,OAAO,CAAC,oBAAoB;IAoB5B,OAAO,CAAC,yBAAyB;IAqBjC,OAAO,CAAC,wBAAwB;IA4DlC,OAAO,CAAC,+BAA+B;IA8FrC,OAAO,CAAC,2BAA2B;IAqFnC,OAAO,CAAC,mCAAmC;IA0B3C,OAAO,CAAC,+BAA+B;YA2BzB,iBAAiB;YAejB,gBAAgB;YAehB,iBAAiB;YAejB,wBAAwB;IA2CtC,OAAO,CAAC,gCAAgC;IAqBlC,SAAS,CAAC,KAAK,EAAE,mBAAmB;IAgBpC,0BAA0B,CAAC,KAAK,EAAE,mBAAmB;YAa7C,cAAc;YA+Dd,oBAAoB;YA4DpB,sBAAsB;YAqGtB,6BAA6B;YAsH7B,qBAAqB;IAsBnC,OAAO,CAAC,4BAA4B;IAyCpC,OAAO,CAAC,2BAA2B;IAMnC;;OAEG;YACW,oCAAoC;IAiDlD;;OAEG;YACW,6BAA6B;IAyB3C;;OAEG;YACW,+BAA+B;IAsB7C;;OAEG;IACH,OAAO,CAAC,+BAA+B;YAyBzB,OAAO;IAqCrB,OAAO,CAAC,wBAAwB;IAa1B,qBAAqB,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAIrD,8BAA8B,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAI9D,8BAA8B,CAAC,KAAK,EAAE,mBAAmB;IAgD/D,OAAO,CAAC,kBAAkB;IA4BpB,0BAA0B,IAAI,OAAO,CAAC,mBAAmB,CAAC;YAIlD,YAAY;YAYZ,kBAAkB;CAwJjC"}
|
|
@@ -1072,11 +1072,15 @@ class ViessmannHeatingCircuitAccessory {
|
|
|
1072
1072
|
return this.states.CurrentRelativeHumidity;
|
|
1073
1073
|
}
|
|
1074
1074
|
async handleUpdate(features) {
|
|
1075
|
+
const t0 = Date.now();
|
|
1075
1076
|
try {
|
|
1076
1077
|
await this.updateFromFeatures(features);
|
|
1078
|
+
this.platform.log.debug(`🌡️ Riscaldamento ${this.circuitNumber} handleUpdate OK in ${Date.now() - t0}ms`);
|
|
1077
1079
|
}
|
|
1078
1080
|
catch (error) {
|
|
1079
|
-
|
|
1081
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
1082
|
+
this.platform.log.error(`❌ Riscaldamento ${this.circuitNumber} handleUpdate failed after ${Date.now() - t0}ms: ${msg}`);
|
|
1083
|
+
this.platform.log.error(` State at failure: mode=${this.currentMode}, program=${this.currentProgram}, temp=${this.states.CurrentTemperature}°C`);
|
|
1080
1084
|
}
|
|
1081
1085
|
}
|
|
1082
1086
|
async updateFromFeatures(features) {
|
|
@@ -1190,17 +1194,31 @@ class ViessmannHeatingCircuitAccessory {
|
|
|
1190
1194
|
if (operatingModeFeature?.properties?.value?.value !== undefined) {
|
|
1191
1195
|
const newMode = operatingModeFeature.properties.value.value;
|
|
1192
1196
|
if (newMode !== this.currentMode) {
|
|
1193
|
-
this.platform.log.
|
|
1197
|
+
this.platform.log.info(`🌡️ Riscaldamento ${this.circuitNumber} mode changed: ${this.currentMode.toUpperCase()} → ${newMode.toUpperCase()}`);
|
|
1194
1198
|
this.currentMode = newMode;
|
|
1195
1199
|
this.updateAllCharacteristics();
|
|
1200
|
+
anyProgramStateChanged = true;
|
|
1201
|
+
}
|
|
1202
|
+
else {
|
|
1203
|
+
this.platform.log.debug(`🌡️ Riscaldamento ${this.circuitNumber} mode unchanged: ${this.currentMode.toUpperCase()}`);
|
|
1196
1204
|
}
|
|
1197
1205
|
}
|
|
1206
|
+
else {
|
|
1207
|
+
this.platform.log.warn(`🌡️ Riscaldamento ${this.circuitNumber}: feature '${circuitPrefix}.operating.modes.active' not found — mode NOT updated`);
|
|
1208
|
+
}
|
|
1198
1209
|
// Update humidity if available
|
|
1199
1210
|
const humidityFeature = features.find(f => f.feature.includes('sensors.humidity'));
|
|
1200
1211
|
if (humidityFeature?.properties?.value?.value !== undefined) {
|
|
1201
1212
|
this.states.CurrentRelativeHumidity = humidityFeature.properties.value.value;
|
|
1202
1213
|
}
|
|
1203
|
-
|
|
1214
|
+
// Summary: log at info when mode or program changed, debug otherwise
|
|
1215
|
+
const summaryLine = `🌡️ Riscaldamento ${this.circuitNumber} — mode=${this.currentMode.toUpperCase()} | prog=${this.currentProgram.toUpperCase()} | room=${this.states.CurrentTemperature}°C | target=${this.states.HeatingThresholdTemperature}°C`;
|
|
1216
|
+
if (anyProgramStateChanged || anyTemperatureChanged) {
|
|
1217
|
+
this.platform.log.info(summaryLine);
|
|
1218
|
+
}
|
|
1219
|
+
else {
|
|
1220
|
+
this.platform.log.debug(summaryLine);
|
|
1221
|
+
}
|
|
1204
1222
|
}
|
|
1205
1223
|
}
|
|
1206
1224
|
exports.ViessmannHeatingCircuitAccessory = ViessmannHeatingCircuitAccessory;
|
package/dist/auth-manager.d.ts
CHANGED
|
@@ -36,7 +36,8 @@ export declare class AuthManager {
|
|
|
36
36
|
private authServer?;
|
|
37
37
|
private authTimeout?;
|
|
38
38
|
private tokenRefreshTimer?;
|
|
39
|
-
|
|
39
|
+
private envDiagnosticsLogged;
|
|
40
|
+
constructor(log: Logger, config: AuthConfig, httpClient: AxiosInstance, hostIp: string, storagePath?: string);
|
|
40
41
|
private validateAuthConfiguration;
|
|
41
42
|
private generatePKCECodes;
|
|
42
43
|
private initializeTokens;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-manager.d.ts","sourceRoot":"","sources":["../src/auth-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACpC,OAAO,EAAE,aAAa,EAAiB,MAAM,OAAO,CAAC;AAOrD,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAkBD,qBAAa,WAAW;
|
|
1
|
+
{"version":3,"file":"auth-manager.d.ts","sourceRoot":"","sources":["../src/auth-manager.ts"],"names":[],"mappings":"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"}
|
package/dist/auth-manager.js
CHANGED
|
@@ -62,13 +62,14 @@ class AuthManager {
|
|
|
62
62
|
authServer;
|
|
63
63
|
authTimeout;
|
|
64
64
|
tokenRefreshTimer;
|
|
65
|
-
|
|
65
|
+
envDiagnosticsLogged = false; // FIX#4: log once at startup only
|
|
66
|
+
constructor(log, config, httpClient, hostIp, storagePath) {
|
|
66
67
|
this.log = log;
|
|
67
68
|
this.config = config;
|
|
68
69
|
this.httpClient = httpClient;
|
|
69
70
|
this.hostIp = hostIp;
|
|
70
71
|
this.redirectUri = `http://${this.hostIp}:${this.config.redirectPort || 4200}/`;
|
|
71
|
-
this.tokenStoragePath = path.join(process.cwd(), '.homebridge', 'viessmann-tokens.json');
|
|
72
|
+
this.tokenStoragePath = storagePath || path.join(process.cwd(), '.homebridge', 'viessmann-tokens.json');
|
|
72
73
|
this.log.debug(`Using redirect URI: ${this.redirectUri}`);
|
|
73
74
|
this.log.debug(`Token storage path: ${this.tokenStoragePath}`);
|
|
74
75
|
this.validateAuthConfiguration();
|
|
@@ -253,7 +254,8 @@ class AuthManager {
|
|
|
253
254
|
if (this.tokenRefreshTimer) {
|
|
254
255
|
clearTimeout(this.tokenRefreshTimer);
|
|
255
256
|
}
|
|
256
|
-
const
|
|
257
|
+
const buffer = this.config.tokenRefreshBuffer || 300000;
|
|
258
|
+
const refreshTime = this.tokenExpiresAt - buffer - Date.now();
|
|
257
259
|
if (refreshTime > 0) {
|
|
258
260
|
this.tokenRefreshTimer = setTimeout(async () => {
|
|
259
261
|
try {
|
|
@@ -266,20 +268,27 @@ class AuthManager {
|
|
|
266
268
|
// Don't clear tokens yet, let normal auth flow handle it
|
|
267
269
|
}
|
|
268
270
|
}, refreshTime);
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
+
const refreshInMin = Math.round(refreshTime / 60000);
|
|
272
|
+
const atTime = new Date(Date.now() + refreshTime).toLocaleTimeString('it-IT');
|
|
273
|
+
this.log.info(`⏰ Next token refresh scheduled in ${refreshInMin} min (at ${atTime}, buffer: ${buffer / 1000}s)`);
|
|
271
274
|
}
|
|
272
275
|
else {
|
|
273
|
-
this.log.warn(
|
|
276
|
+
this.log.warn(`⚠️ Token expires in ${Math.round((this.tokenExpiresAt - Date.now()) / 1000)}s — immediate refresh needed`);
|
|
274
277
|
}
|
|
275
278
|
}
|
|
276
279
|
async authenticate() {
|
|
277
280
|
try {
|
|
278
|
-
|
|
281
|
+
// FIX#4: log env diagnostics only once at startup, not on every authenticate() call
|
|
282
|
+
if (!this.envDiagnosticsLogged) {
|
|
283
|
+
this.logEnvDiagnostics();
|
|
284
|
+
this.envDiagnosticsLogged = true;
|
|
285
|
+
}
|
|
279
286
|
if (this.isTokenValid()) {
|
|
280
|
-
this.
|
|
287
|
+
const remaining = Math.round((this.tokenExpiresAt - Date.now()) / 1000);
|
|
288
|
+
this.log.debug(`🔑 Token valid — ${remaining}s remaining, skipping authenticate`);
|
|
281
289
|
return;
|
|
282
290
|
}
|
|
291
|
+
this.log.debug(`🔑 Token invalid or missing — attempting authentication...`);
|
|
283
292
|
if (this.refreshToken) {
|
|
284
293
|
this.log.debug('🔄 Attempting to refresh token');
|
|
285
294
|
try {
|
|
@@ -695,6 +704,10 @@ class AuthManager {
|
|
|
695
704
|
if (this.refreshTokenExpiresAt && this.refreshTokenExpiresAt < Date.now()) {
|
|
696
705
|
throw new Error('Refresh token has expired (180 days TTL exceeded)');
|
|
697
706
|
}
|
|
707
|
+
if (this.refreshTokenExpiresAt) {
|
|
708
|
+
const daysLeft = Math.round((this.refreshTokenExpiresAt - Date.now()) / (24 * 60 * 60 * 1000));
|
|
709
|
+
this.log.debug(`🔑 Using refresh token (${daysLeft} days until expiry)`);
|
|
710
|
+
}
|
|
698
711
|
const tokenData = new url_1.URLSearchParams({
|
|
699
712
|
grant_type: 'refresh_token',
|
|
700
713
|
client_id: this.config.clientId,
|
|
@@ -720,7 +733,10 @@ class AuthManager {
|
|
|
720
733
|
const tokenRefreshBuffer = this.config.tokenRefreshBuffer || 300000;
|
|
721
734
|
this.accessToken = authData.access_token;
|
|
722
735
|
this.refreshToken = authData.refresh_token || this.refreshToken;
|
|
723
|
-
|
|
736
|
+
// FIX#2: store the REAL expiry time — do NOT subtract buffer here.
|
|
737
|
+
// The buffer is applied exclusively in isTokenValid() and scheduleTokenRefresh().
|
|
738
|
+
// Previously the buffer was subtracted twice, causing refresh ~2x too early.
|
|
739
|
+
this.tokenExpiresAt = now + (authData.expires_in * 1000);
|
|
724
740
|
this.tokenIssuedAt = now;
|
|
725
741
|
this.tokenScope = 'IoT User offline_access';
|
|
726
742
|
// Set refresh token expiry if we got a new refresh token
|
|
@@ -731,9 +747,10 @@ class AuthManager {
|
|
|
731
747
|
this.saveTokens();
|
|
732
748
|
// Schedule proactive refresh
|
|
733
749
|
this.scheduleTokenRefresh();
|
|
734
|
-
const
|
|
750
|
+
const realExpiryInMin = Math.round(authData.expires_in / 60);
|
|
751
|
+
const effectiveWindowSec = Math.round((authData.expires_in * 1000 - tokenRefreshBuffer) / 1000);
|
|
735
752
|
const refreshTokenDays = this.refreshTokenExpiresAt ? Math.round((this.refreshTokenExpiresAt - now) / (24 * 60 * 60 * 1000)) : 'unknown';
|
|
736
|
-
this.log.
|
|
753
|
+
this.log.info(`🔑 Tokens acquired — real expiry: ${realExpiryInMin}min | effective window: ${effectiveWindowSec}s (buffer: ${tokenRefreshBuffer / 1000}s) | refresh token: ${refreshTokenDays} days`);
|
|
737
754
|
}
|
|
738
755
|
getAccessToken() {
|
|
739
756
|
return this.accessToken;
|
|
@@ -753,8 +770,9 @@ class AuthManager {
|
|
|
753
770
|
}
|
|
754
771
|
logEnvDiagnostics() {
|
|
755
772
|
const env = process.env;
|
|
756
|
-
|
|
757
|
-
|
|
773
|
+
// FIX#4: changed from warn to debug — called once at startup only
|
|
774
|
+
this.log.debug([
|
|
775
|
+
'🧪 ENV DIAGNOSTICS (startup)',
|
|
758
776
|
`platform=${process.platform}`,
|
|
759
777
|
`DISPLAY=${env.DISPLAY ?? '(unset)'}`,
|
|
760
778
|
`WAYLAND_DISPLAY=${env.WAYLAND_DISPLAY ?? '(unset)'}`,
|
package/dist/platform.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,GAAG,EAGH,qBAAqB,EACrB,MAAM,EACN,iBAAiB,EACjB,cAAc,EACd,OAAO,EACP,cAAc,EACf,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAExE,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACrI,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EAAgB,MAAM,2BAA2B,CAAC;AAMrI,qBAAa,iBAAkB,YAAW,qBAAqB;aA0B3C,GAAG,EAAE,MAAM;aACX,MAAM,EAAE,uBAAuB,GAAG,cAAc;aAChD,GAAG,EAAE,GAAG;IA3B1B,SAAgB,OAAO,EAAE,OAAO,OAAO,CAAC;IACxC,SAAgB,cAAc,EAAE,OAAO,cAAc,CAAC;IAEtD,SAAgB,WAAW,EAAE,iBAAiB,EAAE,CAAM;IACtD,SAAgB,YAAY,EAAE,YAAY,CAAC;IAE3C,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,YAAY,CAAC,CAAiB;IACtC,OAAO,CAAC,qBAAqB,CAAC,CAAiB;IAC/C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,oBAAoB,CAAK;IACjC,OAAO,CAAC,iBAAiB,CAAK;IAG9B,OAAO,CAAC,oBAAoB,CAA0C;IACtE,OAAO,CAAC,iBAAiB,CAMvB;gBAGgB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,uBAAuB,GAAG,cAAc,EAChD,GAAG,EAAE,GAAG;IAqC1B,OAAO,CAAC,uBAAuB;YAQjB,wBAAwB;YA8CxB,iCAAiC;YA+CjC,iCAAiC;YAoHjC,8BAA8B;YA2D9B,yCAAyC;IA4BhD,4BAA4B,CACjC,cAAc,EAAE,MAAM,EACtB,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,MAAkD,GAC1D,IAAI;IAgBP,OAAO,CAAC,yBAAyB;IAW1B,oBAAoB,IAAI;QAC7B,YAAY,EAAE,MAAM,CAAC;QACrB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,aAAa,EAAE,MAAM,CAAC;QACtB,WAAW,EAAE,MAAM,CAAC;QACpB,cAAc,EAAE,MAAM,CAAC;QACvB,cAAc,EAAE,MAAM,CAAC;QACvB,aAAa,EAAE,MAAM,CAAC;KACvB;IAWD,kBAAkB,CAAC,SAAS,EAAE,iBAAiB;IAKzC,eAAe;IAmDrB,OAAO,CAAC,oBAAoB;IA8B5B,OAAO,CAAC,sBAAsB;IAO9B,OAAO,CAAC,iBAAiB;
|
|
1
|
+
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"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"}
|
package/dist/platform.js
CHANGED
|
@@ -359,20 +359,14 @@ class ViessmannPlatform {
|
|
|
359
359
|
}, delay);
|
|
360
360
|
}
|
|
361
361
|
startRefreshTimer() {
|
|
362
|
-
|
|
363
|
-
let refreshInterval =
|
|
364
|
-
if (this.config.enableRateLimitProtection !== false) {
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
// Warn if interval was adjusted
|
|
371
|
-
if (refreshInterval !== (this.config.refreshInterval || 60000)) {
|
|
372
|
-
this.log.warn(`Refresh interval adjusted to ${refreshInterval / 1000} seconds for rate limit protection`);
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
this.log.info(`Starting refresh timer with ${refreshInterval / 1000} second interval`);
|
|
362
|
+
const baseInterval = this.config.refreshInterval || 60000; // Default 1 minute
|
|
363
|
+
let refreshInterval = baseInterval;
|
|
364
|
+
if (this.config.enableRateLimitProtection !== false) {
|
|
365
|
+
refreshInterval = Math.max(baseInterval * this.backoffMultiplier, 60000); // min 1 minute
|
|
366
|
+
}
|
|
367
|
+
const intervalSec = Math.round(refreshInterval / 1000);
|
|
368
|
+
const nextAtTime = new Date(Date.now() + refreshInterval).toLocaleTimeString('it-IT');
|
|
369
|
+
this.log.info(`⏱️ Refresh timer started — interval: ${intervalSec}s (backoff: ×${this.backoffMultiplier.toFixed(2)}) | next update at ${nextAtTime}`);
|
|
376
370
|
this.refreshTimer = setInterval(() => {
|
|
377
371
|
this.updateAllDevices();
|
|
378
372
|
}, refreshInterval);
|
|
@@ -512,121 +506,133 @@ class ViessmannPlatform {
|
|
|
512
506
|
async updateAllDevices() {
|
|
513
507
|
// Prevent overlapping updates
|
|
514
508
|
if (this.isUpdating) {
|
|
515
|
-
this.log.debug('Skipping update cycle
|
|
509
|
+
this.log.debug('⏭️ Skipping update cycle — previous update still in progress');
|
|
516
510
|
return;
|
|
517
511
|
}
|
|
518
512
|
// Check rate limit status before updating
|
|
519
513
|
const rateLimitStatus = this.viessmannAPI.getRateLimitStatus();
|
|
520
514
|
if (rateLimitStatus.isLimited) {
|
|
521
|
-
this.log.warn(
|
|
515
|
+
this.log.warn(`⛔ Skipping update cycle — API rate limited for ${rateLimitStatus.waitSeconds}s`);
|
|
522
516
|
this.adjustRefreshInterval(true);
|
|
523
517
|
return;
|
|
524
518
|
}
|
|
525
519
|
this.isUpdating = true;
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
520
|
+
const cycleStart = Date.now();
|
|
521
|
+
this.log.debug('🔄 Starting device update cycle...');
|
|
522
|
+
// FIX#5: Deduplicate API calls — build a map of unique deviceKey → features.
|
|
523
|
+
// Previously we called getDeviceFeatures once per accessory, but Caldaia/ACS/Risc all
|
|
524
|
+
// share the same installation+gateway+device, causing 3 redundant API calls per cycle.
|
|
525
|
+
// Now we fetch features ONCE per device and dispatch to all matching accessories.
|
|
526
|
+
const deviceFeatureCache = new Map();
|
|
527
|
+
let successfulDevices = 0;
|
|
528
|
+
let rateLimitedDevices = 0;
|
|
529
|
+
let errorDevices = 0;
|
|
530
530
|
let skippedForBurnerUpdates = 0;
|
|
531
|
+
let handlersCalled = 0;
|
|
532
|
+
let handlersSkipped = 0;
|
|
531
533
|
try {
|
|
532
534
|
for (const accessory of this.accessories) {
|
|
535
|
+
if (!accessory.context.device) {
|
|
536
|
+
this.log.debug(`⚠️ Accessory "${accessory.displayName}" has no device context — skipping`);
|
|
537
|
+
continue;
|
|
538
|
+
}
|
|
539
|
+
const deviceKey = `${accessory.context.installation.id}-${accessory.context.gateway.serial}-${accessory.context.device.id}`;
|
|
540
|
+
// Skip if a recent immediate burner update is pending for this device
|
|
541
|
+
const hasRecentBurnerUpdate = this.pendingBurnerUpdates.has(deviceKey);
|
|
542
|
+
if (hasRecentBurnerUpdate && this.config.enableImmediateBurnerUpdates !== false) {
|
|
543
|
+
this.log.debug(`⚡ "${accessory.displayName}" — skipping full update, immediate burner update in progress`);
|
|
544
|
+
skippedForBurnerUpdates++;
|
|
545
|
+
continue;
|
|
546
|
+
}
|
|
533
547
|
try {
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
accessory.getService(this.Service.Switch) ||
|
|
554
|
-
accessory.getService(this.Service.TemperatureSensor);
|
|
555
|
-
if (service && accessory.context.updateHandler) {
|
|
556
|
-
// Call the update handler if available
|
|
557
|
-
accessory.context.updateHandler(features);
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
catch (error) {
|
|
561
|
-
clearTimeout(timeoutId);
|
|
562
|
-
throw error;
|
|
548
|
+
// FIX#5: fetch features only once per unique device, reuse for other accessories
|
|
549
|
+
let features;
|
|
550
|
+
if (deviceFeatureCache.has(deviceKey)) {
|
|
551
|
+
features = deviceFeatureCache.get(deviceKey);
|
|
552
|
+
this.log.debug(`📋 "${accessory.displayName}" — using already-fetched features for device ${accessory.context.device.id}`);
|
|
553
|
+
}
|
|
554
|
+
else {
|
|
555
|
+
this.log.debug(`🌐 "${accessory.displayName}" — fetching features for device ${accessory.context.device.id}...`);
|
|
556
|
+
const timeoutId = setTimeout(() => {
|
|
557
|
+
this.log.warn(`⏱️ API timeout after 25s for device ${accessory.context.device.id}`);
|
|
558
|
+
}, 25000);
|
|
559
|
+
features = await this.viessmannAPI.getDeviceFeatures(accessory.context.installation.id, accessory.context.gateway.serial, accessory.context.device.id);
|
|
560
|
+
clearTimeout(timeoutId);
|
|
561
|
+
deviceFeatureCache.set(deviceKey, features);
|
|
562
|
+
successfulDevices++;
|
|
563
|
+
this.log.debug(`✅ Fetched ${features.length} features for device ${accessory.context.device.id}`);
|
|
564
|
+
// Small delay between distinct device API calls only
|
|
565
|
+
if (this.config.enableRateLimitProtection !== false) {
|
|
566
|
+
await this.sleep(500);
|
|
563
567
|
}
|
|
564
568
|
}
|
|
569
|
+
// FIX#1: Call updateHandler directly — no longer gating on service type.
|
|
570
|
+
// Previously the code checked for Thermostat/Switch/TemperatureSensor, but
|
|
571
|
+
// DHW/Boiler/HC all use HeaterCooler as their primary service, so the condition
|
|
572
|
+
// could silently skip the handler if services were mid-recreation during async init.
|
|
573
|
+
if (accessory.context.updateHandler) {
|
|
574
|
+
accessory.context.updateHandler(features);
|
|
575
|
+
handlersCalled++;
|
|
576
|
+
this.log.debug(`📡 "${accessory.displayName}" — updateHandler dispatched`);
|
|
577
|
+
}
|
|
578
|
+
else {
|
|
579
|
+
handlersSkipped++;
|
|
580
|
+
this.log.warn(`⚠️ "${accessory.displayName}" — updateHandler not set (accessory still initializing?)`);
|
|
581
|
+
}
|
|
565
582
|
}
|
|
566
583
|
catch (error) {
|
|
567
|
-
|
|
568
|
-
if (
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
else {
|
|
581
|
-
this.log.error(`Failed to update accessory ${accessory.displayName}: ${errorMessage}`);
|
|
582
|
-
errorUpdates++;
|
|
583
|
-
}
|
|
584
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
585
|
+
if (msg.includes('Rate limited') || msg.includes('429')) {
|
|
586
|
+
rateLimitedDevices++;
|
|
587
|
+
this.log.warn(`🚫 "${accessory.displayName}" — rate limited during update, stopping cycle`);
|
|
588
|
+
break;
|
|
589
|
+
}
|
|
590
|
+
else if (msg.includes('ECONNABORTED') || msg.includes('ABORT_ERR') || msg.includes('timeout')) {
|
|
591
|
+
this.log.warn(`⏱️ "${accessory.displayName}" — API timeout, will retry next cycle`);
|
|
592
|
+
errorDevices++;
|
|
593
|
+
}
|
|
594
|
+
else if (msg.includes('401') || msg.includes('403') || msg.includes('Unauthorized')) {
|
|
595
|
+
this.log.error(`🔑 "${accessory.displayName}" — auth error during update (${msg}). Token refresh may be needed.`);
|
|
596
|
+
errorDevices++;
|
|
584
597
|
}
|
|
585
598
|
else {
|
|
586
|
-
this.log.error(
|
|
587
|
-
|
|
599
|
+
this.log.error(`❌ "${accessory.displayName}" — update failed: ${msg}`);
|
|
600
|
+
errorDevices++;
|
|
588
601
|
}
|
|
589
602
|
}
|
|
590
|
-
// Add small delay between accessory updates to be gentle on the API
|
|
591
|
-
if (this.config.enableRateLimitProtection !== false) {
|
|
592
|
-
await this.sleep(1000); // 1 second delay between accessories
|
|
593
|
-
}
|
|
594
603
|
}
|
|
595
|
-
|
|
596
|
-
this.updateCycleComplete(
|
|
604
|
+
const elapsed = Date.now() - cycleStart;
|
|
605
|
+
this.updateCycleComplete(successfulDevices, rateLimitedDevices, errorDevices, skippedForBurnerUpdates, handlersCalled, handlersSkipped, elapsed);
|
|
597
606
|
}
|
|
598
607
|
catch (error) {
|
|
599
|
-
this.log.error('
|
|
608
|
+
this.log.error('❌ Fatal error during device update cycle:', error);
|
|
600
609
|
this.adjustRefreshInterval(true);
|
|
601
610
|
}
|
|
602
611
|
finally {
|
|
603
612
|
this.isUpdating = false;
|
|
604
613
|
}
|
|
605
614
|
}
|
|
606
|
-
updateCycleComplete(successful, rateLimited, errors, skipped) {
|
|
607
|
-
const
|
|
615
|
+
updateCycleComplete(successful, rateLimited, errors, skipped, handlersCalled, handlersSkipped, elapsedMs) {
|
|
616
|
+
const totalAccessories = this.accessories.length;
|
|
617
|
+
const elapsedSec = (elapsedMs / 1000).toFixed(1);
|
|
608
618
|
if (rateLimited > 0) {
|
|
609
|
-
this.log.warn(
|
|
619
|
+
this.log.warn(`🔄 Update cycle done in ${elapsedSec}s — ${successful} device(s) fetched, ${rateLimited} rate-limited, ${errors} errors | handlers: ${handlersCalled} called, ${handlersSkipped} skipped | accessories: ${totalAccessories}`);
|
|
610
620
|
this.adjustRefreshInterval(true);
|
|
611
621
|
this.consecutiveErrors++;
|
|
612
622
|
}
|
|
613
|
-
else if (errors >
|
|
614
|
-
this.log.warn(
|
|
623
|
+
else if (errors > totalAccessories / 2) {
|
|
624
|
+
this.log.warn(`🔄 Update cycle done in ${elapsedSec}s — ${successful} device(s) fetched, ${errors} errors (>50%) | handlers: ${handlersCalled} called | accessories: ${totalAccessories}`);
|
|
615
625
|
this.adjustRefreshInterval(true);
|
|
616
626
|
this.consecutiveErrors++;
|
|
617
627
|
}
|
|
618
628
|
else {
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
this.log.debug(`Update cycle completed: ${successful}/${total} successful, ${errors} errors`);
|
|
624
|
-
}
|
|
625
|
-
// Reset error tracking on successful cycle
|
|
629
|
+
// Success path — log at info level so it's visible without debug mode
|
|
630
|
+
const skippedMsg = skipped > 0 ? `, ${skipped} skipped (burner update)` : '';
|
|
631
|
+
const handlersMsg = handlersSkipped > 0 ? ` ⚠️ ${handlersSkipped} handler(s) not set yet` : '';
|
|
632
|
+
this.log.info(`🔄 Update cycle done in ${elapsedSec}s — ${successful} device(s) fetched, ${handlersCalled}/${totalAccessories} accessories updated${skippedMsg}${handlersMsg}`);
|
|
626
633
|
if (successful > 0 && errors === 0) {
|
|
627
634
|
this.consecutiveErrors = 0;
|
|
628
635
|
this.adjustRefreshInterval(false);
|
|
629
|
-
// Log health score periodically
|
|
630
636
|
const healthScore = this.viessmannAPI.getAPIHealthScore();
|
|
631
637
|
const healthStatus = this.viessmannAPI.getAPIHealthStatus();
|
|
632
638
|
this.log.debug(`📊 API Health: ${healthScore}/100 (${healthStatus})`);
|
|
@@ -635,20 +641,25 @@ class ViessmannPlatform {
|
|
|
635
641
|
}
|
|
636
642
|
adjustRefreshInterval(increase) {
|
|
637
643
|
if (this.config.enableRateLimitProtection === false) {
|
|
638
|
-
return;
|
|
644
|
+
return;
|
|
639
645
|
}
|
|
646
|
+
const prevMultiplier = this.backoffMultiplier;
|
|
640
647
|
if (increase) {
|
|
641
|
-
this.backoffMultiplier = Math.min(this.backoffMultiplier * 1.5, 10);
|
|
648
|
+
this.backoffMultiplier = Math.min(this.backoffMultiplier * 1.5, 10);
|
|
642
649
|
}
|
|
643
650
|
else {
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
651
|
+
// FIX#3: clamp to 1 — multiplier will always be 1 after the first successful cycle,
|
|
652
|
+
// so the old condition (!increase && multiplier < 2) was always true and restarted
|
|
653
|
+
// the timer on every single successful cycle. Now we only restart when the multiplier
|
|
654
|
+
// actually changes by more than 10% from its previous value.
|
|
655
|
+
this.backoffMultiplier = Math.max(this.backoffMultiplier * 0.9, 1);
|
|
656
|
+
}
|
|
657
|
+
const changeRatio = Math.abs(this.backoffMultiplier - prevMultiplier) / Math.max(prevMultiplier, 1);
|
|
658
|
+
const significantChange = changeRatio > 0.1; // >10% change
|
|
659
|
+
if (significantChange && this.refreshTimer) {
|
|
660
|
+
this.log.info(`⏱️ Refresh interval adjusted: backoff ×${prevMultiplier.toFixed(2)} → ×${this.backoffMultiplier.toFixed(2)} (${increase ? 'backing off' : 'recovering'})`);
|
|
661
|
+
clearInterval(this.refreshTimer);
|
|
662
|
+
this.startRefreshTimer();
|
|
652
663
|
}
|
|
653
664
|
}
|
|
654
665
|
sleep(ms) {
|
package/dist/settings.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export declare const PLUGIN_NAME = "homebridge-viessmann-vicare";
|
|
|
9
9
|
/**
|
|
10
10
|
* Plugin version for User-Agent and logging
|
|
11
11
|
*/
|
|
12
|
-
export declare const PLUGIN_VERSION = "2.0.
|
|
12
|
+
export declare const PLUGIN_VERSION = "2.0.9";
|
|
13
13
|
/**
|
|
14
14
|
* Default configuration values
|
|
15
15
|
*/
|
package/dist/settings.js
CHANGED
package/dist/viessmann-api.d.ts
CHANGED
|
@@ -59,10 +59,11 @@ export { ViessmannInstallation, ViessmannFeature, ViessmannGateway, ViessmannDev
|
|
|
59
59
|
export declare class ViessmannAPI {
|
|
60
60
|
private readonly log;
|
|
61
61
|
private readonly config;
|
|
62
|
+
private readonly storagePath?;
|
|
62
63
|
private readonly authManager;
|
|
63
64
|
private readonly apiClient;
|
|
64
65
|
private readonly endpoints;
|
|
65
|
-
constructor(log: Logger, config: ViessmannPlatformConfig);
|
|
66
|
+
constructor(log: Logger, config: ViessmannPlatformConfig, storagePath?: string | undefined);
|
|
66
67
|
private createHttpClient;
|
|
67
68
|
private buildCacheConfig;
|
|
68
69
|
setBurnerUpdateCallback(callback: (installationId: number, gatewaySerial: string, deviceId: string, status: BurnerStatus, reason: string) => void): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"viessmann-api.d.ts","sourceRoot":"","sources":["../src/viessmann-api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACpC,OAAO,EAAe,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEzD,OAAO,EAAyB,qBAAqB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC5J,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAuBlD,MAAM,WAAW,uBAAwB,SAAQ,UAAU;IAEzD,IAAI,CAAC,EAAE,MAAM,CAAC;IAGd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAG9B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAG3B,4BAA4B,CAAC,EAAE,OAAO,CAAC;IACvC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAG9B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAG3B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAGjC,QAAQ,CAAC,EAAE;QACT,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAC9B,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IAGF,WAAW,CAAC,EAAE;QACZ,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,cAAc,CAAC,EAAE,MAAM,CAAC;QAGxB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;QAGjB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,CAAC;QAGb,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,UAAU,CAAC,EAAE,MAAM,CAAC;QAGpB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;IAGF,KAAK,CAAC,EAAE;QACN,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,kBAAkB,CAAC,EAAE,OAAO,CAAC;QAC7B,yBAAyB,CAAC,EAAE,OAAO,CAAC;QACpC,yBAAyB,CAAC,EAAE,OAAO,CAAC;QACpC,kBAAkB,CAAC,EAAE,OAAO,CAAC;KAC9B,CAAC;CACH;AAGD,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC;AAEpG,qBAAa,YAAY;IAMrB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM;
|
|
1
|
+
{"version":3,"file":"viessmann-api.d.ts","sourceRoot":"","sources":["../src/viessmann-api.ts"],"names":[],"mappings":"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"}
|
package/dist/viessmann-api.js
CHANGED
|
@@ -28,16 +28,18 @@ function detectLocalIP() {
|
|
|
28
28
|
class ViessmannAPI {
|
|
29
29
|
log;
|
|
30
30
|
config;
|
|
31
|
+
storagePath;
|
|
31
32
|
authManager;
|
|
32
33
|
apiClient;
|
|
33
34
|
endpoints;
|
|
34
|
-
constructor(log, config) {
|
|
35
|
+
constructor(log, config, storagePath) {
|
|
35
36
|
this.log = log;
|
|
36
37
|
this.config = config;
|
|
38
|
+
this.storagePath = storagePath;
|
|
37
39
|
// Detect host IP if not provided
|
|
38
40
|
const hostIp = this.config.hostIp || detectLocalIP();
|
|
39
|
-
// Initialize auth manager
|
|
40
|
-
this.authManager = new auth_manager_1.AuthManager(this.log, this.config, this.createHttpClient(), hostIp);
|
|
41
|
+
// Initialize auth manager — pass storagePath for Homebridge-compliant file storage
|
|
42
|
+
this.authManager = new auth_manager_1.AuthManager(this.log, this.config, this.createHttpClient(), hostIp, this.storagePath);
|
|
41
43
|
// Initialize API client
|
|
42
44
|
const apiClientConfig = {
|
|
43
45
|
requestTimeout: this.config.requestTimeout || 30000,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "homebridge-viessmann-vicare",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.8",
|
|
4
4
|
"description": "Complete Homebridge plugin for Viessmann ViCare heating systems with full control capabilities, advanced rate limiting protection, and intelligent cache management",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"homepage": "https://github.com/diegoweb100/homebridge-viessmann-vicare#readme",
|
|
37
37
|
"engines": {
|
|
38
|
-
"node": ">=
|
|
38
|
+
"node": ">=20.0.0",
|
|
39
39
|
"homebridge": ">=1.8.0 || >=2.0.0-beta.0"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
@@ -58,4 +58,4 @@
|
|
|
58
58
|
"type": "individual",
|
|
59
59
|
"url": "https://github.com/sponsors/diegoweb100"
|
|
60
60
|
}
|
|
61
|
-
}
|
|
61
|
+
}
|