Skip to content
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
80 changes: 52 additions & 28 deletions src/data/logbook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,28 @@ export const getLogbookData = async (
hass: HomeAssistant,
startDate: string,
endDate: string,
entityId?: string
entityIds?: string[],
deviceIds?: string[]
): Promise<LogbookEntry[]> => {
const localize = await hass.loadBackendTranslation("device_class");
return addLogbookMessage(
hass,
localize,
await getLogbookDataCache(hass, startDate, endDate, entityId)
// bypass cache if we have a device ID
deviceIds?.length
? await getLogbookDataFromServer(
hass,
startDate,
endDate,
entityIds,
undefined,
deviceIds
)
: await getLogbookDataCache(hass, startDate, endDate, entityIds)
);
};

export const addLogbookMessage = (
const addLogbookMessage = (
hass: HomeAssistant,
localize: LocalizeFunc,
logbookData: LogbookEntry[]
Expand All @@ -86,60 +97,73 @@ export const addLogbookMessage = (
return logbookData;
};

export const getLogbookDataCache = async (
const getLogbookDataCache = async (
hass: HomeAssistant,
startDate: string,
endDate: string,
entityId?: string
entityId?: string[]
) => {
const ALL_ENTITIES = "*";

if (!entityId) {
entityId = ALL_ENTITIES;
}

const entityIdKey = entityId ? entityId.toString() : ALL_ENTITIES;
const cacheKey = `${startDate}${endDate}`;

if (!DATA_CACHE[cacheKey]) {
DATA_CACHE[cacheKey] = {};
}

if (entityId in DATA_CACHE[cacheKey]) {
return DATA_CACHE[cacheKey][entityId];
if (entityIdKey in DATA_CACHE[cacheKey]) {
return DATA_CACHE[cacheKey][entityIdKey];
}

if (entityId !== ALL_ENTITIES && DATA_CACHE[cacheKey][ALL_ENTITIES]) {
if (entityId && DATA_CACHE[cacheKey][ALL_ENTITIES]) {
const entities = await DATA_CACHE[cacheKey][ALL_ENTITIES];
return entities.filter((entity) => entity.entity_id === entityId);
return entities.filter(
(entity) => entity.entity_id && entityId.includes(entity.entity_id)
);
}

DATA_CACHE[cacheKey][entityId] = getLogbookDataFromServer(
DATA_CACHE[cacheKey][entityIdKey] = getLogbookDataFromServer(
hass,
startDate,
endDate,
entityId !== ALL_ENTITIES ? entityId : undefined
).then((entries) => entries.reverse());
return DATA_CACHE[cacheKey][entityId];
entityId
);
return DATA_CACHE[cacheKey][entityIdKey];
};

export const getLogbookDataFromServer = (
const getLogbookDataFromServer = (
hass: HomeAssistant,
startDate: string,
endDate?: string,
entityId?: string,
contextId?: string
) => {
let params: any = {
entityIds?: string[],
contextId?: string,
deviceIds?: string[]
): Promise<LogbookEntry[]> => {
// If all specified filters are empty lists, we can return an empty list.
if (
(entityIds || deviceIds) &&
(!entityIds || entityIds.length === 0) &&
(!deviceIds || deviceIds.length === 0)
) {
return Promise.resolve([]);
}

const params: any = {
type: "logbook/get_events",
start_time: startDate,
};
if (endDate) {
params = { ...params, end_time: endDate };
params.end_time = endDate;
}
if (entityIds?.length) {
params.entity_ids = entityIds;
}
if (deviceIds?.length) {
params.device_ids = deviceIds;
}
if (entityId) {
params = { ...params, entity_ids: entityId.split(",") };
} else if (contextId) {
params = { ...params, context_id: contextId };
if (contextId) {
params.context_id = contextId;
}
return hass.callWS<LogbookEntry[]>(params);
};
Expand All @@ -148,7 +172,7 @@ export const clearLogbookCache = (startDate: string, endDate: string) => {
DATA_CACHE[`${startDate}${endDate}`] = {};
};

export const getLogbookMessage = (
const getLogbookMessage = (
hass: HomeAssistant,
localize: LocalizeFunc,
state: string,
Expand Down
5 changes: 4 additions & 1 deletion src/dialogs/more-info/ha-more-info-logbook.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { startOfYesterday } from "date-fns/esm";
import { css, html, LitElement, PropertyValues, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";
import memoizeOne from "memoize-one";
import { isComponentLoaded } from "../../common/config/is_component_loaded";
import { fireEvent } from "../../common/dom/fire_event";
import "../../panels/logbook/ha-logbook";
Expand All @@ -16,6 +17,8 @@ export class MoreInfoLogbook extends LitElement {

private _time = { recent: 86400 };

private _entityIdAsList = memoizeOne((entityId: string) => [entityId]);

protected render(): TemplateResult {
if (!isComponentLoaded(this.hass, "logbook") || !this.entityId) {
return html``;
Expand All @@ -38,7 +41,7 @@ export class MoreInfoLogbook extends LitElement {
<ha-logbook
.hass=${this.hass}
.time=${this._time}
.entityId=${this.entityId}
.entityIds=${this._entityIdAsList(this.entityId)}
narrow
no-icon
no-name
Expand Down
56 changes: 43 additions & 13 deletions src/panels/config/areas/ha-config-area-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import "@material/mwc-button";
import { mdiImagePlus, mdiPencil } from "@mdi/js";
import "@polymer/paper-item/paper-item";
import "@polymer/paper-item/paper-item-body";
import { HassEntity } from "home-assistant-js-websocket/dist/types";
import {
HassEntity,
UnsubscribeFunc,
} from "home-assistant-js-websocket/dist/types";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import { ifDefined } from "lit/directives/if-defined";
Expand All @@ -20,18 +23,21 @@ import "../../logbook/ha-logbook";
import {
AreaRegistryEntry,
deleteAreaRegistryEntry,
subscribeAreaRegistry,
updateAreaRegistryEntry,
} from "../../../data/area_registry";
import { AutomationEntity } from "../../../data/automation";
import {
computeDeviceName,
DeviceRegistryEntry,
sortDeviceRegistryByName,
subscribeDeviceRegistry,
} from "../../../data/device_registry";
import {
computeEntityRegistryName,
EntityRegistryEntry,
sortEntityRegistryByName,
subscribeEntityRegistry,
} from "../../../data/entity_registry";
import { SceneEntity } from "../../../data/scene";
import { ScriptEntity } from "../../../data/script";
Expand All @@ -45,24 +51,19 @@ import {
loadAreaRegistryDetailDialog,
showAreaRegistryDetailDialog,
} from "./show-dialog-area-registry-detail";
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";

declare type NameAndEntity<EntityType extends HassEntity> = {
name: string;
entity: EntityType;
};

@customElement("ha-config-area-page")
class HaConfigAreaPage extends LitElement {
class HaConfigAreaPage extends SubscribeMixin(LitElement) {
@property({ attribute: false }) public hass!: HomeAssistant;

@property() public areaId!: string;

@property() public areas!: AreaRegistryEntry[];

@property() public devices!: DeviceRegistryEntry[];

@property() public entities!: EntityRegistryEntry[];

@property({ type: Boolean, reflect: true }) public narrow!: boolean;

@property() public isWide!: boolean;
Expand All @@ -71,6 +72,12 @@ class HaConfigAreaPage extends LitElement {

@property() public route!: Route;

@state() public _areas!: AreaRegistryEntry[];

@state() public _devices!: DeviceRegistryEntry[];

@state() public _entities!: EntityRegistryEntry[];

@state() private _related?: RelatedResult;

private _logbookTime = { recent: 86400 };
Expand All @@ -89,7 +96,7 @@ class HaConfigAreaPage extends LitElement {
registryDevices: DeviceRegistryEntry[],
registryEntities: EntityRegistryEntry[]
) => {
const devices = new Map();
const devices = new Map<string, DeviceRegistryEntry>();

for (const device of registryDevices) {
if (device.area_id === areaId) {
Expand All @@ -105,7 +112,7 @@ class HaConfigAreaPage extends LitElement {
if (entity.area_id === areaId) {
entities.push(entity);
}
} else if (devices.has(entity.device_id)) {
} else if (entity.device_id && devices.has(entity.device_id)) {
indirectEntities.push(entity);
}
}
Expand All @@ -118,6 +125,10 @@ class HaConfigAreaPage extends LitElement {
}
);

private _allDeviceIds = memoizeOne((devices: DeviceRegistryEntry[]) =>
devices.map((device) => device.id)
);

private _allEntities = memoizeOne(
(memberships: {
entities: EntityRegistryEntry[];
Expand All @@ -140,8 +151,26 @@ class HaConfigAreaPage extends LitElement {
}
}

protected hassSubscribe(): (UnsubscribeFunc | Promise<UnsubscribeFunc>)[] {
return [
subscribeAreaRegistry(this.hass.connection, (areas) => {
this._areas = areas;
}),
subscribeDeviceRegistry(this.hass.connection, (entries) => {
this._devices = entries;
}),
subscribeEntityRegistry(this.hass.connection, (entries) => {
this._entities = entries;
}),
];
}

protected render(): TemplateResult {
const area = this._area(this.areaId, this.areas);
if (!this._areas || !this._devices || !this._entities) {
return html``;
}

const area = this._area(this.areaId, this._areas);

if (!area) {
return html`
Expand All @@ -154,8 +183,8 @@ class HaConfigAreaPage extends LitElement {

const memberships = this._memberships(
this.areaId,
this.devices,
this.entities
this._devices,
this._entities
);
const { devices, entities } = memberships;

Expand Down Expand Up @@ -465,6 +494,7 @@ class HaConfigAreaPage extends LitElement {
.hass=${this.hass}
.time=${this._logbookTime}
.entityIds=${this._allEntities(memberships)}
.deviceIds=${this._allDeviceIds(memberships.devices)}
virtualize
narrow
no-icon
Expand Down
Loading