+
+
+ ${this._value === undefined
+ ? ""
+ : this._value === null
+ ? "?"
+ : formatNumber(this._value, this.hass.locale)}
+ ${this._config.unit ||
+ getDisplayUnit(
+ this.hass,
+ this._config.entity,
+ this._metadata
+ )}
+
+ ${this._footerElement}
+
+ `;
+ }
+
+ protected shouldUpdate(changedProps: PropertyValues): boolean {
+ // Side Effect used to update footer hass while keeping optimizations
+ if (this._footerElement) {
+ this._footerElement.hass = this.hass;
+ }
+ if (
+ changedProps.has("_value") ||
+ changedProps.has("_metadata") ||
+ changedProps.has("_error")
+ ) {
+ return true;
+ }
+ if (this._config) {
+ return hasConfigOrEntityChanged(this, changedProps);
+ }
+ return true;
+ }
+
+ protected firstUpdated() {
+ this._fetchStatistic();
+ this._fetchMetadata();
+ }
+
+ protected updated(changedProps: PropertyValues) {
+ super.updated(changedProps);
+ if (!this._config || !this.hass) {
+ return;
+ }
+
+ const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
+ const oldConfig = changedProps.get("_config") as
+ | EntityCardConfig
+ | undefined;
+
+ if (
+ !oldHass ||
+ !oldConfig ||
+ oldHass.themes !== this.hass.themes ||
+ oldConfig.theme !== this._config.theme
+ ) {
+ applyThemesOnElement(this, this.hass.themes, this._config!.theme);
+ }
+ }
+
+ private async _fetchStatistic() {
+ if (!this.hass || !this._config) {
+ return;
+ }
+ clearInterval(this._interval);
+ this._interval = window.setInterval(
+ () => this._fetchStatistic(),
+ 5 * 1000 * 60
+ );
+ try {
+ const stats = await fetchStatistic(
+ this.hass,
+ this._config.entity,
+ this._config.period
+ );
+ this._value = stats[this._config!.stat_type];
+ this._error = undefined;
+ } catch (e: any) {
+ this._error = e.message;
+ }
+ }
+
+ private async _fetchMetadata() {
+ if (!this.hass || !this._config) {
+ return;
+ }
+ try {
+ this._metadata = (
+ await getStatisticMetadata(this.hass, [this._config.entity])
+ )?.[0];
+ } catch (e: any) {
+ this._error = e.message;
+ }
+ }
+
+ private _handleClick(): void {
+ fireEvent(this, "hass-more-info", { entityId: this._config!.entity });
+ }
+
+ static get styles(): CSSResultGroup {
+ return [
+ css`
+ ha-card {
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ cursor: pointer;
+ outline: none;
+ }
+
+ .header {
+ display: flex;
+ padding: 8px 16px 0;
+ justify-content: space-between;
+ }
+
+ .name {
+ color: var(--secondary-text-color);
+ line-height: 40px;
+ font-weight: 500;
+ font-size: 16px;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ }
+
+ .icon {
+ color: var(--state-icon-color, #44739e);
+ line-height: 40px;
+ }
+
+ .info {
+ padding: 0px 16px 16px;
+ margin-top: -4px;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ line-height: 28px;
+ }
+
+ .value {
+ font-size: 28px;
+ margin-right: 4px;
+ }
+
+ .measurement {
+ font-size: 18px;
+ color: var(--secondary-text-color);
+ }
+ `,
+ ];
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "hui-statistic-card": HuiStatisticCard;
+ }
+}
diff --git a/src/panels/lovelace/cards/types.ts b/src/panels/lovelace/cards/types.ts
index 8d7fe21412..b697e7c48f 100644
--- a/src/panels/lovelace/cards/types.ts
+++ b/src/panels/lovelace/cards/types.ts
@@ -1,4 +1,4 @@
-import { StatisticType } from "../../../data/recorder";
+import { Statistic, StatisticType } from "../../../data/recorder";
import { ActionConfig, LovelaceCardConfig } from "../../../data/lovelace";
import { FullCalendarView, TranslationDict } from "../../../types";
import { Condition } from "../common/validate-condition";
@@ -10,6 +10,7 @@ import {
LovelaceRowConfig,
} from "../entity-rows/types";
import { LovelaceHeaderFooterConfig } from "../header-footer/types";
+import { HaDurationData } from "../../../components/ha-duration-input";
export interface AlarmPanelCardConfig extends LovelaceCardConfig {
entity: string;
@@ -309,6 +310,18 @@ export interface StatisticsGraphCardConfig extends LovelaceCardConfig {
chart_type?: "line" | "bar";
}
+export interface StatisticCardConfig extends LovelaceCardConfig {
+ title?: string;
+ entities: Array