iobroker.laundrylens 0.4.21 → 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 +6 -0
- package/io-package.json +27 -27
- package/lib/cycleDetector.js +11 -0
- package/main.js +55 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -132,6 +132,12 @@ 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
|
+
|
|
138
|
+
### 0.4.22 (2026-09-16)
|
|
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
|
|
140
|
+
|
|
135
141
|
### 0.4.21 (2026-09-08)
|
|
136
142
|
- Fix: translated all remaining German user-visible strings in the admin tab (toasts, table headers, confirm dialogs - about 35 instances, more than initially found by review) into the existing i18n system
|
|
137
143
|
- Fix: a cycle's `matchedProfile` could be stored server-side as literal German text ("Anti-Knitter") for anti-crease-tagged cycles, showing up untranslated in the `lastCycleProgram` data point and cycle history regardless of system language - now stored as a language-neutral marker and translated at display time
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "laundrylens",
|
|
4
|
-
"version": "0.4.
|
|
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
|
+
},
|
|
19
|
+
"0.4.22": {
|
|
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.",
|
|
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.",
|
|
22
|
+
"ru": "Исправление: настройка «Off delay» (offDelayMin) для устройства незаметно игнорировалась - при объединении конфигурации в CycleDetector она никогда не преобразовывалась в поле, которое реально используется (offDelay, в секундах), поэтому каждое устройство всегда использовало жёстко заданное значение по умолчанию в 5 минут независимо от настройки. Обнаружено благодаря реальной записи, где цикл долго оставался «запущенным», хотя мощность давно упала до ~0 Вт.",
|
|
23
|
+
"pt": "Correção: a configuração \"Off delay\" (offDelayMin) por dispositivo era silenciosamente ignorada - a fusão de configuração do CycleDetector nunca a traduzia para o campo realmente usado (offDelay, em segundos), então cada dispositivo sempre usava um padrão fixo de 5 minutos, independentemente do configurado. Encontrado através de um traço real onde um ciclo ficou preso como \"em execução\" muito depois da potência ter realmente caído para ~0W.",
|
|
24
|
+
"nl": "Fix: de instelling \"Off delay\" (offDelayMin) per apparaat werd stilzwijgend genegeerd - bij het samenvoegen van de configuratie in CycleDetector werd deze nooit vertaald naar het veld dat daadwerkelijk wordt gebruikt (offDelay, in seconden), waardoor elk apparaat altijd de vast ingestelde standaard van 5 minuten gebruikte, ongeacht de instelling. Gevonden via een echte trace waarbij een cyclus lang als \"actief\" bleef hangen terwijl het vermogen al naar ~0W was gedaald.",
|
|
25
|
+
"fr": "Correction : le réglage « Off delay » (offDelayMin) par appareil était silencieusement ignoré - la fusion de configuration de CycleDetector ne le traduisait jamais vers le champ réellement utilisé (offDelay, en secondes), donc chaque appareil utilisait toujours la valeur par défaut codée en dur de 5 minutes, quel que soit le réglage. Trouvé via une trace réelle où un cycle est resté bloqué en « en cours » bien après que la puissance soit réellement tombée à ~0W.",
|
|
26
|
+
"it": "Correzione: l'impostazione \"Off delay\" (offDelayMin) per dispositivo veniva silenziosamente ignorata - la fusione della configurazione in CycleDetector non la traduceva mai nel campo effettivamente usato (offDelay, in secondi), quindi ogni dispositivo usava sempre il valore predefinito fisso di 5 minuti, indipendentemente dall'impostazione. Trovato tramite una traccia reale in cui un ciclo è rimasto bloccato come \"in esecuzione\" molto dopo che la potenza era scesa a ~0W.",
|
|
27
|
+
"es": "Corrección: el ajuste \"Off delay\" (offDelayMin) por dispositivo se ignoraba silenciosamente - la fusión de configuración de CycleDetector nunca lo traducía al campo realmente utilizado (offDelay, en segundos), por lo que cada dispositivo siempre usaba el valor predeterminado fijo de 5 minutos, sin importar lo configurado. Encontrado mediante un registro real donde un ciclo quedó atascado como \"en ejecución\" mucho después de que la potencia realmente cayera a ~0W.",
|
|
28
|
+
"pl": "Poprawka: ustawienie \"Off delay\" (offDelayMin) dla urządzenia było po cichu ignorowane - łączenie konfiguracji w CycleDetector nigdy nie przekładało go na pole faktycznie używane (offDelay, w sekundach), więc każde urządzenie zawsze używało sztywno zakodowanej wartości domyślnej 5 minut, niezależnie od ustawienia. Znalezione dzięki rzeczywistemu zapisowi, w którym cykl długo pozostawał jako \"działający\", mimo że moc już dawno spadła do ~0W.",
|
|
29
|
+
"uk": "Виправлення: налаштування \"Off delay\" (offDelayMin) для пристрою непомітно ігнорувалося - під час об'єднання конфігурації в CycleDetector воно ніколи не перетворювалося на поле, яке дійсно використовується (offDelay, у секундах), тому кожен пристрій завжди використовував жорстко задане значення за замовчуванням 5 хвилин, незалежно від налаштування. Виявлено завдяки реальному запису, де цикл довго залишався \"запущеним\", хоча потужність давно впала до ~0 Вт.",
|
|
30
|
+
"zh-cn": "修复:每个设备的\"关闭延迟\"(offDelayMin)设置此前被静默忽略——CycleDetector 合并配置时从未将其转换为实际使用的字段(offDelay,单位为秒),导致每台设备始终使用硬编码的 5 分钟默认值,而与实际配置无关。此问题是通过一次真实记录发现的:某个周期在功率早已降至约 0W 之后,仍长时间卡在\"运行中\"状态。"
|
|
31
|
+
},
|
|
6
32
|
"0.4.21": {
|
|
7
33
|
"en": "Fix: translated all remaining German user-visible strings in the admin tab (toasts, table headers, confirm dialogs - about 35 instances, more than initially found by review) into the existing i18n system. Fix: a cycle's matchedProfile could be stored server-side as literal German text (\"Anti-Knitter\") for anti-crease-tagged cycles, showing up untranslated in the lastCycleProgram data point and cycle history regardless of system language - now stored as a language-neutral marker and translated at display time. Fix: two remaining hardcoded German date/time locales in the admin tab now use the configured language like everywhere else. Fix: added the full MIT license text to README.md (previously only the header/copyright line). Extended the English-only regression test to also cover the admin tab, closing the gap that let these issues go unnoticed.",
|
|
8
34
|
"de": "Fix: alle verbliebenen deutschen, für Nutzer sichtbaren Texte im Admin-Tab (Toasts, Tabellenüberschriften, Bestätigungsdialoge - ca. 35 Stellen, mehr als ursprünglich vom Review gefunden) ins bestehende i18n-System übersetzt. Fix: Der matchedProfile-Wert eines Zyklus konnte serverseitig als wörtlicher deutscher Text (\"Anti-Knitter\") für Anti-Knitter-markierte Zyklen gespeichert werden und erschien unübersetzt im lastCycleProgram-Datenpunkt sowie in der Zyklus-Historie, unabhängig von der Systemsprache - wird jetzt als sprachneutraler Marker gespeichert und erst bei der Anzeige übersetzt. Fix: zwei verbliebene fest codierte deutsche Datums-/Zeit-Gebietsschemata im Admin-Tab nutzen jetzt wie überall sonst die eingestellte Sprache. Fix: vollständigen MIT-Lizenztext zur README.md hinzugefügt (vorher nur Kopfzeile/Copyright-Zeile). Den Englisch-only-Regressionstest erweitert, damit er auch den Admin-Tab abdeckt und diese Lücke künftig auffällt.",
|
|
@@ -67,32 +93,6 @@
|
|
|
67
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\".",
|
|
68
94
|
"uk": "Новинка: три локалізовані, готові до показу точки даних - phaseText, stateText, programText - на додаток до наявних незалежних від мови (phase/state/program). Корисно для показу статусу прямо на панелі VIS без створення власної таблиці перекладів. Мова за замовчуванням - системна мова ioBroker, можна перевизначити для кожного пристрою новим налаштуванням «Мова відображення».",
|
|
69
95
|
"zh-cn": "新功能:新增三个本地化、可直接显示的数据点——phaseText、stateText、programText——与现有的语言无关数据点(phase/state/program)并存。便于在 VIS 仪表盘中直接显示状态,无需自建翻译表。语言默认使用 ioBroker 系统语言,可通过新增的\"显示语言\"设置按设备覆盖。"
|
|
70
|
-
},
|
|
71
|
-
"0.4.16": {
|
|
72
|
-
"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.",
|
|
73
|
-
"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.",
|
|
74
|
-
"ru": "Новое: шаблоны уведомлений теперь поддерживают плейсхолдер `{state:objectId}`, который при отправке подставляет текущее значение любой точки данных ioBroker (например, температуру снаружи, цену электричества) - в дополнение к уже существующим встроенным плейсхолдерам. Работает и внутри условных блоков `[...]`: блок скрывается, если указанная точка данных пуста. Также исправлено оставшееся немецкое слово («Fertig») в теме уведомления.",
|
|
75
|
-
"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.",
|
|
76
|
-
"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.",
|
|
77
|
-
"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.",
|
|
78
|
-
"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.",
|
|
79
|
-
"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.",
|
|
80
|
-
"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.",
|
|
81
|
-
"uk": "Новинка: шаблони повідомлень тепер підтримують заповнювач `{state:objectId}`, який під час надсилання підставляє поточне значення будь-якої точки даних ioBroker (наприклад, температуру зовні, ціну електроенергії) - на додаток до наявних вбудованих заповнювачів. Працює й усередині умовних блоків `[...]`: блок приховується, якщо вказана точка даних порожня. Також виправлено залишкове німецьке слово («Fertig») у темі сповіщення.",
|
|
82
|
-
"zh-cn": "新功能:通知消息模板现在支持 `{state:objectId}` 占位符,可在发送时解析任意 ioBroker 数据点的当前值(例如室外温度、电价)——在现有内置占位符之上新增。在条件性 `[...]` 块内同样有效:若引用的数据点为空,该块会自动隐藏。同时修复了通知主题行中残留的一个德文单词(\"Fertig\")。"
|
|
83
|
-
},
|
|
84
|
-
"0.4.15": {
|
|
85
|
-
"en": "Fixes from a full adapter review: the notification-language cache was module-level state, which could leak between two instances of this adapter sharing one process under compact mode - moved to an instance field. Two devices accidentally configured with the same power sensor now log a warning instead of one silently stopping updates. Cleaned up a small inconsistency in default-value handling for a few settings, and removed unused dead code.",
|
|
86
|
-
"de": "Fixes aus einem vollständigen Adapter-Review: Der Sprach-Cache für Benachrichtigungen war modulweiter State, der unter Compact-Mode zwischen zwei Instanzen dieses Adapters im selben Prozess hätte überlaufen können - jetzt ein Instanz-Feld. Zwei Geräte, die versehentlich denselben Stromsensor nutzen, loggen jetzt eine Warnung statt dass eines stillschweigend keine Updates mehr bekommt. Kleine Inkonsistenz bei Default-Werten einiger Einstellungen bereinigt, toten Code entfernt.",
|
|
87
|
-
"ru": "Исправления по итогам полного ревью адаптера: кэш языка уведомлений был состоянием уровня модуля, что могло привести к утечке между двумя инстанциями этого адаптера в одном процессе при compact-режиме - перенесено в поле инстанции. Два устройства, случайно настроенных на один датчик мощности, теперь логируют предупреждение вместо того, чтобы одно из них молча переставало получать обновления. Устранена небольшая несогласованность в обработке значений по умолчанию, удалён неиспользуемый код.",
|
|
88
|
-
"pt": "Correções de uma revisão completa do adaptador: o cache de idioma de notificação era estado em nível de módulo, podendo vazar entre duas instâncias deste adaptador compartilhando um processo em modo compact - movido para um campo da instância. Dois dispositivos configurados acidentalmente com o mesmo sensor de energia agora registram um aviso em vez de um parar silenciosamente de receber atualizações. Corrigida uma pequena inconsistência no tratamento de valores padrão e removido código morto.",
|
|
89
|
-
"nl": "Fixes uit een volledige adapterreview: de taalcache voor meldingen was module-brede state, die onder compact mode kon lekken tussen twee instanties van deze adapter in hetzelfde proces - nu een instantieveld. Twee apparaten die per ongeluk dezelfde stroomsensor gebruiken, loggen nu een waarschuwing in plaats van dat er één stilletjes geen updates meer krijgt. Kleine inconsistentie bij standaardwaarden opgelost, ongebruikte code verwijderd.",
|
|
90
|
-
"fr": "Corrections issues d'une revue complète de l'adaptateur : le cache de langue des notifications était un état au niveau du module, pouvant fuiter entre deux instances de cet adaptateur partageant un processus en mode compact - déplacé vers un champ d'instance. Deux appareils configurés par erreur avec le même capteur de puissance enregistrent désormais un avertissement au lieu que l'un cesse silencieusement de recevoir des mises à jour. Petite incohérence corrigée dans les valeurs par défaut, code mort supprimé.",
|
|
91
|
-
"it": "Correzioni da una revisione completa dell'adattatore: la cache della lingua delle notifiche era stato a livello di modulo, che poteva perdersi tra due istanze di questo adattatore che condividono un processo in modalità compact - spostata in un campo dell'istanza. Due dispositivi configurati per errore con lo stesso sensore di potenza ora registrano un avviso invece che uno smetta silenziosamente di ricevere aggiornamenti. Risolta una piccola incoerenza nei valori predefiniti, rimosso codice inutilizzato.",
|
|
92
|
-
"es": "Correcciones de una revisión completa del adaptador: la caché de idioma de notificaciones era estado a nivel de módulo, que podía filtrarse entre dos instancias de este adaptador que comparten un proceso en modo compact - movida a un campo de instancia. Dos dispositivos configurados accidentalmente con el mismo sensor de energía ahora registran una advertencia en lugar de que uno deje de recibir actualizaciones silenciosamente. Corregida una pequeña inconsistencia en los valores predeterminados, eliminado código muerto.",
|
|
93
|
-
"pl": "Poprawki z pełnego przeglądu adaptera: pamięć podręczna języka powiadomień była stanem na poziomie modułu, co mogło powodować wyciek między dwiema instancjami tego adaptera współdzielącymi jeden proces w trybie compact - przeniesiono do pola instancji. Dwa urządzenia przypadkowo skonfigurowane z tym samym czujnikiem mocy teraz logują ostrzeżenie zamiast tego, by jedno z nich po cichu przestało otrzymywać aktualizacje. Naprawiono drobną niespójność w wartościach domyślnych, usunięto martwy kod.",
|
|
94
|
-
"uk": "Виправлення за результатами повного огляду адаптера: кеш мови сповіщень був станом рівня модуля, що могло призвести до витоку між двома інстанціями цього адаптера в одному процесі в режимі compact - перенесено в поле інстанції. Два пристрої, випадково налаштовані на один датчик потужності, тепер логують попередження замість того, щоб один із них тихо переставав отримувати оновлення. Виправлено дрібну невідповідність у значеннях за замовчуванням, видалено невикористовуваний код.",
|
|
95
|
-
"zh-cn": "全面审查适配器后的修复:通知语言缓存原为模块级状态,在 compact 模式下共享同一进程的两个适配器实例之间可能发生泄漏——现已改为实例字段。两个设备如果意外配置了相同的功率传感器,现在会记录警告,而不是其中一个默默停止接收更新。修复了部分设置默认值处理中的小的不一致,移除了未使用的死代码。"
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
"titleLang": {
|
package/lib/cycleDetector.js
CHANGED
|
@@ -49,6 +49,17 @@ class CycleDetector {
|
|
|
49
49
|
*/
|
|
50
50
|
constructor(config = {}, onStateChange = null, adapter = null) {
|
|
51
51
|
this.cfg = { ...DEFAULT_CONFIG, ...config };
|
|
52
|
+
// The admin UI's per-device "Off delay" setting is stored as
|
|
53
|
+
// offDelayMin (minutes) on the normalized device config, but this
|
|
54
|
+
// detector's own field is offDelay (seconds) - the naive object-spread
|
|
55
|
+
// merge above never matches those two different key names, so the
|
|
56
|
+
// configured value was silently ignored and every device always used
|
|
57
|
+
// DEFAULT_CONFIG's hardcoded 300s (5 min), regardless of what was set
|
|
58
|
+
// in the admin UI (or the 8/10 min device-type defaults main.js
|
|
59
|
+
// computes for offDelayMin). Translated explicitly here.
|
|
60
|
+
if (config.offDelayMin !== undefined && config.offDelayMin !== null) {
|
|
61
|
+
this.cfg.offDelay = config.offDelayMin * 60;
|
|
62
|
+
}
|
|
52
63
|
this.onStateChange = onStateChange;
|
|
53
64
|
this.adapter = adapter;
|
|
54
65
|
|
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.
|
|
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",
|