Welcome to Tesla Motors Club
Discuss Tesla's Model S, Model 3, Model X, Model Y, Cybertruck, Roadster and More.
Register

PowerWall and switchgear API's

This site may earn commission on affiliate links.
Aha! I understand what you're saying. Here's what I tried this morning:

(in an Emacs buffer so sorry for the Internet line endings showing up odd in machine format):
Code:
! curl -s -i -v -H 'Content-Type: application/json' -X POST -d '{"username":"[email protected]","password":"GATEWAYSERIALNUMBER","force_sm_off":"false"}' http://192.1.2.3/api/login/Basic
*   Trying 192.1.2.3...
* Connected to 192.1.2.3 (192.1.2.3) port 80 (#0)
> POST /api/login/Basic HTTP/1.1^M
> Host: 192.1.2.3^M
> User-Agent: curl/7.42.1^M
> Accept: */*^M
> Content-Type: application/json^M
> Content-Length: 77^M
> ^M
} [77 bytes data]
* upload completely sent off: 77 out of 77 bytes
< HTTP/1.1 401 Unauthorized^M
< Access-Control-Allow-Credentials: false^M
< Access-Control-Allow-Headers: X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept, Accept-Encoding, Authorization^M
< Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS^M
< Access-Control-Allow-Origin: *^M
< Access-Control-Max-Age: 86400^M
< Content-Type: application/json^M
< X-Content-Type-Options: nosniff^M
< Date: Wed, 23 Aug 2017 09:25:07 GMT^M
< Content-Length: 66^M
< ^M
{ [66 bytes data]
* Connection #0 to host 192.1.2.3 left intact
HTTP/1.1 401 Unauthorized^M
Access-Control-Allow-Credentials: false^M
Access-Control-Allow-Headers: X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept, Accept-Encoding, Authorization^M
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS^M
Access-Control-Allow-Origin: *^M
Access-Control-Max-Age: 86400^M
Content-Type: application/json^M
X-Content-Type-Options: nosniff^M
Date: Wed, 23 Aug 2017 09:25:07 GMT^M
Content-Length: 66^M
^M
{"code":401,"error":"Invalid Credentials","message":"Login Error"}

Everything looked ok. I don't know what I got wrong. But, this is further than I've gotten before. I now have an "Invalid Credentials" message. I just need to know what it will accept as credentials. If I could see the function i() being called somewhere, or everywhere, in that app...js file, I could maybe figure out what it wants.

I think I forgot AuthCookie. Is that "-c authcookie.txt"?
 
You might also be able to just borrow this js file and use it for authentication since it looks like this script also handles logging in via
/login/Basic and setting "AuthCookie". Then you can use Chrome's developer functions to examine the auth cookie. When I did this, it just set a seemingly random login string as the AuthCookie value, expiry is "session."

How did you do this (bolded part)? Did you find the main() function and replace it with a call to i(), then load it in your browser? Or were you able to trigger that in the script in some other way? Note that I don't know Java, but do C, bash, sed, assembler, and most Internet protocols as of ~1989 (when I used to read RFCs for entertainment, so just predating WWW, but with all the thoughts of creating such a thing), and I can "man curl", and get pretty far with searching for what other people did with curl that way in search engines.
 
Last edited:
How did you do this (bolded part)? Did you find the main() function and replace it with a call to i(), then load it in your browser?

That is what I was suggesting. You could also just use Chrome to inject some code into the page. Sorry I didn't see that you were using curl instead of intercepting the communications using the Chrome developer tools (which might be easier since you won't have to deal with other network packets like you would with a packet sniffer).

I can take a look again later to see exactly what the format of the data was being sent over the wire, but it sounds like you might want to get this information sooner than I will have time. But basically I am getting this information by looking at what is being sent when entering the wizard.

You shouldn't be afraid to enter the wizard, although your device will get uncomissioned when you log in, you can always just click through the seven or so screens hitting "skip" most of the time and then at the end your device will get recomissioned.
 
  • Informative
Reactions: Ulmo
@mr blue sky, thank you very much. Ok; I'm scared to use the Wizard, and don't want to mess anything up; that's why I didn't. Maybe it's OK; I'll look at all of this in detail Saturday; I'm working long hours now.

I have commissioned and uncommissioned my unit half a dozen times without a problem. I think the worst thing is you unconfigure the networking, but then it defaults to creating its own captive Powerwall wifi network which you can connect to and recommission the unit. I think anyone with a semi-technical background could just commission their own unit.
 
@Ulmo, many thanks for your investigations. I don't see in this thread that you found the Battery SoC and also mentioned the PW-2 firmware version. Here are some additional URI's to add to you original meter statistics. (This is just a copy of what I've found but I have not yet investigated the authorisation exchange. I have noticed that the reser value can ot actually be changed without running the Wizard and then again, if you do not run the PW-2 "test" page, the unit stays decommissioned (not an issue - just run to completion.

ENERGY_GateWay="10.1.1.240";
#
BATTERY_SOC="http://${ENERGY_GateWay}/api/system_status/soe"; # Battery StateOfEnergy [SoC]
METER_Stats="http://${ENERGY_GateWay}/api/meters/aggregates"; # Gateway Current Sensor Data for 4 Basic States plus Interbattey State?
GATEWAY_State="http://${ENERGY_GateWay}/api/sitemaster"; # Gateway Connection Status and Uptime in Seconds

##wget -o /dev/null -O - 'http://10.1.1.240/api/status' | python -mjson.tool
#{
# "git_hash": "993f7d4728705d7afe179614a2f278e8f4a8ad0a\n",
# "is_new": false,
# "start_time": "2017-09-22 02:17:39 +0800",
# "up_time_seconds": "428h51m49.243940208s",
# "version": "1.6.0\n"
#}
#
##wget -o /dev/null -O - 'http://10.1.1.240/api/customer/registration' | python -mjson.tool
#{
# "emailed_registration": true,
# "grid_services": false,
# "limited_warranty": false,
# "marketing": false,
# "privacy_notice": false,
# "registered": true,
# "skipped_registration": false
#}
##wget -o /dev/null -O - 'http://10.1.1.240:/api/powerwalls' | python -mjson.tool
#{
# "hasSync": true,
# "powerwalls": [
# {
# "PackagePartNumber": "1092170-03-E",
# "PackageSerialNumber": "SERIALNUM"
# }
# ]
#}
#
 
Last edited by a moderator:
  • Love
Reactions: Ulmo
@he1957 & @Ulmo, I came back here today to put that state of charge information in this thread, but I see @he1957 already found it. Thanks both for your work that made it easy to pick up this data and get it logged. Between the PVOutput Integration Service, a bit of powershell, and PV Bean Counter, I've now got all my data on PV Output: Flat Out 4.860kW | Live Output. Hopefully PV Output Integration Service will pick up the state of charge in the next release, so I can drop the powershell script.
 
  • Love
Reactions: Ulmo
I am also using PVOutput Integration Service to log data from Powerwall. Since it doesn't support the state of charge yet, I am attempting to calculate it myself using the battery_import and battery_export. Anyone knows how?

Based on the battery_import and battery_export data set that I get from the API, I am thinking about using this formula:

(import * efficiency - export)/total capacity = SoC %

Using this formula, it seems the efficiency is ~0.84725 and total capacity for my 2 Powerwall's is ~25.835 kWh. Both values are worse than the specs.
 
Hi @eml2, if you're using PVOutput Integration Service on windows, and have access to powershell (e.g. running a recent version of windows like Win8 or Win10), this little script will do the trick in the mean time...

Save it to a .ps1 file, right click on it, choose run with Powerwall, accept the prompt to bypass security (the script will be unsigned), and away you go. It sits there and runs and uploads the battery state of charge every five minutes.

It uploads to extended parameter v9 in my case (change the v9 in the script to a different parameter if you need to).

It outputs what it is doing to the powershell window...

do
{
$ThisTime = Get-Date -format HH:mm
$Now = Get-Date -format HH:mm:ss
$ThisMin = Get-Date -format mm
$ThisDate = Get-Date -format yyyyMMdd
$socdata = Invoke-WebRequest -Uri 'http://REPLACE_THIS_WITH_YOUR_GATEWAY_IP/api/system_status/soe' -UseBasicParsing | ConvertFrom-Json
$soc = $socdata.percentage
$soc = [math]::Round($soc,2)
Write-Host ("$Now State of Charge $soc")
if ($ThisMin % 5 -eq 0)
{
Write-Host ("$Now Waiting 15 Seconds")
Start-Sleep 15
$Now = Get-Date -format HH:mm:ss
$parms = @{}
$parms.Add('key','REPLACE_THIS_WITH_YOUR_PVOUTPUT_API_KEY')
$parms.Add('sid','REPLACE_THIS_WITH_YOUR_PVOUTPUT_SID')
$parms.Add('d',$ThisDate)
$parms.Add('t',$ThisTime)
$parms.Add('v9',$soc)
$Response = Invoke-WebRequest -Uri http://pvoutput.org/service/r2/addstatus.jsp -Body $Parms -UseBasicParsing
$Now = Get-Date -format HH:mm:ss
Write-Host ("$Now Result $Response.Content")
}
Start-Sleep 50
}
While ($loop_forever='true')