diff --git a/src/filter.ts b/src/filter.ts index 60747fd..95a0498 100644 --- a/src/filter.ts +++ b/src/filter.ts @@ -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 @@ -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 (entity)[this.config.name]; + return getValueFromObject(entityData, this.config.name); } /** diff --git a/src/utils.ts b/src/utils.ts index a3665b6..644cf71 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -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(); } \ No newline at end of file diff --git a/test/other/filter.test.ts b/test/other/filter.test.ts index d7dd001..d45c8b6 100644 --- a/test/other/filter.test.ts +++ b/test/other/filter.test.ts @@ -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); + }) }); \ No newline at end of file