iobroker.laundrylens 0.4.17 → 0.4.18
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 +3 -0
- package/io-package.json +14 -14
- package/lib/washDataManager.js +31 -0
- package/package.json +1 -1
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.18 (2026-09-02)
|
|
136
|
+
- Fix: the dryer anti-crease lock period (learned duration + a fixed 10-minute buffer) could expire while the dryer was still genuinely doing its anti-crease tumbling - real anti-crease duration varies cycle to cycle, so a fixed length occasionally ran out mid-tumble, letting the tail end trigger a false new-cycle detection. The lock now extends when a genuine tumble spike occurs near its expiry, capped at 90 minutes total from the beep
|
|
137
|
+
|
|
135
138
|
### 0.4.17 (2026-08-31)
|
|
136
139
|
- New: `phaseText`, `stateText`, `programText` data points - localized, ready-to-display versions of the existing language-neutral `phase`/`state`/`program`, useful for a VIS dashboard without building your own translation table
|
|
137
140
|
- New: "Display language" setting per device (defaults to the ioBroker system language)
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "laundrylens",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.18",
|
|
5
5
|
"news": {
|
|
6
|
+
"0.4.18": {
|
|
7
|
+
"en": "Fix: the dryer anti-crease lock period (which prevents anti-crease tumbling after the beep from being mistaken for a new cycle) had a fixed length - learned duration plus a 10-minute buffer. Real anti-crease duration varies cycle to cycle, so the lock could occasionally expire while the dryer was still genuinely tumbling, letting the tail end trigger a false new-cycle detection. The lock is now adaptive: a genuine anti-crease tumble spike extends it further, capped at 90 minutes total from the beep.",
|
|
8
|
+
"de": "Fix: Die Anti-Knitter-Sperrzeit beim Trockner (verhindert, dass Nachlauf-Tummeln nach dem Piepton als neuer Zyklus fehlinterpretiert wird) hatte eine feste Länge - gelernte Dauer plus 10 Minuten Puffer. Die reale Anti-Knitter-Dauer variiert von Zyklus zu Zyklus, wodurch die Sperre gelegentlich ablaufen konnte, während der Trockner noch tatsächlich tummelte, sodass das Ende fälschlich als neuer Zyklus erkannt wurde. Die Sperre ist jetzt adaptiv: Ein echter Tummel-Spike verlängert sie weiter, insgesamt begrenzt auf 90 Minuten ab dem Piepton.",
|
|
9
|
+
"ru": "Исправление: период блокировки защиты от сминания у сушильной машины (предотвращает ошибочное распознавание остаточного вращения после сигнала как нового цикла) имел фиксированную длину - изученная длительность плюс 10-минутный буфер. Реальная длительность варьируется от цикла к циклу, поэтому блокировка иногда истекала, пока сушилка ещё действительно вращалась. Теперь блокировка адаптивная: настоящий всплеск вращения продлевает её, максимум 90 минут от сигнала.",
|
|
10
|
+
"pt": "Correção: o período de bloqueio anti-amarrotamento da secadora (evita que o movimento residual após o sinal seja confundido com um novo ciclo) tinha duração fixa - duração aprendida mais um buffer de 10 minutos. A duração real varia de ciclo para ciclo, então o bloqueio podia expirar enquanto a secadora ainda estava girando de verdade. Agora o bloqueio é adaptativo: um pico genuíno de movimento o estende, limitado a 90 minutos no total desde o sinal.",
|
|
11
|
+
"nl": "Fix: de anti-kreukvergrendelingsperiode van de droger (voorkomt dat na-tuimelen na de piep als nieuwe cyclus wordt gezien) had een vaste lengte - geleerde duur plus 10 minuten buffer. De echte duur varieert per cyclus, waardoor de vergrendeling soms afliep terwijl de droger nog echt aan het tuimelen was. De vergrendeling is nu adaptief: een echte tuimelpiek verlengt hem verder, met een maximum van 90 minuten vanaf de piep.",
|
|
12
|
+
"fr": "Correction : la période de verrouillage anti-froissage du sèche-linge (empêche que le mouvement résiduel après le bip soit confondu avec un nouveau cycle) avait une durée fixe - durée apprise plus un tampon de 10 minutes. La durée réelle varie d'un cycle à l'autre, le verrouillage pouvait donc parfois expirer alors que le sèche-linge tournait encore réellement. Le verrouillage est désormais adaptatif : un vrai pic de mouvement le prolonge, plafonné à 90 minutes au total depuis le bip.",
|
|
13
|
+
"it": "Correzione: il periodo di blocco anti-piega dell'asciugatrice (evita che il movimento residuo dopo il segnale venga scambiato per un nuovo ciclo) aveva una durata fissa - durata appresa più un buffer di 10 minuti. La durata reale varia da ciclo a ciclo, quindi il blocco poteva scadere mentre l'asciugatrice stava ancora davvero girando. Ora il blocco è adattivo: un vero picco di movimento lo estende, con un limite massimo di 90 minuti totali dal segnale.",
|
|
14
|
+
"es": "Corrección: el período de bloqueo antiarrugas de la secadora (evita que el movimiento residual tras el pitido se confunda con un nuevo ciclo) tenía una duración fija - duración aprendida más un margen de 10 minutos. La duración real varía de un ciclo a otro, por lo que el bloqueo podía expirar mientras la secadora aún seguía girando realmente. Ahora el bloqueo es adaptativo: un pico genuino de movimiento lo extiende, con un límite máximo de 90 minutos desde el pitido.",
|
|
15
|
+
"pl": "Poprawka: okres blokady ochrony przed gnieceniem w suszarce (zapobiega myleniu doczesywania po sygnale z nowym cyklem) miał stały czas trwania - wyuczony czas plus 10-minutowy bufor. Rzeczywisty czas różni się między cyklami, więc blokada mogła czasem wygasnąć, gdy suszarka nadal faktycznie się kręciła. Blokada jest teraz adaptacyjna: prawdziwy skok ruchu przedłuża ją, maksymalnie do 90 minut łącznie od sygnału.",
|
|
16
|
+
"uk": "Виправлення: період блокування захисту від зминання сушарки (запобігає помилковому розпізнаванню залишкового обертання після сигналу як нового циклу) мав фіксовану тривалість - вивчена тривалість плюс 10-хвилинний буфер. Реальна тривалість відрізняється від циклу до циклу, тому блокування могло вичерпатися, поки сушарка ще справді оберталася. Тепер блокування адаптивне: справжній сплеск обертання продовжує його, максимум 90 хвилин від сигналу.",
|
|
17
|
+
"zh-cn": "修复:烘干机防皱锁定期(防止提示音后的残余滚动被误判为新周期)此前是固定时长——学习到的时长加 10 分钟缓冲。实际防皱时长因周期而异,因此锁定有时会在烘干机仍在真实滚动时提前到期,导致尾声被误判为新周期。现在锁定改为自适应:真实的滚动波动会延长锁定,总时长从提示音起最多延长至 90 分钟。"
|
|
18
|
+
},
|
|
6
19
|
"0.4.17": {
|
|
7
20
|
"en": "New: three localized, ready-to-display data points - phaseText, stateText, programText - alongside the existing language-neutral ones (phase/state/program). Useful for showing status directly in a VIS dashboard without building your own translation table. Language defaults to the ioBroker system language, overridable per device via the new \"Display language\" setting. The phase-translation table (already used for the admin tab's cycle graph legend) is now a single shared file used by both the admin UI and these new data points, instead of two separately maintained copies.",
|
|
8
21
|
"de": "Neu: drei lokalisierte, fertig anzeigbare Datenpunkte - phaseText, stateText, programText - zusätzlich zu den bisherigen sprachneutralen (phase/state/program). Nützlich, um den Status direkt in einem VIS-Dashboard anzuzeigen, ohne selbst eine Übersetzungstabelle zu bauen. Die Sprache ist standardmäßig die ioBroker-Systemsprache, pro Gerät überschreibbar über die neue Einstellung „Anzeigesprache\". Die Phasen-Übersetzungstabelle (bisher schon für die Legende des Zyklus-Graphen im Admin-Tab genutzt) ist jetzt eine einzige gemeinsame Datei für Admin-Oberfläche und diese neuen Datenpunkte, statt zweier getrennt gepflegter Kopien.",
|
|
@@ -80,19 +93,6 @@
|
|
|
80
93
|
"pl": "Poprawki z ręcznej recenzji ioBroker.repositories (PR #6459): wszystkie komunikaty dziennika i nazwy stanów są teraz w języku angielskim; stan przycisku forceFinish ma teraz poprawnie read: false; istniejące instalacje są automatycznie migrowane przy następnym uruchomieniu; poprawiono sekcję wymagań README. Naprawiono też błąd, który praktycznie uniemożliwiał obsługę wielu urządzeń na jednej instancji adaptera. Dedykowany interfejs administratora do tego jest wciąż opracowywany osobno.",
|
|
81
94
|
"uk": "Виправлення за результатами ручної перевірки ioBroker.repositories (PR #6459): усі повідомлення журналу та назви станів тепер англійською; стан-кнопка forceFinish тепер коректно має read: false; наявні інсталяції автоматично мігрують під час наступного запуску; виправлено розділ вимог README. Також виправлено помилку, яка робила практично неможливим запуск кількох пристроїв на одній інстанції адаптера. Окремий інтерфейс адміністратора для цього ще розробляється.",
|
|
82
95
|
"zh-cn": "来自 ioBroker.repositories 人工审查(PR #6459)的修复:所有日志消息和状态名称现在均为英文;forceFinish 按钮状态现在正确设置为 read: false;现有安装将在下次启动时自动迁移;已更正 README 的要求部分。同时修复了一个使单个适配器实例上运行多个设备实际上不可能实现的错误。用于此目的的专用管理界面仍在单独开发中。"
|
|
83
|
-
},
|
|
84
|
-
"0.4.11": {
|
|
85
|
-
"en": "Fix: audited every remaining admin UI setting for the same class of bug fixed in 0.4.10 (a field silently never reaching the code that uses it) and found one more: \"Notify also for probable program\" (notifyOnProbable) was read in code but never returned by the internal device-config lookup, so checking it had no effect - Telegram updates always waited for the full auto-confirm threshold regardless of this setting. The regression test from 0.4.10 was extended to also check this class of field (read from the device-config lookup directly, not just fields passed into WashDataManager), so this category of bug should now be caught automatically going forward.",
|
|
86
|
-
"de": "Fix: alle übrigen Admin-Einstellungen auf dieselbe Fehlerart geprüft, die in 0.4.10 behoben wurde (ein Feld, das nie beim nutzenden Code ankommt) - und noch einen Fall gefunden: „Auch bei wahrscheinlichem Programm benachrichtigen\" (notifyOnProbable) wurde im Code gelesen, aber vom internen Geräte-Konfigurations-Lookup nie zurückgegeben, sodass die Checkbox wirkungslos war - Telegram-Updates warteten immer auf die volle Auto-Bestätigungs-Schwelle, unabhängig von dieser Einstellung. Der Regressionstest aus 0.4.10 wurde erweitert, um auch diese Art von Feld zu prüfen (direkt aus dem Geräte-Konfigurations-Lookup gelesen, nicht nur an WashDataManager übergebene Felder) - dieser Fehlertyp sollte künftig automatisch auffallen.",
|
|
87
|
-
"ru": "Исправление: проверены все оставшиеся настройки админ-интерфейса на тот же тип ошибки, что был исправлен в 0.4.10 (поле, которое незаметно никогда не доходит до использующего его кода) - и найден ещё один случай: «Уведомлять также при вероятной программе» (notifyOnProbable) считывался в коде, но никогда не возвращался внутренним поиском конфигурации устройства, поэтому включение этого флажка не имело эффекта - уведомления Telegram всегда ждали полного порога автоподтверждения независимо от этой настройки. Регрессионный тест из 0.4.10 расширен для проверки и этого класса полей.",
|
|
88
|
-
"pt": "Correção: auditadas todas as demais configurações da interface admin em busca do mesmo tipo de bug corrigido na 0.4.10 (um campo que silenciosamente nunca chega ao código que o usa) - e encontrado mais um caso: \"Notificar também para programa provável\" (notifyOnProbable) era lido no código, mas nunca retornado pela busca interna de configuração do dispositivo, então marcá-lo não tinha efeito - as atualizações do Telegram sempre esperavam o limite total de confirmação automática, independentemente dessa configuração. O teste de regressão da 0.4.10 foi ampliado para também verificar essa classe de campo.",
|
|
89
|
-
"nl": "Fix: alle overige admin-instellingen gecontroleerd op hetzelfde soort bug dat in 0.4.10 is opgelost (een veld dat stilletjes nooit bij de gebruikende code terechtkomt) - en nog één geval gevonden: \"Ook melden bij waarschijnlijk programma\" (notifyOnProbable) werd in de code gelezen, maar nooit geretourneerd door de interne apparaat-configuratie-opzoeking, waardoor het aanvinken geen effect had - Telegram-updates wachtten altijd op de volledige auto-bevestigingsdrempel, ongeacht deze instelling. De regressietest uit 0.4.10 is uitgebreid om ook dit soort veld te controleren.",
|
|
90
|
-
"fr": "Correction : audit de tous les autres réglages de l'interface admin pour le même type de bug corrigé dans la 0.4.10 (un champ qui n'atteint silencieusement jamais le code qui l'utilise) - et un cas de plus trouvé : « Notifier aussi pour un programme probable » (notifyOnProbable) était lu dans le code mais jamais renvoyé par la recherche interne de configuration de l'appareil, donc cocher la case n'avait aucun effet - les mises à jour Telegram attendaient toujours le seuil complet d'auto-confirmation, quel que soit ce réglage. Le test de régression de la 0.4.10 a été étendu pour vérifier aussi cette catégorie de champ.",
|
|
91
|
-
"it": "Correzione: verificate tutte le altre impostazioni dell'interfaccia admin per lo stesso tipo di bug corretto nella 0.4.10 (un campo che silenziosamente non raggiunge mai il codice che lo usa) - e trovato un altro caso: \"Notifica anche per programma probabile\" (notifyOnProbable) veniva letto nel codice ma mai restituito dalla ricerca interna della configurazione del dispositivo, quindi selezionarlo non aveva alcun effetto - gli aggiornamenti Telegram attendevano sempre la soglia completa di auto-conferma, indipendentemente da questa impostazione. Il test di regressione della 0.4.10 è stato esteso per verificare anche questa categoria di campo.",
|
|
92
|
-
"es": "Corrección: auditadas todas las demás configuraciones de la interfaz de administración en busca del mismo tipo de error corregido en la 0.4.10 (un campo que silenciosamente nunca llega al código que lo usa) - y se encontró un caso más: \"Notificar también para programa probable\" (notifyOnProbable) se leía en el código pero nunca era devuelto por la búsqueda interna de configuración del dispositivo, por lo que marcarlo no tenía efecto - las actualizaciones de Telegram siempre esperaban el umbral completo de auto-confirmación, sin importar esta configuración. La prueba de regresión de la 0.4.10 se amplió para verificar también esta clase de campo.",
|
|
93
|
-
"pl": "Poprawka: sprawdzono wszystkie pozostałe ustawienia interfejsu admina pod kątem tego samego rodzaju błędu naprawionego w 0.4.10 (pole, które nigdy po cichu nie dociera do kodu, który go używa) - i znaleziono jeszcze jeden przypadek: \"Powiadamiaj też przy prawdopodobnym programie\" (notifyOnProbable) było odczytywane w kodzie, ale nigdy nie było zwracane przez wewnętrzne wyszukiwanie konfiguracji urządzenia, więc zaznaczenie go nie miało efektu - powiadomienia Telegram zawsze czekały na pełny próg auto-potwierdzenia, niezależnie od tego ustawienia. Test regresyjny z 0.4.10 został rozszerzony, by sprawdzać także tę klasę pól.",
|
|
94
|
-
"uk": "Виправлення: перевірено всі інші налаштування адмін-інтерфейсу на той самий тип бага, виправленого в 0.4.10 (поле, яке непомітно ніколи не доходить до коду, що його використовує) - і знайдено ще один випадок: «Сповіщати також при ймовірній програмі» (notifyOnProbable) зчитувалося в коді, але ніколи не поверталося внутрішнім пошуком конфігурації пристрою, тому позначення прапорця не мало ефекту - сповіщення Telegram завжди чекали повного порогу автопідтвердження, незалежно від цього налаштування. Регресійний тест з 0.4.10 розширено для перевірки й цього класу полів.",
|
|
95
|
-
"zh-cn": "修复:审查了所有其余的管理界面设置,寻找与 0.4.10 中修复的同类错误(某字段悄悄地从未到达使用它的代码)——又发现了一个:\"可能程序也通知\"(notifyOnProbable)在代码中被读取,但内部设备配置查找从未返回它,因此勾选它没有任何效果——无论此设置如何,Telegram 更新始终等待完整的自动确认阈值。0.4.10 中的回归测试已扩展,以便也检查这一类字段。"
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
"titleLang": {
|
package/lib/washDataManager.js
CHANGED
|
@@ -19,6 +19,14 @@ const PROGRESS_RESET_MS = 5 * 60 * 1000;
|
|
|
19
19
|
const STUCK_POWER_MS = 10 * 60 * 1000;
|
|
20
20
|
const MIN_CYCLE_MS = 2 * 60 * 1000;
|
|
21
21
|
const MIN_CONFIDENCE_FOR_SET = 0.6; // Minimum average score to set a program via accumulation - deliberately strict (better "detecting..." than a wrong match)
|
|
22
|
+
// Dryer anti-crease lock: how far a genuine anti-crease tumble spike pushes
|
|
23
|
+
// the lock's expiry forward, and the absolute ceiling (from when the lock
|
|
24
|
+
// was first set) that extensions can never exceed - real anti-crease
|
|
25
|
+
// duration varies cycle to cycle (load size, dampness), so a purely fixed
|
|
26
|
+
// lock length (learned duration + buffer) can run out while the dryer is
|
|
27
|
+
// still actually tumbling, letting the tail end be mistaken for a new cycle.
|
|
28
|
+
const ANTI_CREASE_LOCK_REFRESH_MS = 10 * 60 * 1000;
|
|
29
|
+
const ANTI_CREASE_LOCK_MAX_MS = 90 * 60 * 1000;
|
|
22
30
|
|
|
23
31
|
/**
|
|
24
32
|
* Central orchestrator: wires the CycleDetector, ProfileStore, and
|
|
@@ -75,6 +83,7 @@ class WashDataManager {
|
|
|
75
83
|
// Dryer Anti-Knitter
|
|
76
84
|
this._dryerDropTriggered = false;
|
|
77
85
|
this._dryerLockUntil = null;
|
|
86
|
+
this._dryerLockStartedAt = null; // when the lock was first set - for the absolute ceiling
|
|
78
87
|
this._dryerHighStart = null;
|
|
79
88
|
this._antiKnitter = null; // { maxWatts, durationMs } – loaded from profileStore
|
|
80
89
|
}
|
|
@@ -307,6 +316,7 @@ class WashDataManager {
|
|
|
307
316
|
`${this._name}: anti-crease protection inactive (disabled or no pattern) – existing lock discarded`,
|
|
308
317
|
);
|
|
309
318
|
this._dryerLockUntil = null;
|
|
319
|
+
this._dryerLockStartedAt = null;
|
|
310
320
|
this._dryerDropTriggered = false;
|
|
311
321
|
this._dryerHighStart = null;
|
|
312
322
|
}
|
|
@@ -317,6 +327,7 @@ class WashDataManager {
|
|
|
317
327
|
`${this._name}: anti-crease lock period expired`,
|
|
318
328
|
);
|
|
319
329
|
this._dryerLockUntil = null;
|
|
330
|
+
this._dryerLockStartedAt = null;
|
|
320
331
|
this._dryerDropTriggered = false;
|
|
321
332
|
this._dryerHighStart = null;
|
|
322
333
|
} else {
|
|
@@ -340,6 +351,7 @@ class WashDataManager {
|
|
|
340
351
|
`${this._name}: real new cycle detected after the beep (>${realThreshold}W for 30s) – lock lifted`,
|
|
341
352
|
);
|
|
342
353
|
this._dryerLockUntil = null;
|
|
354
|
+
this._dryerLockStartedAt = null;
|
|
343
355
|
this._dryerDropTriggered = false;
|
|
344
356
|
this._dryerHighStart = null;
|
|
345
357
|
// Continue with normal processing
|
|
@@ -353,6 +365,23 @@ class WashDataManager {
|
|
|
353
365
|
);
|
|
354
366
|
}
|
|
355
367
|
this._dryerHighStart = null;
|
|
368
|
+
// A meaningful spike (motor tumble, not just idle standby noise)
|
|
369
|
+
// is itself evidence the dryer is still actually doing its
|
|
370
|
+
// anti-crease thing - push the lock's expiry forward instead of
|
|
371
|
+
// letting a fixed-length lock run out mid-tumble, capped at an
|
|
372
|
+
// absolute ceiling from when the lock was first set.
|
|
373
|
+
if (watts > 10 && this._dryerLockStartedAt) {
|
|
374
|
+
const extended = Math.min(
|
|
375
|
+
ts + ANTI_CREASE_LOCK_REFRESH_MS,
|
|
376
|
+
this._dryerLockStartedAt + ANTI_CREASE_LOCK_MAX_MS,
|
|
377
|
+
);
|
|
378
|
+
if (extended > this._dryerLockUntil) {
|
|
379
|
+
this.adapter.log.debug(
|
|
380
|
+
`${this._name}: anti-crease still active (${watts.toFixed(0)}W) – lock extended to ${Math.round((extended - ts) / 60000)} min from now`,
|
|
381
|
+
);
|
|
382
|
+
this._dryerLockUntil = extended;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
356
385
|
this.adapter.log.debug(
|
|
357
386
|
`${this._name}: anti-crease spike ignored (${watts.toFixed(0)}W < ${realThreshold}W threshold)`,
|
|
358
387
|
);
|
|
@@ -394,6 +423,7 @@ class WashDataManager {
|
|
|
394
423
|
);
|
|
395
424
|
this._dryerDropTriggered = true;
|
|
396
425
|
this._dryerLockUntil = ts + lockMs;
|
|
426
|
+
this._dryerLockStartedAt = ts;
|
|
397
427
|
this._dryerCooldownEnd = Date.now() + 45000;
|
|
398
428
|
// Wait 45 seconds – trace keeps recording for a nicer-looking graph
|
|
399
429
|
// Detector stays active so further points get collected
|
|
@@ -1524,6 +1554,7 @@ class WashDataManager {
|
|
|
1524
1554
|
// Also immediately lift any currently active lock period, so the
|
|
1525
1555
|
// next cycle can be recorded without interference.
|
|
1526
1556
|
this._dryerLockUntil = null;
|
|
1557
|
+
this._dryerLockStartedAt = null;
|
|
1527
1558
|
this._dryerDropTriggered = false;
|
|
1528
1559
|
this._dryerHighStart = null;
|
|
1529
1560
|
this.adapter.log.info(`${this._name}: anti-crease pattern deleted`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.laundrylens",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.18",
|
|
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",
|