/** * Luma Weather Card — custom Lovelace card * Shows current conditions + 5-day forecast in the Luma glass style. */ const WEATHER_VERSION = '1.0.0'; const WEATHER_ICONS = { 'clear-night': 'mdi:weather-night', 'cloudy': 'mdi:weather-cloudy', 'fog': 'mdi:weather-fog', 'hail': 'mdi:weather-hail', 'lightning': 'mdi:weather-lightning', 'lightning-rainy': 'mdi:weather-lightning-rainy', 'partlycloudy': 'mdi:weather-partly-cloudy', 'pouring': 'mdi:weather-pouring', 'rainy': 'mdi:weather-rainy', 'snowy': 'mdi:weather-snowy', 'snowy-rainy': 'mdi:weather-snowy-rainy', 'sunny': 'mdi:weather-sunny', 'windy': 'mdi:weather-windy', 'windy-variant': 'mdi:weather-windy-variant', 'exceptional': 'mdi:alert-circle-outline', }; const CONDITION_LABELS = { 'clear-night': 'Clear Night', 'cloudy': 'Cloudy', 'fog': 'Foggy', 'hail': 'Hail', 'lightning': 'Thunderstorm', 'lightning-rainy': 'Thunderstorm', 'partlycloudy': 'Partly Cloudy', 'pouring': 'Heavy Rain', 'rainy': 'Rainy', 'snowy': 'Snowy', 'snowy-rainy': 'Sleet', 'sunny': 'Sunny', 'windy': 'Windy', 'windy-variant': 'Windy', 'exceptional': 'Exceptional', }; class LumaWeatherCard extends HTMLElement { set hass(hass) { this._hass = hass; if (!this._config) return; this._render(); } setConfig(config) { if (!config.entity) throw new Error('Missing entity'); this._config = config; } _render() { const hass = this._hass; const config = this._config; const stateObj = hass.states[config.entity]; if (!stateObj) { this.innerHTML = `
Entity not found: ${config.entity}
`; return; } const condition = stateObj.state; const temp = stateObj.attributes.temperature; const unit = stateObj.attributes.temperature_unit || '°C'; const humidity = stateObj.attributes.humidity; const windSpeed = stateObj.attributes.wind_speed; const windUnit = stateObj.attributes.wind_speed_unit || 'km/h'; const icon = WEATHER_ICONS[condition] || 'mdi:weather-partly-cloudy'; const label = CONDITION_LABELS[condition] || condition; const forecast = stateObj.attributes.forecast || []; if (!this.shadowRoot) { this.attachShadow({ mode: 'open' }); const style = document.createElement('style'); style.textContent = WEATHER_STYLES; this.shadowRoot.appendChild(style); const wrap = document.createElement('div'); wrap.className = 'lw-wrap'; this.shadowRoot.appendChild(wrap); } const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; const forecastDays = forecast.slice(0, 5); this.shadowRoot.querySelector('.lw-wrap').innerHTML = `
${temp !== undefined ? Math.round(temp) : '–'}°
${label}
${humidity !== undefined ? humidity + '%' : '–'}
${windSpeed !== undefined ? windSpeed + ' ' + windUnit : '–'}
${forecastDays.length > 0 ? `
${forecastDays.map(f => { const d = new Date(f.datetime); const day = days[d.getDay()]; const fIcon = WEATHER_ICONS[f.condition] || 'mdi:weather-partly-cloudy'; const lo = f.templow !== undefined ? Math.round(f.templow) : '–'; const hi = f.temperature !== undefined ? Math.round(f.temperature) : '–'; return `
${day}
${hi}° ${lo}°
`; }).join('')}
` : ''}
`; } getCardSize() { return 4; } static getStubConfig() { return { entity: 'weather.forecast_home' }; } } const WEATHER_STYLES = ` :host { display: block; } .lw-card { background: rgba(34,38,46,0.88); border: 2px solid rgba(255,255,255,0.10); border-radius: 22px; padding: 22px; box-shadow: 0 2px 8px rgba(0,0,0,0.25); box-sizing: border-box; } .lw-now { display: flex; align-items: center; gap: 16px; margin-bottom: 16px; } .lw-icon-wrap { width: 72px; height: 72px; border-radius: 50%; background: rgba(245,184,90,0.18); display: flex; align-items: center; justify-content: center; flex-shrink: 0; } .lw-now-info { flex: 1; } .lw-temp { font-size: 48px; font-weight: 700; color: #fff; line-height: 1; letter-spacing: -0.03em; } .lw-condition { font-size: 17px; font-weight: 500; color: rgba(255,255,255,0.72); margin-top: 4px; } .lw-details { display: flex; gap: 20px; margin-bottom: 16px; } .lw-detail { display: flex; align-items: center; gap: 6px; font-size: 15px; font-weight: 500; color: rgba(255,255,255,0.72); } .lw-divider { height: 1px; background: rgba(255,255,255,0.10); margin-bottom: 16px; } .lw-forecast { display: flex; justify-content: space-between; } .lw-day { display: flex; flex-direction: column; align-items: center; gap: 6px; flex: 1; } .lw-day-name { font-size: 13px; font-weight: 600; color: rgba(255,255,255,0.60); text-transform: uppercase; letter-spacing: 0.04em; } .lw-day-range { display: flex; flex-direction: column; align-items: center; gap: 2px; } .lw-hi { font-size: 16px; font-weight: 700; color: #fff; } .lw-lo { font-size: 13px; font-weight: 500; color: rgba(255,255,255,0.50); } `; customElements.define('luma-weather-card', LumaWeatherCard); window.customCards = window.customCards || []; window.customCards.push({ type: 'luma-weather-card', name: 'Luma Weather Card', description: 'Weather card with 5-day forecast in the Luma glass design.', preview: true, }); console.info(`%c LUMA-WEATHER %c v${WEATHER_VERSION} `, 'background:#F5B85A;color:#15181E;font-weight:700', 'background:#22262E;color:#F5B85A');