-
-
Save hazdik/7f2c92032fe39489acb63bfd27b4d9fe to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.clear { | |
clear: both; | |
} | |
.card { | |
margin: auto; | |
padding-top: 2em; | |
padding-bottom: 1em; | |
padding-left: 1em; | |
padding-right:1em; | |
position: relative; | |
} | |
.iron-icon { | |
height: 18px; | |
color: var(--paper-item-icon-color); | |
} | |
.temp { | |
font-weight: 300; | |
font-size: 4em; | |
color: var(--primary-text-color); | |
position: absolute; | |
right: 1em; | |
} | |
.tempc { | |
font-weight: 300; | |
font-size: 1.5em; | |
vertical-align: super; | |
color: var(--primary-text-color); | |
position: absolute; | |
right: 1em; | |
margin-top: -14px; | |
margin-right: 7px; | |
} | |
.variations { | |
display: inline-block; | |
font-weight: 300; | |
color: var(--primary-text-color); | |
list-style: none; | |
margin-left: -2em; | |
margin-top: 3.5em; | |
} | |
.variations.right { | |
position: absolute; | |
right: 1em; | |
margin-left: 0; | |
margin-right: 1em; | |
} | |
.unit { | |
font-size: .8em; | |
} | |
.forecast { | |
width: 100%; | |
margin: 0 auto; | |
height: 9em; | |
} | |
.day { | |
display: block; | |
width: 20%; | |
float: left; | |
text-align: center; | |
color: var(--primary-text-color); | |
border-right: .1em solid #d9d9d9; | |
line-height: 2; | |
box-sizing: border-box; | |
} | |
.dayname { | |
text-transform: uppercase; | |
} | |
.forecast .day:first-child { | |
margin-left: 0; | |
} | |
.forecast .day:nth-last-child(1) { | |
border-right: none; | |
margin-right: 0; | |
} | |
.highTemp { | |
font-weight: bold; | |
} | |
.lowTemp { | |
color: var(--secondary-text-color); | |
} | |
.icon.bigger { | |
width: 10em; | |
height: 10em; | |
margin-top: -4em; | |
position: absolute; | |
left: 0em; | |
} | |
.icon { | |
width: 50px; | |
height: 50px; | |
display: inline-block; | |
vertical-align: middle; | |
background-size: contain; | |
background-position: center center; | |
background-repeat: no-repeat; | |
text-indent: -9999px; | |
} | |
.weather { | |
font-weight: 300; | |
font-size: 1.5em; | |
color: var(--primary-text-color); | |
text-align: left; | |
position: absolute; | |
top: -0.5em; | |
left: 6em; | |
word-wrap: break-word; | |
width: 30%; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class WeatherCard extends HTMLElement { | |
set hass(hass) { | |
if (!this.content) { | |
const card = document.createElement('ha-card'); | |
// card.header = 'Weather Forecast'; | |
const link = document.createElement('link'); | |
link.type = 'text/css'; | |
link.rel = 'stylesheet'; | |
link.href = '/local/custom_ui/weather-card.css'; | |
card.appendChild(link); | |
this.content = document.createElement('div'); | |
this.content.className = 'card'; | |
card.appendChild(this.content); | |
this.appendChild(card); | |
} | |
this.hassObj = hass; | |
const transformDayNight = { | |
"below_horizon": "night", | |
"above_horizon": "day", | |
} | |
const dayToDay = { | |
Mon: 'MON', | |
Tue: 'TUE', | |
Wed: 'WED', | |
Thu: 'THU', | |
Fri: 'FRI', | |
Sat: 'SAT', | |
Sun: 'SUN', | |
}; | |
const sunLocation = transformDayNight[hass.states[this.config.entity_sun].state]; | |
const weatherIcons = { | |
'clear-night': `${sunLocation}`, | |
'cloudy': 'cloudy', | |
'fog': 'cloudy', | |
'hail': 'rainy-7', | |
'lightning': 'thunder', | |
'lightning-rainy': 'thunder', | |
'partlycloudy': `cloudy-${sunLocation}-3`, | |
'pouring': 'rainy-6', | |
'rainy': 'rainy-5', | |
'snowy': 'snowy-6', | |
'snowy-rainy': 'rainy-7', | |
'sunny': `${sunLocation}`, | |
'windy': 'cloudy', | |
'windy-variant': `cloudy-${sunLocation}-3`, | |
'exceptional': '!!', | |
} | |
const windDirections = [ | |
'N', | |
'NNE', | |
'NE', | |
'ENE', | |
'E', | |
'ESE', | |
'SE', | |
'SSE', | |
'S', | |
'SSW', | |
'SW', | |
'WSW', | |
'W', | |
'WNW', | |
'NW', | |
'NNW', | |
'N' | |
]; | |
const entity = hass.states[this.config.entity_weather]; | |
const currentCondition = entity.state; | |
const humidity = entity.attributes.humidity; | |
const pressure = entity.attributes.pressure; | |
const temperature = Math.round(entity.attributes.temperature); | |
const visibility = entity.attributes.visibility; | |
const windBearing = windDirections[(parseInt((entity.attributes.wind_bearing + 11.25) / 22.5))]; | |
const windSpeed = entity.attributes.wind_speed; | |
const forecast = entity.attributes.forecast; | |
this.content.innerHTML = ` | |
<span class="icon bigger" style="background: none, url(/local/icons/weather_icons/animated/${weatherIcons[currentCondition]}.svg) no-repeat; background-size: contain;">${currentCondition}</span> | |
<span class="temp">${temperature}</span><span class="tempc"> ${this.getUnit('temperature')}</span> | |
<div> | |
<ul class="variations right"> | |
<li><span class="iron-icon"><iron-icon icon="mdi:water-percent"></iron-icon></span>${humidity}<span class="unit"> %</span></li> | |
<li><span class="iron-icon"><iron-icon icon="mdi:gauge"></iron-icon></span>${pressure}<span class="unit"> ${this.getUnit('temperature')}</span></li> | |
</ul> | |
<ul class="variations"> | |
<li><span class="iron-icon"><iron-icon icon="mdi:weather-windy"></iron-icon></span>${windBearing} ${windSpeed}<span class="unit"> mi/h</span></li> | |
<li><span class="iron-icon"><iron-icon icon="mdi:weather-fog"></iron-icon></span>${visibility}<span class="unit"> ${this.getUnit('length')}</span></li> | |
</ul> | |
</div> | |
<div class="forecast clear"> | |
${this.getForecastArray(forecast, weatherIcons, dayToDay).map(daily => | |
` | |
<div class="day"> | |
<span class="dayname">${daily.dayIT}</span> | |
<br><i class="icon" style="background: none, url(/local/icons/weather_icons/animated/${daily.condIcon}.svg) no-repeat; background-size: contain;"></i> | |
<br><span class="highTemp">${daily.tempHigh}${this.getUnit('temperature')}</span> | |
<br><span class="lowTemp">${daily.tempLow}${this.getUnit('temperature')}</span> | |
</div>`).join('')} | |
</div>`; | |
} | |
setConfig(config) { | |
if (!config.entity_weather || !config.entity_sun) { | |
throw new Error('Please define entities'); | |
} | |
this.config = config; | |
} | |
getUnit(measure) { | |
const lengthUnit = this.hassObj.config.core.unit_system.length; | |
switch (measure) { | |
case 'air_pressure': | |
return lengthUnit === 'km' ? 'hPa' : 'inHg'; | |
case 'length': | |
return lengthUnit; | |
case 'precipitation': | |
return lengthUnit === 'km' ? 'mm' : 'in'; | |
default: | |
return this.hassObj.config.core.unit_system[measure] || ''; | |
} | |
} | |
getForecastArray(foreast_attribute, weatherIcons, dayToDay) { | |
if (!foreast_attribute) { | |
return []; | |
} | |
var data = foreast_attribute; | |
var forecast = []; | |
var prevDay = ''; | |
for (var i = 0; i < data.length; i++) { | |
var day = new Date(data[i].datetime).toString().split(' ')[0]; | |
if (day != prevDay) { | |
if (data[i].max_temp) { | |
var tempHigh = Math.round(data[i].max_temp * 10) / 10; | |
} else { | |
var tempHigh = Math.round(data[i].temperature * 10) / 10; | |
} | |
if (tempHigh == 0) { | |
tempHigh = '0'; // otherwise the value 0 will not be shown on the weather card | |
} | |
var tempLow = Math.round(data[i].templow * 10) / 10; | |
if (tempLow == 0) { | |
tempLow = '0'; // otherwise the value 0 will not be shown on the weather card | |
} | |
var condIcon = weatherIcons[data[i].condition]; | |
var dayIT = dayToDay[day]; | |
forecast.push({ | |
dayIT: dayIT, | |
tempHigh: tempHigh, | |
tempLow: tempLow, | |
condIcon: condIcon | |
}); | |
prevDay = day; | |
} else { | |
if (data[i].max_temp) { | |
var tempHigh = Math.round(data[i].max_temp * 10) / 10; | |
} else { | |
var tempHigh = Math.round(data[i].temperature * 10) / 10; | |
} | |
var tempLow = Math.round(data[i].tempLow * 10) / 10; | |
if (tempLow > forecast[forecast.length - 1].tempHigh) { | |
forecast[forecast.length - 1].tempHigh = tempLow; | |
} | |
if (tempHigh > forecast[forecast.length - 1].tempHigh) { | |
forecast[forecast.length - 1].tempHigh = tempHigh; | |
} | |
if (!forecast[forecast.length - 1].tempLow) { | |
forecast[forecast.length - 1].tempLow = tempHigh; | |
} | |
if (tempHigh < forecast[forecast.length - 1].tempLow) { | |
forecast[forecast.length - 1].tempLow = tempHigh; | |
} | |
if (tempLow < forecast[forecast.length - 1].tempLow) { | |
forecast[forecast.length - 1].tempLow = tempLow; | |
} | |
} | |
} | |
return forecast.slice(0, 5); | |
} | |
// The height of your card. Home Assistant uses this to automatically | |
// distribute all cards over the available columns. | |
getCardSize() { | |
return 3; | |
} | |
} | |
customElements.define('weather-card', WeatherCard); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment