class StateDurationCard extends HTMLElement {
set hass(hass) {
this._hass = hass;
if (!this.content) {
const cardTitle = this.config.title || 'State Duration Totals';
this.innerHTML = `
| ${state} | ${formattedDuration} |
No data available for the selected period.
'; } } calculateTotals(states) { const totals = {}; const minDuration = this.config.min_duration_seconds * 1000; // Convert seconds to milliseconds for (let i = 0; i < states.length; i++) { const current = states[i]; const next = states[i + 1]; let duration = 0; if (next) { duration = next.last_changed - current.last_changed; } else { duration = new Date() - current.last_changed; // Until now } if (duration >= minDuration) { // Only add durations above the minimum if (!totals[current.state]) { totals[current.state] = 0; } totals[current.state] += duration; } } return totals; } formatDuration(ms) { const hours = Math.floor(ms / (1000 * 60 * 60)); const minutes = Math.floor((ms / (1000 * 60)) % 60); const seconds = Math.floor((ms / 1000) % 60); let duration = ''; if (hours > 0) { duration += `${hours} hours, `; } if (minutes > 0) { duration += `${minutes} minutes, `; } if (seconds > 0) { duration += `${seconds} seconds`; } return duration.trim().replace(/,\s*$/, ''); // Remove trailing comma if present } convertToLocalTime(utcDatetime) { return new Date(utcDatetime); } async fetchHistory(entityId, hours) { const endDate = new Date(); const startDate = new Date(endDate.getTime() - (hours * 60 * 60 * 1000)); const url = `history/period/${startDate.toISOString()}?filter_entity_id=${entityId}`; const response = await this._hass.callApi('GET', url); return response; } setConfig(config) { if (!config.entity) { throw new Error('You need to define an entity'); } this.config = { min_duration_seconds: 0, // Default value, showing all entries ...config }; } getCardSize() { return 3; } } customElements.define('state-duration-card', StateDurationCard);