From f30a146c823b8eca55f961590912d4b506dfb320 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Thu, 4 Jul 2024 18:35:34 +0200 Subject: [PATCH 1/2] Display timer by default on tile card --- src/data/timer.ts | 2 +- src/panels/lovelace/cards/hui-tile-card.ts | 17 +++- .../entity-rows/hui-timer-entity-row.ts | 87 ++----------------- src/state-display/state-display-timer.ts | 74 ++++++++++++++++ src/state-summary/state-card-timer.ts | 67 ++------------ 5 files changed, 101 insertions(+), 146 deletions(-) create mode 100644 src/state-display/state-display-timer.ts diff --git a/src/data/timer.ts b/src/data/timer.ts index 7dc4f8e41dba..4b0ab1ce2768 100644 --- a/src/data/timer.ts +++ b/src/data/timer.ts @@ -92,7 +92,7 @@ export const computeDisplayTimer = ( return hass.formatEntityState(stateObj); } - let display = secondsToDuration(timeRemaining || 0); + let display = secondsToDuration(timeRemaining || 0) || "0"; if (stateObj.state === "paused") { display = `${display} (${hass.formatEntityState(stateObj)})`; diff --git a/src/panels/lovelace/cards/hui-tile-card.ts b/src/panels/lovelace/cards/hui-tile-card.ts index ae8c8a99c0b8..3208928d0273 100644 --- a/src/panels/lovelace/cards/hui-tile-card.ts +++ b/src/panels/lovelace/cards/hui-tile-card.ts @@ -311,10 +311,19 @@ export class HuiTileCard extends LitElement implements LovelaceCard { } if (domain === "update") { - return html`${computeUpdateStateDisplay( - stateObj as UpdateEntity, - this.hass! - )}`; + return html` + ${computeUpdateStateDisplay(stateObj as UpdateEntity, this.hass!)} + `; + } + + if (domain === "timer") { + import("../../../state-display/state-display-timer"); + return html` + + `; } return this._renderStateContent(stateObj, "state"); diff --git a/src/panels/lovelace/entity-rows/hui-timer-entity-row.ts b/src/panels/lovelace/entity-rows/hui-timer-entity-row.ts index bd58e41534b2..8cb3cac9a185 100644 --- a/src/panels/lovelace/entity-rows/hui-timer-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-timer-entity-row.ts @@ -1,7 +1,6 @@ -import { HassEntity } from "home-assistant-js-websocket"; -import { html, LitElement, PropertyValues, nothing } from "lit"; +import { LitElement, PropertyValues, html, nothing } from "lit"; import { customElement, property, state } from "lit/decorators"; -import { computeDisplayTimer, timerTimeRemaining } from "../../../data/timer"; +import "../../../state-display/state-display-timer"; import { HomeAssistant } from "../../../types"; import { hasConfigOrEntityChanged } from "../common/has-changed"; import "../components/hui-generic-entity-row"; @@ -14,42 +13,11 @@ class HuiTimerEntityRow extends LitElement { @state() private _config?: EntityConfig; - @state() private _timeRemaining?: number; - - private _interval?: number; - public setConfig(config: EntityConfig): void { if (!config) { throw new Error("Invalid configuration"); } this._config = config; - - if (!this.hass) { - return; - } - - const stateObj = this.hass!.states[this._config.entity]; - - if (stateObj) { - this._startInterval(stateObj); - } else { - this._clearInterval(); - } - } - - public disconnectedCallback(): void { - super.disconnectedCallback(); - this._clearInterval(); - } - - public connectedCallback(): void { - super.connectedCallback(); - if (this._config && this._config.entity) { - const stateObj = this.hass?.states[this._config!.entity]; - if (stateObj) { - this._startInterval(stateObj); - } - } } protected render() { @@ -70,61 +38,18 @@ class HuiTimerEntityRow extends LitElement { return html`
- ${computeDisplayTimer(this.hass, stateObj, this._timeRemaining)} +
`; } protected shouldUpdate(changedProps: PropertyValues): boolean { - if (changedProps.has("_timeRemaining")) { - return true; - } - return hasConfigOrEntityChanged(this, changedProps); } - - protected updated(changedProps: PropertyValues) { - super.updated(changedProps); - - if (!this._config || !changedProps.has("hass")) { - return; - } - const stateObj = this.hass!.states[this._config!.entity]; - const oldHass = changedProps.get("hass") as this["hass"]; - const oldStateObj = oldHass - ? oldHass.states[this._config!.entity] - : undefined; - - if (oldStateObj !== stateObj) { - this._startInterval(stateObj); - } else if (!stateObj) { - this._clearInterval(); - } - } - - private _clearInterval(): void { - if (this._interval) { - window.clearInterval(this._interval); - this._interval = undefined; - } - } - - private _startInterval(stateObj: HassEntity): void { - this._clearInterval(); - this._calculateRemaining(stateObj); - - if (stateObj.state === "active") { - this._interval = window.setInterval( - () => this._calculateRemaining(stateObj), - 1000 - ); - } - } - - private _calculateRemaining(stateObj: HassEntity): void { - this._timeRemaining = timerTimeRemaining(stateObj); - } } declare global { diff --git a/src/state-display/state-display-timer.ts b/src/state-display/state-display-timer.ts new file mode 100644 index 000000000000..13960c088cc4 --- /dev/null +++ b/src/state-display/state-display-timer.ts @@ -0,0 +1,74 @@ +import type { HassEntity } from "home-assistant-js-websocket"; +import { PropertyValues, ReactiveElement } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { computeDisplayTimer, timerTimeRemaining } from "../data/timer"; +import type { HomeAssistant } from "../types"; + +@customElement("state-display-timer") +class StateDisplayTimer extends ReactiveElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property({ attribute: false }) public stateObj!: HassEntity; + + @state() private timeRemaining?: number; + + private _updateRemaining: any; + + protected createRenderRoot() { + return this; + } + + protected update(changedProps: PropertyValues) { + super.update(changedProps); + this.innerHTML = + computeDisplayTimer(this.hass, this.stateObj, this.timeRemaining) ?? "-"; + } + + connectedCallback() { + super.connectedCallback(); + if (this.stateObj) { + this._startInterval(this.stateObj); + } + } + + disconnectedCallback() { + super.disconnectedCallback(); + this._clearInterval(); + } + + protected willUpdate(changedProp: PropertyValues): void { + super.willUpdate(changedProp); + if (changedProp.has("stateObj")) { + this._startInterval(this.stateObj); + } + } + + private _clearInterval() { + if (this._updateRemaining) { + clearInterval(this._updateRemaining); + this._updateRemaining = null; + } + } + + private _startInterval(stateObj: HassEntity) { + this._clearInterval(); + this._calculateRemaining(stateObj); + + if (stateObj.state === "active") { + this._updateRemaining = setInterval( + () => this._calculateRemaining(this.stateObj), + 1000 + ); + } + } + + private _calculateRemaining(stateObj: HassEntity) { + this.timeRemaining = timerTimeRemaining(stateObj); + } +} + +declare global { + interface HTMLElementTagNameMap { + "state-display-timer": StateDisplayTimer; + } +} diff --git a/src/state-summary/state-card-timer.ts b/src/state-summary/state-card-timer.ts index 57bb83e8e7be..134ebdb89c61 100644 --- a/src/state-summary/state-card-timer.ts +++ b/src/state-summary/state-card-timer.ts @@ -1,17 +1,10 @@ import type { HassEntity } from "home-assistant-js-websocket"; -import { - css, - CSSResultGroup, - html, - LitElement, - PropertyValues, - TemplateResult, -} from "lit"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property } from "lit/decorators"; import "../components/entity/state-info"; -import { computeDisplayTimer, timerTimeRemaining } from "../data/timer"; -import { HomeAssistant } from "../types"; import { haStyle } from "../resources/styles"; +import "../state-display/state-display-timer"; +import { HomeAssistant } from "../types"; @customElement("state-card-timer") class StateCardTimer extends LitElement { @@ -21,10 +14,6 @@ class StateCardTimer extends LitElement { @property({ type: Boolean }) public inDialog = false; - @property({ type: Number }) public timeRemaining?: number; - - private _updateRemaining: any; - protected render(): TemplateResult { return html`
@@ -34,63 +23,21 @@ class StateCardTimer extends LitElement { .inDialog=${this.inDialog} >
- ${this._displayState(this.timeRemaining, this.stateObj)} +
`; } - connectedCallback() { - super.connectedCallback(); - this._startInterval(this.stateObj); - } - - disconnectedCallback() { - super.disconnectedCallback(); - this._clearInterval(); - } - - protected willUpdate(changedProp: PropertyValues): void { - super.willUpdate(changedProp); - if (changedProp.has("stateObj")) { - this._startInterval(this.stateObj); - } - } - - private _clearInterval() { - if (this._updateRemaining) { - clearInterval(this._updateRemaining); - this._updateRemaining = null; - } - } - - private _startInterval(stateObj) { - this._clearInterval(); - this._calculateRemaining(stateObj); - - if (stateObj.state === "active") { - this._updateRemaining = setInterval( - () => this._calculateRemaining(this.stateObj), - 1000 - ); - } - } - - private _calculateRemaining(stateObj) { - this.timeRemaining = timerTimeRemaining(stateObj); - } - - private _displayState(timeRemaining, stateObj) { - return computeDisplayTimer(this.hass, stateObj, timeRemaining); - } - static get styles(): CSSResultGroup { return [ haStyle, css` .state { color: var(--primary-text-color); - margin-left: 16px; margin-inline-start: 16px; margin-inline-end: initial; From 78296f9eefb167d8c134a0484d69caee9a16d61a Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Thu, 4 Jul 2024 18:59:27 +0200 Subject: [PATCH 2/2] Fix energy selection card in grid layout --- .../energy/hui-energy-date-selection-card.ts | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/panels/lovelace/cards/energy/hui-energy-date-selection-card.ts b/src/panels/lovelace/cards/energy/hui-energy-date-selection-card.ts index d6ab8eb4929a..0b2ff5fa817b 100644 --- a/src/panels/lovelace/cards/energy/hui-energy-date-selection-card.ts +++ b/src/panels/lovelace/cards/energy/hui-energy-date-selection-card.ts @@ -1,17 +1,17 @@ import { - html, - LitElement, - nothing, - css, CSSResultGroup, + LitElement, PropertyValues, + css, + html, + nothing, } from "lit"; import { customElement, property, state } from "lit/decorators"; import { HomeAssistant } from "../../../../types"; +import { hasConfigChanged } from "../../common/has-changed"; import "../../components/hui-energy-period-selector"; -import { LovelaceCard } from "../../types"; +import { LovelaceCard, LovelaceLayoutOptions } from "../../types"; import { EnergyCardBaseConfig } from "../types"; -import { hasConfigChanged } from "../../common/has-changed"; @customElement("hui-energy-date-selection-card") export class HuiEnergyDateSelectionCard @@ -26,6 +26,13 @@ export class HuiEnergyDateSelectionCard return 1; } + public getLayoutOptions(): LovelaceLayoutOptions { + return { + grid_rows: 1, + grid_columns: 4, + }; + } + public setConfig(config: EnergyCardBaseConfig): void { this._config = config; } @@ -57,6 +64,13 @@ export class HuiEnergyDateSelectionCard static get styles(): CSSResultGroup { return css` + :host { + ha-card { + height: 100%; + display: flex; + flex-direction: column; + justify-content: center; + } .padded { padding-left: 16px !important; padding-inline-start: 16px !important;