- alias: PV clipping - Forecast clipped PV for next 24 hours description: 'Calculates forecast clipped PV for day = sum of 5 minute predbat.pv_energy forecasts > inverter limit. Change the variables to suit your set-up. Adjust the tuning_factor to optimise battery availability. The tuning factor is designed to account for spikey solar due to intermittent clouds and how aggressive you want to be with making room in the battery - the lower the value, the more room it will make.' triggers: - event: sunrise offset: 0 trigger: sun conditions: [] actions: - variables: tuning_factor: 0.9 inverter_limit_kW: 5 inverter_limit: '{{ inverter_limit_kW / 12 }}' - metadata: {} data: value: "{% set pv_clipped = namespace(value=0.0) %} {% set pv_prev\ \ = namespace(value=0.0) %} {% set pv_cur = namespace(value=0.0) %}\ \ {% if state_attr('predbat.pv_energy', 'results') %}\n {%- for five_min_period\ \ in state_attr('predbat.pv_energy', 'results') -%}\n {% if loop.index0\ \ == 0 %}\n {%- set pv_prev.value = state_attr('predbat.pv_energy', 'results')[five_min_period]\ \ | float -%}\n {% else %}\n {%- set pv_cur.value = state_attr('predbat.pv_energy',\ \ 'results')[five_min_period] | float -%}\n {% set tuned_clipped = (pv_cur.value\ \ - pv_prev.value) / tuning_factor %}\n {% if tuned_clipped > inverter_limit\ \ %}\n {%- set pv_clipped.value = pv_clipped.value + tuned_clipped\ \ - inverter_limit -%}\n {% endif %}\n {%- set pv_prev.value = pv_cur.value\ \ -%}\n {% endif %}\n {# Only look at the next 24 hours (each loop is\ \ 5 minutes) #}\n {% if loop.index0 == 288 %}\n {% break %}\n {%\ \ endif %}\n {%- endfor -%} \n{% endif %} {{ pv_clipped.value }}\n" target: entity_id: input_number.pv_clipped_in_next_24_hours action: input_number.set_value mode: single - alias: PV clipping - make room in battery at sunrise description: "Make room in battery at sunrise if PV clipping is forecast in the\ \ next 24 hours \nAdjust the variables to suit your set-up. The sunrise_to_clipping_hours\ \ variable is the number of hours from sunrise to when your set-up is first at\ \ risk of clipping. Round up to the nearest half-hour eg 3.5\nIf any clipping\ \ is predicted, the automation sets the first 30-min export for (sunrise_to_clipping_hours\ \ - 0.5) hours after sunrise. Then backfills towards sunrise with appropriate\ \ force export and freeze export slots. Assumes a straight-line increase in export\ \ capacity being taken up by solar export from sunrise to clipping start. And\ \ a corresponding decrease in availability for battery export. Does not account\ \ for load." triggers: - event: sunrise offset: '120' trigger: sun conditions: - condition: numeric_state entity_id: predbat.rates above: 0 - condition: template value_template: '{{ states(''input_number.pv_clipped_in_next_24_hours'') | float > 0 }} ' actions: - variables: inverter_limit: 5 bat_capacity_max: 9.5 bat_discharge_max: 3.6 sunrise_to_clipping_hours: 4 slots: '{{ (sunrise_to_clipping_hours * 2) | int }}' soc: '{{ states(''predbat.soc_kw_h0'') | float }}' - repeat: sequence: - if: - condition: template value_template: '{{ states(''input_number.pv_clipped_in_next_24_hours'') | float > 0 }}' then: - metadata: {} data: option: '{% set t = utcnow().strftime("%s") | int %} {# Round up the time to nearest half-hour #} {# Set 30-min export for offset seconds after sunrise #} {% set offset = (slots - repeat.index) * 1800 %} {{ (t - (t % 1800) + offset) | timestamp_custom("%H:%M:%S") }} ' target: entity_id: select.predbat_manual_export action: select.select_option - action: input_number.set_value metadata: {} data: value: "{# Assume straight line climb in solar export from 0 to inverter_limit\ \ over sunrise_to_clipping_hours. #} {% set solar_export = (slots\ \ - repeat.index) * (inverter_limit / slots) %} {% set available_export_capacity\ \ = inverter_limit - solar_export %} {# How much battery can be\ \ exported in 30-min period? #} {% set battery_export = min(bat_discharge_max,\ \ available_export_capacity) / 2 %} {# If the battery isn't full,\ \ we already have some spare capacity for clipping. #} {% set clipping\ \ = namespace(value=states('input_number.pv_clipped_in_next_24_hours')\ \ | float) %} {% if repeat.index == 1 %}\n {%- set clipping.value\ \ = clipping.value - (bat_capacity_max - soc) -%}\n{% endif %} {# We\ \ don't need to export more than the current battery SOC. #} {% set\ \ excess = min(soc, clipping.value) %} {{ max(excess - battery_export,\ \ 0) }}\n" target: entity_id: input_number.pv_clipped_in_next_24_hours else: - metadata: {} data: option: '{% set t = utcnow().strftime("%s") | int %} {# Round up the time to nearest half-hour #} {# Set 30-min freeze charge for offset seconds after sunrise #} {% set offset = (slots - repeat.index) * 1800 %} {{ (t - (t % 1800) + offset) | timestamp_custom("%H:%M:%S") }} ' target: entity_id: select.predbat_manual_freeze_export action: select.select_option - delay: hours: 0 minutes: 0 seconds: 1 milliseconds: 0 count: '{{ slots }}' mode: single - alias: PV clipping - PV goes above inverter limit description: Set predbat force manual export for this 30-min period. (Replace geserial with your GE inverter serial number. Replace 5000 with your hybrid inverter limit in Watts.) triggers: - entity_id: - sensor.givtcp_geserial_pv_power above: 5000 trigger: numeric_state - minutes: '1' trigger: time_pattern - minutes: '31' trigger: time_pattern conditions: - condition: sun before: sunset after: sunrise - condition: numeric_state entity_id: predbat.rates above: 0 - condition: template value_template: "{# Check this half-hour is not already set to force export #}\ \ \n{% set t = utcnow().strftime(\"%s\") | int %} \n{% set half_hour = (t -\ \ (t % 1800 )) | timestamp_custom(\"%H:%M:%S\") %}\n{{ half_hour not in states('select.predbat_manual_export')\ \ }}" - condition: numeric_state entity_id: sensor.givtcp_geserial_pv_power above: 5000 - condition: numeric_state entity_id: predbat.soc_kw_h0 above: 1 actions: - metadata: {} data: option: '{# Round down the time to nearest half-hour #} {% set t = utcnow().strftime("%s") | int %} {{ (t - (t % 1800 )) | timestamp_custom("%H:%M:%S") }} ' target: entity_id: select.predbat_manual_export action: select.select_option mode: single