Custom animated weather card for Lovelace

I tried the change you suggested, but I still get the same error. Do you make this change in two places? Here is a copy of that small section of the js code…I tried changing both and just the first reference and I get the same error in the logs???

          const lengthUnit = hass.config.unit_system;
      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.unit_system[measure] || '';

Frustrated AH here. Why do I get no response or help but anytime someone else posts an issue they get a response? I heard the community is helpful, but I’m not so sure about that.

Mostly because ppl have no idea how to resolve your issue :frowning:

I got the same error after updating to 0.77.2.

MYIP:8123/local/custom_ui/dark-sky-weather-card.js?v=4:17:43 Uncaught TypeError: Cannot read property ‘unit_system’ of undefined

Tried the change as suggested by @wingy3181 , but no success…

Hope somebody knows how to fix this…

@arsaboo ??

@seaverd and @molano

Yes that was the change I made

The only thing I can suggest is to use Chrome Developer Tools and just debug the error.

Also getting this issue since upgrading, @wingy3181’s suggestion did not help here either :frowning:

There was a breaking change in the last release. Please use the latest files from my repo.
weather-card.js
weather-card.css

2 Likes

Hi @arsaboo , I just tried to set this up for the first time in 0.76.2 but got no card at all in the UI and the log shows:

https://xxx.xx.xx.x:8123/local/custom_ui/weather-card.js:17:50 Uncaught TypeError: Cannot read property ‘length’ of undefined

just wondering if this is an error in the file or something in my lovelace.yaml that is causing the issue…

my lovelace.yaml is as per post #1 of this thread

The card has now been updated for 0.77. It won’t work on anything before that.

I’m running 0.77.2 and i have the same error as the above

2018-09-02 23:25:31 ERROR (MainThread) [frontend.js.latest.201808180] /local/weather-card.js:17:50 Uncaught TypeError: Cannot read property ‘length’ of undefined

Clear your local cache. Or add version to resource file for that card.

Still doesn’t work with the changes. Can see weathercard don’t exist flashing by on reload.

Double check the permissions of the file and the file location.

@sparkydave @Kenvase
There was a breaking change in the HA config API. To fix the card change these lines in weather-card.js:

const lengthUnit = hass.config.unit_system.length;
to
const lengthUnit = hass.config.core.unit_system.length;

and
return hass.config.unit_system[measure] || '';
to
return hass.config.core.unit_system[measure] || '';

@arsaboo I need to mention you in another post because I just made an account here but that should fix the card. :slight_smile:

Noop that was what I had before 0.77.2 and .3. still not working. Tried latest from github no joy :frowning:

My modified version of this.

To do: change background picture based on season and day/night

2 Likes

That looks awesome! Would you mind sharing your code please?

dark-sky-weather-card.css:

.clear {
  clear: both;
}

.card {
  background: url(/local/pictures/summer_day.jpg);
  background-size: cover;
  background-repeat: no-repeat;
  margin: auto;
  padding-top: 2em;
  padding-bottom: 1em;
  padding-left: 1em;
  padding-right: 1em;
  position: relative;
}

.ha-icon {
  height: 18px;
  margin-right: 5px;
  color: var(--paper-item-icon-color);
}
.div{
  width: 90%;
  position: inherit;
  left: 5%;
  margin: 0 auto;
  display: inline-block;
  height: auto;
}
.div1 {
  width: auto;
  vertical-align: -1em;
  padding-left: 10%;
  padding-top: 4%
}
.div4 {
  float: right;
  width: auto;
  vertical-align: -1em;
}
.iconbigger {
  background: none;
  background-size: contain;
  width: 5.5em;
  height: 5.5em;
  vertical-align: -2.4em;
}
.temp {
  text-align: right;
  width: auto;
  margin-left: 5px;
  font-weight: 300;
  font-size: 5em;
  vertical-align: -0.5em;
  color: var(--primary-text-color);
}

.tempc {
  text-align: left;
  width: auto;
  font-weight: 300;
  font-size: 1.5em;
  margin-left: 5px;

  color: var(--primary-text-color);
}

.variations {
  font-weight: 300;
  color: var(--primary-text-color);
  list-style: none;
}


.variations.right {
  margin-left: 0em;
  margin-right: 1em;
}


.forecast {
  width: 100%;
  margin: 1 auto;
  height: 9em;
}

.topinfo {
  display: block;
  width: 25%;
  float: left;
  text-align: left;
  box-sizing: border-box;
}
.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 {
  width: 30px;
  height: 30px;
  margin-right: 5px;
  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%;
}

dark-sky-weather-card.js:

class DarkSkyWeatherCard extends HTMLElement {
  set hass(hass) {
    if (!this.content) {
      const card = document.createElement('ha-card');
      const link = document.createElement('link');
      link.type = 'text/css';
      link.rel = 'stylesheet';
      link.href = '/local/custom_ui/dark-sky-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.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.unit_system[measure] || '';
      }
    };

    const transformDayNight = {
      "below_horizon": "night",
      "above_horizon": "day",
    }
    const sunLocation = transformDayNight[hass.states[this.config.entity_sun].state];
    const weatherIcons = {
      'clear-day': 'sunny',
      'clear-night': 'nt_clear',
      'rain': 'rain',
      'snow': 'flurries',
      'sleet': 'chanceflurries',
      'wind': 'hazy',
      'fog': 'fog',
      'cloudy': 'cloudy',
      'partly-cloudy-day': 'partlycloudy',
      'partly-cloudy-night': 'nt_partlycloudy',
      'hail': 'sleet',
      'lightning': 'chancetstorms',
      'thunderstorm': 'tstorms',
      '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'
    ];

    var forecastDate1 = new Date();
    forecastDate1.setDate(forecastDate1.getDate()+1);
    var forecastDate2 = new Date();
    forecastDate2.setDate(forecastDate2.getDate()+2);
    var forecastDate3 = new Date();
    forecastDate3.setDate(forecastDate3.getDate()+3);
    var forecastDate4 = new Date();
    forecastDate4.setDate(forecastDate4.getDate()+4);
    var forecastDate5 = new Date();
    forecastDate5.setDate(forecastDate5.getDate()+5);


    const currentConditions = hass.states[this.config.entity_current_conditions].state;
    const humidity = hass.states[this.config.entity_humidity].state;
    const pressure = Math.round(hass.states[this.config.entity_pressure].state);
    const temperature = Math.round(hass.states[this.config.entity_temperature].state);
    const visibility = hass.states[this.config.entity_visibility].state;
    const windBearing = windDirections[(Math.round((hass.states[this.config.entity_wind_bearing].state / 360) * 16))];
    const windSpeed = Math.round(hass.states[this.config.entity_wind_speed].state);
    const forecast1 = { date: forecastDate1,
    				   condition: this.config.entity_forecast_icon_1,
    				   temphigh: this.config.entity_forecast_high_temp_1,
    				   templow:  this.config.entity_forecast_low_temp_1, };
    const forecast2 = { date: forecastDate2,
    				   condition: this.config.entity_forecast_icon_2,
    				   temphigh: this.config.entity_forecast_high_temp_2,
    				   templow:  this.config.entity_forecast_low_temp_2, };
    const forecast3 = { date: forecastDate3,
    				   condition: this.config.entity_forecast_icon_3,
    				   temphigh: this.config.entity_forecast_high_temp_3,
    				   templow:  this.config.entity_forecast_low_temp_3, };
    const forecast4 = { date: forecastDate4,
    				   condition: this.config.entity_forecast_icon_4,
    				   temphigh: this.config.entity_forecast_high_temp_4,
    				   templow:  this.config.entity_forecast_low_temp_4, };
    const forecast5 = { date: forecastDate5,
    				   condition: this.config.entity_forecast_icon_5,
    				   temphigh: this.config.entity_forecast_high_temp_5,
    				   templow:  this.config.entity_forecast_low_temp_5, };

    const forecast = [forecast1,forecast2,forecast3,forecast4,forecast5];


    this.content.innerHTML = `
    <div style="background: rgba(0, 0, 0, 0.55); /* Black background with transparency */">
    <div class="div" style="padding-left: 2%, padding-right: 2%">
      <div class="div div1">
        <img src="/local/icons/weather_icons/icons/${weatherIcons[currentConditions]}.png" class="iconbigger"></i>
      </div>
      <div class="div temp">
        ${temperature}
      </div>
      <div class="div tempc">
        ${getUnit('temperature')}
      </div>
    <div class="div div4">
        <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: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>
        </ul>
      </div>
    </div>
    <div class="forecast clear">
      ${forecast.map(daily => `
          <div class="day">
            <span class="dayname">${(daily.date).toString().split(' ')[0]}</span>
            <br><i class="icon" style="background: none, url(/local/icons/weather_icons/icons/${weatherIcons[hass.states[daily.condition].state]}.png) no-repeat; background-size: contain;"></i>
            <br><span class="highTemp">${Math.round(hass.states[daily.temphigh].state)}${getUnit('temperature')}</span>
            <br><span class="lowTemp">${Math.round(hass.states[daily.templow].state)}${getUnit('temperature')}</span>
          </div>`).join('')}
    </div></div>`;
  }

  setConfig(config) {
    if (!config.entity_current_conditions ||
    		!config.entity_humidity ||
    		!config.entity_pressure ||
     		!config.entity_temperature ||
    		!config.entity_visibility ||
    		!config.entity_wind_bearing ||
    		!config.entity_wind_speed) {
      throw new Error('Please define entities');
    }
    this.config = config;
  }

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

customElements.define('dark-sky-weather-card', DarkSkyWeatherCard);

background and icons located at: https://github.com/jknoflook/homeassistant

5 Likes

I am by no means great with html and css. There may be some glitches or formatting issues :slight_smile: