Custom animated weather card for Lovelace

Great, thank you. It works :+1:

1 Like

Easier just to append a new number at the end of you resources file:

Example:

resources:
  - url: /local/monster-card.js?v=2
    type: js

Keep updating that number every time you change the file

1 Like

Small update for card:

  • Card Titile added
  • Sunset and sunraise icons with info added
  • Automatic switch to your locale for day of the week naming
weather-card.js
class WeatherCard extends HTMLElement {
  set hass(hass) {
    if (!this.content) {
      const card = document.createElement('ha-card');
      card.header = this.config.entity_title;
      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);
    }

    const getUnit = function (measure) {
      const lengthUnit = hass.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 hass.config.core.unit_system[measure] || '';
      }
    };

    const transformDayNight = {
      "below_horizon": "night",
      "above_horizon": "day",
    }
    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.slice(0, 5);

    const sun = hass.states[this.config.entity_sun];
    const sunraise = sun.attributes.next_rising;
    const sunset = sun.attributes.next_setting;

    this.content.innerHTML = `
      <span class="icon bigger" style="background: none, url(/local/weather_icons/animated/${weatherIcons[currentCondition]}.svg) no-repeat; background-size: contain;">${currentCondition}</span>
      <span class="temp">${temperature}</span><span class="tempc"> ${getUnit('temperature')}</span>
      <span>
        <ul class="variations right">
            <li><span class="ha-icon"><ha-icon icon="mdi:water-percent"></ha-icon></span>${humidity}<span class="unit"> %</span></li>
            <li><span class="ha-icon"><ha-icon icon="mdi:gauge"></ha-icon></span>${pressure}<span class="unit"> ${getUnit('air_pressure')}</span></li>
            <li><span class="ha-icon"><ha-icon icon="mdi:weather-sunset-up"></ha-icon></span>${new Date(sunraise).toLocaleTimeString([], {hour: '2-digit', minute: '2-digit'})}</li>
        </ul>
        <ul class="variations">
            <li><span class="ha-icon"><ha-icon icon="mdi:weather-windy"></ha-icon></span>${windBearing} ${windSpeed}<span class="unit"> ${getUnit('length')}/h</span></li>
            <li><span class="ha-icon"><ha-icon icon="mdi:weather-fog"></ha-icon></span>${visibility}<span class="unit"> ${getUnit('length')}</span></li>
            <li><span class="ha-icon"><ha-icon icon="mdi:weather-sunset-down"></ha-icon></span>${new Date(sunset).toLocaleTimeString([], {hour: '2-digit', minute: '2-digit'})}</li>
        </ul>
      </span>
      <div class="forecast clear">
          ${forecast.map(daily => `
              <div class="day">
                  <span class="dayname">${(new Date(daily.datetime)).toLocaleDateString(hass.selectedLanguage || hass.language, { weekday: 'short' })}</span>
                  <br><i class="icon" style="background: none, url(/local/weather_icons/animated/${weatherIcons[daily.condition]}.svg) no-repeat; background-size: contain;"></i>
                  <br><span class="highTemp">${daily.temperature}${getUnit('temperature')}</span>
                  <br><span class="lowTemp">${daily.templow}${getUnit('temperature')}</span>
              </div>`).join('')}
      </div>`;
  }

  setConfig(config) {
    if (!config.entity_weather || !config.entity_sun) {
      throw new Error('Please define entities');
    }
    this.config = config;
  }

  // @TODO: This requires more intelligent logic
  getCardSize() {
    return 3;
  }
}

customElements.define('weather-card', WeatherCard);
configuration example
- type: "custom:weather-card"
        entity_weather: weather.yweather
        entity_sun: sun.sun
        entity_title: myTitle
Screenshot

image

2 Likes

I think you changed the icon path in the new version. The folder /icons/ is no longer in the path. I changed it to /local/icons/weather_icons/animated and it works again for me :slight_smile:

Yes. I forgot to mention it. It’s point to same location as for old UI version.

Given that we have space between speed and precipitation, may be we can have 3 columns

I modified weather-card and created a dark-sky-weather-card. It uses the Dark Sky Sensor platform not Dark Sky Weather. This is a bit off topic for this thread so if you are interested in it start a new thread and I would be happy to share how I did it.

Great! I’m in. Darksky is more accurate for my location.

Hi arsaboo. Screenshot was made from desktop. On mobile there is not much space.

This card gives me the same error but only if I embed it in a horizontal or vertical stack. It works fine if I just put it into a view by itself. So the weird thing is that the red error flashes for maybe a half second even though the card ultimately loads.

It is not designed to fit in a stack.

i understand it might be designed to “fit”. but that means a big red error stack is expected? let me clarify as i left out a detail: i’m putting this card with an grafana iframe into a horizontal-stack. so yeah that doesn’t look good but notice no error stack ok?

1

so to fill the view i simply set “panel: true” in the view and it’ll look fantastic right? (next post)

…but when i set panel to true guess what happens?

2

so apologies but it’s setting the panel to true which breaks things in my case.

i’ll look further but basically it looks like when “panel: true” is set in the view the css from the card doesn’t get loaded, producing the error

4

There is a bug with custom cards and panel.

1 Like

If changing the frontend to es5, card is not working anymore and I’m getting:

image

just a suggestions: you might want to link to the raw files on github so people can just right click the files and save them.

Hi @arsaboo can we fix this please …

Lovelace:

Regular Card:

Remove the overlapping “Clear Sky”

I don’t think you are using the files from the original post.

Finally got it working , had to change ownership of the files and a couple of restart

I am not using yweather because its not that accuarte instead using openweathermap but get this error:

the weird part is that with the old instructions non lovelace it shows everything fine , any ideas ?

Thanks