Weather Forecast Card (Button Card)

I’m really particular/ocd/anal (whatever you want to call it) about about being able to control every aspect of a card style.

And sometimes, not even Card Mod can help, or I don’t feel like spending any more time trying to make it work.

I didn’t love any of the existing Weather Forecast cards out there, so I made my own only using Button Cards.

Anyone have any thoughts or feedback on what I could do to improve it?

I do have a separate card for current weather. This one is just for the 5 day forecast.

image

EDIT: Below is the code if anyone wants to use it. Sorry it’s not very user friendly.

It uses:

  • Button Card (does most of the work)
  • Decluttering Card (although it doesn’t have to)
  • Card Mod (although could do this all with inline CSS)
  • Horizontal Stack (1 column per day)

The [[[forecast_index]]] code has to be replaced with whatever code/value your weather integration uses to denote the day/date of the week.

Then use a horizontal stack card with 5 columns, with this code in each column, modifying the [[[forecast_index]]] code in each column as mentioned above.

      type: custom:button-card
      layout: vertical
      show_icon: false
      show_state: false
      show_name: false
      custom_fields:
        day: |
          [[[
            const forecastEntity = states['sensor.pirate_weather_daily'];
            if (forecastEntity && forecastEntity.attributes && forecastEntity.attributes.forecast) {
              const forecastDate = new Date(forecastEntity.attributes.forecast[[[forecast_index]]].datetime);
              const options = { weekday: 'short' };
              return forecastDate.toLocaleDateString(undefined, options);
            }
            return 'N/A';
          ]]]
        icon: |
          [[[
            const forecastEntity = states['sensor.pirate_weather_daily'];
            if (forecastEntity && forecastEntity.attributes && forecastEntity.attributes.forecast) {
              const forecast = forecastEntity.attributes.forecast[[[forecast_index]]];
              const condition = forecast.condition.toLowerCase();
              const iconMapping = {
                'sunny': 'mdi:white-balance-sunny',
                'cloudy': 'mdi:weather-cloudy',
                'rainy': 'mdi:weather-rainy',
                // Add more mappings as needed
              };
              return `<ha-icon icon="${iconMapping[condition] || 'mdi:weather-partly-cloudy'}"></ha-icon>`;
            }
            return 'N/A';
          ]]]
        condition: |
          [[[
            const forecastEntity = states['sensor.pirate_weather_daily'];
            return forecastEntity && forecastEntity.attributes && forecastEntity.attributes.forecast
              ? `${forecastEntity.attributes.forecast[[[forecast_index]]].condition}`
              : 'N/A';
          ]]]
        high_temp: |
          [[[
            const forecastEntity = states['sensor.pirate_weather_daily'];
            if (forecastEntity && forecastEntity.attributes && forecastEntity.attributes.forecast) {
              const high = forecastEntity.attributes.forecast[[[forecast_index]]].temperature;
              return `<div>${high}<span class="symbol">°F</span></div><div class="label-large">High Temp</div>`;
            }
            return 'N/A';
          ]]]
        low_temp: |
          [[[
            const forecastEntity = states['sensor.pirate_weather_daily'];
            if (forecastEntity && forecastEntity.attributes && forecastEntity.attributes.forecast) {
              const low = forecastEntity.attributes.forecast[[[forecast_index]]].templow;
              return `<div>${low}<span class="symbol">°F</span></div><div class="label-large">Low Temp</div>`;
            }
            return 'N/A';
          ]]]
        humidity: |
          [[[
            const forecastEntity = states['sensor.pirate_weather_daily'];
            return forecastEntity && forecastEntity.attributes && forecastEntity.attributes.forecast
              ? `<div class="label-small">Humidity</div><div>${forecastEntity.attributes.forecast[[[forecast_index]]].humidity}%</div>`
              : 'N/A';
          ]]]
        precipitation: |
          [[[
            const forecastEntity = states['sensor.pirate_weather_daily'];
            return forecastEntity && forecastEntity.attributes && forecastEntity.attributes.forecast
              ? `</div><div class="label-small">Rain</div><div>${forecastEntity.attributes.forecast[[[forecast_index]]].precipitation}"`
              : 'N/A';
          ]]]
        precipitation_probability: |
          [[[
            const forecastEntity = states['sensor.pirate_weather_daily'];
            return forecastEntity && forecastEntity.attributes && forecastEntity.attributes.forecast
              ? `<div class="label-small">Rain Chance</div><div>${forecastEntity.attributes.forecast[[[forecast_index]]].precipitation_probability}%</div>`
              : 'N/A';
          ]]]
        wind_speed: |
          [[[
            const forecastEntity = states['sensor.pirate_weather_daily'];
            return forecastEntity && forecastEntity.attributes && forecastEntity.attributes.forecast
              ? `<div class="label-small">Wind Speed</div><div>${Math.round(forecastEntity.attributes.forecast[[[forecast_index]]].wind_speed)} mph</div>`
              : 'N/A';
          ]]]
        wind_gust_speed: |
          [[[
            const forecastEntity = states['sensor.pirate_weather_daily'];
            return forecastEntity && forecastEntity.attributes && forecastEntity.attributes.forecast
              ? `<div class="label-small">Wind Gusts</div><div>${Math.round(forecastEntity.attributes.forecast[[[forecast_index]]].wind_gust_speed)} mph</div>`
              : 'N/A';
          ]]]
      styles:
        card:
          - font-family: Roboto
          - color: var(--theme-black)
          - text-align: center
          - padding: 0
          - border: 1px solid var(--theme-grey-400)
          - border-radius: 100px !important
          - box-shadow: none
        grid:
          - grid-template-areas: >-
              "icon" "day" "condition" "high_temp" "low_temp" "humidity"
              "precipitation" "precipitation_probability" "wind_speed"
              "wind_gust_speed"
          - grid-template-columns: 1fr
          - grid-template-rows: auto
        custom_fields:
          day:
            - grid-area: day
            - color: var(--theme-white)
            - background-color: var(--theme-blue-400)
            - font-size: 18px
            - font-weight: 600
            - border-radius: 100px
            - padding: 0 0 0 0
            - margin: 10px 5px 0 5px
          icon:
            - grid-area: icon
            - width: 40px
            - height: 40px
            - margin: 10px 0 0 0
            - padding: 10px
            - color: white
            - background-color: var(--theme-orange-300)
            - border-radius: 100px
            - align-self: center
            - justify-self: center
          condition:
            - grid-area: condition
            - font-size: 14px
            - font-weight: 600
            - text-transform: capitalize
            - padding: 10px 0 5px 0
            - margin: 0 0 0 0
          high_temp:
            - grid-area: high_temp
            - font-size: 24px
            - font-weight: 600
            - color: var(--theme-red-800)
            - background-color: var(--theme-white)
            - border-bottom: 1px solid grey
            - padding: 0 0 8px 0
            - margin: 0 10px 0 10px
          low_temp:
            - grid-area: low_temp
            - font-size: 24px
            - font-weight: 600
            - color: var(--theme-blue-800)
            - padding: 4px 0 6px 0
            - margin: 0 0 10px 0
          humidity:
            - grid-area: humidity
            - font-size: 14px
            - font-weight: 400
            - color: var(--theme-grey-600)
            - background-color: var(--theme-grey-100)
            - padding: 7px 0 7px 0
          precipitation:
            - grid-area: precipitation
            - font-size: 14px
            - font-weight: 400
            - color: var(--theme-grey-600)
            - background-color: var(--theme-grey-200)
            - padding: 7px 0 7px 0
            - margin: 0 0 0 0
          precipitation_probability:
            - grid-area: precipitation_probability
            - font-size: 14px
            - font-weight: 400
            - color: var(--theme-grey-600)
            - background-color: var(--theme-grey-100)
            - padding: 7px 0 7px 0
          wind_speed:
            - grid-area: wind_speed
            - font-size: 13px
            - font-weight: 400
            - color: var(--theme-grey-600)
            - padding: 6px 0 6px 0
            - padding: 7px 0 7px 0
            - background-color: var(--theme-grey-200)
          wind_gust_speed:
            - grid-area: wind_gust_speed
            - font-size: 13px
            - font-weight: 400
            - color: var(--theme-grey-600)
            - background-color: var(--theme-grey-100)
            - padding: 7px 0 10px 0
      card_mod:
        style: |

          .label-large {
            font-family: Roboto;
            font-size: 10px;
            font-weight: 400;
            color: var(--theme-grey-500);
          }

          .label-medium {
            font-family: Roboto;
            font-size: 10px;
            font-weight: 400;
            color: var(--theme-grey-500);
          }

          .label-small {
            font-family: Roboto;
            font-size: 12px;
            font-weight: 600;
            color: var(--theme-grey-800);
            padding: 0 0 3px 0;
          }

          .symbol {
            font-size: 14px;
          }

          .separator {
            color: var(--theme-dark-grey);
            font-weight: 100;
            display: inline-block;
            padding: 0 10px;
          }
1 Like

Use proper SI / metric units

Just kidding. :slight_smile: Nice card.

I was a fan of this one but it got abandoned. GitHub - mlamberts78/weather-chart-card: Custom weather card with charts.

EDIT: actually maybe development has started again.

2 Likes

Other than agreeing with @tom_l re SI units (also kidding …or am I? :rofl:) it’s really good!

1 Like

Hahahaha! I wish! Dumb American government :frowning:

Thanks!

I did see that one, but it was a little more complicated that I was looking for. Wanted one that would be simple to look at for a high wife approval factor.

I 100% agree. I am a fan of SI, America likes doing things the hard way because “money”…

Thanks!

Got a little bit of styling to clean up, but it’s pretty close!

Should work with any weather info, but would require some modifications I think.

I think you could share this as a HACS card (if you know how to do that - I share don’t).

Howe much of it is card-mod (I try to avoid card-mod if I can)?

1 Like

No idea how to do that LOL.

It does use 4 HACS resources though, so not sure if that would prevent it from being able to upload it as a HACS card?

It uses:

  • Button Card (does most of the work)
  • Decluttering Card (although it doesn’t have to)
  • Card Mod (although could do this all with inline CSS)
  • Horizontal Stack (1 column per day)

It only uses 5 custom CSS classes in Card Mod.

But those classes could be converted to inline CSS styles relatively easy. Just makes it a bit of extra effort to update styles since you would then have to do it for each piece of content.

I’ll edit my first post with the code so everyone can see/use it if they want to.

1 Like