Edit 10/26/2023:
Thanks to @jaaem this is now available as a HACS repository at https://github.com/Kethlak/card-alexa-alarms-timers
It’s got a few customization options based on requests people have made on this thread.
Original Post:
Using the Alexa Media Player component via HACS, I created a custom card to display all active timers on my Alexa. I was using Alexa Timer Card - #7 by miki3421 as a reference, and someone asked on there how to display all the active timers, but nobody ever responded. So here’s how I did it.
I created a file at /www/card-alexa-timers.js with this content:
class CardAlexaTimers extends HTMLElement {
// Whenever the state changes, a new `hass` object is set. Use this to
// update your content.
set hass(hass) {
// Initialize the content if it's not there yet.
this.hassStored = hass;
if(!this.initialized) {
// we only want to run this once
this.initialized = true;
this.alarms;
this.interval = window.setInterval(this.draw.bind(this), 500);
this.draw();
}
}
get hass() {
return this.hassStored;
}
// The user supplied configuration. Throw an exception and Lovelace will
// render an error card.
setConfig(config) {
this.config = config;
}
// The height of your card. Home Assistant uses this to automatically
// distribute all cards over the available columns.
getCardSize() {
return 3;
}
draw() {
const entities = this.config.entities;
this.alarms = [];
for(let i = 0; i < entities.length; i++) {
const attributes = this.hass.states[entities[i]].attributes;
if(attributes.hasOwnProperty('sorted_active')) {
const sorted_active = JSON.parse(attributes.sorted_active);
for(let j = 0; j < sorted_active.length; j++) {
const alarm = sorted_active[j][1];
this.alarms.push(new AlexaTimer(alarm.timerLabel, alarm.triggerTime));
}
}
}
this.alarms.sort((a,b) => a.remainingTime - b.remainingTime);
if (this.alarms.length === 0) {
this.innerHTML = '';
this.content = null;
}
if(this.alarms.length > 0) {
this.innerHTML = `
<ha-card header="Echo Timers">
<div class="card-content"></div>
</ha-card>
`;
this.content = this.querySelector('div');
let table = "<table border='0' width='100%'>";
for(let i = 0; i < this.alarms.length; i++) {
let name = this.alarms[i].label;
if(name === null) {
name = "Timer " + (i + 1);
}
let timeLeft = this.alarms[i].hours + ":" + addLeadingZero(this.alarms[i].minutes) + ":" + addLeadingZero(this.alarms[i].seconds);
table += "<tr>";
table += "<td>" + name + "</td>";
table += "<td>" + timeLeft + "</td>";
table += "</tr>";
}
table += "</table>";
this.content.innerHTML = table;
}
}
}
class AlexaTimer {
constructor(label, triggerTime) {
this.label = label;
this.triggerTime = triggerTime;
this.remainingTime = this.triggerTime - (new Date().getTime());
this.seconds = Math.floor(this.remainingTime / 1000);
this.minutes = Math.floor(this.seconds / 60);
this.hours = Math.floor(this.minutes / 60);
this.seconds = this.seconds % 60;
this.minutes = this.minutes % 60;
}
}
function addLeadingZero(num) {
if(num < 10) {
return "0" + num;
}
else {
return num.toString();
}
}
customElements.define('card-alexa-timers', CardAlexaTimers);
And then you have to go into Configuration > Dashboards > Resources tab and create a new resource with the url of “/local/card-alexa-timers.js” and type of “JavaScript module”. I tried to add this in my configuration.yaml file but couldn’t get that working either.
TIP: If you’re going to make changes to this, use a url like “/local/card-alexa-timers.js?v=1” and change the value after “v=” whenever you make changes. HA caches the resources otherwise and your changes won’t show up.
The custom card is only set up to work with a YAML dashboard, and the code for the card in the yaml looks like this:
cards:
- type: "custom:card-alexa-timers"
entities:
- sensor.front_room_dot_next_timer
- sensor.master_bedroom_dot_next_timer
Where you replace the list of entities with your own “_next_timer” entities created by the Alexa Media Player component.
I played around with binding to the hass timer event, but couldn’t get it working, so I used setInterval instead, but made sure I only run it once so it doesn’t clutter up the memory. Also, this card will disappear if there aren’t any active timers, which is how I wanted it to work.
Just thought I’d throw this out there in case anyone else was trying to do something similar and wanted some advice.