Fix counting of hidden entities and devices

Evaluation an entity's hidden property in the strategy options, is now
included in Helper.#areaFilterCallback().
This commit is contained in:
w531t4
2025-02-09 00:48:38 -05:00
committed by GitHub
parent 9ed17d9a56
commit da7d0cd57c
3 changed files with 36 additions and 58 deletions

View File

@ -287,12 +287,12 @@ class Helper {
* The result excludes hidden and disabled entities.
*
* @param {AreaRegistryEntry} area Area entity.
* @param {string} domain The domain of the entity-id.
* @param {string} [domain] The domain of the entity-id.
*
* @return {EntityRegistryEntry[]} Array of device entities.
* @static
*/
static getDeviceEntities(area: AreaRegistryEntry, domain: string): EntityRegistryEntry[] {
static getDeviceEntities(area: AreaRegistryEntry, domain?: string): EntityRegistryEntry[] {
if (!this.isInitialized()) {
console.warn("Helper class should be initialized before calling this method!");
}
@ -414,12 +414,12 @@ class Helper {
* Callback function for filtering entities.
*
* Entities of which all the conditions below are met are kept:
* 1. The entity is not hidden and is not disabled.
* 2. The entity's domain matches the given domain.
* 3. The entity itself or else the entity's linked device is linked to the given area.
* (See variable areaMatch)
* 1. The entity is not hidden and the entity's device is not hidden by the strategy options.
* 2. The entity is not hidden and is not disabled by Hass.
* 3. The entity's domain matches the given domain.
* 4. The entity itself or else the entity's device is linked to the given area.
*
* @param {EntityRegistryEntry} entity The current hass entity to evaluate.
* @param {EntityRegistryEntry} entity The current Hass entity to evaluate.
* @this {AreaFilterContext}
*
* @return {boolean} True to keep the entity.
@ -432,16 +432,20 @@ class Helper {
domain: string,
},
entity: EntityRegistryEntry): boolean {
const entityUnhidden = entity.hidden_by === null && entity.disabled_by === null;
const domainMatches = entity.entity_id.startsWith(`${this.domain}.`);
const cardOptions = Helper.strategyOptions.card_options?.[entity.entity_id];
const deviceOptions = Helper.strategyOptions.card_options?.[entity.device_id ?? "null"];
const entityUnhidden =
!cardOptions?.hidden && !deviceOptions?.hidden // Condition 1.
&& entity.hidden_by === null && entity.disabled_by === null; // Condition 2.
const domainMatches = this.domain === undefined || entity.entity_id.startsWith(`${this.domain}.`); // Condition 3.
// Condition 4.
const entityLinked = this.area.area_id === "undisclosed"
// Undisclosed area;
// nor the entity itself, neither the entity's linked device (if any) is linked to any area.
// Undisclosed area.
? !entity.area_id && (this.areaDeviceIds.includes(entity.device_id ?? "") || !entity.device_id)
// Area is a hass entity;
// The entity itself or the entity's device is linked to the given area.
// Note: entity.area_id is set to null when using device's area.
// Area is a hass entity. Note: entity.area_id is set to null when using device's area.
: entity.area_id === this.area.area_id || (!entity.area_id && this.areaDeviceIds.includes(entity.device_id ?? ""));
return (entityUnhidden && domainMatches && entityLinked);
}

View File

@ -107,11 +107,11 @@ class MushroomStrategy extends HTMLTemplateElement {
const className = Helper.sanitizeClassName(domain + "Card");
let domainCards = [];
let domainCards: EntityCardConfig[] = [];
try {
domainCards = await import(`./cards/${className}`).then(cardModule => {
let domainCards = [];
let domainCards: EntityCardConfig[] = [];
const entities = Helper.getDeviceEntities(area, domain);
let configEntityHidden =
Helper.strategyOptions.domains[domain ?? "_"].hide_config_entities
@ -132,7 +132,7 @@ class MushroomStrategy extends HTMLTemplateElement {
).createCard();
if (domain === "sensor") {
// Create a card for each entity-sensor of the current area.
// Create a card for each sensor-entity of the current area.
const sensorStates = Helper.getStateEntities(area, "sensor");
const sensorCards: EntityCardConfig[] = [];
@ -140,18 +140,15 @@ class MushroomStrategy extends HTMLTemplateElement {
// Find the state of the current sensor.
const sensorState = sensorStates.find(state => state.entity_id === sensor.entity_id);
let cardOptions = Helper.strategyOptions.card_options?.[sensor.entity_id];
let deviceOptions = Helper.strategyOptions.card_options?.[sensor.device_id ?? "null"];
if (!cardOptions?.hidden && !deviceOptions?.hidden) {
if (sensorState?.attributes.unit_of_measurement) {
cardOptions = {
...{
type: "custom:mini-graph-card",
entities: [sensor.entity_id],
},
...cardOptions,
};
}
if (sensorState?.attributes.unit_of_measurement) {
cardOptions = {
...{
type: "custom:mini-graph-card",
entities: [sensor.entity_id],
},
...cardOptions,
};
sensorCards.push(new SensorCard(sensor, cardOptions).getCard());
}
@ -178,11 +175,6 @@ class MushroomStrategy extends HTMLTemplateElement {
deviceOptions = Helper.strategyOptions.card_options?.[entity.device_id];
}
// Don't include the entity if hidden in the strategy options.
if (cardOptions?.hidden || deviceOptions?.hidden) {
continue;
}
// Don't include the config-entity if hidden in the strategy options.
if (entity.entity_category === "config" && configEntityHidden) {
continue;
@ -193,7 +185,7 @@ class MushroomStrategy extends HTMLTemplateElement {
if (domain === "binary_sensor") {
// Horizontally group every two binary sensor cards.
const horizontalCards = [];
const horizontalCards: EntityCardConfig[] = [];
for (let i = 0; i < domainCards.length; i += 2) {
horizontalCards.push({
@ -226,22 +218,10 @@ class MushroomStrategy extends HTMLTemplateElement {
if (!Helper.strategyOptions.domains.default.hidden) {
// Create cards for any other domain.
// Collect device entities of the current area.
const areaDevices = Helper.devices.filter((device) => device.area_id === area.area_id)
.map((device) => device.id);
// Collect the remaining entities of which all conditions below are met:
// 1. The entity is not hidden.
// 2. The entity's domain isn't exposed (entities of exposed domains are already included).
// 3. The entity is linked to a device which is linked to the current area,
// or the entity itself is linked to the current area.
const miscellaneousEntities = Helper.entities.filter((entity) => {
const entityLinked = areaDevices.includes(entity.device_id ?? "null") || entity.area_id === area.area_id;
const entityUnhidden = entity.hidden_by === null && entity.disabled_by === null;
const domainExposed = exposedDomainIds.includes(entity.entity_id.split(".", 1)[0]);
return entityUnhidden && !domainExposed && entityLinked;
});
// Collect entities of the current area and unexposed domains.
const miscellaneousEntities = Helper.getDeviceEntities(area).filter(
entity => !exposedDomainIds.includes(entity.entity_id.split(".", 1)[0])
);
// Create a column of miscellaneous entity cards.
if (miscellaneousEntities.length) {
@ -257,11 +237,6 @@ class MushroomStrategy extends HTMLTemplateElement {
let cardOptions = Helper.strategyOptions.card_options?.[entity.entity_id];
let deviceOptions = Helper.strategyOptions.card_options?.[entity.device_id ?? "null"];
// Don't include the entity if hidden in the strategy options.
if (cardOptions?.hidden || deviceOptions?.hidden) {
continue;
}
// Don't include the config-entity if hidden in the strategy options
if (entity.entity_category === "config" && Helper.strategyOptions.domains["_"].hide_config_entities) {
continue;

View File

@ -186,13 +186,12 @@ export namespace generic {
*
* @property {AreaRegistryEntry} area Area Entity.
* @property {string[]} areaDeviceIds The id of devices which are linked to the area entity.
* @property {string} domain Domain of the entity.
* Example: `light`.
* @property {string} [domain] Domain of the entity. Example: `light`.
*/
export interface AreaFilterContext {
area: AreaRegistryEntry;
areaDeviceIds: string[];
domain: string;
domain?: string;
}
/**