feat(filter): add verbose filter logging option

New `verboseFilterLog` boolean (default `false`). When enabled, the initial
sync logs every excluded entity_id individually on INFO level. This is
useful when iterating on exclude patterns or verifying that the filter
catches the intended entities.

The verbose output is intentionally limited to the first sync. Subsequent
debouncedSync() calls only emit the aggregate count to avoid log spam
during normal operation. Live `state_changed` events for filtered entities
remain on DEBUG.

Admin UI gets a checkbox below the patterns field; i18n keys added for
all 11 supported languages.
This commit is contained in:
mokusone
2026-05-14 11:40:28 +02:00
parent 288273005a
commit fc7efd4768
14 changed files with 55 additions and 12 deletions
+3 -1
View File
@@ -6,5 +6,7 @@
"Passwords missmatch!": "Passwörter stimmen nicht überein!",
"Secure": "HTTPS?",
"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."
"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)."
}
+3 -1
View File
@@ -6,5 +6,7 @@
"Passwords missmatch!": "Passwords missmatch!",
"Secure": "HTTPS?",
"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."
"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)."
}
+3 -1
View File
@@ -6,5 +6,7 @@
"Passwords missmatch!": "¡Las contraseñas no coinciden!",
"Secure": "¿HTTPS?",
"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."
"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)."
}
+3 -1
View File
@@ -6,5 +6,7 @@
"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é."
"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)."
}
+3 -1
View File
@@ -6,5 +6,7 @@
"Passwords missmatch!": "Le password non corrispondono!",
"Secure": "HTTPS?",
"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."
"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)."
}
+3 -1
View File
@@ -6,5 +6,7 @@
"Passwords missmatch!": "Wachtwoorden komen niet overeen!",
"Secure": "HTTPS?",
"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."
"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)."
}
+3 -1
View File
@@ -6,5 +6,7 @@
"Passwords missmatch!": "Niezgodność haseł!",
"Secure": "HTTPS?",
"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."
"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)."
}
+3 -1
View File
@@ -6,5 +6,7 @@
"Passwords missmatch!": "As senhas não correspondem!",
"Secure": "HTTPS?",
"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."
"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)."
}
+3 -1
View File
@@ -6,5 +6,7 @@
"Passwords missmatch!": "Пароли не совпадают!",
"Secure": "HTTPS?",
"Exclude patterns (one per line)": "Шаблоны исключения (по одному на строку)",
"Glob patterns, * wildcard. Lines starting with # are comments. Empty = filter off.": "Glob-шаблоны, * — подстановочный знак. Строки, начинающиеся с #, являются комментариями. Пусто = фильтр выключен."
"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)."
}
+3 -1
View File
@@ -6,5 +6,7 @@
"Passwords missmatch!": "Паролі не збігаються!",
"Secure": "HTTPS?",
"Exclude patterns (one per line)": "Шаблони виключення (по одному в рядку)",
"Glob patterns, * wildcard. Lines starting with # are comments. Empty = filter off.": "Glob-шаблони, * — підстановочний знак. Рядки, що починаються з #, є коментарями. Порожньо = фільтр вимкнено."
"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)."
}
+3 -1
View File
@@ -6,5 +6,7 @@
"Passwords missmatch!": "密码不匹配!",
"Secure": "HTTPS",
"Exclude patterns (one per line)": "排除模式(每行一个)",
"Glob patterns, * wildcard. Lines starting with # are comments. Empty = filter off.": "Glob 模式,* 通配符。以 # 开头的行是注释。为空 = 过滤器关闭。"
"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)。"
}
+6
View File
@@ -50,6 +50,12 @@
"multiline": true,
"minRows": 6,
"sm": 12
},
"verboseFilterLog": {
"type": "checkbox",
"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
}
}
}
+2 -1
View File
@@ -253,7 +253,8 @@
"port": 8123,
"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_*"
"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
},
"protectedNative": [
"password"
+14
View File
@@ -8,6 +8,7 @@ interface HassAdapterConfig {
password: string;
secure: boolean;
excludePatterns: string;
verboseFilterLog: boolean;
}
interface HassEntity {
@@ -191,6 +192,7 @@ class HassAdapter extends Adapter {
private syncDebounceTimeout: ReturnType<typeof setTimeout> | null = null;
private stopped: boolean = false;
private excludePatterns: string[] = [];
private initialSyncCompleted: boolean = false;
public constructor(options: Partial<AdapterOptions> = {}) {
super({
@@ -458,6 +460,7 @@ class HassAdapter extends Adapter {
const states: { id: string; lc?: number; ts?: number; val: ioBroker.StateValue; ack: boolean }[] = [];
const expectedObjects = new Set<string>();
let excludedCount = 0;
const excludedIds: string[] = [];
for (let e = 0; e < entities.length; e++) {
const entity = entities[e];
@@ -467,6 +470,9 @@ class HassAdapter extends Adapter {
if (isExcluded(entity.entity_id, this.excludePatterns)) {
excludedCount++;
if (this.config.verboseFilterLog && !this.initialSyncCompleted) {
excludedIds.push(entity.entity_id);
}
continue;
}
@@ -667,6 +673,14 @@ class HassAdapter extends Adapter {
`Entity filter excluded ${excludedCount} entit${excludedCount === 1 ? 'y' : 'ies'} from sync`,
);
}
if (excludedIds.length > 0) {
for (const id of excludedIds) {
this.log.info(`Entity filter excluded: ${id}`);
}
}
this.initialSyncCompleted = true;
}
private async main(): Promise<void> {