diff --git a/admin/i18n/de.json b/admin/i18n/de.json index f0b008d..23b0c5f 100644 --- a/admin/i18n/de.json +++ b/admin/i18n/de.json @@ -8,5 +8,7 @@ "Exclude patterns (one per line)": "Filter-Patterns (eines pro Zeile)", "Glob patterns, * wildcard. Lines starting with # are comments. Empty = filter off.": "Glob-Patterns mit * als Wildcard. Zeilen mit # sind Kommentare. Leer = Filter aus.", "Verbose filter logging": "Ausführliches Filter-Logging", - "When enabled, log each excluded entity_id individually during the initial adapter sync (requires loglevel info or debug).": "Wenn aktiv: jede ausgeschlossene entity_id wird beim initialen Adapter-Sync einzeln geloggt (benötigt Loglevel info oder debug)." -} \ No newline at end of file + "When enabled, log each excluded entity_id individually during the initial adapter sync (requires loglevel info or debug).": "Wenn aktiv: jede ausgeschlossene entity_id wird beim initialen Adapter-Sync einzeln geloggt (benötigt Loglevel info oder debug).", + "Cleanup excluded entities on adapter start": "Ausgefilterte Entitäten beim Adapter-Start löschen", + "When enabled, on each adapter start delete existing objects under entities.* whose entity_id matches the exclude patterns. Objects with custom adapter config (history/influxdb/sql) are kept and logged.": "Wenn aktiv: bei jedem Adapter-Start werden vorhandene Objekte unter entities.*, deren entity_id auf die Filter-Patterns matched, gelöscht. Objekte mit Custom-Adapter-Konfiguration (history/influxdb/sql) bleiben erhalten und werden geloggt." +} diff --git a/admin/i18n/en.json b/admin/i18n/en.json index 307dd24..8724b5b 100644 --- a/admin/i18n/en.json +++ b/admin/i18n/en.json @@ -8,5 +8,7 @@ "Exclude patterns (one per line)": "Exclude patterns (one per line)", "Glob patterns, * wildcard. Lines starting with # are comments. Empty = filter off.": "Glob patterns, * wildcard. Lines starting with # are comments. Empty = filter off.", "Verbose filter logging": "Verbose filter logging", - "When enabled, log each excluded entity_id individually during the initial adapter sync (requires loglevel info or debug).": "When enabled, log each excluded entity_id individually during the initial adapter sync (requires loglevel info or debug)." -} \ No newline at end of file + "When enabled, log each excluded entity_id individually during the initial adapter sync (requires loglevel info or debug).": "When enabled, log each excluded entity_id individually during the initial adapter sync (requires loglevel info or debug).", + "Cleanup excluded entities on adapter start": "Cleanup excluded entities on adapter start", + "When enabled, on each adapter start delete existing objects under entities.* whose entity_id matches the exclude patterns. Objects with custom adapter config (history/influxdb/sql) are kept and logged.": "When enabled, on each adapter start delete existing objects under entities.* whose entity_id matches the exclude patterns. Objects with custom adapter config (history/influxdb/sql) are kept and logged." +} diff --git a/admin/i18n/es.json b/admin/i18n/es.json index 712e053..c02c44e 100644 --- a/admin/i18n/es.json +++ b/admin/i18n/es.json @@ -8,5 +8,7 @@ "Exclude patterns (one per line)": "Patrones de exclusión (uno por línea)", "Glob patterns, * wildcard. Lines starting with # are comments. Empty = filter off.": "Patrones glob, * como comodín. Las líneas que empiezan con # son comentarios. Vacío = filtro desactivado.", "Verbose filter logging": "Registro detallado del filtro", - "When enabled, log each excluded entity_id individually during the initial adapter sync (requires loglevel info or debug).": "Cuando está activado, cada entity_id excluido se registra individualmente durante la sincronización inicial del adaptador (requiere loglevel info o debug)." -} \ No newline at end of file + "When enabled, log each excluded entity_id individually during the initial adapter sync (requires loglevel info or debug).": "Cuando está activado, cada entity_id excluido se registra individualmente durante la sincronización inicial del adaptador (requiere loglevel info o debug).", + "Cleanup excluded entities on adapter start": "Cleanup excluded entities on adapter start", + "When enabled, on each adapter start delete existing objects under entities.* whose entity_id matches the exclude patterns. Objects with custom adapter config (history/influxdb/sql) are kept and logged.": "When enabled, on each adapter start delete existing objects under entities.* whose entity_id matches the exclude patterns. Objects with custom adapter config (history/influxdb/sql) are kept and logged." +} diff --git a/admin/i18n/fr.json b/admin/i18n/fr.json index 9a042de..efe89e3 100644 --- a/admin/i18n/fr.json +++ b/admin/i18n/fr.json @@ -1,12 +1,14 @@ { - "Home assistant IP": "IP de l'assistant à domicile ", - "Home assistant WS Port": "Port WS de l'assistant domestique ", - "Password repeat": "Répéter le mot de passe ", + "Home assistant IP": "IP de l'assistant à domicile ", + "Home assistant WS Port": "Port WS de l'assistant domestique ", + "Password repeat": "Répéter le mot de passe ", "Password": "Mot de passe", - "Passwords missmatch!": "Les mots de passe ne correspondent pas !", + "Passwords missmatch!": "Les mots de passe ne correspondent pas !", "Secure": "HTTPS ?", "Exclude patterns (one per line)": "Modèles d'exclusion (un par ligne)", "Glob patterns, * wildcard. Lines starting with # are comments. Empty = filter off.": "Modèles glob, * comme joker. Les lignes commençant par # sont des commentaires. Vide = filtre désactivé.", "Verbose filter logging": "Journalisation détaillée du filtre", - "When enabled, log each excluded entity_id individually during the initial adapter sync (requires loglevel info or debug).": "Lorsqu'activé, chaque entity_id exclu est journalisé individuellement pendant la synchronisation initiale de l'adaptateur (nécessite loglevel info ou debug)." -} \ No newline at end of file + "When enabled, log each excluded entity_id individually during the initial adapter sync (requires loglevel info or debug).": "Lorsqu'activé, chaque entity_id exclu est journalisé individuellement pendant la synchronisation initiale de l'adaptateur (nécessite loglevel info ou debug).", + "Cleanup excluded entities on adapter start": "Cleanup excluded entities on adapter start", + "When enabled, on each adapter start delete existing objects under entities.* whose entity_id matches the exclude patterns. Objects with custom adapter config (history/influxdb/sql) are kept and logged.": "When enabled, on each adapter start delete existing objects under entities.* whose entity_id matches the exclude patterns. Objects with custom adapter config (history/influxdb/sql) are kept and logged." +} diff --git a/admin/i18n/it.json b/admin/i18n/it.json index d8c812b..0bc1bf3 100644 --- a/admin/i18n/it.json +++ b/admin/i18n/it.json @@ -8,5 +8,7 @@ "Exclude patterns (one per line)": "Pattern di esclusione (uno per riga)", "Glob patterns, * wildcard. Lines starting with # are comments. Empty = filter off.": "Pattern glob, * come wildcard. Le righe che iniziano con # sono commenti. Vuoto = filtro disattivato.", "Verbose filter logging": "Logging dettagliato del filtro", - "When enabled, log each excluded entity_id individually during the initial adapter sync (requires loglevel info or debug).": "Se attivato, registra ogni entity_id escluso individualmente durante la sincronizzazione iniziale dell'adattatore (richiede loglevel info o debug)." -} \ No newline at end of file + "When enabled, log each excluded entity_id individually during the initial adapter sync (requires loglevel info or debug).": "Se attivato, registra ogni entity_id escluso individualmente durante la sincronizzazione iniziale dell'adattatore (richiede loglevel info o debug).", + "Cleanup excluded entities on adapter start": "Cleanup excluded entities on adapter start", + "When enabled, on each adapter start delete existing objects under entities.* whose entity_id matches the exclude patterns. Objects with custom adapter config (history/influxdb/sql) are kept and logged.": "When enabled, on each adapter start delete existing objects under entities.* whose entity_id matches the exclude patterns. Objects with custom adapter config (history/influxdb/sql) are kept and logged." +} diff --git a/admin/i18n/nl.json b/admin/i18n/nl.json index 8c69b91..2fa44e1 100644 --- a/admin/i18n/nl.json +++ b/admin/i18n/nl.json @@ -8,5 +8,7 @@ "Exclude patterns (one per line)": "Uitsluitpatronen (één per regel)", "Glob patterns, * wildcard. Lines starting with # are comments. Empty = filter off.": "Glob-patronen, * als wildcard. Regels die beginnen met # zijn commentaar. Leeg = filter uit.", "Verbose filter logging": "Uitgebreide filterlogging", - "When enabled, log each excluded entity_id individually during the initial adapter sync (requires loglevel info or debug).": "Indien ingeschakeld, wordt elke uitgesloten entity_id afzonderlijk gelogd tijdens de initiële adapter-synchronisatie (vereist loglevel info of debug)." -} \ No newline at end of file + "When enabled, log each excluded entity_id individually during the initial adapter sync (requires loglevel info or debug).": "Indien ingeschakeld, wordt elke uitgesloten entity_id afzonderlijk gelogd tijdens de initiële adapter-synchronisatie (vereist loglevel info of debug).", + "Cleanup excluded entities on adapter start": "Cleanup excluded entities on adapter start", + "When enabled, on each adapter start delete existing objects under entities.* whose entity_id matches the exclude patterns. Objects with custom adapter config (history/influxdb/sql) are kept and logged.": "When enabled, on each adapter start delete existing objects under entities.* whose entity_id matches the exclude patterns. Objects with custom adapter config (history/influxdb/sql) are kept and logged." +} diff --git a/admin/i18n/pl.json b/admin/i18n/pl.json index 5c79d78..dba6e9d 100644 --- a/admin/i18n/pl.json +++ b/admin/i18n/pl.json @@ -8,5 +8,7 @@ "Exclude patterns (one per line)": "Wzorce wykluczeń (jeden na linię)", "Glob patterns, * wildcard. Lines starting with # are comments. Empty = filter off.": "Wzorce glob, * jako symbol wieloznaczny. Linie zaczynające się od # to komentarze. Puste = filtr wyłączony.", "Verbose filter logging": "Szczegółowe logowanie filtra", - "When enabled, log each excluded entity_id individually during the initial adapter sync (requires loglevel info or debug).": "Gdy włączone, każde wykluczone entity_id jest logowane osobno podczas początkowej synchronizacji adaptera (wymaga poziomu logowania info lub debug)." -} \ No newline at end of file + "When enabled, log each excluded entity_id individually during the initial adapter sync (requires loglevel info or debug).": "Gdy włączone, każde wykluczone entity_id jest logowane osobno podczas początkowej synchronizacji adaptera (wymaga poziomu logowania info lub debug).", + "Cleanup excluded entities on adapter start": "Cleanup excluded entities on adapter start", + "When enabled, on each adapter start delete existing objects under entities.* whose entity_id matches the exclude patterns. Objects with custom adapter config (history/influxdb/sql) are kept and logged.": "When enabled, on each adapter start delete existing objects under entities.* whose entity_id matches the exclude patterns. Objects with custom adapter config (history/influxdb/sql) are kept and logged." +} diff --git a/admin/i18n/pt.json b/admin/i18n/pt.json index 8c67662..c693c1a 100644 --- a/admin/i18n/pt.json +++ b/admin/i18n/pt.json @@ -8,5 +8,7 @@ "Exclude patterns (one per line)": "Padrões de exclusão (um por linha)", "Glob patterns, * wildcard. Lines starting with # are comments. Empty = filter off.": "Padrões glob, * como wildcard. Linhas começando com # são comentários. Vazio = filtro desligado.", "Verbose filter logging": "Registro detalhado do filtro", - "When enabled, log each excluded entity_id individually during the initial adapter sync (requires loglevel info or debug).": "Quando ativado, cada entity_id excluído é registrado individualmente durante a sincronização inicial do adaptador (requer loglevel info ou debug)." -} \ No newline at end of file + "When enabled, log each excluded entity_id individually during the initial adapter sync (requires loglevel info or debug).": "Quando ativado, cada entity_id excluído é registrado individualmente durante a sincronização inicial do adaptador (requer loglevel info ou debug).", + "Cleanup excluded entities on adapter start": "Cleanup excluded entities on adapter start", + "When enabled, on each adapter start delete existing objects under entities.* whose entity_id matches the exclude patterns. Objects with custom adapter config (history/influxdb/sql) are kept and logged.": "When enabled, on each adapter start delete existing objects under entities.* whose entity_id matches the exclude patterns. Objects with custom adapter config (history/influxdb/sql) are kept and logged." +} diff --git a/admin/i18n/ru.json b/admin/i18n/ru.json index 7f3f987..b4a9107 100644 --- a/admin/i18n/ru.json +++ b/admin/i18n/ru.json @@ -8,5 +8,7 @@ "Exclude patterns (one per line)": "Шаблоны исключения (по одному на строку)", "Glob patterns, * wildcard. Lines starting with # are comments. Empty = filter off.": "Glob-шаблоны, * — подстановочный знак. Строки, начинающиеся с #, являются комментариями. Пусто = фильтр выключен.", "Verbose filter logging": "Подробное логирование фильтра", - "When enabled, log each excluded entity_id individually during the initial adapter sync (requires loglevel info or debug).": "Когда включено, каждый исключённый entity_id логируется отдельно во время начальной синхронизации адаптера (требуется loglevel info или debug)." -} \ No newline at end of file + "When enabled, log each excluded entity_id individually during the initial adapter sync (requires loglevel info or debug).": "Когда включено, каждый исключённый entity_id логируется отдельно во время начальной синхронизации адаптера (требуется loglevel info или debug).", + "Cleanup excluded entities on adapter start": "Cleanup excluded entities on adapter start", + "When enabled, on each adapter start delete existing objects under entities.* whose entity_id matches the exclude patterns. Objects with custom adapter config (history/influxdb/sql) are kept and logged.": "When enabled, on each adapter start delete existing objects under entities.* whose entity_id matches the exclude patterns. Objects with custom adapter config (history/influxdb/sql) are kept and logged." +} diff --git a/admin/i18n/uk.json b/admin/i18n/uk.json index aa15ae0..ecc21c0 100644 --- a/admin/i18n/uk.json +++ b/admin/i18n/uk.json @@ -8,5 +8,7 @@ "Exclude patterns (one per line)": "Шаблони виключення (по одному в рядку)", "Glob patterns, * wildcard. Lines starting with # are comments. Empty = filter off.": "Glob-шаблони, * — підстановочний знак. Рядки, що починаються з #, є коментарями. Порожньо = фільтр вимкнено.", "Verbose filter logging": "Детальне логування фільтра", - "When enabled, log each excluded entity_id individually during the initial adapter sync (requires loglevel info or debug).": "Коли увімкнено, кожен виключений entity_id логується окремо під час початкової синхронізації адаптера (потрібен loglevel info або debug)." -} \ No newline at end of file + "When enabled, log each excluded entity_id individually during the initial adapter sync (requires loglevel info or debug).": "Коли увімкнено, кожен виключений entity_id логується окремо під час початкової синхронізації адаптера (потрібен loglevel info або debug).", + "Cleanup excluded entities on adapter start": "Cleanup excluded entities on adapter start", + "When enabled, on each adapter start delete existing objects under entities.* whose entity_id matches the exclude patterns. Objects with custom adapter config (history/influxdb/sql) are kept and logged.": "When enabled, on each adapter start delete existing objects under entities.* whose entity_id matches the exclude patterns. Objects with custom adapter config (history/influxdb/sql) are kept and logged." +} diff --git a/admin/i18n/zh-cn.json b/admin/i18n/zh-cn.json index 926adaf..cb0785f 100644 --- a/admin/i18n/zh-cn.json +++ b/admin/i18n/zh-cn.json @@ -8,5 +8,7 @@ "Exclude patterns (one per line)": "排除模式(每行一个)", "Glob patterns, * wildcard. Lines starting with # are comments. Empty = filter off.": "Glob 模式,* 通配符。以 # 开头的行是注释。为空 = 过滤器关闭。", "Verbose filter logging": "详细过滤器日志", - "When enabled, log each excluded entity_id individually during the initial adapter sync (requires loglevel info or debug).": "启用后,在适配器初始同步期间单独记录每个被排除的 entity_id(需要日志级别 info 或 debug)。" -} \ No newline at end of file + "When enabled, log each excluded entity_id individually during the initial adapter sync (requires loglevel info or debug).": "启用后,在适配器初始同步期间单独记录每个被排除的 entity_id(需要日志级别 info 或 debug)。", + "Cleanup excluded entities on adapter start": "Cleanup excluded entities on adapter start", + "When enabled, on each adapter start delete existing objects under entities.* whose entity_id matches the exclude patterns. Objects with custom adapter config (history/influxdb/sql) are kept and logged.": "When enabled, on each adapter start delete existing objects under entities.* whose entity_id matches the exclude patterns. Objects with custom adapter config (history/influxdb/sql) are kept and logged." +} diff --git a/admin/jsonConfig.json b/admin/jsonConfig.json index c320740..89b49a3 100644 --- a/admin/jsonConfig.json +++ b/admin/jsonConfig.json @@ -55,6 +55,12 @@ "label": "Verbose filter logging", "help": "When enabled, log each excluded entity_id individually during the initial adapter sync (requires loglevel info or debug).", "sm": 12 + }, + "cleanupExcludedOnStart": { + "type": "checkbox", + "label": "Cleanup excluded entities on adapter start", + "help": "When enabled, on each adapter start delete existing objects under entities.* whose entity_id matches the exclude patterns. Objects with custom adapter config (history/influxdb/sql) are kept and logged.", + "sm": 12 } } } diff --git a/io-package.json b/io-package.json index dd74f9c..938c86c 100644 --- a/io-package.json +++ b/io-package.json @@ -254,7 +254,8 @@ "password": "", "secure": false, "excludePatterns": "# Glob patterns, one per line. Lines starting with # are comments.\n# Example: filter out all entities prefixed with `iob_` regardless of domain:\n# *.iob_*", - "verboseFilterLog": false + "verboseFilterLog": false, + "cleanupExcludedOnStart": false }, "protectedNative": [ "password" diff --git a/src/main.ts b/src/main.ts index 2826c08..875dbba 100644 --- a/src/main.ts +++ b/src/main.ts @@ -9,6 +9,7 @@ interface HassAdapterConfig { secure: boolean; excludePatterns: string; verboseFilterLog: boolean; + cleanupExcludedOnStart: boolean; } interface HassEntity { @@ -683,6 +684,105 @@ class HassAdapter extends Adapter { this.initialSyncCompleted = true; } + private async cleanupExcludedObjects(): Promise { + if (!this.config.cleanupExcludedOnStart) { + return; + } + if (this.excludePatterns.length === 0) { + this.log.info('Cleanup skipped: no exclude patterns configured'); + return; + } + + let allObjects: Record; + try { + allObjects = (await this.getAdapterObjectsAsync()) as Record; + } catch (err) { + this.log.error(`Cleanup: failed to load adapter objects: ${err}`); + return; + } + + const prefix = `${this.namespace}.entities.`; + const channelsToDelete: { id: string; entityId: string }[] = []; + + for (const id in allObjects) { + if (!Object.prototype.hasOwnProperty.call(allObjects, id) || !id.startsWith(prefix)) { + continue; + } + const obj = allObjects[id]; + if (obj.type !== 'channel') { + continue; + } + const entityId = (obj.native as Record)?.entity_id; + if (typeof entityId !== 'string') { + continue; + } + if (isExcluded(entityId, this.excludePatterns)) { + channelsToDelete.push({ id, entityId }); + } + } + + if (channelsToDelete.length === 0) { + this.log.info('Cleanup: no existing objects matched exclude patterns'); + return; + } + + let deletedCount = 0; + let keptForCustomCount = 0; + + for (const { id, entityId } of channelsToDelete) { + const channelCustom = (allObjects[id].common as { custom?: Record } | undefined) + ?.custom; + let hasCustom = !!(channelCustom && Object.keys(channelCustom).length); + if (!hasCustom) { + const subPrefix = `${id}.`; + for (const subId in allObjects) { + if (!subId.startsWith(subPrefix)) { + continue; + } + const subCustom = ( + allObjects[subId].common as { custom?: Record } | undefined + )?.custom; + if (subCustom && Object.keys(subCustom).length) { + hasCustom = true; + break; + } + } + } + + if (hasCustom) { + keptForCustomCount++; + this.log.warn( + `Cleanup: keeping "${id}" (entity ${entityId}) — has custom adapter config (history/influxdb/sql); remove it manually if you really want to drop it`, + ); + continue; + } + + try { + await this.delObjectAsync(id, { recursive: true }); + delete this.hassObjects[id]; + const subPrefix = `${id}.`; + for (const cachedId of Object.keys(this.hassObjects)) { + if (cachedId.startsWith(subPrefix)) { + delete this.hassObjects[cachedId]; + } + } + deletedCount++; + if (this.config.verboseFilterLog) { + this.log.info(`Cleanup: deleted "${id}" (entity ${entityId})`); + } + } catch (err) { + this.log.error(`Cleanup: failed to delete "${id}": ${err}`); + } + } + + this.log.info( + `Cleanup: deleted ${deletedCount} excluded entit${deletedCount === 1 ? 'y' : 'ies'}` + + (keptForCustomCount > 0 + ? `, kept ${keptForCustomCount} with custom config (see warnings above)` + : ''), + ); + } + private async main(): Promise { this.config.host ||= '127.0.0.1'; this.config.port = parseInt(String(this.config.port), 10) || 8123; @@ -701,6 +801,8 @@ class HassAdapter extends Adapter { ); } + await this.cleanupExcludedObjects(); + await this.setStateAsync('info.connection', false, true); this.hass = new HASS(this.config, this.log);