Skip to content
Draft
Show file tree
Hide file tree
Changes from 5 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 @@ import type {
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 @@ export class HuiAreaCard extends LitElement implements LovelaceCard {
}
);

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 @@ export class HuiAreaCard extends LitElement implements LovelaceCard {

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);
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
66 changes: 64 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,29 @@ export class HuiAreaCardEditor
},
] as const satisfies readonly HaFormSchema[])
: []),
...(displayType === "camera"
? ([
{
name: "camera_entity",
required: true,
default: cameraEntities?.[0],
selector: {
select: {
options:
cameraEntities === undefined
? []
: cameraEntities.map((entityId) => ({
label:
this.hass!.states[entityId]?.attributes
?.friendly_name || entityId,
value: entityId,
})),
mode: "dropdown",
},
},
},
] as const satisfies readonly HaFormSchema[])
: []),
],
},
{
Expand Down Expand Up @@ -299,6 +342,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 +433,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 +503,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 +604,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 @@ -7656,7 +7656,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