iobroker.utility-monitor 1.4.2 → 1.4.5
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 +23 -132
- package/io-package.json +14 -66
- package/lib/billingManager.js +32 -6
- package/lib/consumptionManager.js +1 -1
- package/lib/multiMeterManager.js +68 -89
- package/lib/stateManager.js +31 -0
- package/main.js +6 -20
- package/package.json +13 -13
package/README.md
CHANGED
|
@@ -96,11 +96,11 @@ Für jede aktivierte Verbrauchsart (Gas/Wasser/Strom/PV) werden folgende Ordner
|
|
|
96
96
|
| `daily` | Kosten **heute** | daily × Arbeitspreis | 2,27 € |
|
|
97
97
|
| `monthly` | Kosten **diesen Monat** | monthly × Arbeitspreis | 21,61 € |
|
|
98
98
|
| `yearly` | **Verbrauchskosten** seit Vertragsbeginn | yearly × Arbeitspreis | 137,61 € |
|
|
99
|
-
| `totalYearly` | **Gesamtkosten Jahr** (Verbrauch + alle Fixkosten) | yearly-cost + basicCharge + annualFee |
|
|
100
|
-
| `basicCharge` | **Grundgebühr akkumuliert**
|
|
101
|
-
| `annualFee` | **Jahresgebühr
|
|
99
|
+
| `totalYearly` | **Gesamtkosten Jahr** (Verbrauch + alle Fixkosten) | yearly-cost + basicCharge + annualFee | 212,64 € |
|
|
100
|
+
| `basicCharge` | **Grundgebühr akkumuliert** | Grundgebühr × Monate | 15,03 € |
|
|
101
|
+
| `annualFee` | **Jahresgebühr** (fester Wert pro Jahr) | Jahresgebühr (aus Config) | 60,00 € |
|
|
102
102
|
| `paidTotal` | **Bezahlt** via Abschlag | Abschlag × Monate | 150,00 € |
|
|
103
|
-
| `balance` | **🎯 WICHTIGSTER Wert!**<br>Nachzahlung (+) oder Guthaben (-) | totalYearly - paidTotal | **+
|
|
103
|
+
| `balance` | **🎯 WICHTIGSTER Wert!**<br>Nachzahlung (+) oder Guthaben (-) | totalYearly - paidTotal | **+62,64 €**<br>→ Nachzahlung! |
|
|
104
104
|
|
|
105
105
|
#### 🔍 **balance** genauer erklärt:
|
|
106
106
|
|
|
@@ -112,13 +112,14 @@ Für jede aktivierte Verbrauchsart (Gas/Wasser/Strom/PV) werden folgende Ordner
|
|
|
112
112
|
|
|
113
113
|
```
|
|
114
114
|
Verbrauchskosten: 137,61 € (yearly)
|
|
115
|
-
Grundgebühr: + 15,03 € (basicCharge)
|
|
115
|
+
Grundgebühr: + 15,03 € (basicCharge - 1 Monat × 15,03€)
|
|
116
|
+
Jahresgebühr: + 60,00 € (annualFee - fester Wert)
|
|
116
117
|
────────────────────────────
|
|
117
|
-
Gesamtkosten:
|
|
118
|
+
Gesamtkosten: 212,64 € (totalYearly)
|
|
118
119
|
|
|
119
|
-
Bezahlt (Abschlag): 150,00 € (paidTotal)
|
|
120
|
+
Bezahlt (Abschlag): 150,00 € (paidTotal - 1 Monat × 150€)
|
|
120
121
|
────────────────────────────
|
|
121
|
-
Balance: +
|
|
122
|
+
Balance: +62,64 € → Nachzahlung
|
|
122
123
|
```
|
|
123
124
|
|
|
124
125
|
---
|
|
@@ -228,7 +229,20 @@ Der Adapter setzt Zähler automatisch zurück:
|
|
|
228
229
|
|
|
229
230
|
## Changelog
|
|
230
231
|
|
|
231
|
-
###
|
|
232
|
+
### 1.4.5 (2026-01-20)
|
|
233
|
+
|
|
234
|
+
- **FIX:** 🐛 **Critical Multi-Meter Cost Calculation Bugs** - Comprehensive fixes for multi-meter functionality:
|
|
235
|
+
- **Main Meter Sync Issue**: Removed duplicate initialization that prevented `lastSync` updates on main meter
|
|
236
|
+
- **basicCharge Accumulation**: Now correctly calculates `basicCharge = grundgebuehr × months` (was showing only 1 month)
|
|
237
|
+
- **paidTotal Accumulation**: Now correctly calculates `paidTotal = abschlag × months` (was showing only 1 month)
|
|
238
|
+
- **annualFee as Fixed Value**: Jahresgebühr is now used as fixed yearly value (e.g., 60€ stays 60€)
|
|
239
|
+
- Previously incorrectly treated as monthly fee and multiplied by months
|
|
240
|
+
- User-entered value in config (e.g., 60€) is now used directly as intended
|
|
241
|
+
- **Balance Formula Corrected**: Fixed reversed formula `balance = totalYearly - paidTotal`
|
|
242
|
+
- Positive balance = Nachzahlung (you owe money)
|
|
243
|
+
- Negative balance = Guthaben (you get money back)
|
|
244
|
+
- **IMPROVED:** 📦 **Dev-Dependencies**: Updated from tilde (~) to caret (^) versioning for better security updates
|
|
245
|
+
- **CLEANUP:** 🧹 **Repository Compliance**: Removed unpublished versions from changelog (resolves ioBroker Bot Issue #1)
|
|
232
246
|
|
|
233
247
|
### 1.4.2 (2026-01-18)
|
|
234
248
|
|
|
@@ -252,129 +266,6 @@ Der Adapter setzt Zähler automatisch zurück:
|
|
|
252
266
|
- Prevents silent failures in StateManager
|
|
253
267
|
- **IMPROVED:** 🧪 **Code Quality** - All tests passing (31 unit + 57 package tests)
|
|
254
268
|
|
|
255
|
-
### 1.4.1 (2026-01-18)
|
|
256
|
-
|
|
257
|
-
- **FIX:** 🐛 **Multi-Meter Critical Bugs** - Comprehensive fixes for multi-meter functionality:
|
|
258
|
-
- Fixed `updateCosts()` to correctly delegate to multiMeterManager for all meters
|
|
259
|
-
- Fixed `closeBillingPeriod()` to archive totals instead of only main meter values
|
|
260
|
-
- Fixed `checkMonthlyReport()` to display totals in reports for multi-meter setups
|
|
261
|
-
- Fixed state type mismatch: `lastDayStart`, `lastMonthStart`, `lastYearStart` now use number (timestamp) instead of string
|
|
262
|
-
- **NEW:** 🎯 **Per-Meter Billing Closure** - Each meter can now be closed individually with its own `billing.closePeriod` button
|
|
263
|
-
- Main meter: `gas.billing.closePeriod`
|
|
264
|
-
- Additional meters: `gas.erdgeschoss.billing.closePeriod`, `gas.keller.billing.closePeriod`, etc.
|
|
265
|
-
- Each meter uses its own contract date for yearly resets
|
|
266
|
-
- **NEW:** 📅 **Individual Contract Anniversary Resets** - Each meter resets on its own contract date
|
|
267
|
-
- Primary: Manual `closePeriod` triggers yearly reset immediately
|
|
268
|
-
- Fallback: Automatic reset on contract anniversary if user forgets to close period
|
|
269
|
-
- Contract date is preserved when closing period early (no drift)
|
|
270
|
-
- **IMPROVED:** 💰 **Billing Period Closure** - No longer resets `basicCharge` and `annualFee` to zero
|
|
271
|
-
- These values now persist from config (user must update config if tariff changes)
|
|
272
|
-
- Helpful reminder message added after closing period
|
|
273
|
-
- **FIX:** 🤖 **ioBroker Bot Compliance** - All bot checker issues resolved:
|
|
274
|
-
- Removed non-existent version 1.3.4 from news
|
|
275
|
-
- Added complete translations for all news entries (9 languages)
|
|
276
|
-
- Removed `.npmignore` file (using `files` field in package.json)
|
|
277
|
-
- DevDependencies already use `~` syntax (compliant)
|
|
278
|
-
|
|
279
|
-
### 1.4.0 (2026-01-17)
|
|
280
|
-
|
|
281
|
-
- **NEW:** 🎉 **Multi-Meter Support** - Verwende mehrere Zähler pro Typ (z.B. Gas Hauptzähler + Werkstatt-Zähler)
|
|
282
|
-
- Beliebig viele zusätzliche Zähler mit eigenen Namen konfigurierbar
|
|
283
|
-
- Separate Kostenberechnung und Statistiken pro Zähler
|
|
284
|
-
- Automatische Totals-Berechnung über alle Zähler
|
|
285
|
-
- **NEW:** ✨ **Komma-Dezimaltrenner Support** - Admin UI akzeptiert jetzt sowohl Komma als auch Punkt (z.B. `12,50` oder `12.50`)
|
|
286
|
-
- **NEW:** 📊 **Pro-Meter Billing** - Jeder Zähler hat eigene `billing.daysRemaining` und `billing.periodEnd` Werte
|
|
287
|
-
- **NEW:** 🔧 **Config-Parser** - Automatische Konvertierung von String→Number mit Komma-Support
|
|
288
|
-
- **FIX:** 💰 **Balance-Berechnung korrigiert** - Nutzt jetzt begonnene Monate statt volle Monate (17 Tage = 1 Monat gezahlt)
|
|
289
|
-
- **FIX:** 🐛 **String-Type Fehler** behoben - Config-Werte werden korrekt als Numbers verarbeitet
|
|
290
|
-
- **IMPROVED:** 🔍 **Debug-Logging** - Hilfreiche Debug-Logs für Troubleshooting (nur in Debug-Modus sichtbar)
|
|
291
|
-
- **CLEANUP:** 🧹 Repository aufgeräumt - Alte Backup-Dateien und temporäre Scripts entfernt
|
|
292
|
-
|
|
293
|
-
### 1.3.5 (2026-01-11)
|
|
294
|
-
|
|
295
|
-
- **NEW:** **Monatlicher Status-Bericht** - Optionaler monatlicher Bericht per Benachrichtigung.
|
|
296
|
-
- **NEW:** Datenpunkte `statistics.lastDay` (Verbrauch gestern) für alle Typen und `lastDayVolume` (Gas) hinzugefügt.
|
|
297
|
-
- **FIX:** **PV-Reset Bug** behoben (Tages- und Monatswerte wurden nicht zurückgesetzt).
|
|
298
|
-
- **FIX:** Schema-Validierung für Preisfelder korrigiert (Fix für Kommastellen).
|
|
299
|
-
- **FIX:** HT/NT-Anzeige korrigiert.
|
|
300
|
-
- **IMPROVED:** **Admin-UI Info-Tab** komplett optimiert (Sauberes Markdown & Layout).
|
|
301
|
-
- **IMPROVED:** Einheitliche Rundung berechneter Werte auf **2 Nachkommastellen** (daily, monthly, yearly).
|
|
302
|
-
- **ROBUSTNESS:** ioBroker Bot Compliance Check (Grid-Attribute in Admin-UI vereinheitlicht).
|
|
303
|
-
|
|
304
|
-
### 1.3.4 (2026-01-10)
|
|
305
|
-
|
|
306
|
-
- **FIX:** Kritischer Fix: Kommastellen für Gebühren-Felder (Grundgebühr, Arbeitspreis) werden nun korrekt gespeichert (Erlaubt 4 Nachkommastellen).
|
|
307
|
-
|
|
308
|
-
### 1.3.3 (2026-01-09)
|
|
309
|
-
|
|
310
|
-
- **IMPROVED:** Konfigurations-Reihenfolge optimiert (Gebühren logisch gruppiert).
|
|
311
|
-
- **NEW:** **PV-Benachrichtigungen** - Erhalte Erinnerungen auch für deine PV-Anlage (Abrechnung/Vertrag).
|
|
312
|
-
|
|
313
|
-
### 1.3.2 (2026-01-09)
|
|
314
|
-
|
|
315
|
-
- **NEW:** **PV / Einspeise-Unterstützung** ☀️ - Neuer Tab für Photovoltaik:
|
|
316
|
-
- Überwache deine Netzeinspeisung (kWh).
|
|
317
|
-
- Berechne deine Vergütung (Earnings) automatisch.
|
|
318
|
-
- Volle Unterstützung für Zählerstände, Abrechnungszeiträume und Historie.
|
|
319
|
-
|
|
320
|
-
### 1.3.1 (2026-01-09)
|
|
321
|
-
|
|
322
|
-
- **FIX:** Kritischer Fehler behoben: HT/NT-Datenpunkte wurden aufgrund eines internen Namensfehlers (electricity vs. strom) nicht angelegt.
|
|
323
|
-
- **FIX:** Warnungen im Log "State ... has no existing object" beseitigt.
|
|
324
|
-
|
|
325
|
-
### 1.3.0 (2026-01-09)
|
|
326
|
-
|
|
327
|
-
- **NEW:** **Differenzierte Benachrichtigungen** - Zwei getrennte Erinnerungstypen:
|
|
328
|
-
- **Abrechnungsende**: Erinnerung zum Zählerstand ablesen (z.B. 7 Tage vorher).
|
|
329
|
-
- **Vertragswechsel**: Erinnerung zum Tarif-Check / Kündigen (z.B. 60 Tage vorher).
|
|
330
|
-
- **NEW:** **Interaktives Benachrichtigungs-Feedback** - Der Test-Button zeigt nun direkt Erfolgs- oder Fehlermeldungen via Popup an (inkl. SMTP-Fehler vom Email-Adapter).
|
|
331
|
-
- **NEW:** **Live-Test ohne Speichern** - Benachrichtigungen können jetzt sofort getestet werden, ohne die Konfiguration vorher speichern zu müssen.
|
|
332
|
-
- **NEW:** **Modularer Code-Aufbau** - Umstellung auf eine moderne Architektur mit spezialisierten Managern für bessere Performance und Wartbarkeit.
|
|
333
|
-
- **IMPROVED:** **Responsives Admin-UI** - Kompakteres Button-Design und optimierte Darstellung auf mobilen Geräten.
|
|
334
|
-
- **FIX:** Redundante Volumen-Datenpunkte (`dailyVolume` etc.) für Strom und Wasser entfernt, um Log-Warnungen zu vermeiden.
|
|
335
|
-
- **FIX:** Mandatory bot requirements (Changelog header, News cleanup).
|
|
336
|
-
|
|
337
|
-
### 1.2.7 (2026-01-08)
|
|
338
|
-
|
|
339
|
-
- **NEW:** Universelles Benachrichtigungssystem für Abrechnungszeitraum-Erinnerungen (Telegram, Pushover, Email, etc.)
|
|
340
|
-
- **NEW:** Optionale PayPal-Unterstützung (Links in README und Config)
|
|
341
|
-
- **FIX:** Dezimalstellen für Tagesverbrauch auf 3 erhöht (bessere Unterstützung für Sensoren mit kleinen Deltas wie Shelly)
|
|
342
|
-
- **FIX:** Erlauben von leeren Preisen/Gebühren in der Konfiguration (verhindert Speicher-Fehler)
|
|
343
|
-
|
|
344
|
-
### 1.2.6 (2026-01-08)
|
|
345
|
-
|
|
346
|
-
- **FIX:** Erlaube leere Felder für Grundgebühr/Jahresgebühr/Abschlag in der Konfiguration (verhindert Speicher-Block im Admin-UI)
|
|
347
|
-
|
|
348
|
-
### 1.2.5 (2026-01-08)
|
|
349
|
-
|
|
350
|
-
- **NEW:** Transparente Anzeige des Vertragsbeginns bei jedem Adapter-Start im Log
|
|
351
|
-
- **NEW:** Unterstützung für zusätzliche **Jahresgebühren** (z.B. Zählermiete)
|
|
352
|
-
- **NEW:** Datenpunkt `costs.totalYearly` für die echten Gesamtkosten
|
|
353
|
-
- **FIX:** Kritischer Fehler in der Verbrauchs-Delta-Berechnung behoben (v1.2.4)
|
|
354
|
-
- **FIX:** Arbeitspreis-Anzeige bei Strom korrigiert
|
|
355
|
-
- **FIX:** Gas m³ → kWh Umrechnung für Anpassungswerte
|
|
356
|
-
- **FIX:** Korrekte Initialisierung des Vertragsjahres bei Neustart
|
|
357
|
-
- **FIX:** Vereinheitlichung der Konfigurationsschlüssel (`wasserInitialReading`)
|
|
358
|
-
- **ROBUSTNESS:** Schutz vor Datenverlust bei Adapter-Neustart (Zählerstand-Persistierung)
|
|
359
|
-
- **ROBUSTNESS:** Integration von manuellen Anpassungen in die HT/NT-Kostenrechnung
|
|
360
|
-
- **NEW:** Volle Unterstützung für **HT/NT-Tarife** für alle Energieträger (Strom, Gas, Wasser)
|
|
361
|
-
- **NEW:** Automatische Archivierung von HT/NT-Verbräuchen und Kosten in der Historie
|
|
362
|
-
- **DOCS:** Internationalisierung von Titel und Beschreibung
|
|
363
|
-
|
|
364
|
-
### 1.2.2 (2026-01-08)
|
|
365
|
-
|
|
366
|
-
- **NEW:** Manuelle Anpassung für Sensor-Abdrift-Korrektur
|
|
367
|
-
- **NEW:** Abrechnungszeitraum-Management mit automatischer Archivierung
|
|
368
|
-
- **NEW:** Unterstützung für zusätzliche **Jahresgebühren** (z.B. Zählermiete)
|
|
369
|
-
- **NEW:** Datenpunkt `costs.totalYearly` für die echten Gesamtkosten
|
|
370
|
-
- **FIX:** Arbeitspreis-Anzeige bei Strom korrigiert
|
|
371
|
-
- **FIX:** Gas m³ → kWh Umrechnung für Anpassungswerte
|
|
372
|
-
- **DOCS:** Internationalisierung von Titel und Beschreibung
|
|
373
|
-
|
|
374
|
-
---
|
|
375
|
-
|
|
376
|
-
- Initial release
|
|
377
|
-
|
|
378
269
|
---
|
|
379
270
|
|
|
380
271
|
## License
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "utility-monitor",
|
|
4
|
-
"version": "1.4.
|
|
4
|
+
"version": "1.4.5",
|
|
5
5
|
"news": {
|
|
6
|
+
"1.4.5": {
|
|
7
|
+
"en": "Fix: Critical multi-meter cost calculation bugs (main meter sync, basicCharge/paidTotal accumulation, annualFee as fixed yearly value). Fix: Balance formula corrected. Fix: Removed duplicate initialization causing sync issues.",
|
|
8
|
+
"de": "Fix: Kritische Multi-Meter Kostenberechnungsfehler (Hauptzähler-Sync, basicCharge/paidTotal Akkumulation, Jahresgebühr als fester Jahreswert). Fix: Balance-Formel korrigiert. Fix: Doppelte Initialisierung entfernt.",
|
|
9
|
+
"ru": "Исправление: Критические ошибки расчета затрат multi-meter (синхронизация главного счетчика, накопление basicCharge/paidTotal, annualFee как фиксированное годовое значение). Исправление: Формула баланса исправлена. Исправление: Удалена дублирующая инициализация.",
|
|
10
|
+
"pt": "Correção: Bugs críticos de cálculo de custos multi-medidor (sincronização medidor principal, acumulação basicCharge/paidTotal, annualFee como valor anual fixo). Correção: Fórmula de saldo corrigida. Correção: Inicialização duplicada removida.",
|
|
11
|
+
"nl": "Fix: Kritieke multi-meter kostenberekeningsfouten (hoofdmeter sync, basicCharge/paidTotal accumulatie, annualFee als vaste jaarwaarde). Fix: Balans formule gecorrigeerd. Fix: Dubbele initialisatie verwijderd.",
|
|
12
|
+
"fr": "Correction: Bugs critiques calcul coûts multi-compteurs (sync compteur principal, accumulation basicCharge/paidTotal, annualFee comme valeur annuelle fixe). Correction: Formule de solde corrigée. Correction: Initialisation en double supprimée.",
|
|
13
|
+
"it": "Correzione: Bug critici calcolo costi multi-contatore (sync contatore principale, accumulazione basicCharge/paidTotal, annualFee come valore annuale fisso). Correzione: Formula bilancio corretta. Correzione: Inizializzazione duplicata rimossa.",
|
|
14
|
+
"es": "Corrección: Bugs críticos cálculo costos multi-medidor (sincronización medidor principal, acumulación basicCharge/paidTotal, annualFee como valor anual fijo). Corrección: Fórmula balance corregida. Corrección: Inicialización duplicada eliminada.",
|
|
15
|
+
"pl": "Naprawa: Krytyczne błędy obliczania kosztów multi-meter (synchronizacja głównego licznika, akumulacja basicCharge/paidTotal, annualFee jako stała wartość roczna). Naprawa: Formuła salda poprawiona. Naprawa: Usunięto podwójną inicjalizację.",
|
|
16
|
+
"uk": "Виправлення: Критичні помилки розрахунку витрат multi-meter (синхронізація головного лічильника, накопичення basicCharge/paidTotal, annualFee як фіксоване річне значення). Виправлення: Формула балансу виправлена. Виправлення: Видалено подвійну ініціалізацію.",
|
|
17
|
+
"zh-cn": "修复:关键多表成本计算错误(主表同步、basicCharge/paidTotal累积、annualFee作为固定年值)。修复:余额公式已更正。修复:删除重复初始化。"
|
|
18
|
+
},
|
|
6
19
|
"1.4.2": {
|
|
7
20
|
"en": "Fix: Critical multi-meter balance bug (hardcoded 12 months). Fix: TypeScript errors resolved. New: Enhanced input validation. New: Extended constants. New: Error handling wrapper.",
|
|
8
21
|
"de": "Fix: Kritischer Multi-Meter Balance-Bug (hardcodierte 12 Monate). Fix: TypeScript-Fehler behoben. Neu: Erweiterte Eingabevalidierung. Neu: Erweiterte Konstanten. Neu: Fehlerbehandlungs-Wrapper.",
|
|
@@ -15,71 +28,6 @@
|
|
|
15
28
|
"pl": "Naprawa: Krytyczny błąd salda multi-meter (zakodowane 12 miesięcy). Naprawa: Naprawione błędy TypeScript. Nowe: Ulepszona walidacja danych. Nowe: Rozszerzone stałe. Nowe: Wrapper obsługi błędów.",
|
|
16
29
|
"uk": "Виправлення: Критична помилка балансу multi-meter (жорстко задані 12 місяців). Виправлення: Усунено помилки TypeScript. Нове: Покращена перевірка даних. Нове: Розширені константи. Нове: Обробник помилок.",
|
|
17
30
|
"zh-cn": "修复:关键多表余额错误(硬编码12个月)。修复:解决TypeScript错误。新增:增强输入验证。新增:扩展常量。新增:错误处理包装器。"
|
|
18
|
-
},
|
|
19
|
-
"1.4.1": {
|
|
20
|
-
"en": "Fix: Multi-meter bugs (cost calculation, billing period closure, monthly reports, yearly resets). Fix: Per-meter billing closure support. Fix: State type corrections (lastDayStart). Fix: ioBroker Bot compliance.",
|
|
21
|
-
"de": "Fix: Multi-Meter-Fehler (Kostenberechnung, Periodenabschluss, Monatsberichte, Jahres-Resets). Fix: Zähler-individuelle Periodenabschlüsse. Fix: State-Typ-Korrekturen (lastDayStart). Fix: ioBroker Bot-Compliance.",
|
|
22
|
-
"ru": "Исправление: Ошибки нескольких счетчиков (расчет затрат, закрытие периода, ежемесячные отчеты, годовые сбросы). Исправление: Поддержка закрытия периода для каждого счетчика. Исправление: Исправления типов состояний. Исправление: Соответствие ioBroker Bot.",
|
|
23
|
-
"pt": "Correção: Bugs multi-medidor (cálculo custos, fechamento período, relatórios mensais, resets anuais). Correção: Suporte fechamento período por medidor. Correção: Correções tipo estado. Correção: Conformidade Bot ioBroker.",
|
|
24
|
-
"nl": "Fix: Multi-meter bugs (kostenberekening, periode afsluiting, maandraporten, jaarlijkse resets). Fix: Per-meter periode afsluiting. Fix: State type correcties. Fix: ioBroker Bot compliance.",
|
|
25
|
-
"fr": "Correction: Bugs multi-compteurs (calcul coûts, clôture période, rapports mensuels, réinitialisations annuelles). Correction: Support clôture période par compteur. Correction: Corrections type d'état. Correction: Conformité Bot ioBroker.",
|
|
26
|
-
"it": "Correzione: Bug multi-contatore (calcolo costi, chiusura periodo, report mensili, reset annuali). Correzione: Supporto chiusura periodo per contatore. Correzione: Correzioni tipo stato. Correzione: Conformità Bot ioBroker.",
|
|
27
|
-
"es": "Corrección: Bugs multi-medidor (cálculo costos, cierre período, informes mensuales, reinicios anuales). Corrección: Soporte cierre período por medidor. Corrección: Correcciones tipo estado. Corrección: Cumplimiento Bot ioBroker.",
|
|
28
|
-
"pl": "Naprawa: Błędy wielu liczników (obliczanie kosztów, zamknięcie okresu, raporty miesięczne, resety roczne). Naprawa: Wsparcie zamknięcia okresu dla licznika. Naprawa: Poprawki typu stanu. Naprawa: Zgodność z Bot ioBroker.",
|
|
29
|
-
"uk": "Виправлення: Помилки кількох лічильників (розрахунок витрат, закриття періоду, місячні звіти, річні скидання). Виправлення: Підтримка закриття періоду для лічильника. Виправлення: Виправлення типу стану. Виправлення: Відповідність ioBroker Bot.",
|
|
30
|
-
"zh-cn": "修复:多表错误(成本计算、期间关闭、月度报告、年度重置)。修复:每表期间关闭支持。修复:状态类型更正。修复:ioBroker Bot合规性。"
|
|
31
|
-
},
|
|
32
|
-
"1.4.0": {
|
|
33
|
-
"en": "New: Multi-Meter Support! Add unlimited custom-named meters per utility type (gas, water, electricity). Automatic totals calculation. Fully backward compatible.",
|
|
34
|
-
"de": "Neu: Multi-Meter-Unterstützung! Unbegrenzt viele Zähler pro Medium (Gas, Wasser, Strom) mit benutzerdefinierten Namen. Automatische Gesamt-Summen. Vollständig rückwärtskompatibel.",
|
|
35
|
-
"ru": "Новое: Поддержка нескольких счетчиков! Добавьте неограниченное количество пользовательских счетчиков для каждого типа коммунальных услуг (газ, вода, электричество). Автоматический расчет итогов. Полная обратная совместимость.",
|
|
36
|
-
"pt": "Novo: Suporte Multi-Medidor! Adicione medidores personalizados ilimitados por tipo de utilidade (gás, água, eletricidade). Cálculo automático de totais. Totalmente compatível com versões anteriores.",
|
|
37
|
-
"nl": "Nieuw: Multi-Meter Ondersteuning! Voeg onbeperkt aangepaste meters toe per type (gas, water, elektriciteit). Automatische totaalberekening. Volledig achterwaarts compatibel.",
|
|
38
|
-
"fr": "Nouveau: Support Multi-Compteur! Ajoutez des compteurs personnalisés illimités par type de service (gaz, eau, électricité). Calcul automatique des totaux. Entièrement rétrocompatible.",
|
|
39
|
-
"it": "Nuovo: Supporto Multi-Contatore! Aggiungi contatori personalizzati illimitati per tipo di servizio (gas, acqua, elettricità). Calcolo automatico dei totali. Completamente retrocompatibile.",
|
|
40
|
-
"es": "Nuevo: Soporte Multi-Medidor! Agregue medidores personalizados ilimitados por tipo de servicio (gas, agua, electricidad). Cálculo automático de totales. Totalmente compatible con versiones anteriores.",
|
|
41
|
-
"pl": "Nowe: Obsługa Wielu Liczników! Dodaj nieograniczoną liczbę niestandardowych liczników dla każdego typu mediów (gaz, woda, prąd). Automatyczne obliczanie sum. Pełna kompatybilność wsteczna.",
|
|
42
|
-
"uk": "Нове: Підтримка кількох лічильників! Додайте необмежену кількість власних лічильників для кожного типу комунальних послуг (газ, вода, електрика). Автоматичний розрахунок підсумків. Повна зворотна сумісність.",
|
|
43
|
-
"zh-cn": "新增:多表支持!为每种公用事业类型(燃气、水、电)添加无限的自定义计量表。自动总计计算。完全向后兼容。"
|
|
44
|
-
},
|
|
45
|
-
"1.3.5": {
|
|
46
|
-
"en": "New: Monthly Status Report. New: Added lastDay statistics. Fix: PV period reset bug. Fix: Schema validation for prices. Improved: Admin UI Info-Tab optimized. Improved: Consistent rounding (2 decimals). Improved: Bot compliance grid attributes.",
|
|
47
|
-
"de": "Neu: Monatlicher Status-Bericht. Neu: lastDay-Statistiken hinzugefügt. Fix: PV Perioden-Reset Fehler behoben. Fix: Schema-Validierung für Preisfelder. Verbessert: Admin-UI Info-Tab optimiert. Verbessert: Einheitliche Rundung (2 Stellen). Verbessert: Bot-Compliance Grid-Attribute.",
|
|
48
|
-
"ru": "Новое: Ежемесячный отчет о состоянии. Новое: Добавлена статистика lastDay. Исправление: Ошибка сброса периода PV. Исправление: Проверка схемы для цен. Улучшено: Оптимизирована вкладка информации Admin UI. Улучшено: Последовательное округление (2 знака). Улучшено: Атрибуты сетки соответствия ботов.",
|
|
49
|
-
"pt": "Novo: Relatório de Status Mensal. Novo: Adicionadas estatísticas lastDay. Correção: Bug de redefinição de período PV. Correção: Validação de esquema para preços. Melhorado: Guia de informações da Admin UI otimizada. Melhorado: Arredondamento consistente (2 decimais). Melhorado: Atributos de grade de conformidade do bot.",
|
|
50
|
-
"nl": "Nieuw: Maandelijks statusrapport. Nieuw: lastDay statistieken toegevoegd. Fix: PV periode reset bug. Fix: Schema validatie voor prijzen. Verbeterd: Admin UI Info-Tab geoptimaliseerd. Verbeterd: Consistente afronding (2 decimalen). Verbeterd: Bot compliance grid attributen.",
|
|
51
|
-
"fr": "Nouveau: Rapport d'état mensuel. Nouveau: Ajout de statistiques lastDay. Correction: Bug de réinitialisation de période PV. Correction: Validation de schéma pour les prix. Amélioré: Onglet d'informations Admin UI optimisé. Amélioré: Arrondi cohérent (2 décimales). Amélioré: Attributs de grille de conformité des bots.",
|
|
52
|
-
"it": "Nuovo: Rapporto di stato mensile. Nuovo: Aggiunte statistiche lastDay. Correzione: Bug di reset periodo PV. Correzione: Convalida dello schema per i prezzi. Migliorato: Scheda informazioni Admin UI ottimizzata. Migliorato: Arrotondamento coerente (2 decimali). Migliorato: Attributi griglia conformità bot.",
|
|
53
|
-
"es": "Nuevo: Informe de Estado Mensual. Nuevo: Agregadas estadísticas lastDay. Corrección: Error de reinicio de período PV. Corrección: Validación de esquema para precios. Mejorado: Pestaña de información de Admin UI optimizada. Mejorado: Redondeo consistente (2 decimales). Mejorado: Atributos de cuadrícula de cumplimiento de bots.",
|
|
54
|
-
"pl": "Nowe: Miesięczny raport statusu. Nowe: Dodano statystyki lastDay. Naprawa: Błąd resetowania okresu PV. Naprawa: Walidacja schematu dla cen. Ulepszone: Zoptymalizowana zakładka informacji Admin UI. Ulepszone: Spójne zaokrąglanie (2 miejsca dziesiętne). Ulepszone: Atrybuty siatki zgodności botów.",
|
|
55
|
-
"uk": "Нове: Щомісячний звіт про стан. Нове: Додано статистику lastDay. Виправлення: Помилка скидання періоду PV. Виправлення: Перевірка схеми для цін. Покращено: Оптимізовано вкладку інформації Admin UI. Покращено: Послідовне округлення (2 знаки). Покращено: Атрибути сітки відповідності ботів.",
|
|
56
|
-
"zh-cn": "新增:每月状态报告。新增:添加了lastDay统计信息。修复:PV周期重置错误。修复:价格架构验证。改进:优化了Admin UI信息选项卡。改进:一致的四舍五入(2位小数)。改进:机器人合规网格属性。"
|
|
57
|
-
},
|
|
58
|
-
"1.3.3": {
|
|
59
|
-
"en": "New: PV/Feed-in integration! Monitor your solar feed-in and earnings. New: Notifications for PV. Improved: Reorganized config UI.",
|
|
60
|
-
"de": "Neu: PV/Einspeise-Integration! Überwache deine Solareinspeisung und Vergütung. Neu: Benachrichtigungen für PV. Verbessert: Aufgeräumte Konfigurations-Oberfläche.",
|
|
61
|
-
"ru": "Новое: Интеграция PV/Feed-in! Отслеживайте свою солнечную подачу и доходы. Новое: Уведомления для PV. Улучшено: Реорганизован интерфейс конфигурации.",
|
|
62
|
-
"pt": "Novo: Integração PV/Feed-in! Monitore sua alimentação solar e ganhos. Novo: Notificações para PV. Melhorado: IU de configuração reorganizada.",
|
|
63
|
-
"nl": "Nieuw: PV/Feed-in integratie! Monitor je zonne-invoeding en inkomsten. Nieuw: Meldingen voor PV. Verbeterd: Gereorganiseerde configuratie-UI.",
|
|
64
|
-
"fr": "Nouveau: Intégration PV/Feed-in! Surveillez votre injection solaire et vos revenus. Nouveau: Notifications pour PV. Amélioré: Interface de configuration réorganisée.",
|
|
65
|
-
"it": "Nuovo: Integrazione PV/Feed-in! Monitora il tuo immissione solare e i guadagni. Nuovo: Notifiche per PV. Migliorato: IU di configurazione riorganizzata.",
|
|
66
|
-
"es": "Nuevo: Integración PV/Feed-in! Monitorea tu alimentación solar y ganancias. Nuevo: Notificaciones para PV. Mejorado: IU de configuración reorganizada.",
|
|
67
|
-
"pl": "Nowe: Integracja PV/Feed-in! Monitoruj swoje zasilanie słoneczne i zarobki. Nowe: Powiadomienia dla PV. Ulepszone: Zreorganizowany interfejs konfiguracji.",
|
|
68
|
-
"uk": "Нове: Інтеграція PV/Feed-in! Відстежуйте своє сонячне живлення та доходи. Нове: Сповіщення для PV. Покращено: Реорганізований інтерфейс конфігурації.",
|
|
69
|
-
"zh-cn": "新增:PV/Feed-in集成!监控您的太阳能馈入和收益。新增:PV通知。改进:重新组织的配置界面。"
|
|
70
|
-
},
|
|
71
|
-
"1.3.2": {
|
|
72
|
-
"en": "New: Initial support for PV integration.",
|
|
73
|
-
"de": "Neu: Erste Unterstützung für PV-Integration.",
|
|
74
|
-
"ru": "Новое: Начальная поддержка интеграции PV.",
|
|
75
|
-
"pt": "Novo: Suporte inicial para integração PV.",
|
|
76
|
-
"nl": "Nieuw: Initiële ondersteuning voor PV-integratie.",
|
|
77
|
-
"fr": "Nouveau: Support initial pour l'intégration PV.",
|
|
78
|
-
"it": "Nuovo: Supporto iniziale per l'integrazione PV.",
|
|
79
|
-
"es": "Nuevo: Soporte inicial para integración PV.",
|
|
80
|
-
"pl": "Nowe: Wstępne wsparcie dla integracji PV.",
|
|
81
|
-
"uk": "Нове: Початкова підтримка інтеграції PV.",
|
|
82
|
-
"zh-cn": "新增:PV集成的初始支持。"
|
|
83
31
|
}
|
|
84
32
|
},
|
|
85
33
|
"titleLang": {
|
package/lib/billingManager.js
CHANGED
|
@@ -155,10 +155,14 @@ class BillingManager {
|
|
|
155
155
|
monthsSinceContract = Math.max(1, yDiff * 12 + mDiff + 1);
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
+
// Calculate accumulated basic charge (monthly fee × months)
|
|
158
159
|
const basicChargeAccumulated = basicChargeMonthly * monthsSinceContract;
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
160
|
+
|
|
161
|
+
// Jahresgebühr ist ein FIXER Wert pro Jahr (z.B. 60€)
|
|
162
|
+
// NICHT pro-rata nach Monaten/Tagen berechnen!
|
|
163
|
+
const annualFeeAccumulated = annualFeePerYear;
|
|
164
|
+
|
|
165
|
+
const totalYearlyCost = yearlyConsumptionCost + basicChargeAccumulated + annualFeeAccumulated;
|
|
162
166
|
|
|
163
167
|
// Update states
|
|
164
168
|
await this.adapter.setStateAsync(
|
|
@@ -186,9 +190,11 @@ class BillingManager {
|
|
|
186
190
|
calculator.roundToDecimals(annualFeeAccumulated, 2),
|
|
187
191
|
true,
|
|
188
192
|
);
|
|
193
|
+
// basicCharge enthält NUR die monatliche Grundgebühr (akkumuliert)
|
|
194
|
+
// Jahresgebühr ist separat in annualFee
|
|
189
195
|
await this.adapter.setStateAsync(
|
|
190
196
|
`${type}.costs.basicCharge`,
|
|
191
|
-
calculator.roundToDecimals(
|
|
197
|
+
calculator.roundToDecimals(basicChargeAccumulated, 2),
|
|
192
198
|
true,
|
|
193
199
|
);
|
|
194
200
|
|
|
@@ -438,7 +444,7 @@ class BillingManager {
|
|
|
438
444
|
const configType = this.adapter.consumptionManager.getConfigType(type);
|
|
439
445
|
contractStartDate = this.adapter.config[`${configType}ContractStart`];
|
|
440
446
|
} else {
|
|
441
|
-
contractStartDate = meter.config?.
|
|
447
|
+
contractStartDate = meter.config?.contractStart;
|
|
442
448
|
}
|
|
443
449
|
|
|
444
450
|
if (!contractStartDate) {
|
|
@@ -587,7 +593,7 @@ class BillingManager {
|
|
|
587
593
|
contractStartDate = this.adapter.config[`${configType}ContractStart`];
|
|
588
594
|
} else {
|
|
589
595
|
// Additional meter: use meter's individual config
|
|
590
|
-
contractStartDate = meter.config?.
|
|
596
|
+
contractStartDate = meter.config?.contractStart;
|
|
591
597
|
}
|
|
592
598
|
|
|
593
599
|
if (contractStartDate) {
|
|
@@ -665,6 +671,18 @@ class BillingManager {
|
|
|
665
671
|
await this.adapter.setStateAsync(`${basePath}.consumption.dailyVolume`, 0, true);
|
|
666
672
|
}
|
|
667
673
|
|
|
674
|
+
// Reset HT/NT daily counters if enabled
|
|
675
|
+
const configType = this.adapter.consumptionManager.getConfigType(type);
|
|
676
|
+
const htNtEnabled = this.adapter.config[`${configType}HtNtEnabled`] || false;
|
|
677
|
+
if (htNtEnabled) {
|
|
678
|
+
const dailyHT = await this.adapter.getStateAsync(`${basePath}.consumption.dailyHT`);
|
|
679
|
+
const dailyNT = await this.adapter.getStateAsync(`${basePath}.consumption.dailyNT`);
|
|
680
|
+
await this.adapter.setStateAsync(`${basePath}.statistics.lastDayHT`, dailyHT?.val || 0, true);
|
|
681
|
+
await this.adapter.setStateAsync(`${basePath}.statistics.lastDayNT`, dailyNT?.val || 0, true);
|
|
682
|
+
await this.adapter.setStateAsync(`${basePath}.consumption.dailyHT`, 0, true);
|
|
683
|
+
await this.adapter.setStateAsync(`${basePath}.consumption.dailyNT`, 0, true);
|
|
684
|
+
}
|
|
685
|
+
|
|
668
686
|
await this.adapter.setStateAsync(`${basePath}.costs.daily`, 0, true);
|
|
669
687
|
|
|
670
688
|
// Update lastDayStart timestamp
|
|
@@ -715,6 +733,14 @@ class BillingManager {
|
|
|
715
733
|
await this.adapter.setStateAsync(`${basePath}.consumption.monthlyVolume`, 0, true);
|
|
716
734
|
}
|
|
717
735
|
|
|
736
|
+
// Reset HT/NT monthly counters if enabled
|
|
737
|
+
const configType = this.adapter.consumptionManager.getConfigType(type);
|
|
738
|
+
const htNtEnabled = this.adapter.config[`${configType}HtNtEnabled`] || false;
|
|
739
|
+
if (htNtEnabled) {
|
|
740
|
+
await this.adapter.setStateAsync(`${basePath}.consumption.monthlyHT`, 0, true);
|
|
741
|
+
await this.adapter.setStateAsync(`${basePath}.consumption.monthlyNT`, 0, true);
|
|
742
|
+
}
|
|
743
|
+
|
|
718
744
|
await this.adapter.setStateAsync(`${basePath}.costs.monthly`, 0, true);
|
|
719
745
|
|
|
720
746
|
// Update lastMonthStart timestamp
|
|
@@ -244,7 +244,7 @@ class ConsumptionManager {
|
|
|
244
244
|
const lastValue = this.lastSensorValues[sensorDP];
|
|
245
245
|
this.lastSensorValues[sensorDP] = consumption;
|
|
246
246
|
|
|
247
|
-
if (lastValue === undefined || consumption
|
|
247
|
+
if (lastValue === undefined || consumption < lastValue) {
|
|
248
248
|
if (lastValue !== undefined && consumption < lastValue) {
|
|
249
249
|
this.adapter.log.warn(
|
|
250
250
|
`${type}: Sensor value decreased (${lastValue} -> ${consumption}). Assuming meter reset or replacement.`,
|
package/lib/multiMeterManager.js
CHANGED
|
@@ -221,43 +221,46 @@ class MultiMeterManager {
|
|
|
221
221
|
}
|
|
222
222
|
|
|
223
223
|
// Initialize period start timestamps
|
|
224
|
-
const nowIso = calculator.formatDateString(new Date());
|
|
225
224
|
const timestampRoles = ['lastDayStart', 'lastMonthStart', 'lastYearStart'];
|
|
226
225
|
|
|
227
226
|
for (const role of timestampRoles) {
|
|
228
227
|
const statePath = `${basePath}.statistics.${role}`;
|
|
229
228
|
const state = await this.adapter.getStateAsync(statePath);
|
|
230
229
|
|
|
231
|
-
if (
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
if (yearStartDate > now) {
|
|
248
|
-
yearStartDate.setFullYear(now.getFullYear() - 1);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
230
|
+
if (role === 'lastYearStart') {
|
|
231
|
+
// Calculate expected yearStart based on contract
|
|
232
|
+
const contractStart = calculator.parseGermanDate(config.contractStart);
|
|
233
|
+
let expectedYearStart;
|
|
234
|
+
|
|
235
|
+
if (contractStart && !isNaN(contractStart.getTime())) {
|
|
236
|
+
const now = new Date();
|
|
237
|
+
expectedYearStart = new Date(
|
|
238
|
+
now.getFullYear(),
|
|
239
|
+
contractStart.getMonth(),
|
|
240
|
+
contractStart.getDate(),
|
|
241
|
+
12,
|
|
242
|
+
0,
|
|
243
|
+
0,
|
|
244
|
+
);
|
|
251
245
|
|
|
252
|
-
if (
|
|
253
|
-
|
|
246
|
+
if (expectedYearStart > now) {
|
|
247
|
+
expectedYearStart.setFullYear(now.getFullYear() - 1);
|
|
254
248
|
}
|
|
255
|
-
await this.adapter.setStateAsync(statePath, calculator.formatDateString(yearStartDate), true);
|
|
256
|
-
} else if (typeof state?.val === 'number') {
|
|
257
|
-
await this.adapter.setStateAsync(statePath, calculator.formatDateString(new Date(state.val)), true);
|
|
258
|
-
} else {
|
|
259
|
-
await this.adapter.setStateAsync(statePath, nowIso, true);
|
|
260
249
|
}
|
|
250
|
+
|
|
251
|
+
if (!expectedYearStart) {
|
|
252
|
+
expectedYearStart = new Date(new Date().getFullYear(), 0, 1, 12, 0, 0);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Always set to expected value (fixes mismatches from config changes)
|
|
256
|
+
await this.adapter.setStateAsync(statePath, expectedYearStart.getTime(), true);
|
|
257
|
+
} else {
|
|
258
|
+
// For lastDayStart and lastMonthStart
|
|
259
|
+
if (!state || !state.val || typeof state.val === 'string') {
|
|
260
|
+
// Initialize with current timestamp (convert string to number if needed)
|
|
261
|
+
await this.adapter.setStateAsync(statePath, Date.now(), true);
|
|
262
|
+
}
|
|
263
|
+
// If already a valid number, no action needed (already correct in state)
|
|
261
264
|
}
|
|
262
265
|
}
|
|
263
266
|
|
|
@@ -546,84 +549,60 @@ class MultiMeterManager {
|
|
|
546
549
|
await this.adapter.setStateAsync(`${basePath}.costs.monthly`, calculator.roundToDecimals(monthlyCost, 2), true);
|
|
547
550
|
await this.adapter.setStateAsync(`${basePath}.costs.yearly`, calculator.roundToDecimals(yearlyCost, 2), true);
|
|
548
551
|
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
// Calculate annual fee (prorated)
|
|
552
|
+
// Calculate accumulated costs based on contract start
|
|
552
553
|
const yearStartState = await this.adapter.getStateAsync(`${basePath}.statistics.lastYearStart`);
|
|
553
|
-
let
|
|
554
|
+
let monthsSinceYearStart = 1;
|
|
555
|
+
let basicChargeAccumulated = 0;
|
|
554
556
|
|
|
555
557
|
if (yearStartState && yearStartState.val) {
|
|
556
|
-
|
|
557
|
-
|
|
558
|
+
// yearStartState.val is a timestamp (number)
|
|
559
|
+
const yearStartDate = new Date(yearStartState.val);
|
|
560
|
+
if (!isNaN(yearStartDate.getTime())) {
|
|
558
561
|
const now = new Date();
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
562
|
+
|
|
563
|
+
// Calculate months since contract start (started months, including current)
|
|
564
|
+
monthsSinceYearStart = calculator.getMonthsDifference(yearStartDate, now) + 1;
|
|
565
|
+
|
|
566
|
+
// Calculate accumulated basic charge (monthly fee × months)
|
|
567
|
+
basicChargeAccumulated = (config.grundgebuehr || 0) * monthsSinceYearStart;
|
|
564
568
|
}
|
|
565
569
|
}
|
|
566
570
|
|
|
571
|
+
// Jahresgebühr ist ein FIXER Wert pro Jahr (z.B. 60€)
|
|
572
|
+
// NICHT pro-rata nach Monaten/Tagen berechnen!
|
|
573
|
+
const annualFeeAccumulated = config.jahresgebuehr || 0;
|
|
574
|
+
|
|
575
|
+
// Update basicCharge with accumulated value (not just monthly!)
|
|
576
|
+
await this.adapter.setStateAsync(
|
|
577
|
+
`${basePath}.costs.basicCharge`,
|
|
578
|
+
calculator.roundToDecimals(basicChargeAccumulated, 2),
|
|
579
|
+
true,
|
|
580
|
+
);
|
|
581
|
+
|
|
567
582
|
await this.adapter.setStateAsync(
|
|
568
583
|
`${basePath}.costs.annualFee`,
|
|
569
584
|
calculator.roundToDecimals(annualFeeAccumulated, 2),
|
|
570
585
|
true,
|
|
571
586
|
);
|
|
572
587
|
|
|
573
|
-
// Calculate
|
|
574
|
-
|
|
575
|
-
const yearStartDate = calculator.parseDateString(yearStartState.val);
|
|
576
|
-
if (yearStartDate && !isNaN(yearStartDate.getTime())) {
|
|
577
|
-
const now = new Date();
|
|
578
|
-
// Calculate paid total based on started months (not just completed months)
|
|
579
|
-
// If current month has started, count it as paid
|
|
580
|
-
const monthsSinceYearStart = calculator.getMonthsDifference(yearStartDate, now) + 1;
|
|
588
|
+
// Calculate total yearly costs and balance
|
|
589
|
+
const totalYearlyCost = yearlyCost + basicChargeAccumulated + annualFeeAccumulated;
|
|
581
590
|
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
`${basePath}.costs.totalYearly`,
|
|
588
|
-
calculator.roundToDecimals(totalYearlyCost, 2),
|
|
589
|
-
true,
|
|
590
|
-
);
|
|
591
|
+
await this.adapter.setStateAsync(
|
|
592
|
+
`${basePath}.costs.totalYearly`,
|
|
593
|
+
calculator.roundToDecimals(totalYearlyCost, 2),
|
|
594
|
+
true,
|
|
595
|
+
);
|
|
591
596
|
|
|
592
|
-
|
|
593
|
-
|
|
597
|
+
const paidTotal = (config.abschlag || 0) * monthsSinceYearStart;
|
|
598
|
+
const balance = totalYearlyCost - paidTotal;
|
|
594
599
|
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
600
|
+
this.adapter.log.debug(
|
|
601
|
+
`[${basePath}] Balance calculation: grundgebuehr=${config.grundgebuehr}, jahresgebuehr=${config.jahresgebuehr}, abschlag=${config.abschlag}, months=${monthsSinceYearStart}, basicCharge=${basicChargeAccumulated.toFixed(2)}, annualFee=${annualFeeAccumulated.toFixed(2)}, paidTotal=${paidTotal.toFixed(2)}, totalYearly=${totalYearlyCost.toFixed(2)}, balance=${balance.toFixed(2)}`,
|
|
602
|
+
);
|
|
598
603
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
calculator.roundToDecimals(paidTotal, 2),
|
|
602
|
-
true,
|
|
603
|
-
);
|
|
604
|
-
await this.adapter.setStateAsync(
|
|
605
|
-
`${basePath}.costs.balance`,
|
|
606
|
-
calculator.roundToDecimals(balance, 2),
|
|
607
|
-
true,
|
|
608
|
-
);
|
|
609
|
-
} else {
|
|
610
|
-
// Fallback if yearStartDate parsing fails
|
|
611
|
-
const totalYearlyCost = yearlyCost + annualFeeAccumulated;
|
|
612
|
-
await this.adapter.setStateAsync(
|
|
613
|
-
`${basePath}.costs.totalYearly`,
|
|
614
|
-
calculator.roundToDecimals(totalYearlyCost, 2),
|
|
615
|
-
true,
|
|
616
|
-
);
|
|
617
|
-
}
|
|
618
|
-
} else {
|
|
619
|
-
// Fallback if no yearStartState exists
|
|
620
|
-
const totalYearlyCost = yearlyCost + annualFeeAccumulated;
|
|
621
|
-
await this.adapter.setStateAsync(
|
|
622
|
-
`${basePath}.costs.totalYearly`,
|
|
623
|
-
calculator.roundToDecimals(totalYearlyCost, 2),
|
|
624
|
-
true,
|
|
625
|
-
);
|
|
626
|
-
}
|
|
604
|
+
await this.adapter.setStateAsync(`${basePath}.costs.paidTotal`, calculator.roundToDecimals(paidTotal, 2), true);
|
|
605
|
+
await this.adapter.setStateAsync(`${basePath}.costs.balance`, calculator.roundToDecimals(balance, 2), true);
|
|
627
606
|
}
|
|
628
607
|
|
|
629
608
|
/**
|
package/lib/stateManager.js
CHANGED
|
@@ -718,6 +718,37 @@ async function createUtilityStateStructure(adapter, type, _config = {}) {
|
|
|
718
718
|
native: {},
|
|
719
719
|
});
|
|
720
720
|
|
|
721
|
+
// HT/NT lastDay states - only create if HT/NT tariff is enabled
|
|
722
|
+
if (_config[htNtEnabledKey]) {
|
|
723
|
+
await adapter.setObjectNotExistsAsync(`${type}.statistics.lastDayHT`, {
|
|
724
|
+
type: 'state',
|
|
725
|
+
common: {
|
|
726
|
+
name: `Verbrauch gestern HT (${label.unit})`,
|
|
727
|
+
type: 'number',
|
|
728
|
+
role: STATE_ROLES.consumption,
|
|
729
|
+
read: true,
|
|
730
|
+
write: false,
|
|
731
|
+
unit: label.unit,
|
|
732
|
+
def: 0,
|
|
733
|
+
},
|
|
734
|
+
native: {},
|
|
735
|
+
});
|
|
736
|
+
|
|
737
|
+
await adapter.setObjectNotExistsAsync(`${type}.statistics.lastDayNT`, {
|
|
738
|
+
type: 'state',
|
|
739
|
+
common: {
|
|
740
|
+
name: `Verbrauch gestern NT (${label.unit})`,
|
|
741
|
+
type: 'number',
|
|
742
|
+
role: STATE_ROLES.consumption,
|
|
743
|
+
read: true,
|
|
744
|
+
write: false,
|
|
745
|
+
unit: label.unit,
|
|
746
|
+
def: 0,
|
|
747
|
+
},
|
|
748
|
+
native: {},
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
|
|
721
752
|
if (type === 'gas') {
|
|
722
753
|
await adapter.setObjectNotExistsAsync(`${type}.statistics.lastDayVolume`, {
|
|
723
754
|
type: 'state',
|
package/main.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
/*
|
|
4
|
-
* ioBroker
|
|
4
|
+
* ioBroker Utility Monitor Adapter
|
|
5
5
|
* Monitors gas, water, and electricity consumption with cost calculation
|
|
6
6
|
*/
|
|
7
7
|
|
|
@@ -11,14 +11,14 @@ const BillingManager = require('./lib/billingManager');
|
|
|
11
11
|
const MessagingHandler = require('./lib/messagingHandler');
|
|
12
12
|
const MultiMeterManager = require('./lib/multiMeterManager');
|
|
13
13
|
|
|
14
|
-
class
|
|
14
|
+
class UtilityMonitor extends utils.Adapter {
|
|
15
15
|
/**
|
|
16
16
|
* @param {Partial<utils.AdapterOptions>} [options] - Adapter options
|
|
17
17
|
*/
|
|
18
18
|
constructor(options) {
|
|
19
19
|
super({
|
|
20
20
|
...options,
|
|
21
|
-
name: '
|
|
21
|
+
name: 'utility-monitor',
|
|
22
22
|
});
|
|
23
23
|
this.on('ready', this.onReady.bind(this));
|
|
24
24
|
this.on('stateChange', this.onStateChange.bind(this));
|
|
@@ -44,26 +44,12 @@ class NebenkostenMonitor extends utils.Adapter {
|
|
|
44
44
|
this.multiMeterManager = new MultiMeterManager(this, this.consumptionManager, this.billingManager);
|
|
45
45
|
|
|
46
46
|
// Initialize each utility type based on configuration
|
|
47
|
+
// Note: initializeUtility() internally calls multiMeterManager.initializeType()
|
|
47
48
|
await this.initializeUtility('gas', this.config.gasAktiv);
|
|
48
49
|
await this.initializeUtility('water', this.config.wasserAktiv);
|
|
49
50
|
await this.initializeUtility('electricity', this.config.stromAktiv);
|
|
50
|
-
|
|
51
51
|
await this.initializeUtility('pv', this.config.pvAktiv);
|
|
52
52
|
|
|
53
|
-
// Initialize Multi-Meter structures for each active type
|
|
54
|
-
if (this.config.gasAktiv) {
|
|
55
|
-
await this.multiMeterManager.initializeType('gas');
|
|
56
|
-
}
|
|
57
|
-
if (this.config.wasserAktiv) {
|
|
58
|
-
await this.multiMeterManager.initializeType('water');
|
|
59
|
-
}
|
|
60
|
-
if (this.config.stromAktiv) {
|
|
61
|
-
await this.multiMeterManager.initializeType('electricity');
|
|
62
|
-
}
|
|
63
|
-
if (this.config.pvAktiv) {
|
|
64
|
-
await this.multiMeterManager.initializeType('pv');
|
|
65
|
-
}
|
|
66
|
-
|
|
67
53
|
// Initialize General Info States
|
|
68
54
|
await this.setObjectNotExistsAsync('info', {
|
|
69
55
|
type: 'channel',
|
|
@@ -290,8 +276,8 @@ if (require.main !== module) {
|
|
|
290
276
|
/**
|
|
291
277
|
* @param {Partial<utils.AdapterOptions>} [options] - Adapter options
|
|
292
278
|
*/
|
|
293
|
-
module.exports = options => new
|
|
279
|
+
module.exports = options => new UtilityMonitor(options);
|
|
294
280
|
} else {
|
|
295
281
|
// otherwise start the instance directly
|
|
296
|
-
new
|
|
282
|
+
new UtilityMonitor();
|
|
297
283
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.utility-monitor",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.5",
|
|
4
4
|
"description": "Monitor gas, water, and electricity consumption with cost calculation",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "fischi87",
|
|
@@ -39,18 +39,18 @@
|
|
|
39
39
|
"@iobroker/adapter-core": "^3.3.2"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@alcalzone/release-script": "
|
|
43
|
-
"@alcalzone/release-script-plugin-iobroker": "
|
|
44
|
-
"@alcalzone/release-script-plugin-license": "
|
|
45
|
-
"@alcalzone/release-script-plugin-manual-review": "
|
|
46
|
-
"@iobroker/adapter-dev": "
|
|
47
|
-
"@iobroker/dev-server": "
|
|
48
|
-
"@iobroker/eslint-config": "
|
|
49
|
-
"@iobroker/testing": "
|
|
50
|
-
"@tsconfig/node20": "
|
|
51
|
-
"@types/iobroker": "npm:@iobroker/types
|
|
52
|
-
"@types/node": "
|
|
53
|
-
"typescript": "
|
|
42
|
+
"@alcalzone/release-script": "^5.0.0",
|
|
43
|
+
"@alcalzone/release-script-plugin-iobroker": "^4.0.0",
|
|
44
|
+
"@alcalzone/release-script-plugin-license": "^4.0.0",
|
|
45
|
+
"@alcalzone/release-script-plugin-manual-review": "^4.0.0",
|
|
46
|
+
"@iobroker/adapter-dev": "^1.5.0",
|
|
47
|
+
"@iobroker/dev-server": "^0.8.0",
|
|
48
|
+
"@iobroker/eslint-config": "^2.2.0",
|
|
49
|
+
"@iobroker/testing": "^5.2.2",
|
|
50
|
+
"@tsconfig/node20": "^20.1.8",
|
|
51
|
+
"@types/iobroker": "npm:@iobroker/types@^7.1.0",
|
|
52
|
+
"@types/node": "^20.19.27",
|
|
53
|
+
"typescript": "^5.9.3"
|
|
54
54
|
},
|
|
55
55
|
"main": "main.js",
|
|
56
56
|
"files": [
|