iobroker.laundrylens 0.4.38 → 0.4.39
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 +5 -0
- package/io-package.json +14 -14
- package/main.js +18 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -132,6 +132,11 @@ This also works inside the conditional `[...]` blocks: `[🌡️ Outside: {state
|
|
|
132
132
|
|
|
133
133
|
### **WORK IN PROGRESS**
|
|
134
134
|
|
|
135
|
+
### 0.4.39 (2026-10-06)
|
|
136
|
+
- Fix: reported live - `elapsedTime` stayed frozen (often at a stale value left over from a previous cycle) for the entire "detecting..." period of a new cycle, only starting to update once a program was actually confirmed (observed: stuck at 11342 while only ~15 minutes into a new washer cycle; for a dryer, jumped from frozen to 1096 the moment the program was recognized). Root cause: `elapsedTime` is just `Date.now()` minus the cycle's start time, with no real dependency on program detection - but the `onTimeUpdate` callback that wrote it (via `_onTime()`) returned early, skipping the write entirely, whenever `WashDataManager._updateTimeEstimate()` reported no program/bestCandidate yet
|
|
137
|
+
- Fixed by extracting the computation into a shared `_updateElapsedTime()` helper, now called unconditionally at the top of `onTimeUpdate` - before its "no program detected" early return - as well as from `_onTime()`'s normal path, so it updates from the moment a cycle starts running regardless of detection status
|
|
138
|
+
- Covered by a new regression test (`tests/test_elapsed_time_before_detection.js`)
|
|
139
|
+
|
|
135
140
|
### 0.4.38 (2026-10-04)
|
|
136
141
|
- New: the Lernkontrolle (learning review/feedback) flow can now be driven from a VIS dashboard, not just the admin tab - previously only reachable via sendTo commands, invisible to VIS, which can only read/write data points
|
|
137
142
|
- New read-only data points: `pendingFeedbackCount`, `pendingFeedback` (JSON array of all unconfirmed cycles, oldest first), and `feedbackCycleId`/`feedbackProgram`/`feedbackDuration`/`feedbackEnergy`/`feedbackConfidence` (convenience fields for the oldest pending cycle, so a simple VIS text widget doesn't need to parse JSON)
|
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.39",
|
|
5
5
|
"news": {
|
|
6
|
+
"0.4.39": {
|
|
7
|
+
"en": "Fix: elapsedTime stayed frozen (often at a stale value left over from a previous cycle) for the entire \"detecting...\" period of a new cycle, only starting to update once a program was actually confirmed. elapsedTime is just Date.now() minus the cycle's start time though, with no real dependency on program detection - the callback that writes it was simply skipped entirely whenever no program had been recognized yet. Now updates from the moment a cycle starts running, regardless of detection status.",
|
|
8
|
+
"de": "Fix: elapsedTime blieb waehrend der gesamten \"detecting...\"-Phase eines neuen Zyklus eingefroren (oft auf einem veralteten Wert vom vorherigen Zyklus) und aktualisierte sich erst, sobald ein Programm tatsaechlich bestaetigt war. elapsedTime ist aber nur Date.now() minus Zyklusstartzeit, ohne echte Abhaengigkeit von der Programmerkennung - der Callback, der es schreibt, wurde schlicht komplett uebersprungen, solange noch kein Programm erkannt war. Aktualisiert sich jetzt ab dem Moment, in dem ein Zyklus zu laufen beginnt, unabhaengig vom Erkennungsstatus.",
|
|
9
|
+
"ru": "Исправление: elapsedTime оставался замороженным (часто на устаревшем значении с предыдущего цикла) на протяжении всего периода \"detecting...\" нового цикла и начинал обновляться только после фактического подтверждения программы. Однако elapsedTime - это просто Date.now() минус время начала цикла, без реальной зависимости от распознавания программы - колбэк, который его записывал, просто полностью пропускался, пока программа ещё не была распознана. Теперь обновляется с момента начала работы цикла, независимо от статуса распознавания.",
|
|
10
|
+
"pt": "Correcao: elapsedTime permanecia congelado (muitas vezes num valor obsoleto deixado do ciclo anterior) durante todo o periodo \"detecting...\" de um novo ciclo, so comecando a atualizar quando um programa era realmente confirmado. No entanto, elapsedTime e apenas Date.now() menos o horario de inicio do ciclo, sem dependencia real da deteccao de programa - o callback que o escrevia era simplesmente ignorado por completo enquanto nenhum programa tivesse sido reconhecido ainda. Agora atualiza a partir do momento em que um ciclo comeca a rodar, independente do status de deteccao.",
|
|
11
|
+
"nl": "Fix: elapsedTime bleef bevroren (vaak op een verouderde waarde van een vorige cyclus) gedurende de hele \"detecting...\"-periode van een nieuwe cyclus en werd pas bijgewerkt zodra een programma daadwerkelijk bevestigd was. elapsedTime is echter gewoon Date.now() min de startijd van de cyclus, zonder echte afhankelijkheid van programmaherkenning - de callback die het schreef werd simpelweg volledig overgeslagen zolang nog geen programma herkend was. Wordt nu bijgewerkt vanaf het moment dat een cyclus begint te lopen, ongeacht de herkenningsstatus.",
|
|
12
|
+
"fr": "Correction : elapsedTime restait fige (souvent sur une valeur obsolete laissee par un cycle precedent) pendant toute la periode \"detecting...\" d'un nouveau cycle, ne commencant a se mettre a jour qu'une fois un programme reellement confirme. Pourtant, elapsedTime n'est que Date.now() moins l'heure de debut du cycle, sans veritable dependance a la detection du programme - le callback qui l'ecrivait etait simplement totalement ignore tant qu'aucun programme n'avait encore ete reconnu. Se met desormais a jour des l'instant ou un cycle commence a tourner, quel que soit l'etat de detection.",
|
|
13
|
+
"it": "Correzione: elapsedTime restava bloccato (spesso su un valore obsoleto lasciato da un ciclo precedente) per l'intero periodo \"detecting...\" di un nuovo ciclo, iniziando ad aggiornarsi solo una volta che un programma veniva effettivamente confermato. Tuttavia elapsedTime e solo Date.now() meno l'orario di inizio del ciclo, senza una reale dipendenza dal rilevamento del programma - il callback che lo scriveva veniva semplicemente saltato del tutto finche non era stato riconosciuto alcun programma. Ora si aggiorna dal momento in cui un ciclo inizia a funzionare, indipendentemente dallo stato di rilevamento.",
|
|
14
|
+
"es": "Correccion: elapsedTime permanecia congelado (a menudo en un valor obsoleto de un ciclo anterior) durante todo el periodo \"detecting...\" de un nuevo ciclo, y solo empezaba a actualizarse una vez que se confirmaba realmente un programa. Sin embargo, elapsedTime es solo Date.now() menos la hora de inicio del ciclo, sin una dependencia real de la deteccion del programa - el callback que lo escribia simplemente se saltaba por completo mientras no se hubiera reconocido ningun programa todavia. Ahora se actualiza desde el momento en que un ciclo empieza a ejecutarse, independientemente del estado de deteccion.",
|
|
15
|
+
"pl": "Poprawka: elapsedTime pozostawal zamrozony (czesto na nieaktualnej wartosci pozostalej z poprzedniego cyklu) przez caly okres \"detecting...\" nowego cyklu i zaczynal sie aktualizowac dopiero po faktycznym potwierdzeniu programu. Jednak elapsedTime to po prostu Date.now() minus czas rozpoczecia cyklu, bez rzeczywistej zaleznosci od wykrywania programu - wywolanie zwrotne, ktore je zapisywalo, bylo po prostu calkowicie pomijane, dopoki zaden program nie zostal jeszcze rozpoznany. Teraz aktualizuje sie od momentu rozpoczecia dzialania cyklu, niezaleznie od statusu wykrywania.",
|
|
16
|
+
"uk": "Виправлення: elapsedTime залишався замороженим (часто на застарілому значенні з попереднього циклу) протягом усього періоду \"detecting...\" нового циклу і починав оновлюватися лише після фактичного підтвердження програми. Проте elapsedTime - це просто Date.now() мінус час початку циклу, без реальної залежності від розпізнавання програми - зворотний виклик, який його записував, просто повністю пропускався, доки програму ще не було розпізнано. Тепер оновлюється з моменту початку роботи циклу, незалежно від статусу розпізнавання.",
|
|
17
|
+
"zh-cn": "修复:在新周期的整个「detecting...」(检测中)阶段,elapsedTime 会一直冻结(通常停留在上一个周期遗留的过期值上),只有在程序被真正确认后才开始更新。然而 elapsedTime 其实只是 Date.now() 减去周期开始时间,与程序检测并无真正关联——写入它的回调函数在尚未识别出程序时会被完全跳过。现在从周期开始运行的那一刻起就会更新,与检测状态无关。"
|
|
18
|
+
},
|
|
6
19
|
"0.4.38": {
|
|
7
20
|
"en": "New: the Lernkontrolle (learning review/feedback) flow can now be driven from VIS, not just the admin tab. New read-only data points: pendingFeedbackCount, pendingFeedback (JSON list of all unconfirmed cycles, oldest first), and feedbackCycleId/feedbackProgram/feedbackDuration/feedbackEnergy/feedbackConfidence (convenience fields for the oldest one). New writable actions, each acting on the oldest pending cycle: feedbackConfirm (button, confirms it), feedbackCorrectProgram (dropdown of program names - writing one corrects and confirms), feedbackDelete (button, discards it without confirming).",
|
|
8
21
|
"de": "Neu: Die Lernkontrolle kann jetzt auch aus VIS heraus bedient werden, nicht nur ueber den Admin-Tab. Neue schreibgeschuetzte Datenpunkte: pendingFeedbackCount, pendingFeedback (JSON-Liste aller unbestaetigten Zyklen, aelteste zuerst) sowie feedbackCycleId/feedbackProgram/feedbackDuration/feedbackEnergy/feedbackConfidence (Komfortfelder fuer den aeltesten). Neue schreibbare Aktionen, die jeweils auf den aeltesten offenen Zyklus wirken: feedbackConfirm (Button, bestaetigt ihn), feedbackCorrectProgram (Dropdown mit Programmnamen - Eintrag schreiben korrigiert und bestaetigt), feedbackDelete (Button, verwirft ihn ohne Bestaetigung).",
|
|
@@ -80,19 +93,6 @@
|
|
|
80
93
|
"pl": "Poprawka: nowy cykl mógł przez kilka minut pokazywać pozostałość przypuszczenia programu z *poprzedniego*, już zakończonego cyklu (np. \"~30 Speed (76%)\" zaraz na starcie cyklu) - wewnętrzne pole najlepszego kandydata nie było czyszczone przy starcie nowego cyklu. Poprawka: cycleProgress pozostawał na ostatniej wartości (często 100%) po zakończeniu cyklu zamiast wrócić do 0. Poprawka: wyjątek podczas przetwarzania końcowego cyklu (zwłaszcza analiza post-hoc faz dla pralek/zmywarek) mógł po cichu blokować aktualizację datapointów statusu na żywo. Nowa opcja \"Pokaż prawdopodobny program przed potwierdzeniem\": opcjonalnie pokazuje bieżące przypuszczenie najlepszego kandydata w datapointach program/programText/confidence (z przedrostkiem \"≈\"), nie tylko we własnym podglądzie zakładki administratora. Nowa opcja \"Datapointy tekstowe bez emoji\": opcjonalnie pomija emoji w phaseText/stateText, na potrzeby dashboardów lub syntezy mowy.",
|
|
81
94
|
"uk": "Виправлення: новий цикл міг кілька хвилин показувати залишкове припущення ймовірної програми з *попереднього*, уже завершеного циклу (наприклад, \"~30 Speed (76%)\" одразу на старті циклу) - внутрішнє поле найкращого кандидата не скидалося під час старту нового циклу. Виправлення: cycleProgress залишався на останньому значенні (часто 100%) після завершення циклу замість скидання до 0. Виправлення: виняток під час постобробки наприкінці циклу (зокрема постфактум-аналіз фаз для пральних/посудомийних машин) міг непомітно блокувати оновлення датапоінтів живого статусу. Нова опція \"Показувати ймовірну програму до підтвердження\": опціонально виводить поточне припущення найкращого кандидата в датапоінти program/programText/confidence (з префіксом \"≈\"), а не лише у власному прев'ю вкладки адміністратора. Нова опція \"Текстові датапоінти без емодзі\": опціонально прибирає емодзі з phaseText/stateText для дашбордів або синтезу мовлення.",
|
|
82
95
|
"zh-cn": "修复:新周期可能会在最初几分钟内显示来自*上一个*已结束周期残留的可能程序猜测(例如周期刚开始就显示「~30 Speed (76%)」)——内部的最佳候选字段在新周期开始时未被清空。修复:周期结束后 cycleProgress 停留在最后的值(通常是 100%)而不会重置为 0。修复:周期结束后处理过程中的异常(尤其是洗衣机/洗碗机的事后阶段分析)可能会悄悄阻止实时状态数据点的更新。新增选项「确认前显示可能的程序」:可选择将实时最佳候选猜测显示到 program/programText/confidence 数据点中(带「≈」前缀),而不仅仅是管理标签页自身的预览。新增选项「文本数据点不含表情符号」:可选择在 phaseText/stateText 中省略表情符号,便于仪表盘或文本转语音使用。"
|
|
83
|
-
},
|
|
84
|
-
"0.4.32": {
|
|
85
|
-
"en": "Follow-up fix to 0.4.31: a restart alone did not clear an already-stale state data point (e.g. stuck on \"Running\"), even with 0.4.31 installed. onReady() only re-writes the state/stateText/running/program/phase data points when a restore branch fires (sensor currently active, or a saved cycle needs resuming/finishing) - with neither true, the common case, nothing touched them at all. Now every device's startup unconditionally re-syncs these data points with the manager's actual resolved state, so a restart always clears any stale value immediately, regardless of cause.",
|
|
86
|
-
"de": "Folgefix zu 0.4.31: ein reiner Neustart raeumte einen bereits haengengebliebenen Status-Datenpunkt (z.B. festgefahren auf \"Running\") nicht auf, selbst mit installiertem 0.4.31. onReady() schrieb die Datenpunkte state/stateText/running/program/phase bisher nur neu, wenn ein Restore-Zweig griff (Sensor aktuell aktiv, oder ein gespeicherter Zyklus muss fortgesetzt/beendet werden) - traf keins von beidem zu, der Normalfall, wurde nichts angefasst. Jetzt synchronisiert jeder Geraete-Start diese Datenpunkte bedingungslos mit dem tatsaechlichen, aufgeloesten Zustand des Managers, sodass ein Neustart jeden haengengebliebenen Wert sofort beseitigt, unabhaengig von der Ursache.",
|
|
87
|
-
"ru": "Дополнительное исправление к 0.4.31: одна лишь перезагрузка не устраняла уже зависший датапоинт состояния (например, застрявший на \"Running\"), даже при установленном 0.4.31. onReady() перезаписывал датапоинты state/stateText/running/program/phase только при срабатывании ветки восстановления (датчик сейчас активен либо сохранённый цикл нужно возобновить/завершить) - если ни то, ни другое не верно (обычный случай), ничего не менялось. Теперь при каждом запуске устройства эти датапоинты безусловно синхронизируются с фактическим состоянием менеджера, поэтому перезапуск всегда немедленно устраняет любое зависшее значение, независимо от причины.",
|
|
88
|
-
"pt": "Correcao de acompanhamento a 0.4.29: reiniciar sozinho nao limpava um data point de estado ja obsoleto (por exemplo, preso em \"Running\"), mesmo com a 0.4.31 instalada. O onReady() so reescrevia os data points state/stateText/running/program/phase quando um ramo de restauracao era acionado (sensor atualmente ativo, ou um ciclo salvo precisa ser retomado/finalizado) - sem nenhum dos dois, o caso comum, nada era alterado. Agora a inicializacao de cada dispositivo sincroniza incondicionalmente esses data points com o estado real resolvido do gerenciador, entao reiniciar sempre limpa qualquer valor obsoleto imediatamente, independente da causa.",
|
|
89
|
-
"nl": "Vervolgfix op 0.4.31: een herstart alleen wiste een reeds verouderd state-datapoint (bijv. vastgelopen op \"Running\") niet, zelfs met 0.4.31 geinstalleerd. onReady() herschreef de datapoints state/stateText/running/program/phase alleen wanneer een herstel-tak werd geactiveerd (sensor momenteel actief, of een opgeslagen cyclus moet worden hervat/afgerond) - was geen van beide waar, het normale geval, dan werd er niets aangepast. Nu synchroniseert elke apparaatstart deze datapoints onvoorwaardelijk met de daadwerkelijk vastgestelde status van de manager, zodat een herstart elke verouderde waarde altijd meteen opheldert, ongeacht de oorzaak.",
|
|
90
|
-
"fr": "Correction complementaire a 0.4.31 : un simple redemarrage ne nettoyait pas un data point d'etat deja obsolete (par ex. bloque sur \"Running\"), meme avec la 0.4.31 installee. onReady() ne reecrivait les data points state/stateText/running/program/phase que lorsqu'une branche de restauration se declenchait (capteur actuellement actif, ou un cycle enregistre doit etre repris/termine) - si aucun des deux n'etait vrai, le cas courant, rien n'etait modifie. Desormais, chaque demarrage d'appareil resynchronise inconditionnellement ces data points avec l'etat reel resolu du gestionnaire, de sorte qu'un redemarrage efface toujours immediatement toute valeur obsolete, quelle qu'en soit la cause.",
|
|
91
|
-
"it": "Correzione di follow-up alla 0.4.31: un semplice riavvio non ripuliva un data point di stato gia bloccato (ad es. fermo su \"Running\"), anche con la 0.4.31 installata. onReady() riscriveva i data point state/stateText/running/program/phase solo quando si attivava un ramo di ripristino (sensore attualmente attivo, oppure un ciclo salvato deve essere ripreso/terminato) - se nessuno dei due era vero, il caso comune, non veniva modificato nulla. Ora l'avvio di ogni dispositivo risincronizza incondizionatamente questi data point con lo stato effettivo risolto del manager, cosi un riavvio ripulisce sempre immediatamente qualsiasi valore bloccato, indipendentemente dalla causa.",
|
|
92
|
-
"es": "Correccion de seguimiento a 0.4.31: reiniciar por si solo no limpiaba un data point de estado ya obsoleto (por ejemplo, atascado en \"Running\"), incluso con 0.4.31 instalado. onReady() solo reescribia los data points state/stateText/running/program/phase cuando se activaba una rama de restauracion (sensor actualmente activo, o un ciclo guardado necesita reanudarse/finalizarse) - si ninguno de los dos era cierto, el caso comun, no se tocaba nada. Ahora el arranque de cada dispositivo resincroniza incondicionalmente estos data points con el estado real resuelto del gestor, por lo que reiniciar siempre limpia de inmediato cualquier valor atascado, sin importar la causa.",
|
|
93
|
-
"pl": "Poprawka uzupelniajaca do 0.4.31: samo ponowne uruchomienie nie czyscilo juz nieaktualnego datapointu stanu (np. utknietego na \"Running\"), nawet po zainstalowaniu 0.4.31. onReady() ponownie zapisywal datapointy state/stateText/running/program/phase tylko wtedy, gdy uruchamiala sie galaz przywracania (czujnik aktualnie aktywny lub zapisany cykl wymaga wznowienia/zakonczenia) - jesli zadne z tych warunkow nie bylo spelnione, czyli w typowym przypadku, nic nie bylo zmieniane. Teraz uruchomienie kazdego urzadzenia bezwarunkowo synchronizuje te datapointy z faktycznym, rozwiazanym stanem menedzera, dzieki czemu ponowne uruchomienie zawsze natychmiast czysci kazda utkniete wartosc, niezaleznie od przyczyny.",
|
|
94
|
-
"uk": "Додаткове виправлення до 0.4.31: сама лише перезагрузка не очищала вже застарілий датапоінт стану (наприклад, застряглий на \"Running\"), навіть із встановленим 0.4.31. onReady() перезаписував датапоінти state/stateText/running/program/phase лише коли спрацьовувала гілка відновлення (датчик наразі активний, або збережений цикл потрібно відновити/завершити) - якщо жодне з цього не було правдою, звичайний випадок, нічого не змінювалося. Тепер запуск кожного пристрою безумовно синхронізує ці датапоінти з фактичним, визначеним станом менеджера, тому перезапуск завжди негайно очищує будь-яке застарile значення, незалежно від причини.",
|
|
95
|
-
"zh-cn": "0.4.31 的后续修复:即使安装了 0.4.31,仅重启也无法清除已经过期的状态数据点(例如卡在「Running」)。此前 onReady() 只有在触发恢复分支时(传感器当前处于活动状态,或需要恢复/结束已保存的周期)才会重写 state/stateText/running/program/phase 数据点——如果两者都不成立(这是常见情况),则完全不做任何更改。现在每台设备启动时都会无条件将这些数据点与管理器实际解析出的状态同步,因此重启总能立即清除任何过期的值,无论原因是什么。"
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
"titleLang": {
|
package/main.js
CHANGED
|
@@ -347,6 +347,7 @@ class WashdataAdapter extends utils.Adapter {
|
|
|
347
347
|
onProgramChange: (program, confidence) =>
|
|
348
348
|
this._onProgram(deviceCfg.deviceId, program, confidence),
|
|
349
349
|
onTimeUpdate: (remaining, total, pct) => {
|
|
350
|
+
this._updateElapsedTime(deviceCfg.deviceId);
|
|
350
351
|
if (remaining === null) {
|
|
351
352
|
// No program detected – reset remaining time and progress
|
|
352
353
|
this.setState(`${deviceCfg.deviceId}.timeRemaining`, 0, true);
|
|
@@ -1711,6 +1712,22 @@ class WashdataAdapter extends utils.Adapter {
|
|
|
1711
1712
|
}
|
|
1712
1713
|
}
|
|
1713
1714
|
|
|
1715
|
+
// elapsedTime is purely Date.now() - cycleStartTime - meaningful and
|
|
1716
|
+
// available from the moment RUNNING starts, with no actual dependency
|
|
1717
|
+
// on whether a program has been detected yet. Called both from
|
|
1718
|
+
// onTimeUpdate()'s "no program detected" early-return branch and from
|
|
1719
|
+
// _onTime()'s normal path, so it keeps ticking up throughout the
|
|
1720
|
+
// entire "detecting..." period instead of only once a program is
|
|
1721
|
+
// confirmed - found live (reported stuck at a stale value, e.g. left
|
|
1722
|
+
// over from a previous, longer cycle, until recognition caught up).
|
|
1723
|
+
_updateElapsedTime(deviceId) {
|
|
1724
|
+
const mgr = this.managers[deviceId];
|
|
1725
|
+
if (mgr && mgr.cycleStartTime) {
|
|
1726
|
+
const elapsedSec = Math.round((Date.now() - mgr.cycleStartTime) / 1000);
|
|
1727
|
+
this.setState(`${deviceId}.elapsedTime`, elapsedSec, true);
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1714
1731
|
_onTime(
|
|
1715
1732
|
deviceId,
|
|
1716
1733
|
remainingSeconds,
|
|
@@ -1771,12 +1788,7 @@ class WashdataAdapter extends utils.Adapter {
|
|
|
1771
1788
|
).catch(() => {});
|
|
1772
1789
|
}
|
|
1773
1790
|
this.setState(`${deviceId}.timeRemaining`, remainingSeconds ?? 0, true);
|
|
1774
|
-
|
|
1775
|
-
const mgr2 = this.managers[deviceId];
|
|
1776
|
-
if (mgr2 && mgr2.cycleStartTime) {
|
|
1777
|
-
const elapsedSec = Math.round((Date.now() - mgr2.cycleStartTime) / 1000);
|
|
1778
|
-
this.setState(`${deviceId}.elapsedTime`, elapsedSec, true);
|
|
1779
|
-
}
|
|
1791
|
+
this._updateElapsedTime(deviceId);
|
|
1780
1792
|
this.setState(`${deviceId}.totalDuration`, totalSeconds ?? 0, true);
|
|
1781
1793
|
// Only overwrite progress if > 0 (prevents a reset if the profile
|
|
1782
1794
|
// briefly doesn't match) - UNLESS forceWrite is set, which is how
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.laundrylens",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.39",
|
|
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",
|