Skip to content

Commit

Permalink
Allow filtering by extended entity data
Browse files Browse the repository at this point in the history
  • Loading branch information
maxwroc committed Feb 11, 2024
1 parent 27b0e30 commit b162372
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 11 deletions.
18 changes: 7 additions & 11 deletions src/filter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getRegexFromString, isNumber, log, toNumber } from "./utils";
import { getRegexFromString, getValueFromObject, isNumber, log, toNumber } from "./utils";

/**
* Functions to check if filter condition is met
Expand Down Expand Up @@ -49,34 +49,30 @@ export class Filter {

/**
* Checks whether entity meets the filter conditions.
* @param entity Hass entity
* @param entityData Hass entity data
* @param state State override - battery state/level
*/
isValid(entity: any, state?: string): boolean {
const val = this.getValue(entity, state);
isValid(entityData: any, state?: string): boolean {
const val = this.getValue(entityData, state);
return this.meetsExpectations(val);
}

/**
* Gets the value to validate.
* @param entity Hass entity
* @param entityData Hass entity data
* @param state State override - battery state/level
*/
private getValue(entity: any, state?: string): string | undefined {
private getValue(entityData: any, state?: string): string | undefined {
if (!this.config.name) {
log("Missing filter 'name' property");
return;
}

if (this.config.name.indexOf("attributes.") == 0) {
return entity.attributes[this.config.name.substr(11)];
}

if (this.config.name == "state" && state !== undefined) {
return state;
}

return (<any>entity)[this.config.name];
return getValueFromObject(entityData, this.config.name);
}

/**
Expand Down
23 changes: 23 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,4 +145,27 @@ export const getRegexFromString = (ruleVal: string): RegExp | null => {
}

return null;
}

/**
* Extracts value for given path from the object
* @param dataObject Object to extract data from
* @param path Path to the value
* @returns Value from the path
*/
export const getValueFromObject = (dataObject: any, path: string): string | undefined => {
const chunks = path.split(".");

for (let i = 0; i < chunks.length; i++) {
dataObject = dataObject[chunks[i]];
if (dataObject === undefined) {
break;
}
}

if (typeof dataObject == "object") {
dataObject = JSON.stringify(dataObject);
}

return dataObject === undefined ? undefined : dataObject.toString();
}
15 changes: 15 additions & 0 deletions test/other/filter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,19 @@ describe("Filter", () => {

expect(isValid).toBe(expectedIsVlid);
})

test.each([
[{ state: "45", device: { name: "Device name" } }, "path.missing", "Device name", false],
[{ state: "45", device: { name: "Device name" } }, "device.name", "Device name", true],
[{ state: "45", device: { name: "Device name" } }, "device.name", "Device other name", false],
[{ state: "45", device: { name: "Device name", manufacturer: { name: "Contoso" } } }, "device.manufacturer", "Contoso", false],
[{ state: "45", device: { name: "Device name", manufacturer: { name: "Contoso" } } }, "device.manufacturer.name", "Contoso", true],
])("filter based on nested entity data", (entityData: any, filterName: string, filterValue: string, expectedIsValid: boolean) => {
const hassMock = new HomeAssistantMock();

const filter = new Filter({ name: filterName, value: filterValue });
const isValid = filter.isValid(entityData, "45");

expect(isValid).toBe(expectedIsValid);
})
});

0 comments on commit b162372

Please sign in to comment.