Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow filtering by extended entity data #683

Merged
merged 1 commit into from
Feb 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
})
});
Loading