Skip to content

Instantly share code, notes, and snippets.

@hazdik
Forked from arsaboo/weather-card.css
Created June 13, 2019 14:06
Show Gist options
  • Save hazdik/7f2c92032fe39489acb63bfd27b4d9fe to your computer and use it in GitHub Desktop.
Save hazdik/7f2c92032fe39489acb63bfd27b4d9fe to your computer and use it in GitHub Desktop.
.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%;
}
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