iobroker.laundrylens 0.4.22 → 0.4.23

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
@@ -132,6 +132,9 @@ This also works inside the conditional `[...]` blocks: `[🌡️ Outside: {state
132
132
 
133
133
  ### **WORK IN PROGRESS**
134
134
 
135
+ ### 0.4.23 (2026-09-16)
136
+ - Fix: a cycle interrupted by an ioBroker restart while the device's power had already returned to idle was silently orphaned - the on-startup restore logic only handled the case where power was still high at restart, so the manager just reinitialized to "off" without ever properly finishing the interrupted cycle, leaving it stuck showing "running" with stale pre-restart values forever. Combined with the `offDelayMin` fix in 0.4.22, this should resolve "cycle never ends" reports after a mid/post-cycle adapter restart
137
+
135
138
  ### 0.4.22 (2026-09-16)
136
139
  - Fix: the per-device "Off delay" setting (`offDelayMin`) was silently ignored - `CycleDetector`'s config merge never translated it into the field the detector actually uses (`offDelay`, in seconds), so every device always used a hardcoded 5-minute default regardless of what was configured. Found via a real trace where a cycle stayed stuck as "running" long after power had genuinely dropped to ~0W. Note: this alone doesn't fully explain very long stalls (well over an hour) - if a cycle still gets stuck after this fix, please share the adapter log from around that time
137
140
 
package/io-package.json CHANGED
@@ -1,8 +1,21 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "laundrylens",
4
- "version": "0.4.22",
4
+ "version": "0.4.23",
5
5
  "news": {
6
+ "0.4.23": {
7
+ "en": "Fix: a cycle interrupted by an ioBroker restart while the device's power had already returned to idle was silently orphaned - it stayed stuck showing \"running\" (with stale pre-restart values) forever, since the on-startup restore logic only handled the case where power was still high at restart. Combined with the offDelayMin fix in 0.4.22, this should resolve \"cycle never ends\" reports after a mid/post-cycle adapter restart. If a cycle still gets stuck after this, please share the adapter log so any remaining cause can be found.",
8
+ "de": "Fix: Ein Zyklus, der durch einen ioBroker-Neustart unterbrochen wurde, während die Leistung des Geräts bereits wieder im Leerlauf war, wurde stillschweigend vergessen - er blieb für immer als „läuft\" hängen (mit veralteten Werten von vor dem Neustart), da die Wiederherstellungs-Logik beim Start nur den Fall behandelte, dass die Leistung beim Neustart noch hoch war. Zusammen mit dem offDelayMin-Fix aus 0.4.22 sollte das Meldungen von „Zyklus endet nie\" nach einem Adapter-Neustart mitten im oder nach einem Zyklus beheben. Falls ein Zyklus danach weiterhin hängen bleibt, bitte das Adapter-Log teilen.",
9
+ "ru": "Исправление: цикл, прерванный перезапуском ioBroker в момент, когда мощность устройства уже вернулась к простою, незаметно забывался - он навсегда оставался в состоянии «работает» (с устаревшими значениями до перезапуска), поскольку логика восстановления при запуске обрабатывала только случай, когда мощность при перезапуске всё ещё была высокой. В сочетании с исправлением offDelayMin из 0.4.22 это должно устранить сообщения о том, что «цикл никогда не завершается» после перезапуска адаптера.",
10
+ "pt": "Correção: um ciclo interrompido por uma reinicialização do ioBroker enquanto a energia do dispositivo já havia voltado ao repouso era silenciosamente esquecido - ficava preso mostrando \"em execução\" para sempre (com valores desatualizados de antes da reinicialização), já que a lógica de restauração na inicialização só tratava o caso em que a energia ainda estava alta na reinicialização. Combinado com a correção do offDelayMin na 0.4.22, isso deve resolver relatos de \"ciclo nunca termina\" após uma reinicialização do adaptador.",
11
+ "nl": "Fix: een cyclus die werd onderbroken door een herstart van ioBroker terwijl het vermogen van het apparaat al was teruggekeerd naar inactief, werd stilzwijgend vergeten - deze bleef voor altijd \"actief\" tonen (met verouderde waarden van vóór de herstart), omdat de herstellogica bij het opstarten alleen het geval afhandelde waarin het vermogen bij herstart nog hoog was. Samen met de offDelayMin-fix in 0.4.22 zou dit meldingen van \"cyclus eindigt nooit\" na een herstart van de adapter moeten oplossen.",
12
+ "fr": "Correction : un cycle interrompu par un redémarrage d'ioBroker alors que la puissance de l'appareil était déjà revenue au repos était silencieusement oublié - il restait bloqué indéfiniment sur « en cours » (avec des valeurs obsolètes d'avant le redémarrage), car la logique de restauration au démarrage ne traitait que le cas où la puissance était encore élevée au redémarrage. Combiné à la correction d'offDelayMin dans la 0.4.22, cela devrait résoudre les rapports de « cycle qui ne se termine jamais » après un redémarrage de l'adaptateur.",
13
+ "it": "Correzione: un ciclo interrotto da un riavvio di ioBroker mentre la potenza del dispositivo era già tornata inattiva veniva silenziosamente dimenticato - rimaneva bloccato mostrando \"in esecuzione\" per sempre (con valori obsoleti precedenti al riavvio), poiché la logica di ripristino all'avvio gestiva solo il caso in cui la potenza fosse ancora alta al riavvio. Combinato con la correzione di offDelayMin nella 0.4.22, questo dovrebbe risolvere le segnalazioni di \"il ciclo non termina mai\" dopo un riavvio dell'adattatore.",
14
+ "es": "Corrección: un ciclo interrumpido por un reinicio de ioBroker mientras la energía del dispositivo ya había vuelto al reposo se olvidaba silenciosamente - se quedaba atascado mostrando \"en ejecución\" para siempre (con valores obsoletos previos al reinicio), ya que la lógica de restauración al inicio solo manejaba el caso en que la energía seguía alta en el reinicio. Combinado con la corrección de offDelayMin en la 0.4.22, esto debería resolver los informes de \"el ciclo nunca termina\" tras un reinicio del adaptador.",
15
+ "pl": "Poprawka: cykl przerwany przez ponowne uruchomienie ioBroker, gdy moc urządzenia już wróciła do stanu bezczynności, był po cichu zapominany - pozostawał na zawsze zablokowany, pokazując \"działa\" (z nieaktualnymi wartościami sprzed ponownego uruchomienia), ponieważ logika przywracania przy starcie obsługiwała tylko przypadek, gdy moc była nadal wysoka przy restarcie. W połączeniu z poprawką offDelayMin w 0.4.22 powinno to rozwiązać zgłoszenia \"cykl nigdy się nie kończy\" po ponownym uruchomieniu adaptera.",
16
+ "uk": "Виправлення: цикл, перерваний перезапуском ioBroker, коли потужність пристрою вже повернулася до простою, непомітно забувався - він назавжди залишався у стані \"працює\" (із застарілими значеннями до перезапуску), оскільки логіка відновлення під час запуску обробляла лише випадок, коли потужність усе ще була високою під час перезапуску. У поєднанні з виправленням offDelayMin у 0.4.22 це має вирішити повідомлення про те, що \"цикл ніколи не завершується\" після перезапуску адаптера.",
17
+ "zh-cn": "修复:当设备功率已恢复到空闲状态时,因 ioBroker 重启而中断的周期会被静默遗忘——它会永远卡在\"运行中\"状态(显示重启前的过期数值),因为启动时的恢复逻辑此前只处理了重启时功率仍然较高的情况。结合 0.4.22 中的 offDelayMin 修复,这应该能解决适配器重启后\"周期永不结束\"的问题。"
18
+ },
6
19
  "0.4.22": {
7
20
  "en": "Fix: the per-device \"Off delay\" setting (offDelayMin) was silently ignored - CycleDetector's config merge never translated it into the field the detector actually uses (offDelay, in seconds), so every device always used a hardcoded 5-minute default regardless of what was configured. Found via a real trace where a cycle stayed stuck as \"running\" long after power had genuinely dropped to ~0W. Note: this alone doesn't fully explain very long stalls (well over an hour) - if a cycle still gets stuck after this fix, please share the adapter log from around that time so the remaining cause can be tracked down.",
8
21
  "de": "Fix: Die Geräte-Einstellung „Off delay\" (offDelayMin) wurde stillschweigend ignoriert - beim Zusammenführen der Konfiguration im CycleDetector wurde sie nie in das tatsächlich verwendete Feld (offDelay, in Sekunden) übersetzt, wodurch jedes Gerät unabhängig von der Einstellung immer den fest codierten 5-Minuten-Standard genutzt hat. Gefunden über eine reale Aufzeichnung, bei der ein Zyklus lange als „läuft\" hängen blieb, obwohl die Leistung längst auf ~0W gefallen war. Hinweis: Das allein erklärt sehr lange Aussetzer (deutlich über eine Stunde) nicht vollständig - falls ein Zyklus nach diesem Fix weiterhin hängen bleibt, bitte das Adapter-Log aus diesem Zeitraum teilen, damit die verbleibende Ursache gefunden werden kann.",
@@ -80,19 +93,6 @@
80
93
  "pl": "Nowość: trzy zlokalizowane, gotowe do wyświetlenia punkty danych - phaseText, stateText, programText - oprócz istniejących niezależnych od języka (phase/state/program). Przydatne do pokazywania statusu bezpośrednio w panelu VIS bez tworzenia własnej tabeli tłumaczeń. Domyślnie język systemowy ioBroker, można nadpisać dla każdego urządzenia nowym ustawieniem \"Język wyświetlania\".",
81
94
  "uk": "Новинка: три локалізовані, готові до показу точки даних - phaseText, stateText, programText - на додаток до наявних незалежних від мови (phase/state/program). Корисно для показу статусу прямо на панелі VIS без створення власної таблиці перекладів. Мова за замовчуванням - системна мова ioBroker, можна перевизначити для кожного пристрою новим налаштуванням «Мова відображення».",
82
95
  "zh-cn": "新功能:新增三个本地化、可直接显示的数据点——phaseText、stateText、programText——与现有的语言无关数据点(phase/state/program)并存。便于在 VIS 仪表盘中直接显示状态,无需自建翻译表。语言默认使用 ioBroker 系统语言,可通过新增的\"显示语言\"设置按设备覆盖。"
83
- },
84
- "0.4.16": {
85
- "en": "New: notification message templates now support a `{state:objectId}` placeholder that resolves any ioBroker data point's current value at send time (e.g. outside temperature, electricity price) - on top of the existing built-in placeholders. Works inside conditional `[...]` blocks too: a block hides itself if the referenced data point is empty. Also fixed a leftover German word (\"Fertig\") in the notification subject line.",
86
- "de": "Neu: Benachrichtigungs-Vorlagen unterstützen jetzt einen `{state:objectId}`-Platzhalter, der den aktuellen Wert eines beliebigen ioBroker-Datenpunkts beim Versenden einsetzt (z.B. Außentemperatur, Strompreis) - zusätzlich zu den bisherigen fest eingebauten Platzhaltern. Funktioniert auch innerhalb der `[...]`-Bedingungsblöcke: Ein Block verschwindet, wenn der referenzierte Datenpunkt leer ist. Außerdem ein übrig gebliebenes deutsches Wort (\"Fertig\") in der Benachrichtigungs-Betreffzeile behoben.",
87
- "ru": "Новое: шаблоны уведомлений теперь поддерживают плейсхолдер `{state:objectId}`, который при отправке подставляет текущее значение любой точки данных ioBroker (например, температуру снаружи, цену электричества) - в дополнение к уже существующим встроенным плейсхолдерам. Работает и внутри условных блоков `[...]`: блок скрывается, если указанная точка данных пуста. Также исправлено оставшееся немецкое слово («Fertig») в теме уведомления.",
88
- "pt": "Novo: os modelos de mensagem de notificação agora suportam um placeholder `{state:objectId}` que resolve o valor atual de qualquer ponto de dados do ioBroker no momento do envio (por exemplo, temperatura externa, preço da eletricidade) - além dos placeholders integrados existentes. Também funciona dentro de blocos condicionais `[...]`: um bloco se oculta se o ponto de dados referenciado estiver vazio. Também corrigida uma palavra alemã remanescente (\"Fertig\") na linha de assunto da notificação.",
89
- "nl": "Nieuw: meldingssjablonen ondersteunen nu een `{state:objectId}`-plaatshouder die de actuele waarde van elk ioBroker-datapunt oplost op het moment van verzenden (bijv. buitentemperatuur, stroomprijs) - naast de bestaande ingebouwde plaatshouders. Werkt ook binnen voorwaardelijke `[...]`-blokken: een blok verbergt zichzelf als het gerefereerde datapunt leeg is. Ook een overgebleven Duits woord (\"Fertig\") in de meldingsonderwerpregel opgelost.",
90
- "fr": "Nouveau : les modèles de messages de notification prennent désormais en charge un espace réservé `{state:objectId}` qui résout la valeur actuelle de n'importe quel point de données ioBroker au moment de l'envoi (ex. température extérieure, prix de l'électricité) - en plus des espaces réservés intégrés existants. Fonctionne aussi dans les blocs conditionnels `[...]` : un bloc se masque si le point de données référencé est vide. Correction également d'un mot allemand oublié (\"Fertig\") dans la ligne d'objet de la notification.",
91
- "it": "Novità: i modelli dei messaggi di notifica ora supportano un segnaposto `{state:objectId}` che risolve il valore attuale di qualsiasi punto dati ioBroker al momento dell'invio (es. temperatura esterna, prezzo dell'elettricità) - in aggiunta ai segnaposto integrati esistenti. Funziona anche all'interno dei blocchi condizionali `[...]`: un blocco si nasconde se il punto dati referenziato è vuoto. Corretta anche una parola tedesca residua (\"Fertig\") nella riga dell'oggetto della notifica.",
92
- "es": "Novedad: las plantillas de mensajes de notificación ahora admiten un marcador `{state:objectId}` que resuelve el valor actual de cualquier punto de datos de ioBroker en el momento del envío (p. ej. temperatura exterior, precio de la electricidad) - además de los marcadores integrados existentes. También funciona dentro de bloques condicionales `[...]`: un bloque se oculta si el punto de datos referenciado está vacío. También se corrigió una palabra alemana residual (\"Fertig\") en la línea de asunto de la notificación.",
93
- "pl": "Nowość: szablony wiadomości powiadomień obsługują teraz symbol zastępczy `{state:objectId}`, który podczas wysyłania podstawia bieżącą wartość dowolnego punktu danych ioBroker (np. temperatura na zewnątrz, cena prądu) - oprócz istniejących wbudowanych symboli zastępczych. Działa też wewnątrz bloków warunkowych `[...]`: blok ukrywa się, jeśli wskazany punkt danych jest pusty. Naprawiono też pozostałe niemieckie słowo (\"Fertig\") w temacie powiadomienia.",
94
- "uk": "Новинка: шаблони повідомлень тепер підтримують заповнювач `{state:objectId}`, який під час надсилання підставляє поточне значення будь-якої точки даних ioBroker (наприклад, температуру зовні, ціну електроенергії) - на додаток до наявних вбудованих заповнювачів. Працює й усередині умовних блоків `[...]`: блок приховується, якщо вказана точка даних порожня. Також виправлено залишкове німецьке слово («Fertig») у темі сповіщення.",
95
- "zh-cn": "新功能:通知消息模板现在支持 `{state:objectId}` 占位符,可在发送时解析任意 ioBroker 数据点的当前值(例如室外温度、电价)——在现有内置占位符之上新增。在条件性 `[...]` 块内同样有效:若引用的数据点为空,该块会自动隐藏。同时修复了通知主题行中残留的一个德文单词(\"Fertig\")。"
96
96
  }
97
97
  },
98
98
  "titleLang": {
package/main.js CHANGED
@@ -419,6 +419,61 @@ class WashdataAdapter extends utils.Adapter {
419
419
  `${deviceCfg.name}: no saved cycle, but sensor active → directly running`,
420
420
  );
421
421
  }
422
+ } else if (manager._restoredCycle && manager._restoredCycle.startTime) {
423
+ // The device was mid-cycle when the adapter went down (or was
424
+ // restarted), but power has since dropped back to idle - the
425
+ // appliance actually finished while the adapter was offline.
426
+ // Without this branch, the in-memory manager/detector would
427
+ // just silently sit at their constructor defaults (state: "off",
428
+ // no cycleStartTime) and this interrupted cycle would never be
429
+ // properly closed out: the last-written state/program/etc data
430
+ // points would stay frozen at whatever they showed before the
431
+ // restart, and the cycle history entry would stay open forever
432
+ // with no end ever recorded, since nothing would ever call
433
+ // _onCycleFinished() for it - a real "kein Ende erkannt" case
434
+ // found via a production trace.
435
+ //
436
+ // Fix: restore the trace and resume the state machine as
437
+ // "running", then feed the current (already-low) reading
438
+ // through it so it proceeds through the normal
439
+ // PAUSED -> ENDING -> OFF path (using the real offDelayMin, now
440
+ // that it's correctly wired - see the offDelayMin fix) and
441
+ // finishes the cycle properly instead of orphaning it.
442
+ manager.detector.state = "running";
443
+ manager.currentState = "running";
444
+ manager.detector.cycleStartTime = manager._restoredCycle.startTime;
445
+ const savedTrace = manager._restoredCycle.trace;
446
+ if (
447
+ savedTrace &&
448
+ savedTrace.length > 0 &&
449
+ manager.detector.restoreTrace
450
+ ) {
451
+ manager.detector.restoreTrace(savedTrace);
452
+ manager.detector._maxWattsObserved = Math.max(
453
+ ...savedTrace.map((p) => p.watts),
454
+ 0,
455
+ );
456
+ // The ENDING->OFF transition needs lastAboveThreshold to compute
457
+ // how long power has been low - without seeding it here it
458
+ // stays null forever (only ever set inside processPowerReading's
459
+ // normal per-reading gate), and the resumed cycle would get
460
+ // stuck in "ending" indefinitely instead of actually finishing.
461
+ // Use the last trace point that was actually above threshold as
462
+ // a reasonable estimate of when the device was last truly on;
463
+ // cycleStartTime is a safe fallback if none is found (e.g. a
464
+ // very short/sparse trace).
465
+ const lastHighPoint = [...savedTrace]
466
+ .reverse()
467
+ .find((p) => p.watts >= (deviceCfg.powerThreshold || 10));
468
+ manager.detector.lastAboveThreshold = lastHighPoint
469
+ ? lastHighPoint.ts
470
+ : manager._restoredCycle.startTime;
471
+ }
472
+ this.log.info(
473
+ `${deviceCfg.name}: cycle was running before restart but sensor is now idle ` +
474
+ `(${wattsNow}W) - resuming to finish it properly instead of leaving it stuck`,
475
+ );
476
+ manager.processPowerReading(wattsNow, Date.now());
422
477
  }
423
478
  } catch (_e) {
424
479
  /* ignore restore errors */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.laundrylens",
3
- "version": "0.4.22",
3
+ "version": "0.4.23",
4
4
  "description": "ioBroker adapter that detects washing machine and dryer cycles via smart plug power measurement, matches them against learned programs and estimates remaining time",
5
5
  "author": {
6
6
  "name": "backfisch88",