Macro to get day range for maximize pv power based on Solcast prevision

Based on Solcast prevision, the macro determine best hours next day to power water boiler for instance.

This is my first macro in HA/Templating/Jinja/Python, please be indulgent ^^

To put inside /homeassistant/custom_templates/tools.jinja for instance

{# Macro pour déterminer les heures d'ensoleillement #}
{%- macro dates_sun(seuil_on, seuil_off) -%}
{%- set myvar = namespace(start=now(), end=now(), power=0) -%}
{%- set myvar.start = ((states('sensor.solcast_pv_forecast_heure_du_pic_demain') | as_datetime | as_local) + timedelta(hours=-1)) -%}
{%- set myvar.end   = ((states('sensor.solcast_pv_forecast_heure_du_pic_demain') | as_datetime | as_local) + timedelta(hours=+1)) -%}
{%- set forecast = state_attr('sensor.solcast_pv_forecast_previsions_pour_demain','detailedForecast') -%}
{%- for data in forecast -%}
  {# {{ data.period_start | as_datetime | as_local }} = {{ data.pv_estimate }} #}  
  {%- if( data.pv_estimate >= (seuil_on/1000) ) -%}
    {# critere de 1800W mini en début de chauffe #}
    {%- set myvar.start=min(myvar.start, data.period_start + timedelta(minutes=-30) ) -%}
  {%- endif -%}
  {%- if( data.pv_estimate >= (seuil_off/1000) ) -%}
    {# critere de 1300W mini en fin de chauffe #}
    {%- set myvar.end=max(myvar.end, data.period_start + timedelta(minutes=+30) ) -%}
    {%- set myvar.power=myvar.power+data.pv_estimate*1000 -%}
  {%- endif -%}
{%- endfor -%}
{# formatage de la sortie en JSON #}
{{- dict(start=myvar.start.isoformat(), end=myvar.end.isoformat(), power=myvar.power) | to_json -}}
{%- endmacro -%}

Then

{%- from 'tools.jinja' import dates_sun -%}
{%- set sundates= dates_sun(1800,1300)|from_json -%}
Beginning:{{ sundates.start }}         # Beginning:2025-05-15T08:00:00+02:00
End:      {{ sundates.end }}           # End:      2025-05-15T17:00:00+02:00
Power:    {{ sundates.power|float }}W  # Power:    45686.8W
1 Like

I use this macro in an automation that creates events in a calendar called calendar.cumulus.
If the prevision for tomorrow is good, the water boiler will be heated during the day, otherwise it is heated the night.

It requires an input_select called input_select.cumulus_mode = [‘On’,‘Off’,‘Auto’,‘Jour/Nuit’,‘Vacances’]

alias: Cumulus - Planification periode de chauffe
description: ""
triggers:
  - trigger: time
    at: "20:00:00"
  - trigger: state
    entity_id:
      - input_select.cumulus_mode
    to: Auto
conditions:
  - condition: or
    conditions:
      - condition: state
        entity_id: input_select.cumulus_mode
        state: Auto
      - condition: state
        entity_id: input_select.cumulus_mode
        state: Jour/Nuit
actions:
  - alias: Set variables
    variables:
      sundates: >-
        {%- from 'tools.jinja' import dates_sun -%} {{-
        dates_sun(1800,1300)|from_json -}}
  - choose:
      - conditions:
          - condition: template
            value_template: "{{ sundates.power|float>5000 }}"
            alias: Si prod >5kW sur la période de chauffe
          - condition: numeric_state
            entity_id: sensor.solcast_pv_forecast_previsions_pour_demain
            attribute: estimate
            above: 10
            enabled: false
          - condition: numeric_state
            entity_id: sensor.solcast_pv_forecast_previsions_du_pic_pour_demain
            attribute: estimate
            above: 1800
          - condition: state
            entity_id: input_select.cumulus_mode
            state: Auto
        sequence:
          - action: calendar.create_event
            alias: Planifie la chauffe en journée le lendemain
            metadata: {}
            data:
              summary: Chauffe CE
              start_date_time: "{{ sundates.start }}"
              end_date_time: "{{ sundates.end }}"
            target:
              entity_id: calendar.cumulus
        alias: Si mode auto ET puissance demain >10kWh ET pic >1800W
    default:
      - alias: Planifie la chauffe durant la nuit
        action: calendar.create_event
        metadata: {}
        data:
          summary: Chauffe CE
          start_date_time: "{{ now().replace(hour=23, minute=0, second=0).isoformat() }}"
          end_date_time: >-
            {{ (now().replace(hour=23, minute=0, second=0) +
            timedelta(hours=3)).isoformat() }}
        target:
          entity_id: calendar.cumulus
mode: single