Optimizing use of unused Solar Power to charge a Tesla

As I have had received the request to share my project on another forum, I have decided to document it here in a structured way. Hoping it inspires or triggers additional idea’s.

The objective of this set of automations is to activate the charging of a Tesla when the electricity produced by my solar panels would normally be sent back to the grid.
In order to only charge when I don’t use the solar electricity I produce I actually based the triggers on the net (negative) consumption from the digital meter, but one could consider only using energy produced from solar panels as an alternative trigger.

Preparing for the 2022 electricty rate card that will be based on peak usage in my area, I also included a reverse trigger to stop charging when the rest of the house is using electricty.

Setup
Hardware :

Integrations :

My installation produces a maximum of 4 KWh.
I have set the Tesla to charge at 13A when at home (you can configure that in the car based on geo-location): charging at 3KWh, which is purposely low and enough for my needs. If you charge at a higher rate, some thresholds will have to be adapted in the codes below (otherwise charging would overpass the threshold and provoke the end of charging by itself).

Automations

There are two basic automations:

  1. The basic: activate charging switch when electricity is available
- id: 'Tesla001'
  alias: Tesla - Active charge si électricité solaire disponible (>2KWh exporté &
    batterie <80%)
  description: ''
  trigger:
  - platform: numeric_state
    entity_id: sensor.fluvius_p1_active_power
    below: '-2000'
#value to be adapted based on your solar capacity & charging rate
    for: 00:00:20
#adding a 'for' duration condition to avoid start on short sunbursts, if you want to avoid multiple on/offs you may increase that duration
  condition:
  - condition: state
    entity_id: device_tracker.[TeslaName]_location_tracker
    state: home
#making sure this only activates when the Tesla is actually at home
  - condition: state
    entity_id: binary_sensor.[TeslaName]_charger_sensor
    state: 'on'
  - condition: state
    entity_id: switch.[TeslaName]_charger_switch
    state: 'off'
#avoid a loop where the automation would try to turn on a switch that's already on
  action:
  - service: switch.turn_on
    target:
      entity_id: switch.[TeslaName]_charger_switch
  mode: single
  1. Stop charging when consumming too much from the grid
- id: 'Tesla002'
  alias: Tesla - Couper charge si consommation trop élevée (>1500)
  description: ''
  trigger:
  - platform: numeric_state
    entity_id: sensor.fluvius_p1_active_power
    above: '1500'
    for: 00:01:00
#adding a 'for' duration condition to avoid stop on every small cloud, if you want to avoid multiple on/offs you may increase that duration
  condition:
  - condition: state
    entity_id: device_tracker.[TeslaName]_location_tracker
    state: home
#making sure this only activates when the Tesla is actually at home
  - condition: numeric_state
    entity_id: sensor.[TeslaName]_charging_rate_sensor
    above: '2'
#making sure this only activates when the Tesla is actually charging: using the charging rate value seemed more stable than the state of the switch
  - condition: not
    conditions:
    - condition: state
      entity_id: switch.[TeslaName]_maxrange_switch
      state: 'on'
#"misusing" the Max Range switch to force charging even if conditions are not optimal, this switch is used in different automations
  action:
  - service: switch.turn_off
    target:
      entity_id: switch.[TeslaName]_charger_switch
  mode: single

On top of these, there are ways to fine-tune the concept, for instance:

  1. Making sure charging stops quickly when above acceptable peak (unless battery is really low)
- id: 'Tesla006'
  alias: Tesla - Stop Charge au-dessus de 5.4KWH
  description: ''
  trigger:
  - platform: numeric_state
    entity_id: sensor.fluvius_p1_active_power
    above: '5400'
  condition:
  - condition: state
    entity_id: device_tracker.[TeslaName]_location_tracker
    state: home
  - condition: numeric_state
    entity_id: sensor.[TeslaName]_range_sensor
    above: '40'
  action:
  - service: switch.turn_off
    target:
      entity_id: switch.[TeslaName]_charger_switch
  mode: single
  1. “Misusing” the Max Range switch to force charge manually
- id: 'Tesla007'
  alias: Tesla - Force charge si mode max range enclenché
  description: ''
  trigger:
  - platform: state
    entity_id: switch.[TeslaName]_maxrange_switch
    from: 'off'
    to: 'on'
    for:
      hours: 0
      minutes: 0
      seconds: 5
      milliseconds: 0
  condition: []
  action:
  - service: switch.turn_on
    target:
      entity_id: switch.[TeslaName]_charger_switch
  mode: single

Those are a few example.

Display commands

As far as Lovelace is concerned, buttons are just placed in a box on my mobile interface: note, the “charging” icon updates with some delay.

type: horizontal-stack
cards:
  - type: custom:button-card
    tap_action:
      action: toggle
    hold_action:
      action: more-info
    entity: climate.[TeslaName]_hvac_climate_system
    name: Tesla A/C
    icon: mdi:thermometer
    size: 25%
    color: orange
    show_state: false
    styles:
      name:
        - justify-self: middle
        - font-weight: bold
        - font-size: 14px
    state:
      - value: 'off'
        icon: mdi:thermometer-off
        color: '#56819F'
  - type: custom:button-card
    tap_action:
      action: toggle
    hold_action:
      action: more-info
    entity: switch.[TeslaName]_charger_switch
    name: Charge
    icon: mdi:battery-charging-medium
    size: 25%
    color: orange
    show_state: false
    styles:
      name:
        - justify-self: middle
        - font-weight: bold
        - font-size: 14px
    state:
      - value: 'off'
        icon: mdi:battery-off
        color: '#56819F'
  - type: custom:button-card
    tap_action:
      action: toggle
    hold_action:
      action: more-info
    entity: switch.[TeslaName]_maxrange_switch
    name: Max Range
    icon: mdi:gauge-full
    size: 25%
    color: orange
    show_state: false
    styles:
      name:
        - justify-self: middle
        - font-weight: bold
        - font-size: 14px
    state:
      - value: 'off'
        icon: mdi:gauge
        color: '#56819F'
10 Likes

I approach this slightly differently. Using a 2 minute low pass filtered average of my total inverter output power I subtract my known house base load (450W) and the only other large load, my hot water heater actual power consumption. If the excess is greater than 2.5kW, the “excess_solar_power” template binary sensor turns on.

I then use this binary sensor to switch my ducted heat pump on or off using a “for 10 minutes” state trigger.

Using the inverter power avoids cycling that can possibly happen if monitoring the power returned to the grid (heat pump turns on , so grid return reduces, so heat pump turns off, so grid return increases… repeat).

3 Likes

Can you please share your config, I have something similar but I have 0-10v sensor which controls the power up to 2.5kW but is configured a dimmer from 0-100%

I am struggeling how to impement this, I allready have a P1 HomeWizard meter connected to obtain the live active power values + solaredge integration.

I want to understand how you have implemented your solution and try to adjust it to mine.

The main goal is to increase your self usage constanly.

Thank you!

sensor:
- platform: filter
  name: LP20 Inverter Power
  entity_id: sensor.sma_inverter_power
  filters:
    - filter: lowpass
      time_constant: 20
      precision: 0
template:
- binary_sensor:
  - name: "Excess Solar"
    icon: "mdi:solar-power"
    state: "{{ ( states('sensor.lp20_inverter_power')|float(0) - states('sensor.hot_water_power')|float(0) ) > 2500 }}"
    delay_off:
      minutes: 10
    delay_on:
      minutes: 10
automation:
- id: d69928c0-8586-43df-9c5d-1f31ed7ad2fe
  alias: 'Upstairs Excess Solar On'
  trigger:
  - platform: state
    entity_id: binary_sensor.excess_solar
    from: 'off'
    to: 'on'
  condition:
  - condition: state
    entity_id: input_boolean.upstairs_ac_use_excess_solar
    state: 'on'
  - condition: state
    entity_id: group.upstairs_doors_and_windows
    state: 'off'
  action:
  - choose:
    - conditions:
      - condition: numeric_state
        entity_id: sensor.bom_today_max
        below: 18
      sequence:
      - service: climate.set_temperature
        target:
          entity_id: climate.upstairs
        data:
          hvac_mode: heat
          temperature: "{{ states('input_number.upstairs_ac_temp_set_heat') }}"
      - service: notify.telegram_system
        data:
          title: "♨️ *Upstairs AC heating {{ 'turned on' if is_state('input_boolean.upstairs_ac_24_7', 'off') else 'changed' }}*"
          message: >
            Due to high solar power.

            Set temp: {{ states('sensor.upstairs_set_temperature') }}°C

            Inside temp: {{ states('sensor.lounge_room_temperature') }}°C

            Forecast max: {{ states('sensor.bom_today_max') }}°C

            Current solar: {{ states('sensor.sma_inverter_power') }}W
    - conditions:
      - condition: numeric_state
        entity_id: sensor.bom_today_max
        above: 22
      sequence:
      - service: climate.set_temperature
        target:
          entity_id: climate.upstairs
        data:
          hvac_mode: cool
          temperature: "{{ states('input_number.upstairs_ac_temp_set_cool') }}"
      - service: notify.telegram_system
        data:
          title: "❄️ *Upstairs AC cooling {{ 'turned on' if is_state('input_boolean.upstairs_ac_24_7', 'off') else 'changed' }}*"
          message: >
            Due to high solar power.

            Set temp: {{ states('sensor.upstairs_set_temperature') }}°C

            Inside temp: {{ states('sensor.lounge_room_temperature') }}°C

            Forecast max: {{ states('sensor.bom_today_max') }}°C

            Current solar: {{ states('sensor.sma_inverter_power') }}W

- id: 7832b252-84c8-4101-bb79-0689e7173a68
  alias: 'Upstairs Excess Solar Off'
  trigger:
  - platform: state
    entity_id: binary_sensor.excess_solar
    from: 'on'
    to: 'off'
  condition:
  - condition: state
    entity_id: input_boolean.upstairs_ac_use_excess_solar
    state: 'on'
  - condition: state
    entity_id: binary_sensor.upstairs_ac_am_automation_time_active
    state: 'off'
  - condition: state
    entity_id: binary_sensor.upstairs_ac_pm_automation_time_active
    state: 'off'
  action:
  - choose:
    - conditions:
      - condition: state
        entity_id: input_boolean.upstairs_ac_24_7
        state: 'off'
      sequence:
      - service: climate.turn_off
        target:
          entity_id: climate.upstairs
      - service: notify.telegram_system
        data:
          title: '⏹️ *Upstairs AC turned off*'
          message: >
            Due to due to low solar power.

            Inside temp: {{ states('sensor.lounge_room_temperature') }}°C

            Forecast max: {{ states('sensor.bom_today_max') }}°C

            Current solar: {{ states('sensor.sma_inverter_power') }}W
    - conditions:
      - condition: state
        entity_id: input_boolean.upstairs_ac_24_7
        state: 'on'
      sequence:
      - service: climate.set_temperature
        target:
          entity_id: climate.upstairs
        data:
          temperature: >
            {% if is_state('climate.upstairs', 'heat') %}
              {{ states('input_number.upstairs_ac_night_away_heat_temp') }}
            {% elif is_state('climate.upstairs', 'cool') %}
              {{ states('input_number.upstairs_ac_night_away_cool_temp') }}
            {% else %}
              19
            {% endif %}
      - service: notify.telegram_system
        data:
          title: '↕️ *Upstairs AC temperature changed*'
          message: >
            Due to low solar power.

            Set temp: {{ states('sensor.upstairs_set_temperature') }}°C

            Inside temp: {{ states('sensor.lounge_room_temperature') }}°C

            Forecast max: {{ states('sensor.bom_today_max') }}°C

            Current solar: {{ states('sensor.sma_inverter_power') }}W
1 Like

thank you, I’ll check this weekend.

How many message do you get on a cloudy day and how do you avoid quick turn on/off.

As shown above, I use a low pass filter on the sensor and a delayed on/off on the binary sensor.

Today was partly cloudy but this is what the excess solar sensor was doing (in orange):

Screenshot 2021-10-19 at 22-28-33 Overview - Home Assistant

The short spike was 15 minutes long.

1 Like

Is there a way to do this dynamically, you limit your self to max 2500w?

In my case I can modulate the heating power from 0 to 10V which is from 0 to 2500W. I use a light swich brightness from 0 to 100% which can modulate the power output accordingly.

Should I create different low pass filter sensors for each specific need?

Sometimes there is enough power for 60min at 250/500W or 30min 1000/1500W or 2500W etc.

2500W is the excess I require to run my heat pump. If that is variable in your case, replace it with a sensor that contains how much power you want to draw.

How should I create a sensor, on the basis of what, using different power output levels?

do you have power outlet measuring power of your heat pump ? I am trying to understand how this works

Is this your heat pump ?

sensor.hot_water_power

So your binary sensor does the following “Solar Power” minus “Hot Water Power” is greater than 2500W
Why do you include the hot water power in your binary sensor?

Example
2000W solar power
-450 W house power consumption (how do you take care of this)
= 1550W excess power

Sorry for asking so many questions, I really appreciate your effort of sharing !

The hot water load is only on for a few hours a day. But is a big load, 1000W when on. So I have to take that into account.

If the inverter power minus the hot water power is greater than 2500W then I have enough power to run my base load (450W) and the heat pump (2000W). And I only run it based on a bunch of other temperature and manual automation settings (input booleans).

It’s pretty much specific to my situation and probably not much use to you.

With the new Tesla firmware 2021.36 we can set the charging speed from the api. And since this week the Tesla component has added the api call as well. So now we can adjust the speed like this:

service: tesla_custom.api
data:
  command: CHARGING_AMPS
  parameters:
    path_vars:
      vehicle_id: 'xxxxxxx'
    charging_amps: '5'

Hope this helps

3 Likes

I am now using the Tesla API to match charging to solar production.

Looks pretty good.

I have the following script setup to run every minute when the car is charging.

service: tesla_custom.api
data:
  command: CHARGING_AMPS
  parameters:
    path_vars:
      vehicle_id: '{{ state_attr(''binary_sensor.<car_name>_online_sensor'', ''id'') }}'
    charging_amps: '{{ ((states(''sensor.solaredge_solar_power''))| float *1.4 )| int }}'
5 Likes

The API can set charging amps to 0 as well, no more need to turn on/off?

By the way, how did you get your car on your energy dashboard?

1 Like

Yes you can just set it to 0 and it stops. You can even set values smaller than 5 to very slowly charge the car. I use my P1 smart meter values to calculate how much power can go to the car.

I think his card is the tesla-style-solar-power-card.

3 Likes

Following this thread heavily, now with the new API, I use the CircuitSetup ESP8266 based Energy Monitor to monitor solar production directly at the breaker which feeds my panel as soon as I get this update pushed to my car I plan to follow what you guys are doing here and variable update how much charge goes into the car based on that energy reading.

can you help me with using this api in python script. below is not working.

hass.services.call('tesla_custom','api', service_data={'command': 'CHARGING_AMPS', 'parameters': { 'path_vars': {'vehicle_id': '174565455069'}, 'charging_amps': tesla_charge_rate}})

If you are going to use in python, I think you are better off calling teslajsonpy or TeslaPy directly rather than going back through Hass.

1 Like

I have had mixed results with setting to 0.

Sometimes it stops, sometimes it continues to trickle at 1 Amp.

Using the sun sensor I also switch off at sunset and switch on at sunrise.

Yes I’m using the Tesla style power card, which displays real-time power and energy and is thus a bit more advanced than the energy dashboard.

1 Like

Thanks @markpurcell

actually it worked. the mistake I did was taking the wrong vehicle_id. Looks like we should use the id (not vehicle_id) as vehicle_id.

I just want to say that this is a fantastic find. I’m about to expand my solar system, and I’m anticipating having plenty of surplus generation in the middle of the day. I’m just now switching from SmartThings to HA, and I had plans to devise something like this. Great to see that it’s already being developed. Hopefully, as I learn my way around HA, I’ll be able to contribute to this.