Custom component Nissan Leaf via LeLink 2 (ELM327) BLE

I have a gen2 leaf, and it will only respond to requests via the dongle when the car is switched on. If you turn the car on when it’s charging, it stays on at least, but not a tremendously reliable strategy.

I also use a Wallbox charger which reports charging power and energy added (but not SoC) over WiFi: much more reliable.

1 Like

I just put a deposit on a second gen leaf (2019 SL) and was planning on ordering a wallbox “charger” and hoping to find a way to get the SOC from the leaf so that I can use home assistant to control how full I charge the leaf. This looks like it might do it if I order a Bluetooth odb adapter?

Hi @peter.vk, I do exactly this.
I have a 2021 62kWh Lean, and a Wallbox Pulsar, which reliably reports the amount of energy added.

Since the OBD dongle can only fetch state of charge (SoC) while the car is switched on, I use an input_number helper to ‘save’ the last known SoC.

I then have an automation that calculates the estimated amount of energy to add to get to 80% SoC. This result is stored in another input_number helper.


(excuse the decimal places)

Another automation monitors the wallbox energy_added sensor and pauses charging once the target amount has been added.

One last little detail is that the wallbox energy_added sensor resets to zero when each time the car is plugged in. So I account for that.

Here’s the automations:

Save the SoC

alias: Update SoC
description: ""
trigger:
  - platform: state
    entity_id:
      - sensor.nissan_leaf_state_of_charge
condition:
  - condition: template
    value_template: >
      {% set state = states('sensor.nissan_leaf_state_of_charge') %}
      {{state.isdigit() or state.replace('.', '', 1).isdigit() }}
    alias: Check that the SoC is a valid number
action:
  - metadata: {}
    data:
      value: "{{ states('sensor.nissan_leaf_state_of_charge') | float }}"
    target:
      entity_id: input_number.car_state_of_charge
    action: input_number.set_value
mode: single

Calculate charge limit:

alias: Car SoC to kWh charge limit
description: ""
trigger:
  - platform: state
    entity_id:
      - input_number.car_state_of_charge
condition:
  - condition: template
    value_template: >
      {% set state = states('sensor.car_charger_added_energy') %}
      {% if not state.isnumeric() and not state|float(false) %}
        {{ false }}
      {% endif %}
      {{ true }}
action:
  - if:
      - condition: or
        conditions:
          - condition: state
            entity_id: sensor.car_charger_status_description
            state: Paused
          - condition: state
            entity_id: sensor.car_charger_status_description
            state: Scheduled
          - condition: state
            entity_id: sensor.car_charger_status_description
            state: Charging
        alias: If the car is plugged in
    then:
      - metadata: {}
        data:
          value: >-
            {% set SoC = (states('input_number.car_state_of_charge') | float) %}
            {% set added_energy = (states('sensor.car_charger_added_energy') | float) %}
            {% set target_percent = 80 %} {% set scale_factor = 68.7 %}
            {% set remaining_energy = (target_percent - SoC) / 100 * scale_factor %}
            {% set energy_limit = remaining_energy + added_energy %}
            {{ [0, [scale_factor, energy_limit] | min] | max }}
        target:
          entity_id: input_number.car_charger_kwh_limit
        alias: >-
          Estimate the kWh limit based on current SoC and the amount already added
        action: input_number.set_value
    else:
      - metadata: {}
        data:
          value: >-
            {% set SoC = (states('input_number.car_state_of_charge') | float) %}
            {% set target_percent = 80 %} {% set scale_factor = 68.7 %}
            {% set target_energy = (target_percent - SoC) / 100 * scale_factor %}
            {{ [0, [scale_factor, target_energy] | min] | max }}
        target:
          entity_id: input_number.car_charger_kwh_limit
        alias: Estimate the kWh limit based on current SoC
        action: input_number.set_value
mode: single

Cut off the charging:

alias: "Car charger: Charging cutoff"
description: ""
trigger:
  - platform: numeric_state
    entity_id:
      - sensor.car_charger_added_energy
    above: input_number.car_charger_kwh_limit
condition:
  - condition: state
    entity_id: sensor.car_charger_status_description
    state: Charging
action:
  - type: turn_off
    device_id: 1643276e5d516342711e6a4ca97e725a
    entity_id: fedb6af0f6fd631045aa53c65bd92cc4
    domain: switch
mode: single
1 Like

This is awesome, thanks for sharing! What ODB dongle did you buy?