Add support for Tesla Powerwall

wow, I just found this thread!
I’ve been doing this all by hand, and it’s great to be able to add this to home assistant! I wonder if someone might make this into a HACS module someday?

I posted this one, but it wasn’t the same as the one you quoted above:

import teslapy
tesla = teslapy.Tesla('<insert email address here>')
if not tesla.authorized:
    print('Use browser to login. Page Not Found will be shown at success.')
    print('Open this URL: ' + tesla.authorization_url())
    tesla.fetch_token(authorization_response=input('Enter URL after authentication: '))
vehicles = tesla.vehicle_list()
print(vehicles[0])
tesla.close()

The Tesla Custom Integration is now available for testing and provides control and monitoring over Tesla vehicles as well as energy products including powerwall, allowing changing operating mode, backup reserve. This is a breaking change if you already have the integration installed.

This rewrite greatly simplifies authentication using the standard HA config flow, so you no longer need shell commands and copying json files around!

You can install by including as a custom repository in

You need to install the dev version:

Happy to take comments here, but please raise any issues in GitHub.

Thanks @shred & @alandtse

3 Likes

somebody fetch this man a beverage :smiley:
I’m installing now to test!

Alright!
I’ve got it all plugged in!
now it’s time to setup some automations to charge after midnight, and discharge after 4pm!

1 Like

Great work,

Charging at midnight is easy, either increase the backup reserve % or switch the operation mode to ‘Backup’.

Discharging on demand is a bit more problematic :frowning:

The ‘Grid Charging’ selector doesn’t start discharging, it only allows it if your Time Based Controls are wanting to discharge to the grid. Have a look at this article. EMHASS: An Energy Management for Home Assistant - #57 by markpurcell

I don’t suppose the code for this panel is available somewhere? I’m aiming to do something very similar - basically turn on TOU charge/discharge as a toggle, and I’d like all the threshholds to be static like you’ve got here.

I’ve been doing it manually using the app until now.
just past midnight, i slide the reserve to 100%, and turn grid charging on, then I go to bed.
when I get up, I turn the reserve back down to 5% and I turn grid charging off. It’s currently in TOU mode, so when 4pm hits, it dumps all the juice from the battery into the grid during the highest buyback price.

So in theory as long as I can just set the times up, it’ll be basically fire and forget! :smiley:

I can only do that til Nov 1, the ‘season’ changes, and the rates fall dramatically to within a cent or two between peak/off peak/super off peak, so it’s only ‘worth it’ to do it here during the summer.

1 Like

Well yes and no, the automatons are mainly from @BruceH5200 here: bruces_homeassistant_config/packages/systems/tesla_powerwall at master · B-Hartley/bruces_homeassistant_config · GitHub

I made manual input helpers before I had my PW installed to try to add more manual input, but in the end it we a bit futile so I removed the ones that are hard coded in to the automation. Then created a manual toggle for autonomous (0% res, 100% back-up) when turned on and 5% res, 95% back-up when turned off.

Here is Bruces’ automation that calculates over night charging levels (extracted from the above link) we are both UK based and using Octopus Energy tariffs (OctopusGo):

automation:
  - id: calculate_max_powerwall_charge_price
    alias: "Powerwall work out what prices to charge below"
    trace:
      stored_traces: 15
    mode: single
    
    description: >
      Work out what price to charge below based on charge level, target and prices
      Assumptions:
      Powerwall useable Capacity: 13.2 kWh
      Max Charge Level is (13.2 - (solar_forecast - tomorrow_solar_threshold) + overnight_usage)/13.2
      ChargeRate = 3.6 kW      
      
    trigger:
    # Forecast.Solar goes to zero between 11(:30) and 00:00 ???
      - platform: time
        id: 'time'
        at: 
          - '21:00:00'
          - '22:15:00'        
          - '00:25:00'  
          - '02:35:00'   
          - '04:45:00'
      - platform: homeassistant
        id: 'start'
        event: start
      - platform: event
        id: 'reload'
        event_type: automation_reloaded     
        
    condition:
    # Forecast should never be zero, so zero would show error ?
      - condition: numeric_state
        entity_id: sensor.solcast_forecast_today
        above: 0
      - condition: numeric_state
        entity_id: sensor.solcast_forecast_tomorrow
        above: 0        
      - condition: state
        entity_id: sensor.enphase_status
        state: "Sleep"

#### This is where I tried to make the hard coded inputs, user changeable from the UI ####      
#    variables:
#     - overnight_usage_percent: "={{ states('input_number.overnight_usage_percent') | int(default=0) }}"
#     - tomorrow_solar_threshold: "={{ states('input_number.tomorrow_solar_threshold') | int(default=0) }}"
#     - go_tomorrow_solar_threshold: "={{ states('input_number.go_tomorrow_solar_threshold') | int(default=0) }}"
#     - charge_rate: 3.6
#     - powerwall_capacity: 13.2
#     - percentage_per_half_hour: "={{ states('input_number.percentage_per_half_hour') }}"

      #{% set percentage_per_half_hour = (100*(charge_rate/2.0)/powerwall_capacity) %}

    variables:
      overnight_usage_percent: 35.0
      tomorrow_solar_threshold: 8.0
      go_tomorrow_solar_threshold: 12.0
      charge_rate: 3.6
      powerwall_capacity: 13.2
      percentage_per_half_hour: 13.6


    action:
      - choose:
          - conditions: 
              - condition: state
                entity_id: input_boolean.go_tariff
                state: 'on'
            sequence:
              - alias: "Update Solcast Forecast"
                event: solcast_update_all_forecasts
              - delay: 30
              - service: input_number.set_value
                target:
                  entity_id: input_number.overnight_powerwall_max_charge
                data:
                  value: "{% set solar_forecast = (states('sensor.solcast_forecast_tomorrow')|float(0)) if now().strftime('%-H')|int(0) > 12 else (states('sensor.solcast_forecast_today')|float(0)) %}{{ ([0,[(100 * (powerwall_capacity - (solar_forecast - go_tomorrow_solar_threshold))) / powerwall_capacity,100]|min]|max)|int(0) }}"
              - service: input_number.set_value
                target:
                  entity_id: input_number.powerwall_charge_below_x_pence
                data:
                  value: 8
              - service: telegram_bot.send_message
                data:
                  target: !secret telegram_chat_id_chris
                  title: "Solar Today/Tomorrow: {{ states('sensor.solcast_forecast_today')|int(0) }}/{{states('sensor.solcast_forecast_tomorrow')|int(0) }}kWh"
                  message: >
                    {% set charge_slots_needed =  (0.5 + (((states('input_number.overnight_powerwall_max_charge')|float(0)) + overnight_usage_percent - (states('sensor.powerwall_charge')|float(0)) )/percentage_per_half_hour))|int(0)  %}
                    
                    Powerwall Charge Level: {{ states('sensor.powerwall_charge')|int(0) }}%                    
                    
                    {% if charge_slots_needed > 0 %}Powerwall Charging overnight to {{ states('input_number.overnight_powerwall_max_charge')|int(0) }}%
                    
                    {{ charge_slots_needed }} half hour periods.  
                    Max Price of 7.5p. Total Cost GBP{{ ( charge_slots_needed * 0.075) }}{% endif %}
                
                
          - conditions: "{{ states.octopusagile.rates == none  or  (states.octopusagile.rates.attributes.values()|count) < 34 or  (states.octopusagile.rates.attributes.values()|count) > 52  or (states('sensor.solcast_forecast_tomorrow')|int(0)) == 0 }}"
            sequence:
              - service: notify.telegram_chris
                data:
                  title: "Powerwall: Error"
                  message: "Error setting overnight charging price, will try again within the next half hour."
                    
        default:
          - alias: "Update Solcast Forecast"
            event: solcast_update_all_forecasts
          - delay: 30         
          - service: input_number.set_value
            target:
              entity_id: input_number.overnight_powerwall_max_charge
            data:
              value: "{% set solar_forecast = (states('sensor.solcast_forecast_tomorrow')|float(0)) if now().strftime('%-H')|int(0) > 12 else (states('sensor.solcast_forecast_today')|float(0)) %}{{ ([0,[(100 * (powerwall_capacity - (solar_forecast - tomorrow_solar_threshold))) / powerwall_capacity,100]|min]|max)|int(0) }}"
          - service: input_number.set_value
            target:
              entity_id: input_number.powerwall_charge_below_x_pence
            data:
              # Take the 20 last prices for the list (next 10 hours), sort them by price and take the 8th for example if 4 hours charging (80% charging) is required.
              value: "{% set howmanyrates = 18 if now().strftime('%-H')|int(0) > 12 else (18-now().strftime('%-H')|int(0)) %}{% set solar_forecast = (states('sensor.solcast_forecast_tomorrow')|float(0)) if now().strftime('%-H')|int(0) > 12 else (states('sensor.solcast_forecast_today')|float(0)) %}{% set rates =  states.octopusagile.rates.attributes.values()|list %}{% set octopusrates = rates[-howmanyrates:]|sort %}{% set charge_slots_needed =  (0.5 + (((states('input_number.overnight_powerwall_max_charge')|float(0)) + overnight_usage_percent - (states('sensor.powerwall_charge')|float(0)) )/percentage_per_half_hour))|int(0)  %}{% if charge_slots_needed == 0 %}0.0{% else %}{{  (octopusrates[charge_slots_needed -1]|float(0) )  }}{% endif %}"
          - service: telegram_bot.send_message
            data:
              target: !secret telegram_chat_id_chris
              title: "Solar Today/Tomorrow: {{ states('sensor.solcast_forecast_today')|int(0) }}/{{states('sensor.solcast_forecast_tomorrow')|int(0) }}kWh"
              message: >
                {% set charge_slots_needed =  (0.5 + (((states('input_number.overnight_powerwall_max_charge')|float(0)) + overnight_usage_percent - (states('sensor.powerwall_charge')|float(0)) )/percentage_per_half_hour))|int(0)  %}
                
                Powerwall Charge Level: {{ states('sensor.powerwall_charge')|int(0) }}%                    
                
                {% if charge_slots_needed > 0 %}Powerwall Charging overnight to {{ states('input_number.overnight_powerwall_max_charge')|int(0) }}%
                
                {{ charge_slots_needed }} half hour periods.  
                Max Price of {{ states('input_number.powerwall_charge_below_x_pence')  }}p. Total Cost GBP{{ ( charge_slots_needed * 0.075) }}{% endif %}

And this automation for setting charge level and mode:

alias: "Powerwall: Set reserve level and mode"
description: |
  Set powerwall reserve and mode
trigger:
  - platform: time
    id: time
    at:
      - "06:30:05"
      - "14:00:05"
      - "15:00:05"
      - "15:59:55"
  - platform: numeric_state
    id: below25
    entity_id: sensor.powerwall_charge_corrected
    below: 25
  - platform: numeric_state
    id: above25
    entity_id: sensor.powerwall_charge_corrected
    above: 25
  - platform: numeric_state
    id: above50
    entity_id: sensor.powerwall_charge_corrected
    above: 50
  - platform: numeric_state
    id: below45
    entity_id: sensor.powerwall_charge_corrected
    below: 45
  - platform: state
    id: states
    entity_id:
      - binary_sensor.go_cheap
      - binary_sensor.power_hour
      - binary_sensor.agile_peak
      - binary_sensor.agile_plunge
      - input_number.overnight_powerwall_max_charge
      - binary_sensor.powerwall_at_or_below_max_charge_cost_and_charge_limit
      - sensor.zappi_car_mode
  - platform: homeassistant
    id: start
    event: start
  - platform: event
    id: reload
    event_type: automation_reloaded
condition: []
action:
  - choose:
      - conditions:
          condition: or
          conditions:
            - condition: state
              entity_id: binary_sensor.power_hour
              state: "on"
            - condition: state
              entity_id: binary_sensor.agile_plunge
              state: "on"
            - condition: state
              entity_id: >-
                binary_sensor.powerwall_at_or_below_max_charge_cost_and_charge_limit
              state: "on"
        sequence:
          - service: tesla_gateway.set_operation
            data:
              real_mode: backup
      - conditions:
          condition: state
          entity_id: binary_sensor.agile_peak
          state: "on"
        sequence:
          - service: input_number.set_value
            target:
              entity_id: input_number.powerwall_reserve_requested
            data:
              value: 1
          - service: tesla_gateway.set_operation
            data:
              real_mode: self_consumption
              backup_reserve_percent: 1
      - conditions:
          - condition: state
            entity_id: >-
              binary_sensor.powerwall_at_or_below_max_charge_cost_and_charge_limit
            state: "off"
          - condition: state
            entity_id: sensor.enphase_status
            state: Sleep
          - condition: state
            entity_id: input_boolean.freeze_power_when_cars_charging
            state: "on"
          - condition: or
            conditions:
              - condition: state
                entity_id: sensor.zappi_car_mode
                state: Fast
        sequence:
          - service: tesla_gateway.set_operation
            data:
              real_mode: self_consumption
              backup_reserve_percent: "{{ states('sensor.powerwall_charge')|int(default=0) }}"
          - service: input_number.set_value
            target:
              entity_id: input_number.powerwall_reserve_requested
            data:
              value: "{{ states('sensor.powerwall_charge')|int(default=0)  }}"
      - conditions:
          - condition: state
            entity_id: binary_sensor.go_cheap
            state: "on"
        sequence:
          - service: tesla_gateway.set_operation
            data:
              real_mode: self_consumption
              backup_reserve_percent: 35
            enabled: false
          - service: input_number.set_value
            target:
              entity_id: input_number.powerwall_reserve_requested
            data:
              value: 35
            enabled: false
          - choose:
              - conditions:
                  - condition: numeric_state
                    entity_id: sensor.solcast_forecast_today
                    below: 8
                sequence:
                  - service: input_number.set_value
                    data:
                      value: 100
                    target:
                      entity_id: input_number.overnight_powerwall_max_charge
              - conditions:
                  - condition: numeric_state
                    entity_id: sensor.solcast_forecast_today
                    above: 8
                    below: 12
                sequence:
                  - service: input_number.set_value
                    data:
                      value: 80
                    target:
                      entity_id: input_number.overnight_powerwall_max_charge
              - conditions:
                  - condition: numeric_state
                    entity_id: sensor.solcast_forecast
                    above: 12
                    below: 14
                sequence:
                  - service: input_number.set_value
                    data:
                      value: 70
                    target:
                      entity_id: input_number.overnight_powerwall_max_charge
              - conditions:
                  - condition: numeric_state
                    entity_id: sensor.solcast_forecast
                    above: 14
                    below: 18
                sequence:
                  - service: input_number.set_value
                    data:
                      value: 60
                    target:
                      entity_id: input_number.overnight_powerwall_max_charge
              - conditions:
                  - condition: numeric_state
                    entity_id: sensor.solcast_forecast
                    above: 18
                sequence:
                  - service: input_number.set_value
                    data:
                      value: 50
                    target:
                      entity_id: input_number.overnight_powerwall_max_charge
      - conditions:
          - condition: state
            entity_id: input_boolean.go_tariff
            state: "off"
          - condition: state
            entity_id: >-
              binary_sensor.powerwall_at_or_below_max_charge_cost_and_charge_limit
            state: "off"
          - condition: time
            after: "00:30:00"
            before: "04:30:00"
        sequence:
          - service: tesla_gateway.set_operation
            data:
              real_mode: self_consumption
              backup_reserve_percent: >-
                {{ [ states('sensor.powerwall_charge')|int(default=0) ,
                states('input_number.overnight_powerwall_max_charge')|int(default=0)]|min
                }}
          - service: input_number.set_value
            target:
              entity_id: input_number.powerwall_reserve_requested
            data:
              value: >-
                {{ [ states('sensor.powerwall_charge')|int(default=0) ,
                states('input_number.overnight_powerwall_max_charge')|int(default=0)]|min
                }}
      - conditions:
          - condition: state
            entity_id: input_boolean.go_tariff
            state: "off"
          - condition: time
            after: "14:00:00"
            before: "14:59:59"
          - condition: numeric_state
            entity_id: sensor.powerwall_charge
            below: 25
        sequence:
          - service: tesla_gateway.set_operation
            data:
              real_mode: backup
      - conditions:
          - condition: state
            entity_id: input_boolean.go_tariff
            state: "off"
          - condition: time
            after: "15:00:00"
            before: "15:59:30"
          - condition: numeric_state
            entity_id: sensor.powerwall_charge
            below: 50
        sequence:
          - service: tesla_gateway.set_operation
            data:
              real_mode: backup
    default:
      - service: input_number.set_value
        target:
          entity_id: input_number.powerwall_reserve_requested
        data:
          value: "{{ [ states('sensor.powerwall_charge')|int(default=0) , 5]|min }}"
      - service: tesla_gateway.set_operation
        data:
          real_mode: self_consumption
          backup_reserve_percent: "{{ [ states('sensor.powerwall_charge')|int(default=0) , 5]|min }}"
mode: queued
trace:
  stored_traces: 15

This is my current UI controls:


I also incorporated my own 5 choice decision tree in to the automation which will set the charge level according to the next days Solarcast prediction:

alias: "Powerwall: Set reserve level and mode2"
description: Set Powerwall Max Overnight Charge % at 21:00
trigger:
  - platform: time
    at: "21:00:00"
condition: []
action:
  - choose:
      - conditions:
          - condition: numeric_state
            entity_id: sensor.solcast_forecast_tomorrow
            below: 8
        sequence:
          - service: input_number.set_value
            data:
              value: 100
            target:
              entity_id: input_number.overnight_powerwall_max_charge
      - conditions:
          - condition: numeric_state
            entity_id: sensor.solcast_forecast_tomorrow
            above: 8
            below: 12
            value_template: ""
        sequence:
          - service: input_number.set_value
            data:
              value: 80
            target:
              entity_id: input_number.overnight_powerwall_max_charge
      - conditions:
          - condition: numeric_state
            entity_id: sensor.solcast_forecast_tomorrow
            above: 12
            below: 14
        sequence:
          - service: input_number.set_value
            data:
              value: 70
            target:
              entity_id: input_number.overnight_powerwall_max_charge
      - conditions:
          - condition: numeric_state
            entity_id: sensor.solcast_forecast_tomorrow
            above: 14
            below: 18
        sequence:
          - service: input_number.set_value
            data:
              value: 60
            target:
              entity_id: input_number.overnight_powerwall_max_charge
      - conditions:
          - condition: numeric_state
            entity_id: sensor.solcast_forecast_tomorrow
            above: 18
        sequence:
          - service: input_number.set_value
            data:
              value: 50
            target:
              entity_id: input_number.overnight_powerwall_max_charge
trace:
  stored_traces: 10
mode: single

1 Like

this is awsome, thank you!

Hi just installed the great looking Tesla Custom Integration component through HACS (dev version), have powerwall no car, used the [Chromium Tesla Token Generator] in the setup but all I get is “Integration
Failed to set up” check the logs. but there is nothing in the logs, am I missing something?
Can this co-exist with the official HA tesla integration or do I need to remove that?

Are you sure that you installed the “dev” version when in HACS? Go back in to hacs and select re-download but make sure to use the drop down menu for the version and scroll to bottom of the list to “dev”.

1 Like

If you mean the https://www.home-assistant.io/integrations/powerwall then yes they can coexist. The powerwall integration polls your device direct over your local area network (localAPI). The Tesla Custom Integration from HACS polls the Tesla server in the cloud (cloudAPI - using the same data as the Tesla Ap).

Generally in Home Assistant we prefer localAPI over cloudAPI, but in the case of Tesla they have removed all control from the localAPI.

As to your specific authentication issues, it would be best to enable debug for your integration and see what is coming back through the logs.

You can enable debugging with the following lines in configuration.yaml

logger:
  default: warning
  logs:
    teslajsonpy: debug
    custom_components.tesla_custom: debug
1 Like

Thanks all, so it looks like a HACS issues firstly I had installed the latest version then gone back and updated to dev version. That seems to be the issue. I deleted the full HACS install and started again and worked first time.

1 Like

Thanks for this defiantly need to do some automation of my PW charging new to this only had the PW since Sept, its on time-based control and done pretty well so far on using solar and charging overnight when needed. However last night it didn’t bother charging and today no chance the solar and battery are going to see the day out, tesla algo. not that great then :slight_smile:

Install Solcast and then you will have Fairly accurate forecast of the super available in your area. You have to create a Solarcast account and get the API from the website to use in the integration. The sensors in HA will all be created as default names and same as used in Bruces automatons.

On my 5 choice automation above that one is triggered at 21:00 and looks at “sensor.solcast_tomorrow_forecast” and sets the PW charge level accordingly. You may need to adjust the solar predictions against required charge % based on your home loads and consumption. My standing loads runs 24/7 at around 450wh and my consumption is high when there is solar as other automatons switch on additional electrical loads. But like today’s forecast is less that 8kWh so all non essential electrical loads are left off all day to preserve the PW SOC as long as possible.

1 Like

Your use case sounds like a great candidate for using the EMHASS: Energy Management for Home Assistant add on.

EMHASS uses a linear programming model to optimise energy usage by continuously calculating when to switch deferrable loads throughout your house. I use it to schedule my home battery and EV charging, various other systems (hot water, air conditioning, pool pumps and heating). EMHASS considers forecasts for your household load, solar production as well as the buy/ sell price for electricity. If I have a low solar production day forecast it will defer loads to the next 24 hours.

Here is my household optimisation sensors created for the next 24 hours, HA reruns the optimisation every minute as my variable pricing changes that quickly. I use these sensors in automations for my devices to switch them at the appropriate timing.

You can see in the dark blue when my battery is scheduled to charge or export to the grid - after 5pm you can see a big export block as that is when my export tariff is highest and EMHASS has calculated exactly how much I can export, but keep the house running overnight.

You can see on the dark green when it is best to export to the grid, for today’s plan there is no grid import required. You can see the light green the charging profile for my EV for the day. You can see my pool heater isn’t scheduled as it’s run hours are set to only run when the value of my solar exports are extremely_low (< 5¢/ kWh) and I want to maximise self consumption. You can see my standing load in light purple which is based off the average standing load for the last couple of days.

There is some complexity in setting up the add-on, but the Author is very responsive and claims an 8-10% improvement in efficiency. I’m probably seeing higher efficiency as optimising quickly for my changes in my variable pricing gives me a high operational benefits (financial, environmental, sustainable).

1 Like

Hi Mark,

I tried to set up before and again tonight but I can’t get past the web ui fails to open. I set up a port forwarding rule to use 5005 external port and direct to my HA ip address:5000 but no joy.

Also in the configuration as soon as I try to change the monetary values from the default the entry forms go red and it doesn’t accept my values. I’m trying to enter then looks this:

Peak rate: 0.3100
Off peak: 0.0750
Sell: 0.0410
1 Like

Happy to work with you to get this working.

I presume you are using the add-on?

Do you need the port forwarding, can you just setup EMHASS to use port 5005? Can you access your HomeAssistant via you LAN?

I don’t actually use the dialogue for cost entry, but just tried and see what you mean, so there is a bug - @davidusb . A workaround is to switch configuration to yaml where you can edit, save and restart add-on.

It might also make sense to switch this discussion over to EMHASS add-on: An energy management optimization add-on for Home Assistant OS and supervised