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