iobroker.pv-notifications 1.2.31 → 1.2.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  ![Logo](admin/pv-notifications.png)
4
4
 
5
+ ![Stable](https://iobroker.live/badges/pv-notifications-stable.svg)
6
+ [![NPM version](https://img.shields.io/npm/v/iobroker.pv-notifications.svg)](https://www.npmjs.com/package/iobroker.pv-notifications)
7
+ [![Downloads](https://img.shields.io/npm/dm/iobroker.pv-notifications.svg)](https://www.npmjs.com/package/iobroker.pv-notifications)
8
+ [![License](https://img.shields.io/github/license/sadam6752-tech/ioBroker.pv-notifications.svg)](LICENSE)
9
+
10
+ [![NPM](https://nodei.co/npm/iobroker.pv-notifications.png?downloads=true)](https://nodei.co/npm/iobroker.pv-notifications/)
11
+
12
+ [![Test and Release](https://github.com/sadam6752-tech/ioBroker.pv-notifications/actions/workflows/test-and-release.yml/badge.svg)](https://github.com/sadam6752-tech/ioBroker.pv-notifications/actions/workflows/test-and-release.yml)
13
+ ![Number of Installations](https://iobroker.live/badges/pv-notifications-installed.svg)
14
+
5
15
  Sends Telegram notifications for PV battery status (full, empty, intermediate levels).
6
16
 
7
17
  ## Features
@@ -314,6 +324,15 @@ sadam6752@gmail.com
314
324
  ### **WORK IN PROGRESS**
315
325
  -->
316
326
 
327
+ ### 1.2.32 (2026-10-08)
328
+ * (FIX) Daily, weekly and monthly statistics (cycles, min/max SOC) are no longer reset on every adapter restart
329
+ * (FIX) Monthly statistics reported the daily cycle counters; there are now real monthly counters (`statistics.fullCyclesMonth`, `statistics.emptyCyclesMonth`)
330
+ * (FIX) Weekly/monthly auto-save no longer fails with an unhandled error when the weekly/monthly data points are empty
331
+ * (FIX) SOC delivered as a string (e.g. "100") now triggers the full/empty/intermediate notifications
332
+ * (FIX) Test message: tomorrow's weather no longer breaks when only text or only temperature is configured
333
+ * (FIX) Weekly/monthly own consumption can no longer be negative
334
+ * (ADD) Unit tests (`npm run test:js`), README badges, `.gitattributes` (LF line endings)
335
+
317
336
  ### 1.2.31 (2026-09-21)
318
337
  * (ADD) CI: Node.js 26 in the test matrix and a new deploy job using npm Trusted Publishing (OIDC) with provenance
319
338
  * (FIX) Added the missing changelog entry for 1.2.30
package/io-package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "pv-notifications",
4
- "version": "1.2.31",
4
+ "version": "1.2.32",
5
5
  "titleLang": {
6
6
  "en": "PV Notifications",
7
7
  "de": "PV-Benachrichtigungen",
@@ -29,6 +29,19 @@
29
29
  "zh-cn": "发送 Telegram 通知用于 PV 电池状态"
30
30
  },
31
31
  "news": {
32
+ "1.2.32": {
33
+ "en": "Fix: daily, weekly and monthly statistics are no longer lost on adapter restart. Fix: monthly statistics now report real monthly cycle counts. Fix: weekly/monthly saving no longer fails with empty data points. Fix: SOC delivered as text is accepted. Fix: test message with partially configured weather. Added unit tests and README badges.",
34
+ "de": "Fix: Tages-, Wochen- und Monatsstatistik gehen beim Neustart des Adapters nicht mehr verloren. Fix: Die Monatsstatistik zeigt jetzt die echten Monatszyklen. Fix: Wochen-/Monatsspeicherung schlaegt bei leeren Datenpunkten nicht mehr fehl. Fix: SOC als Text wird akzeptiert. Fix: Testnachricht bei teilweise konfiguriertem Wetter. Unit-Tests und README-Badges hinzugefuegt.",
35
+ "ru": "Исправлено: дневная, недельная и месячная статистика больше не теряется при перезапуске адаптера. Исправлено: месячная статистика показывает реальное число месячных циклов. Исправлено: сохранение недельных/месячных данных больше не падает при пустых точках данных. Исправлено: SOC в виде текста принимается. Исправлено: тестовое сообщение при частично настроенной погоде. Добавлены юнит-тесты и бейджи в README.",
36
+ "fr": "Correction : les statistiques journalieres, hebdomadaires et mensuelles ne sont plus perdues au redemarrage de l'adaptateur. Correction : les statistiques mensuelles indiquent les vrais cycles mensuels. Correction : l'enregistrement hebdomadaire/mensuel n'echoue plus avec des points de donnees vides. Correction : SOC fourni en texte accepte. Correction : message de test avec meteo partiellement configuree. Tests unitaires et badges README ajoutes.",
37
+ "it": "Correzione: le statistiche giornaliere, settimanali e mensili non vengono piu perse al riavvio dell'adattatore. Correzione: le statistiche mensili mostrano i veri cicli mensili. Correzione: il salvataggio settimanale/mensile non fallisce piu con punti dati vuoti. Correzione: SOC fornito come testo accettato. Correzione: messaggio di test con meteo configurato parzialmente. Aggiunti test unitari e badge README.",
38
+ "es": "Correccion: las estadisticas diarias, semanales y mensuales ya no se pierden al reiniciar el adaptador. Correccion: las estadisticas mensuales muestran los ciclos mensuales reales. Correccion: el guardado semanal/mensual ya no falla con puntos de datos vacios. Correccion: se acepta SOC entregado como texto. Correccion: mensaje de prueba con clima configurado parcialmente. Anadidas pruebas unitarias e insignias en README.",
39
+ "pl": "Poprawka: statystyki dzienne, tygodniowe i miesieczne nie sa juz tracone po restarcie adaptera. Poprawka: statystyki miesieczne pokazuja prawdziwe cykle miesieczne. Poprawka: zapis tygodniowy/miesieczny nie konczy sie juz bledem przy pustych punktach danych. Poprawka: SOC dostarczony jako tekst jest akceptowany. Poprawka: wiadomosc testowa przy czesciowo skonfigurowanej pogodzie. Dodano testy jednostkowe i odznaki w README.",
40
+ "pt": "Correcao: as estatisticas diarias, semanais e mensais ja nao se perdem ao reiniciar o adaptador. Correcao: as estatisticas mensais mostram os ciclos mensais reais. Correcao: a gravacao semanal/mensal ja nao falha com pontos de dados vazios. Correcao: SOC entregue como texto e aceite. Correcao: mensagem de teste com meteorologia parcialmente configurada. Adicionados testes unitarios e emblemas no README.",
41
+ "nl": "Fix: dag-, week- en maandstatistieken gaan niet meer verloren bij het herstarten van de adapter. Fix: maandstatistieken tonen de echte maandcycli. Fix: week-/maandopslag mislukt niet meer bij lege datapunten. Fix: SOC als tekst wordt geaccepteerd. Fix: testbericht bij gedeeltelijk geconfigureerd weer. Unit-tests en README-badges toegevoegd.",
42
+ "uk": "Виправлено: денна, тижнева та місячна статистика більше не втрачається під час перезапуску адаптера. Виправлено: місячна статистика показує реальну кількість місячних циклів. Виправлено: збереження тижневих/місячних даних більше не падає з порожніми точками даних. Виправлено: SOC у вигляді тексту приймається. Виправлено: тестове повідомлення при частково налаштованій погоді. Додано модульні тести та бейджі в README.",
43
+ "zh-cn": "修复:适配器重启后日、周、月统计数据不再丢失。修复:月统计现在显示真实的月循环次数。修复:数据点为空时每周/每月保存不再失败。修复:接受文本形式的SOC。修复:天气部分配置时的测试消息。新增单元测试和README徽章。"
44
+ },
32
45
  "1.2.31": {
33
46
  "en": "CI: Node.js 26 added to the test matrix and a new deploy job using npm Trusted Publishing (OIDC) with provenance. Added the missing changelog entry for 1.2.30 and completed the short 1.2.29 news translations. Dependencies: @iobroker/testing 6.2.x, @alcalzone/release-script-plugin-license 5.2.2.",
34
47
  "de": "CI: Node.js 26 in die Test-Matrix aufgenommen und neuer Deploy-Job mit npm Trusted Publishing (OIDC) samt Provenance. Fehlender Changelog-Eintrag fuer 1.2.30 ergaenzt und zu kurze 1.2.29-News-Uebersetzungen vervollstaendigt. Abhaengigkeiten: @iobroker/testing 6.2.x, @alcalzone/release-script-plugin-license 5.2.2.",
@@ -106,19 +119,6 @@
106
119
  "nl": "W5604: ontbrekende i18n-sleutels voor zonsondergang-statistieken in 8 talen toegevoegd; oud changelog verplaatst naar CHANGELOG_OLD.md; README-structuur gecorrigeerd",
107
120
  "uk": "W5604: додано відсутні i18n ключі для статистики заходу сонця у 8 мовах; старий changelog перенесено до CHANGELOG_OLD.md; виправлено структуру README",
108
121
  "zh-cn": "修复W5604:在8种语言中添加日落统计缺失的i18n键;将旧changelog移至CHANGELOG_OLD.md;修复README结构"
109
- },
110
- "1.2.25": {
111
- "en": "Fix W5604: add missing weather i18n keys in 8 languages; update engines.node to >=22; fix workflow node versions; update devDependencies; add tsconfig.json, prettier.config.mjs",
112
- "de": "W5604 behoben: fehlende Wetter-i18n-Schlüssel in 8 Sprachen ergänzt; engines.node auf >=22 aktualisiert; Workflow-Node-Versionen korrigiert; devDependencies aktualisiert; tsconfig.json, prettier.config.mjs hinzugefügt",
113
- "ru": "Исправление W5604: добавлены отсутствующие weather i18n ключи в 8 языках; engines.node обновлён до >=22; исправлены версии node в workflow; обновлены devDependencies; добавлены tsconfig.json, prettier.config.mjs",
114
- "fr": "Fix W5604: clés i18n météo manquantes ajoutées dans 8 langues; engines.node mis à jour à >=22; versions node workflow corrigées; devDependencies mis à jour; tsconfig.json, prettier.config.mjs ajoutés",
115
- "it": "Fix W5604: chiavi i18n meteo mancanti aggiunte in 8 lingue; engines.node aggiornato a >=22; versioni node workflow corrette; devDependencies aggiornati; tsconfig.json, prettier.config.mjs aggiunti",
116
- "es": "Fix W5604: claves i18n clima faltantes añadidas en 8 idiomas; engines.node actualizado a >=22; versiones node workflow corregidas; devDependencies actualizados; tsconfig.json, prettier.config.mjs añadidos",
117
- "pl": "Naprawa W5604: dodano brakujące klucze i18n pogody w 8 językach; engines.node zaktualizowano do >=22; poprawiono wersje node w workflow; zaktualizowano devDependencies; dodano tsconfig.json, prettier.config.mjs",
118
- "pt": "Fix W5604: chaves i18n meteorologia em falta adicionadas em 8 idiomas; engines.node atualizado para >=22; versões node workflow corrigidas; devDependencies atualizados; tsconfig.json, prettier.config.mjs adicionados",
119
- "nl": "Fix W5604: ontbrekende weer-i18n-sleutels in 8 talen toegevoegd; engines.node bijgewerkt naar >=22; node-versies workflow gecorrigeerd; devDependencies bijgewerkt; tsconfig.json, prettier.config.mjs toegevoegd",
120
- "uk": "Виправлення W5604: додано відсутні weather i18n ключі у 8 мовах; engines.node оновлено до >=22; виправлено версії node у workflow; оновлено devDependencies; додано tsconfig.json, prettier.config.mjs",
121
- "zh-cn": "修复W5604:在8种语言中添加缺失的weather i18n键;将engines.node更新为>=22;修复workflow中的node版本;更新devDependencies;添加tsconfig.json、prettier.config.mjs"
122
122
  }
123
123
  },
124
124
  "authors": [
package/main.js CHANGED
@@ -42,6 +42,8 @@ class PvNotifications extends utils.Adapter {
42
42
  minSOC: 100,
43
43
  weekFullCycles: 0,
44
44
  weekEmptyCycles: 0,
45
+ monthFullCycles: 0,
46
+ monthEmptyCycles: 0,
45
47
  lastStatsReset: new Date().getDate(),
46
48
  lastWeekReset: new Date().getDay(),
47
49
  lastMonthReset: 0,
@@ -155,6 +157,32 @@ class PvNotifications extends utils.Adapter {
155
157
  type: 'state',
156
158
  common: { name: 'Empty cycles this week', type: 'number', role: 'value', read: true, write: false, def: 0 },
157
159
  });
160
+ await this.setObjectNotExists('statistics.fullCyclesMonth', {
161
+ type: 'state',
162
+ common: { name: 'Full cycles this month', type: 'number', role: 'value', read: true, write: false, def: 0 },
163
+ });
164
+ await this.setObjectNotExists('statistics.emptyCyclesMonth', {
165
+ type: 'state',
166
+ common: {
167
+ name: 'Empty cycles this month',
168
+ type: 'number',
169
+ role: 'value',
170
+ read: true,
171
+ write: false,
172
+ def: 0,
173
+ },
174
+ });
175
+ await this.setObjectNotExists('statistics.lastStatsReset', {
176
+ type: 'state',
177
+ common: {
178
+ name: 'Day of last daily reset',
179
+ type: 'number',
180
+ role: 'value',
181
+ read: true,
182
+ write: false,
183
+ def: 0,
184
+ },
185
+ });
158
186
  await this.extendObject('statistics.currentSOC', {
159
187
  type: 'state',
160
188
  common: {
@@ -516,8 +544,27 @@ class PvNotifications extends utils.Adapter {
516
544
  try {
517
545
  const today = new Date().getDate();
518
546
  const lastReset = await this.getStateAsync('statistics.lastStatsReset');
519
-
520
- if (!lastReset || lastReset.val !== today) {
547
+ const num = async id => {
548
+ const st = await this.getStateAsync(id);
549
+ return st && typeof st.val === 'number' ? st.val : 0;
550
+ };
551
+
552
+ // Week/month counters survive restarts
553
+ this.stats.weekFullCycles = await num('statistics.fullCyclesWeek');
554
+ this.stats.weekEmptyCycles = await num('statistics.emptyCyclesWeek');
555
+ this.stats.monthFullCycles = await num('statistics.fullCyclesMonth');
556
+ this.stats.monthEmptyCycles = await num('statistics.emptyCyclesMonth');
557
+
558
+ if (lastReset && lastReset.val === today) {
559
+ // Same day - restore daily values (a restart must not wipe them)
560
+ this.stats.fullCycles = await num('statistics.fullCyclesToday');
561
+ this.stats.emptyCycles = await num('statistics.emptyCyclesToday');
562
+ const max = await this.getStateAsync('statistics.maxSOCToday');
563
+ const min = await this.getStateAsync('statistics.minSOCToday');
564
+ this.stats.maxSOC = max && typeof max.val === 'number' ? max.val : 0;
565
+ this.stats.minSOC = min && typeof min.val === 'number' ? min.val : 100;
566
+ this.stats.lastStatsReset = today;
567
+ } else {
521
568
  // New day - reset statistics
522
569
  this.stats.fullCycles = 0;
523
570
  this.stats.emptyCycles = 0;
@@ -586,7 +633,7 @@ class PvNotifications extends utils.Adapter {
586
633
  const socState = await this.getForeignStateAsync(this.config.batterySOC);
587
634
  if (socState && socState.val !== null) {
588
635
  this.log.debug(`SOC read: ${socState.val}%`);
589
- this.onBatterySOCChange(socState.val);
636
+ await this.onBatterySOCChange(socState.val);
590
637
  } else {
591
638
  this.log.warn('SOC state is null or undefined');
592
639
  this.log.warn(`Please check: Does "${this.config.batterySOC}" exist in Objects?`);
@@ -617,6 +664,25 @@ class PvNotifications extends utils.Adapter {
617
664
  }
618
665
  }
619
666
 
667
+ /**
668
+ * Read a numeric foreign state; returns 0 for empty id, missing state or read error
669
+ *
670
+ * @param {string} id - Foreign state ID (may be empty)
671
+ */
672
+ async readForeignNumber(id) {
673
+ if (!id) {
674
+ return 0;
675
+ }
676
+ try {
677
+ const state = await this.getForeignStateAsync(id);
678
+ const val = state ? Number(state.val) : NaN;
679
+ return state && state.val !== null && !isNaN(val) ? val : 0;
680
+ } catch (e) {
681
+ this.log.warn(`Could not read "${id}": ${e.message}`);
682
+ return 0;
683
+ }
684
+ }
685
+
620
686
  /**
621
687
  * Save statistics to states
622
688
  */
@@ -628,6 +694,9 @@ class PvNotifications extends utils.Adapter {
628
694
  await this.setStateAsync('statistics.minSOCToday', this.stats.minSOC, true);
629
695
  await this.setStateAsync('statistics.fullCyclesWeek', this.stats.weekFullCycles, true);
630
696
  await this.setStateAsync('statistics.emptyCyclesWeek', this.stats.weekEmptyCycles, true);
697
+ await this.setStateAsync('statistics.fullCyclesMonth', this.stats.monthFullCycles, true);
698
+ await this.setStateAsync('statistics.emptyCyclesMonth', this.stats.monthEmptyCycles, true);
699
+ await this.setStateAsync('statistics.lastStatsReset', this.stats.lastStatsReset, true);
631
700
 
632
701
  // Save last month/week data
633
702
  await this.setStateAsync('statistics.lastMonthProduction', this.stats.lastMonthProduction, true);
@@ -713,10 +782,12 @@ class PvNotifications extends utils.Adapter {
713
782
  */
714
783
  async onBatterySOCChange(soc) {
715
784
  // Check for undefined/null values
716
- if (soc === null || soc === undefined || isNaN(soc)) {
785
+ if (soc === null || soc === undefined || soc === '' || isNaN(soc)) {
717
786
  this.log.warn(`Invalid SOC value received: ${soc}`);
718
787
  return;
719
788
  }
789
+ // Some adapters deliver the SOC as string - strict comparisons below need a number
790
+ soc = Number(soc);
720
791
 
721
792
  // Update current states
722
793
  await this.setStateAsync('statistics.currentSOC', soc, true);
@@ -765,6 +836,7 @@ class PvNotifications extends utils.Adapter {
765
836
  this.status.lastNotification.full = Date.now();
766
837
  this.stats.fullCycles++;
767
838
  this.stats.weekFullCycles++;
839
+ this.stats.monthFullCycles++;
768
840
  this.saveStatistics();
769
841
  this.log.info('Battery full - Telegram sent');
770
842
  } else if (this.status.full && !this.canNotify('full')) {
@@ -794,6 +866,7 @@ class PvNotifications extends utils.Adapter {
794
866
  this.status.lastNotification.empty = Date.now();
795
867
  this.stats.emptyCycles++;
796
868
  this.stats.weekEmptyCycles++;
869
+ this.stats.monthEmptyCycles++;
797
870
  this.saveStatistics();
798
871
  this.log.info('Battery empty - Telegram sent');
799
872
  } else if (blockedByQuietTime) {
@@ -839,8 +912,8 @@ class PvNotifications extends utils.Adapter {
839
912
  }
840
913
  }
841
914
  }
842
- } else if (nightModeActive) {
843
- this.log.debug('Night time (00:00-08:00) - intermediate notifications suppressed');
915
+ } else {
916
+ this.log.debug('Night/quiet time - intermediate notifications suppressed');
844
917
  }
845
918
  }
846
919
 
@@ -1469,7 +1542,7 @@ ${statusText}
1469
1542
  // const consumption = this.round(this.stats.lastWeekConsumption, 1); // ESLint: unused
1470
1543
  const feedIn = this.round(Math.abs(this.stats.lastWeekFeedIn), 1);
1471
1544
  const gridPower = this.round(this.stats.lastWeekGridPower, 1);
1472
- const selfConsumption = this.round(totalProd - feedIn, 1);
1545
+ const selfConsumption = this.round(Math.max(0, totalProd - feedIn), 1);
1473
1546
  const selfConsumptionRate = totalProd > 0 ? this.round((selfConsumption / totalProd) * 100, 1) : 0;
1474
1547
 
1475
1548
  return `📊 *${this.translate('Weekly statistics PV system')}*
@@ -1494,7 +1567,7 @@ ${statusText}
1494
1567
  // const consumption = this.round(this.stats.lastMonthConsumption, 1); // ESLint: unused
1495
1568
  const feedIn = this.round(Math.abs(this.stats.lastMonthFeedIn), 1);
1496
1569
  const gridPower = this.round(this.stats.lastMonthGridPower, 1);
1497
- const selfConsumption = this.round(totalProd - feedIn, 1);
1570
+ const selfConsumption = this.round(Math.max(0, totalProd - feedIn), 1);
1498
1571
  const selfConsumptionRate = totalProd > 0 ? this.round((selfConsumption / totalProd) * 100, 1) : 0;
1499
1572
 
1500
1573
  return `📊 *${this.translate('Monthly statistics PV system')}*
@@ -1620,8 +1693,8 @@ ${statusText}
1620
1693
  // Alle 5 Minuten: Statistik prüfen (um :00, :05, :10, ...)
1621
1694
  if (minutes % 5 === 0) {
1622
1695
  this.resetDailyStats();
1623
- this.resetWeeklyStats();
1624
- this.resetMonthlyStats();
1696
+ this.resetWeeklyStats().catch(e => this.log.error(`Weekly reset failed: ${e.message}`));
1697
+ this.resetMonthlyStats().catch(e => this.log.error(`Monthly reset failed: ${e.message}`));
1625
1698
  }
1626
1699
 
1627
1700
  // Tägliche Statistik — entweder zur konfigurierten Zeit oder zum Sonnenuntergang
@@ -1710,16 +1783,10 @@ ${statusText}
1710
1783
  // Aktuelle Daten aus externen States lesen (direkter Zugriff)
1711
1784
  // WICHTIG: weeklyProduction/weeklyConsumption/etc. verwenden (sourceanalytix Wochenwerte)
1712
1785
  // NICHT totalProduction/consumption/etc. (das sind Tageswerte!)
1713
- const weeklyProd = await this.getForeignStateAsync(this.config.weeklyProduction);
1714
- const weeklyConsumption = await this.getForeignStateAsync(this.config.weeklyConsumption);
1715
- const weeklyFeedIn = await this.getForeignStateAsync(this.config.weeklyFeedIn);
1716
- const weeklyGridPower = await this.getForeignStateAsync(this.config.weeklyGridPower);
1717
-
1718
- this.stats.lastWeekProduction = weeklyProd && weeklyProd.val !== null ? weeklyProd.val : 0;
1719
- this.stats.lastWeekConsumption =
1720
- weeklyConsumption && weeklyConsumption.val !== null ? weeklyConsumption.val : 0;
1721
- this.stats.lastWeekFeedIn = weeklyFeedIn && weeklyFeedIn.val !== null ? weeklyFeedIn.val : 0;
1722
- this.stats.lastWeekGridPower = weeklyGridPower && weeklyGridPower.val !== null ? weeklyGridPower.val : 0;
1786
+ this.stats.lastWeekProduction = await this.readForeignNumber(this.config.weeklyProduction);
1787
+ this.stats.lastWeekConsumption = await this.readForeignNumber(this.config.weeklyConsumption);
1788
+ this.stats.lastWeekFeedIn = await this.readForeignNumber(this.config.weeklyFeedIn);
1789
+ this.stats.lastWeekGridPower = await this.readForeignNumber(this.config.weeklyGridPower);
1723
1790
  this.stats.lastWeekFullCycles = this.stats.weekFullCycles;
1724
1791
  this.stats.lastWeekEmptyCycles = this.stats.weekEmptyCycles;
1725
1792
 
@@ -1759,17 +1826,15 @@ ${statusText}
1759
1826
  );
1760
1827
 
1761
1828
  // Aktuelle Daten aus externen States lesen (direkter Zugriff)
1762
- const totalProd = await this.getForeignStateAsync(this.config.monthlyProduction);
1763
- const consumption = await this.getForeignStateAsync(this.config.monthlyConsumption);
1764
- const feedIn = await this.getForeignStateAsync(this.config.monthlyFeedIn);
1765
- const gridPower = await this.getForeignStateAsync(this.config.monthlyGridPower);
1766
-
1767
- this.stats.lastMonthProduction = totalProd && totalProd.val !== null ? totalProd.val : 0;
1768
- this.stats.lastMonthConsumption = consumption && consumption.val !== null ? consumption.val : 0;
1769
- this.stats.lastMonthFeedIn = feedIn && feedIn.val !== null ? feedIn.val : 0;
1770
- this.stats.lastMonthGridPower = gridPower && gridPower.val !== null ? gridPower.val : 0;
1771
- this.stats.lastMonthFullCycles = this.stats.fullCycles;
1772
- this.stats.lastMonthEmptyCycles = this.stats.emptyCycles;
1829
+ this.stats.lastMonthProduction = await this.readForeignNumber(this.config.monthlyProduction);
1830
+ this.stats.lastMonthConsumption = await this.readForeignNumber(this.config.monthlyConsumption);
1831
+ this.stats.lastMonthFeedIn = await this.readForeignNumber(this.config.monthlyFeedIn);
1832
+ this.stats.lastMonthGridPower = await this.readForeignNumber(this.config.monthlyGridPower);
1833
+ // Monthly cycle counters (previously the daily counters were stored by mistake)
1834
+ this.stats.lastMonthFullCycles = this.stats.monthFullCycles;
1835
+ this.stats.lastMonthEmptyCycles = this.stats.monthEmptyCycles;
1836
+ this.stats.monthFullCycles = 0;
1837
+ this.stats.monthEmptyCycles = 0;
1773
1838
 
1774
1839
  this.stats.lastMonthReset = today;
1775
1840
  this.saveStatistics();
@@ -2065,8 +2130,12 @@ ${statusText}
2065
2130
 
2066
2131
  // Wetter morgen
2067
2132
  if (this.config.weatherTomorrowText || this.config.weatherTomorrowTemp) {
2068
- const weatherTomorrowTextState = await this.getForeignStateAsync(this.config.weatherTomorrowText);
2069
- const weatherTomorrowState = await this.getForeignStateAsync(this.config.weatherTomorrowTemp);
2133
+ const weatherTomorrowTextState = this.config.weatherTomorrowText
2134
+ ? await this.getForeignStateAsync(this.config.weatherTomorrowText)
2135
+ : null;
2136
+ const weatherTomorrowState = this.config.weatherTomorrowTemp
2137
+ ? await this.getForeignStateAsync(this.config.weatherTomorrowTemp)
2138
+ : null;
2070
2139
 
2071
2140
  const weatherTomorrowText =
2072
2141
  weatherTomorrowTextState && weatherTomorrowTextState.val !== null
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.pv-notifications",
3
- "version": "1.2.31",
3
+ "version": "1.2.32",
4
4
  "description": "PV-Anlage Batterie-Status Telegram Benachrichtigungen",
5
5
  "author": {
6
6
  "name": "Alex1808 via LLM: Qwen",