blueprint: name: "AWTRIX Weather ⛈️ + Forecast + \U0001F315️" description: "\nThis 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.\n\n\n![](https://raw.githubusercontent.com/jeeftor/HomeAssistant/master/docs/weather.gif)\n\n![](https://raw.githubusercontent.com/jeeftor/HomeAssistant/master/docs/sunset.gif)\nThis blueprint will publish to two separate topics. `jeef_weather` for the weather report and `jeef_weather_sun` if its near sunrise/set\n## ⚠️ REQUIREMENTS ⚠️\nFor this blueprint to work you MUST have a few things pre-setup. \n### Moon Integration \U0001F315️\n .------.\n ( I MOON ) ..\n `------' .' /\n O \ / ;\n o i OO\n C `-. Make sure you've\n | \ <-' enabled\n ( ,--. the MOON Sensor\n V \ \\_)\n \\ :\n `._\\. \n\n\nThe 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)\n### Moon Rise/Set Sensor \U0001F315️ ⏲️\n\n M\n (X)\n // \\\\ \ Lets use a GeoLocation to find\n // \\\\ out the Moon Rise / Set\n \ // \\\\ TIMES\n // \\\\\n / \\\n\nAs 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.\nTo do so you will need to create an account and extract your `API_KEY`. Additionally you need your `LAT` and `LON`.\nThen you can add a [REST](https://www.home-assistant.io/integrations/sensor.rest/) sensor to your `configuraiton.yaml` file like the one here:\n\n resource: https://api.ipgeolocation.io/astronomy?lat=&long=&apiKey=\n \ name: ip_geo_location\n scan_interval: 300\n value_template: \"OK\"\n \ json_attributes:\n - moonrise\n - moonset\n - moon_altitude\n\n### Icons\nYou can call my custom script which will prompt you for an Awtrix device and then upload the required icons:\n \n (If you have windows I don't know if this will work)\n\n bash -c \"$(curl -fsSL https://raw.githubusercontent.com/jeeftor/HomeAssistant/master/icons/upload_icon.sh)\"\n\n_This blueprint ~will~ may be updated as new features_\n![](https://www.gravatar.com/avatar/3b9968835eb719e5d78a04ba7a2bafbd?s=64) https://raw.githubusercontent.com/jeeftor/HomeAssistant/master/blueprints/automation/awtrix_weatherflow.yaml\n" domain: automation input: awtrix: name: AWTRIX Device description: Select the Awtrix light selector: device: integration: mqtt manufacturer: Blueforcer model: AWTRIX Light multiple: true forecast_var: name: Hourly Forecast description: "Select a sensor that provides an Hourly forecast (not a daily one)\nThis integration has been tested with:\n\n - HACS [Weatherflow](https://github.com/briis/hass-weatherflow) integration \n \n - HomeAssistant [Openweather](https://www.home-assistant.io/integrations/openweathermap/)\n" selector: entity: filter: - 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.0 min: 0.0 unit_of_measurement: hours mode: box step: 1.0 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. \n\n - If you are using [Weatherflow](https://github.com/briis/hass-weatherflow) you may be able to select from either `feels_like` or `temperature`\n\n - In [Openweather](https://www.home-assistant.io/integrations/openweathermap/) you only have access to `temperature`\n" 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.0 max: 2.0 step: 1.0 mode: box unit_of_measurement: Decimal places default: 0 temp_suffix: name: Temperature suffix description: "How do you want to display the temperature\nIf you live in a country with the following flags:\n\U0001F1FA\U0001F1F8️\U0001F1F5\U0001F1F7️\U0001F1F5\U0001F1FC️\U0001F1E7\U0001F1FF️\U0001F1F0\U0001F1FE️\U0001F1EB\U0001F1F2️\U0001F1F2\U0001F1ED️\U0001F1FB\U0001F1EE️\U0001F1EC\U0001F1FA️\nYou probbaly use Farenheit.\nEverybody else in the \U0001F5FA️ 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 sort: false custom_value: false multiple: false 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:\n\n - `sensor.openweathermap_feels_like_temperature`\n" 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** \nHere you can enter a temperature to color mapping. \n> Please note the format is *JSON*,\n \n\nSome possible mappings are:\n#### USA: Farenheit 0-100 (Based on NOAA scale from 0-100)\n\n\n {\"0\": \"#FEC4FF\",\"10\": \"#D977DF\",\"20\": \"#9545BC\",\"30\": \"#4B379C\",\"40\": \"#31B8DB\",\"50\": \"#31DB8B\",\"60\": \"#6ED228\",\"70\": \"#FFFF28\",\"80\": \"#F87E27\",\"90\": \"#CF3927\",\"100\": \"#A12527\"}\n\n\n#### EURO: -12°c to -38°c based on USA NOAA Colors \n\n {\"-12\": \"#D977DF\",\"-6\": \"#9545BC\",\"-1\": \"#4B379C\",\"0\": \"#FEC4FF\",\"4\": \"#31B8DB\",\"10\": \"#31DB8B\",\"15\": \"#6ED228\",\"21\": \"#FFFF28\",\"27\": \"#F87E27\",\"32\": \"#CF3927\",\"38\": \"#A12527\"}\n" selector: text: multiline: true default: "{\n \"0\": \"#FEC4FF\",\n \"10\": \"#D977DF\",\n \"20\": \"#9545BC\",\n \ \"30\": \"#4B379C\",\n \"40\": \"#31B8DB\",\n \"50\": \"#31DB8B\",\n \"60\": \"#6ED228\",\n \"70\": \"#FFFF28\",\n \"80\": \"#F87E27\",\n \"90\": \"#CF3927\",\n \ \"100\": \"#A12527\"\n}\n" moon: name: Moon Phase Sensor description: "\U0001F311️\U0001F312️\U0001F313️\U0001F314️\U0001F316️\U0001F317️\U0001F318️\nTo setup a moon sensor see here: https://www.home-assistant.io/integrations/moon/\nor just [clicking here](https://my.home-assistant.io/redirect/config_flow_start?domain=moon)\n" 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.\nYou can create a custom REST sensor as follows:\n``` sensor: - platform: rest\n resource: https://api.ipgeolocation.io/astronomy?lat=&long=-&apiKey=\n \ name: ip_geo_location\n scan_interval: 300\n value_template: \"OK\"\n \ json_attributes:\n - moonrise\n - moonset\n - moon_altitude\n```\n" 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 \U0001F43A️ and they are called Wearwolves or maybe Astronomers. \n\nPlease select how and when you want the moon displayed\n\nBy 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.\n### NOTE:\n\n At Brightness values less than 29 the greys of the moon will render green on the clock.\n" 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 sort: false custom_value: false multiple: false 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 use_moon_sunny_night: name: Swap Sunny + Night for the Moon description: Some weather integrations may not correctly implement the `clear-night` weather state. In that case you can use this option to automatically swap out the moon for if you have night + sunny selector: boolean: {} default: true show_sun_rise_set: name: ☀️ Show Sunrise/Sunset description: "Prior to both sunrise and sunset times offer a message about pending sun transitional state.\n\n :\n `. ; .'\n \ `. .-'''-. .'\n ;' __ _;'\n / '_ _`\\ \ TURN ME ON!\n | _( a ( a |\n ''''| (_) > |``````\n \ \\ \\ / /\n `. `--'.'\n .' `-,,,-' `.\n \ .' : `.\n :\n\n\n_You can change the icons for sun rise/set way down below._\n" selector: boolean: {} default: true sun_event_minute_threshold: name: "Sun Time Prior \U0001F570️" description: "This value controls when to show sunrise/set notifications. \n\nIf 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.0 max: 1440.0 unit_of_measurement: min step: 1.0 mode: slider 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:\n\n - Relative Time: `12 min`\n - Actual Time: \ `8:31 pm` or `22:31`\n" selector: select: options: - Relative - Actual sort: false custom_value: false multiple: false 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:\n\n - `%H%M` which would render `0529`\n \n - `%-I%M%p` which woudl render `529AM`\n - `%-I%:M%p` which woudl render `5:29AM`\n\n\n\n For details see https://strftime.org/\n" selector: text: type: text multiline: false 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.0 max: 300.0 unit_of_measurement: sec step: 1.0 mode: slider 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.0 max: 300.0 unit_of_measurement: sec step: 1.0 mode: slider default: 30 icon_clear_night: name: Icon for clear-night description: "\nThe default clear_night icon is: \n\n ![](https://developer.lametric.com/content/apps/icon_thumbs/53383_icon_thumb.gif?v=2) - `53383`\n" 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`\n \n![](https://developer.lametric.com/content/apps/icon_thumbs/2286_icon_thumb.gif?v=1)\n" 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 source_url: https://raw.githubusercontent.com/jeeftor/HomeAssistant/master/blueprints/automation/awtrix_weatherflow.yaml 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 %}\n{%- set ns = namespace(devices=[]) %} {%- for device_id in device_ids %}\n {%- set device=get_device_topic(device_id)|replace(' ','') %}\n {% set ns.devices = ns.devices + [ device ~ '/custom/' ~ app_topic] %}\n{%- 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: !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 %}' 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)}}' temp_text: "{%- macro round_and_set_temp(temp_var, temp_suffix, digits=0) -%} {%- if has_value(temp_var) -%}\n {{ states(temp_var) | round(digits) ~ temp_suffix}} \n{%- else -%} ?? {%- endif -%} {%- endmacro -%} {{ round_and_set_temp(current_temp_var, temp_suffix, temp_digits)}}" 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 %}\n {%- if char.isdigit() %}\n {%- set length.value = length.value + 3 %}\n {%- elif char == '°' %}\n {%- set length.value = length.value + 2 %}\n {%- elif char == '.' %}\n {%- set length.value = length.value + 1 %}\n {%- elif char in ['-','C','F'] %}\n {%- set length.value = length.value + 3 %}\n {%- else %}\n {%- set length.value = length.value + 1 %}\n {%- endif %}\n {%- if not loop.last %}\n {%- set length.value = length.value + 1 %}{%- endif -%}\n{%- endfor -%} {{ length.value }} {%- endmacro %}\n{{get_text_len(temp_text)}}" text_x: '{{8 + ((text_available_width - text_len)/2)}}' 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(sun_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' %}\n \ {{ 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)) }}\n{%- else %} {#- relative time #}\n {% set hours = sun_min_until_next_event // 60 %}\n {% set remaining_minutes = sun_min_until_next_event % 60 %}\n\n {% if hours == 0 %}\n {{ remaining_minutes }} min\n {% else %}\n [\n {\"t\":\"{{hours}}\", \"c\":\"#ffffff\"},\n {\"t\":\"h\", \"c\":\"#9c9d97\"},\n {\"t\":\"{{remaining_minutes}}\", \"c\":\"#ffffff\"},\n {\"t\":\"m\", \"c\":\"#9c9d97\"}\n ]\n {% endif %}\n \n{%- 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 use_moon_sunny_night: !input use_moon_sunny_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({\n 'full_moon': '2314',\n 'waning_gibbous': '2315',\n \ 'last_quarter': '2316',\n 'waning_crescent': '2317',\n 'new_moon': '2318',\n \ 'waxing_crescent': '2319',\n 'first_quarter': '2320',\n '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 -%}\n {%- set key = k|float -%}\n {%- set ns.tuples = ns.tuples + [(key,v)] %} \n{% 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) %}\n {{clear_night_dict[moon_phase]}}\n{%- elif (sun_next_event == 'sunrise') and use_moon_sunny_night and (weather == 'sunny') -%}\n \n{%- else %}\n {{ icon_dict[weather] }}\n{%- endif %}\n" moon_data: "{%- macro draw_moon(phase,x=22,y=0) %}\n {%- if phase == 'first_quarter' \ %}\n {\"db\":[{{x}},{{y}},8,8,[0,0,3355443,3355443,14079702,14079702,0,0,0,3355443,3355443,3355443,15790320,14079702,14079702,0,3355443,3355443,3355443,3355443,13355979,13355979,14079702,14079702,3355443,3355443,1644825,3355443,13355979,15790320,15790320,14079702,3355443,3355443,1644825,3355443,15790320,15790320,15790320,14079702,3355443,3355443,3355443,3355443,15790320,13355979,14079702,14079702,0,3355443,3355443,3355443,15790320,14079702,14079702,0,0,0,3355443,3355443,14079702,14079702,0,0]]}\n \ {%- endif %}\n {%- if phase == 'full_moon' %}\n {\"db\":[{{x}},{{y}},8,8,[0,0,14079702,14079702,14079702,14079702,0,0,0,14079702,14079702,15790320,15790320,14079702,14079702,0,14079702,14079702,15790320,15790320,11974326,11974326,14079702,14079702,14079702,15790320,11974326,15790320,11974326,15790320,15790320,14079702,14079702,15790320,11974326,15790320,15790320,15790320,15790320,14079702,14079702,14079702,15790320,15790320,15790320,11974326,14079702,14079702,0,14079702,14079702,11974326,15790320,14079702,14079702,0,0,0,14079702,14079702,14079702,14079702,0,0]]}\n \ {%- endif %}\n {%- if phase == 'last_quarter' %}\n {\"db\":[{{x}},{{y}},8,8,[0,0,14079702,14079702,3487029,3487029,0,0,0,14079702,14079702,15790320,3487029,3487029,3487029,0,14079702,14079702,15790320,15790320,1907997,1907997,3487029,3487029,14079702,15790320,13553358,15790320,1907997,3487029,3487029,3487029,14079702,15790320,13553358,15790320,3487029,3487029,3487029,3487029,14079702,14079702,15790320,15790320,3487029,1907997,3487029,3487029,0,14079702,14079702,13553358,3487029,3487029,3487029,0,0,0,14079702,14079702,3487029,3487029,0,0]]}\n \ {%- endif %}\n {%- if phase == 'new_moon' %}\n {\"db\":[{{x}},{{y}},8,8,[0,0,2763306,2763306,2763306,2763306,0,0,0,2763306,2763306,2763306,2763306,2763306,2763306,0,2763306,2763306,2763306,2763306,1842204,1842204,2763306,2763306,2763306,2763306,1842204,2763306,1842204,2763306,2763306,2763306,2763306,2763306,1842204,2763306,2763306,2763306,2763306,2763306,2763306,2763306,2763306,2763306,2763306,1842204,2763306,2763306,0,2763306,2763306,1842204,2763306,2763306,2763306,0,0,0,2763306,2763306,2763306,2763306,0,0]]}\n \ {%- endif %}\n {%- if phase == 'waning_crescent' %}\n {\"db\":[{{x}},{{y}},8,8,[0,0,14079702,14079702,2763306,2763306,0,0,0,14079702,14079702,2763306,2763306,2763306,2763306,0,14079702,14079702,2763306,2763306,1842204,1842204,2763306,2763306,14079702,15790320,1842204,2763306,1842204,2763306,2763306,2763306,14079702,15790320,1842204,2763306,2763306,2763306,2763306,2763306,14079702,14079702,2763306,2763306,2763306,1842204,2763306,2763306,0,14079702,14079702,1842204,2763306,2763306,2763306,0,0,0,14079702,14079702,2763306,2763306,0,0]]}\n \ {%- endif %}\n {%- if phase == 'waning_gibbous' %}\n {\"db\":[{{x}},{{y}},8,8,[0,0,14079702,14079702,3552822,3552822,0,0,0,14079702,14079702,15790320,15790320,3552822,3552822,0,14079702,14079702,15790320,15790320,13421772,13421772,3552822,3552822,14079702,15790320,13421772,15790320,13421772,15790320,3552822,3552822,14079702,15790320,13421772,15790320,15790320,15790320,3552822,3552822,14079702,14079702,15790320,15790320,15790320,13421772,3552822,3552822,0,14079702,14079702,13421772,15790320,3552822,3552822,0,0,0,14079702,14079702,3552822,3552822,0,0]]}\n \ {%- endif %}\n {%- if phase == 'waxing_crescent' %}\n {\"db\":[{{x}},{{y}},8,8,[0,0,3355443,3355443,14079702,14079702,0,0,0,3355443,3355443,3355443,3355443,14079702,14079702,0,3355443,3355443,3355443,3355443,1644825,1644825,14079702,14079702,3355443,3355443,1644825,3355443,1644825,3355443,15790320,14079702,3355443,3355443,1644825,3355443,3355443,3355443,15790320,14079702,3355443,3355443,3355443,3355443,3355443,1644825,14079702,14079702,0,3355443,3355443,3355443,3355443,14079702,14079702,0,0,0,3355443,3355443,14079702,14079702,0,0]]}\n \ {%- endif %}\n {%- if phase == 'waxing_gibbous' %}\n {\"db\":[{{x}},{{y}},8,8,[0,0,3355443,3355443,14079702,14079702,0,0,0,3355443,3355443,14079702,15790320,14079702,14079702,0,3355443,3355443,15790320,15790320,12763842,12763842,14079702,14079702,3355443,3355443,12763842,15790320,12763842,15790320,15790320,14079702,3355443,3355443,12763842,15790320,15790320,15790320,15790320,14079702,3355443,3355443,15790320,15790320,15790320,12763842,14079702,14079702,0,3355443,3355443,12763842,15790320,14079702,14079702,0,0,0,3355443,3355443,14079702,14079702,0,0]]}\n \ {%- endif %}\n{%- endmacro %}\n{%- if weather == 'clear-night' and use_moon_clear_night -%} {{draw_moon(moon_phase,0,0)}} {%- elif(sun_next_event == 'sunrise') and use_moon_sunny_night and (weather == 'sunny') -%} {{draw_moon(moon_phase,0,0)}} {%- else -%} {{draw_moon(moon_phase,23,0)}} {%- endif -%}\n" payload: "{%- macro interpolate(dictionary, x) -%}\n \n {%- set sorted_keys = dictionary|dictsort -%}\n {%- set above = sorted_keys|selectattr('0', 'gt', x)|map(attribute='0')|list|first -%}\n {%- set below = sorted_keys|selectattr('0', 'lt', x)|map(attribute='0')|list|last -%}\n\n {#- Key matches x exactly -#}\n {%- if above is defined and dictionary[above] == x -%}\n {%- set value = dictionary[above] -%}\n {{ value }}\n {%- elif below is defined and dictionary[below] == x -%}\n {%- set value = dictionary[below] -%}\n {{ value }}\n {#- Interpolation between two values -#}\n {%- elif below is defined and above is defined -%}\n {%- set lower_value = dictionary[below] -%}\n {%- set upper_value = dictionary[above] -%}\n {%- set lower_rgb = lower_value[1:] -%}\n {%- set upper_rgb = upper_value[1:] -%}\n\n {%- set lower_r = lower_rgb[0:2]|int(base=16) -%}\n {%- set lower_g = lower_rgb[2:4]|int(base=16) -%}\n {%- set lower_b = lower_rgb[4:6]|int(base=16) -%}\n\n {%- set upper_r = upper_rgb[0:2]|int(base=16) -%}\n {%- set upper_g = upper_rgb[2:4]|int(base=16) -%}\n {%- set upper_b = upper_rgb[4:6]|int(base=16) -%}\n\n {%- set interpolation_factor = (x - below) / (above - below) -%}\n {%- set interpolated_r = ((1 - interpolation_factor) * lower_r + interpolation_factor * upper_r)|int -%}\n {%- set interpolated_g = ((1 - interpolation_factor) * lower_g + interpolation_factor * upper_g)|int -%}\n {%- set interpolated_b = ((1 - interpolation_factor) * lower_b + interpolation_factor * upper_b)|int -%}\n\n {%- set interpolated_hex = '#' ~ '%02X' % interpolated_r ~ '%02X' % interpolated_g ~ '%02X' % interpolated_b -%}\n {{ interpolated_hex }}\n {#- Only below key available -#}\n {%- elif below is defined -%}\n {%- set value = dictionary[below] -%}\n {{ value }}\n {#- Only above key available -#}\n {%- elif above is defined -%}\n {%- set value = dictionary[above] -%}\n \ {{ value }}\n {#- No matching keys available -#}\n {%- else -%}\n No matching key found.\n {%- endif -%}\n{%- endmacro -%}\n{#- 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 %}\n{#- Define a macro to draw out the forecast lines#} {%- macro draw_forecast_lines(x,hours,height) %}\n {%- for hour in range(hours) %}\n {%- if height == 0 %}\n {\"dp\": [{{x+hour}},7,\"{{interpolate(color_dict, forecast[hour][forecast_temp_field]) }}\"]}\n {%- else %}\n {\"dl\": [{{x+hour}},7,{{x+hour}},{{7 - height}},\"{{interpolate(color_dict, forecast[hour][forecast_temp_field]) }}\"]}\n \ {%- endif %}\n {%- if hour+1 != hours %},{%endif%}\n {%- endfor %}\n{%- endmacro %}\n\n{# Define the color mapping dictionary #} { \"draw\": [\n {%- if hours_to_show > 0 %}\n {{draw_forecast_lines(8,hours_to_show,0)}}\n {%- endif %}\n {%- if current_temp != 'unavailable' -%}\n ,{\"dt\":[{{text_x}},1,\"{{temp_text}}\",\"{{interpolate(color_dict, current_temp | float)}}\"]}\n {%- else -%}\n {\"dt\":\"err\"}\n {%- endif -%}\n \n {% if show_moon %}\n ,{{moon_data}}\n {% endif %}\n], \"icon\": \"{{icon}}\", \"duration\": {{message_duration}}, \"pushIcon\": 2, \"lifetime\": 120, \"lifetimeMode\":1, \"weather\": \"{{weather}}\" }\n" 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}} '