Which way to automate simple load-balancing (car charging with solar energy)?

Hi there,

I am new to Home Assistant and I love it so far. I have integrated easily many sensors and devices in my home. Now that I can read the values from my photovoltaic system and control the car charging parameters (mainly the max current), I want to integrate both to start, stop, increase and decrease car charging depending on the power available.

I started to do that using simple automations, that run every minute, and does exactly that, e.g. start, stop, increase, decrease, depending on the values. For instance:

alias: Increase current
description: "Increase the charging current of the car if more power is available"
triggers:
  - trigger: time_pattern
    minutes: "*"
conditions:
  - condition: numeric_state
    entity_id: number.charger_max_current
    below: 15
  - condition: numeric_state
    entity_id: sensor.grid_power
    above: 800
actions:
  - action: number.set_value
    metadata: {}
    data:
      value: "{{ states('number.charger_max_current')|int(0) + 1 }}"
    target:
      entity_id: number.charger_max_current
mode: single

I am confident I can get something working this way, but it does not feel satisfying or elegant. It is very verbose and redundant, and I fear strange side-effects at runtime since all automations run at the same time. I am looking for alternative approaches. Ideally, I also want additional controls like “Managed / Unmanaged by HA”, strategies: “Reduce charging speed / Reduce grid consumption / Quick charge” that I can use in the UI later.

The first question is if I need to reinvent the wheel. May be there any generic solution for that in HA?

If not, I could use the Python integration (like here). Or I could create a custom_component. Do you have recommendations? Are there other options?

what car charging are you using?

theres a lot of integration for that there’s no need to reinvent the wheel

Ohme
V2C
Peblar

evcc HA integration
SLX Charging Controller

blueprint

node-red

It is a go-e Charger. Actually it has a PV function that I need to try out. I will do that.

Still, independently of this specific case, I am still interested in the original question, e.g. what are the design options for complex automations. Also if there is a generic approach for power load balancing, e.g. between a wall-box, a boiler for hot-water and other power-hungry equipment that can be time-shifted.

not sure if this can help you

1 Like

Thanks! I use the MQTT integration. This section of the documentation explains how to send the PV surplus over MQTT to the charger. In my case:

alias: go-e Surplus Charging
description: Update values needed for using solar surplus with go-e Chargers
triggers:
  - seconds: /5
    trigger: time_pattern
conditions: []
actions:
  - data:
      qos: "0"
      topic: go-eCharger/2123456/ids/set
      payload: "{\"pGrid\": {{ states(\"sensor.my_grid_power\") }}, \"pAkku\":0.0, \"pPv\":0.0}"
      retain: false
    action: mqtt.publish

Then I can use the app of the manufacturer to enable the “eco” mode. This way the charger handles the load balancing, controlling the power and the number of phases used. It makes it very easy and robust.

Hi,
I tried to use this automation again with my go-eCharger and my balcony PV system Anker Solix.
The go-eCharger App reacts and activates to eco mode, but the power send to the car is always 1.3 kW (lowest value I can set manually…).
Is there a way to reduce this value to an even lower value?
My house consumes ~350 W constantly and the PV sends 800 W. So, I would like to send only the difference of ~450 W to the car…
Thanks!

This is not a limitation of the charger but of the standards. The minimum charging current is 6A. See here for some explanation.
The minimum power is even higher with 3 phases, it is around 4,5 kW. If the charger does not allow to reduce the number of phases per software, it is possible to use a cable with a single phase to force it.

Just to say that it is not always easy to charge a car slowly :smiley:

Hi,

I’m not sure if this helps or if it’s the best or simplest approach, but I’ll share how I’ve handled a similar setup using a Solax EV charger.


To keep everything organized and maintainable, I use a folder structure for my configuration files:

configuration.yaml

homeassistant:
  packages: !include_dir_named includes

This allows breaking configurations into smaller, more readable parts:


In the main automation YAML, I created a state machine to control the EV charger. It evaluates various binary sensors to determine the current operation mode.

template:
  - sensor:
      - name: evc_operation_mode
        icon: mdi:state-machine
        state: >
          {% set ns = namespace(result='Standby') %}
          {% set sensor_modes = [
            ('binary_sensor.evc_mode_disabled', 'Disabled'),
            ('binary_sensor.evc_mode_manual_charge', 'Charge_Manual'),
            ('binary_sensor.evc_mode_solar_charge', 'Charge_From_Solar'),
            ('binary_sensor.evc_mode_spot_charge', 'Charge_Spot'),
            ('binary_sensor.evc_mode_scheduled_charge', 'Charge_Scheduled')
          ] %}

          {% for sensor, mode in sensor_modes %}
            {% if mode == 'Disabled' %}
              {% set sensor_state = states(sensor) | bool(default=true) %}
            {% else %}
              {% set sensor_state = states(sensor) | bool(default=false) %}
            {% endif %}

            {% if sensor_state %}
              {% set ns.result = mode %}
              {% break %}
            {% endif %}
          {% endfor %}
          {{ ns.result }}

script:
  evc_select_operation_mode:
    alias: "Select and run EVC automation mode"
    sequence:
      - variables:
          mode: "{{ states('sensor.evc_operation_mode') }}"
      - choose:
          - conditions: "{{ mode == 'Disabled' }}"
            sequence:
              - service: script.evc_reset
          - conditions: "{{ mode in ['Charge_Manual', 'Charge_From_Solar', 'Charge_Scheduled'] }}"
            sequence:
              - service: script.evc_start_charge
          - conditions: "{{ mode == 'Charge_Spot' }}"
            sequence:
              - service: script.evc_set_max_charge_current
              - service: script.evc_start_charge
        default:
          - service: script.evc_reset

Each mode is driven by a binary sensor. Here’s an example for planned charging, which activates based on dashboard inputs and conditions.

template:
  - binary_sensor:
    # EVC Automation Mode - Scheduled Charging
    - name: evc_mode_scheduled_charge
      state: >
        {% set scheduled = states('input_boolean.evc_scheduled_enabled') | bool(default=false) %}
        {% set connected = states('binary_sensor.evc_connected') | bool(default=false) %}

        {% set time_check_enabled = states('binary_sensor.evc_sched_time_check_enabled') | bool(default=false) %}
        {% set time_ok = states('binary_sensor.evc_sched_time_ok') | bool(default=false) %}

        {% set energy_check_enabled = states('binary_sensor.evc_sched_energy_check_enabled') | bool(default=false) %}
        {% set energy_ok = states('binary_sensor.evc_sched_energy_ok') | bool(default=false) %}

        {% set time_valid = time_ok if time_check_enabled else false %}
        {% set energy_valid = energy_ok if energy_check_enabled else false %}

        {{ 
          connected and
          scheduled and
          time_valid and
          energy_valid
        }}

    # Time condition for scheduled charging (active within time window)
    - name: evc_sched_time_ok
      state: >
        {% set start = states('input_datetime.evc_sched_start') %}
        {% set end = states('input_datetime.evc_sched_end') %}
        {% set now = now().strftime('%H:%M:%S') %}

        {{
          (start <= now < end) or
          (start > end and (now >= start or now < end))
        }}

    # Energy condition for scheduled charging (not yet fully charged)
    - name: evc_sched_energy_ok
      state: >
        {% set target = states('input_number.evc_sched_target_energy') | int(default=0) %}
        {% set current = states('sensor.evc_energy_charged') | int(default=0) %}

        {{ current < target }}

    # Is scheduled time condition enabled
    - name: evc_sched_time_check_enabled
      state: >
        {% set start = states('input_datetime.evc_sched_start') %}
        {% set end = states('input_datetime.evc_sched_end') %}

        {{ start != end }}

    # Is scheduled energy condition enabled
    - name: evc_sched_energy_check_enabled
      state: >
        {% set target = states('input_number.evc_sched_target_energy') | int(default=0) %}

        {{ target != 0 }}

My control dashboard lets me toggle modes and conditions:

Through which I manage actually manage following entities, available from the integration: