DIY Solar EV Charger

I have just finished building the hardware for my solar EV charger. I now need some advice on how to structure the YAML code for the automation. Sadly software is not my forte. In return I am happy to share the hardware plans for the charger if you want to recreate an Eddi on the cheap.

In brief the charger consists of 3 sonoff minis which have been modified to act as a volt free relays which switch in resistors. Each has a different resistance value which sets an input voltage on the Viridian controller. So if all 3 sonoffs are on (default state) the resistance is very low and the charger is paused. If relay 3 turns off the charger will output 1.4kW, if i further turn off relay 2 output goes to 2kW and with relay 1 off it goes to 3kW.

What I am trying to write is the code that monitors my grid export power and follows this by switching on and off relays.

Ages ago I wrote some code for a simple solar water heater which I am using as my starting point:

- id: Solar car charger
  alias: Solar car charger
  trigger:
  - platform: numeric_state
    entity_id: sensor.grid_export_power
    above: 1600
  action:
  - service: switch.turn_off
    data:
      entity_id: switch.charger_3
    entity_id: switch.charger_3
  - wait_for_trigger:
    - platform: numeric_state
      entity_id: sensor.grid_export_power
      below: 1400
  - service: switch.turn_on
    data:
      entity_id: switch.charger_3
    entity_id: switch.charger_3
  initial_state: 'on'
  mode: single

How do I turn this into the “ladder” that follows the grid export and keeps switching realys on and off endlessly to keep my export roughly zero?

In words it is something like:

if grid export is above 1600 then turn off relay 3
above 2200 turn off relay 2 & 3
above 3200 turn off relay 1, 2 &3

then wait for grid export to drop

if below 3000 turn on relay 1
below 2000 turn on relay 1 & 2
below 1400 turn on relay 1, 2 & 3

and go on until battery reaches target level or is charged

All help massively appreciated.

I would maybe look at your levels like this and then you can more easily translatw that to a chooser in actions

Above 3200, all off, 3kw
Above 2200, below 3200, relay 1 on, 2kw
Above 1400, below 2200, relay 1 & 2 on, 1.4kw
Below 1400, al on, standby

I would also think about maybe using a time pattern trigger to make this run every minute, otherwise it may turn these relays on and off very rapidly, depending on how often your sensor updates. Chooser would look a little like this…

action:
  - choose:
      - conditions:
          - condition: numeric_state
            entity_id: sensor.grid_export_power
            above: 2200
            below: 3200
        sequence:
          - service: switch.turn_off
            target:
              entity_id:
                - switch.relay2
                - switch.relay3
          - service: switch.turn_on
            target:
              entity_id: switch.relay1

And repeat conditions section for each condition in list. I would aet each relay on each condition as you do not know what state you are coming from.

Thanks Mark, I have spent most of the day trying to get this to work and am struggling. I will see if I can make a bit more progress before updating this thread.

Feel free to post what you have an i’ll see if i can help.

Finally I have something that is almost working. What I don’t quite understand is the ‘chooser’. In the first part, where the code deals with export, let’s assume the export power (before charger and immersion) is 2300 watts. What is the logic of the code? My hope is it tests the first condition above 2800w and gets false. Then tests the next condition at 2200w and finds true, does the automation exit there or does it also test above 1400w?
I haven’t quite got the thing to handle the import side yet. I think it is more or less there but the clouds came over before I could test it.

- id: Solar charging optimisation
  alias: Solar charging optimisation
  trigger:
  - platform: state
    entity_id:
    - sensor.export_minus_charger_immersion
  condition:
  - condition: sun
    after: sunrise
    after_offset: '2'
  - condition: sun
    before: sunset
    before_offset: '2'
  - condition: not
    conditions:
    - condition: state
      entity_id: switch.charger_1
      state: unavailable
    - condition: state
      entity_id: switch.charger_2
      state: unavailable
    - condition: state
      entity_id: switch.charger_3
      state: unavailable
  - condition: state
    entity_id: input_boolean.solar_charger_activation
    state: 'on'
  action:
  - if:
    - condition: numeric_state
      entity_id: sensor.export_minus_charger_immersion
      above: 0
    then:
    - choose:
      - conditions:
        - condition: numeric_state
          entity_id: sensor.export_minus_charger_immersion
          above: 2800
        sequence:
        - service: switch.turn_off
          data: {}
          target:
            entity_id:
            - switch.charger_1
            - switch.charger_2
            - switch.charger_3
      - conditions:
        - condition: numeric_state
          entity_id: sensor.export_minus_charger_immersion
          above: 2200
        sequence:
        - service: switch.turn_off
          data: {}
          target:
            entity_id:
            - switch.charger_2
            - switch.charger_3
        - service: switch.turn_on
          data: {}
          target:
            entity_id:
            - switch.charger_1
      - conditions:
        - condition: numeric_state
          entity_id: sensor.export_minus_charger_immersion
          above: 1400
        sequence:
        - service: switch.turn_off
          data: {}
          target:
            entity_id: switch.charger_3
        - service: switch.turn_on
          data: {}
          target:
            entity_id:
            - switch.charger_1
            - switch.charger_2
    else:
    - if:
      - condition: numeric_state
        entity_id: sensor.sensor.grid_import_p
        above: 0
      then:
      - choose:
        - conditions:
          - condition: numeric_state
            entity_id: sensor.grid_import_p
            above: 2200
          sequence:
          - service: switch.turn_on
            data: {}
            target:
              entity_id:
              - switch.charger_1
              - switch.charger_2
              - switch.charger_3
        - conditions:
          - condition: numeric_state
            entity_id: sensor.grid_import_p
            above: 1400
          sequence:
          - service: switch.turn_off
            data: {}
            target:
              entity_id: switch.charger_3
          - service: switch.turn_on
            data: {}
            target:
              entity_id:
              - switch.charger_1
              - switch.charger_2
        - conditions:
          - condition: numeric_state
            entity_id: sensor.grid_import_p
            above: 0
          sequence:
          - service: switch.turn_on
            data: {}
            target:
              entity_id:
              - switch.charger_1
              - switch.charger_2
              - switch.charger_3

It does what you hope. If runs the first true condition only. Described in the docs as like an if, elif, else (you can add a default option if none match)