feat(filter): integrate exclude filter into parseStates and state_changed
Adapter now consults the exclude-pattern list (new `native.excludePatterns` config option, multi-line string) at two points: - `parseStates()` skips matching entities entirely. They are not registered as ioBroker objects and no state is written. A summary INFO line reports the count when the filter dropped anything from a sync. - The `state_changed` event handler short-circuits matching live updates with a DEBUG line, so a filtered entity that still emits state changes in HA does not cause any churn in ioBroker. Patterns are parsed once at adapter start: trimmed, empty lines and lines starting with `#` are dropped. An empty resulting list means the filter is inactive — adapter behaviour is then identical to the previous version. Default config ships with example comments only, so existing installations see no functional change after the update.
This commit is contained in:
+2
-1
@@ -252,7 +252,8 @@
|
|||||||
"host": "127.0.0.1",
|
"host": "127.0.0.1",
|
||||||
"port": 8123,
|
"port": 8123,
|
||||||
"password": "",
|
"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": [
|
"protectedNative": [
|
||||||
"password"
|
"password"
|
||||||
|
|||||||
+34
@@ -1,11 +1,13 @@
|
|||||||
import { Adapter, type AdapterOptions } from '@iobroker/adapter-core';
|
import { Adapter, type AdapterOptions } from '@iobroker/adapter-core';
|
||||||
import HASS from './lib/hass';
|
import HASS from './lib/hass';
|
||||||
|
import { isExcluded } from './lib/entityFilter';
|
||||||
|
|
||||||
interface HassAdapterConfig {
|
interface HassAdapterConfig {
|
||||||
host: string;
|
host: string;
|
||||||
port: number;
|
port: number;
|
||||||
password: string;
|
password: string;
|
||||||
secure: boolean;
|
secure: boolean;
|
||||||
|
excludePatterns: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HassEntity {
|
interface HassEntity {
|
||||||
@@ -188,6 +190,7 @@ class HassAdapter extends Adapter {
|
|||||||
private delayTimeout: ReturnType<typeof setTimeout> | null = null;
|
private delayTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||||
private syncDebounceTimeout: ReturnType<typeof setTimeout> | null = null;
|
private syncDebounceTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||||
private stopped: boolean = false;
|
private stopped: boolean = false;
|
||||||
|
private excludePatterns: string[] = [];
|
||||||
|
|
||||||
public constructor(options: Partial<AdapterOptions> = {}) {
|
public constructor(options: Partial<AdapterOptions> = {}) {
|
||||||
super({
|
super({
|
||||||
@@ -454,6 +457,7 @@ class HassAdapter extends Adapter {
|
|||||||
const objs: (ioBroker.ChannelObject | ioBroker.StateObject)[] = [];
|
const objs: (ioBroker.ChannelObject | ioBroker.StateObject)[] = [];
|
||||||
const states: { id: string; lc?: number; ts?: number; val: ioBroker.StateValue; ack: boolean }[] = [];
|
const states: { id: string; lc?: number; ts?: number; val: ioBroker.StateValue; ack: boolean }[] = [];
|
||||||
const expectedObjects = new Set<string>();
|
const expectedObjects = new Set<string>();
|
||||||
|
let excludedCount = 0;
|
||||||
|
|
||||||
for (let e = 0; e < entities.length; e++) {
|
for (let e = 0; e < entities.length; e++) {
|
||||||
const entity = entities[e];
|
const entity = entities[e];
|
||||||
@@ -461,6 +465,11 @@ class HassAdapter extends Adapter {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isExcluded(entity.entity_id, this.excludePatterns)) {
|
||||||
|
excludedCount++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const name = entity.name || entity.attributes?.friendly_name || entity.entity_id;
|
const name = entity.name || entity.attributes?.friendly_name || entity.entity_id;
|
||||||
const desc = entity.attributes?.attribution || undefined;
|
const desc = entity.attributes?.attribution || undefined;
|
||||||
|
|
||||||
@@ -652,12 +661,32 @@ class HassAdapter extends Adapter {
|
|||||||
}
|
}
|
||||||
this.log.info(`Synchronization completed: ${changes.join(', ')}`);
|
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<void> {
|
private async main(): Promise<void> {
|
||||||
this.config.host ||= '127.0.0.1';
|
this.config.host ||= '127.0.0.1';
|
||||||
this.config.port = parseInt(String(this.config.port), 10) || 8123;
|
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);
|
await this.setStateAsync('info.connection', false, true);
|
||||||
|
|
||||||
this.hass = new HASS(this.config, this.log);
|
this.hass = new HASS(this.config, this.log);
|
||||||
@@ -670,6 +699,11 @@ class HassAdapter extends Adapter {
|
|||||||
return;
|
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 id = `entities.${entity.entity_id}.`;
|
||||||
const lc = entity.last_changed ? new Date(entity.last_changed).getTime() : undefined;
|
const lc = entity.last_changed ? new Date(entity.last_changed).getTime() : undefined;
|
||||||
const ts = entity.last_updated ? new Date(entity.last_updated).getTime() : undefined;
|
const ts = entity.last_updated ? new Date(entity.last_updated).getTime() : undefined;
|
||||||
|
|||||||
Reference in New Issue
Block a user