Skip to content
Draft
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
32 changes: 13 additions & 19 deletions src/panels/lovelace/cards/hui-area-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
LovelaceGridOptions,
} from "../types";
import type { AreaCardConfig } from "./types";
import { getCameraEntities } from "../editor/config-elements/hui-area-card-editor";

export const DEFAULT_ASPECT_RATIO = "16:9";

Expand Down Expand Up @@ -236,21 +237,6 @@
}
);

private _getCameraEntity = memoizeOne(
(
entities: HomeAssistant["entities"],
areaId: string
): string | undefined => {
const cameraFilter = generateEntityFilter(this.hass, {
area: areaId,
entity_category: "none",
domain: "camera",
});
const cameraEntities = Object.keys(entities).filter(cameraFilter);
return cameraEntities.length > 0 ? cameraEntities[0] : undefined;
}
);

private _computeActiveAlertStates(): HassEntity[] {
const areaId = this._config?.area;
const area = areaId ? this.hass.areas[areaId] : undefined;
Expand Down Expand Up @@ -496,10 +482,18 @@

const displayType = this._config.display_type || "picture";

const cameraEntityId =
displayType === "camera"
? this._getCameraEntity(this.hass.entities, area.area_id)
: undefined;
let cameraEntityId;

if (displayType === "camera") {
cameraEntityId = this._config?.camera_entity ?? undefined;

if (cameraEntityId === undefined) {
const cameraList = getCameraEntities(this.hass, this._config.area);

Check failure on line 491 in src/panels/lovelace/cards/hui-area-card.ts

View workflow job for this annotation

GitHub Actions / Lint and check format

Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
if (cameraList !== undefined && cameraList.length > 0) {
cameraEntityId = cameraList[0];
}
}
}

const ignoreAspectRatio = this.layout === "grid" || this.layout === "panel";

Expand Down
1 change: 1 addition & 0 deletions src/panels/lovelace/cards/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ export interface AreaCardConfig extends LovelaceCardConfig {
display_type?: AreaCardDisplayType;
/** @deprecated Use `display_type` instead */
show_camera?: boolean;
camera_entity?: string;
camera_view?: HuiImage["cameraView"];
aspect_ratio?: string;
sensor_classes?: string[];
Expand Down
58 changes: 56 additions & 2 deletions src/panels/lovelace/editor/config-elements/hui-area-card-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ const cardConfigStruct = assign(
display_type: optional(enums(["compact", "icon", "picture", "camera"])),
vertical: optional(boolean()),
camera_view: optional(string()),
camera_entity: optional(string()),
alert_classes: optional(array(string())),
sensor_classes: optional(array(string())),
features: optional(array(any())),
Expand All @@ -64,6 +65,24 @@ const cardConfigStruct = assign(
})
);

let availableCameraEntities;

export const getCameraEntities = memoizeOne(
(
// entities: HomeAssistant["entities"],
hass: any,
areaId: string
): string[] | undefined => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't really return undefined does it?

const cameraFilter = generateEntityFilter(hass!, {
area: areaId,
entity_category: "none",
domain: "camera",
});

return Object.keys(hass.entities).filter(cameraFilter);
}
);

@customElement("hui-area-card-editor")
export class HuiAreaCardEditor
extends LitElement
Expand All @@ -82,7 +101,8 @@ export class HuiAreaCardEditor
localize: LocalizeFunc,
displayType: AreaCardDisplayType,
binaryClasses: SelectOption[],
sensorClasses: SelectOption[]
sensorClasses: SelectOption[],
cameraEntities: string[] | undefined
) =>
[
{ name: "area", selector: { area: {} } },
Expand Down Expand Up @@ -154,6 +174,21 @@ export class HuiAreaCardEditor
},
] as const satisfies readonly HaFormSchema[])
: []),
...(displayType === "camera"
? ([
{
name: "camera_entity",
required: true,
default: cameraEntities?.[0],
selector: {
entity: {
include_entities: cameraEntities,
filter: [{ domain: "camera" }],
Comment on lines +185 to +186
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you don't need a domain filter if you've already whitelisted the list of cameras?

},
},
},
] as const satisfies readonly HaFormSchema[])
: []),
],
},
{
Expand Down Expand Up @@ -299,6 +334,11 @@ export class HuiAreaCardEditor

const displayType =
config.display_type || (config.show_camera ? "camera" : "picture");

availableCameraEntities = config.area
? getCameraEntities(this.hass, config.area)
: [];

this._config = {
...config,
display_type: displayType,
Expand Down Expand Up @@ -385,7 +425,8 @@ export class HuiAreaCardEditor
this.hass.localize,
displayType,
binarySelectOptions,
sensorSelectOptions
sensorSelectOptions,
availableCameraEntities
);

const vertical = this._config.vertical && displayType === "compact";
Expand Down Expand Up @@ -454,11 +495,23 @@ export class HuiAreaCardEditor
private _valueChanged(ev: CustomEvent): void {
const newConfig = ev.detail.value as AreaCardConfig;

availableCameraEntities = newConfig.area
? getCameraEntities(this.hass, newConfig.area)
: [];

if (this._config!.area !== newConfig.area) {
delete newConfig.camera_entity;
}

const config: AreaCardConfig = {
features: this._config!.features,
...newConfig,
};

if (this._config!.area !== newConfig.area) {
delete newConfig.camera_entity;
}

if (config.display_type !== "camera") {
delete config.camera_view;
}
Expand Down Expand Up @@ -543,6 +596,7 @@ export class HuiAreaCardEditor
return this.hass!.localize("ui.panel.lovelace.editor.card.area.name");
case "name":
case "camera_view":
case "camera_entity":
case "content":
case "interactions":
return this.hass!.localize(
Expand Down
2 changes: 1 addition & 1 deletion src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -7672,7 +7672,7 @@
"aspect_ratio": "Aspect ratio",
"aspect_ratio_ignored": "Will be ignored because the card is resized.",
"attribute": "Attribute",
"camera_image": "Camera entity",
"camera_entity": "Camera entity",
"image_entity": "Image entity",
"camera_view": "Camera view",
"camera_view_options": {
Expand Down
Loading