GoodWe grid export limit

Try this.

blueprint:
  name: GoodWe export-limiter naar doelwaarde met hysterese (P1 + HomeWizard)
  description: >
    Regelt de GoodWe exportlimiet zodat ~target W naar het net wordt teruggeleverd,
    met hysterese om fladderen te voorkomen. Werkt met HomeWizard P1 (netvermogen)
    en een GoodWe "number" entiteit voor exportlimiet (0–4200 W).
  domain: automation
  input:
    p1_power_entity:
      name: P1 netvermogen sensor
      description: Sensor met actueel netvermogen (W). Bij P1 is export meestal negatief.
      selector:
        entity:
          domain: sensor
    goodwe_limit_entity:
      name: GoodWe exportlimiet (number)
      description: Number-entiteit waarmee je de exportlimiet (W) zet.
      selector:
        entity:
          domain: number
    target_export_w:
      name: Doelwaarde export (W)
      default: 250
      selector:
        number:
          min: 0
          max: 6000
          step: 50
          unit_of_measurement: W
          mode: box
    hysteresis_w:
      name: Hysterese (±W)
      description: Pas de limiet pas aan als de afwijking groter is dan deze waarde.
      default: 100
      selector:
        number:
          min: 50
          max: 1000
          step: 10
          unit_of_measurement: W
          mode: box
    step_w:
      name: Stapgrootte (W)
      description: Grootte van elke aanpassing van de exportlimiet.
      default: 100
      selector:
        number:
          min: 20
          max: 1000
          step: 10
          unit_of_measurement: W
          mode: box
    min_limit_w:
      name: Minimum exportlimiet (W)
      default: 0
      selector:
        number:
          min: 0
          max: 4200
          step: 50
          unit_of_measurement: W
          mode: box
    max_limit_w:
      name: Maximum exportlimiet (W)
      default: 4200
      selector:
        number:
          min: 0
          max: 10000
          step: 50
          unit_of_measurement: W
          mode: box
    invert_p1_sign:
      name: P1-teken omkeren (export is negatief)
      description: Laat aan staan wanneer je P1 export negatief is (standaard bij HomeWizard P1).
      default: true
      selector:
        boolean: {}
    sample_seconds:
      name: Update-interval (seconden)
      default: 5
      selector:
        number:
          min: 5
          max: 120
          step: 5
          unit_of_measurement: s
          mode: slider
    enable_helper:
      name: (Optioneel) schakelaar om regeling te activeren
      default:
      selector:
        entity:
          domain: input_boolean
          multiple: false

mode: single
max_exceeded: silent

variables:
  p1_entity: !input p1_power_entity
  limit_entity: !input goodwe_limit_entity
  target_w: !input target_export_w
  hyst_w: !input hysteresis_w
  step_w: !input step_w
  min_w: !input min_limit_w
  max_w: !input max_limit_w
  invert: !input invert_p1_sign

  # Huidige metingen/staten
  p1_raw: "{{ states(p1_entity) | float(0) }}"
  # Maak export positief in W; import wordt 0
  export_now: >
    {% set v = (invert | iif(-1,1)) * p1_raw %}
    {{ [v, 0] | max }}
  limit_now: "{{ states(limit_entity) | float(0) }}"
  error_w: "{{ target_w - export_now }}"
  need_adjust: "{{ (error_w | abs) > hyst_w }}"
  direction: "{{ 1 if error_w > 0 else -1 }}"
  proposed_limit: >
    {% set adjust = [step_w, (error_w | abs)] | min * direction %}
    {{ (limit_now + adjust) | float }}
  clamped_limit: >
    {% if proposed_limit < min_w %} {{ min_w }}
    {% elif proposed_limit > max_w %} {{ max_w }}
    {% else %} {{ proposed_limit }}
    {% endif %}

trigger:
  - platform: time_pattern
    seconds: "/10"

condition:
  - condition: template
    value_template: "{{ states(p1_entity) not in ['unknown','unavailable','none'] }}"
  - condition: template
    value_template: "{{ states(limit_entity) not in ['unknown','unavailable','none'] }}"
  - condition: template
    value_template: >
      {% if not enable_helper %}
        true
      {% else %}
        {{ is_state(enable_helper, 'on') }}
      {% endif %}

action:
  - choose:
      - conditions:
          - condition: template
            value_template: "{{ need_adjust }}"
        sequence:
          - service: number.set_value
            target:
              entity_id: "{{ limit_entity }}"
            data:
              value: "{{ clamped_limit }}"
    default: []

Hi, how can i use this, do i have to modify anything?

Hi everyone,

I have set this up aswell with a GoodWe GW5000D-NS inverter and a HomeWizzard P1 meter.

Question: Is there a risk the inverter gets overheated with the (fluctuating) export to grid limitation setting? How does the inverter deal with the enery it can`t get rid of?

It took me some time to understand how to implement this, but I’ve got it running now. This works great @m.villing, thanks allot!

I’m going to purchase solar panels and I’m considering a GoodWe inverter.
Indeed I like to be able to steer how much power the solar panels generate, or to be able to shut the system down when desired.

GoodWe Inverter - Home Assistant makes no mention whatsoever of such a ‘export limit’ functionality input_number. Is the documentation incomplete?

Can someone please confirm it is really there? How does it work, the number entered regulates how much power the inverter generates? Because the inverter won’t get to know my house consumption. I have a P1 meter connected to HA, so HA has this data. Based on that I would want HA to tell the interter what to do, using f.i. the blueprint of @m.villing ?

Hello M.Villing, I am new to the field of HA but would like to use your Bleuprint “Goodwe export limit with P1 HomeWizard”. I have two Goodwe inverters (GW3000N-XS) and a HomeWizard in the P1 port. I can import the data into HA but do not see any regulation regarding the export limit, and after much trying, I am at a loss for now and think I will ask the creator of the Bleuprint for help. Can and will you provide me with assistance? Regards, Arjan

Looks like the export limit entity of the Goodwe integration was removed(?) in the latest version of Home Assistant. It's listed as removed in my Home Assistant (5000 W 3-phase inverter)

I've been using it to dynamically turn off the inverter

Reloading the integration fixed it. Seems like a little networking hiccup, compounded by a PEBKAC error to these forums

Hi @oZZies

I have the same setup (GW5000D-NS and a Home Wizard P1 meter)
Can you give me a kickstart on how to fill in the blueprint with the entities of Goodwe and Home Wizard?

Hi again,

I want to share my automation for others.

Something you must know about my setup and goals:

18 solar panels on EAST
If I set the grid export limit of my Goodwe GW5000D-NS converter to "0" it won't generate ANY solar power

My goal is to minimize the export of the generated PV power back to the energy company, because in the Netherlands (starting on 1 january 2027) you have to pay money for exported PV-power without a good compensation for that delivered exported energy.

Here is my automation:

alias: GoodWe Export Limiter
description: 🔴 Variables alleen zichtbaar in YAML
triggers:
  - entity_id:
      - sensor.p1_meter_active_power
    trigger: state
conditions:
  - condition: numeric_state
    entity_id: sensor.pv_power
    above: 10
actions:
  - condition: template
    value_template: "{{ active }}"
  - target:
      entity_id: "{{ limit_entity }}"
    data:
      value: "{{ clamped_limit }}"
    action: number.set_value
variables:
  p1_entity: sensor.p1_meter_active_power
  pv_entity: sensor.pv_power
  limit_entity: number.grid_export_limit
  target_export: 250
  min_w: 0
  max_w: 4200
  max_step: 250
  deadband: 80
  p1: "{{ states(p1_entity) | float(0) }}"
  pv: "{{ states(pv_entity) | float(0) }}"
  export_now: "{{ -p1 if p1 < 0 else 0 }}"
  error: "{{ target_export - export_now }}"
  active: "{{ error | abs > deadband }}"
  kp: 0.5
  step_raw: "{{ error * kp }}"
  step_limited: |
    {% if step_raw > max_step %}
      {{ max_step }}
    {% elif step_raw < -max_step %}
      {{ -max_step }}
    {% else %}
      {{ step_raw }}
    {% endif %}
  limit_now: "{{ states(limit_entity) | float(0) }}"
  proposed_limit: "{{ limit_now + step_limited }}"
  clamped_limit: |
    {% if proposed_limit < min_w %}
      {{ min_w }}
    {% elif proposed_limit > max_w %}
      {{ max_w }}
    {% else %}
      {{ proposed_limit | round(0) }}
    {% endif %}
mode: restart

Here the results on a sunny day:

afbeelding

Below the result without the automation that limits the export on a partially sunny day (you can see the dips):

afbeelding

This is exactly what I'm looking for. Thanks for sharing!

I also have a Homewizard P1 meter and a Goodwe inverter (3600D-NS). Can you confirm the following:

  • In your automation I see sensor.p1_meter_active_power. I think in my P1 meter that's called sensor.p1_meter_power (see screenshot below). Because I also see that Goodwe has a sensor called goodwe_meter_active_power, but that's not the one I should use, right?

Note: solar panels are off right now because it's night time, so that's why some sensors are unavailable.

Hi Ton,

Yes, it is the P1 sensor

Great, thanks! Currently trying to set it up but it seems I need to first enable the export limit function on the inverter itself. I think my export limit never worked

As far as I know, the export limit option is already present.

After some test runs, I modified my automation a bit.

I now set the export limit to 8000 W at 16:00, because at that time my household consumption is usually higher than what my PV system can generate. (My PV installation is east-facing, as mentioned before.)
This will also allow the inverter to start up without being restricted by the export limit that was set the previous day.

The export limiter is only active between 10:00 and 15:59 is a test.

alias: GoodWe Export Limiter Nieuw
description: 🔴 Variables alleen zichtbaar in YAML
triggers:
  - at: "16:00:00"
    id: goodwe_stop_export_limit
    trigger: time
  - entity_id:
      - sensor.p1_meter_3c39e72f4cec_active_power
    trigger: state
conditions: []
actions:
  - choose:
      - conditions:
          - condition: trigger
            id:
              - goodwe_stop_export_limit
        sequence:
          - target:
              entity_id: number.grid_export_limit
            data:
              value: 8000
            action: number.set_value
      - conditions:
          - condition: time
            after: "10:00:00"
            before: "15:59:00"
          - condition: numeric_state
            entity_id: sensor.pv_power
            above: 10
          - condition: template
            value_template: "{{ active | bool }}"
        sequence:
          - target:
              entity_id: "{{ limit_entity }}"
            data:
              value: "{{ clamped_limit }}"
            action: number.set_value
variables:
  p1_entity: sensor.p1_meter_3c39e72f4cec_active_power
  pv_entity: sensor.pv_power
  limit_entity: number.grid_export_limit
  target_export: 250
  min_w: 0
  max_w: 4200
  max_step: 250
  deadband: 80
  kp: 0.5
  p1: "{{ states(p1_entity) | float(0) }}"
  pv: "{{ states(pv_entity) | float(0) }}"
  export_now: "{{ -p1 if p1 < 0 else 0 }}"
  error: "{{ target_export - export_now }}"
  active: "{{ (error | abs) > deadband }}"
  step_raw: "{{ (error | float(0)) * kp }}"
  step_limited: |
    {% set s = step_raw | float(0) %} {% if s > max_step %}
      {{ max_step }}
    {% elif s < -max_step %}
      {{ -max_step }}
    {% else %}
      {{ s }}
    {% endif %}
  limit_now: "{{ states(limit_entity) | float(0) }}"
  proposed_limit: |
    {{ limit_now + (step_limited | float(0)) }}
  clamped_limit: |
    {% set p = proposed_limit | float(0) %} {% if p < min_w %}
      {{ min_w }}
    {% elif p > max_w %}
      {{ max_w }}
    {% else %}
      {{ p | round(0) }}
    {% endif %}
mode: restart

Nice! I also have east-facing panels so I implemented your changes as well. Running some tests with it now.

I contacted GoodWe support on how the export limit works and they responded the following (in Dutch):

Als u de terugleverlimiet op 0 zet, blijft uw systeem stroom maken voor eigen gebruik, maar levert het geen extra stroom aan het net terug. De terugleverlimiet van 0 schakelt dus alleen de teruglevering uit, niet de gehele stroomopwekking.

I was under the impression that export limit 0 meant no power at all, but they say that's not true. If they are correct, wouldn't it be better to just set export limit to 0 to prevent exporting to the grid and not care about it at all anymore?

Hi,

Hmm... I tested this and checked my energy results after setting the export limit to 0.
To me, an export limit of 0 means no PV power export at all .
Default, the export limit value in HA is 0 but after changing it, 0 was not an option anymore...

I use the custom card below, which is always accurate in real time.

type: custom:power-flow-card
entities:
  grid: sensor.p1_meter_active_power
  solar: sensor.pv_power
watt_threshold: 1000
kw_decimals: 1
uix:
  style: |
    ha-card {
      background: none;
      box-shadow: none;
      border: none;
    }

These are the results for the day when the export limit was set to 0 :frowning:. Not funny. I noticed the issue at around 18:00, as you can see, and then changed the export limit back to 8000 so I could still generate the last bit of solar energy for the day.

I tried it too and support seems to be wrong in their statement. Export limit 0 means not generating any power at all.

Thanks for sharing your implementation. I have it running now and seems to do the job pretty well!

I disabled the export limit automation for a few days. In that time window I restarted and updated Home Assistant. After checking the export limit of my Goodwe integration after the restarts and update, it was on "0" and my converter was working normally.

Don't know what is going on with the Goodwe export limit regulator of the integration but it looks like;

  1. If you don't change the value (automation turned off) after a restart, the default = 0
  2. If you change the value (automation on), then you can't set it back to 0 because it will turn off the inverter which causing generating no PV power at all

After some creativity and creative stealing, I've made this to prevent delivering power to the grid when the price is between -13 and 0 cents per kWh (so when you have to start paying for delivery to grid), I have a HomeWizard p1 meter, and a GoodWe GW5000‑STD‑20 inverter.
Couple of things:

  • The price may vary when you start paying for delivery to grid, I still need to calculate that for myself.

  • I still need to build in an automation that allows me to charge my car when the price is negative for delivering to the grid, because my charger (Wallbox) can do green charging by only using the solar panels but now they don't see any power as the panels are switched only to what the house is currently using.

I have a template sensor helper (with prices for NextEnergy, this agrees with their prices in the app, I get my prices from ENTSO-e Transparency Platform ) :

{% set raw = state_attr('sensor.day_ahead_prices_average_electricity_price','current_price') %}
{% set p = (raw if raw not in [None, 'unknown', 'unavailable', ''] else 0) | float %}
{% set total = (p * 1.21) + 0.006 + 0.12599 %}

{% if total < -0.13 %}
  zone_3
{% elif total < 0 %}
  zone_2
{% else %}
  zone_1
{% endif %}

An automation to switch the panels to either 100% when in zone 1: price is above 0 cent, or to 0% when in zone 3, price is lower than -13 cent (you make money when using power, so don't produce power at all with the panels)

alias: Energy zone switching
description: ""
triggers:
  - minutes: /1
    trigger: time_pattern
  - entity_id: sensor.energy_zone_2
    trigger: state
actions:
  - choose:
      - conditions:
          - condition: state
            entity_id: sensor.energy_zone_2
            state: zone_1
        sequence:
          - target:
              entity_id: number.goodwe_inverter_grid_export_limit
            data:
              value: 100
            action: number.set_value
          - target:
              entity_id: select.wallbox_mode
            data:
              option: solar
            action: select.select_option
      - conditions:
          - condition: state
            entity_id: sensor.energy_zone_2
            state: zone_2
        sequence: []
      - conditions:
          - condition: state
            entity_id: sensor.energy_zone_2
            state: zone_3
        sequence:
          - target:
              entity_id: number.goodwe_inverter_grid_export_limit
            data:
              value: 0
            action: number.set_value
          - target:
              entity_id: select.wallbox_mode
            data:
              option: grid
            action: select.select_option
mode: single

And lastly, the logic for the inverter itself: it does do hysteresis up to 150W to stop it flipping all the time, it also calculates the need of the house in percentages of current panel output, as the panels are not in full light all the time (so clouds, sunsets, random birdshits, etc. are caught)

alias: GoodWe load-following for zone 2
triggers:
  - seconds: /2
    trigger: time_pattern
conditions:
  - condition: state
    entity_id: sensor.energy_zone_2
    state: zone_2
actions:
  - variables:
      pv: "{{ states('sensor.goodwe_inverter_pv_power') | float(0) }}"
      net: "{{ states('sensor.p1_meter_power') | float(0) }}"
      last_pct: "{{ states('input_number.goodwe_load_target') | float(0) }}"
      hysteresis: 150
  - variables:
      current_pct: "{{ states('number.goodwe_inverter_grid_export_limit') | float(0) }}"
  - variables:
      pv_100: |
        {% if current_pct > 5 and pv > 50 %}
          {{ (pv / (current_pct / 100)) | float }}
        {% elif pv > 50 %}
          {{ pv }}
        {% else %}
          6000
        {% endif %}
  - variables:
      needed_pv: "{{ (pv + net) | float }}"
  - variables:
      target_pct_raw: |
        {% if net | abs < hysteresis %}
          {{ last_pct }}
        {% else %}
          {{ (needed_pv / pv_100 * 100) | float }}
        {% endif %}
  - variables:
      target_pct_stable: |
        {% if pv > 100 and target_pct_raw < 5 %}
          {{ last_pct }}
        {% else %}
          {{ target_pct_raw }}
        {% endif %}
  - variables:
      safe_pct: |
        {% if target_pct_stable < 0 %}
          0
        {% elif target_pct_stable > 100 %}
          100
        {% else %}
          {{ target_pct_stable }}
        {% endif %}
  - target:
      entity_id: input_number.goodwe_load_target
    data:
      value: "{{ safe_pct }}"
    action: input_number.set_value
  - target:
      entity_id: number.goodwe_inverter_grid_export_limit
    data:
      value: "{{ safe_pct }}"
    action: number.set_value
mode: single

with me it runs every 2 seconds. The inverter can handle that as it shifts all the time anyway.

This one is wrong, because it also calculates BTW (vat) etc, and you need the prices without anything, I think it needs to be this:

    {% set raw = state_attr('sensor.day_ahead_prices_average_electricity_price','current_price') %}
    {% set p = (raw if raw not in [None, 'unknown', 'unavailable', ''] else 0) | float %}

    {% if total < -0.13 %}
      zone_3
    {% elif total < 0 %}
      zone_2
    {% else %}
      zone_1
    {% endif %}

I've deleted this bit:


{% set total = (p * 1.21) + 0.006 + 0.12599 %}