tesla_powerwall
Python Tesla Powerwall API for consuming a local endpoint.
https://github.com/jrester/tesla_powerwall
Category: Consumption
Sub Category: Mobility and Transportation
Keywords
api battery powerwall powerwall-api powerwall-status python tesla tesla-powerwall
Keywords from Contributors
varta varta-storage
Last synced: about 21 hours ago
JSON representation
Repository metadata
Python API for Tesla Powerwall
- Host: GitHub
- URL: https://github.com/jrester/tesla_powerwall
- Owner: jrester
- License: mit
- Created: 2019-02-12T19:50:07.000Z (about 6 years ago)
- Default Branch: master
- Last Pushed: 2025-02-05T07:25:46.000Z (3 months ago)
- Last Synced: 2025-03-22T19:44:41.166Z (about 1 month ago)
- Topics: api, battery, powerwall, powerwall-api, powerwall-status, python, tesla, tesla-powerwall
- Language: Python
- Homepage:
- Size: 450 KB
- Stars: 74
- Watchers: 14
- Forks: 25
- Open Issues: 4
- Releases: 15
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG
- License: LICENSE
README.md
Python Tesla Powerwall API for consuming a local endpoint.
Note: This is not an official API provided by Tesla and this project is not affilated with Tesla in any way.
Powerwall Software versions from 1.47.0 to 1.50.1 as well as 20.40 to 22.9.2 are tested, but others will probably work too.
Table of Contents
Installation
Install the library via pip:
$ pip install tesla_powerwall
Limitations
Adjusting Backup Reserve Percentage
Currently it is not possible to control the Backup Percentage, because you need to be logged in as installer, which requires physical switch toggle. There is an ongoing discussion about a possible solution here.
However, if you believe there exists a solution, feel free to open an issue detailing the solution.
Usage
For a basic Overview of the functionality of this library you can take a look at examples/example.py
. You can run the example, by cloning the repo and executing in your shell:
$ export POWERWALL_IP=<ip of your Powerwall>
$ export POWERWALL_PASSWORD=<your password>
$ tox -e example
Setup
from tesla_powerwall import Powerwall
# Create a simple powerwall object by providing the IP
powerwall = Powerwall("<ip of your Powerwall>")
#=> <Powerwall ...>
# Create a powerwall object with more options
powerwall = Powerwall(
endpoint="<ip of your powerwall>",
# Configure timeout; default is 10
timeout=10,
# Provide a requests.Session or None. If None is provided, a Session will be created.
http_session=None,
# Whether to verify the SSL certificate or not
verify_ssl=False
)
#=> <Powerwall ...>
Note: By default the API client does not verify the SSL certificate of the Powerwall. If you want to verify the SSL certificate you can set
verify_ssl
toTrue
.
Authentication
Since version 20.49.0 authentication is required for all methods. For that reason you must call login
before making a request to the API.
When you perform a request without being authenticated, an AccessDeniedError
will be thrown.
To login you can either use login
or login_as
. login
logs you in as User.CUSTOMER
whereas with login_as
you can choose a different user:
from tesla_powerwall import User
# Login as customer without email
# The default value for the email is ""
await powerwall.login("<password>")
#=> <LoginResponse ...>
# Login as customer with email
await powerwall.login("<password>", "<email>")
#=> <LoginResponse ...>
# Login with different user
await powerwall.login_as(User.INSTALLER, "<password>", "<email>")
#=> <LoginResponse ...>
# Check if we are logged in
# This method only checks wether a cookie with a Bearer token exists
# It does not verify whether this token is valid
powerwall.is_authenticated()
#=> True
# Logout
await powerwall.logout()
powerwall.is_authenticated()
#=> False
General
The API object directly maps the REST endpoints with a python method in the form of <verb>_<path>
. So if you need the raw json responses you can use the API object. It can be either created manually or retrived from an existing Powerwall
:
from tesla_powerwall import API
# Manually create API object
api = API('https://<ip>/')
# Perform get on 'system_status/soe'
await api.get_system_status_soe()
#=> {'percentage': 97.59281925744594}
# From existing powerwall
api = powerwall.get_api()
await api.get_system_status_soe()
The Powerwall
objet provides a wrapper around the API and exposes common methods.
Battery level
Get charge in percent:
await powerwall.get_charge()
#=> 97.59281925744594 (%)
Get charge in watt:
await powerwall.get_energy()
#=> 14807 (Wh)
Capacity
Get the capacity of your powerwall in watt:
await powerwall.get_capacity()
#=> 28078 (Wh)
Battery Packs
Get information about the battery packs that are installed:
Assuming that the battery is operational, you can retrive a number of values about each battery:
batteries = await powerwall.get_batteries()
#=> [<Battery ...>, <Battery ...>]
batteries[0].part_number
#=> "XXX-G"
batteries[0].serial_number
#=> "TGXXX"
batteries[0].energy_remaining
#=> 7378 (Wh)
batteries[0].capacity
#=> 14031 (Wh)
batteries[0].energy_charged
#=> 5525740 (Wh)
batteries[0].energy_discharged
#=> 4659550 (Wh)
batteries[0].wobble_detected
#=> False
batteries[0].p_out
#=> 260
batteries[0].q_out
#=> -1080
batteries[0].v_out
#=> 245.70
batteries[0].f_out
#=> 49.953
batteries[0].i_out
#=> -7.4
batteries[0].grid_state
#=> GridState.COMPLIANT
batteries[0].disabled_reasons
#=> []
If a battery is disabled it's grid_state
will be GridState.DISABLED
and some values will be None
. The variable disabled_reasons
might contain more information why the battery is disabled:
...
batteries[1].grid_state
#=> GridState.DISABLED
batteries[1].disabled_reasons
#=> ["DisabledExcessiveVoltageDrop"]
batteries[1].p_out
#=> None
batteries[1].energy_charged
#=> None
Powerwall Status
status = await powerwall.get_status()
#=> <PowerwallStatus ...>
status.version
#=> '1.49.0'
status.up_time_seconds
#=> datetime.timedelta(days=13, seconds=63287, microseconds=146455)
status.start_time
#=> datetime.datetime(2020, 9, 23, 23, 31, 16, tzinfo=datetime.timezone(datetime.timedelta(seconds=28800)))
status.device_type
#=> DeviceType.GW2
Sitemaster
sm = await powerwall.get_sitemaster()
#=> <SiteMaster ...>
sm.status
#=> StatusUp
sm.running
#=> true
sm.connected_to_tesla
#=> true
The sitemaster can be started and stopped using run()
and stop()
Siteinfo
info = await powerwall.get_site_info()
#=> <SiteInfo ...>
info.site_name
#=> 'Tesla Home'
info.country
#=> 'Germany'
info.nominal_system_energy
#=> 13.5 (kWh)
info.timezone
#=> 'Europe/Berlin'
Meters
Aggregates
from tesla_powerwall import MeterType
meters = await powerwall.get_meters()
#=> <MetersAggregates ...>
# access meter, but may return None when meter is not available
meters.get_meter(MeterType.SOLAR)
#=> <Meter ...>
# access meter, but may raise MeterNotAvailableError when the meter is not available at your powerwall (e.g. no solar panels installed)
meters.solar
#=> <MeterResponse ...>
# get all available meters at the current powerwall
meters.meters.keys()
#=> [<MeterType.SITE: 'site'>, <MeterType.BATTERY: 'battery'>, <MeterType.LOAD: 'load'>, <MeterType.SOLAR: 'solar'>]
Available meters are: solar
, site
, load
, battery
, generator
, and busway
. Some of those meters might not be available based on the installation and raise MeterNotAvailableError when accessed.
Current power supply/draw
Meter
provides different methods for checking current power supply/draw:
meters = await powerwall.get_meters()
meters.solar.get_power()
#=> 0.4 (kW)
meters.solar.instant_power
#=> 409.941801071167 (W)
meters.solar.is_drawing_from()
#=> True
meters.load.is_sending_to()
#=> True
meters.battery.is_active()
#=> False
# Different precision settings might return different results
meters.battery.is_active(precision=5)
#=> True
Note: For MeterType.LOAD
is_drawing_from
always returnsFalse
because it cannot be drawn fromload
.
Energy exported/imported
Get energy exported/imported in watt-hours (Wh) with energy_exported
and energy_imported
. For the values in kilowatt-hours (kWh) use get_energy_exported
and get_energy_imported
:
meters.battery.energy_exported
#=> 6394100 (Wh)
meters.battery.get_energy_exported()
#=> 6394.1 (kWh)
meters.battery.energy_imported
#=> 7576570 (Wh)
meters.battery.get_energy_imported()
#=> 7576.6 (kWh)
Details
You can receive more detailed information about the meters site
and solar
:
meter_details = await powerwall.get_meter_site() # or get_meter_solar() for the solar meter
#=> <MeterDetailsResponse ...>
readings = meter_details.readings
#=> <MeterDetailsReadings ...>
readings.real_power_a # same for real_power_b and real_power_c
#=> 619.13532458
readings.i_a_current # same for i_b_current and i_c_current
#=> 3.02
readings.v_l1n # smae for v_l2n and v_l3n
#=> 235.82
readings.instant_power
#=> -18.000023458
readings.is_sending()
As MeterDetailsReadings
inherits from MeterResponse
(which is used in MetersAggratesResponse
) it exposes the same data and methods.
For the meters battery and grid no additional details are provided, therefore no methods exist for those meters
Device Type
await powerwall.get_device_type()
#=> <DeviceType.GW1: 'hec'>
Grid Status
Get current grid status.
await powerwall.get_grid_status()
#=> <GridStatus.Connected: 'SystemGridConnected'>
await powerwall.is_grid_services_active()
#=> False
Operation mode
await powerwall.get_operation_mode()
#=> <OperationMode.SELF_CONSUMPTION: ...>
await powerwall.get_backup_reserve_percentage()
#=> 5.000019999999999 (%)
Powerwalls Serial Numbers
await serials = powerwall.get_serial_numbers()
#=> ["...", "...", ...]
Gateway DIN
await din = powerwall.get_gateway_din()
#=> 4159645-02-A--TGXXX
VIN
await vin = powerwall.get_vin()
Off-grid status (Set Island mode)
Take your powerwall on- and off-grid similar to the "Take off-grid" button in the Tesla app.
Set powerwall to off-grid (Islanded)
await powerwall.set_island_mode(IslandMode.OFFGRID)
Set powerwall to off-grid (Connected)
await powerwall.set_island_mode(IslandMode.ONGRID)
Development
pre-commit
This project uses pre-commit to run linters, formatters and type checking. You can easily run those checks locally:
# Install the pre-commit hooks
$ pre-commit install
pre-commit installed at .git/hooks/pre-commit
Now those checks will be execute on every git commit
. You can also execute all checks manually with pre-commit run --all-files
.
Building
$ python -m build
Testing
The tests are split in unit and integration tests.
The unit tests are self-contained and can simply be run locally by executing tox -e unit
, whereas the integration test, run against a real powerwall.
Unit-Tests
To run unit tests use tox:
$ tox -e unit
Integration-Tests
To execute the integration tests you need to first provide some information about your powerwall:
$ export POWERWALL_IP=<ip of your powerwall>
$ export POWERWALL_PASSWORD=<password for your powerwall>
$ tox -e integration
The integration tests might take your powerwall off grid and bring it back online. Before running the tests, make sure that you know what you are doing!
Owner metadata
- Name:
- Login: jrester
- Email:
- Kind: user
- Description:
- Website:
- Location: Munich, Germany
- Twitter:
- Company:
- Icon url: https://avatars.githubusercontent.com/u/31157644?u=0c47cb57c6505e29fc96be40bdb9e7ffc7a7a1b3&v=4
- Repositories: 30
- Last ynced at: 2024-06-11T15:45:15.256Z
- Profile URL: https://github.com/jrester
GitHub Events
Total
- Issues event: 8
- Watch event: 1
- Issue comment event: 6
- Push event: 2
- Fork event: 1
Last Year
- Issues event: 8
- Watch event: 1
- Issue comment event: 6
- Push event: 2
- Fork event: 1
Committers metadata
Last synced: 4 days ago
Total Commits: 139
Total Committers: 14
Avg Commits per committer: 9.929
Development Distribution Score (DDS): 0.165
Commits in past year: 7
Committers in past year: 2
Avg Commits per committer in past year: 3.5
Development Distribution Score (DDS) in past year: 0.143
Name | Commits | |
---|---|---|
Jrester | j****9@g****m | 116 |
J. Nick Koston | n****k@k****g | 8 |
maikukun | 1****n | 3 |
Josh Pettersen | 1****b | 2 |
z00nx 0 | z****0@g****m | 1 |
some-guy-in-oz | 8****z | 1 |
purcell-lab | 7****b | 1 |
Simon Moore | s****e@c****k | 1 |
Paul Hofmann | 6****n | 1 |
Jonathan Wood | d****i@d****s | 1 |
Daniel O'Connor | d****s@d****u | 1 |
Dan Simpson | d****n | 1 |
Barry Quiel | b****l@g****m | 1 |
Andreas Billmeier | b@e****t | 1 |
Committer domains:
- edevau.net: 1
- dons.net.au: 1
- dilect.us: 1
- cl.cam.ac.uk: 1
- koston.org: 1
Issue and Pull Request metadata
Last synced: 2 days ago
Total issues: 40
Total pull requests: 31
Average time to close issues: about 2 months
Average time to close pull requests: 4 days
Total issue authors: 35
Total pull request authors: 14
Average comments per issue: 5.1
Average comments per pull request: 3.03
Merged pull request: 27
Bot issues: 0
Bot pull requests: 0
Past year issues: 5
Past year pull requests: 0
Past year average time to close issues: 16 days
Past year average time to close pull requests: N/A
Past year issue authors: 4
Past year pull request authors: 0
Past year average comments per issue: 1.2
Past year average comments per pull request: 0
Past year merged pull request: 0
Past year bot issues: 0
Past year bot pull requests: 0
Top Issue Authors
- greyghoster (2)
- abuenano (2)
- billmoseley (2)
- Panda88CO (2)
- swm11 (2)
- pietervanderwesthuizen (1)
- DanielBaulig (1)
- quielb (1)
- T3CHKOMMIE (1)
- kl1947 (1)
- mweinelt (1)
- jackkorber (1)
- Arsecroft (1)
- nugget (1)
- wcwong (1)
Top Pull Request Authors
- bdraco (8)
- jrester (6)
- bubonicbob (5)
- daniel-simpson (2)
- onkelbeh (1)
- z00nx (1)
- purcell-lab (1)
- triandaphilos (1)
- dilecti (1)
- some-guy-in-oz (1)
- swm11 (1)
- DanielO (1)
- quielb (1)
- maikukun (1)
Top Issue Labels
Top Pull Request Labels
- hacktoberfest-accepted (2)
Package metadata
- Total packages: 1
-
Total downloads:
- pypi: 3,886 last-month
- Total docker downloads: 757,189,574
- Total dependent packages: 0
- Total dependent repositories: 596
- Total versions: 41
- Total maintainers: 1
pypi.org: tesla-powerwall
A simple API for accessing the Tesla Powerwall over your local network
- Homepage: https://github.com/jrester/tesla_powerwall
- Documentation: https://tesla-powerwall.readthedocs.io/
- Licenses: MIT License Copyright (c) 2024 Jrester Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- Latest release: 0.5.2 (published about 1 year ago)
- Last Synced: 2025-04-25T12:08:32.267Z (2 days ago)
- Versions: 41
- Dependent Packages: 0
- Dependent Repositories: 596
- Downloads: 3,886 Last month
- Docker Downloads: 757,189,574
-
Rankings:
- Docker downloads count: 0.195%
- Dependent repos count: 0.579%
- Average: 4.984%
- Downloads: 5.499%
- Dependent packages count: 7.299%
- Forks count: 8.015%
- Stargazers count: 8.316%
- Maintainers (1)
Dependencies
- actions/checkout v2 composite
- actions/setup-python v2 composite
- actions/checkout v2 composite
- actions/create-release v1 composite
- requests >=2.22.0
Score: 27.440896366801812