A car charging load balancer for Home Assistant tailored to Belgian energy regulation (Capaciteitstarief).
- Introduction
- Features
- Prerequisites
- Installation
- Details
- Charge Modes
- Configuration and Helpers
- Advanced Features
- Future Developments
- Disclaimer
- Troubleshooting
- Contributing
- License
This Home Assistant automation provides intelligent load balancing for EV charging, designed to minimize energy costs and avoid exceeding your maximum power limit (capaciteitspiek) under Belgian energy regulations. By dynamically adjusting the charging phases and current based on your household's power consumption, this system helps you charge your EV efficiently without exceeding a set peak power (capaciteitstarief).
This project is ideal for users with an EV charger that can switch phases and adjust current, such as the Alfen Eve Pro wallbox. When car-aware mode is enabled, the load balancer can also read the car's State of Charge (SOC) to respect per-session charge limits and hardware minimums reported by the car itself.
This is not a fully-fledged Home Assistant integration (yet), but a package that can easily be integrated into your existing Home Assistant setup.
Important
The separate YAML files are deprecated and archived in the archive folder.
graph TD
HA[Home Assistant]
LB[EV Load Balancer Package]
HA -->|Hosts| LB
subgraph Sensors
HS[Net Household Power]
PV[Solar Data]
car[Car SoC]
Prices[Dynamic Prices]
EMS[EMS Control Signal]
end
Sensors -->|Provides Data| LB
LB -->|Calculates Optimal<br>Phase & Current| Integration[Charger Integration]
Integration -->|Communication| Charger[EV Charger]
Charger --> EV
Get up and running in 3 steps:
- Copy Files: Place
packages/ev_loadbalancer.yamlandpackages/ev_loadbalancer_user_config.yamlinto your Home Assistantpackages/directory. (Ensure packages are enabled in yourconfiguration.yaml). - Update Setup: Open
ev_loadbalancer_user_config.yamland replace the placeholder template sensors (e.g.sensor.netto_verbruik_huis_lp,sensor.alfen_eve_real_power_sum) with the actual entity IDs from your installation. - Add Dashboard Controls: Restart Home Assistant. The package will automatically create several UI helpers (like
input_select.ev_load_balancer_charge_modeandinput_number.ev_load_balancer_power_limit). Add these to your Lovelace dashboard to start controlling your charger!
- Dynamically adjusts EV charging based on household power consumption.
- Supports 3-phase electrical installations.
- Car-aware functionality to meet minimum SOC targets by a set time.
- Configurable modes: Off, 1-Phase Minimum, 3-Phases Minimum, Fast, Limited, Solar and Comfort.
- Handles charger efficiency and measurement noise with filtering.
- Phase switching protection to prevent frequent switching between 1 and 3 phases on days with alternating sun and clouds.
- EMS Integration: External control of charging modes based on price/grid signals.
- EV charger integration: Only 1 socket is currently supported.
- Household power consumption sensor excluding charger power consumption.
- For the Alfen Eve Pro
- Active Load Balancing enabled
- Install my fork of the Home Assistant HACS Alfen Wallbox Modbus integration: Alfen Modbus Integration. The original Alfen Modbus Integration has some stability issues and appears to be no longer maintained.
Warning
CRITICAL: Flash Memory Wear on Alfen Eve Do not use the Home Assistant integration Alfen Wallbox. That integration uses register 2129_0 to control output current, which writes to the charger's EEPROM/Flash Memory. Flash memory has a limited number of write cycles (typically ~100,000). Updating this every minute will physically destroy the charger's memory chip within a few months. Use Active Load Balancing instead with Modbus. The Alfen Wallbox integration can still be used for reading data.
Tip
If you can't measure the household power consumption separately, create helpers to calculate the household power by subtracting the charger power from the total power consumption.
Follow the Home Assistant package documentation for installation details. The package files are located in the packages folder. You need to copy both ev_loadbalancer.yaml and ev_loadbalancer_user_config.yaml.
If you copy both yaml files to the root of the packages folder, you can simply activate the package by adding the following code to configuration.yaml.
homeassistant:
packages: !include_dir_named packages/Update packages/ev_loadbalancer_user_config.yaml to your specific setup and check the configuration from the developer YAML section.
The main logic file packages/ev_loadbalancer.yaml should not be modified to allow for easy updates.
If you don't need Car Aware functionality, the settings in the car configuration section can be left at their defaults.
Tip
Use a low-pass filter to smooth noisy household power consumption data. Example configuration:
platform: filter
name: "Netto verbruik huis LP"
unique_id: netto_verbruik_huis_lp
entity_id: sensor.netto_verbruik_huis
filters:
- filter: outlier
window_size: 4
radius: 500.0
- filter: lowpass
time_constant: 12
precision: 2Here, sensor.netto_verbruik_huis is the raw household power consumption, and netto_verbruik_huis_lp is the filtered value used by the load balancer.
Tip
For PV-aware charging, use a low-pass filter to prevent excessive switching caused by cloud coverage. Example configuration:
platform: filter
name: "PV Power LP"
unique_id: pv_power_lp
entity_id: sensor.sma_power_w
filters:
- filter: outlier
window_size: 3
radius: 1000.0
- filter: lowpass
time_constant: 5
precision: 0The script to set the charger parameters currently supports the Alfen Eve Pro Single charger. Update the script outputs according to your charger.
Note
The charger connection states are based on the IEC-61851 standard. If your charger is not compliant with this standard, you need to update the state mapping.
Restart Home Assistant.
Set the helpers that are now available in the UI to the desired values.
This load balancer checks every 10 seconds the current household power consumption and sets the charger output parameters, phase and current, according to the remaining available power. The total allowed power to use (capaciteitspiek), household + EV charger, is defined in an input helper parameter. The load balancer also takes charger efficiency into account by comparing the calculated power output with the actual power output.
Note
The maximum current can still be limited by the car's own on-board charger settings, which are respected when car_aware is enabled.
Here, during charging, the power is kept stable around 6000W despite major changes in household power consumption. At 18h, the car was disconnected for a while. The spikes are measurement errors.
If there is not enough power to charge at 3 phases at minimum current (6A), the charger switches to 1 phase. When the remaining power is not enough to reach even 1 phase at 6A, charging stops by setting the maximum socket current to 0A. There is a risk that the car is not charged for a prolonged period if household power consumption remains high. See Frequent Phase Switching Protection for how rapid switching is mitigated.
Note
There is a built in dynamic delay in the script when the charger parameters are changed. There will be no update sent to the charger until the setting is updated or a time-out in the script occurs.
When the charger is disconnected, the charger phases and current are set to a default value. This way you shouldn't end up with a charger that is set to 0A when Home Assistant is not available.
Warning
There is still a risk if Home Assistant becomes unavailable during charging with the charger set at 0A. In that case you need to configure the charger directly via the Eve Connect app or the ACE Service Installer. Check your charger's manufacturer manual.
The available charge modes dictate how the car charges based on solar availability, pricing, and optional EMS signals.
| Mode | Description |
|---|---|
| Off | Charging disabled. |
| 1-Phase Minimum | Fixed single-phase charging at minimum current (e.g. 6A = ~1.4 kW). Not affected by grid/EMS constraints. |
| 3-Phases Minimum | Fixed three-phase charging at minimum current (e.g. 6A = ~4.1 kW). Not affected by grid/EMS constraints. |
| Fast | Full speed charging at maximum rated current. EMS can block grid usage, forcing solar-only charging if active. |
| Limited | Dynamic power limiting based on household consumption up to power_limit. EMS signal is used to cap or block grid usage. |
| Solar | Charges only on solar surplus. Grid is never used, regardless of EMS or price. |
| Comfort | Hybrid mode: behaves as Limited while SOC is below comfort_soc, then switches to Solar once the minimum SOC is reached. |
The system executes the following checks every 10 seconds:
flowchart TD
Start([Execute every 10s]) --> Emergency{Is Car SOC < Emergency SOC?}
Emergency -- Yes --> MaxLimit[Bypass all constraints. Charge up to Power Limit]
Emergency -- No --> Target{Is car_aware and SOC >= Target SOC?}
Target -- Yes --> StopCharge[Stop Charging]
Target -- No --> Price{Is Power Price <= Max Cost?}
Price -- No --> Block[Block Grid. Solar Surplus Only]
Price -- Yes --> EMS{Is EMS Active?}
EMS -- Yes --> EMSGating[Apply EMS Budget / Signal Gating]
EMS -- No --> ModeCheck
EMSGating --> ModeCheck{Which Mode?}
ModeCheck -- Off/Blocked --> MOff[0 Amps]
ModeCheck -- Fixed Modes --> MFixed[Set fixed Phase/Amps]
ModeCheck -- Solar Only --> MSolar[Calculate Amps based purely on PV Surplus]
ModeCheck -- Limited/Fast --> MLimit[Calculate Available Power = Limit - House + PV]
MOff --> SetCharger([Send Modbus Updates])
MFixed --> SetCharger
MSolar --> SetCharger
MLimit --> SetCharger
How modes interact with PV Priority and EMS signals:
| Mode | PV Prio | EMS Control | EMS Signal | Resulting Behavior |
|---|---|---|---|---|
| Solar | Any | Any | Any | Solar Only: Charges strictly on solar surplus. Grid is never used. |
| Fast | Any | OFF | - | Max Power: Charges at maximum capacity (e.g. 11kW). |
| ON | ON (>0W) | Max Power: EMS Budget is ignored (treated as binary "Go"). | ||
| ON | OFF (0W) | Solar Only: Grid blocked by EMS. Charges only if solar surplus exists. | ||
| Limited | OFF | OFF | - | Max Grid: Charges up to power_limit + Solar Surplus. |
| ON | ON (>0W) | Optimized Grid: • Budget Mode: Grid limit = ems_signal.• On/Off Mode: Grid limit = power_limit.Solar surplus is added on top of this limit (Turbo). |
||
| ON | OFF (0W) | Solar Only: Grid blocked. Charges only on solar surplus. | ||
| Limited | ON | Any | Any | Solar Priority: • Sun > 0: Follows Solar Only behavior (ignores Grid/EMS). • No Sun: Follows standard Limited behavior (see above). |
| Comfort | Any | Any | Any | Hybrid: • SOC < comfort_soc: Behaves like Limited (Ensures charge). • SOC ≥ comfort_soc: Behaves like Solar (Saves money). |
- EMS Signal: Define
ems_signalinev_loadbalancer_user_config.yaml. A value of0blocks grid usage. - Control Toggle: Turn
input_boolean.ev_load_balancer_ems_controlON to enable EMS gating. - Mode Toggle (Optional):
input_boolean.ev_load_balancer_ems_as_onoff(false= Budget Mode,true= Binary on/off Mode).
Configuration is done in packages/ev_loadbalancer_user_config.yaml. Each logical "device" is represented as a template sensor whose attributes hold the settings. This allows the core logic file to reference a clean, stable interface regardless of your specific sensor names.
Tip
Once the monthly peak consumption passes the set power limit of the load balancer, you can increase this limit to the new monthly peak via an automation. Don't forget to reset it at the beginning of the month.
The state of this sensor is the active charge mode, driven by input_select.ev_load_balancer_charge_mode.
These attributes are wired to input_* helpers that the package defines. They are ready to use out of the box — just set the desired values in the Home Assistant UI. No changes are needed in ev_loadbalancer_user_config.yaml for these.
| Attribute | Helper entity | Unit | Description |
|---|---|---|---|
power_limit |
input_number.ev_load_balancer_power_limit |
W | Maximum total power (household + charging) allowed. |
car_aware |
input_boolean.ev_load_balancer_car_aware |
bool | Enable car-aware mode. When enabled, the car's SOC and current limits are respected. |
pv_prioritized |
input_boolean.ev_load_balancer_pv_prioritized |
bool | Solar-first priority for Limited mode. |
pv_prio_threshold |
input_number.ev_load_balancer_pv_prio_threshold |
W | Threshold for solar-first priority. The amount of power the can be added with grid power to fill the gap between 0W and the minimum required power to charge. This prevents going 1000W or more solar going to waste. |
single_phase_only |
input_boolean.ev_load_balancer_single_phase_only |
bool | Force all modes to single-phase. |
ems_control |
input_boolean.ev_load_balancer_ems_control |
bool | Master switch to activate EMS gating. |
ems_as_onoff |
input_boolean.ev_load_balancer_ems_as_onoff |
bool | false = Budget mode; true = Binary on/off mode. |
max_cost_rate |
input_number.ev_max_charging_cost |
€/kWh | Maximum electricity price at which grid charging is allowed. |
emergency_soc |
input_number.ev_load_balancer_emergency_soc |
% | SOC floor — below this, all constraints (EMS, price, solar) are bypassed. Default 20%. |
target_soc |
input_number.ev_load_balancer_target_soc |
% | (car_aware only) Target SOC ceiling — charging stops when this SOC is reached. Emergency SOC floor still overrides. Default 80%. |
comfort_soc |
input_number.ev_load_balancer_comfort_soc |
% | Comfort mode minimum SOC. Below this, Comfort acts as Limited; above, it switches to Solar. |
Note
target_soc and comfort_soc are optional helpers. target_soc can be removed if car-aware mode is not used. comfort_soc can be removed if Comfort mode is not used.
These attributes must be set in ev_loadbalancer_user_config.yaml to match your specific installation.
| Attribute | Unit | Description |
|---|---|---|
power_update_threshold |
W | [Optional] Minimum power change before updating the charger. Prevents excessive updates. Defaults to 230 W. |
phase_switch_delay |
min | [Optional] Cooldown after switching 3→1 phase before allowing switch back. Defaults to 5 min. |
ems_signal |
W | [Optional] EMS power budget in Watts. Point to a sensor such as an EMHASS deferrable output. 0 blocks the grid. |
electricity_price |
€/kWh | [Optional] Current electricity price sensor. Used with max_cost_rate to block grid charging when expensive. Omit or set to 0 to disable. |
The state of this sensor is a descriptive name for your charger (e.g. "Alfen Eve Pro Single").
| Attribute | Unit | Type | Description |
|---|---|---|---|
active_power |
W | Sensor | Actual measured power output of the charger. Used for efficiency calculation. |
connection_state |
— | Sensor | Connection state of the charger. Must resolve to "Disconnected", "Connected", or "Error". |
current_input |
A | Sensor | Currently applied charging current, as reported by the charger. |
current_output |
— | Output entity | Entity ID of the number entity used to set the charger current. |
phases_input |
— | Sensor | Currently active phase setting, as reported by the charger. |
phases_output |
— | Output entity | Entity ID of the select entity used to set the charger phase. |
default_current |
A | Parameter | Current to reset to when the car disconnects (e.g. 7). |
default_phases |
— | Parameter | Phase count to reset to when the car disconnects (e.g. 1). |
max_current |
A | Parameter/Sensor | Maximum charging current supported by the charger. Can be a fixed value or a sensor. |
min_current |
A | Parameter | Minimum charging current for the charger (typically 6 A). |
nominal_voltage |
V | Parameter | Nominal phase voltage (typically 230 V). |
phase_1_state |
— | Parameter | String value representing the 1-phase state on your charger. Default: "1 Phase". |
phase_3_state |
— | Parameter | String value representing the 3-phase state on your charger. Default: "3 Phases". |
Important
current_output and phases_output are entity IDs (plain strings, not templated sensor values). The script uses states(entity_id) to read them and number.set_value / select.select_option to write to them.
The state of this sensor is the current household power consumption (W). Filtered/smoothed values are strongly recommended.
| Attribute | Unit | Type | Description |
|---|---|---|---|
pv_power |
W | Sensor | [Optional] Current PV generation. A negative household_power (i.e. solar surplus) is used directly; this attribute is informational. |
Note
The household power sensor should represent net household consumption — positive when consuming from the grid, negative when exporting solar surplus. The charger's own power consumption must be excluded.
Car configuration is optional and only needed when car_aware is enabled. The state of this sensor is a descriptive name for your car (e.g. "BMW iX3").
| Attribute | Unit | Type | Description |
|---|---|---|---|
max_current |
A | Parameter | Maximum charging current supported by the car's on-board charger. |
min_current |
A | Parameter | Minimum charging current accepted by the car. |
battery_capacity_wh |
Wh | Parameter | Usable battery capacity of the car. |
battery_percentage |
% | Sensor | Current State of Charge (SOC) of the car battery. |
Note
If any of these sensors are unavailable, the system falls back to car_aware: false and uses charger limits only.
| Attribute | Helper | Scope | Priority | Purpose |
|---|---|---|---|---|
emergency_soc |
input_number.ev_load_balancer_emergency_soc |
All modes | Highest | Safety floor — bypasses all constraints (EMS, price, solar). Charges at power_limit. |
target_soc |
input_number.ev_load_balancer_target_soc |
All modes (car_aware only) | High | Charging ceiling — stops all charging (including solar surplus) once reached. Emergency SOC overrides this. |
comfort_soc |
input_number.ev_load_balancer_comfort_soc |
Comfort mode only | Normal | Minimum SOC for Comfort mode. Below → Limited behaviour. Above → Solar behaviour. |
Note
The price guard (electricity_price vs max_cost_rate) is bypassed when SOC is below emergency_soc. target_soc only takes effect when car_aware is enabled and the car's SOC sensors are available and valid.
Once configured, you can add the generated helpers directly to an entities card in your Lovelace dashboard:
type: entities
title: EV Charging Control
entities:
- entity: input_select.ev_load_balancer_charge_mode
name: Charge Mode
- entity: input_number.ev_load_balancer_power_limit
name: Grid Peak Limit (W)
- entity: input_boolean.ev_load_balancer_car_aware
name: Car Aware
- entity: input_number.ev_load_balancer_target_soc
name: Target SOC %
- entity: input_boolean.ev_load_balancer_pv_prioritized
name: PV Priority Mode
- entity: input_number.ev_load_balancer_comfort_soc
name: Comfort SOC %
- entity: input_number.ev_load_balancer_emergency_soc
name: Emergency/Min SOC %
- entity: input_boolean.ev_load_balancer_ems_control
name: EMS External Control
- entity: input_number.ev_max_charging_cost
name: Max Cost rate (€/kWh)pv_prioritizedis only applicable to Limited mode. When enabled, the car charges purely on solar surplus if available. If solar is insufficient, grid power fills up topower_limit. This is useful to maximize self-consumption while guaranteeing the car is charged.- With Solar charging, only remaining solar power is used. If this is not enough to charge the car, charging stops. Useful when the car only needs a small top-up or is connected for an extended period.
- In Comfort mode, the system behaves as Limited when the current SOC is below
comfort_soc, and as Solar once it exceeds it. This is not the same as Limited withpv_prioritizedenabled. In Comfort, charging stops once the minimum SOC is reached, while in Limited it continues until the car is fully charged.
The system accounts for charger efficiency in all power calculations, by comparing the theoretical output with the real output:
- Available power is adjusted using measured charger efficiency
- Phase selection considers efficiency losses
- Current calculations include efficiency compensation
- Efficiency is calculated dynamically based on actual power measurements
- Fallback to 100% efficiency when no valid measurements are available
When car-aware mode is enabled (car_aware: true), the system reads battery_percentage and battery_capacity_wh from sensor.ev_load_balancer_car. If either is unavailable the system falls back to car_aware: false.
Car-aware mode affects two things:
- Current limits: the minimum of the car's and the charger's min/max current is used.
- Target SOC: charging stops automatically once
current_soc >= target_soc. Theemergency_socfloor still overrides this — charging resumes if SOC drops below it.
The load balancer can be configured to operate in single-phase mode only:
- Toggle
Single Phase Onlyin the configuration to force single phase operation - When enabled:
- All modes will operate in single phase regardless of power availability
- Fast mode will still use maximum current but only on a single phase (equivalent to 3-Phases Minimum with max current)
- Limited and Solar modes will calculate optimal current for single phase
- Use this option if:
- Your installation only supports single-phase charging
- You want to minimize the impact on phase balancing
- You prefer consistent single-phase operation
The load balancer prevents rapid switching between 1 and 3 phases in dynamic modes (Limited, Solar, Comfort):
- When switching from 3 phases to 1 phase, a timer is started (duration set by
phase_switch_delay, default 5 minutes). - During this period the charger will not switch back to 3 phases even if more power becomes available; current utilization on 1 phase is maximized instead.
- This protection does not apply to manual mode changes (e.g. switching to "1-Phase Minimum" or "3-Phases Minimum").
When the charger upgrades from 1-phase to 3-phase charging, the sudden power jump can take a moment to register uniformly across the household and charger power sensors. To prevent the load balancer from reacting to this temporary data miscalculation and inappropriately throttling power, a 40-second grace period timer (timer.ev_load_balancer_sensor_grace_period) is automatically triggered upon the phase change. During this brief window, balancing automations are paused to allow all sensors to catch up to a steady state.
If any required sensor or attribute for the selected charge mode is unavailable, unknown, none, or non-numeric, the automation will:
- Log an error to Home Assistant's system log:
[EV Load Balancer] Base sensors unavailable or invalid - fallback to default charger values. - Set the charger to its default current and phase, skipping all further logic.
- Autocalculate charger efficiency.
- Make car awareness optional.
- Option to prioritize PV consumption.
- Phase switching protection.
- Optimize for dynamic energy contracts (EMS Integration).
- Provide as a generic Home Assistant package.
- Option to limit to 1 phase only.
- Target SOC: stop charging when car-aware and SOC reached.
- Implement a minimum charge power instead of switching off the charger.
- Convert to a full Home Assistant integration.
The use of this automation is at your own risk. The author assumes no responsibility for any consequences arising from its use, including power consumption, vehicle SOC, or damages. Test thoroughly in your environment before relying on it for critical operations.
-
Missing or Invalid Sensor Data
- If any required sensor becomes unavailable, the charger falls back to default values.
- Check Home Assistant logs for
[EV Load Balancer] Base sensors unavailablemessages. - Verify all required sensors are properly configured and responding.
-
Phase Switching Issues
- The timer prevents rapid phase switching.
- Check if the phase switching timer (
timer.ev_load_balancer_phase_switching_timer) is active. - Verify charger's phase switching capability.
-
Car Awareness Not Working
- Ensure
car_awareis enabled (input_boolean.ev_load_balancer_car_awareis ON). - Verify all car-related sensors (
battery_percentage,battery_capacity_wh) are available and providing valid data. - Check the Developer Tools > States page for
sensor.ev_load_balancer_carand inspect its attributes.
- Ensure
-
Target SOC Not Stopping Charging
- Ensure
car_awareis enabled —target_sochas no effect without it. - Check that
sensor.ev_load_balancer_carattributebattery_percentageis resolving to a valid integer. - Verify
input_number.ev_load_balancer_target_socis set to the desired value in the UI. - Charging will resume if SOC falls below
emergency_soc, by design.
- Ensure
-
EMS Not Having Any Effect
- Verify
input_boolean.ev_load_balancer_ems_controlis turned ON. - Confirm
ems_signalin the user config is resolving to a numeric float value (check with Developer Tools > Template). - EMS only affects Limited, Comfort, and Fast modes; Solar mode always ignores EMS.
- Verify
To enable automation trace logging for the load balancer automation, enable trace storage in the automation settings (default 90 traces are stored). You can also check the Home Assistant log for [EV Load Balancer] and [Pkg] prefixed messages.
To enable general Home Assistant debug logging, add the following to your configuration.yaml:
logger:
default: info
logs:
homeassistant.components.automation: debugContributions are welcome! Please feel free to submit a Pull Request. For major changes:
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.