FastAPI server for Tesla Solar & Powerwall: multi-gateway monitoring, streaming, MQTT & web console.
7.4K
A high-performance FastAPI-based server for monitoring and managing Tesla Powerwall systems. Designed as the next-generation evolution of the pypowerwall proxy with multi-gateway support, real-time monitoring, and a built-in status console.
The easiest way to get started is using the provided Docker image. You can run in either TEDAPI Mode (local access) or Cloud Mode (remote access). Select the appropriate option below:
# TEDAPI Mode requires host network to access gateway at 192.168.91.1
docker run -d \
--name pypowerwall-server \
--network host \
-e PW_HOST=192.168.91.1 \
-e PW_GW_PWD=your_gateway_password \
jasonacox/pypowerwall-server
# TEDAPI v1r uses an RSA-4096 private key instead of the gateway Wi-Fi password.
# Generate a key pair with pypowerwall, then mount it into the container.
docker run -d \
--name pypowerwall-server \
--network host \
-e PW_HOST=192.168.91.1 \
-e PW_RSA_KEY_PATH=/keys/tedapi_rsa_private.pem \
-e PW_WIFI_HOST=192.168.91.1 \
-v /path/to/keys:/keys \
jasonacox/pypowerwall-server
Note:
PW_WIFI_HOSTis the IP address pypowerwall uses for the WiFi fallback path in v1r mode. It defaults to192.168.91.1. Only set it if your gateway is on a different IP (e.g. behind a travel router).
# Cloud Mode requires one-time setup using Tesla login step below
docker run -d \
--name pypowerwall-server \
-p 8675:8675 \
-v ~/.pypowerwall:/auth \
-e PW_EMAIL="[email protected]" \
-e PW_AUTHPATH=/auth \
jasonacox/pypowerwall-server
# One-time setup (runs auth flow to generate token files)
docker exec -it pypowerwall-server python -m pypowerwall setup
The PyPowerwall Server will be running at: http://localhost:8675 (if not running local, replace "localhost" with the IP of the host running the container).
# Multiple local gateways - requires host network
docker run -d \
--name pypowerwall-server \
--network host \
-e PW_GATEWAYS='[
{"id": "home", "name": "Home Gateway", "host": "192.168.91.1", "gw_pwd": "gateway_password_1"},
{"id": "cabin", "name": "Cabin Gateway", "host": "192.168.91.2", "gw_pwd": "gateway_password_2"},
{"id": "garage", "name": "Garage (travel router)", "host": "192.168.1.50", "port": 8443, "gw_pwd": "gateway_password_3"}
]' \
jasonacox/pypowerwall-server
# Install
pip install pypowerwall-server
# TEDAPI Mode
pypowerwall-server --host 192.168.91.1 --gw-pwd your_gateway_password
# Multiple Powerwalls
pypowerwall-server --config gateways.yaml
# Cloud Mode
pypowerwall-server --setup # one-time setup
pypowerwall-server --email "[email protected]"
Note: Most users will use TEDAPI to connect to their Powerwall gateway, which is accessible at the standard IP address
192.168.91.1on your local network. You'll need your gateway password (found in the Tesla app under your gateway settings).
If you want to control your Powerwall (set reserve level, operating mode, etc.), you'll need Tesla Cloud authentication:
One-time setup:
pip install pypowerwall-server
pypowerwall-server --setup
This will:
.pypowerwall.auth and .pypowerwall.site token filesSingle Gateway Mode (Read-Only via TEDAPI):
PW_HOST=192.168.91.1
PW_GW_PWD=your_gateway_password
PW_TIMEZONE=America/Los_Angeles
PW_PORT=8675 # Default port (proxy-compatible)
PW_BIND_ADDRESS=0.0.0.0 # Listen on all interfaces
PROXY_BASE_URL=/pypowerwall # Optional: serve under a sub-path (see Reverse Proxy)
Single Gateway Mode (TEDAPI v1r — RSA Key Auth):
PW_HOST=192.168.91.1
PW_RSA_KEY_PATH=/path/to/tedapi_rsa_private.pem # RSA-4096 private key (alternative to PW_GW_PWD)
PW_WIFI_HOST=192.168.91.1 # WiFi fallback IP for v1r mode (default: 192.168.91.1)
PW_TIMEZONE=America/Los_Angeles
Single Gateway Mode (With Cloud Control):
PW_HOST=192.168.91.1
PW_GW_PWD=your_gateway_password # For TEDAPI data reads
[email protected]
PW_AUTHPATH=/path/to/auth/files # Directory with .pypowerwall.auth/.site
PW_TIMEZONE=America/Los_Angeles
Multi-Gateway Mode:
PW_GATEWAYS='[
{
"id": "home",
"name": "Home System",
"host": "192.168.91.1",
"gw_pwd": "gw_pwd_1",
"email": "[email protected]",
"authpath": "/auth"
},
{
"id": "cabin",
"name": "Cabin System",
"host": "192.168.91.1",
"gw_pwd": "gw_pwd_2",
"email": "[email protected]",
"authpath": "/auth"
}
]'
server:
host: 0.0.0.0
port: 8675
cors_origins:
- http://localhost:3000
gateways:
- id: home
name: Home System
host: 192.168.91.1
gw_pwd: gw_pwd_1
email: [email protected]
authpath: /auth
timezone: America/Los_Angeles
- id: cabin
name: Cabin System
host: 192.168.91.1
gw_pwd: gw_pwd_2
email: [email protected]
authpath: /auth
timezone: America/Denver
- id: garage
name: Garage (travel router)
host: 192.168.1.50 # travel router IP
port: 8443 # non-standard HTTPS port forwarded to 192.168.91.1
gw_pwd: gw_pwd_3
timezone: America/Los_Angeles
- id: south-inverter
name: South Array Inverter
host: 192.168.91.1
gw_pwd: gw_pwd_4
type: inverter # solar-only; suppresses battery panels in console
timezone: America/Los_Angeles
- id: cloud-site
name: Cloud Mode Site
email: [email protected]
authpath: /auth
cloud_mode: true
- id: v1r-gateway
name: TEDAPI v1r Gateway
host: 192.168.91.1
rsa_key_path: /keys/tedapi_rsa_private.pem # RSA-4096 private key (TEDAPI v1r mode)
wifi_host: 192.168.91.1 # WiFi fallback IP (optional, defaults to 192.168.91.1)
timezone: America/Los_Angeles
Authentication:
gw_pwd: For TEDAPI local gateway access (standard mode)rsa_key_path: Path to RSA-4096 private key PEM file for TEDAPI v1r LAN access (alternative to gw_pwd)email + authpath: For Tesla Cloud API (control operations)
pypowerwall-server --setup to authenticate and generate auth files.pypowerwall.auth and .pypowerwall.site filesTEDAPI connection modes:
host + gw_pwd → TEDAPI (standard, uses gateway Wi-Fi password)host + rsa_key_path → TEDAPI v1r (uses RSA-4096 private key; shown as "TEDAPI v1r" in console)wifi_host → Optional WiFi fallback IP for v1r mode (default 192.168.91.1; only needed when your gateway is on a non-standard IP)Optional fields:
port: Non-standard HTTPS port (e.g. 8443) — use when the gateway is behind a travel router that forwards a custom port to 192.168.91.1:443type: Gateway device type — powerwall (default, has batteries) or inverter (solar-only; suppresses battery panels in the console)rsa_key_path: RSA-4096 private key PEM path for TEDAPI v1r LAN authenticationwifi_host: WiFi host IP for TEDAPI v1r WiFi fallback (default 192.168.91.1; set this when your gateway's WiFi AP is on a different subnet, e.g. behind a travel router)You can serve pypowerwall-server from a sub-path alongside other services (e.g. Grafana on /) using PROXY_BASE_URL. This is the recommended setup for HTTPS via nginx.
Environment variable:
PROXY_BASE_URL=/pypowerwall # Serve everything under /pypowerwall/
With this set, all UI pages, static assets, and API calls are rendered with the correct prefix so the browser resolves them through the proxy. No changes to API clients are needed.
Example nginx configuration:
server {
listen 443 ssl;
server_name lab.lan;
# Grafana at root
location / {
proxy_pass http://grafana:3000/;
}
# PyPowerwall at /pypowerwall/
location /pypowerwall/ {
# Strip the /pypowerwall prefix before forwarding (trailing slash is required)
proxy_pass http://pypowerwall:8675/;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
# Strip CORS headers added by pypowerwall so nginx can set its own
proxy_hide_header Access-Control-Allow-Origin;
proxy_hide_header Access-Control-Allow-Credentials;
proxy_hide_header Access-Control-Allow-Methods;
proxy_hide_header Access-Control-Allow-Headers;
# Using "*" is suitable for trusted LAN deployments where API data is not sensitive.
# For stricter setups, replace "*" with your specific trusted origin, e.g.:
# add_header Access-Control-Allow-Origin "https://pypowerwall.lan" always;
add_header Access-Control-Allow-Origin "*" always;
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always;
# WebSocket upgrade support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
Note: nginx's trailing slash in
proxy_pass http://pypowerwall:8675/;strips the/pypowerwallprefix before forwarding requests to pypowerwall. ThePROXY_BASE_URLsetting is only used to generate correct browser-side URLs (asset paths, API URLs, redirects) — pypowerwall itself receives all requests without the prefix.
URL mapping with this configuration:
| Browser URL | Forwarded to pypowerwall as |
|---|---|
https://lab.lan/pypowerwall/ | GET / — Power Flow animation |
https://lab.lan/pypowerwall/console | GET /console — Management console |
https://lab.lan/pypowerwall/api/... | GET /api/... — API endpoints |
https://lab.lan/pypowerwall/static/... | GET /static/... — Static assets |
Set MQTT_HOST to enable publishing. All other variables are optional.
export MQTT_HOST=192.168.1.100 # broker IP — required to enable MQTT
export MQTT_PORT=1883 # default: 1883
export MQTT_USERNAME=mqttuser # optional
export MQTT_PASSWORD=mqttpassword # optional
export MQTT_HA_DISCOVERY=true # auto-configure Home Assistant sensors (default: true)
| Variable | Default | Description |
|---|---|---|
MQTT_HOST | (none) | Broker hostname/IP. Required to enable MQTT. |
MQTT_PORT | 1883 | Broker port |
MQTT_USERNAME | (none) | Username for authentication |
MQTT_PASSWORD | (none) | Password for authentication |
MQTT_TLS | false | Enable TLS/SSL |
MQTT_TLS_CA_CERT | (none) | Path to CA certificate |
MQTT_TLS_INSECURE | false | Disable cert verification (testing only) |
MQTT_TOPIC_PREFIX | pypowerwall | Root topic prefix |
MQTT_RETAIN | true | Retain messages on broker |
MQTT_QOS | 1 | MQTT QoS level (0, 1, or 2) |
MQTT_HA_DISCOVERY | true | Publish Home Assistant auto-discovery payloads |
MQTT_HA_PREFIX | homeassistant | HA discovery prefix |
MQTT_CLIENT_ID | pypowerwall-server | MQTT client identifier |
MQTT_KEEPALIVE | 60 | Connection keepalive in seconds |
Topics are published under {MQTT_TOPIC_PREFIX}/{gateway_id}/ — e.g. pypowerwall/default/battery, pypowerwall/default/solar, etc. See mqtt-tools/README.md for the full topic list, broker setup guide, Home Assistant integration steps, and the live monitor GUI.
All existing proxy endpoints work unchanged:
Core Data Endpoints:
GET /vitals - Detailed system vitalsGET /aggregates - Power meter aggregatesGET /soe - State of energy (battery %)GET /freq - Grid frequency dataGET /pod - Battery pod detailsGET /strings - Solar string dataGET /battery - Battery informationGET /json - Combined metrics and status (JSON)Temperature & Environment:
GET /temps - All temperature sensorsGET /temps/pw - Powerwall temperatures onlyAlerts & Status:
GET /alerts - System alertsGET /alerts/pw - Powerwall alerts onlyFan Information:
GET /fans - All fan statusGET /fans/pw - Powerwall fans onlyData Export:
GET /csv - CSV format for Telegraf/InfluxDBGET /csv/v2 - Enhanced CSV formatTEDAPI Raw Access:
GET /tedapi - TEDAPI endpoint listGET /tedapi/config - Gateway configurationGET /tedapi/status - System statusGET /tedapi/components - Component detailsGET /tedapi/battery - Battery informationGET /tedapi/controller - Controller dataTesla API Endpoints:
GET /api/system_status/soe - State of energyGET /api/system_status/grid_status - Grid connection statusGET /api/system_status/grid_faults - Grid fault logGET /api/sitemaster - Sitemaster informationGET /api/meters/aggregates - Power metersGET /api/status - System statusGET /api/site_info - Site informationGET /api/site_info/site_name - Site nameGET /api/customer/registration - Customer registration infoGET /api/troubleshooting/problems - Problem listGET /api/auth/toggle/supported - Auth toggle supportGET /api/networks - Network configurationGET /api/system/networks - System networksGET /api/powerwalls - Powerwall device listServer Status:
GET /version - Server and firmware versionsGET /stats - Server statistics (uptime, requests, errors)Control Operations (requires authentication):
POST /control/{path} - Control operations (reserve, mode, etc.)Gateway Selection:
GET /api/gateways - List all configured gatewaysGET /api/gateways/{id} - Gateway detailsGET /api/gateways/{id}/vitals - Gateway-specific vitalsGET /api/gateways/{id}/aggregates - Gateway-specific power dataAggregated Data:
GET /api/aggregate/power - Combined power across all gatewaysGET /api/aggregate/soe - Total battery capacity and chargeGET /api/aggregate/status - Health status of all gatewaysWebSocket Endpoints:
WS /ws/gateway/{id} - Real-time data stream for specific gatewayWS /ws/aggregate - Real-time aggregated data streamThe server supports Tesla Cloud authentication for control operations:
TEDAPI (Local): For fast data reads from 192.168.91.1
host + password (gateway password)Cloud (Control): For control operations via Tesla API
email + authpathpypowerwall-server --setup to authenticate.pypowerwall.auth and .pypowerwall.site token filesConfiguration:
# TEDAPI only (monitoring)
PW_HOST=192.168.91.1
PW_GW_PWD=gateway_password
# TEDAPI + Cloud (monitoring + control)
PW_HOST=192.168.91.1
PW_GW_PWD=gateway_password
[email protected]
PW_AUTHPATH=/path/to/auth # Directory with .pypowerwall.auth/.site files
FastAPI is async, but pypowerwall is synchronous. This is handled using asyncio.run_in_executor() to run blocking pypowerwall calls in thread pools, preventing event loop blocking.
The server maintains no persistent state or historical data. All historical data for graphs is stored in browser localStorage, allowing:
Default: Read-only - The server operates in monitoring mode by default.
Optional Control Mode: Enable with environment variables:
CONTROL_ENABLED=true
CONTROL_TOKEN=your-secure-random-token
When control is enabled:
Authorization header/control endpoint)Multi-gateway aggregation uses smart aggregation that will evolve over time:
Current implementation (v0.1.x):
Future considerations documented in code:
This area is expected to need tuning as real-world multi-gateway deployments provide feedback.
Vanilla JavaScript - lightweight, no build step, fast loading. Charts and advanced features can be added incrementally without framework overhead.
pypowerwall-server/
├── app/
│ ├── main.py # FastAPI application entry point
│ ├── config.py # Configuration management
│ ├── api/
│ │ ├── __init__.py
│ │ ├── legacy.py # Legacy proxy endpoints
│ │ ├── gateways.py # Multi-gateway endpoints
│ │ ├── aggregates.py # Aggregated data endpoints
│ │ └── websockets.py # WebSocket handlers
│ ├── core/
│ │ ├── __init__.py
│ │ └── gateway_manager.py # Connection manager with caching
│ ├── models/
│ │ ├── __init__.py
│ │ └── gateway.py # All data models
│ ├── utils/
│ │ ├── __init__.py
│ │ └── transform.py # UI data transformations
│ └── static/
│ ├── index.html # Management console
│ ├── example.html # iFrame demo
│ └── powerflow/ # Power flow UI assets
├── tests/
│ ├── conftest.py
│ ├── test_api_aggregates.py
│ ├── test_api_gateways.py
│ ├── test_api_legacy.py
│ ├── test_basic.py
│ ├── test_config.py
│ ├── test_edge_cases.py
│ └── test_gateway_manager.py
├── Dockerfile
├── docker-compose.yml
├── requirements.txt
├── requirements-dev.txt
└── README.md
# Create virtual environment
python -m venv venv
source venv/bin/activate
# Install dependencies
pip install -r requirements-dev.txt
# Run development server with auto-reload
#
# Local TEDAPI Mode
PW_GW_PWD=ABCDEFGHIJ ./run.sh uvicorn app.main:app --reload --port 8675
#
# Cloud Mode
pypowerwall-server --setup # create .pypowerwall.auth
PW_EMAIL="[email protected]" PW_HOST= uvicorn app.main:app --reload --port 8675
# Run all tests
pytest
# Run with coverage
pytest --cov=app --cov-report=html
# Run specific test file
pytest tests/test_api.py -v
docker build -t pypowerwall-server .
docker run -p 8675:8675 pypowerwall-server
The server is designed for efficiency with background polling and caching:
Contributions are welcome! Please feel free to submit a Pull Request.
MIT License - See LICENSE for details.
Content type
Image
Digest
sha256:4e404ccda…
Size
51.6 MB
Last updated
12 days ago
docker pull jasonacox/pypowerwall-server