// WashData - Home Assistant integration for appliance cycle monitoring via smart plugs. // Copyright (C) 2026 Lukas Bandura // SPDX-License-Identifier: AGPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . const CARD_TAG = "ha-washdata-card"; const EDITOR_TAG = "ha-washdata-card-editor"; // Gesture timing (ms) and movement tolerance (px) for tap / hold / double-tap, // chosen to match Home Assistant's own action handler conventions. const HOLD_MS = 500; const DOUBLE_TAP_MS = 250; const TAP_MOVE_TOLERANCE = 10; const TRANSLATIONS = {"en":{"washer_program":"Washer Program","program_placeholder":"Select Program","duration":"Duration","minutes":"min","time_remaining":"Time Remaining","no_prediction":"No Prediction","cycle_in_progress":"Cycle in progress","status":"Status","progress":"Progress","select_program":"Select a program to see details","title":"Title","status_entity":"Status Entity","icon":"Icon","active_color":"Active Icon Color","show_state":"Show State","show_program":"Show Program","show_details":"Show Details","spin_icon":"Spinning Icon (While running)","program_entity":"Program Entity","pct_entity":"Progress Entity (Optional)","time_entity":"Time Entity (Optional)","display_mode":"Display Mode","show_time_remaining":"Show Time Remaining","show_percentage":"Show Percentage","entity_not_found":"Entity not found","tap_action":"Tap Action","hold_action":"Hold Action","double_tap_action":"Double Tap Action"},"bg":{"washer_program":"Програма за пране","program_placeholder":"Изберете Програма","duration":"Продължителност","minutes":"мин","time_remaining":"Оставащо време","no_prediction":"Няма прогноза","cycle_in_progress":"Цикълът е в ход","status":"Статус","progress":"Напредък","select_program":"Изберете програма, за да видите подробности","title":"Заглавие","status_entity":"Състояние на обекта","icon":"Икона","active_color":"Цвят на активната икона","show_state":"Показване на състояние","show_program":"Шоу програма","show_details":"Показване на подробности","spin_icon":"Въртяща се икона (докато работи)","program_entity":"Програмен субект","pct_entity":"Обект на напредъка (по избор)","time_entity":"Времеви обект (по избор)","display_mode":"Режим на показване","show_time_remaining":"Показване на оставащото време","show_percentage":"Показване на процента","entity_not_found":"Обектът не е намерен","tap_action":"Докосване на действие","hold_action":"Задръж действие","double_tap_action":"Двойно докосване"},"bs":{"washer_program":"Program za pranje","program_placeholder":"Odaberite Program","duration":"Trajanje","minutes":"min","time_remaining":"Preostalo vrijeme","no_prediction":"Nema predviđanja","cycle_in_progress":"Ciklus je u toku","status":"Status","progress":"Napredak","select_program":"Odaberite program da vidite detalje","title":"Naslov","status_entity":"Status Entiteta","icon":"Ikona","active_color":"Aktivna boja ikone","show_state":"Prikaži državu","show_program":"Show Program","show_details":"Prikaži detalje","spin_icon":"Ikona za okretanje (dok trčanje)","program_entity":"Programski entitet","pct_entity":"Entitet napretka (opciono)","time_entity":"Vremenski entitet (opcionalno)","display_mode":"Način prikaza","show_time_remaining":"Prikaži preostalo vrijeme","show_percentage":"Prikaži procenat","entity_not_found":"Entitet nije pronađen","tap_action":"Dodirnite Akcija","hold_action":"Držite akciju","double_tap_action":"Dvostruki dodir Akcija"},"cs":{"washer_program":"Program pračky","program_placeholder":"Vyberte Program","duration":"Trvání","minutes":"min","time_remaining":"Zbývající čas","no_prediction":"Žádná předpověď","cycle_in_progress":"Cyklus probíhá","status":"Postavení","progress":"Pokrok","select_program":"Chcete-li zobrazit podrobnosti, vyberte program","title":"Titul","status_entity":"Stavová entita","icon":"Ikona","active_color":"Barva aktivní ikony","show_state":"Zobrazit stav","show_program":"Zobrazit program","show_details":"Zobrazit podrobnosti","spin_icon":"Ikona rotace (při běhu)","program_entity":"Entita programu","pct_entity":"Entita průběhu (volitelné)","time_entity":"Časová entita (volitelné)","display_mode":"Režim zobrazení","show_time_remaining":"Zobrazit zbývající čas","show_percentage":"Zobrazit procento","entity_not_found":"Entita nenalezena","tap_action":"Klepněte na možnost Akce","hold_action":"Držet akci","double_tap_action":"Akce dvojitého klepnutí"},"da":{"washer_program":"Vaskeprogram","program_placeholder":"Vælg Program","duration":"Varighed","minutes":"min","time_remaining":"Tid tilbage","no_prediction":"Ingen forudsigelse","cycle_in_progress":"Cyklus i gang","status":"Status","progress":"Fremskridt","select_program":"Vælg et program for at se detaljer","title":"Titel","status_entity":"Statusenhed","icon":"Ikon","active_color":"Aktiv ikon farve","show_state":"Vis tilstand","show_program":"Vis program","show_details":"Vis detaljer","spin_icon":"Spinning-ikon (mens du løber)","program_entity":"Programenhed","pct_entity":"Fremskridtsenhed (valgfrit)","time_entity":"Tidsenhed (valgfrit)","display_mode":"Visningstilstand","show_time_remaining":"Vis resterende tid","show_percentage":"Vis procent","entity_not_found":"Enheden blev ikke fundet","tap_action":"Tap på handling","hold_action":"Hold handling","double_tap_action":"Dobbelt tastehandling"},"de":{"washer_program":"Waschprogramm","program_placeholder":"Wählen Sie Programm","duration":"Dauer","minutes":"min","time_remaining":"Verbleibende Zeit","no_prediction":"Keine Vorhersage","cycle_in_progress":"Zyklus läuft","status":"Status","progress":"Fortschritt","select_program":"Wählen Sie ein Programm aus, um Details anzuzeigen","title":"Titel","status_entity":"Status-Entität","icon":"Symbol","active_color":"Aktive Symbolfarbe","show_state":"Status anzeigen","show_program":"Programm anzeigen","show_details":"Details anzeigen","spin_icon":"Spinning-Symbol (während des Laufens)","program_entity":"Programmeinheit","pct_entity":"Fortschrittsentität (optional)","time_entity":"Zeiteinheit (optional)","display_mode":"Anzeigemodus","show_time_remaining":"Verbleibende Zeit anzeigen","show_percentage":"Prozentsatz anzeigen","entity_not_found":"Entität nicht gefunden","tap_action":"Tippen Sie auf","hold_action":"Action spielen","double_tap_action":"Doppeltipp-Aktion"},"el":{"washer_program":"Πρόγραμμα πλύσης","program_placeholder":"Επιλέξτε Πρόγραμμα","duration":"Διάρκεια","minutes":"ελάχ","time_remaining":"Χρόνος που απομένει","no_prediction":"Καμία Πρόβλεψη","cycle_in_progress":"Κύκλος σε εξέλιξη","status":"Κατάσταση","progress":"Πρόοδος","select_program":"Επιλέξτε ένα πρόγραμμα για να δείτε λεπτομέρειες","title":"Τίτλος","status_entity":"Οντότητα κατάστασης","icon":"Εικόνισμα","active_color":"Χρώμα ενεργού εικονιδίου","show_state":"Εμφάνιση κατάστασης","show_program":"Εμφάνιση προγράμματος","show_details":"Εμφάνιση λεπτομερειών","spin_icon":"Περιστρεφόμενο εικονίδιο (Κατά την εκτέλεση)","program_entity":"Οντότητα προγράμματος","pct_entity":"Οντότητα προόδου (Προαιρετικό)","time_entity":"Οντότητα ώρας (Προαιρετικό)","display_mode":"Λειτουργία εμφάνισης","show_time_remaining":"Εμφάνιση χρόνου που απομένει","show_percentage":"Εμφάνιση ποσοστού","entity_not_found":"Η οντότητα δεν βρέθηκε","tap_action":"Πατήστε ενέργεια","hold_action":"Διατήρηση ενέργειας","double_tap_action":"Διπλή ενέργεια πατήματος"},"es":{"washer_program":"Programa de lavadora","program_placeholder":"Seleccionar programa","duration":"Duración","minutes":"mín.","time_remaining":"Tiempo restante","no_prediction":"Sin predicción","cycle_in_progress":"Ciclo en progreso","status":"Estado","progress":"Progreso","select_program":"Selecciona un programa para ver detalles","title":"Título","status_entity":"Entidad de estado","icon":"Icono","active_color":"Color del icono activo","show_state":"Mostrar estado","show_program":"Mostrar programa","show_details":"Mostrar detalles","spin_icon":"Icono de giro (mientras se ejecuta)","program_entity":"Entidad del programa","pct_entity":"Entidad de progreso (opcional)","time_entity":"Entidad de tiempo (opcional)","display_mode":"Modo de visualización","show_time_remaining":"Mostrar tiempo restante","show_percentage":"Mostrar porcentaje","entity_not_found":"Entidad no encontrada","tap_action":"Toque Acción","hold_action":"Mantener acción","double_tap_action":"Doble toque de acción"},"et":{"washer_program":"Pesumasina programm","program_placeholder":"Valige Programm","duration":"Kestus","minutes":"min","time_remaining":"Järelejäänud aeg","no_prediction":"Ei mingit ennustust","cycle_in_progress":"Tsükkel on pooleli","status":"Olek","progress":"Edusammud","select_program":"Üksikasjade vaatamiseks valige programm","title":"Pealkiri","status_entity":"Olekuüksus","icon":"Ikoon","active_color":"Aktiivne ikooni värv","show_state":"Näita olekut","show_program":"Näita programmi","show_details":"Näita üksikasju","spin_icon":"Pöörlev ikoon (jooksmise ajal)","program_entity":"Programmi üksus","pct_entity":"Edenemisüksus (valikuline)","time_entity":"Ajaüksus (valikuline)","display_mode":"Kuvamisrežiim","show_time_remaining":"Näita järelejäänud aega","show_percentage":"Näita protsenti","entity_not_found":"Üksust ei leitud","tap_action":"Puudutustoiming","hold_action":"Hoidke tegevust","double_tap_action":"Topeltpuutetoiming"},"fi":{"washer_program":"Pesuohjelma","program_placeholder":"Valitse Ohjelma","duration":"Kesto","minutes":"min","time_remaining":"Aikaa jäljellä","no_prediction":"Ei ennustetta","cycle_in_progress":"Kierto käynnissä","status":"Tila","progress":"Edistyminen","select_program":"Valitse ohjelma nähdäksesi tiedot","title":"Otsikko","status_entity":"Tilayksikkö","icon":"Kuvake","active_color":"Aktiivinen kuvakkeen väri","show_state":"Näytä tila","show_program":"Näytä ohjelma","show_details":"Näytä tiedot","spin_icon":"Pyörivä kuvake (juoksessa)","program_entity":"Ohjelmakokonaisuus","pct_entity":"Etenemiskokonaisuus (valinnainen)","time_entity":"Aikakokonaisuus (valinnainen)","display_mode":"Näyttötila","show_time_remaining":"Näytä jäljellä oleva aika","show_percentage":"Näytä prosenttiosuus","entity_not_found":"Kokonaisuutta ei löydy","tap_action":"Napauta toimintoa","hold_action":"Pidä toimintoa","double_tap_action":"Kaksoisnapaustoiminto"},"fr":{"washer_program":"Programme de laveuse","program_placeholder":"Sélectionnez le programme","duration":"Durée","minutes":"min","time_remaining":"Temps restant","no_prediction":"Aucune prédiction","cycle_in_progress":"Cycle en cours","status":"Statut","progress":"Progrès","select_program":"Sélectionnez un programme pour voir les détails","title":"Titre","status_entity":"Entité de statut","icon":"Icône","active_color":"Couleur de l'icône active","show_state":"Afficher l'état","show_program":"Programme du spectacle","show_details":"Afficher les détails","spin_icon":"Icône de rotation (pendant l'exécution)","program_entity":"Entité du programme","pct_entity":"Entité de progression (facultatif)","time_entity":"Entité temporelle (facultatif)","display_mode":"Mode d'affichage","show_time_remaining":"Afficher le temps restant","show_percentage":"Afficher le pourcentage","entity_not_found":"Entité introuvable","tap_action":"Appuyez sur Action","hold_action":"Maintenez l'action","double_tap_action":"Double action de la touche"},"hr":{"washer_program":"Program za pranje","program_placeholder":"Odaberite Program","duration":"Trajanje","minutes":"min","time_remaining":"Preostalo vrijeme","no_prediction":"Nema predviđanja","cycle_in_progress":"Ciklus u tijeku","status":"Status","progress":"Napredak","select_program":"Odaberite program da biste vidjeli pojedinosti","title":"Titula","status_entity":"Statusni entitet","icon":"Ikona","active_color":"Boja aktivne ikone","show_state":"Prikaži stanje","show_program":"Show Program","show_details":"Prikaži pojedinosti","spin_icon":"Ikona koja se vrti (dok radi)","program_entity":"Programski entitet","pct_entity":"Entitet napretka (neobavezno)","time_entity":"Entitet vremena (neobavezno)","display_mode":"Način prikaza","show_time_remaining":"Prikaži preostalo vrijeme","show_percentage":"Prikaži postotak","entity_not_found":"Entitet nije pronađen","tap_action":"Dodirnite Akcija","hold_action":"Zadrži akciju","double_tap_action":"Akcija dvostrukog dodira"},"hu":{"washer_program":"Mosó program","program_placeholder":"Válassza a Program lehetőséget","duration":"Időtartam","minutes":"min","time_remaining":"Hátralévő idő","no_prediction":"Nincs előrejelzés","cycle_in_progress":"Ciklus folyamatban","status":"Állapot","progress":"Előrehalad","select_program":"Válasszon ki egy programot a részletek megtekintéséhez","title":"Cím","status_entity":"Állapot entitás","icon":"Ikon","active_color":"Aktív Ikon színe","show_state":"Állapot megjelenítése","show_program":"Program megjelenítése","show_details":"Részletek megjelenítése","spin_icon":"Pörgő ikon (futás közben)","program_entity":"Program entitás","pct_entity":"Haladási entitás (opcionális)","time_entity":"Idő entitás (opcionális)","display_mode":"Kijelző mód","show_time_remaining":"Mutasd a hátralévő időt","show_percentage":"Százalék megjelenítése","entity_not_found":"Az entitás nem található","tap_action":"Koppintson a Művelet elemre","hold_action":"Tartsa akciót","double_tap_action":"Dupla koppintás művelet"},"is":{"washer_program":"Þvottavélaforrit","program_placeholder":"Veldu Program","duration":"Lengd","minutes":"mín","time_remaining":"Tími sem eftir er","no_prediction":"Engin spá","cycle_in_progress":"Hringrás í gangi","status":"Staða","progress":"Framfarir","select_program":"Veldu forrit til að sjá upplýsingar","title":"Titill","status_entity":"Staða eining","icon":"Táknmynd","active_color":"Virkur táknlitur","show_state":"Sýna ástand","show_program":"Sýna dagskrá","show_details":"Sýna upplýsingar","spin_icon":"Snúningstákn (meðan í gangi)","program_entity":"Dagskráreining","pct_entity":"Framvindueining (valfrjálst)","time_entity":"Tímaeining (valfrjálst)","display_mode":"Sýnastilling","show_time_remaining":"Sýna tíma sem eftir er","show_percentage":"Sýna hlutfall","entity_not_found":"Eining fannst ekki","tap_action":"Bankaðu á Aðgerð","hold_action":"Haltu Action","double_tap_action":"Tvíspikkaðu á Action"},"it":{"washer_program":"Programma Lavatrice","program_placeholder":"Seleziona Programma","duration":"Durata","minutes":"min","time_remaining":"Tempo rimanente","no_prediction":"Nessuna previsione","cycle_in_progress":"Ciclo in corso","status":"Stato","progress":"Progressi","select_program":"Seleziona un programma per vedere i dettagli","title":"Titolo","status_entity":"Entità di stato","icon":"Icona","active_color":"Colore icona attiva","show_state":"Mostra stato","show_program":"Mostra programma","show_details":"Mostra dettagli","spin_icon":"Icona che gira (durante la corsa)","program_entity":"Entità del programma","pct_entity":"Entità di avanzamento (facoltativo)","time_entity":"Entità temporale (facoltativo)","display_mode":"Modalità di visualizzazione","show_time_remaining":"Mostra tempo rimanente","show_percentage":"Mostra percentuale","entity_not_found":"Entità non trovata","tap_action":"Tocca Azione","hold_action":"Mantieni Azione","double_tap_action":"Azione doppio tocco"},"ja":{"washer_program":"ウォッシャープログラム","program_placeholder":"プログラムの選択","duration":"間隔","minutes":"分","time_remaining":"残り時間","no_prediction":"予測なし","cycle_in_progress":"進行中のサイクル","status":"状態","progress":"進捗","select_program":"プログラムを選択して詳細を表示します","title":"タイトル","status_entity":"ステータスエンティティ","icon":"アイコン","active_color":"アクティブなアイコンの色","show_state":"状態を表示","show_program":"ショープログラム","show_details":"詳細を表示","spin_icon":"回転アイコン(走行中)","program_entity":"プログラムエンティティ","pct_entity":"進行状況エンティティ (オプション)","time_entity":"時間エンティティ (オプション)","display_mode":"表示モード","show_time_remaining":"残りの上映時間","show_percentage":"パーセンテージを表示","entity_not_found":"エンティティが見つかりません","tap_action":"タップアクション","hold_action":"ホールドアクション","double_tap_action":"ダブルタップアクション"},"ko":{"washer_program":"세탁기 프로그램","program_placeholder":"프로그램 선택","duration":"지속","minutes":"분","time_remaining":"남은 시간","no_prediction":"예측 없음","cycle_in_progress":"사이클 진행 중","status":"상태","progress":"진전","select_program":"세부정보를 보려면 프로그램을 선택하세요.","title":"제목","status_entity":"상태 엔터티","icon":"상","active_color":"활성 아이콘 색상","show_state":"상태 표시","show_program":"쇼 프로그램","show_details":"세부정보 표시","spin_icon":"회전 아이콘(실행 중)","program_entity":"프로그램 엔터티","pct_entity":"진행 엔터티(선택 사항)","time_entity":"시간 엔터티(선택 사항)","display_mode":"디스플레이 모드","show_time_remaining":"남은 시간 표시","show_percentage":"백분율 표시","entity_not_found":"엔터티를 찾을 수 없습니다.","tap_action":"탭 동작","hold_action":"보류 조치","double_tap_action":"더블 탭 액션"},"lt":{"washer_program":"Skalbimo programa","program_placeholder":"Pasirinkite Programa","duration":"Trukmė","minutes":"min","time_remaining":"Likęs laikas","no_prediction":"Jokios prognozės","cycle_in_progress":"Vyksta ciklas","status":"Būsena","progress":"Pažanga","select_program":"Norėdami pamatyti išsamią informaciją, pasirinkite programą","title":"Pavadinimas","status_entity":"Būsenos subjektas","icon":"Piktograma","active_color":"Aktyvios piktogramos spalva","show_state":"Rodyti būseną","show_program":"Rodyti programą","show_details":"Rodyti išsamią informaciją","spin_icon":"Sukimo piktograma (bėgant)","program_entity":"Programos subjektas","pct_entity":"Pažangos subjektas (neprivaloma)","time_entity":"Laiko objektas (neprivaloma)","display_mode":"Ekrano režimas","show_time_remaining":"Rodyti likusį laiką","show_percentage":"Rodyti procentą","entity_not_found":"Subjektas nerastas","tap_action":"Bakstelėkite Veiksmas","hold_action":"Laikyti veiksmą","double_tap_action":"Dukart bakstelėkite veiksmas"},"lv":{"washer_program":"Mazgāšanas programma","program_placeholder":"Atlasiet Programma","duration":"Ilgums","minutes":"min","time_remaining":"Atlikušais laiks","no_prediction":"Nav prognožu","cycle_in_progress":"Notiek cikls","status":"Statuss","progress":"Progress","select_program":"Izvēlieties programmu, lai skatītu detalizētu informāciju","title":"Nosaukums","status_entity":"Statusa entītija","icon":"Ikona","active_color":"Aktīvās ikonas krāsa","show_state":"Rādīt stāvokli","show_program":"Rādīt programmu","show_details":"Rādīt detaļas","spin_icon":"Griešanās ikona (skrienot)","program_entity":"Programmas entītija","pct_entity":"Progresa entītija (neobligāti)","time_entity":"Laika entītija (neobligāti)","display_mode":"Displeja režīms","show_time_remaining":"Rādīt atlikušo laiku","show_percentage":"Rādīt procentus","entity_not_found":"Entītija nav atrasta","tap_action":"Pieskarieties darbībai","hold_action":"Aizturēt darbību","double_tap_action":"Dubultskāriena darbība"},"mk":{"washer_program":"Програма за перење","program_placeholder":"Изберете Програма","duration":"Времетраење","minutes":"мин","time_remaining":"Преостанато време","no_prediction":"Без предвидување","cycle_in_progress":"Циклус во тек","status":"Статус","progress":"Напредок","select_program":"Изберете програма за да видите детали","title":"Наслов","status_entity":"Статусен ентитет","icon":"Икона","active_color":"Активна боја на иконата","show_state":"Прикажи држава","show_program":"Прикажи програма","show_details":"Прикажи детали","spin_icon":"Икона за вртење (додека работи)","program_entity":"Програмски ентитет","pct_entity":"Ентитет за напредок (изборно)","time_entity":"Временски ентитет (изборно)","display_mode":"Режим на прикажување","show_time_remaining":"Прикажи преостанатото време","show_percentage":"Прикажи процент","entity_not_found":"Субјектот не е пронајден","tap_action":"Допрете Акција","hold_action":"Држете акција","double_tap_action":"Акција со двоен допир"},"nb":{"washer_program":"Vaskeprogram","program_placeholder":"Velg Program","duration":"Varighet","minutes":"min","time_remaining":"Gjenstående tid","no_prediction":"Ingen prediksjon","cycle_in_progress":"Syklus pågår","status":"Status","progress":"Framgang","select_program":"Velg et program for å se detaljer","title":"Tittel","status_entity":"Status Entitet","icon":"Ikon","active_color":"Aktiv ikonfarge","show_state":"Vis tilstand","show_program":"Vis program","show_details":"Vis detaljer","spin_icon":"Spinning-ikon (mens du løper)","program_entity":"Program Entitet","pct_entity":"Fremdriftsenhet (valgfritt)","time_entity":"Tidsenhet (valgfritt)","display_mode":"Visningsmodus","show_time_remaining":"Vis gjenværende tid","show_percentage":"Vis prosentandel","entity_not_found":"Enheten ble ikke funnet","tap_action":"Trykk på Handling","hold_action":"Hold handling","double_tap_action":"Dobbelttrykk på handling"},"nl":{"washer_program":"Wasprogramma","program_placeholder":"Selecteer Programma","duration":"Duur","minutes":"min","time_remaining":"Resterende tijd","no_prediction":"Geen voorspelling","cycle_in_progress":"Cyclus in uitvoering","status":"Status","progress":"Voortgang","select_program":"Selecteer een programma om details te bekijken","title":"Titel","status_entity":"Statusentiteit","icon":"Icon","active_color":"Actieve pictogramkleur","show_state":"Toon staat","show_program":"Programma weergeven","show_details":"Details tonen","spin_icon":"Draaiend pictogram (tijdens hardlopen)","program_entity":"Programma-entiteit","pct_entity":"Voortgangsentiteit (optioneel)","time_entity":"Tijdsentiteit (optioneel)","display_mode":"Weergavemodus","show_time_remaining":"Resterende tijd weergeven","show_percentage":"Percentage weergeven","entity_not_found":"Entiteit niet gevonden","tap_action":"Tik op Actie","hold_action":"Actie vasthouden","double_tap_action":"Dubbeltikactie"},"pl":{"washer_program":"Program prania","program_placeholder":"Wybierz Program","duration":"Czas trwania","minutes":"min","time_remaining":"Pozostały czas","no_prediction":"Brak przewidywania","cycle_in_progress":"Cykl w toku","status":"Status","progress":"Postęp","select_program":"Wybierz program, aby zobaczyć szczegóły","title":"Tytuł","status_entity":"Jednostka statusowa","icon":"Ikona","active_color":"Aktywny kolor ikony","show_state":"Pokaż stan","show_program":"Pokaż program","show_details":"Pokaż szczegóły","spin_icon":"Ikona obracania się (podczas biegu)","program_entity":"Jednostka programu","pct_entity":"Jednostka postępu (opcjonalnie)","time_entity":"Jednostka czasu (opcjonalnie)","display_mode":"Tryb wyświetlania","show_time_remaining":"Pokaż pozostały czas","show_percentage":"Pokaż procent","entity_not_found":"Nie znaleziono elementu","tap_action":"Kliknij Akcja","hold_action":"Wstrzymaj akcję","double_tap_action":"Akcja podwójnego dotknięcia"},"pt":{"washer_program":"Programa de lavadora","program_placeholder":"Selecione o programa","duration":"Duração","minutes":"min","time_remaining":"Tempo restante","no_prediction":"Sem previsão","cycle_in_progress":"Ciclo em andamento","status":"Status","progress":"Progresso","select_program":"Selecione um programa para ver detalhes","title":"Título","status_entity":"Entidade de status","icon":"Ícone","active_color":"Cor do ícone ativo","show_state":"Mostrar estado","show_program":"Mostrar programa","show_details":"Mostrar detalhes","spin_icon":"Ícone giratório (durante a execução)","program_entity":"Entidade do Programa","pct_entity":"Entidade de progresso (opcional)","time_entity":"Entidade de tempo (opcional)","display_mode":"Modo de exibição","show_time_remaining":"Mostrar tempo restante","show_percentage":"Mostrar porcentagem","entity_not_found":"Entidade não encontrada","tap_action":"Toque em Ação","hold_action":"Manter ação","double_tap_action":"Ação de toque duplo"},"pt-BR":{"washer_program":"Programa de lavadora","program_placeholder":"Selecione o programa","duration":"Duração","minutes":"min","time_remaining":"Tempo restante","no_prediction":"Sem previsão","cycle_in_progress":"Ciclo em andamento","status":"Status","progress":"Progresso","select_program":"Selecione um programa para ver detalhes","title":"Título","status_entity":"Entidade de status","icon":"Ícone","active_color":"Cor do ícone ativo","show_state":"Mostrar estado","show_program":"Mostrar programa","show_details":"Mostrar detalhes","spin_icon":"Ícone giratório (durante a execução)","program_entity":"Entidade do Programa","pct_entity":"Entidade de progresso (opcional)","time_entity":"Entidade de tempo (opcional)","display_mode":"Modo de exibição","show_time_remaining":"Mostrar tempo restante","show_percentage":"Mostrar porcentagem","entity_not_found":"Entidade não encontrada","tap_action":"Toque em Ação","hold_action":"Manter ação","double_tap_action":"Ação de toque duplo"},"ro":{"washer_program":"Program de spălat","program_placeholder":"Selectați Program","duration":"Durată","minutes":"min","time_remaining":"Timp rămas","no_prediction":"Fără predicție","cycle_in_progress":"Ciclu în curs","status":"Stare","progress":"Progres","select_program":"Selectați un program pentru a vedea detalii","title":"Titlu","status_entity":"Entitate de stare","icon":"Pictogramă","active_color":"Culoarea pictogramei active","show_state":"Arată stare","show_program":"Arată programul","show_details":"Afișați detalii","spin_icon":"Pictogramă care se învârte (în timpul alergării)","program_entity":"Entitatea de program","pct_entity":"Entitate de progres (opțional)","time_entity":"Entitate oră (Opțional)","display_mode":"Modul de afișare","show_time_remaining":"Arată timpul rămas","show_percentage":"Arată procentul","entity_not_found":"Entitatea nu a fost găsită","tap_action":"Atingeți Acțiune","hold_action":"Țineți Acțiune","double_tap_action":"Atingeți de două ori Acțiune"},"ru":{"washer_program":"Программа стирки","program_placeholder":"Выберите программу","duration":"Продолжительность","minutes":"мин","time_remaining":"Оставшееся время","no_prediction":"Нет прогноза","cycle_in_progress":"Цикл в процессе","status":"Статус","progress":"Прогресс","select_program":"Выберите программу, чтобы увидеть подробности","title":"Заголовок","status_entity":"Статус объекта","icon":"Икона","active_color":"Цвет активного значка","show_state":"Показать состояние","show_program":"Шоу-программа","show_details":"Показать детали","spin_icon":"Вращающийся значок (во время бега)","program_entity":"Программный объект","pct_entity":"Сущность прогресса (необязательно)","time_entity":"Сущность времени (необязательно)","display_mode":"Режим отображения","show_time_remaining":"Показать оставшееся время","show_percentage":"Показать процент","entity_not_found":"Объект не найден","tap_action":"Нажмите «Действие».","hold_action":"Удерживать действие","double_tap_action":"Двойное нажатие"},"sk":{"washer_program":"Program práčky","program_placeholder":"Vyberte položku Program","duration":"Trvanie","minutes":"min","time_remaining":"Zostávajúci čas","no_prediction":"Žiadna predpoveď","cycle_in_progress":"Prebiehajúci cyklus","status":"Stav","progress":"Pokrok","select_program":"Ak chcete zobraziť podrobnosti, vyberte program","title":"Názov","status_entity":"Stavová entita","icon":"Ikona","active_color":"Farba aktívnej ikony","show_state":"Zobraziť stav","show_program":"Zobraziť program","show_details":"Zobraziť podrobnosti","spin_icon":"Ikona otáčania (pri behu)","program_entity":"Programová entita","pct_entity":"Entita pokroku (voliteľné)","time_entity":"Časová entita (voliteľné)","display_mode":"Režim zobrazenia","show_time_remaining":"Zobraziť zostávajúci čas","show_percentage":"Zobraziť percento","entity_not_found":"Entita sa nenašla","tap_action":"Klepnite na položku Akcia","hold_action":"Hold Action","double_tap_action":"Akcia dvojitého klepnutia"},"sl":{"washer_program":"Program za pranje","program_placeholder":"Izberite Program","duration":"Trajanje","minutes":"min","time_remaining":"Preostali čas","no_prediction":"Brez napovedi","cycle_in_progress":"Cikel v teku","status":"Stanje","progress":"Napredek","select_program":"Za ogled podrobnosti izberite program","title":"Naslov","status_entity":"Statusna entiteta","icon":"Ikona","active_color":"Barva aktivne ikone","show_state":"Prikaži stanje","show_program":"Show Program","show_details":"Pokaži podrobnosti","spin_icon":"Vrteča se ikona (med tekom)","program_entity":"Programska entiteta","pct_entity":"Entiteta napredka (neobvezno)","time_entity":"Časovna entiteta (neobvezno)","display_mode":"Način prikaza","show_time_remaining":"Prikaži preostali čas","show_percentage":"Pokaži odstotek","entity_not_found":"Entiteta ni najdena","tap_action":"Tapnite Dejanje","hold_action":"Zadrži akcijo","double_tap_action":"Dejanje dvojnega dotika"},"sq":{"washer_program":"Programi i larës","program_placeholder":"Zgjidhni Programin","duration":"Kohëzgjatja","minutes":"min","time_remaining":"Koha e mbetur","no_prediction":"Asnjë Parashikim","cycle_in_progress":"Cikli në vazhdim","status":"Statusi","progress":"Përparim","select_program":"Zgjidhni një program për të parë detajet","title":"Titulli","status_entity":"Entiteti i statusit","icon":"Ikona","active_color":"Ngjyra e ikonës aktive","show_state":"Trego shtetin","show_program":"Shfaq programin","show_details":"Shfaq Detajet","spin_icon":"Ikona rrotulluese (Gjatë funksionimit)","program_entity":"Subjekti i programit","pct_entity":"Entiteti i progresit (opsionale)","time_entity":"Entiteti i kohës (opsionale)","display_mode":"Modaliteti i shfaqjes","show_time_remaining":"Shfaq kohën e mbetur","show_percentage":"Shfaq përqindjen","entity_not_found":"Subjekti nuk u gjet","tap_action":"Prekni Veprim","hold_action":"Mbajeni veprimin","double_tap_action":"Veprimi i prekjes së dyfishtë"},"sr-Latn":{"washer_program":"Program pranja","program_placeholder":"Izaberi program","duration":"Trajanje","minutes":"min","time_remaining":"Preostalo vreme","no_prediction":"Nema procene","cycle_in_progress":"Ciklus je u toku","status":"Status","progress":"Napredak","select_program":"Izaberite program da vidite detalje","title":"Naslov","status_entity":"Entitet statusa","icon":"Ikona","active_color":"Boja aktivne ikone","show_state":"Prikaži stanje","show_program":"Prikaži program","show_details":"Prikaži detalje","spin_icon":"Rotirajuća ikona (dok radi)","program_entity":"Entitet programa","pct_entity":"Entitet napretka (opciono)","time_entity":"Entitet vremena (opciono)","display_mode":"Režim prikaza","show_time_remaining":"Prikaži preostalo vreme","show_percentage":"Prikaži procenat","entity_not_found":"Entitet nije pronađen","tap_action":"Radnja na dodir","hold_action":"Radnja na zadržavanje","double_tap_action":"Radnja na dvostruki dodir"},"sv":{"washer_program":"Tvättprogram","program_placeholder":"Välj Program","duration":"Varaktighet","minutes":"min","time_remaining":"Återstående tid","no_prediction":"Ingen förutsägelse","cycle_in_progress":"Cykel pågår","status":"Status","progress":"Framsteg","select_program":"Välj ett program för att se detaljer","title":"Titel","status_entity":"Status Entitet","icon":"Ikon","active_color":"Aktiv ikonfärg","show_state":"Visa tillstånd","show_program":"Visa program","show_details":"Visa detaljer","spin_icon":"Spinning-ikon (medan du springer)","program_entity":"Program Entitet","pct_entity":"Progress Entity (valfritt)","time_entity":"Tidsenhet (valfritt)","display_mode":"Visningsläge","show_time_remaining":"Visa återstående tid","show_percentage":"Visa procent","entity_not_found":"Enheten hittades inte","tap_action":"Tryck på Åtgärd","hold_action":"Håll Action","double_tap_action":"Dubbeltrycksåtgärd"},"tr":{"washer_program":"Yıkama Programı","program_placeholder":"Program Seç","duration":"Süre","minutes":"dk.","time_remaining":"Kalan Süre","no_prediction":"Tahmin Yok","cycle_in_progress":"Döngü devam ediyor","status":"Durum","progress":"İlerlemek","select_program":"Ayrıntıları görmek için bir program seçin","title":"Başlık","status_entity":"Durum Varlığı","icon":"Simge","active_color":"Etkin Simge Rengi","show_state":"Durumu Göster","show_program":"Programı Göster","show_details":"Ayrıntıları Göster","spin_icon":"Dönen Simge (Koşarken)","program_entity":"Program Varlığı","pct_entity":"İlerleme Varlığı (İsteğe bağlı)","time_entity":"Zaman Varlığı (İsteğe Bağlı)","display_mode":"Ekran Modu","show_time_remaining":"Kalan Süreyi Göster","show_percentage":"Yüzdeyi Göster","entity_not_found":"Varlık bulunamadı","tap_action":"Eylem'e dokunun","hold_action":"Eylemi Beklet","double_tap_action":"Çift Dokunma Eylemi"},"uk":{"washer_program":"Програма прання","program_placeholder":"Виберіть програму","duration":"Тривалість","minutes":"хв","time_remaining":"Час, що залишився","no_prediction":"Без передбачення","cycle_in_progress":"Цикл триває","status":"Статус","progress":"Прогрес","select_program":"Виберіть програму, щоб переглянути деталі","title":"Назва","status_entity":"Status Entity","icon":"значок","active_color":"Активний колір значка","show_state":"Показати стан","show_program":"Шоу програма","show_details":"Показати деталі","spin_icon":"Піктограма обертання (під час бігу)","program_entity":"Програмна сутність","pct_entity":"Сутність прогресу (необов'язково)","time_entity":"Сутність часу (необов’язково)","display_mode":"Режим відображення","show_time_remaining":"Показати час, що залишився","show_percentage":"Показати відсоток","entity_not_found":"Об'єкт не знайдено","tap_action":"Натисніть Дія","hold_action":"Дія утримання","double_tap_action":"Подвійне торкання"},"zh-Hans":{"washer_program":"清洗程序","program_placeholder":"选择节目","duration":"期间","minutes":"分钟","time_remaining":"剩余时间","no_prediction":"没有预测","cycle_in_progress":"循环正在进行中","status":"地位","progress":"进步","select_program":"选择一个程序以查看详细信息","title":"标题","status_entity":"状态实体","icon":"图标","active_color":"活动图标颜色","show_state":"显示状态","show_program":"演出节目","show_details":"显示详情","spin_icon":"旋转图标(运行时)","program_entity":"程序实体","pct_entity":"进度实体(可选)","time_entity":"时间实体(可选)","display_mode":"显示模式","show_time_remaining":"显示剩余时间","show_percentage":"显示百分比","entity_not_found":"未找到实体","tap_action":"点击操作","hold_action":"保持行动","double_tap_action":"双击操作"}}; class WashDataCard extends HTMLElement { _resolveLanguage() { const raw = (this._hass && this._hass.locale && this._hass.locale.language) || (this._hass && this._hass.language) || "en"; if (!raw || typeof raw !== "string") return "en"; return raw; } static getStubConfig() { return { entity: "sensor.washing_machine_state", title: "Washing Machine", icon: "mdi:washing-machine", display_mode: "time", active_color: [33, 150, 243], show_state: true, show_program: true, show_details: true, spin_icon: true, tap_action: { action: "more-info" }, hold_action: { action: "none" }, double_tap_action: { action: "none" } }; } static getConfigElement() { return document.createElement(EDITOR_TAG); } _getTranslation(key) { const lang = this._resolveLanguage(); const baseLang = lang.split("-")[0]; const translations = TRANSLATIONS[lang] || TRANSLATIONS[baseLang] || TRANSLATIONS["en"]; return translations[key] || TRANSLATIONS["en"][key] || key; } constructor() { super(); this.attachShadow({ mode: "open" }); this._rendered = false; // Gesture state for tap / hold / double-tap recognition. this._holdTimer = null; this._holdTriggered = false; this._tapTimer = null; this._lastTapTime = 0; this._pointerStart = null; this._onPointerDown = this._onPointerDown.bind(this); this._onPointerMove = this._onPointerMove.bind(this); this._onPointerUp = this._onPointerUp.bind(this); this._onPointerCancel = this._onPointerCancel.bind(this); } disconnectedCallback() { // Avoid stray actions firing after the card is removed from the DOM. this._clearHoldTimer(); if (this._tapTimer) { window.clearTimeout(this._tapTimer); this._tapTimer = null; } } setConfig(config) { if (!config.entity) { throw new Error("Please define an entity"); } this._cfg = { ...WashDataCard.getStubConfig(), ...config }; this._render(); } set hass(hass) { this._hass = hass; this._update(); } getCardSize() { return 1; } _clearHoldTimer() { if (this._holdTimer) { window.clearTimeout(this._holdTimer); this._holdTimer = null; } } _onPointerDown(ev) { // Only react to the primary pointer (left mouse button / touch / pen). if (ev.button !== undefined && ev.button !== 0) return; this._holdTriggered = false; this._pointerCanceled = false; this._pointerStart = { x: ev.clientX, y: ev.clientY }; const holdCfg = this._cfg && this._cfg.hold_action; if (holdCfg && holdCfg.action && holdCfg.action !== "none") { this._clearHoldTimer(); this._holdTimer = window.setTimeout(() => { this._holdTimer = null; this._holdTriggered = true; this._fireHaptic("success"); this._executeAction(holdCfg); }, HOLD_MS); } } _onPointerMove(ev) { // Cancel the gesture if the pointer drifts (e.g. the user is scrolling), so // neither the pending hold nor the release-tap fires. if (!this._pointerStart) return; const dx = ev.clientX - this._pointerStart.x; const dy = ev.clientY - this._pointerStart.y; if (dx * dx + dy * dy > TAP_MOVE_TOLERANCE * TAP_MOVE_TOLERANCE) { this._clearHoldTimer(); this._pointerStart = null; this._pointerCanceled = true; } } _onPointerCancel() { this._clearHoldTimer(); } _onPointerUp() { this._clearHoldTimer(); // The pointer drifted (scroll/drag): the release should not count as a tap. if (this._pointerCanceled) { this._pointerCanceled = false; return; } // A hold already fired its action; the release should not also count as a tap. if (this._holdTriggered) { this._holdTriggered = false; return; } const tapCfg = (this._cfg && this._cfg.tap_action) || { action: "more-info" }; const doubleCfg = this._cfg && this._cfg.double_tap_action; const hasDouble = doubleCfg && doubleCfg.action && doubleCfg.action !== "none"; // With no double-tap action configured, fire the tap immediately (no latency). if (!hasDouble) { this._executeAction(tapCfg); return; } const now = Date.now(); if (this._tapTimer && now - this._lastTapTime < DOUBLE_TAP_MS) { window.clearTimeout(this._tapTimer); this._tapTimer = null; this._lastTapTime = 0; this._executeAction(doubleCfg); return; } // First tap: wait briefly to see whether a second one arrives. this._lastTapTime = now; this._tapTimer = window.setTimeout(() => { this._tapTimer = null; this._executeAction(tapCfg); }, DOUBLE_TAP_MS); } _fireHaptic(type) { this.dispatchEvent(new CustomEvent("haptic", { detail: type, bubbles: true, composed: true, })); } _executeAction(actionCfg) { if (!actionCfg) return; const action = actionCfg.action || "more-info"; const entityId = actionCfg.entity || (this._cfg && this._cfg.entity); switch (action) { case "none": return; case "more-info": { if (!entityId) return; this.dispatchEvent(new CustomEvent("hass-more-info", { detail: { entityId }, bubbles: true, composed: true, })); return; } case "toggle": { // homeassistant.toggle routes to the correct domain service for all // common toggleable domains, so no per-domain table is needed. if (!this._hass || !entityId) return; this._hass.callService("homeassistant", "toggle", { entity_id: entityId }); return; } case "call-service": case "perform-action": { const svc = actionCfg.perform_action || actionCfg.service; if (!svc || !this._hass) return; const [svcDomain, svcName] = svc.split("."); if (!svcDomain || !svcName) return; const data = { ...(actionCfg.data || actionCfg.service_data || {}) }; this._hass.callService(svcDomain, svcName, data, actionCfg.target); return; } case "navigate": { const path = actionCfg.navigation_path; if (!path) return; if (actionCfg.navigation_replace) { window.history.replaceState(window.history.state, "", path); } else { window.history.pushState(null, "", path); } window.dispatchEvent(new CustomEvent("location-changed", { detail: { replace: !!actionCfg.navigation_replace }, })); return; } case "url": { const url = actionCfg.url_path; if (!url) return; // noopener/noreferrer prevents the opened page from reaching back via // window.opener (reverse tabnabbing). window.open(url, "_blank", "noopener,noreferrer"); return; } default: // Unsupported actions (e.g. "assist") are intentionally ignored: a // standalone card resource cannot resolve Home Assistant's internal // dialog chunks, so attempting them would only throw at runtime. return; } } _render() { if (!this.shadowRoot) return; // Only create the DOM once to avoid memory leaks from duplicate event listeners if (!this._rendered) { this.shadowRoot.innerHTML = `
`; const cardEl = this.shadowRoot.getElementById("card"); cardEl.addEventListener("pointerdown", this._onPointerDown); cardEl.addEventListener("pointermove", this._onPointerMove); cardEl.addEventListener("pointerup", this._onPointerUp); cardEl.addEventListener("pointercancel", this._onPointerCancel); cardEl.addEventListener("pointerleave", this._onPointerCancel); this._rendered = true; } this._update(); } _update() { if (!this.shadowRoot || !this._hass || !this._cfg) return; const entityId = this._cfg.entity; const stateObj = this._hass.states[entityId]; const titleEl = this.shadowRoot.getElementById("title"); const stateEl = this.shadowRoot.getElementById("state"); const iconEl = this.shadowRoot.getElementById("icon"); const iconContainer = this.shadowRoot.getElementById("icon-container"); if (!stateObj) { if (titleEl) titleEl.textContent = this._getTranslation("entity_not_found"); if (stateEl) stateEl.textContent = entityId; return; } const title = this._cfg.title || "Washing Machine"; const icon = this._cfg.icon || stateObj.attributes.icon || "mdi:washing-machine"; const activeColor = this._cfg.active_color; const state = stateObj.state; // Treat as inactive if off, unknown, unavailable, idle const isInactive = ['off', 'unknown', 'unavailable', 'idle'].includes(state.toLowerCase()); if (isInactive) { iconContainer.style.background = `rgba(128, 128, 128, 0.1)`; iconContainer.style.color = `var(--disabled-text-color, grey)`; } else { let colorCss = "var(--primary-color)"; let bgCss = "rgba(var(--rgb-primary-color, 33, 150, 243), 0.2)"; if (Array.isArray(activeColor)) { const [r, g, b] = activeColor; colorCss = `rgb(${r}, ${g}, ${b})`; bgCss = `rgba(${r}, ${g}, ${b}, 0.2)`; } else if (activeColor) { colorCss = activeColor; bgCss = `rgba(128, 128, 128, 0.15)`; } iconContainer.style.color = colorCss; iconContainer.style.background = bgCss; } iconEl.setAttribute("icon", icon); if (state.toLowerCase() === 'running' && this._cfg.spin_icon !== false) { iconEl.classList.add("spinning"); } else { iconEl.classList.remove("spinning"); } titleEl.textContent = title; const attr = stateObj.attributes; const parts = []; // 1. State / Sub-State // Default show_state to true if undefined if (this._cfg.show_state !== false) { if (state.toLowerCase() === 'running') { const subState = attr.sub_state; if (subState) { // If sub_state is "Running (Rinsing)", extract "Rinsing" const match = subState.match(/Running \((.*)\)/); if (match && match[1]) { parts.push(match[1]); } else { parts.push(subState); } } // If no sub_state (or just "Running"), we show NOTHING (redundant) } else { // Not running (e.g. Off, Completed, etc) - show standard state parts.push(state.charAt(0).toUpperCase() + state.slice(1)); } } // 2. Program if (this._cfg.show_program !== false) { let program = ""; if (this._cfg.program_entity) { const progState = this._hass.states[this._cfg.program_entity]; if (progState) program = progState.state; } else if (attr.program) { program = attr.program; } if (program && !["unknown", "none", "off", "unavailable"].includes(program.toLowerCase())) { parts.push(program); } } // 3. Details (Time / Pct) if (this._cfg.show_details !== false && !isInactive) { let remaining = ""; if (this._cfg.time_entity) { remaining = this._hass.states[this._cfg.time_entity]?.state; } else if (attr.time_remaining) { remaining = attr.time_remaining; } let pct = ""; if (this._cfg.pct_entity) { pct = this._hass.states[this._cfg.pct_entity]?.state; } else if (attr.cycle_progress) { pct = attr.cycle_progress; } if (this._cfg.display_mode === 'percentage' && pct) { parts.push(`${Math.round(pct)}%`); } else if (remaining) { // Append 'min' if it is a number (WashData attribute is raw minutes) if (!isNaN(remaining)) { parts.push(`${remaining} ${this._getTranslation("minutes")}`); } else { parts.push(remaining); } } } stateEl.textContent = parts.length > 0 ? parts.join(" • ") : ""; } } class WashDataCardEditor extends HTMLElement { _resolveLanguage() { const raw = (this._hass && this._hass.locale && this._hass.locale.language) || (this._hass && this._hass.language) || "en"; if (!raw || typeof raw !== "string") return "en"; return raw; } _getTranslation(key) { const lang = this._resolveLanguage(); const baseLang = lang.split("-")[0]; const translations = TRANSLATIONS[lang] || TRANSLATIONS[baseLang] || TRANSLATIONS["en"]; return translations[key] || TRANSLATIONS["en"][key] || key; } setConfig(config) { this._cfg = { ...WashDataCard.getStubConfig(), ...config }; this._render(); } set hass(hass) { this._hass = hass; if (this._form) { this._form.hass = hass; } } _render() { if (!this.shadowRoot) { this.attachShadow({ mode: "open" }); } if (!this._form) { this.shadowRoot.innerHTML = `
`; this._form = document.createElement("ha-form"); this.shadowRoot.getElementById("editor-container").appendChild(this._form); this._form.addEventListener("value-changed", (ev) => this._valueChanged(ev)); this._form.schema = [ { name: "title", selector: { text: {} } }, { name: "entity", selector: { entity: { domain: "sensor" } } }, { name: "icon", selector: { icon: {} } }, { name: "active_color", selector: { color_rgb: {} } }, { name: "show_state", selector: { boolean: {} } }, { name: "show_program", selector: { boolean: {} } }, { name: "show_details", selector: { boolean: {} } }, { name: "spin_icon", selector: { boolean: {} } }, { name: "display_mode", selector: { select: { options: [ { value: "time", label: this._getTranslation("show_time_remaining") }, { value: "percentage", label: this._getTranslation("show_percentage") } ], mode: "dropdown" } } }, { name: "program_entity", selector: { entity: { domain: ["sensor", "select", "input_select", "input_text"] } } }, { name: "pct_entity", selector: { entity: { domain: "sensor" } } }, { name: "time_entity", selector: { entity: { domain: "sensor" } } }, { name: "tap_action", selector: { ui_action: {} } }, { name: "hold_action", selector: { ui_action: {} } }, { name: "double_tap_action", selector: { ui_action: {} } }, ]; this._form.computeLabel = (schema) => { const labels = { title: this._getTranslation("title"), entity: this._getTranslation("status_entity"), icon: this._getTranslation("icon"), active_color: this._getTranslation("active_color"), show_state: this._getTranslation("show_state"), show_program: this._getTranslation("show_program"), show_details: this._getTranslation("show_details"), spin_icon: this._getTranslation("spin_icon"), program_entity: this._getTranslation("program_entity"), pct_entity: this._getTranslation("pct_entity"), time_entity: this._getTranslation("time_entity"), display_mode: this._getTranslation("display_mode"), tap_action: this._getTranslation("tap_action"), hold_action: this._getTranslation("hold_action"), double_tap_action: this._getTranslation("double_tap_action") }; return labels[schema.name] || schema.name; }; } this._form.data = this._cfg; if (this._hass) { this._form.hass = this._hass; } } _valueChanged(ev) { if (!this._cfg || !this._hass) return; const val = ev.detail.value; this._cfg = { ...this._cfg, ...val }; const event = new CustomEvent("config-changed", { detail: { config: this._cfg }, bubbles: true, composed: true, }); this.dispatchEvent(event); } } customElements.define(CARD_TAG, WashDataCard); customElements.define(EDITOR_TAG, WashDataCardEditor); window.customCards = window.customCards || []; window.customCards.push({ type: CARD_TAG, name: "WashData Tile Card", preview: true, description: "A compact tile-style card for washing machines.", });