From b1acf9a057c99bfcb2568c3e301d0f5c153e7041 Mon Sep 17 00:00:00 2001 From: karwosts <32912880+karwosts@users.noreply.github.com> Date: Wed, 8 Jan 2025 05:36:19 -0800 Subject: [PATCH] Enable Statistics Graph card to integrate with Energy Dashboard (V2) (#23478) * Simplify date subtraction * Enable Statistics Graph card to integrate with Energy Dashboard Adds boolean option `energy_date_selection` to Statistics Graph card. If true, the graph will set its time range to that specified by an Energy Date Picker card on the same dashboard, similar to the plots on the Energy Dashboard. * Revert UI addition PR reviewer suggested it was too confusing, especially without dynamically hiding the overridden days_to_show option. * Remove boolean param energy_date_selection and instead activate when collection_key is specified * Revert "Remove boolean param energy_date_selection" This reverts commit 95cebdbbe35dcb04339b940e929fe5db0094721a. * Don't assume !20903 has merged * updates * refresh when collection_key changes --------- Co-authored-by: Andrew Reiter --- .../energy/common/energy-chart-options.ts | 9 +- .../cards/hui-statistics-graph-card.ts | 100 +++++++++++++++--- src/panels/lovelace/cards/types.ts | 3 +- 3 files changed, 93 insertions(+), 19 deletions(-) diff --git a/src/panels/lovelace/cards/energy/common/energy-chart-options.ts b/src/panels/lovelace/cards/energy/common/energy-chart-options.ts index a366122525..3e1328501c 100644 --- a/src/panels/lovelace/cards/energy/common/energy-chart-options.ts +++ b/src/panels/lovelace/cards/energy/common/energy-chart-options.ts @@ -33,6 +33,12 @@ export function getSuggestedMax(dayDifference: number, end: Date): number { return suggestedMax.getTime(); } +export function getSuggestedPeriod( + dayDifference: number +): "month" | "day" | "hour" { + return dayDifference > 35 ? "month" : dayDifference > 2 ? "day" : "hour"; +} + export function getCommonOptions( start: Date, end: Date, @@ -91,8 +97,7 @@ export function getCommonOptions( : dayDifference > 0 ? "datetime" : "hour", - minUnit: - dayDifference > 35 ? "month" : dayDifference > 2 ? "day" : "hour", + minUnit: getSuggestedPeriod(dayDifference), }, }, y: { diff --git a/src/panels/lovelace/cards/hui-statistics-graph-card.ts b/src/panels/lovelace/cards/hui-statistics-graph-card.ts index 4e703dafb4..d5b0c147f7 100644 --- a/src/panels/lovelace/cards/hui-statistics-graph-card.ts +++ b/src/panels/lovelace/cards/hui-statistics-graph-card.ts @@ -1,9 +1,12 @@ -import type { HassEntity } from "home-assistant-js-websocket"; +import type { HassEntity, UnsubscribeFunc } from "home-assistant-js-websocket"; +import { subHours, differenceInDays } from "date-fns"; import type { CSSResultGroup, PropertyValues } from "lit"; import { css, html, LitElement, nothing } from "lit"; import { customElement, property, state } from "lit/decorators"; import { classMap } from "lit/directives/class-map"; import "../../../components/ha-card"; +import { getEnergyDataCollection } from "../../../data/energy"; +import { getSuggestedPeriod } from "./energy/common/energy-chart-options"; import type { Statistics, StatisticsMetaData, @@ -69,8 +72,15 @@ export class HuiStatisticsGraphCard extends LitElement implements LovelaceCard { private _statTypes?: Array; + private _energySub?: UnsubscribeFunc; + + @state() private _energyStart?: Date; + + @state() private _energyEnd?: Date; + public disconnectedCallback() { super.disconnectedCallback(); + this._unsubscribeEnergy(); if (this._interval) { clearInterval(this._interval); this._interval = undefined; @@ -82,7 +92,32 @@ export class HuiStatisticsGraphCard extends LitElement implements LovelaceCard { if (!this.hasUpdated) { return; } - this._setFetchStatisticsTimer(); + if (this._config?.energy_date_selection) { + this._subscribeEnergy(); + } else { + this._setFetchStatisticsTimer(); + } + } + + private _subscribeEnergy() { + if (!this._energySub) { + this._energySub = getEnergyDataCollection(this.hass!, { + key: this._config?.collection_key, + }).subscribe((data) => { + this._energyStart = data.start; + this._energyEnd = data.end; + this._getStatistics(); + }); + } + } + + private _unsubscribeEnergy() { + if (this._energySub) { + this._energySub(); + this._energySub = undefined; + } + this._energyStart = undefined; + this._energyEnd = undefined; } public getCardSize(): number { @@ -150,6 +185,27 @@ export class HuiStatisticsGraphCard extends LitElement implements LovelaceCard { | StatisticsGraphCardConfig | undefined; + if (this.hass) { + if (this._config.energy_date_selection && !this._energySub) { + this._subscribeEnergy(); + return; + } + if (!this._config.energy_date_selection && this._energySub) { + this._unsubscribeEnergy(); + this._setFetchStatisticsTimer(); + return; + } + if ( + this._config.energy_date_selection && + this._energySub && + changedProps.has("_config") && + oldConfig?.collection_key !== this._config.collection_key + ) { + this._unsubscribeEnergy(); + this._subscribeEnergy(); + } + } + if ( changedProps.has("_config") && oldConfig?.entities !== this._config.entities @@ -175,9 +231,22 @@ export class HuiStatisticsGraphCard extends LitElement implements LovelaceCard { this._getStatistics(); // statistics are created every hour clearInterval(this._interval); - this._interval = window.setInterval( - () => this._getStatistics(), - this._intervalTimeout + if (!this._config?.energy_date_selection) { + this._interval = window.setInterval( + () => this._getStatistics(), + this._intervalTimeout + ); + } + } + + private get _period() { + return ( + this._config?.period ?? + (this._energyStart && this._energyEnd + ? getSuggestedPeriod( + differenceInDays(this._energyEnd, this._energyStart) + ) + : undefined) ); } @@ -198,7 +267,7 @@ export class HuiStatisticsGraphCard extends LitElement implements LovelaceCard { .isLoadingData=${!this._statistics} .statisticsData=${this._statistics} .metadata=${this._metadata} - .period=${this._config.period} + .period=${this._period} .chartType=${this._config.chart_type || "line"} .statTypes=${this._statTypes!} .names=${this._names} @@ -231,14 +300,13 @@ export class HuiStatisticsGraphCard extends LitElement implements LovelaceCard { } private async _getStatistics(): Promise { - const startDate = new Date(); - startDate.setTime( - startDate.getTime() - - 1000 * - 60 * - 60 * - (24 * (this._config!.days_to_show || DEFAULT_DAYS_TO_SHOW) + 1) - ); + const startDate = + this._energyStart ?? + subHours( + new Date(), + 24 * (this._config!.days_to_show || DEFAULT_DAYS_TO_SHOW) + 1 + ); + const endDate = this._energyEnd; try { let unitClass; if (this._config!.unit && this._metadata) { @@ -264,9 +332,9 @@ export class HuiStatisticsGraphCard extends LitElement implements LovelaceCard { const statistics = await fetchStatistics( this.hass!, startDate, - undefined, + endDate, this._entities, - this._config!.period, + this._period, unitconfig, this._statTypes ); diff --git a/src/panels/lovelace/cards/types.ts b/src/panels/lovelace/cards/types.ts index 9a7d555b7f..36b5345784 100644 --- a/src/panels/lovelace/cards/types.ts +++ b/src/panels/lovelace/cards/types.ts @@ -360,7 +360,7 @@ export interface HistoryGraphCardConfig extends LovelaceCardConfig { split_device_classes?: boolean; } -export interface StatisticsGraphCardConfig extends LovelaceCardConfig { +export interface StatisticsGraphCardConfig extends EnergyCardBaseConfig { title?: string; entities: Array; unit?: string; @@ -373,6 +373,7 @@ export interface StatisticsGraphCardConfig extends LovelaceCardConfig { fit_y_data?: boolean; hide_legend?: boolean; logarithmic_scale?: boolean; + energy_date_selection?: boolean; } export interface StatisticCardConfig extends LovelaceCardConfig {