diff --git a/io-package.json b/io-package.json index b92e29d..3684fd7 100644 --- a/io-package.json +++ b/io-package.json @@ -252,7 +252,8 @@ "host": "127.0.0.1", "port": 8123, "password": "", - "secure": false + "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_*" }, "protectedNative": [ "password" diff --git a/src/main.ts b/src/main.ts index 187c129..ce09d7b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,11 +1,13 @@ import { Adapter, type AdapterOptions } from '@iobroker/adapter-core'; import HASS from './lib/hass'; +import { isExcluded } from './lib/entityFilter'; interface HassAdapterConfig { host: string; port: number; password: string; secure: boolean; + excludePatterns: string; } interface HassEntity { @@ -188,6 +190,7 @@ class HassAdapter extends Adapter { private delayTimeout: ReturnType | null = null; private syncDebounceTimeout: ReturnType | null = null; private stopped: boolean = false; + private excludePatterns: string[] = []; public constructor(options: Partial = {}) { super({ @@ -454,6 +457,7 @@ class HassAdapter extends Adapter { const objs: (ioBroker.ChannelObject | ioBroker.StateObject)[] = []; const states: { id: string; lc?: number; ts?: number; val: ioBroker.StateValue; ack: boolean }[] = []; const expectedObjects = new Set(); + let excludedCount = 0; for (let e = 0; e < entities.length; e++) { const entity = entities[e]; @@ -461,6 +465,11 @@ class HassAdapter extends Adapter { continue; } + if (isExcluded(entity.entity_id, this.excludePatterns)) { + excludedCount++; + continue; + } + const name = entity.name || entity.attributes?.friendly_name || entity.entity_id; const desc = entity.attributes?.attribution || undefined; @@ -652,12 +661,32 @@ class HassAdapter extends Adapter { } this.log.info(`Synchronization completed: ${changes.join(', ')}`); } + + if (excludedCount > 0) { + this.log.info( + `Entity filter excluded ${excludedCount} entit${excludedCount === 1 ? 'y' : 'ies'} from sync`, + ); + } } private async main(): Promise { this.config.host ||= '127.0.0.1'; this.config.port = parseInt(String(this.config.port), 10) || 8123; + const rawPatterns = (this.config.excludePatterns || '').toString(); + this.excludePatterns = rawPatterns + .split('\n') + .map(s => s.trim()) + .filter(line => line.length > 0 && !line.startsWith('#')); + + if (this.excludePatterns.length === 0) { + this.log.info('Entity filter inactive (no exclude patterns configured)'); + } else { + this.log.info( + `Entity filter active: ${this.excludePatterns.length} pattern(s) loaded: ${this.excludePatterns.join(', ')}`, + ); + } + await this.setStateAsync('info.connection', false, true); this.hass = new HASS(this.config, this.log); @@ -670,6 +699,11 @@ class HassAdapter extends Adapter { return; } + if (isExcluded(entity.entity_id, this.excludePatterns)) { + this.log.debug(`Entity filter: ignored state_changed for ${entity.entity_id}`); + return; + } + const id = `entities.${entity.entity_id}.`; const lc = entity.last_changed ? new Date(entity.last_changed).getTime() : undefined; const ts = entity.last_updated ? new Date(entity.last_updated).getTime() : undefined;