lubeda / EspHoMaTriXv2

A simple DIY status display with a 8x32 RGB LED matrix, implemented with esphome.io and Home Assistant.
MIT License
276 stars 25 forks source link

[FEATURE REQUEST] Hourly forecast bar - Interesting idea #149

Closed andrewjswan closed 9 months ago

andrewjswan commented 10 months ago

Feature Request

Describe the solution / feature you'd like

Interesting idea, to make a screen with weather, but exactly made for the weather, but here we need to figure out how to fit it into the current concept of our screens.

I mean, we need to transfer to the screen:

like:

weather_screen(icon_name, text, default_font, default_color, forecast)

IMHO better

icon_prognosis_screen(icon_name, text, default_font, default_color, forecast)
icon_prognosis_screen_rgb(icon_name, text, default_font, default_color, forecast, r, g, b)

Additional context

image

andrewjswan commented 10 months ago
{%- set values = namespace(temp=[]) %}
{% for temp in  (states.weather.current_weather.attributes.forecast | map(attribute='temperature') | list)[:5] %}
  {%- set json = ([255,0,0] if temp > 30 else [0,255,0] if temp > 20 else [255,255,0] if temp > 5 else [0,0,255]) -%}
  {%- set values.temp = values.temp + [ json ] %}
{% endfor %}
{{ values.temp }}
andrewjswan commented 10 months ago
    {% set current_temp = states('sensor.temperature_outside') %}
    {% set forecast = state_attr('weather.current_weather','forecast') %}
    {% set forecast_temp_field = "temperature" %} {# "feels_like" #}
    {% set hours_to_show = 3 %}
    {% set color_dict = {-12: "#D977DF",-6: "#9545BC",-1: "#4B379C",0: "#FEC4FF",4: "#31B8DB",10: "#31DB8B",15: "#6ED228",21: "#FFFF28",27: "#F87E27",32: "#CF3927",38: "#A12527"} %}

    {%- 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_value = interpolated_r ~ ',' ~ interpolated_g ~ ',' ~ interpolated_b -%}
        {{ interpolated_value }}
      {#- 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 -%}

    {%- macro draw_forecast_lines(hours) -%}
      {%- if forecast -%}
        {%- for hour in range(hours) -%}
          {%- if hour < forecast | count -%}
            [{{ interpolate(color_dict, forecast[hour][forecast_temp_field]) }}]
            {%- if hour + 1 != hours -%},{%- endif -%}
          {%- endif -%}
        {%- endfor -%}
      {%- endif -%}
    {%- endmacro -%}

    {{ draw_forecast_lines(hours_to_show) }} 
[
  [
    100,
    187,
    228
  ],
  [
    100,
    187,
    228
  ],
  [
    100,
    187,
    228
  ]
]
andrewjswan commented 10 months ago
    {% set current_temp = states('sensor.temperature_outside') %}
    {% set forecast = state_attr('weather.current_weather','forecast') %}
    {% set forecast_temp_field = "temperature" %} {# "feels_like" #}
    {% set hours_to_show = 3 %}
    {% set color_dict = {-12: "#D977DF",-6: "#9545BC",-1: "#4B379C",0: "#FEC4FF",4: "#31B8DB",10: "#31DB8B",15: "#6ED228",21: "#FFFF28",27: "#F87E27",32: "#CF3927",38: "#A12527"} %}

    {%- 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_value = interpolated_r ~ ',' ~ interpolated_g ~ ',' ~ interpolated_b -%}
        {{ interpolated_value }}
      {#- 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 -%}

    {%- macro get_forecast_array(hours) -%}
      {% set array = namespace(data = []) %}
      {%- if forecast -%}
        {%- for hour in range(min(hours, 24)) -%}
          {%- if hour < forecast | count -%}
            {% set array.data = array.data + [interpolate(color_dict, forecast[hour][forecast_temp_field])] %}
          {%- endif -%}
        {%- endfor -%}
      {%- endif -%}
      {{ '{ "data": ' ~ array.data | to_json ~ '}' }}
    {%- endmacro -%}

    {%- macro make_forecast_line(hours) -%}
      {% set forecast = get_forecast_array(hours) | from_json %}
      {%- if forecast.data | count > 0 -%}
        {% set step = namespace(steps = 0) %}
        {%- for hour in range(min(hours, 24)) -%}
          {%- set step.steps = step.steps + 1 -%}
          {%- for h in range( ((hour * 24 / hours) | round(0)), ((step.steps * 24 / hours) | round(0)) ) -%}
            [{{ forecast.data[hour] }}]
          {%- endfor -%}
        {%- endfor -%}
      {%- endif -%}
    {%- endmacro -%}

    {{ make_forecast_line(hours_to_show) | replace('][',',') }} 
lubeda commented 10 months ago

The visual impression is great but the coding on the client side is "rocket science". I will take a look on how blueprints could help users to use the complex features of ehmtx.

@andrewjswan your creativity pushes this project. Thanx

andrewjswan commented 10 months ago

The visual impression is great but the coding on the client side is "rocket science". I will take a look on how blueprints could help users to use the complex features of ehmtx.

I'm not good at Blueprint, but I think adapting the template above into Blueprint is not a problem. And this screen will essentially be able to display any information, not necessarily the weather, for example a certain forecast, with an icon, text and a forecast line.

andrewjswan commented 10 months ago
service: esphome.ulanzi_icon_prognosis_screen
data:
  icon_name: "weather_{{ states('weather.current_weather') | replace('-','_') }}|weather"
  text: "{{ states('sensor.temperature_outside') }}¬"
  prognosis: >-
    {% set forecast = state_attr('weather.current_weather','forecast') %}
    {% set forecast_temp_field = "temperature" %} {# "feels_like" #}
    {% set hours_to_show = 12 %}
    {% set color_dict = {-12: "#D977DF",-6: "#9545BC",-1: "#4B379C",0: "#FEC4FF",4: "#31B8DB",10: "#31DB8B",15: "#6ED228",21: "#FFFF28",27: "#F87E27",32: "#CF3927",38: "#A12527"} %}

    {%- 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 above == x -%}
        {%- set value = dictionary[above] -%}
        {%- set rgb = value[1:] -%}
        {{ rgb[0:2]|int(base=16) ~ ',' ~ rgb[2:4]|int(base=16) ~ ',' ~ rgb[4:6]|int(base=16)}}
      {%- elif below is defined and below == x -%}
        {%- set value = dictionary[below] -%}
        {%- set rgb = value[1:] -%}
        {{ rgb[0:2]|int(base=16) ~ ',' ~ rgb[2:4]|int(base=16) ~ ',' ~ rgb[4:6]|int(base=16)}}
      {#- 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_value = interpolated_r ~ ',' ~ interpolated_g ~ ',' ~ interpolated_b -%}
        {{ interpolated_value }}
      {#- Only below key available -#}
      {%- elif below is defined -%}
        {%- set value = (sorted_keys|last)[1] -%}
        {%- set rgb = value[1:] -%}
        {{ rgb[0:2]|int(base=16) ~ ',' ~ rgb[2:4]|int(base=16) ~ ',' ~ rgb[4:6]|int(base=16)}}
      {#- Only above key available -#}
      {%- elif above is defined -%}
        {%- set value = (sorted_keys|first)[1] -%}
        {%- set rgb = value[1:] -%}
        {{ rgb[0:2]|int(base=16) ~ ',' ~ rgb[2:4]|int(base=16) ~ ',' ~ rgb[4:6]|int(base=16)}}
      {#- No matching keys available -#}
      {%- else -%}
        No matching key found.
      {%- endif -%}
    {%- endmacro -%} 

    {%- macro get_forecast_array(hours) -%}
      {% set array = namespace(data = []) %}
      {%- if forecast -%}
        {%- for hour in range(min(hours, 24)) -%}
          {%- if hour < forecast | count -%}
            {% set array.data = array.data + [interpolate(color_dict, forecast[hour][forecast_temp_field])] %}
          {%- endif -%}
        {%- endfor -%}
      {%- endif -%}
      {{ '{ "data": ' ~ array.data | to_json ~ '}' }}
    {%- endmacro -%}

    {%- macro make_forecast_line(hours) -%}
      {% set forecast = get_forecast_array(hours) | from_json %}
      {%- if forecast.data | count > 0 -%}
        {% set step = namespace(steps = 0) %}
        {% set result = forecast.data | count %}
        {%- for hour in range(min(result, 24)) -%}
          {%- set step.steps = step.steps + 1 -%}
          {%- for h in range( ((hour * 24 / result) | round(0)), ((step.steps * 24 / result) | round(0)) ) -%}
            [{{ forecast.data[hour] }}]
          {%- endfor -%}
        {%- endfor -%}
      {%- endif -%}
    {%- endmacro -%}

    {{ make_forecast_line(hours_to_show) | replace('][',',') }}
  lifetime: 1
  screen_time: 10
  default_font: true
andrewjswan commented 10 months ago

Farenheit:

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

@lubeda That's a funny screen we get, it's basically ready to go, but I'm going to have obvious difficulties with documentation. I can briefly describe it, but there is no point in writing a sheet of code in Blueprint in the documentation.... Do a PR with minimal documentation?

andrewjswan commented 9 months ago

IMG_20231118_112909

chertvl commented 9 months ago

I added a little to the jinja template to move away from fixed temperature and color values (changes only in color_dict). In this option, a forecast is taken for the n-period, the minimum value for the period is assigned cold blue, the maximum value warm yellow, and the average value neutral white.

With floating min/max values, you can very clearly see when it will be warmer and when it will be colder during the period, compared to the average value for the period.

This is what my forecast looks like, which consists of values: +2, =0, +1, +1, -1, +1, +5° (by day) The matrix shows that at the end of the week (7th day) warming can be expected:

image

        {% set forecast = state_attr('weather.home','forecast') %} 
        {% set forecast_temp_field = "temperature" %} {# "feels_like" #} 
        {% set hours_to_show = 7 %} 
        {% set color_dict = {
           forecast | map(attribute=forecast_temp_field) | min: '#0077ff', 
           forecast | map(attribute=forecast_temp_field) | average: '#ffffff', 
           forecast | map(attribute=forecast_temp_field) | max: '#ffaa00' } %}

        {%- 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 above == x -%}
            {%- set value = dictionary[above] -%}
            {%- set rgb = value[1:] -%}
            {{ rgb[0:2]|int(base=16) ~ ',' ~ rgb[2:4]|int(base=16) ~ ',' ~ rgb[4:6]|int(base=16)}}
          {%- elif below is defined and below == x -%}
            {%- set value = dictionary[below] -%}
            {%- set rgb = value[1:] -%}
            {{ rgb[0:2]|int(base=16) ~ ',' ~ rgb[2:4]|int(base=16) ~ ',' ~ rgb[4:6]|int(base=16)}}
          {#- 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_value = interpolated_r ~ ',' ~ interpolated_g ~ ',' ~ interpolated_b -%}
            {{ interpolated_value }}
          {#- Only below key available -#}
          {%- elif below is defined -%}
            {%- set value = (sorted_keys|last)[1] -%}
            {%- set rgb = value[1:] -%}
            {{ rgb[0:2]|int(base=16) ~ ',' ~ rgb[2:4]|int(base=16) ~ ',' ~ rgb[4:6]|int(base=16)}}
          {#- Only above key available -#}
          {%- elif above is defined -%}
            {%- set value = (sorted_keys|first)[1] -%}
            {%- set rgb = value[1:] -%}
            {{ rgb[0:2]|int(base=16) ~ ',' ~ rgb[2:4]|int(base=16) ~ ',' ~ rgb[4:6]|int(base=16)}}
          {#- No matching keys available -#}
          {%- else -%}
            No matching key found.
          {%- endif -%}
        {%- endmacro -%}

        {%- macro get_forecast_array(hours) -%}
          {% set array = namespace(data = []) %}
          {%- if forecast -%}
            {%- for hour in range(min(hours, 24)) -%}
              {%- if hour < forecast | count -%}
                {% set array.data = array.data + [interpolate(color_dict, forecast[hour][forecast_temp_field])] %}
              {%- endif -%}
            {%- endfor -%}
          {%- endif -%}
          {{ '{ "data": ' ~ array.data | to_json ~ '}' }}
        {%- endmacro -%}

        {%- macro make_forecast_line(hours) -%}
          {% set forecast = get_forecast_array(hours) | from_json %}
          {%- if forecast.data | count > 0 -%}
            {% set step = namespace(steps = 0) %}
            {% set result = forecast.data | count %}
            {%- for hour in range(min(result, 24)) -%}
              {%- set step.steps = step.steps + 1 -%}
              {%- for h in range( ((hour * 24 / result) | round(0)), ((step.steps * 24 / result) | round(0)) ) -%}
                [{{ forecast.data[hour] }}]
              {%- endfor -%}
            {%- endfor -%}
          {%- endif -%}
        {%- endmacro -%}

        {{ make_forecast_line(hours_to_show) | replace('][',',') }}
chertvl commented 9 months ago

Instead of my addition in previous message, Fixed values (from 0 to 100% for example) perfectly fits for some cases, for example, chance of rain for 5 hours: image

    {% set forecast = state_attr('weather.home','forecast') %} 
    {% set forecast_temp_field = "precipitation_probability" %} {# "feels_like" #} 
    {% set hours_to_show = 5 %} 
    {% set max_prob = forecast | map(attribute=forecast_temp_field) | max %}
    {% set color_dict = {0: '#999999', 100: '#0000ff'} %}

    {%- 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 above == x -%}
        {%- set value = dictionary[above] -%}
        {%- set rgb = value[1:] -%}
        {{ rgb[0:2]|int(base=16) ~ ',' ~ rgb[2:4]|int(base=16) ~ ',' ~ rgb[4:6]|int(base=16)}}
      {%- elif below is defined and below == x -%}
        {%- set value = dictionary[below] -%}
        {%- set rgb = value[1:] -%}
        {{ rgb[0:2]|int(base=16) ~ ',' ~ rgb[2:4]|int(base=16) ~ ',' ~ rgb[4:6]|int(base=16)}}
      {#- 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_value = interpolated_r ~ ',' ~ interpolated_g ~ ',' ~ interpolated_b -%}
        {{ interpolated_value }}
      {#- Only below key available -#}
      {%- elif below is defined -%}
        {%- set value = (sorted_keys|last)[1] -%}
        {%- set rgb = value[1:] -%}
        {{ rgb[0:2]|int(base=16) ~ ',' ~ rgb[2:4]|int(base=16) ~ ',' ~ rgb[4:6]|int(base=16)}}
      {#- Only above key available -#}
      {%- elif above is defined -%}
        {%- set value = (sorted_keys|first)[1] -%}
        {%- set rgb = value[1:] -%}
        {{ rgb[0:2]|int(base=16) ~ ',' ~ rgb[2:4]|int(base=16) ~ ',' ~ rgb[4:6]|int(base=16)}}
      {#- No matching keys available -#}
      {%- else -%}
        No matching key found.
      {%- endif -%}
    {%- endmacro -%}

    {%- macro get_forecast_array(hours) -%}
      {% set array = namespace(data = []) %}
      {%- if forecast -%}
        {%- for hour in range(min(hours, 24)) -%}
          {%- if hour < forecast | count -%}
            {% set array.data = array.data + [interpolate(color_dict, forecast[hour][forecast_temp_field])] %}
          {%- endif -%}
        {%- endfor -%}
      {%- endif -%}
      {{ '{ "data": ' ~ array.data | to_json ~ '}' }}
    {%- endmacro -%}

    {%- macro make_forecast_line(hours) -%}
      {% set forecast = get_forecast_array(hours) | from_json %}
      {%- if forecast.data | count > 0 -%}
        {% set step = namespace(steps = 0) %}
        {% set result = forecast.data | count %}
        {%- for hour in range(min(result, 24)) -%}
          {%- set step.steps = step.steps + 1 -%}
          {%- for h in range( ((hour * 24 / result) | round(0)), ((step.steps * 24 / result) | round(0)) ) -%}
            [{{ forecast.data[hour] }}]
          {%- endfor -%}
        {%- endfor -%}
      {%- endif -%}
    {%- endmacro -%}

    {{ make_forecast_line(hours_to_show) | replace('][',',') }}
andrewjswan commented 9 months ago

Added to 2023.9.1