/*jshint esversion: 9 */ class GoogleTimersCard extends HTMLElement { set hass(hass) { const entityId = this.config.entity; const alarms_entityId = this.config.alarms_entity; const state = hass.states[entityId]; const state_alarms = hass.states[alarms_entityId]; if (state === undefined) { this.innerHTML = `
Entity not found: ${entityId}
`; return; } if (!this.content) { const card = document.createElement('ha-card'); this.content = document.createElement('div'); const style = document.createElement('style'); style.textContent = ` 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; } .no-header { padding: 16px 16px 0; } .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 { display: flex; padding: 0px 16px 16px; overflow: hidden; margin-top: -4px; white-space: nowrap; text-overflow: ellipsis; line-height: 28px; } .value { font-size: 28px; margin-right: 4px; } .timer { font-size: 20px; margin: 8px 4px -5px; } .alarm { font-size: 20px; margin: 8px 4px -5px; text-transform: capitalize; } .title { color: var(--secondary-text-color); font-size: 1.2em; padding: 0 5px 0 5px; text-transform: capitalize; font-weight: 500; } .duration { font-size: 0.7em; padding: 0 5px 0 5px; } .next { font-size: 0.7em; padding: 0 5px 15px 5px; text-transform: lowercase; overflow: hidden; white-space: wrap; text-overflow: ellipsis; } `; card.appendChild(style); card.appendChild(this.content); this.appendChild(card); } const STATE_UNKNOWN = "unknown" const STATE_UNAVAILABLE = "unavailable" const DEFAULT_ICON = "mdi:timer-sand" // STRINGS const NO_TIMERS = "None set"; const TIMER_IS_DONE = "TIMER DONE!"; // JSON attributes const JSON_TIMERS = "timers" const JSON_ALARMS = "alarms" const JSON_RECURRENCE = "recurrence" const JSON_DURATION = "duration"; const JSON_LOCAL_TIME = "local_time" const JSON_LOCAL_TIME_ISO = "local_time_iso"; const JSON_FIRE_TIME = "fire_time" const JSON_NAME = "label"; // ICONS const ICON_ALARM = "mdi:alarm"; const ICON_TIMER = "mdi:timer" const ICON_ALARM_DONE = "mdi:bell-ring"; const ICON_DURATION = "mdi:timelapse"; const ICON_ALARM_TIME = "mdi:clock"; const ICON_LABEL = "mdi:label-variant" const ICON_NEXT = "mdi:calendar-week" // TIME const STRING_HOURS = " h. " const STRING_MINUTES = " mins. " const STRING_SECONDS = " secs." var WEEKDAYS = { 1 : "mon.", 2 : "tue.", 3 : "wed.", 4 : "thu.", 5 : "fri.", 6 : "sat.", 0 : "sun." }; // Get's timedelta between now and fire_time function get_timedelta(ts) { return new Date((ts * 1000) - Date.now()); } // Format the timestring to match 1 h. 11 mins. 11 secs. . function format_to_human_readable(rt) { var h = rt.getUTCHours() > 0 ? rt.getUTCHours() + STRING_HOURS : "" var m = rt.getUTCMinutes() < 10 && rt.getUTCHours() > 1 ? "0"+ rt.getUTCMinutes() : rt.getUTCMinutes(); var s = rt.getUTCSeconds() < 10 ? "0"+ rt.getUTCSeconds() : rt.getUTCSeconds(); var ts = h + m + STRING_MINUTES + s + STRING_SECONDS; return ts; } function format_alarm_time(ts, is_ampm) { var d = new Date(ts * 1000) // var time = (d.toLocaleString(window.navigator.language, {weekday: 'long'})) + ': ' + d.getHours() + ':' + (d.getMinutes()<10?'0':'') + d.getMinutes() var time = d.toLocaleString(window.navigator.language, {weekday: 'long', hour: '2-digit', minute: '2-digit', hour12: is_ampm }) return time } const name = this.config.title || state.attributes['friendly_name']; const icon = this.config.icon || DEFAULT_ICON var timers = []; var alarms = []; var html = `` if (state.state != STATE_UNKNOWN) { timers = state.attributes[JSON_TIMERS]; if (this.config.alarms_entity && state_alarms.state != STATE_UNKNOWN) { alarms = state_alarms.attributes[JSON_ALARMS]; } } if (!this.config.hide_header) { // Header with name and icon html = `
${name}
`; } else { html = `
`; } // Checks if there is a timer set, and the loops through the sensor. Or else it shows a message. if (state.state != STATE_UNAVAILABLE || state_alarms.state != STATE_UNAVAILABLE) { for (const alarm of alarms) { var alarm_name = "" var alarm_icon = ICON_ALARM var alarm_next_icon = '' var alarm_next = "" var formatted_time = format_alarm_time(alarm[JSON_FIRE_TIME], this.config.use_12hour) var recurrence = "" if (alarm[JSON_RECURRENCE] != null && alarm[JSON_RECURRENCE].length >= 7) { recurrence = "all weekdays" alarm_next = alarm_next_icon } else if (alarm[JSON_RECURRENCE] != null) { alarm[JSON_RECURRENCE].forEach(function(entry) { recurrence += WEEKDAYS[entry] + " " }); alarm_next = alarm_next_icon } // If a label is set then it displays it else it shows nothing. if (alarm[JSON_NAME]) { alarm_name = "
" + alarm[JSON_NAME] + "
" } html += `
${alarm_name}
${formatted_time}${alarm_next}${recurrence}
`; } for (const timer of timers) { if (timer[JSON_DURATION] === undefined) { continue; } var timer_name = "" var alarm_time = "" var timer_icon = ICON_TIMER var remaining_time = get_timedelta(timer[JSON_FIRE_TIME]) var formatted_time = format_to_human_readable(remaining_time) if (Math.sign(remaining_time) == -1) { formatted_time = TIMER_IS_DONE timer_icon = ICON_ALARM_DONE } // If show_fire_time is true then it displays the time when the alarm will fire. if (this.config.show_fire_time) { alarm_time = "" + timer[JSON_LOCAL_TIME].split(" ")[1] + "" } // If a label is set then it displays it else it shows nothing. if (timer[JSON_NAME]) { timer_name = "
" + timer[JSON_NAME] + "
" } html += `
${timer_name}
${formatted_time}${timer[JSON_DURATION]}${alarm_time}
`; } } else { html += `
${NO_TIMERS}
`; } this.content.innerHTML = html; } setConfig(config) { if (!config.entity) { throw new Error('You need to define an entity'); } this.config = config; } getCardSize() { return 2 } } customElements.define('googletimers-card', GoogleTimersCard); window.customCards = window.customCards || []; window.customCards.push({ type: 'googletimers-card', name: 'Google Timers Card', preview: false, description: 'The Google Home timers card shows timers and alarms set in Google Home.' });