# HassLink Entity & Device Filtering Specification
This document defines the configuration parameters, evaluation model, and execution rules for entity and device filtering within the hasslink openHAB binding.
# 1. Architectural Model & Filter Logic
Filtering in hasslink operates as a Sequential Pipeline using Composite AND logic across criteria levels, with a top-priority override for explicitly linked entities.
# 1.1 The Composite AND Logic
When multiple filtering criteria (such as includedEntities, includedDomains, and includedLabels) are configured on a Thing, all active inclusion criteria must evaluate to true for a candidate entity to be accepted.
Specifically:
- Exclusions (
excluded*) act as immediate short-circuit rejections. If an entity matches any active exclusion rule (excludedEntities,excludedDomains, orexcludedLabels), it is immediately rejected (false). - Inclusions (
included*) act as a composite allowlist. If an inclusion filter category is active (non-empty), candidate entities must match that filter. If multiple inclusion filters are active (e.g., bothincludedEntitiesANDincludedDomains), an entity must satisfy ALL of them to pass.
# 2. Evaluation Flow (isEntityAllowedForDevice)
Candidate entities belonging to a Home Assistant Device are evaluated step-by-step in the following exact sequence:
- Explicit Thing Entity Match (
config.entityIds): Checks if the entity is explicitly defined inentityIds. If yes, it is allowed immediately (returningtrue), bypassing all other rules. - Explicit Entity Exclusion (
config.excludedEntities): Checks if the entity matches any glob or string inexcludedEntities. If yes, it is rejected immediately (returningfalse). - Explicit Entity Inclusion (
config.includedEntities): Checks if theincludedEntitiesfilter is active (non-blank). If active and the entity does not match, it is rejected (returningfalse); otherwise, it passes to the next step. - Domain Filtering (
config.excludedDomains/config.includedDomains): Checks if the entity domain matchesexcludedDomains(rejection) or ifincludedDomainsis active and the domain does not match (rejection); otherwise, it passes to the next step. - Label Filtering (
config.excludedLabels/config.includedLabels): Checks if any entity or device label matchesexcludedLabels(rejection), or ifincludedLabelsis active and no labels match (rejection). If all checks pass, the entity is allowed (returningtrue).
# 3. Top Priority Override: config.entityIds
The entityIds configuration array on a device Thing represents an explicit user request to link specific Home Assistant entities to openHAB channels.
- Entities listed in
entityIdsbypass all device exclusions and filter rules (excludedEntities,excludedDomains,includedDomains,excludedLabels,includedLabels). - Execution returns
trueimmediately at Step 1, ensuring explicitly defined items are never filtered out.
# 4. Wildcard Glob Matching & Whitespace Handling
# 4.1 Wildcard Glob Patterns
All entity, domain, area, and label filter options support standard wildcard glob syntax:
*matches zero or more characters (e.g.,sensor.*_temperature,*_version,*_mac).?matches exactly one character (e.g.,switch.plug_?).- String comparison is case-insensitive.
# 4.2 Blank and Whitespace Filter Normalization
UI configurations and text files can sometimes supply empty strings or lists containing whitespace elements (e.g. [""] or [" "]).
- Filter lists containing only empty or whitespace-only elements are recognized as inactive filters (
hasActiveFilter = false). - Inactive filters are skipped during evaluation and will not cause blanket rejections of all incoming entities.
# 5. Summary Matrix & Examples
| Scenario | Config Setup | Candidate Entity | Result | Reason |
|---|---|---|---|---|
| Explicit Override | entityIds = ["sensor.attic_temp"]excludedDomains = ["sensor"] | sensor.attic_temp | ALLOWED | Step 1 match; bypasses domain exclusion. |
| Excluded Entity Glob | excludedEntities = ["*_version"] | sensor.mower_fw_version | REJECTED | Step 2 match against wildcard pattern. |
| Composite Inclusions (Match) | includedEntities = ["sensor.livingroom_*"]includedDomains = ["sensor"] | sensor.livingroom_temp | ALLOWED | Matches both includedEntities AND includedDomains. |
| Composite Inclusions (Mismatch) | includedEntities = ["sensor.livingroom_*"]includedDomains = ["switch"] | sensor.livingroom_temp | REJECTED | Matches includedEntities but fails includedDomains (Composite AND failure). |
| Domain Exclusion | excludedDomains = ["update", "button"] | update.firmware | REJECTED | Step 4 match against excludedDomains. |