# Hourly Weather Card by [@decompil3d](https://www.github.com/decompil3d) An hourly weather card for Home Assistant. Visualize upcoming weather conditions as a colored horizontal bar. [![GitHub Release][releases-shield]][releases] [![License][license-shield]](LICENSE) [![hacs_badge](https://img.shields.io/badge/HACS-Default-orange.svg?style=for-the-badge)](https://github.com/hacs/integration) ![Project Maintenance][maintenance-shield] [![GitHub Activity][commits-shield]][commits] [![Lovelace Hourly Weather](https://img.shields.io/endpoint?url=https://dashboard.cypress.io/badge/simple/o468vw/main&style=for-the-badge&logo=cypress)](https://dashboard.cypress.io/projects/o468vw/runs) ![Screenshot of Hourly Weather card](hourly-weather.png) ## Installation ### Easiest method: ✨ Install via HACS [![Open your Home Assistant instance and open a repository inside the Home Assistant Community Store.](https://my.home-assistant.io/badges/hacs_repository.svg)](https://my.home-assistant.io/redirect/hacs_repository/?owner=decompil3d&repository=lovelace-hourly-weather) ### Alternative method: 1. Download `hourly-weather.js` from the [Releases][releases] page 2. Upload to `/www/hourly-weather/hourly-weather.js` (via Samba, File Editor, SSH, etc.) 3. Visit the Resources page in your Home Assistant install and add `/hourly-weather/hourly-weather.js` as a JavaScript Module. [![Open your Home Assistant instance and show your dashboard resources.](https://my.home-assistant.io/badges/lovelace_resources.svg)](https://my.home-assistant.io/redirect/lovelace_resources/) 4. Refresh your browser ## Usage This card will show in the "Add card" modal. It has a GUI editor for configuring settings. If you prefer YAML, here is a sample config: ```yaml type: custom:hourly-weather entity: weather.my_weather_entity num_segments: 18 # optional, defaults to 12 name: Next 18 hours # optional, defaults to "Hourly Weather" ``` ### Choosing the right entity This card is focused on displaying hourly weather data. It will work with coarser- or finer-grained data, though. I've tested with the OpenWeatherMap integration using the `onecall_hourly` mode and that works very well. As of Home Assistant 2023.9.0, most weather integrations provide data in multiple time increments. If your weather entity provides hourly data, the card will use that by default. Otherwise, the card will attempt to use the finest-grained increments available, unless you have configured otherwise. > ℹ️ NOTE: If your selected weather entity provides forecasts in increments of greater than one hour at a time, each > segment of the bar will be for one segment, not one hour. Prior to Home Assistant version 2023.9.0, if you already use OpenWeatherMap for daily data, you can add a second integration of the same component for hourly -- just adjust the latitude or longitude a tiny bit (i.e. change the last decimal by 1). Otherwise, the integration may complain of a duplicate unique ID. ## Options | Name | Type | Requirement | Description | Default | |----------------------------------|------------------------|--------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------| | `type` | string | **Required** | `custom:hourly-weather` | | | `entity` | string | **Required** | Home Assistant weather entity ID. | | | `forecast_type` | string | **Optional** | The type of forecast data to use. One of `hourly`, `daily`, or `twice-daily`. If not specified, the card will attempt to use the finest-grained data available. | | | `name` | string | **Optional** | Card name (set to `null` to hide) | `Hourly Weather` | | `icons` | bool | **Optional** | Whether to show icons instead of text labels | `false` | | `show_current` | bool | **Optional** | Whether to prepend the weather entity's current condition and temperature as the first segment | `false` | | `auto_label_spacing` | bool | **Optional** | Increase label spacing automatically when the card becomes too narrow, while preserving the configured `label_spacing` as the minimum | `false` | | `icon_map` | [Icon map][icon_map] | **Optional** | Custom icons to use for the weather conditions. Uses `mdi` icons by default. | | | `num_segments` | number | **Optional** | Number of forecast segments to show (integer >= 1) | `12` | | ~~`num_hours`~~ | number | **Optional** | _Deprecated:_ Use `num_segments` instead | `12` | | `offset` | number | **Optional** | Number of forecast segments to offset from start | `0` | | `label_spacing` | number | **Optional** | Number of forecast segments represented by each displayed label (integer >= 1) | `2` | | `colors` | [object][color] | **Optional** | Set colors for all or some conditions | | | `hide_hours` | bool | **Optional** | Whether to hide hour labels under the bar | `false` | | `hide_minutes` | bool | **Optional** | Whether to show hours without minutes under the bar (display only "17" instead of "17:00") | `false` | | `hide_temperatures` | bool | **Optional** | Whether to hide temperatures under the bar | `false` | | `round_temperatures` | bool | **Optional** | Whether to round temperatures to the nearest whole number | `false` | | `hide_bar` | bool | **Optional** | Whether to hide the bar itself | `false` | | `icon_fill` | [Icon Fill][icon_fill] | **Optional** | Whether to repeat the icon inside the bar | `'single` | | `show_wind` | [Wind][wind] | **Optional** | Whether to show wind speed and/or direction under the bar | `'false'` | | `show_precipitation_amounts` | bool | **Optional** | Whether to show the aggregated precipitation (rain) amount for each displayed label interval under the bar | `false` | | `show_precipitation_probability` | bool | **Optional** | Whether to show the combined precipitation probability for each displayed label interval under the bar | `false` | | `show_date` | [string][dates] | **Optional** | Whether to show date under the bar | `'false'` | | `tap_action` | [object][action] | **Optional** | Action to take on tap | `action: more-info` | | `hold_action` | [object][action] | **Optional** | Action to take on hold | `none` | | `double_tap_action` | [object][action] | **Optional** | Action to take on double tap | `none` | | `language` | string | **Optional** | Language to use for card (overrides HA & user settings) | | > Note that some of the more advanced options are not available in the card editor UI and must be configured via YAML. ### Precipitation and label spacing When precipitation amounts or probabilities are enabled, their values represent the forecast segments covered by each displayed label. For example, with `label_spacing: 2`, the precipitation label at the first segment summarizes segments 1-2, the next label summarizes segments 3-4, and so on. Precipitation amounts are summed. Precipitation probabilities are combined as the probability that precipitation occurs during at least one segment in that interval: $$ P(\text{precipitation}) = 1 - \prod_{i=1}^{n} (1 - p_i) $$ where $p_i$ is the precipitation probability of each segment expressed as a value from 0 to 1. The displayed result is rounded to the nearest whole percentage. If the final label interval contains fewer segments than `label_spacing`, it summarizes the remaining segment or segments. ### Current weather segment Set `show_current: true` to prepend the weather entity's current condition and temperature to the forecast. `num_segments` still controls the total number of segments displayed, including the current segment. If the entity does not expose a valid current condition and temperature, the card safely falls back to the forecast alone. When the weather entity does not expose current precipitation, the current segment uses amount and probability from the ongoing hourly forecast interval without combining them with future intervals. `label_spacing` restarts at the first future segment, and the already-started forecast interval is omitted from the remaining timeline so it is not duplicated. The current segment is labeled "Now" (translated to the configured language). Hover over the label to see the weather entity's update time in a native browser tooltip, including minutes even when `hide_minutes` is enabled. ### Templating The following options allow Home Assistant Jinja templates as values: - `name` - `num_segments` - `offset` - `label_spacing` You may use any valid template expression that produces a string or number. For example, you can define offset based on the current time of day so that you see the next day's weather: ```yaml name: Tomorrow num_segments: 24 offset: | {{ 24 - now().hour }} label_spacing: 4 ``` Or maybe show the rest of today's weather: ```yaml name: Today num_segments: | {{ 24 - now().hour }} label_spacing: | {% set segments = 24 - now().hour %} {{ 4 if segments > 12 else 2 }} ``` ## Action Options | Name | Type | Requirement | Description | Default | |-------------------|--------|--------------|----------------------------------------------------------------------------------------------------|-------------| | `action` | string | **Required** | Action to perform (more-info, toggle, call-service, navigate url, none) | `more-info` | | `navigation_path` | string | **Optional** | Path to navigate to (e.g. /lovelace/0/) when action defined as navigate | `none` | | `url` | string | **Optional** | URL to open on click when action is url. The URL will open in a new tab | `none` | | `service` | string | **Optional** | Service to call (e.g. media_player.media_play_pause) when action defined as call-service | `none` | | `service_data` | object | **Optional** | Service data to include (e.g. entity_id: media_player.bedroom) when action defined as call-service | `none` | | `haptic` | string | **Optional** | Haptic feedback _success, warning, failure, light, medium, heavy, selection_ | `none` | | `repeat` | number | **Optional** | How often to repeat the `hold_action` in milliseconds. | `none` | ## Day and night conditions Home Assistant weather integrations decide between `sunny` and `clear-night` from the sun position at the moment the forecast is produced, and then apply that one choice to every segment of the forecast. A forecast fetched at noon therefore labels tonight's clear hours `sunny`, and one fetched after dark labels tomorrow's clear hours `clear-night`. This card resolves each segment against its own timestamp instead, using your Home Assistant home location: | Reported by the integration | Sun is up | Sun is down | |-----------------------------|----------------|------------------------| | `sunny` / `clear-night` | `sunny` | `clear-night` | | `partlycloudy` | `partlycloudy` | `night-partly-cloudy` | `night-partly-cloudy` is not a Home Assistant condition — the card derives it, because Home Assistant has no nighttime variant of `partlycloudy`. It can be styled and re-iconed like any other condition via [`colors`](#color-options) and [`icon_map`](#icon-map-options). No configuration is needed. If your `hass.config` carries no latitude and longitude, the condition reported by the integration is used unchanged. ## Color Options `colors` is specified as an object containing one or more of the keys listed below and values that are valid CSS colors or objects of foreground and/or background valid CSS colors. Invalid color values will be discarded and will trigger a warning. ### Color value format Colors may be specified as a valid CSS color string or as an object with one or more of the following fields, each containing a valid CSS color string: - `foreground`: The color of the condition label text or icon - `background`: The color of the bar background during that span If color is specified as a plain string, it will be used for background. Foreground color defaults to the primary text color in your Home Assistant theme. Some conditions will default to whatever the value is of some other condition. For example, `fog` will default to whatever `cloudy` is. | Key | Default | |-----------------------|------------------------| | `clear-night` | `#111` | | `cloudy` | `#777` | | `fog` | same as `cloudy` | | `hail` | `#2b5174` | | `lightning` | same as `rainy` | | `lightning-rainy` | same as `rainy` | | `partlycloudy` | `#b3dbff` | | `night-partly-cloudy` | `#333` | | `pouring` | same as `rainy` | | `rainy` | `#44739d` | | `snowy` | `#fff` | | `snowy-rainy` | same as `partlycloudy` | | `sunny` | `#90cbff` | | `windy` | same as `sunny` | | `windy-variant` | same as `sunny` | | `exceptional` | `#ff9d00` | ### Sample colors configuration ```yaml colors: sunny: '#bbccee' # note that hex colors must be quoted snowy-rainy: rgba(255, 255, 255, 0.8) # rgba works (and hsla too) exceptional: red # as do valid CSS color names rainy: var(--primary-color) # CSS custom properties (aka variables) are fine as well windy: background: lightgray foreground: '#000' ``` ## Icon map Options `icon_map` can be used to customize the icon used for each weather condition. It is specified as an object containing one or more of the keys listed below and values that are valid icons installed in Home Assistant. | Key | Default | |-----------------------|-----------------------------------| | `clear-night` | `mdi:weather-night` | | `cloudy` | `mdi:weather-cloudy` | | `fog` | `mdi:weather-fog` | | `hail` | `mdi:weather-hail` | | `lightning` | `mdi:weather-lightning` | | `lightning-rainy` | `mdi:weather-lightning-rainy` | | `partlycloudy` | `mdi:weather-partly-cloudy` | | `night-partly-cloudy` | `mdi:weather-night-partly-cloudy` | | `pouring` | `mdi:weather-pouring` | | `rainy` | `mdi:weather-rainy` | | `snowy` | `mdi:weather-snowy` | | `snowy-rainy` | `mdi:weather-snowy-rainy` | | `sunny` | `mdi:weather-sunny` | | `windy` | `mdi:weather-windy` | | `windy-variant` | `mdi:weather-windy-variant` | | `exceptional` | `mdi:alert-outline` | ### Sample icon map configuration ```yaml icon_map: sunny: mdi:emotion-cool cloudy: phu:nextcloud # can use any icon set ``` ### Wind Options `show_wind` can be one of the following values: - `false` Don't show wind speed/direction (default) - `true` Show both wind speed and direction - `speed` Only show wind speed - `direction` Only show wind direction - `barb` Show wind direction as a wind barb arrow - `barb-and-direction` Show wind direction as a wind barb arrow and also show textual direction - `barb-and-speed` Show wind direction as a wind barb arrow and also show speed - `barb-speed-and-direction` Show wind direction as a wind barb arrow and also show speed and textual direction ### Date Options `show_date` can be one of the following values: - `false` Don't show date (default) - `boundary` Show date at the boundary between days - `all` Always show date ### Icon Fill Options `icon_fill` can be one of the following values: - `single` Show one icon per forecast span (default) - `full` Show one icon per forecast segment - `` (an integer). Show icons every _n-th_ forecast segment (will show at least one icon per forecast span) > **NOTE:** If a forecast segment is not wide enough to fit an icon, the icon will not be shown. That means that on > narrow screens or with many segments, you may not see all icons. If that happens, consider using a larger numeric > value for `icon_fill` or use `single` to show one icon per forecast span. ## Upgrades ### Version 3 ➡️ 4 In version 4.x, the `num_hours` option was deprecated in favor of `num_segments`. This simplifies the card and makes it clear that it operates on whatever size forecast segment your entity provides. The `num_hours` option still works, but `num_segments` takes precedence, if set. `num_hours` will be removed in a later major version of the card. ### Version 4 ➡️ 5 In version 5.x, the DOM structure of the weather bar and its labels was changed to allow for odd-numbered segment counts and label spacing. Labels now appear centered with the segment they are representing, and the first label shown on the bar represents the first segment of data where in prior versions labels would begin at the second segment. This change may cause some custom CSS to break. If you have custom CSS, you may need to adjust it to account for the new structure. ### Version 5 ➡️ 6 No breaking changes here. I tried using sun position information to calculate whether to show a night version of the partly cloudy icon, but it didn't work out and was removed in a patch release. [commits-shield]: https://img.shields.io/github/commit-activity/y/decompil3d/lovelace-hourly-weather.svg?style=for-the-badge [commits]: https://github.com/decompil3d/lovelace-hourly-weather/commits/main [devcontainer]: https://code.visualstudio.com/docs/remote/containers [license-shield]: https://img.shields.io/github/license/decompil3d/lovelace-hourly-weather.svg?style=for-the-badge [maintenance-shield]: https://img.shields.io/maintenance/yes/2026.svg?style=for-the-badge [releases-shield]: https://img.shields.io/github/release/decompil3d/lovelace-hourly-weather.svg?style=for-the-badge [releases]: https://github.com/decompil3d/lovelace-hourly-weather/releases [icon_map]: #icon-map-options [color]: #color-options [wind]: #wind-options [icon_fill]: #icon-fill-options [dates]: #date-options [action]: #action-options