-
Notifications
You must be signed in to change notification settings - Fork 1
Zero Export and Export Limiting
Automations that cap what the inverter produces, from a fixed percentage to a control loop that holds the grid connection at zero. All of them use the export controls, which are a beta and off by default. Read Battery and export control first; it lists the entities, explains the revert timer, and says what can go wrong. This page assumes you have.
The export limit caps the inverter's output, not the flow at the grid connection. A limit of 0 % means the inverter produces nothing at all, and your house draws everything from the grid. Zero feed-in while still using your own production needs a control loop that reads a grid meter and moves the limit up and down. That loop is the third recipe below.
Feed-in limits may be regulated where you live. A permanent cap that your grid operator requires is usually configured by the installer in the inverter itself, and what you set from Home Assistant comes on top.
Placeholders. Entity names and IDs explains how to find yours. Whether you get the block 123 or the block 704 entities depends on your inverter; the names are the same.
| Placeholder | What it is |
|---|---|
number.inverter_export_limit |
Export limit in percent of the inverter's WMax
|
switch.inverter_export_limit_enabled |
The limit only applies while this is on |
number.inverter_export_limit_revert_time |
Seconds until the inverter drops the limit on its own |
number.inverter_active_power_setpoint |
Block 704 only: the limit in watts |
switch.inverter_active_power_setpoint_enabled |
Block 704 only |
select.inverter_active_power_setpoint_mode |
Block 704 only, watts or w_max_pct
|
sensor.grid_meter_ac_power |
Power at the grid connection, positive = import |
And the sunspec2.set_export_limit action, which writes the
percentage and the enable flag together. It needs the config entry id
of the inverter. Build the action once in the visual automation
editor, pick the inverter from the dropdown, switch to Edit in YAML,
and copy the id from there.
Suppose you want the inverter never to produce more than 70 % of its rating. Two ways, and the choice is about what happens when Home Assistant is down.
With the inverter's timeout switched off. Set Export limit revert time to 0, set Export limit to 70, switch Export limit enabled
on. Done, and it survives a Home Assistant outage, because nothing
has to keep it alive. Not every inverter accepts 0 as "no timeout";
if yours reverts anyway, use the second way.
With a keepalive. The revert timer is a dead-man switch: the inverter honours the limit for that many seconds and then lets go, so a controller that died does not leave it throttled forever. Keep the timer, and re-write the limit more often than it expires:
input_number:
export_limit_pct:
name: Export limit
min: 0
max: 100
step: 1
unit_of_measurement: "%"
initial: 70
input_boolean:
export_limit_active:
name: Export limit activeSet Export limit revert time to 120 once. Then:
alias: Export limit keepalive
description: >
Re-writes the limit every 15 s. The inverter drops it by itself
120 s after the last write, so a stopped Home Assistant means an
unlimited inverter, not a stuck one.
mode: single
triggers:
- trigger: time_pattern
seconds: "/15"
conditions:
- condition: state
entity_id: input_boolean.export_limit_active
state: "on"
actions:
- action: sunspec2.set_export_limit
data:
config_entry_id: 0123456789abcdef0123456789abcdef
percent: "{{ states('input_number.export_limit_pct') | float(100) }}"
enable: trueAnd one automation to switch it off cleanly rather than waiting for the lapse:
alias: Export limit off
triggers:
- trigger: state
entity_id: input_boolean.export_limit_active
to: "off"
actions:
- action: switch.turn_off
target:
entity_id: switch.inverter_export_limit_enabledWhy the action rather than the Number entity: the action writes the percentage and the enable flag in one operation. On a Fronius the new value only takes effect once the enable flag goes from off to on again, and the Number entity alone never touches it. The integration option Re-apply the export limit and power factor by switching them off and on when their value changes does that cycle for every write, including through the Number entity; it defaults on for the Symo/Symo Hybrid generation and off for GEN24, see Vendor notes.
With a dynamic tariff there are hours in which feeding in costs money. If in those hours you would rather produce nothing at all, drive the helpers from recipe 1:
alias: Curtail at negative prices
triggers:
- trigger: numeric_state
entity_id: sensor.electricity_price
below: 0
id: negative
- trigger: numeric_state
entity_id: sensor.electricity_price
above: 0
id: positive
actions:
- choose:
- conditions:
- condition: trigger
id: negative
sequence:
- action: input_number.set_value
target:
entity_id: input_number.export_limit_pct
data:
value: 0
- action: input_boolean.turn_on
target:
entity_id: input_boolean.export_limit_active
- conditions:
- condition: trigger
id: positive
sequence:
- action: input_boolean.turn_off
target:
entity_id: input_boolean.export_limit_activesensor.electricity_price stands for whatever your tariff integration
provides. If you want to keep using your own production during those
hours and only stop the feed-in, run recipe 3 instead and switch it on
and off from the price.
A control loop. Every 10 s it reads the grid power, compares it with a small target import, and nudges the limit. Exporting more than the target lowers the limit, importing raises it, and the limit stays between 0 and 100.
It needs the inverter's rated power in watts to turn a watt error into a percentage step. Block 120 has it, but the block is not polled by default and its sensor starts disabled, so an input helper is the simpler source:
input_number:
inverter_nameplate_w:
name: Inverter rated power
min: 500
max: 100000
step: 100
unit_of_measurement: W
initial: 8000
zero_export_target_w:
name: Zero export target
min: -500
max: 500
step: 10
unit_of_measurement: W
initial: 50
input_boolean:
zero_export_active:
name: Zero export activeA positive target means "import a little", which keeps the loop off
the export side while the meter and the inverter disagree by a few
watts. Set Export limit revert time to 60 once, so a stopped loop
frees the inverter within a minute.
alias: Zero export control loop
mode: single
triggers:
- trigger: time_pattern
seconds: "/10"
conditions:
- condition: state
entity_id: input_boolean.zero_export_active
state: "on"
- condition: template
value_template: >
{{ has_value('sensor.grid_meter_ac_power')
and has_value('number.inverter_export_limit') }}
variables:
grid_w: "{{ states('sensor.grid_meter_ac_power') | float(0) }}"
target_w: "{{ states('input_number.zero_export_target_w') | float(50) }}"
nameplate_w: "{{ states('input_number.inverter_nameplate_w') | float(8000) }}"
current_pct: "{{ states('number.inverter_export_limit') | float(100) }}"
gain: 0.5
step_pct: "{{ (grid_w - target_w) / nameplate_w * 100 * gain }}"
new_pct: "{{ [0, [100, current_pct + step_pct] | min] | max | round(1) }}"
actions:
- action: sunspec2.set_export_limit
data:
config_entry_id: 0123456789abcdef0123456789abcdef
percent: "{{ new_pct }}"
enable: trueTuning:
- Gain 0.5 takes half the error per step. Oscillation means too much, a slow crawl towards zero means too little. Inverters ramp their output over a few seconds, so a gain above 1 fights the ramp.
- The poll interval of the meter sets the real speed. A meter read by this integration every 30 s makes a 10 s loop pointless; either poll the meter's config entry at 5 s, or read the meter through something faster.
-
Smooth the import side. A dishwasher heater switching on for
two seconds should not open the limit fully. Feed the meter through
Home Assistant's
filterplatform with a low-pass and use the filtered value for raising the limit and the raw value for lowering it. That asymmetry is what a KACO owner in #17 has run for two years, before the beta existed, through a Modbus proxy.
While the loop runs, block 123 reads back whatever was last written,
so the Export limit entity is not evidence that the limit is in
force. The grid meter is. On block 704 the sensor with sunspec_key
WMaxLimPctRvrtRem counts down to the lapse and is worth a card.
If your inverter has block 704 you get an absolute setpoint. The loop becomes simpler because the nameplate drops out:
variables:
grid_w: "{{ states('sensor.grid_meter_ac_power') | float(0) }}"
target_w: "{{ states('input_number.zero_export_target_w') | float(50) }}"
current_w: "{{ states('number.inverter_active_power_setpoint') | float(0) }}"
nameplate_w: "{{ states('input_number.inverter_nameplate_w') | float(8000) }}"
gain: 0.5
new_w: "{{ [0, [nameplate_w, current_w + (grid_w - target_w) * gain] | min] | max | round(0) }}"
actions:
- action: select.select_option
target:
entity_id: select.inverter_active_power_setpoint_mode
data:
option: watts
- action: number.set_value
target:
entity_id: number.inverter_active_power_setpoint
data:
value: "{{ new_w }}"
- action: switch.turn_on
target:
entity_id: switch.inverter_active_power_setpoint_enabledThe mode select starts disabled; enable it once in the entity
settings. The watt setpoint's own revert timer is not exposed as a
control, so watch the WSetRvrtTms and WSetRvrtRem sensors to see
what your device does with it.
Nobody has confirmed the watt setpoint on real hardware yet. The percent limit on block 704 is confirmed on a KACO. If you run the watt path, a line in #17 with the result is what everyone after you needs.
Before you rely on any of this, stop Home Assistant for two minutes on a sunny day and watch the inverter. It should return to full output within the revert time. If it does not, the timeout is off or your inverter ignores it, and a Home Assistant outage would then leave the inverter throttled until you notice.
Recipes
- Energy dashboard and statistics
- Zero export and export limiting
- Battery control
- Alerts and notifications
- Dashboard cards
- n8n workflows
- Node-RED workflows
- Sharing the inverter
Reference
- SunSpec models explained
- Entity names and IDs
- Diagnostics file reference
- Vendor notes
- Hardware reports
- FAQ
Under the hood
In the repository