Custom Dark Sky Animated Weather Card

I’ve been following this thread but not updated anything till today. Just updated. Really nice. Thanks for this card.

1 Like

image

don’t what happened, but I can’t get the card to work at all any longer. Dl’d a fresh and unchanged copy just now to be sure, and this is what happens:

44
log:

local/lovelace/resources/dark-sky-weather-card.js?v=7.1:1:0 SyntaxError: Unexpected token '{'. import call expects exactly one argument.

__EDIT

well finally made it…
boiled down to an error I made in the module/js setting between the 2 cards, and the path.
since i have a separate dedicated path for forecast icons, your template was incorrect and I couldn’t change it in the card, without breaking its templating functionality. (I have a dedicated forecast folder because that was the solution for the blurry large icon in the pre-lovelace card)
I had edited the card, just like I did before, to point to the /forecast folder…
as I had the icons already in the regular folder, I simply had to remove that /forecast path. simple… duh.

had to refresh a couple of times, and now its there, using the dutch locale: nl:

57

sorry for bugging you.

please let me suggest a further enhancement: have the path to the icons as a configuration option setting. That way users don’t have to edit the card, and can adjust according to their own personal settings easily and safely.

path_animated_icons: 
path_animated_icons_forecast:
1 Like

Passing along some trouble-shooting and fixes I did to get this to work.
I’m running Hass (Ubuntu virtual-env) 0.84.6.
When it didn’t work, the logs revealed a couple of “undefined” when running the js file.
To get to work…
I had to change the .js

const getUnit = function (measure) {

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

// return hass.config.core.unit_system[measure] || ‘’;
return hass.config.unit_system[measure] || ‘’;

I also had to tweak the lovelace config slightly for hass.states[daily.templow].state was
being logged as undefined. The tweaks were made to match the actual entities.

    entity_forecast_low_temp_1: sensor.dark_sky_overnight_low_temperature_1
    entity_forecast_low_temp_2: sensor.dark_sky_overnight_low_temperature_2
    entity_forecast_low_temp_3: sensor.dark_sky_overnight_low_temperature_3
    entity_forecast_low_temp_4: sensor.dark_sky_overnight_low_temperature_4
    entity_forecast_low_temp_5: sensor.dark_sky_overnight_low_temperature_5

I think you might be using an old version… getUnit is not in the code any longer. It was replaced by a class property and getter method called getUOM a couple of versions ago.

// #####
// ##### getUOM: gets UOM for specified measure in either metric or imperial
// #####

  getUOM(measure) {
    
    const lengthUnit = this.hass.config.unit_system.length;
    
    switch (measure) {
      case 'air_pressure':
        return lengthUnit === 'km' ? 'hPa' : 'mbar';
      case 'length':
        return lengthUnit;
      case 'precipitation':
        return lengthUnit === 'km' ? 'mm' : 'in';
      default:
        return this.hass.config.unit_system[measure] || '';
    }
  }

Please see the following links: Custom Dark Sky Animated Weather Card, Custom Dark Sky Animated Weather Card, and the Readme: where the use of low_temperature_0 - 4 vs 1 -5 are discussed. If you want to use the 0th overnight low you need to add a 0 forecast day to your darksky sensor.

Yes looks like I was using an older version. Now updated. Thanks.

This is great! But… Anyone knows why there is wrong (moon) icon displayed for some days?

Weather

what editor is this? thanks

The Icons are based on the values passed back from the Dark Sky platform. It shows night icons because that is the value Dark Sky passed back.

Note the night Icons on Fri and Sun …
image

Here are the values being passed by Dark Sky. Note Icon_2 and Icon_4 (Fri and Sun) are night Icons.
image

Mine is showing the cloudy moon as well today.
My guess is that it is coming from sensor.dark_sky_icon_x
when the state is “partly-cloudy-night”; and thus from dark sky itself.

I found this link which may explain (and dark sky may change this):
https://darksky.net/dev/docs/faq#icon-selection

Based off the info on the dark sky site it looks like partly-cloudy-night is the only icon that behaves this way and it should be mapped to clear-day.

You can use template sensors to do the mapping.

  - platform: template
    sensors:
      dark_sky_mapped_icon_1:
        value_template: '{% if is_state("sensor.dark_sky_icon_1","partly-cloudy-night") %} clear-day {% else %} {{ states("sensor.dark_sky_icon_1") }} {% endif %}'
      dark_sky_mapped_icon_2:
        value_template: '{% if is_state("sensor.dark_sky_icon_2","partly-cloudy-night") %} clear-day {% else %} {{ states("sensor.dark_sky_icon_2") }} {% endif %}'
      dark_sky_mapped_icon_3:
        value_template: '{% if is_state("sensor.dark_sky_icon_3","partly-cloudy-night") %} clear-day {% else %} {{ states("sensor.dark_sky_icon_3") }} {% endif %}'
      dark_sky_mapped_icon_4:
        value_template: '{% if is_state("sensor.dark_sky_icon_4","partly-cloudy-night") %} clear-day {% else %} {{ states("sensor.dark_sky_icon_4") }} {% endif %}'
      dark_sky_mapped_icon_5:
        value_template: '{% if is_state("sensor.dark_sky_icon_5","partly-cloudy-night") %} clear-day {% else %} {{ states("sensor.dark_sky_icon_5") }} {% endif %}'

and then use these sensors for the icons in the card

entity_forecast_icon_1: sensor.dark_sky_mapped_icon_1
entity_forecast_icon_2: sensor.dark_sky_mapped_icon_2
entity_forecast_icon_3: sensor.dark_sky_mapped_icon_3
entity_forecast_icon_4: sensor.dark_sky_mapped_icon_4
entity_forecast_icon_5: sensor.dark_sky_mapped_icon_5

Thank you! I was having trouble with Cannot read property 'state' of undefined and totally glanced over the difference between low_temperature and low_temperature_1!

ERROR (MainThread) [frontend.js.latest.201812112] https://ip/local/custom_ui/dark-sky-weather-card.js?v=4:86:63 Uncaught TypeError: Cannot read property ‘state’ of undefined

trying to keep the number of states in my system down a bit> i have 2 dark sky sensors defined. One with all monitored conditions for the current day and 1 for the forecast conditions, but only a few:

  - platform: darksky
    api_key: !secret darksky_key
    name: dark_sky_forecast
    update_interval:
    # At least one of these must be specified:
      minutes: 720
    forecast:
      - 0
      - 1
      - 2
      - 3
      - 4
      - 5
    monitored_conditions:
      - summary
      - icon
      - temperature
      - temperature_high
      - temperature_low

all of these are fine except for the numbered temperature forecast:

25

is this a bug?

I don’t have any dark_sky_forecast_temperature states. The daily forecast high is in dark_sky_daytime_high_temperature_1 thru 5. As far as I know the Dark Sky API doesn’t return anything called forecast_temperature. Are those possibly template sensors?

I don’t think you are using the latest version from github as line 86 is a comment line in the latest version. Also, please post your configuration both the dark sky sensor config and your ui-lovelace.yaml (storage mode configuration if using .84 or above)

https://gist.github.com/abeksis/1d34af803db3b106f2eb7ab62eec8ac3

No, they are created by the component based on my sensor I posted above. They simply don’t get a value …

As you are not using the current version of the card, can you post the js file as well or at least lines around line 86

Well, its something to do with Dark Sky’s API / darksky sensor platform… I get dark_sky_temperature_1 thru 5 (not forecast_temperature). These all show as unknown for me. Maybe ask the folks who built the darksky sensor platform?

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.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-day': 'day',
      'clear-night': 'night',
      'rain': 'rainy-5',
      'snow': 'snowy-6',
      'sleet': 'rainy-6',
      'wind': 'cloudy',
      'fog': 'cloudy',
      'cloudy': 'cloudy',
      'partly-cloudy-day': 'cloudy-day-3',
      'partly-cloudy-night': 'cloudy-night-3',
      'hail': 'rainy-7',
      'lightning': 'thunder',
      'thunderstorm': 'thunder',
      '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 = `
      <span class="icon bigger" style="background: none, url(/local/icons/weather_icons/animated/${weatherIcons[currentConditions]}.svg) no-repeat; background-size: contain;">${currentConditions}</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>
        </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>
        </ul>
      </span>
      <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/animated/${weatherIcons[hass.states[daily.condition].state]}.svg) 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>
      <br><span class="unit">${hass.states[this.config.entity_daily_summary].state}</span></br>`;
  }

  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);