Custom Dark Sky Animated Weather Card

As I was trying to respond @itajackass who asked to see code on how tooltips were implemented, I noticed that I can no longer make changes to my original post that started this thread. Apparently this is by design of the admins (see this post: Edit Original Post?). I am not going to weigh in on whether this is a good or bad policy, it is what it is… Unfortunately it means that the code in that post, which no longer works due to the many changes to HA and Lovelace along the way, cannot be corrected.

So, for those interested, I have posted the current version of my card on GitHub. You can get it here:
dark-sky-weather-card.js

For installation / configuration instructions please see the following file: Readme

Please note that my version of the card does not contain all of the changes that others have made to the card. It is based on the original I posted that started this thread. I plan on reviewing the changes that people have made and potentially adding them to my card if appropriate. I will attempt to keep this post updated as I make changes.

This version works with 0.84. and incorporates tooltips to show the daily summary information.

image

Note that in my version of the card I add an extra forecast day (0). This was in response to a breaking change that was made a couple of versions ago. The original platform provided the 0 (current day) forecast items without explicitly requesting them. The breaking change made this work like the rest of the forecast days which also meant that the entities for forecast day 0 now had a _0 appended to them. This is important so that the overnight low forecast can be correctly set for each day. eg: Day 1’s overnight forecast should come from forecast 0 to match the way it is displayed on the DarkSky website.


Corrected / Added 12 Dec 18

  • Fixed Pressure UOM. The value returned from DarkSky is in millibars so the UOM now states mbar.
  • Added Tooltips for daily summary

Added 13 Dec 18

  • Added configuration flag capability
  • Added tooltips flag (turns daily summary tooltips on or off)
  • Added static_icons flag (switches between animated and static icons)

Added 14 Dec 18

  • Added sunset flag. Allows display of sunset and sunrise icons.
  • Added locale flag. Controls display of day names and time formats.

Added 16 Dec 18

  • Tooltips now match icon color scheme (change to .css file)
  • WInd direction localization now works for en, fr, it and de.

Modified 21 Dec 18

  • Refactored the entire card. It is now based on the light weight LitElement class instead of the HTMLElement class.
  • Moved all CSS code into the .js file. (The .css file is no longer needed.)
  • Added several configuration options for controlling the look and feel of the tooltips.

Special note: If you use this version and beyond you must change the resource type for the card to module from js. Failure to do so will result in the card not loading and an error thrown stating there is an invalid token on line 1.

resources:
  - type: module
    url: /local/custom_ui/dark-sky-weather-card.js?v=7.2

Old Instructions (prior to 21 Dec Update)

I will leave these in place in case anyone wants to see how tooltips can be implemented but these notes do not reflect how the card currently works.

For those interested in implementing tooltips in other versions of the card, it is probably easiest to use the dark-sky-weather-card.js file linked above as a reference. Below are the modifications I made to it.

  1. Modify each forecast object by adding a entity summary attribute (last line in block below to each day)
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, 
                 summary: this.config.entity_summary_1, };
  1. Add another css class to the ‘daily’ container (I called mine fcasttooltip)
  <div class="forecast clear">
      ${forecast.map(daily => `
          <div class="day fcasttooltip">
  1. Add the following line

<span class="fcasttooltiptext">${hass.states[daily.summary].state}</span>

As seen below:

image

The dark-sky-weather-card.css file also needs modification to implement the visibility and style of the tooltip class. Here are are the additions to the file:

dark-sky-weather-card.css (only showing additions)

.fcasttooltip {
  position: relative;
  display: inline-block;
}

.fcasttooltip .fcasttooltiptext {
  visibility: hidden;
  width: 110px;
  background-color: black;
  color: #fff;
  text-align: center;
  border-radius: 6px;
  padding: 5px 0;

  /* Position the tooltip */
  position: absolute;
  z-index: 1;
  bottom: 50%;
  left: 0%; 
  margin-left: -5px;
}

.fcasttooltip .fcasttooltiptext::after {
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  margin-left: -5px;
  border-width: 5px;
  border-style: solid;
  border-color: black transparent transparent transparent;
}

.fcasttooltip:hover .fcasttooltiptext {
  visibility: visible;
}

Also make sure to pass in the summary entities in ui-lovelace.yaml

entity_summary_1: sensor.dark_sky_summary_1
entity_summary_2: sensor.dark_sky_summary_2
entity_summary_3: sensor.dark_sky_summary_3
entity_summary_4: sensor.dark_sky_summary_4
entity_summary_5: sensor.dark_sky_summary_5
4 Likes

Thanks. Replaced with static icons. They also look beautiful and I don’t need the animated effect.

Really love this.
Is it possible to remove the 3-day summary at the bottom of the card?

yup, just remove this from the .js file

      <span class="threedaysum">
          <span style="font-weight:bold">${forecast[0].date}:</span> ${hass.states[this.config.entity_forecast_sum_1].state}<br>
          <span style="font-weight:bold">${forecast[1].date}:</span> ${hass.states[this.config.entity_forecast_sum_2].state}<br>
          <span style="font-weight:bold">${forecast[2].date}:</span> ${hass.states[this.config.entity_forecast_sum_3].state}<br>
      </span>      
1 Like

The tooltip thing is really cool. I will probably play around with it.
No worries about adapting my changes, I really liked the card, but there were a few things that I wanted to add/change for my purposes, and it kinda snowballed from there. Was a good learning experience.

I do think the language stuff I added is pretty useful so that others don’t need to edit the .js file. They just need to edit the yaml file.

Reading your post though, I’m trying to understand the overnight low thing. So forecast_0 (high and low) are both for today. And forecast_1 high is tomorrow daytime, and forecast_1 low is tomorrow night time. But you’re saying that the forecast_0 corresponds to the low for tomorrow hence why you’re putting those together.

Great stuff here. I am just about to move over to using Lovelace and this is the second custom card I have played around with. I currently have Lovelace: Group card working, yet I cannot get this custom card to work.
I have copy/pasted all the configs (.js, .css, darksy sensor, card) from above and also added

    - url: /local/custom_ui/dark-sky-weather-card.js
      type: js

to the ui-lovelace.yaml however I keep getting this error

https://XXXXXX.com/local/dark-sky-weather-card.js:17:13 TypeError: hass.config.core is undefined

Any chance I could get some pointers on how to solve this error? Is there any other configuration that I missed?

@m.p.frankland would an option to have either static or animated icons be possible? I utilise the animated icons and static icons in other places so it doesn’t make sense to just replace the animated with static.

@cjsimmons No need to actually replace the icons… Assuming you have both sets of icons in a directory structure like weather_icons/animated and weather_icons/static, simply replace the references in the dark-sky-weather-card.js file. There are two places that need to be updated. Replace the word animated with the word static in the following two lines of code.

<span class="icon bigger" style="background: none, url(/local/icons/weather_icons/animated/${weatherIcons[currentConditions]}.svg) no-repeat; background-size: contain;">${currentConditions}</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>

On a related note I am looking at how to pass flags into the card from the ui-lovelace.yaml file. If I can figure that out It would be possible to conditionaly have either set based on a setting.

It sounds like you are using the dark-sky-weather-card.js code from the original post. Unfortunately, there was a breaking change in Lovelace a few revisions ago that broke that code. As I can no longer edit that original post, I can’t update the code listed there. Please use the card source referenced in this post Custom Dark Sky Animated Weather Card. It has corrections that fix that error.

You will also need to add a version to your ui-lovelace.yaml file to get the new version to load. For example:

resources:
  - url: /local/custom_ui/dark-sky-weather-card.js?v=6.8
    type: js

Note the v=6.8 Everytime you change the card source code you must use a different v= number in order for Lovelace to realize that the card has changed. It doesn’t matter what the number is, it just needs to be different than the previous number. You can start at 1.0 as you don’t currently have a v= number specified.

Too easy. Now to decide if I like static or animate… :thinking:

Yah, The language stuff you added does seem pretty helpful. It is definitely one of the updates I would like to make to the base code of the card. Any issue with me “borrowing” your code ?

As far as the forecast goes, The way to think about it is:

Day 0 Forecast High = Today’s forecasted high temp
Day 0 Overnight Low = Tonight into tomorrow morning low temp
Day 1 Forecast High = Tomorrow’s forecasted high temp
Day 1 Overnight Low = Tomorrow night into Day 2’s morning low temp
etc …

The confusion is because the overnight low spans two distinct days. In reality it is really up to the individual if they want the low to be the morning low or night low. The DarySky site uses morning low so I tried to match that.

To add to the confusion the card shows the high temp first (on top). If the temps were displayed side by side from low to high it might make more intuitive sense… (hmmm… maybe a change to the card there)

Perfect! I had previously used the code from the original post, however I did switch to the new code and it still was not working. I had no idea about the version number and I was wondering why it was showing up in different people’s code. I also had my darksky sensor configured with a “name” which was causing some troubles. It now works great! Many thanks!

Added configuration flag ability to the card. So far the following two flags are available.

  1. tooltips (Turns daily summary tooltips on and off)
  2. static_icons (switches between static and animated icons)

Flags are entered into ui-lovelace.yaml file which should allow for some interesting configuration changes without having to edit the source js file.

        entity_summary_4: sensor.dark_sky_summary_4
        entity_summary_5: sensor.dark_sky_summary_5
        tooltips: true
        static_icons: false

Did you test it on HA 0.84.1 with new lovelace with config in /.storage ?

HI,

followed all your install instructions with the latest (dl’d today) and this is what shows:

18

no temp…and no station name or location?

suggestion/feature request: please add sun up/sun down to your card? I use this in my other custom crd, and it really is a nice addition as is the feels like below the temp:

28

code:

const windBft = hass.states[this.config.entity_wind_force].state;
const forecast = entity.attributes.forecast.slice(0, 5);
const apparent_temperature = hass.states[this.config.entity_apparent_temperature].state;

var sunSetOrRiseA = new Date(hass.states[this.config.entity_sun].attributes.next_setting);
var sunSetOrRiseIconA = "mdi:weather-sunset-down";
var sunSetOrRiseB = new Date(hass.states[this.config.entity_sun].attributes.next_rising);
var sunSetOrRiseIconB = "mdi:weather-sunset-up";
// A == sunset   B == sunrise
if ( hass.states[this.config.entity_sun].state == "above_horizon" ) {
    // sun has risen, but hasn't set
    // sunset is today (no date displayed). sunrise is tomorrow (display date)
    // next is sunset == A
    
    sunSetOrRiseA = sunSetOrRiseA.toLocaleTimeString();
    var ssrI = sunSetOrRiseA.lastIndexOf(":");
    sunSetOrRiseA = sunSetOrRiseA.substr(0,ssrI) + sunSetOrRiseA.substr(ssrI+4);
    sunSetOrRiseB = sunSetOrRiseB.toDateString().substr(0,3) + " " + sunSetOrRiseB.toLocaleTimeString();
    ssrI = sunSetOrRiseB.lastIndexOf(":");
    sunSetOrRiseB = sunSetOrRiseB.substr(0,ssrI) + sunSetOrRiseB.substr(ssrI+4);
} else {
    // next is sunrise == B
    var ss = sunSetOrRiseA;
    if ( new Date().getDate() != sunSetOrRiseB.getDate() ) {
        // sun hasn't risen, and it's not same day
        // so display dates for both
        sunSetOrRiseA = sunSetOrRiseB.toDateString().substr(0,3) + " " + sunSetOrRiseB.toLocaleTimeString();
        sunSetOrRiseB = ss.toDateString().substr(0,3) + " " + ss.toLocaleTimeString();
    } else {
        // sun hasn't risen, but it's the same day
        // since rise and set are today, no dates displayed
        sunSetOrRiseA = sunSetOrRiseB.toLocaleTimeString();
        sunSetOrRiseB = ss.toLocaleTimeString();
    }
    var ssrI = sunSetOrRiseA.lastIndexOf(":");
    sunSetOrRiseA = sunSetOrRiseA.substr(0,ssrI) + sunSetOrRiseA.substr(ssrI+4);
    ssrI = sunSetOrRiseB.lastIndexOf(":");
    sunSetOrRiseB = sunSetOrRiseB.substr(0,ssrI) + sunSetOrRiseB.substr(ssrI+4);
    sunSetOrRiseIconA = "mdi:weather-sunset-up";
    sunSetOrRiseIconB = "mdi:weather-sunset-down";
}

this.content.innerHTML = `
  <span class="header" >${currentCondition}</span><span class="weather">${station}</span>
  <span class="icon bigger" style="background: none, url(/local/weather/animated/${weatherIcons[currentCondition]}.svg) no-repeat; background-size: contain;"> </span>
  <ul style="list-style-type:none">
    <li><span class="temp">${temperature}</span><span class="tempc"> ${getUnit('temperature')}</span></li>
    <li><span class="tempa">Feels like ${apparent_temperature}</span><span class="unitc"> ${getUnit('temperature')}</span></li>
  </ul>
  <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=${sunSetOrRiseIconB}></ha-icon></span>${sunSetOrRiseB}</li>
    </ul>
    <ul class="variations">
        <li><span class="ha-icon"><ha-icon icon="mdi:weather-windy"></ha-icon></span>Bft: ${windBft} - ${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('visibility')}</span></li>
        <li><span class="ha-icon"><ha-icon icon=${sunSetOrRiseIconA}></ha-icon></span>${sunSetOrRiseA}</li>
    </ul>
  </span>
  <div class="forecast clear">
      ${forecast.map(daily => `
          <div class="day">
              <span class="dayname">${(new Date(daily.datetime)).toLocaleDateString((navigator.language) ? navigator.language : navigator.userLanguage, {weekday: 'short'}).split(' ')[0]}</span>
              <br><i class="icon" style="background: none, url(/local/weather/animated/forecast/${weatherIcons[daily.condition]}.svg);"></i>
              <br><span class="highTemp">${daily.temperature}${getUnit('temperature')}</span>
              <br><span class="lowTemp">${daily.templow}${getUnit('temperature')}</span>
          </div>`).join('')}
  </div>`;

}

I have mixed experiences with changing the code of the custom card myself, so would like to ask if you could have a look, and update yours (if you would) yourself to keep it all in working order…

never mind the big -1 in the screen shot, it is a remnant of the transition to HA 0.84.1 and issues with the weather cards… --UPDATE–(fixed that for now, a and the temp in your card also. I had another cuts weather card in the yaml and it was listed in succession. Apparently the css didn’t like that? dont know if that is even possible, but now that I’ve split this view up, have 1 at the top and the other further down the view, the cards she alright.??):

01

and

06

station name, condition and sunrise/set…

Another update…

This version adds two new flags.

  1. sunset : this flag enables or disables the display of sunset and sunrise icons. (Defaults to false/off)
  2. locale : this flag controls the locale used to display day names and time formats. (Defaults to en/english)
 sunset: true

locale: fr

2 Likes

nice!
will test immediately.

please help me out, I am wondering why this currentConditions variable is not displayed at all unless you comment out the icon:

  <span class="icon bigger" style="background: none, url(/local/weather/animated/${weatherIcons[currentConditions]}.svg) no-repeat; background-size: contain;">${currentConditions}</span>

AS said before, I wanted it to show in my card, so changed the config to:

this.content.innerHTML = `
  <span class="header" >${currentCondition}</span><span class="weather">${station}</span>
  <span class="icon bigger" style="background: none, url(/local/weather/animated/${weatherIcons[currentCondition]}.svg) no-repeat; background-size: contain;"> </span>

  <ul style="list-style-type:none">
    <li><span class="temp">${temperature}</span><span class="tempc"> ${getUnit('temperature')}</span></li>
    <li><span class="tempa">Feels like ${apparent_temperature}</span><span class="unitc"> ${getUnit('temperature')}</span></li>
  </ul>
  <span>

maybe you could try and see what happend if you added that?

station is:

const station = entity.attributes.friendly_name;

I just added your code but I get the following error :

dark-sky-weather-card.js:132:47 Uncaught TypeError: nextSunRise.getDate is not a function

Any idea what’s up ?

I did copy your dark-sky-weather-card.js and lovelace config.

I’m having the same exact error.

@Mariusthvdb] The value of currentConditions is actually displayed… It’s just hidden behind the icon. The purpose is to show a value if something bad happens to the icon or if Dark Sky adds a condition that isn’t mapped to an icon.

Not quite sure what your “Station” is. You are referencing an object called entity. What is that object? Where does it come from ?