Add support for Tesla Powerwall

@Jez I was literally just coming here to ask. I can’t get it working at all. Tried a few things from this thread as well as reinstalling through HACS and manually, and I get the “tesla_gateway has no attribute ‘async_setup_entry’” error, apparently from config_entries.py. Are you having the same issue?

@craigrouse Yes, that’s the same error I get if I try to upgrade HA.

I’ve made some progress by modifying the init.py as follows:

"""
Monitors and controls the Tesla gateway.
"""
import logging

import asyncio
import voluptuous as vol
import teslapy
import aiohttp
import asyncio
import async_timeout
import base64
import hashlib
import json
import os
import re
import time
from urllib.parse import parse_qs
import voluptuous as vol
from homeassistant import config_entries, core
from homeassistant.const import (
    CONF_USERNAME,
    CONF_PASSWORD,
    CONF_ACCESS_TOKEN,
)
from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv

from homeassistant.const import (
    CONF_USERNAME,
    CONF_PASSWORD
    )
import homeassistant.helpers.config_validation as cv

DOMAIN = 'tesla_gateway'

_LOGGER = logging.getLogger(__name__)

CONFIG_SCHEMA = vol.Schema({
    DOMAIN: vol.Schema({
        vol.Required(CONF_USERNAME): cv.string,
        vol.Required(CONF_PASSWORD): cv.string
    }),
}, extra=vol.ALLOW_EXTRA)


@asyncio.coroutine
def async_setup_entry(
    hass: core.HomeAssistant, config_entry: config_entries.ConfigEntry
) -> bool:
    websession = async_get_clientsession(hass, verify_ssl=False)

    hass.data.setdefault(DOMAIN, {})
    hass.data[DOMAIN][config_entry.entry_id] = config_entry.data
    domain_config = dict(config_entry.data)
    conf_user = domain_config[CONF_USERNAME]
    conf_password = domain_config[CONF_PASSWORD]
    # setup_common(domain_config=domain_config)
    tesla = teslapy.Tesla(domain_config[CONF_USERNAME], domain_config[CONF_PASSWORD])
    return True

@asyncio.coroutine
def async_setup(hass, config):

    domain_config = config[DOMAIN]
    conf_user = domain_config[CONF_USERNAME]
    conf_password = domain_config[CONF_PASSWORD]
    
    tesla = teslapy.Tesla(domain_config[CONF_USERNAME], domain_config[CONF_PASSWORD])

    def get_battery():
        batteries = tesla.battery_list()
        if len(batteries) > 0:
            return batteries[0]
        else:
            return None
    
    @asyncio.coroutine
    async def set_operation(service):
        
        battery = await hass.async_add_executor_job(get_battery)
        if not battery:
            _LOGGER.warning('Battery object is None')
            return None

        await hass.async_add_executor_job(battery.set_operation, service.data['real_mode'])
        if 'backup_reserve_percent' in service.data:
            await hass.async_add_executor_job(battery.set_backup_reserve_percent, service.data['backup_reserve_percent'])

    hass.services.async_register(DOMAIN, 'set_operation', set_operation)

    @asyncio.coroutine
    async def set_reserve(service):
        
        battery = await hass.async_add_executor_job(get_battery)
        if not battery:
            _LOGGER.warning('Battery object is None')
            return None
            
        if 'backup_reserve_percent' in service.data:
            await hass.async_add_executor_job(battery.set_backup_reserve_percent, service.data['backup_reserve_percent'])

    hass.services.async_register(DOMAIN, 'set_reserve', set_reserve)

    return True

I know the code isn’t totally correct, but it solves the error and gets me to the point where I can authenticate… almost! I had to update the manifest.json to use teslapy 1.4.0, as I was getting auth errors. I now get an error because the Tesla API is returning a captcha code, and I haven’t yet figured out how to solve the captcha, since I obviously can’t see it anywhere! It’s progress anyway. I’ll keep chipping away!

I’ve just had success… a very long and involved process of running teslapy locally on my mac to generate a cache.json file and manually copy it over to the pi, edit the script and tell it to use the supplied json cache file. I’ll write up full instructions ASAP, but that’s enough for tonight!

Well done Craig. Keep us posted on your progress please.

BEFORE PROCEEDING, TAKE A SYSTEM BACKUP! It’s quite possible some of the quotes and whitespace may have been messed up in my copy/pasting, but I’ve done the best I can.

First off, make sure you have python and pip installed on your system (not your HASS system). I was running this on my Mac.

Install Teslapy using pip

pip install teslapy

Create a script somewhere you can access with this content:

import teslapy

def solve_captcha(svg):
    with open('/Users/<username>/captcha.svg', 'wb') as f:
        f.write(svg)
        f.close()
    return input('Captcha: ')

with teslapy.Tesla("your-tesla-username", "your-password") as tesla:
        tesla.fetch_token()
        battery = tesla.battery_list()[0]
        battery.set_backup_reserve_percent(6)
        print(battery) # should print battery status once successfully authenticated

Save it as something like “tesla-auth.py”, then run

python tesla-auth.py

NOTE: Make sure your browser is set to be the default file handler for .svg files! On a mac, find an svg file, right click on it and hit “get info”, then under “open with”, make sure your preferred browser is selected and hit “change all”. If you don’t do this, the captcha won’t open.

If Tesla decides to serve you a captcha, your browser will now open, displaying the captcha. Go back to the terminal window and enter the captcha at the prompt, and you should find the script runs successfully and your battery info is printed out.

At this point, you should also have a “cache.json” file in the same directory you ran the python script from. This contains your Tesla API token and associated info. Copy the contents of this file to your clipboard.

Load up the HASS web UI and use something like Visual Studio Code to navigate to /config/custom_components/tesla_gateway and create a new file here. Paste in the contents of the cache.json that you just copied to your clipboard. Save the file and call it cache.json, and make sure it’s saved at the same directory level as init.py (directly under tesla_gateway).

Still in VSCode, go into init.py and paste my modified script:

"""
Monitors and controls the Tesla gateway.
"""
import logging

import asyncio
import voluptuous as vol
import teslapy
import aiohttp
import asyncio
import async_timeout
import base64
import hashlib
import json
import os
import re
import time
from urllib.parse import parse_qs
import voluptuous as vol
from homeassistant import config_entries, core
from homeassistant.const import (
    CONF_USERNAME,
    CONF_PASSWORD,
    CONF_ACCESS_TOKEN,
)
from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv

from homeassistant.const import (
    CONF_USERNAME,
    CONF_PASSWORD
    )
import homeassistant.helpers.config_validation as cv

DOMAIN = 'tesla_gateway'

_LOGGER = logging.getLogger(__name__)

CONFIG_SCHEMA = vol.Schema({
    DOMAIN: vol.Schema({
        vol.Required(CONF_USERNAME): cv.string,
        vol.Required(CONF_PASSWORD): cv.string
    }),
}, extra=vol.ALLOW_EXTRA)


@asyncio.coroutine
def async_setup_entry(
    hass: core.HomeAssistant, config_entry: config_entries.ConfigEntry
) -> bool:
    websession = async_get_clientsession(hass, verify_ssl=False)

    hass.data.setdefault(DOMAIN, {})
    hass.data[DOMAIN][config_entry.entry_id] = config_entry.data
    domain_config = dict(config_entry.data)
    conf_user = domain_config[CONF_USERNAME]
    conf_password = domain_config[CONF_PASSWORD]
    # setup_common(domain_config=domain_config)
    tesla = teslapy.Tesla("your-tesla-username", "your-tesla-password", cache_file="/config/custom_components/tesla_gateway/cache.json")
    return True

@asyncio.coroutine
def async_setup(hass, config):

    domain_config = config[DOMAIN]
    conf_user = domain_config[CONF_USERNAME]
    conf_password = domain_config[CONF_PASSWORD]
    
    tesla = teslapy.Tesla("your-tesla-username", "your-tesla-password", cache_file="/config/custom_components/tesla_gateway/cache.json")

    def get_battery():
        batteries = tesla.battery_list()
        if len(batteries) > 0:
            return batteries[0]
        else:
            return None
    
    @asyncio.coroutine
    async def set_operation(service):
        
        battery = await hass.async_add_executor_job(get_battery)
        if not battery:
            _LOGGER.warning('Battery object is None')
            return None

        await hass.async_add_executor_job(battery.set_operation, service.data['real_mode'])
        if 'backup_reserve_percent' in service.data:
            await hass.async_add_executor_job(battery.set_backup_reserve_percent, service.data['backup_reserve_percent'])

    hass.services.async_register(DOMAIN, 'set_operation', set_operation)

    @asyncio.coroutine
    async def set_reserve(service):
        
        battery = await hass.async_add_executor_job(get_battery)
        if not battery:
            _LOGGER.warning('Battery object is None')
            return None
            
        if 'backup_reserve_percent' in service.data:
            await hass.async_add_executor_job(battery.set_backup_reserve_percent, service.data['backup_reserve_percent'])

    hass.services.async_register(DOMAIN, 'set_reserve', set_reserve)

    return True

Finally, still in VSCode, modify manifest.json and set the teslapy dependency to 1.4.0. If you don’t do this, it won’t work.

"requirements": ["teslapy==1.4.0"],

Restart Home Assistant. If I’ve not forgotten anything, Bob’s your uncle - you should be able to successfully make API calls to set the reserve percentage and mode. NOTE: when I first set this up, it worked once, then started failing every time with timeouts. I believe I was just unlucky and hit a server issue on Tesla’s end right when I set it up, but it’s possible they may be doing some kind of throttling. If it fails with timeouts, leave it overnight and come back to it in the morning. That’s what I did, and the issue was resolved. You may have to go through this process again when your token expires in a few weeks, but with a bit of luck the token will just keep being refreshed.

I haven’t ever played with Home Assistant components before, and I’ve done just enough here to make it work, but not enough to do it properly and make it look nice. Other integrations that have Captchas integrate with the Notifications bar to display the captcha and have you solve it. I think this should be possible to do with this integration too - it just needs a bit of time spending on it that I don’t have right now, but if I do get the time, I’ll take a look. Perhaps someone else has some better ideas or more experience with Home Assistant and can help with a better solution, but at least this works for now!

1 Like

I don’t have time to try this yet but when I do I’ll let you know how I get on.

1 Like

Just wanted to say this…

If the problem you’re getting is in regards to this error:
AttributeError: module 'custom_components.tesla_gateway' has no attribute 'async_setup_entry'

This only occurs when attempting to add Tesla Gateway integration, correct?

I’ve just been using this integration without adding thru config flow and manually adding username/password to configuration.yaml file.

tesla_gateway:
  username: ***
  password: ***

I’m now just (occasionally) getting an error in regard to api authentication. But still very usable.

Glad that some could figure it out… Tesla has added a captcha and most Tesla integrations are failing. The current official Tesla-car integration from HA is failing for this same reason.
This integration had the benefit that it saves the refresh/auth token so it can survive restarts (this is something that produced failures last time). But now, once the refresh token expires, the captcha is needed.

Long term, we need to re-eneble the config flow piece (sorry, I broke that last time) and add the captcha to that. If the token expires, we would have to re-add the integration (maybe we can put the captcha in the configure part of config flow).

If someone has the time, feel free to put a pull request against GitHub - carboncoop/tesla-gateway-ha-component: A Home Assistant component to control Tesla Powerwall.</ti

1 Like

This python library is adding support for set operations through the local API, which might work better.

HA newbie, other than mostly using the integrations that just work out of the box with the UI and simple-to-follow steps.

Having said that, I’ve had the TeslaPowerwall collecting stats for a long time. Now I have the Energy setup in HA working properly. Unfortunately, I only have stats showing the the Energy setup going back 1 month. How/when does the TeslaPowerwall stats get purged? Preferably, I’d like to keep this data forever, or at least be able to set purge info.

I am currently using the Tesla Powerwall integration and it is working great. My powerwall is currently in Storm Watch mode but I don’t see that in Home Assistant. Is that data available in the API? Could it be added into the integration?

Whilst this isn’t HA, GitHub - mihailescu2m/powerwall_monitor: Monitoring for the Tesla powerwall will help you keep your stats for a longer time.

I note they have the car integration working in HACS via the Tesla Tokens phone app, is there any chance this could adopt that too? It’s not perfect but it works well enough and easier in comparison to creating your own token files…

1 Like

Hi,

The CarbonCoOp custom component seems pretty broken now.
I’m guessing it’s changes made by Tesla.

It is using 1.1.0 TeslaPy which seems very out of date now.
I’ve tried giving it a cache.json file that I created offline using latest teslapy, but that didn’t work.
Is anyone able to update this component so it works again, even if it is with a cached key file that you have to generate manually.
I just need to be able to change the mode of my powerwall, but coding this is sadly beyond me at the moment.

Thanks

1 Like

Yup. For the past few days, I haven’t been able to get access to do this.

Error: Unexpected error for call_service at pos 1: 401 Client Error: Unauthorized for url: https://owner-api.teslamotors.com/api/1/products

Definitely hoping to get this working again. It was fabulous before.

The issue as I understand it is that Tesla changed the methods around authorization tokens. This integration is based on Teslapy which has since been upgraded and works.
Unfortunately this HA integration doesn’t appear to be maintained by anyone at the moment and unless someone takes it on and integrates the new version of Teslapy then sadly it’s finished.

Personally, I’ve installed the latest version of Teslapy on my Homeseer PC and using Craig’s code and method above I can set the reserve % to charge the Powerwall overnight. Homeseer is my preferred system anyway so I’ll stick with this.

This integration still works for me on latest version of HA. However I am using email address and the token as username and password.

I manually generate a token from teslafi each month.

Not ideal, but it works until anyone wishes to own this add on. It’s too complex for me, but it would be a shame not to have it working.

For me I just wish I now knew how to access a couple of other sensors on the local gateway, namely instant voltage.

mine stopped working too. I don’t think anyone is maintaining this anymore as I haven’t seen @estebanp around in some time. I just want my PW to go to 100 reserve before my car charges, then back to 25 when it is done so I don’t drain and add cycles to the PW unnecessarily.

Is there something else that will do this even outside of HA?

Mine and my father in-law’s setup have stopped working too. We were using the original setup and we were not using a Tesla API Token. I have tried to follow the instructions for to add the Tesla API token as explained by @craigrouse and when I get to the stage of running the tesla-auth.py I get an ‘OSError: Could not find a suitable TLS CA certificate bundle error.’ Any ideas?

I assume this still works as @Hodor has said their setup is still working, but has to refresh the token every month. It would be better if Tesla just added the function to fully charge the battery in the app.

TIA