Display live remaining time for timer on tile card (#21290)

Display timer by default on tile card
This commit is contained in:
Paul Bottein 2024-07-11 11:09:14 +02:00 committed by GitHub
parent d9583582e6
commit e59c04c685
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 101 additions and 146 deletions

View File

@ -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)})`;

View File

@ -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`
<state-display-timer
.hass=${this.hass}
.stateObj=${stateObj}
></state-display-timer>
`;
}
return this._renderStateContent(stateObj, "state");

View File

@ -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`
<hui-generic-entity-row .hass=${this.hass} .config=${this._config}>
<div class="text-content">
${computeDisplayTimer(this.hass, stateObj, this._timeRemaining)}
<state-display-timer
.hass=${this.hass}
.stateObj=${stateObj}
></state-display-timer>
</div>
</hui-generic-entity-row>
`;
}
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 {

View File

@ -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;
}
}

View File

@ -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`
<div class="horizontal justified layout">
@ -34,63 +23,21 @@ class StateCardTimer extends LitElement {
.inDialog=${this.inDialog}
></state-info>
<div class="state">
${this._displayState(this.timeRemaining, this.stateObj)}
<state-display-timer
.hass=${this.hass}
.stateObj=${this.stateObj}
></state-display-timer>
</div>
</div>
`;
}
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;