/** * Luma Toggle Card — Custom HA Lovelace card * Matches the TV app's toggle card visual spec. */ const LUMA_CARD_VERSION = '0.1.0'; class LumaToggleCard extends HTMLElement { static get properties() { return { hass: {}, config: {} }; } set hass(hass) { this._hass = hass; this._render(); } setConfig(config) { if (!config.entity) throw new Error('Entity is required'); this._config = { entity: config.entity, name: config.name || '', size: config.size || '1x1', accent_color: config.accent_color || '', glow_color: config.glow_color || '', icon: config.icon || '', tap_action: config.tap_action || { action: 'toggle' }, hold_action: config.hold_action || { action: 'more-info' }, confirmation: config.confirmation || false, ...config, }; this._render(); } getCardSize() { const size = this._config?.size || '1x1'; return size === '1x2' || size === '2x2' ? 4 : 2; } static getConfigElement() { return document.createElement('luma-card-editor'); } static getStubConfig() { return { entity: '', name: '', size: '1x1' }; } connectedCallback() { if (!this.shadowRoot) { this.attachShadow({ mode: 'open' }); } this._render(); } _getState() { if (!this._hass || !this._config) return null; return this._hass.states[this._config.entity]; } _isOn() { const state = this._getState(); return state && (state.state === 'on' || state.state === 'open' || state.state === 'unlocked'); } _getAccentColor() { if (this._config?.accent_color) return this._config.accent_color; const state = this._getState(); if (!state) return '#bbbbbb'; switch (state.state) { case 'on': case 'open': return '#7EB8DA'; case 'heat': case 'heat_cool': case 'auto': return '#f0a060'; case 'cool': return '#60b0f0'; default: return '#bbbbbb'; } } _getGlowColor() { if (this._config?.glow_color) return this._config.glow_color; const state = this._getState(); if (state?.attributes?.rgb_color) { const [r, g, b] = state.attributes.rgb_color; return `rgb(${r}, ${g}, ${b})`; } return '#fab95c'; } _getTypeLabel() { const entity = this._config?.entity || ''; if (entity.startsWith('light.')) return 'Light'; if (entity.startsWith('cover.')) return 'Cover'; if (entity.startsWith('switch.')) return 'Switch'; if (entity.startsWith('lock.')) return 'Lock'; return 'Toggle'; } _getStatusText() { const state = this._getState(); if (!state) return 'Unavailable'; const map = { on: 'On', off: 'Off', open: 'Open', closed: 'Closed', locked: 'Locked', unlocked: 'Unlocked' }; return map[state.state] || state.state; } _getIcon() { if (this._config?.icon) return this._config.icon; const entity = this._config?.entity || ''; if (entity.startsWith('light.')) return 'mdi:lightbulb'; if (entity.startsWith('cover.')) return 'mdi:curtains'; if (entity.startsWith('switch.')) return 'mdi:power-plug'; if (entity.startsWith('lock.')) return 'mdi:lock'; return 'mdi:toggle-switch'; } _handleClick() { if (!this._hass || !this._config) return; const action = this._config.tap_action?.action || 'toggle'; if (action === 'toggle') { this._hass.callService('homeassistant', 'toggle', { entity_id: this._config.entity }); } else if (action === 'more-info') { const event = new Event('hass-more-info', { composed: true }); event.detail = { entityId: this._config.entity }; this.dispatchEvent(event); } } _render() { if (!this.shadowRoot || !this._config) return; const isOn = this._isOn(); const accent = this._getAccentColor(); const glow = this._getGlowColor(); const typeLabel = this._getTypeLabel(); const name = this._config.name || this._getState()?.attributes?.friendly_name || this._config.entity.split('.')[1] || ''; const status = this._getStatusText(); const icon = this._getIcon(); this.shadowRoot.innerHTML = `
${typeLabel}
${name}
${status}
`; this.shadowRoot.querySelector('.card').addEventListener('click', () => this._handleClick()); } } customElements.define('luma-toggle-card', LumaToggleCard); window.customCards = window.customCards || []; window.customCards.push({ type: 'luma-toggle-card', name: 'Luma Toggle', description: 'Luma-style toggle card for lights, switches, and binary entities.', preview: true, }); console.info(`%c LUMA-TOGGLE-CARD %c v${LUMA_CARD_VERSION} `, 'background:#7EB8DA;color:#111;font-weight:bold', 'background:#161a22;color:#7EB8DA');