Skip to content

Commit

Permalink
Merge pull request #699 from maxwroc/FixBattLevelExc
Browse files Browse the repository at this point in the history
Fix exception when entity attributes are missing
  • Loading branch information
maxwroc authored Feb 16, 2024
2 parents 57833e9 + 48e3ba1 commit 86638f5
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 21 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "battery-state-card",
"version": "3.2.0",
"version": "3.2.1",
"description": "Battery State card for Home Assistant",
"main": "dist/battery-state-card.js",
"author": "Max Chodorowski",
Expand Down
4 changes: 2 additions & 2 deletions src/entity-fields/battery-level.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ export const getBatteryLevel = (config: IBatteryEntityConfig, hass: HomeAssistan
}
else {
const candidates: (string | number | undefined)[] = [
config.non_battery_entity ? null: entityData.attributes.battery_level,
config.non_battery_entity ? null: entityData.attributes.battery,
config.non_battery_entity ? null: entityData.attributes?.battery_level,
config.non_battery_entity ? null: entityData.attributes?.battery,
entityData.state
];

Expand Down
6 changes: 1 addition & 5 deletions src/entity-fields/get-name.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,7 @@ export const getName = (config: IBatteryEntityConfig, hass: HomeAssistant | unde
return proc.process(config.name);
}

if (!hass) {
return config.entity;
}

let name = hass.states[config.entity]?.attributes.friendly_name;
let name = entityData?.attributes?.friendly_name;

// when we have failed to get the name we just return entity id
if (!name) {
Expand Down
8 changes: 7 additions & 1 deletion test/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,12 @@ export class HomeAssistantMock<T extends LovelaceCard<any>> {
return entity;
},
setAttributes: (attribs: IEntityAttributes) => {

if (attribs === null) {
this.hass.states[entity.entity_id].attributes = <any>undefined;
return entity;
}

this.hass.states[entity.entity_id].attributes = {
...this.hass.states[entity.entity_id].attributes,
...attribs
Expand Down Expand Up @@ -242,7 +248,7 @@ interface IEntityMock {
readonly entity_id: string;
readonly state: string;
setState(state: string): IEntityMock;
setAttributes(attribs: IEntityAttributes): IEntityMock;
setAttributes(attribs: IEntityAttributes | null): IEntityMock;
setLastUpdated(val: string): void;
setLastChanged(val: string): void;
setProperty<K extends keyof HaEntityPropertyToTypeMap>(name: K, val: HaEntityPropertyToTypeMap[K]): void;
Expand Down
12 changes: 12 additions & 0 deletions test/other/entity-fields/battery-level.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@ describe("Battery level", () => {
expect(unit).toBe("%");
});

test("doen't throw exception when attributes are not set on entity", () => {
const hassMock = new HomeAssistantMock(true);
const entity = hassMock.addEntity("Mocked entity", "45", { battery_state: "45" });
entity.setAttributes(null);

const { state, level, unit } = getBatteryLevel({ entity: "mocked_entity" }, hassMock.hass, hassMock.hass.states["mocked_entity"]);

expect(level).toBe(45);
expect(state).toBe("45");
expect(unit).toBe("%")
});

test("is 'Unknown' when entity not found and no localized string", () => {
const hassMock = new HomeAssistantMock(true);
hassMock.hass.localize = () => <string><unknown>null;
Expand Down
34 changes: 22 additions & 12 deletions test/other/entity-fields/get-name.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,22 @@ describe("Get name", () => {
expect(name).toBe("sensor.my_entity_id");
});

test("returns name from friendly_name attribute of the entity", () => {
test("doesn't throw exception when attributes property is missing", () => {
const hassMock = new HomeAssistantMock(true);
hassMock.addEntity("My entity", "45", { friendly_name: "My entity name" });
const entity = hassMock.addEntity("My entity", "45", { friendly_name: "My entity name" });
entity.setAttributes(null);

let name = getName({ entity: "my_entity" }, hassMock.hass, {});

expect(name).toBe("my_entity");
});

test("returns name from friendly_name attribute of the entity", () => {
const hassMock = new HomeAssistantMock(true);
const entity = hassMock.addEntity("My entity", "45", { friendly_name: "My entity name" });

let name = getName({ entity: "my_entity" }, hassMock.hass, hassMock.hass.states[entity.entity_id]);

expect(name).toBe("My entity name");
});

Expand All @@ -33,18 +43,18 @@ describe("Get name", () => {

test("returns entity id when entity doesn't have a friendly_name attribute", () => {
const hassMock = new HomeAssistantMock(true);
hassMock.addEntity("My entity", "45", { friendly_name: undefined });
const entity = hassMock.addEntity("My entity", "45", { friendly_name: undefined });

let name = getName({ entity: "my_entity" }, hassMock.hass, {});
let name = getName({ entity: "my_entity" }, hassMock.hass, hassMock.hass.states[entity.entity_id]);

expect(name).toBe("my_entity");
});

test("doesn't throw when name is empty", () => {
const hassMock = new HomeAssistantMock(true);
hassMock.addEntity("My entity", "45", { friendly_name: "Battery" });
const entity = hassMock.addEntity("My entity", "45", { friendly_name: "Battery" });

let name = getName({ entity: "my_entity", bulk_rename: [{ from: "Battery", to: "" }] }, hassMock.hass, {});
let name = getName({ entity: "my_entity", bulk_rename: [{ from: "Battery", to: "" }] }, hassMock.hass, hassMock.hass.states[entity.entity_id]);

expect(name).toBe("");
});
Expand All @@ -57,9 +67,9 @@ describe("Get name", () => {
]
)("returns renamed entity name", (entityName: string, renameRules: IConvert | IConvert[], expectedResult: string) => {
const hassMock = new HomeAssistantMock(true);
hassMock.addEntity("My entity", "45", { friendly_name: entityName });
const entity = hassMock.addEntity("My entity", "45", { friendly_name: entityName });

let name = getName({ entity: "my_entity", bulk_rename: renameRules }, hassMock.hass, {});
let name = getName({ entity: "my_entity", bulk_rename: renameRules }, hassMock.hass, hassMock.hass.states[entity.entity_id]);

expect(name).toBe(expectedResult);
});
Expand All @@ -72,9 +82,9 @@ describe("Get name", () => {
]
)("regex", (entityName: string, renameRules: IConvert | IConvert[], expectedResult: string) => {
const hassMock = new HomeAssistantMock(true);
hassMock.addEntity("My entity", "45", { friendly_name: entityName });
const entity = hassMock.addEntity("My entity", "45", { friendly_name: entityName });

let name = getName({ entity: "my_entity", bulk_rename: renameRules }, hassMock.hass, {});
let name = getName({ entity: "my_entity", bulk_rename: renameRules }, hassMock.hass, hassMock.hass.states[entity.entity_id]);

expect(name).toBe(expectedResult);
});
Expand Down Expand Up @@ -102,9 +112,9 @@ describe("Get name", () => {
["battery kitchen6", undefined, "Battery kitchen6"],
])("KString in the name", (entityName: string, renameRules: IBulkRename | IConvert | IConvert[] | undefined, expectedResult: string) => {
const hassMock = new HomeAssistantMock(true);
hassMock.addEntity("My entity", "45", { friendly_name: entityName });
const entity = hassMock.addEntity("My entity", "45", { friendly_name: entityName });

let result = getName({entity: "my_entity", bulk_rename: renameRules}, hassMock.hass, {});
let result = getName({entity: "my_entity", bulk_rename: renameRules}, hassMock.hass, hassMock.hass.states[entity.entity_id]);
expect(result).toBe(expectedResult);
})
});

0 comments on commit 86638f5

Please sign in to comment.