Custom UI: Weather state card

That’s something in your config. It shows the pressure and visibility from weather.home and sensor.br_pressure and sensor.br_visibility. If you remove these then only one value will be shown.

You’re right. I have updated it so this is changed when I share a new version.

All credits go to @Bram_Kragten and @eddi89. All I did was making some changes in their version.
The graph is something that is standard available if you add e.g. Yahoo weather. That has nothing to do with this card.

Guess you already have those as you have a double entry for the pressure and visibility?
But this is what I use. Data is used from De Bilt weather station.

# Buienradar gegevens De Bilt
br_pressure_de_bilt:
  value_template: '{{ states.weather.de_bilt.attributes.pressure }}'
  friendly_name: "Luchtdruk"
  unit_of_measurement: 'hPa'
br_visibility_de_bilt:
  value_template: '{{ states.weather.de_bilt.attributes.visibility }}'
  friendly_name: "Zicht"
  unit_of_measurement: 'm'

yes they where there after all and north icons have changed as i set them in the html:

19

remarkably, the values are quite different, especially the visibility values…

I have that indeed, doubling the Yahoo info into 2 cards, just thought it would be nice to have it all in 1 card.

i see, why do you use a template for that if I may ask, and not just a direct sensor? You must have the station configured, so all options available ?

Cheers,
And thanks again,
Marius

@gerard33 I use https://www.home-assistant.io/components/sensor.airvisual/ platform that gets the following data

1 Like

@Mariusthvdb I’ve been experimenting with the blurry image and I seemed to resolve it by making a copy of the animated directory and then changing the reference to one of the image lookup line (you’ll see there’s two of them, sorry can’t look it up just yet since I’m not at my computer). You’ll have to delete the cache on your device you’re using but it seems to have resolved the issue.

1 Like

Anyone know what to put in the custom-weather-card.html to use the night icons instead of day? Last night it showed “Sunny” lol

There is the Openweathermap custom component that works with this card

I just map icon and string to 31 value like this:

  var _WEATHER_TO_ICON = {
    cloudy: 'cloudy',
    fog: 'cloudy-fog',
    hail: 'rainy-7',
    lightning: 'thunder',
    'lightning-rainy': 'thunder-rainy',
    partlycloudy: 'cloudy-day-3',
    pouring: 'rainy-6',
    rainy: 'rainy-5',
    snowy: 'snowy-6',
    'snowy-rainy': 'rainy-7',
    sunny: 'day',
    windy: 'windy-1',
    'windy-variant': 'windy-1',
    exceptional: '!!',
    31: 'night',
  };

  var _WEATHER_TO_NAME = {
    cloudy: 'Pochmurno',
    fog: 'Mglisto',
    hail: 'Gradobicie',
    lightning: 'Burzowo',
    'lightning-rainy': 'Deszcz z błyskawicami',
    partlycloudy: 'Częściowe zachmurzenie',
    pouring: 'Ulewnie',
    rainy: 'Deszczowo',
    snowy: 'Śnieżnie',
    'snowy-rainy': 'Deszcz ze śniegiem',
    sunny: 'Słonecznie',
    windy: 'Wietrznie',
    'windy-variant': 'Wiatr zmienny',
    exceptional: '!',
    31: 'Bezchmurnie',
  };

and it works.

2 Likes

Thank you so much! I’ve been looking for a fix for this for ages.

yweather component should be updated because the best way will be map 31 value to “clear-night” in yweather component and then map this string in custom weather state card.

But for now we can just use your workaround until yweather gets updated, right?

Sure. I created a pull request with yweather component modification.
I think that the UV index will be also useful but right now I don’t know how to get it beacuse it’s not exist in yahoo component.

I had ‘31’ and it wasn’t working but I guess it’s an integer and not a string. Thanks

for me work after reboot my pi3

It’s an integer. After homeassistant restart and clear browser cache it should work.
In the next Home Assistant release this value will be replaced with “clear-night” string.

2 Likes

Weather card update. Main changes:

  1. Now the weather map changes depending on the selected theme. @poebae
  2. Icons of the current weather vary depending on the time of day (the sun component is required)
custom-weather-card.html
<dom-module id='custom-weather-card'>
  <template>
    <style>
      .clear {
        clear:both;
      }
      .card {
        margin:1em auto;
        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 {
        font-weight:300;
        color: var(--primary-text-color);
        list-style:none;
        margin-left:-2em;
        margin-top: 3.5em;
      }
      .variations.right {
        float: right;
        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(2) {
        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%;
      }

    </style>
    <div class="card">
      <span class="icon bigger" style="background: none, url(/local/weather_icons/animated/[[nowCond]].svg) no-repeat; background-size: contain;"></span>
      <span class="temp">[[roundedTemp]]</span><span class="tempc">&#176;C</span>
      <span class="weather">[[nowCondIT]]</span>
      <br>
      <span>
        <ul class="variations right">
          <template is="dom-if" if="[[weatherObj.attributes.humidity]]">
            <li><span class="iron-icon"><iron-icon icon="mdi:water-percent"></iron-icon></span> [[weatherObj.attributes.humidity]]<span class="unit"> %</span></li>
          </template>
          <template is="dom-if" if="[[weatherObj.attributes.pressure]]">
            <li><span class="iron-icon"><iron-icon icon="mdi:gauge"></iron-icon></span> [[weatherObj.attributes.pressure]]<span class="unit"> hPa</span></li>
          </template>
          <template is="dom-if" if="[[pressureObj.state]]"> <!-- if weather station doesn't have pressure info, get it from a separate sensor -->
            <li><span class="iron-icon"><iron-icon icon="mdi:gauge"></iron-icon></span> [[nowPressure]]<span class="unit"> hPa</span></li>
          </template>
          <template is="dom-if" if="[[precipationfcObj.state]]">
            <li><span class="iron-icon"><iron-icon icon="mdi:weather-rainy"></iron-icon></span> [[nowPrecipationfc]]<span class="unit" > mm/u (> uur)</span></li>
          </template>

        </ul>
        <ul class="variations">
          <template is="dom-if" if="[[weatherObj.attributes.wind_speed]]">
            <li><span class="iron-icon"><iron-icon icon="mdi:weather-windy"></iron-icon></span> [[windBearing]] [[weatherObj.attributes.wind_speed]]<span class="unit"> m/s</span></li>
          </template>
          <template is="dom-if" if="[[weatherObj.attributes.visibility]]">
            <li><span class="iron-icon"><iron-icon icon="mdi:weather-fog"></iron-icon></span> [[weatherObj.attributes.visibility]]<span class="unit"> m</span></li>
          </template>
          <template is="dom-if" if="[[visibilityObj.state]]"> <!-- if weather station doesn't have visibility info, get it from a separate sensor -->
            <li><span class="iron-icon"><iron-icon icon="mdi:weather-fog"></iron-icon></span> [[nowVisibility]]<span class="unit" > m</span></li>
          </template>
          <template is="dom-if" if="[[precipationObj.state]]">
            <li><span class="iron-icon"><iron-icon icon="mdi:weather-pouring"></iron-icon></span> [[nowPrecipation]]<span class="unit" > mm/u</span></li>
          </template>
        </ul>
      </span>

      <div class="forecast clear">
        <template is="dom-repeat" items="[[forecast]]">
        <div class="day"><span class="dayname">[[item.dayIT]]</span>
          <template is="dom-if" if="[[item.condIcon]]">
          <br> <i class="icon" style="background: none, url(/local/weather_icons/animated/[[item.condIcon]].svg) no-repeat; background-size: contain;"></i> 
          </template>
          <template is="dom-if" if="[[item.tempHigh]]">
          <br> <span class="highTemp">[[item.tempHigh]]&#176;C</span> 
          </template>
          <template is="dom-if" if="[[item.tempLow]]">
          <br> <span class="lowTemp">[[item.tempLow]]&#176;C</span>
          </template>
        </div>
      </template>
      </div>
    </div>
  </template>
</dom-module>

<script>
(function () {
  'use strict';

  var _WEATHER_TO_ICON_DAY = {
    'cloudy': 'cloudy',
    'fog': 'cloudy',
    'hail': 'rainy-7',
    'lightning': 'thunder',
    'lightning-rainy': 'thunder',
    'partlycloudy': 'cloudy-day-3',
    'pouring': 'rainy-6',
    'rainy': 'rainy-5',
    'snowy': 'snowy-6',
    'snowy-rainy': 'rainy-7',
    'sunny': 'day',
    'windy': 'cloudy',
    'windy-variant': 'cloudy-day-3',
    'exceptional': '!!',
  };
  
  var _WEATHER_TO_ICON_NIGHT = {
    'cloudy': 'cloudy',
    'fog': 'cloudy',
    'hail': 'rainy-7',
    'lightning': 'thunder',
    'lightning-rainy': 'thunder',
    'partlycloudy': 'cloudy-night-3',
    'pouring': 'rainy-6',
    'rainy': 'rainy-5',
    'snowy': 'snowy-6',
    'snowy-rainy': 'rainy-7',
    'sunny': 'night',
    'windy': 'cloudy',
    'windy-variant': 'cloudy-night-3',
    'exceptional': '!!',
  };
  
  var _WEATHER_TO_NAME = {
    cloudy: 'Cloudy',
    fog: 'Fog',
    hail: 'Hail',
    lightning: 'Lightning',
    'lightning-rainy': 'Lightning',
    partlycloudy: 'Partly cloudy',
    pouring: 'Pouring',
    rainy: 'Rainy',
    snowy: 'Snowy',
    'snowy-rainy': 'Rain and snow',
    sunny: 'Clear sky',
    windy: 'Windy',
    'windy-variant': 'Windy',
    exceptional: '!',
  };


  var _DEGREE_TEXT = [
    'N', 'NNO', 'NO', 'ONO', 'O', 'OZO', 'ZO', 'ZZO',
    'Z', 'ZZW', 'ZW', 'WZW', 'W', 'WNW', 'NW', 'NNW', 'N'
  ];
  
  var _DAY_TO_DAY = {
    Mon: 'MON',
    Tue: 'TUE',
    Wed: 'WED',
    Thu: 'THU',
    Fri: 'FRI',
    Sat: 'SAT',
    Sun: 'SUN',
  };

  Polymer({
    is: 'custom-weather-card',

    properties: {
      hass: {
        type: Object,
      },
      stateObj: {
        type: Object,
      },
      weatherObj: {
        type: Object,
        observer: 'checkRequirements',
        computed: 'computeWeatherObj(hass, stateObj)',
      },
      sunObj: {
        type: Object,
        observer: 'checkRequirements',
        computed: 'computeSunObj(hass, stateObj)',
      },
      pressureObj: {
        type: Object,
        observer: 'checkRequirements',
        computed: 'computePressureObj(hass, stateObj)',
      },
      visibilityObj: {
        type: Object,
        observer: 'checkRequirements',
        computed: 'computeVisibilityObj(hass, stateObj)',
      },
      precipationObj: {
        type: Object,
        observer: 'checkRequirements',
        computed: 'computePrecipationObj(hass, stateObj)',
      },
      precipationfcObj: {
        type: Object,
        observer: 'checkRequirements',
        computed: 'computePrecipationfcObj(hass, stateObj)',
      },
    },

    computeWeatherObj: function (hass, stateObj) {
      return stateObj && stateObj.attributes && stateObj.attributes.config && stateObj.attributes.config.weather ? hass.states[stateObj.attributes.config.weather] : null;
    },
    computeSunObj: function (hass, stateObj) {
      return stateObj && stateObj.attributes && stateObj.attributes.config && stateObj.attributes.config.sun ? hass.states[stateObj.attributes.config.sun] : null;
    },
    computePressureObj: function (hass, stateObj) {
      return stateObj && stateObj.attributes && stateObj.attributes.config && stateObj.attributes.config.pressure ? hass.states[stateObj.attributes.config.pressure] : null;
    },
    computeVisibilityObj: function (hass, stateObj) {
      return stateObj && stateObj.attributes && stateObj.attributes.config && stateObj.attributes.config.visibility ? hass.states[stateObj.attributes.config.visibility] : null;
    },
    computePrecipationObj: function (hass, stateObj) {
      return stateObj && stateObj.attributes && stateObj.attributes.config && stateObj.attributes.config.precipation ? hass.states[stateObj.attributes.config.precipation] : null;
    },
    computePrecipationfcObj: function (hass, stateObj) {
      return stateObj && stateObj.attributes && stateObj.attributes.config && stateObj.attributes.config.precipationfc ? hass.states[stateObj.attributes.config.precipationfc] : null;
    },

    getForecastArray: function () {
      if (!this.weatherObj.attributes.forecast) {
        return [];
      }
      
      var data = this.weatherObj.attributes.forecast;
      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 = _WEATHER_TO_ICON_DAY[data[i].condition];
          var dayIT = _DAY_TO_DAY[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;
    },

    checkRequirements: function () {
      if (!this.weatherObj) {
        return;
      }
      if (this.nowSun == 'above_horizon') {
	    this.nowCond = _WEATHER_TO_ICON_DAY[this.weatherObj.state];
      }
      if (this.nowSun == 'below_horizon') {
	    this.nowCond = _WEATHER_TO_ICON_NIGHT[this.weatherObj.state];
      }
      this.nowCondIT = _WEATHER_TO_NAME[this.weatherObj.state];
      if (this.pressureObj != null) {
        this.nowPressure = this.pressureObj.state;
      }
      if (this.sunObj != null) {
        this.nowSun = this.sunObj.state;
      }
      if (this.visibilityObj != null) {
        this.nowVisibility = this.visibilityObj.state;
      }
      if (this.precipationObj != null) {
        this.nowPrecipation = this.precipationObj.state;
      }
      if (this.precipationfcObj != null) {
        this.nowPrecipationfc = this.precipationfcObj.state;
      }
      if (this.weatherObj.attributes.temperature) {
        this.roundedTemp = Math.round(this.weatherObj.attributes.temperature);
        if (this.roundedTemp == 0) {
          this.roundedTemp = '0'; // otherwise the value 0 will not be shown on the weather card
        }
		if (this.roundedTemp > 0) {
          this.roundedTemp = '+'+this.roundedTemp;
        }
      }
      if (this.weatherObj.attributes.wind_bearing) {
        this.windBearing = this.windBearingToText(this.weatherObj.attributes.wind_bearing);
      }
      this.forecast = this.getForecastArray().slice(0, 5);
    },

    windBearingToText: function (degree) {
      // return _DEGREE_TEXT[((parseInt(degree) + 5.63) / 11.25) | 0];
      return _DEGREE_TEXT[(parseInt((degree + 11.25) / 22.5))];
    },
  });
}());
</script>
configuration.yaml
homeassistant:
  customize:
    input_boolean.weather:
      custom_ui_state_card: custom-weather-card
      config:
        weather: weather.yweather
        sun: sun.sun
Screenshots

pic-1
pic-2

PS. Visibility icon not displayed bacause my weather component not support it

3 Likes

Awesome, thank you!

ok, so I am missing the large icon next to the current temp but the forecast shows up. Tried a reboot and a forced cache refresh to no avail. What am I missing here folks?

Check the paths to the icons (line 112). The path must be the same as in line 152.

</style>
<div class="card">
  <span class="icon bigger" style="background: none, url(/local/weather_icons/animated/[[nowCond]].svg) no-repeat; background-size: contain;"></span>

What is the state of the yweather component now? (sunny, cloudy e.t.c.)

Thanks @Yevgeniy

<span class="icon bigger" style="background: none, url(/local/weather_icons/animated/[[nowCond]].svg) no-repeat; background-size: contain;"></span>

and

<br> <i class="icon" style="background: none, url(/local/weather_icons/animated/[[item.condIcon]].svg) no-repeat; background-size: contain;"></i>

look the same to me… right?
Current condition in the yWeather is showing a cloudy symbol like so…
Capture
not sure how I can actually see the value though as the state just reports a value of:
[object Object]

any ideas what to check for?

Clear your browser’s cache. Not ctrl + F5 but in the browser settings