AWTRIX Weather ⛈️ + Forecast + 🌕️
Home Assistant Blueprint

AWTRIX Weather ⛈️ + Forecast + 🌕️

A somewhat complex weather forecast blueprint - showing temperature, weather and moon states. Initially designed for integration with a Tempest Weatherflow
A flow by Jeeftor

Import blueprint Download blueprint Download assets

Flow Details

Open your Home Assistant instance and show the blueprint import dialog with a specific blueprint pre-filled.

Some of the features include:

  • Hourly forecast bar
  • Customized Colors per/temp
  • Moon Icon showing phase when the moon is up
  • SunRise/Set time displays
  • Some emoji in the blueprint

NOTE

Make sure you read the full blueprint description once you install it. You will need to setup a few custom sensors in order for the moon to work correctly

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005
---
blueprint:
  name: AWTRIX Weather ⛈️ + Forecast + 🌕️
  description: >

    This is somewhat of a mega-weather blueprint with moon phase support. However for it work correctly you will need a variety of different things setup. It was initially designed to use in partnership with a personal weather station however it seems to work fine with OpenWeather as well or any other provider that offers an hourly forecast.



    ![](https://raw.githubusercontent.com/jeeftor/HomeAssistant/master/docs/weather.gif)


    ![](https://raw.githubusercontent.com/jeeftor/HomeAssistant/master/docs/sunset.gif)

    This blueprint will publish to two separate topics.  `jeef_weather` for the weather report and `jeef_weather_sun` if its near sunrise/set

    ## ⚠️ REQUIREMENTS ⚠️

    For this blueprint to work you MUST have a few things pre-setup. 

    ### Moon Integration 🌕️
         .------.
        ( I MOON )    ..
         `------'   .' /
              O    /  ;
                o i  OO
                 C    `-.  Make sure you've
                 |    <-'      enabled
                 (  ,--.   the MOON Sensor
                  V  \_)
                   \  :
                    `._\.    


    The moon integration is required. You can add it via the [moon](https://www.home-assistant.io/integrations/moon/) page or just by [clicking here](https://my.home-assistant.io/redirect/config_flow_start?domain=moon)

    ### Moon Rise/Set Sensor 🌕️ ⏲️

              M
             (X)
            // \\   Lets use a GeoLocation to find
           //   \\     out the Moon Rise / Set
          //     \\       TIMES
         //       \\
        /           \

    As Home Assistant doesn't _currently_ provide moon rise/set times you will need to get this from some api. 
    You can use the [ipgeolocation](https://app.ipgeolocation.io) API.

    To do so you will need to create an account and extract your `API_KEY`. Additionally you need your `LAT` and `LON`.

    Then you can add a [REST](https://www.home-assistant.io/integrations/sensor.rest/) sensor to your `configuraiton.yaml` file like the one here:

        resource: https://api.ipgeolocation.io/astronomy?lat=<LAT>&long=-<LON>&apiKey=<API_KEY>
        name: ip_geo_location
        scan_interval: 300
        value_template: "OK"
        json_attributes:
          - moonrise
          - moonset
          - moon_altitude

    ### Icons

    You can call my custom script which will prompt you for an Awtrix device and then upload the required icons:
      
      (If you have windows I don't know if this will work)

        bash -c "$(curl -fsSL https://raw.githubusercontent.com/jeeftor/HomeAssistant/master/icons/upload_icon.sh)"

    _This blueprint ~will~ may be updated as new features_

    ![](https://www.gravatar.com/avatar/3b9968835eb719e5d78a04ba7a2bafbd?s=64)
    https://raw.githubusercontent.com/jeeftor/HomeAssistant/master/blueprints/automation/awtrix_weatherflow.yaml

  domain: automation
  input:
    awtrix:
      name: AWTRIX Device
      description: Select the Awtrix 3
      selector:
        device:
          integration: mqtt
          manufacturer: Blueforcer
          model: AWTRIX 3
          multiple: true

    forecast_var:
      name: Hourly Forecast
      description: >
        Select a sensor that provides an Hourly forecast (not a daily one)

        This integration has been tested with:

          - HACS [Weatherflow](https://github.com/briis/hass-weatherflow) integration 
          
          - HomeAssistant [Openweather](https://www.home-assistant.io/integrations/openweathermap/)
      selector:
        entity:
          domain:
            - weather
          multiple: false

    hours_to_show:
      name: Forecast Hours to Show
      description: >
        How many hours of forecast do you wish to show along the bottom of the display
      selector:
        number:
          max: 24
          min: 0
          unit_of_measurement: "hours"
          mode: box
      default: 12

    forecast_temp_field:
      name: Temperature Attributes
      description: >
        Once you've selected your hourly forecast you will need to identify which attributes in the forecast provides a temperature value. 

          - If you are using [Weatherflow](https://github.com/briis/hass-weatherflow) you may be able to select from either `feels_like` or `temperature`

          - In [Openweather](https://www.home-assistant.io/integrations/openweathermap/) you only have access to `temperature`

      selector:
        text:
      default: "feels_like"

    temp_digits:
      name: Temp Digits
      description: >
        By default we will round the temp to the nearest whole-number. If you want percisions you can change this to 1 or 2 in order to see more decimalm places.
      selector:
        number:
          min: 0
          max: 2
          step: 1
          mode: box
          unit_of_measurement: "Decimal places"
      default: 0
    temp_suffix:
      name: Temperature suffix
      description: >-
        How do you want to display the temperature

        If you live in a country with the following flags:

        🇺🇸️🇵🇷️🇵🇼️🇧🇿️🇰🇾️🇫🇲️🇲🇭️🇻🇮️🇬🇺️

        You probbaly use Farenheit.

        Everybody else in the 🗺️ seems to rock the Metric System

      selector:
        select:
          options:
            - label: None
              value: ""
            - label: "°"
              value: "°"
            - label: °F
              value: "°F"
            - label: °C
              value: "°C"
            - label: F
              value: "F"
            - label: C
              value: "C"
      default: "°"

    current_temp_var:
      name: The current outside temperature
      description: >
        Select a sensor either from a PWS or a forecast that provides the current outside temperature you wish to display:

          -  `sensor.openweathermap_feels_like_temperature`

      selector:
        entity:
          domain:
            - sensor
          multiple: false
      default: sensor.weatherflow_air_temperature

    color_matrix_json:
      name: Color Matrix
      description: >
        The `Color Matrix` will control colors map to temperature ranges on the display. The format of this map is **JSON** 

        Here you can enter a temperature to color mapping. 

        > Please note the format is *JSON*,
                

        Some possible mappings are:

        #### USA: Farenheit 0-100 (Based on NOAA scale from 0-100)


            {"0": "#FEC4FF","10": "#D977DF","20": "#9545BC","30": "#4B379C","40": "#31B8DB","50": "#31DB8B","60": "#6ED228","70": "#FFFF28","80": "#F87E27","90": "#CF3927","100": "#A12527"}


        #### EURO: -12°c to  -38°c based on USA NOAA Colors 

            {"-12": "#D977DF","-6": "#9545BC","-1": "#4B379C","0": "#FEC4FF","4": "#31B8DB","10": "#31DB8B","15": "#6ED228","21": "#FFFF28","27": "#F87E27","32": "#CF3927","38": "#A12527"}

      selector:
        text:
          multiline: true
      default: >
        {
          "0": "#FEC4FF",
          "10": "#D977DF",
          "20": "#9545BC",
          "30": "#4B379C",
          "40": "#31B8DB",
          "50": "#31DB8B",
          "60": "#6ED228",
          "70": "#FFFF28",
          "80": "#F87E27",
          "90": "#CF3927",
          "100": "#A12527"
        }

    # -------------
    # Moon Stuff
    # -------------
    moon:
      name: Moon Phase Sensor
      description: >
        🌑️🌒️🌓️🌔️🌖️🌗️🌘️

        To setup a moon sensor see here: https://www.home-assistant.io/integrations/moon/

        or just [clicking here](https://my.home-assistant.io/redirect/config_flow_start?domain=moon)

      selector:
        entity:
          multiple: false
          filter:
            integration: moon
    moon_rise_set:
      name: Moon Riese/Set Sensor
      description: >
        As Home Assistant doesn't provide moon rise/set times you will need to get this from some api. In my personal setup I use [ipgeolocation](https://app.ipgeolocation.io) as my api.

        You can create a custom REST sensor as follows:

        ```
        sensor:
        - platform: rest
          resource: https://api.ipgeolocation.io/astronomy?lat=<LAT>&long=-<LON>&apiKey=<API_KEY>
          name: ip_geo_location
          scan_interval: 300
          value_template: "OK"
          json_attributes:
            - moonrise
            - moonset
            - moon_altitude
        ```

      selector:
        entity:
          multiple: false
          filter:
            integration: rest
    when_show_moon:
      name: When should the moon be displayed
      description: >
        Some people are really into the moon 🐺️ and they are called Wearwolves or maybe Astronomers. 


        Please select how and when you want the moon displayed


        By selecting `Always show moon` the moon will always be drawn to the right of the display. Otherwise the moon will only be drawn if its risen depending on the option selected.

        ### NOTE:

          At Brightness values less than 29 the greys of the moon will render green on the clock.

      selector:
        select:
          options:
            - label: Never show moon
              value: never
            - label: Always show moon
              value: always
            - label: Only show moon if its risen
              value: risen
            - label: Only show moon if risen + night
              value: night
      default: "night"

    use_moon_clear_night:
      name: Swap Clear Night for Moon
      description: >-

        The default case is for the moon to be drawn to the right-side of the clock, however, you have the option if this is selected to repalce the `clear_night` icon with the moon icon. This will only swap icons if the moon is currently being displayed.



        - ![](https://developer.lametric.com/content/apps/icon_thumbs/2314_icon_thumb.png?v=1) - `full_moon`

        - ![](https://developer.lametric.com/content/apps/icon_thumbs/2315_icon_thumb.png?v=1) - `waning_gibbous`

        - ![](https://developer.lametric.com/content/apps/icon_thumbs/2316_icon_thumb.png?v=1) - `last_quarter`

        - ![](https://developer.lametric.com/content/apps/icon_thumbs/2317_icon_thumb.png?v=1) - `waning_crescent`

        - ![](https://developer.lametric.com/content/apps/icon_thumbs/2318_icon_thumb.png?v=1) - `new_moon`

        - ![](https://developer.lametric.com/content/apps/icon_thumbs/2319_icon_thumb.png?v=1) - `waxing_crescent`

        - ![](https://developer.lametric.com/content/apps/icon_thumbs/2320_icon_thumb.png?v=1) - `first_quarter`

        - ![](https://developer.lametric.com/content/apps/icon_thumbs/2321_icon_thumb.png?v=1) - `waxing_gibbous`

        If you wish to use a different icon please enter its text in the box to the right
      selector:
        boolean:
      default: True
    #----------------------------------------
    # Sunrise Sunset Times :)
    #----------------------------------------
    show_sun_rise_set:
      name: ☀️ Show Sunrise/Sunset
      description: >
        Prior to both sunrise and sunset times offer a message about pending sun transitional state.

                       :
              `.       ;        .'
                `.  .-'''-.   .'
                  ;'  __   _;'
                 /   '_    _`\       TURN ME ON!
                |  _( a (  a  |
            ''''| (_)    >    |``````
                 \    \    / /
                  `.   `--'.'
                 .' `-,,,-' `.
               .'      :      `.
                       :


        _You can change the icons for sun rise/set way down below._
      selector:
        boolean:
      default: True
    sun_event_minute_threshold:
      name: Sun Time Prior 🕰️
      description: >-
        This value controls when to show sunrise/set notifications. 


        If the sunrise will occur in `50` minutes and this value is set to `60` it will show, however if this value is only `30` it won't show.

      selector:
        number:
          min: 5
          max: 1440
          unit_of_measurement: "min"
      default: 30

    sun_time_type:
      name: Sun Time Type
      description: >
        When showing a notification about sun rise/set it can offer 3 different time formats:

          - Relative Time:  `12 min`
          - Actual Time:  `8:31 pm` or `22:31`
      selector:
        select:
          options:
            - Relative
            - Actual
      default: "Actual"
    sun_time_format:
      name: Actual Time Format
      description: >
        If you are using actual time you can enter a STRFTIME format string here for the time. Some options would be:

          - `%H%M` which would render `0529`
          
          - `%-I%M%p` which woudl render `529AM`
          - `%-I%:M%p` which woudl render `5:29AM`



          For details see https://strftime.org/
      selector:
        text:
          type: text
      default: "%-I%M%p"
    message_duration_forecast:
      name: Forecast Duration ⏱️
      description: >-
        How long should the forecast message remain on the screen(in seconds).  *If you select `0` it will use the Global App Time*
      selector:
        number:
          min: 0
          max: 300
          unit_of_measurement: "sec"
      default: 30

    message_duration_riseset:
      name: Sun Rise/Set Duration ⏱️
      description: >-
        How long should the sunrise sunset message remain on the screen(in seconds).  *If you select `0` it will use the Global App Time*
      selector:
        number:
          min: 0
          max: 300
          unit_of_measurement: "sec"
      default: 30

    #-----------------------------------------
    # This was really annoying to generate :)
    #-----------------------------------------
    icon_clear_night:
      name: Icon for clear-night
      description: >

        The default clear_night icon is: 

          ![](https://developer.lametric.com/content/apps/icon_thumbs/53383_icon_thumb.gif?v=2) - `53383`

      selector:
        text:
      default: "w-clear-night"

    icon_cloudy:
      name: Icon for cloudy
      description: >
        This is the icon ID which maps to the weather state: `cloudy`

        ![](https://developer.lametric.com/content/apps/icon_thumbs/53384_icon_thumb.gif?v=1)
      selector:
        text:
      default: "w-cloudy"
    icon_exceptional:
      name: Icon for exceptional
      description: >
        This is the icon ID which maps to the weather state: `exceptional`


        ![](https://developer.lametric.com/content/apps/icon_thumbs/36637_icon_thumb.gif?v=1)
      selector:
        text:
      default: "w-exceptional"
    icon_fog:
      name: Icon for fog
      description: >
        This is the icon ID which maps to the weather state: `fog`

        ![](https://developer.lametric.com/content/apps/icon_thumbs/17055_icon_thumb.gif?v=1)
      selector:
        text:
      default: "w-fog"
    icon_hail:
      name: Icon for hail
      description: >
        This is the icon ID which maps to the weather state: `hail` (IF YOU HAVE A BETTER ONE PLEASE LET ME KNOW)

        ![](https://developer.lametric.com/content/apps/icon_thumbs/53385_icon_thumb.gif?v=1)

      selector:
        text:
      default: "w-hail"
    icon_lightning:
      name: Icon for lightning
      description: >
        This is the icon ID which maps to the weather state: `lightning`

        ![](https://developer.lametric.com/content/apps/icon_thumbs/29839_icon_thumb.gif?v=1)

      selector:
        text:
      default: "w-lightning"
    icon_lightning_rainy:
      name: Icon for lightning-rainy
      description: >
        This is the icon ID which maps to the weather state: `lightning-rainy`

        ![](https://developer.lametric.com/content/apps/icon_thumbs/49299_icon_thumb.gif?v=4)
      selector:
        text:
      default: "w-lightning-rainy"
    icon_partlycloudy:
      name: Icon for partlycloudy
      description: >
        This is the icon ID which maps to the weather state: `partlycloudy`
         
        ![](https://developer.lametric.com/content/apps/icon_thumbs/2286_icon_thumb.gif?v=1)

      selector:
        text:
      default: "w-partlycloudy"
    icon_pouring:
      name: Icon for pouring
      description: >
        This is the default icon which maps to the weather state: `pouring`

        ![](https://developer.lametric.com/content/apps/icon_thumbs/49300_icon_thumb.gif?v=1)

      selector:
        text:
      default: "w-pouring"
    icon_rainy:
      name: Icon for rainy
      description: >
        This is the default icon which maps to the weather state: `rainy`

        ![](https://developer.lametric.com/content/apps/icon_thumbs/2720_icon_thumb.gif?v=1)

      selector:
        text:
      default: "w-rainy"
    icon_snowy:
      name: Icon for snowy
      description: >
        This is the icon ID which maps to the weather state: `snowy`

        ![](https://developer.lametric.com/content/apps/icon_thumbs/2289_icon_thumb.gif?v=1)
      selector:
        text:
      default: "w-snowy"
    icon_snowy_rainy:
      name: Icon for snowy-rainy
      description: >
        This is the icon ID which maps to the weather state: `snowy-rainy`

        ![](https://developer.lametric.com/content/apps/icon_thumbs/49301_icon_thumb.gif?v=2)
      selector:
        text:
      default: "w-snowy-rainy"
    icon_sunny:
      name: Icon for sunny
      description: >
        This is the icon ID which maps to the weather state: `sunny`

        ![](https://developer.lametric.com/content/apps/icon_thumbs/53386_icon_thumb.gif?v=1)
      selector:
        text:
      default: "w-sunny"
    icon_windy:
      name: Icon for windy
      description: >
        This is the icon ID which maps to the weather state: `windy`

        ![](https://developer.lametric.com/content/apps/icon_thumbs/3363_icon_thumb.gif?v=1)
      selector:
        text:
      default: "w-windy"
    icon_windy_variant:
      name: Icon for windy-variant
      description: >
        This is the icon ID which maps to the weather state: `windy-variant`

        ![](https://developer.lametric.com/content/apps/icon_thumbs/3363_icon_thumb.gif?v=1)
      selector:
        text:
      default: "w-windy-variant"

    icon_sunrise:
      name: Icon for sunrise
      description: >
        This is the icon ID which maps to the `sunrise`

        ![](https://developer.lametric.com/content/apps/icon_thumbs/53418_icon_thumb.gif?v=1)
      selector:
        text:
      default: "w-sunrise"

    icon_sunset:
      name: Icon for sunset
      description: >
        This is the icon ID which maps to the `sunset`

        ![](https://developer.lametric.com/content/apps/icon_thumbs/53417_icon_thumb.gif?v=1)
      selector:
        text:
      default: "w-sunset"

mode: restart
variables:
  device_ids: !input awtrix
  app_topic: jeef_weather
  devices_topics: >-
    {%- macro get_device_topic(device_id) %}
    {{ states((device_entities(device_id) | select('search','device_topic') | list)[0]) }}
    {%- endmacro %}

    {%- set ns = namespace(devices=[]) %}
    {%- for device_id in device_ids %}
      {%- set device=get_device_topic(device_id)|replace(' ','') %}
      {% set ns.devices = ns.devices + [ device ~ '/custom/' ~ app_topic] %}
    {%- endfor %}
    {{ ns.devices | reject('match','unavailable') | list}}

  forecast_var: !input forecast_var
  forecast: "{{state_attr(forecast_var,'forecast')}}"
  weather: "{{states(forecast_var)}}"
  hours_to_show: !input hours_to_show
  #---------------------------------
  # Moon Stuff
  #---------------------------------
  moon: !input moon
  moon_phase: "{{states(moon)}}"
  moon_times: !input moon_rise_set
  moon_rise: "{{state_attr(moon_times,'moonrise')}}"
  moon_set: "{{state_attr(moon_times,'moonset')}}"
  moon_alt: "{{state_attr(moon_times,'moon_altitude')}}"
  moon_risen: "{{moon_alt > 0}}"
  when_show_moon: !input when_show_moon
  show_moon: >-
    {%- if when_show_moon == 'always' %}
    True
    {%- elif when_show_moon == 'never' %}
    False
    {%- elif when_show_moon == 'risen' %}
    {{moon_risen}}
    {%- else %}
    {{state_attr('sun.sun', 'elevation') > 0 and moon_risen}}
    {%- endif %}
  #----------------
  # Temp & Text
  # --------------
  message_duration: !input message_duration_forecast
  message_duration_riseset: !input message_duration_riseset
  current_temp_var: !input current_temp_var
  temp_digits: !input temp_digits
  temp_suffix: !input temp_suffix
  current_temp: "{{states(current_temp_var) | round(temp_digits)}}"
  temp_text: "{{ current_temp ~ temp_suffix}}"
  forecast_temp_field: !input forecast_temp_field
  text_available_width: >
    {%- if show_moon %}16{%- else %}24{%- endif %}
  text_len: >-
    {%- macro get_text_len(string) %}
    {%- set length = namespace(value=0) %}
    {%- for char in string %}
      {%- if char.isdigit() %}
        {%- set length.value = length.value + 3 %}
      {%- elif char == '°' %}
        {%- set length.value = length.value + 2 %}
      {%- elif char == '.' %}
        {%- set length.value = length.value + 1 %}
      {%- elif char in ['-','C','F'] %}
        {%- set length.value = length.value + 3 %}
      {%- else %}
        {%- set length.value = length.value + 1 %}
      {%- endif %}
      {%- if not loop.last %}
        {%- set length.value = length.value + 1 %}{%- endif -%}
    {%- endfor -%}
    {{ length.value }}
    {%- endmacro %}

    {{get_text_len(temp_text)}}
  text_x: >-
    {{8 + ((text_available_width - text_len)/2)}}
  # ------------------------------
  # SUN THINGS
  # ------------------------------
  sun_event_minute_threshold: !input sun_event_minute_threshold
  sun_time_type: !input sun_time_type
  sun_time_format: !input sun_time_format
  icon_sunrise: !input icon_sunrise
  icon_sunset: !input icon_sunset
  show_sun_rise_set: !input show_sun_rise_set

  sun_next_event: >-
    {%- set rise = state_attr('sun.sun','next_rising') %}
    {%- set set = state_attr('sun.sun','next_setting') %}
    {%- set ts_rise = rise |as_timestamp %}
    {%- set ts_set = set |as_timestamp %}
    {{ iif(ts_set < ts_rise,'sunset','sunrise') }}
  sun_min_until_next_event: >-
    {%- set rise = state_attr('sun.sun','next_rising') %}
    {%- set set = state_attr('sun.sun','next_setting') %}
    {%- set ts_rise = rise |as_timestamp %}
    {%- set ts_set = set |as_timestamp %}
    {{ iif(next_event == 'sunrise',(ts_rise - utcnow()|as_timestamp) / 60,(ts_set - utcnow()|as_timestamp) / 60) | round(0) }}

  sun_next_str: >-
    {%- set rise = state_attr('sun.sun','next_rising') %}
    {%- set set = state_attr('sun.sun','next_setting') %}
    {%- set ts_rise = rise |as_timestamp %}
    {%- set ts_set = set |as_timestamp %}
    {%- if sun_time_type == 'Actual' %}
      {{ iif(sun_next_event == 'sunrise',(ts_rise | as_datetime | as_local).strftime(sun_time_format),  (ts_set | as_datetime | as_local).strftime(sun_time_format)) }}
    {%- else %}
    {#- relative time #}
      {% set hours = sun_min_until_next_event // 60 %}
      {% set remaining_minutes = sun_min_until_next_event % 60 %}

      {% if hours == 0 %}
          {{ remaining_minutes }} min
      {% else %}
          [
            {"t":"{{hours}}", "c":"#ffffff"},
            {"t":"h", "c":"#9c9d97"},
            {"t":"{{remaining_minutes}}", "c":"#ffffff"},
            {"t":"m", "c":"#9c9d97"}
        ]
      {% endif %}
      
    {%- endif %}
  sun_event_icon: >-
    {{ iif(sun_next_event == 'sunrise', icon_sunrise, icon_sunset) }}
  sun_event_payload: >-
    {"icon":"{{sun_event_icon}}", "text":{{sun_next_str}}, "duration": {{message_duration_riseset}}}
  sun_payload: >-
    {%- if show_sun_rise_set %}
    {{ iif(sun_event_minute_threshold >= sun_min_until_next_event, sun_event_payload, "{}") }}
    {%- else %}
    {}
    {%- endif %}

  icon_clear_night: !input icon_clear_night
  use_moon_clear_night: !input use_moon_clear_night
  icon_cloudy: !input icon_cloudy
  icon_exceptional: !input icon_exceptional
  icon_fog: !input icon_fog
  icon_hail: !input icon_hail
  icon_lightning: !input icon_lightning
  icon_lightning_rainy: !input icon_lightning_rainy
  icon_partlycloudy: !input icon_partlycloudy
  icon_pouring: !input icon_pouring
  icon_rainy: !input icon_rainy
  icon_snowy: !input icon_snowy
  icon_snowy_rainy: !input icon_snowy_rainy
  icon_sunny: !input icon_sunny
  icon_windy: !input icon_windy
  icon_windy_variant: !input icon_windy_variant
  clear_night_dict: >-
    {{ dict({
      'full_moon': '2314',
      'waning_gibbous': '2315',
      'last_quarter': '2316',
      'waning_crescent': '2317',
      'new_moon': '2318',
      'waxing_crescent': '2319',
      'first_quarter': '2320',
      'waxing_gibbous': '2321'}) }}
  color_matrix_json: !input color_matrix_json
  color_dict: >-
    {% set b = color_matrix_json | from_json %}    
    {%- set ns = namespace(tuples=[]) %}
    {%- for k,v in b | items -%}
      {%- set key = k|float -%}
      {%- set ns.tuples = ns.tuples + [(key,v)] %}      
    {% endfor %}
    {{ dict.from_keys(ns.tuples) }}

  icon_dict: >-
    {{ dict({'clear-night': icon_clear_night,
    'cloudy': icon_cloudy,
    'exceptional': icon_exceptional,
    'fog': icon_fog,
    'hail': icon_hail,
    'lightning': icon_lightning,
    'lightning-rainy': icon_lightning_rainy,
    'partlycloudy': icon_partlycloudy,
    'pouring': icon_pouring,
    'rainy': icon_rainy,
    'snowy': icon_snowy,
    'snowy-rainy': icon_snowy_rainy,
    'sunny': icon_sunny,
    'windy': icon_windy, 
    'windy-variant': icon_windy_variant})}}

  icon: >
    {%- if ((weather == 'clear_night') and use_moon_clear_night) %}
      {{clear_night_dict[moon_phase]}}
    {%- else %}
      {{ icon_dict[weather] }}
    {%- endif %}

  moon_data: >
    {%- macro draw_moon(phase,x=22,y=0) %}
      {%- if phase == 'full'  %}
          {"db":[{{x}},{{y}},8,8,[
          0,	0,	54970,	54970,	54970,	54970,	0,	0,
          0,	54970,	54970,	63390,	63390,	54970,	54970,	0,
          54970,	54970,	63390,	63390,	46518,	46518,	54970,	54970,
          54970,	63390,	46518,	63390,	46518,	63390,	63390,	54970,
          54970,	63390,	46518,	63390,	63390,	63390,	63390,	54970,
          54970,	54970,	63390,	63390,	63390,	46518,	54970,	54970,
          0,	54970,	54970,	46518,	63390,	54970,	54970,	0,
          0,	0,	54970,	54970,	54970,	54970,	0,	0
          ]]}
        {%- endif  %}
        {%- if phase == 'waning_gibbous'  %}
          {"db":[{{x}},{{y}},8,8,[
          0,	0,	54970,	54970,	12710,	12710,	0,	0,
          0,	54970,	54970,	63390,	63390,	12710,	12710,	0,
          54970,	54970,	63390,	63390,	52857,	52857,	12710,	12710,
          54970,	63390,	52857,	63390,	52857,	63390,	12710,	12710,
          54970,	63390,	52857,	63390,	63390,	63390,	12710,	12710,
          54970,	54970,	63390,	63390,	63390,	52857,	12710,	12710,
          0,	54970,	54970,	52857,	63390,	12710,	12710,	0,
          0,	0,	54970,	54970,	12710,	12710,	0,	0
          ]]}
        {%- endif  %}
        {%- if phase == 'last_quarter'  %}
          {"db":[{{x}},{{y}},8,8,[
          0,	0,	54970,	54970,	12710,	12710,	0,	0,
          0,	54970,	54970,	63390,	12710,	12710,	12710,	0,
          54970,	54970,	63390,	63390,	6371,	6371,	12710,	12710,
          54970,	63390,	52857,	63390,	6371,	12710,	12710,	12710,
          54970,	63390,	52857,	63390,	12710,	12710,	12710,	12710,
          54970,	54970,	63390,	63390,	12710,	6371,	12710,	12710,
          0,	54970,	54970,	52857,	12710,	12710,	12710,	0,
          0,	0,	54970,	54970,	12710,	12710,	0,	0
          ]]}
        {%- endif  %}
        {%- if phase == 'last_quarter'  %}
          {"db":[{{x}},{{y}},8,8,[
          0,	0,	54970,	54970,	12710,	12710,	0,	0,
          0,	54970,	54970,	63390,	12710,	12710,	12710,	0,
          54970,	54970,	63390,	63390,	6371,	6371,	12710,	12710,
          54970,	63390,	52857,	63390,	6371,	12710,	12710,	12710,
          54970,	63390,	52857,	63390,	12710,	12710,	12710,	12710,
          54970,	54970,	63390,	63390,	12710,	6371,	12710,	12710,
          0,	54970,	54970,	52857,	12710,	12710,	12710,	0,
          0,	0,	54970,	54970,	12710,	12710,	0,	0
          ]]}
        {%- endif  %}
        {%- if phase == 'waning_crescent'  %}
          {"db":[{{x}},{{y}},8,8,[
          0,	0,	54970,	54970,	10565,	10565,	0,	0,
          0,	54970,	54970,	10565,	10565,	10565,	10565,	0,
          54970,	54970,	10565,	10565,	6371,	6371,	10565,	10565,
          54970,	63390,	6371,	10565,	6371,	10565,	10565,	10565,
          54970,	63390,	6371,	10565,	10565,	10565,	10565,	10565,
          54970,	54970,	10565,	10565,	10565,	6371,	10565,	10565,
          0,	54970,	54970,	6371,	10565,	10565,	10565,	0,
          0,	0,	54970,	54970,	10565,	10565,	0,	0
          ]]}
        {%- endif  %}
        {%- if phase == 'new_moon'  %}
        
          {"db":[{{x}},{{y}},8,8,[
          0,	0,	10565,	10565,	10565,	10565,	0,	0,
          0,	10565,	10565,	10565,	10565,	10565,	10565,	0,
          10565,	10565,	10565,	10565,	6371,	6371,	10565,	10565,
          10565,	10565,	6371,	10565,	6371,	10565,	10565,	10565,
          10565,	10565,	6371,	10565,	10565,	10565,	10565,	10565,
          10565,	10565,	10565,	10565,	10565,	6371,	10565,	10565,
          0,	10565,	10565,	6371,	10565,	10565,	10565,	0,
          0,	0,	10565,	10565,	10565,	10565,	0,	0
          ]]}
        {%- endif  %}
        {%- if phase == 'waxing_crescent'  %}
          {"db":[{{x}},{{y}},8,8,[
          0,	0,	12678,	12678,	54970,	54970,	0,	0,
          0,	12678,	12678,	12678,	12678,	54970,	54970,	0,
          12678,	12678,	12678,	12678,	6339,	6339,	54970,	54970,
          12678,	12678,	6339,	12678,	6339,	12678,	63390,	54970,
          12678,	12678,	6339,	12678,	12678,	12678,	63390,	54970,
          12678,	12678,	12678,	12678,	12678,	6339,	54970,	54970,
          0,	12678,	12678,	12678,	12678,	54970,	54970,	0,
          0,	0,	12678,	12678,	54970,	54970,	0,	0
          ]]}
        {%- endif  %}
        {%- if phase == 'first_quarter'  %}
          {"db":[{{x}},{{y}},8,8,[
          0,	0,	12678,	12678,	54970,	54970,	0,	0,
          0,	12678,	12678,	12678,	63390,	54970,	54970,	0,
          12678,	12678,	12678,	12678,	52825,	52825,	54970,	54970,
          12678,	12678,	6339,	12678,	52825,	63390,	63390,	54970,
          12678,	12678,	6339,	12678,	63390,	63390,	63390,	54970,
          12678,	12678,	12678,	12678,	63390,	52825,	54970,	54970,
          0,	12678,	12678,	12678,	63390,	54970,	54970,	0,
          0,	0,	12678,	12678,	54970,	54970,	0,	0
          ]]}
        {%- endif  %}
        {%- if phase == 'waxing_gibbous'  %}
          {"db":[{{x}},{{y}},8,8,[
          0,	0,	12678,	12678,	54970,	54970,	0,	0,
          0,	12678,	12678,	54970,	63390,	54970,	54970,	0,
          12678,	12678,	63390,	63390,	50712,	50712,	54970,	54970,
          12678,	12678,	50712,	63390,	50712,	63390,	63390,	54970,
          12678,	12678,	50712,	63390,	63390,	63390,	63390,	54970,
          12678,	12678,	63390,	63390,	63390,	50712,	54970,	54970,
          0,	12678,	12678,	50712,	63390,	54970,	54970,	0,
          0,	0,	12678,	12678,	54970,	54970,	0,	0
          ]]}
        {%- endif  %}

    {% endmacro %}  
    {{iif(weather == 'clear-night' and use_moon_clear_night, draw_moon(moon_phase,0,0), draw_moon(moon_phase,23,0))}}

  payload: >
    {%- macro interpolate(dictionary, x) -%}
      {%- set sorted_keys = dictionary|dictsort -%}
      {%- set above = sorted_keys|selectattr('0', 'gt', x)|map(attribute='0')|list|first -%}
      {%- set below = sorted_keys|selectattr('0', 'lt', x)|map(attribute='0')|list|last -%}

      {#- Key matches x exactly -#}
      {%- if above is defined and dictionary[above] == x -%}
        {%- set value = dictionary[above] -%}
        {{ value }}
      {%- elif below is defined and dictionary[below] == x -%}
        {%- set value = dictionary[below] -%}
        {{ value }}
      {#- Interpolation between two values -#}
      {%- elif below is defined and above is defined -%}
        {%- set lower_value = dictionary[below] -%}
        {%- set upper_value = dictionary[above] -%}
        {%- set lower_rgb = lower_value[1:] -%}
        {%- set upper_rgb = upper_value[1:] -%}

        {%- set lower_r = lower_rgb[0:2]|int(base=16) -%}
        {%- set lower_g = lower_rgb[2:4]|int(base=16) -%}
        {%- set lower_b = lower_rgb[4:6]|int(base=16) -%}

        {%- set upper_r = upper_rgb[0:2]|int(base=16) -%}
        {%- set upper_g = upper_rgb[2:4]|int(base=16) -%}
        {%- set upper_b = upper_rgb[4:6]|int(base=16) -%}

        {%- set interpolation_factor = (x - below) / (above - below) -%}
        {%- set interpolated_r = ((1 - interpolation_factor) * lower_r + interpolation_factor * upper_r)|int -%}
        {%- set interpolated_g = ((1 - interpolation_factor) * lower_g + interpolation_factor * upper_g)|int -%}
        {%- set interpolated_b = ((1 - interpolation_factor) * lower_b + interpolation_factor * upper_b)|int -%}

        {%- set interpolated_hex = '#' ~ '%02X' % interpolated_r ~ '%02X' % interpolated_g ~ '%02X' % interpolated_b -%}
        {{ interpolated_hex }}
      {#- Only below key available -#}
      {%- elif below is defined -%}
        {%- set value = dictionary[below] -%}
        {{ value }}
      {#- Only above key available -#}
      {%- elif above is defined -%}
        {%- set value = dictionary[above] -%}
        {{ value }}
      {#- No matching keys available -#}
      {%- else -%}
        No matching key found.
      {%- endif -%}
    {%- endmacro -%}

    {#- Define macro to get length of the forecast}
    {%- macro str_len(str) %}
    {%- if '.' in str %}
    {%- set char_count = (str | length) -1 %}{{char_count * 3 + 1 + char_count}}
    {%- else %}
    {%- set char_count = (str | length) %}{{char_count * 3 + (char_count - 1)}}    
    {%- endif %}
    {%- endmacro %}

    {#- Define a macro to draw out the forecast lines#}
    {%- macro draw_forecast_lines(x,hours,height) %}
      {%- for hour in range(hours) %}
        {%- if height == 0 %}
          {"dp": [{{x+hour}},7,"{{interpolate(color_dict, forecast[hour][forecast_temp_field]) }}"]}
        {%- else %}
          {"dl": [{{x+hour}},7,{{x+hour}},{{7 - height}},"{{interpolate(color_dict, forecast[hour][forecast_temp_field]) }}"]}
        {%- endif %}
        {%- if hour+1 != hours %},{%endif%}
      {%- endfor %}
    {%- endmacro %}
    {# Define the color mapping dictionary #}
    {
    "draw": [
      {{draw_forecast_lines(8,hours_to_show,0)}},
      {"dt":[{{text_x}},1,"{{temp_text}}","{{interpolate(color_dict, current_temp | float)}}"]}
      {% if show_moon %}, {{moon_data}} {% endif %}
    ],
    "icon": "{{icon}}",
    "duration": {{message_duration}},
    "pushIcon": 2,
    "lifetime": 120,
    "weather": "{{weather}}"
    }

trigger:
  - platform: time_pattern
    seconds: /5
  - platform: state
    entity_id: !input forecast_var
    id: Changes
    enabled: true

condition: []

action:
  - repeat:
      for_each: "{{ devices_topics }}"
      sequence:
        - service: mqtt.publish
          data:
            qos: 0
            retain: false
            topic: "{{ repeat.item }}"
            payload: >
              {{payload}}
        - service: mqtt.publish
          data:
            qos: 0
            retain: false
            topic: "{{ repeat.item ~ '_sun'}} "
            payload: >
              {{sun_payload}}
/flows/6RpwLAMGOlZ4/w-sunrise.gif
/flows/6RpwLAMGOlZ4/w-sunset.gif
/flows/6RpwLAMGOlZ4/w-clear-night.gif
/flows/6RpwLAMGOlZ4/w-cloudy.gif
/flows/6RpwLAMGOlZ4/w-exceptional.gif
/flows/6RpwLAMGOlZ4/w-fog.gif
/flows/6RpwLAMGOlZ4/w-hail.gif
/flows/6RpwLAMGOlZ4/w-lightning-rainy.gif
/flows/6RpwLAMGOlZ4/w-lightning.gif
/flows/6RpwLAMGOlZ4/w-partlycloudy.gif
/flows/6RpwLAMGOlZ4/w-pouring.gif
/flows/6RpwLAMGOlZ4/w-rainy.gif
/flows/6RpwLAMGOlZ4/w-snowy-rainy.gif
/flows/6RpwLAMGOlZ4/w-snowy.gif
/flows/6RpwLAMGOlZ4/w-sunny.gif
/flows/6RpwLAMGOlZ4/w-windy-variant.gif
/flows/6RpwLAMGOlZ4/w-windy.gif
-- Flow first published on May 30, 2023, last updated on March 12, 2024 at 21:15.