UNPKG

homebridge-homeconnect

Version:

A Homebridge plugin that connects Home Connect appliances to Apple HomeKit

105 lines 4.43 kB
// Homebridge plugin for Home Connect home appliances // Copyright © 2023-2025 Alexander Thoukydides import { assertIsDefined, assertIsInstanceOf } from '../../utils.js'; import { cloneTemplate, getElementById, getSlot } from './utils-dom.js'; // Cards to select global or per-appliance configuration export class Cards { // Construct a new cards handler constructor(log) { this.log = log; // Current cards this.nonApplianceCards = []; this.applianceCards = []; this.parentElement = getElementById('hc-appliance-cards'); } // Update the list of non-appliance cards setNonAppliances(cards) { this.nonApplianceCards = cards; this.updateCards(); } // Update the list of appliances setAppliances(appliances) { // Convert the appliances to card descriptions const applianceCards = appliances.map(appliance => ({ id: appliance.haId, icon: appliance.type.toLocaleLowerCase(), name: appliance.name, detail: `${appliance.brand} ${appliance.enumber}` })); applianceCards.sort((a, b) => a.name.localeCompare(b.name)); // Check whether the list of appliances has changed if (JSON.stringify(applianceCards) !== JSON.stringify(this.applianceCards)) { this.applianceCards = applianceCards; this.updateCards(); } } // Update the list of cards and restore the selection, if still valid updateCards() { // Replace the existing cards with new ones const allCards = [...this.nonApplianceCards, ...this.applianceCards]; this.parentElement.replaceChildren(...allCards.map(card => this.makeCard(card))); this.parentElement.hidden = !allCards.length; // Restore any previous selection this.selectCard(this.selectedCardId); } // Create a new card makeCard({ id, icon, name, detail }) { // Create a new card from the template detail ?? (detail = ' '); // (non-breaking space) const card = cloneTemplate('hc-appliance-card', { name, detail }); this.loadCardIcon(getSlot(card, 'icon'), `./images/icon-${icon}.svg`, id); // Handle card selection const element = card.children[0]; assertIsInstanceOf(element, HTMLElement); element.dataset.id = id; element.onclick = () => { this.selectCard(id); }; return card; } // Load the icon image for a card async loadCardIcon(element, url, id) { try { // Load the icon and add it to the card const response = await fetch(url); if (!response.ok) throw new Error(`Failed to fetch icon ${response.url}: ${response.statusText}`); element.innerHTML = await response.text(); // Change the group (layer) IDs to classes element.querySelectorAll('g[id]').forEach(group => { const id = group.getAttribute('id'); assertIsDefined(id); group.removeAttribute('id'); group.classList.add(id); }); // Assign unique IDs to gradient fills element.querySelectorAll('defs [id]').forEach(def => { const oldId = def.getAttribute('id'); const newId = `${id}-${oldId}`; def.setAttribute('id', newId); element.querySelectorAll(`[fill='url(#${oldId})']`).forEach(ref => { ref.setAttribute('fill', `url(#${newId})`); }); }); } catch (err) { this.log.error(`loadCardIcon(${id}) =>`, err); } } // A card has been selected selectCard(id) { // Select this card and deselect all others let selectedCard; for (const card of Array.from(this.parentElement.children)) { assertIsInstanceOf(card, HTMLElement); if (card.dataset.id === id) selectedCard = card; card.classList.toggle('hc-selected', card.dataset.id === id); } if (!selectedCard) id = undefined; // Notify the client of selection changes if (this.selectedCardId !== id) { this.log.debug(`onSelect(${id}) (was ${this.selectedCardId})`); this.selectedCardId = id; this.onSelect?.(id); } } } //# sourceMappingURL=cards.js.map