/**
* 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 `
`;
}).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');