Custom UI: Weather state card

sometimes the awnser is so simple, but my mind is thinking dificuld. :sweat_smile:

why need the input_boolean in the first place? Only to switch the custom-card on or off? Otherwise it might be even simpler to take that out completely?

I have made some changes to custom-weather-card.html

  • if the temperature value is 0 then it will not be shown on the weather card, added some code to check that and save the temp as string so it will be shown
  • changed attribute name to wind_bearing
  • changed the formula for wind_bearing
  • make the wind_bearing visible on the weather card

weather_custom

Below the updated version which contains Dutch text and works with Buienradar.

HTML code
<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: #c8c8c8;
      }
      .temp {
        font-weight: 300;
        font-size: 4em;
        color:#5b5b5b;
        position: absolute;
        right: .5em;
      }
      .tempc {
        font-weight: 300;
        font-size: 1.5em;
        vertical-align: super;
        color:#5b5b5b;
        position: absolute;
        right: 0em;
      }
      .variations {
        font-weight:300;
        color:#8c8c8c;
        list-style:none;
        margin-left:-2em;
        margin-top: 2.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: 25%;
        float:left;
        text-align:center;
        color: #5b5b5b;
        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: #8c8c8c;
      }
      .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:#5b5b5b;
        text-align:center;
        position: absolute;
        top: 0em;
        left: 6em;
      }

    </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><iron-icon icon="mdi:water-percent"></iron-icon> [[weatherObj.attributes.humidity]]<span class="unit">%</span></li>
          </template>
          <template is="dom-if" if="[[weatherObj.attributes.pressure]]">
              <li><iron-icon icon="mdi:gauge"></iron-icon> [[weatherObj.attributes.pressure]]<span class="unit"> hPa</span></li>
          </template>

        </ul>
        <ul class="variations">
          <template is="dom-if" if="[[weatherObj.attributes.wind_speed]]">
            <li><iron-icon icon="mdi:weather-windy"></iron-icon> [[windBearing]] [[weatherObj.attributes.wind_speed]]<span class="unit"> m/s</span></li>
          </template>
          <template is="dom-if" if="[[weatherObj.attributes.visibility]]">
              <li><iron-icon icon="mdi:weather-fog"></iron-icon> [[weatherObj.attributes.visibility]]<span class="unit">m</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 = {
    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_NAME = {
    cloudy: 'Bewolkt',
    fog: 'Mist',
    hail: 'Hagel',
    lightning: 'Onweer',
    'lightning-rainy': 'Onweer',
    partlycloudy: 'Gedeeltelijk bewolkt',
    pouring: 'Stortregen',
    rainy: 'Regen',
    snowy: 'Sneeuw',
    'snowy-rainy': 'Natte sneeuw',
    sunny: 'Zonnig',
    windy: 'Winderig',
    'windy-variant': 'Variable wind',
    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: 'MA',
    Tue: 'DI',
    Wed: 'WO',
    Thu: 'DO',
    Fri: 'VR',
    Sat: 'ZA',
    Sun: 'ZO',
  };

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

    properties: {
      hass: {
        type: Object,
      },
      stateObj: {
        type: Object,
      },
      weatherObj: {
        type: Object,
        observer: 'checkRequirements',
        computed: 'computeWeatherObj(hass, stateObj)',
      },
    },

    computeWeatherObj: function (hass, stateObj) {
      return stateObj && stateObj.attributes && stateObj.attributes.config && stateObj.attributes.config.weather ? hass.states[stateObj.attributes.config.weather] : 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[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;
      }
  
      this.nowCond = _WEATHER_TO_ICON[this.weatherObj.state];
      this.nowCondIT = _WEATHER_TO_NAME[this.weatherObj.state];
      if (this.weatherObj.attributes.temperature) {
      this.roundedTemp = Math.round( this.weatherObj.attributes.temperature * 10) / 10;
      }
      if (this.weatherObj.attributes.wind_bearing) {
      this.windBearing = this.windBearingToText(this.weatherObj.attributes.wind_bearing);
      }
        this.forecast = this.getForecastArray().slice(0, 4);
    },

    windBearingToText: function (degree) {
      // return _DEGREE_TEXT[((parseInt(degree) + 5.63) / 11.25) | 0];
      return _DEGREE_TEXT[(parseInt((degree + 11.25) / 22.5))];
    },
  });
}());
</script>
4 Likes

HI gerard, thanks!
what settings do you use in the config and customize to get it to show. I cant seem the get the yweather card to show other than regular. im puzzled…

i was bussy with the same before posting the custom-weather-card.html.
the only extra thing you provided, was the 0 degrees to show on the map.
thanks for that,

the only thing i want to change is the unit of windspeed, and the the unit of visibility to bft and meters.
but cant find it yet how to change these units.
curently the visibility is showing miles i think,

The units are in the html page just before the </span>.

<li><iron-icon icon="mdi:weather-windy"></iron-icon> [[windBearing]] [[weatherObj.attributes.wind_speed]]<span class="unit"> m/s</span></li>
<li><iron-icon icon="mdi:weather-fog"></iron-icon> [[weatherObj.attributes.visibility]]<span class="unit"> m</span></li>

i saw that, but this wil only change the text after the vallue.
the vallue self won’t change.

i think it should be changed in the component Yweater, that is where the vallue read from.

The value and unit is indeed part of the component. If you want to change that you can do that in the script part of the html, there are some more calculations in there like

var tempHigh = Math.round(data[i].temperature * 10) / 10;

I am using the settings from this post.
Looks like you have 2 yweather platforms defined.
Can you remove one and see if that works?

that’s what i tried indeed, tried to have the customization take place on my existing Home card, but it doesnt stick, still shows as it always has done.

20

why does the card use the init_boolean in the customization and not the weather card directly? all i can see in my group is an input_boolean switch now :wink:

That’s strange. Can you try it with your buienradar platform?
And maybe one more doublecheck if you have all items from the config of eddi89? :wink:

its a bit confusing since all items use ‘weather’… and my setup already uses:

- platform: yweather
  name: Home

this why i asked what eddi89’s config would have to look like in my config…

please see what you would make of that?

customize: would i need to add Home in here?

homeassistant:
  customize:
    input_boolean.weather:
      custom_ui_state_card: custom-weather-card
      config:
        weather: weather.yweather

input_boolean: i guess this is about the platform itself, so no need to change that?

   input_boolean:
      weather:

Group: only item is the boolean, so no need to change that i suppose. Can show that in any group already there.

group:
  weather:
    name: Weather
    entities:
      - input_boolean.weather

You have to use the name of the entity_id in customize.yaml.
So weather.yweather has to be in your list with entities. You can also try your buienradar platform.

Correct.

Just follow the example and don’t place it in another group.

thanks, but that wont resolve it, i get this empty card, and clicking that shows only the boolean:

5703

You’re not the only one. I can’t seem to get it to load with either Yweather or DarkSky.

EDIT: My problem was not including the custom card in the frontend section. Double check the exmple to your config.

Remove “name: Home” string

thanks, but no that doesn’t work either. also tried the secondary state card, since i have custom-ui loaded globally.
no show.
reverted to the trusted setup.

Hey Guys,
I get an empty card, too.
Any ideas ?

Try to use input_text instead of input_bolean, i think the problem could be the “more info” and input_text don’t have it.
I always use input_text for any dummy card like tiles or floorplan.

My configuration is somethink like this:

homeassistant:
  customize:
    input_text.weather:
      name: Weather
      custom_ui_state_card: custom-weather-card
      config:
        weather: weather.weather

frontend:
  extra_html_url:
    - /local/custom_ui/custom-weather-card.html
  extra_html_url_es5:
    - /local/custom_ui/custom-weather-card.html

weather:
  - platform: yweather
    name: Weather
    woeid: "12345678"

input_text:
  weather:
  name: Weather

Okay, got it working.
My config was wrong.

This, have to be under homeassistant: and before config:

frontend:
  extra_html_url:
    - /local/custom_ui/custom-weather-card.html
  extra_html_url_es5:
    - /local/custom_ui/custom-weather-card.html

weather:
  - platform: yweather

input_boolean:
  weather:

group:
  weather:
    name: Wetter
    entities:
      - input_boolean.weather

And I have to add following to customize_glob:

  customize_glob: 
    input_boolean.weather:
      custom_ui_state_card: custom-weather-card
      friendly_name: Wetter
      config:
        weather: weather.yweather

My files are at the follwoing path: ~/.homeassistant/www/custom_ui
and ~/.homeassistant/www/weather_icons/animated

EDIT: Wrong weather icons path, sorry.

1 Like